diff --git a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt index 0d9568b0..ebdcfd92 100644 --- a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt +++ b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt @@ -179,6 +179,10 @@ actual fun PlatformPlayerSurface( var currentSubtitleStyle by remember { mutableStateOf(SubtitleStyleState.DEFAULT) } var subtitleSelectionJob by remember { mutableStateOf(null) } + fun syncPlayerViewKeepScreenOn() { + playerViewRef?.keepScreenOn = exoPlayer.shouldKeepPlayerScreenOn() + } + DisposableEffect(exoPlayer) { PlayerPictureInPictureManager.registerPausePlaybackCallback { exoPlayer.pause() @@ -186,6 +190,7 @@ actual fun PlatformPlayerSurface( val listener = object : Player.Listener { override fun onPlayerError(error: PlaybackException) { + syncPlayerViewKeepScreenOn() latestOnError.value(error.localizedMessage ?: runBlocking { getString(Res.string.player_unable_to_play_stream) }) } @@ -202,10 +207,12 @@ actual fun PlatformPlayerSurface( latestOnError.value(null) exoPlayer.logCurrentTracks("STATE_READY") } + syncPlayerViewKeepScreenOn() latestOnSnapshot.value(exoPlayer.snapshot()) } override fun onIsPlayingChanged(isPlaying: Boolean) { + syncPlayerViewKeepScreenOn() latestOnSnapshot.value(exoPlayer.snapshot()) } @@ -235,6 +242,7 @@ actual fun PlatformPlayerSurface( onDispose { PlayerPictureInPictureManager.registerPausePlaybackCallback(null) exoPlayer.removeListener(listener) + playerViewRef?.keepScreenOn = false subtitleSelectionJob?.cancel() } } @@ -264,6 +272,7 @@ actual fun PlatformPlayerSurface( LaunchedEffect(exoPlayer, playWhenReady) { exoPlayer.playWhenReady = playWhenReady + syncPlayerViewKeepScreenOn() latestOnSnapshot.value(exoPlayer.snapshot()) } @@ -424,7 +433,7 @@ actual fun PlatformPlayerSurface( useController = useNativeController layoutParams = android.view.ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) player = exoPlayer - keepScreenOn = true + keepScreenOn = exoPlayer.shouldKeepPlayerScreenOn() this.resizeMode = resizeMode.toExoResizeMode() setShutterBackgroundColor(android.graphics.Color.BLACK) playerViewRef = this @@ -441,6 +450,7 @@ actual fun PlatformPlayerSurface( playerView.useController = useNativeController playerView.resizeMode = resizeMode.toExoResizeMode() playerViewRef = playerView + syncPlayerViewKeepScreenOn() playerView.syncLibassOverlay( player = exoPlayer, enabled = useLibass, @@ -469,6 +479,11 @@ private fun ExoPlayer.snapshot(): PlayerPlaybackSnapshot = playbackSpeed = playbackParameters.speed, ) +private fun ExoPlayer.shouldKeepPlayerScreenOn(): Boolean = + playerError == null && + playWhenReady && + playbackState in setOf(Player.STATE_BUFFERING, Player.STATE_READY) + private fun PlayerResizeMode.toExoResizeMode(): Int = when (this) { PlayerResizeMode.Fit -> AspectRatioFrameLayout.RESIZE_MODE_FIT diff --git a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.android.kt b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.android.kt index bc1a8734..c02f9f6a 100644 --- a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.android.kt +++ b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.android.kt @@ -35,7 +35,7 @@ actual fun LockPlayerToLandscape() { } @Composable -actual fun EnterImmersivePlayerMode() { +actual fun EnterImmersivePlayerMode(keepScreenAwake: Boolean) { val activity = LocalContext.current.findActivity() ?: return DisposableEffect(activity) { diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.kt index b60ccbec..024b0e50 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.kt @@ -19,7 +19,7 @@ data class PlayerAudioLevel( expect fun LockPlayerToLandscape() @Composable -expect fun EnterImmersivePlayerMode() +expect fun EnterImmersivePlayerMode(keepScreenAwake: Boolean) @Composable expect fun ManagePlayerPictureInPicture( diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreen.kt index a99d0be5..e19e11b7 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/PlayerScreen.kt @@ -139,7 +139,6 @@ fun PlayerScreen( initialProgressFraction: Float? = null, ) { LockPlayerToLandscape() - EnterImmersivePlayerMode() val playerSettingsUiState by remember { PlayerSettingsRepository.ensureLoaded() PlayerSettingsRepository.uiState @@ -195,6 +194,9 @@ fun PlayerScreen( var playerController by remember { mutableStateOf(null) } var playerControllerSourceUrl by remember { mutableStateOf(null) } var errorMessage by remember { mutableStateOf(null) } + val keepScreenAwake = errorMessage == null && + (playbackSnapshot.isPlaying || (shouldPlay && playbackSnapshot.isLoading)) + EnterImmersivePlayerMode(keepScreenAwake = keepScreenAwake) var scrubbingPositionMs by remember { mutableStateOf(null) } var pausedOverlayVisible by remember { mutableStateOf(false) } var gestureFeedback by remember { mutableStateOf(null) } diff --git a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.ios.kt b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.ios.kt index a0f97372..90575e4d 100644 --- a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.ios.kt +++ b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerPlatformEffects.ios.kt @@ -2,6 +2,7 @@ package com.nuvio.app.features.player import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.remember import androidx.compose.ui.unit.IntSize import platform.Foundation.NSNotificationCenter @@ -32,10 +33,12 @@ actual fun LockPlayerToLandscape() { } @Composable -actual fun EnterImmersivePlayerMode() { +actual fun EnterImmersivePlayerMode(keepScreenAwake: Boolean) { + SideEffect { + UIApplication.sharedApplication.setIdleTimerDisabled(keepScreenAwake) + } + DisposableEffect(Unit) { - // Request idle timer disabled to keep screen awake during playback - UIApplication.sharedApplication.setIdleTimerDisabled(true) onDispose { UIApplication.sharedApplication.setIdleTimerDisabled(false) }