From b04a500e4ae1d5e51f292e29a5ede4d12732a441 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 18:25:52 +0000 Subject: [PATCH] fix(home): stop hero channel preview audio when the app is backgrounded Pressing Home while a favorite TV channel previewed in the hero only stopped the activity; the Home composition stayed alive and its ExoPlayer kept playing. Gate the hero video on the lifecycle being STARTED and release the stream on stop so it re-prepares on return. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MYpWycUKkE68tJ8MZK2ucm --- .../arflix/tv/ui/screens/home/HomeScreen.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeScreen.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeScreen.kt index c40ee3956..de0a5b994 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeScreen.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/home/HomeScreen.kt @@ -70,6 +70,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.collectAsState import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.compose.currentStateAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key @@ -1044,12 +1045,18 @@ fun HomeScreen( // moving elsewhere replays it. var collectionVideoFinishedId by remember { mutableStateOf(null) } val heroVideoAllowed = true + // Leaving the app (Home button / minimize) stops the activity but keeps this + // composition alive, so the hero preview has to follow the lifecycle or its + // audio keeps playing in the background. + val homeLifecycleState by lifecycleOwner.lifecycle.currentStateAsState() + val isHomeStarted = homeLifecycleState.isAtLeast(Lifecycle.State.STARTED) val serviceHeroVideoUrl = displayHeroItem ?.takeIf { heroVideoAllowed && isHeroCollection && collectionVideoFinishedId != it.id } ?.let { viewModel.getCollectionHeroVideoUrl(it) } val heroVideoUrl = when { !isMobile && !focusState.userHasNavigated -> null !heroVideoAllowed -> null + !isHomeStarted -> null // Service collection MP4s should start as soon as the card becomes the hero. // Keep the idle gate for heavier IPTV/live playback, but do not delay MP4 previews. serviceHeroVideoUrl != null -> serviceHeroVideoUrl @@ -1076,6 +1083,19 @@ fun HomeScreen( } } + // Fully release the stream while backgrounded: a paused live channel would be + // behind the live window on return, so it gets re-prepared fresh instead. + LaunchedEffect(isHomeStarted) { + if (!isHomeStarted) { + heroPlaybackHandles?.player?.let { player -> + player.playWhenReady = false + player.stop() + player.clearMediaItems() + } + preparedHeroVideoUrl = null + } + } + // Service-collection video lifecycle: play once on focus, with sound, // then mark the card "played" so subsequent focus returns fall back to // the stock image. IPTV live streams bypass this (they loop naturally).