diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt index b644ebc685..b7102b0f84 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaView.kt @@ -30,6 +30,7 @@ import androidx.compose.material.icons.outlined.GraphicEq import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -172,17 +173,26 @@ private fun ExoPlayerMediaVideoView( localMedia: LocalMedia?, modifier: Modifier = Modifier, ) { - var playableState: PlayableState.Playable by remember { + var mediaPlayerControllerState: MediaPlayerControllerState by remember { mutableStateOf( - PlayableState.Playable( + MediaPlayerControllerState( + isVisible = false, isPlaying = false, progressInMillis = 0, durationInMillis = 0, - isShowingControls = false, isMuted = false, ) ) } + + val playableState: PlayableState.Playable by remember { + derivedStateOf { + PlayableState.Playable( + isShowingControls = mediaPlayerControllerState.isVisible, + ) + } + } + localMediaViewState.playableState = playableState val context = LocalContext.current @@ -195,16 +205,20 @@ private fun ExoPlayerMediaVideoView( } override fun onIsPlayingChanged(isPlaying: Boolean) { - playableState = playableState.copy(isPlaying = isPlaying) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isPlaying = isPlaying, + ) } override fun onVolumeChanged(volume: Float) { - playableState = playableState.copy(isMuted = volume == 0f) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isMuted = volume == 0f, + ) } override fun onTimelineChanged(timeline: Timeline, reason: Int) { if (reason == Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE) { - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( durationInMillis = exoPlayer.duration, ) } @@ -221,21 +235,23 @@ private fun ExoPlayerMediaVideoView( LaunchedEffect(autoHideController) { delay(5.seconds) if (exoPlayer.isPlaying) { - playableState = playableState.copy(isShowingControls = false) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = false, + ) } } LaunchedEffect(exoPlayer.isPlaying) { if (exoPlayer.isPlaying) { while (true) { - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( progressInMillis = exoPlayer.currentPosition, ) delay(200) } } else { // Ensure we render the final state - playableState = playableState.copy( + mediaPlayerControllerState = mediaPlayerControllerState.copy( progressInMillis = exoPlayer.currentPosition, ) } @@ -248,7 +264,7 @@ private fun ExoPlayerMediaVideoView( } else { exoPlayer.setMediaItems(emptyList()) } - KeepScreenOn(playableState.isPlaying) + KeepScreenOn(mediaPlayerControllerState.isPlaying) Box( modifier = modifier .background(ElementTheme.colors.bgSubtlePrimary) @@ -263,7 +279,9 @@ private fun ExoPlayerMediaVideoView( layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) setOnClickListener { autoHideController++ - playableState = playableState.copy(isShowingControls = !playableState.isShowingControls) + mediaPlayerControllerState = mediaPlayerControllerState.copy( + isVisible = !mediaPlayerControllerState.isVisible, + ) } useController = false } @@ -275,10 +293,7 @@ private fun ExoPlayerMediaVideoView( }, ) MediaPlayerControllerView( - state = MediaPlayerControllerState( - isVisible = playableState.isShowingControls, - playableState = playableState, - ), + state = mediaPlayerControllerState, onTogglePlay = { autoHideController++ if (exoPlayer.isPlaying) { diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt index 54eb3f0970..b7237c26eb 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/local/LocalMediaViewState.kt @@ -29,11 +29,7 @@ class LocalMediaViewState internal constructor( sealed interface PlayableState { data object NotPlayable : PlayableState data class Playable( - val isPlaying: Boolean, - val progressInMillis: Long, - val durationInMillis: Long, val isShowingControls: Boolean, - val isMuted: Boolean, ) : PlayableState } diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt index b6963a16b1..f5197af99b 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerState.kt @@ -7,9 +7,10 @@ package io.element.android.libraries.mediaviewer.api.player -import io.element.android.libraries.mediaviewer.api.local.PlayableState - data class MediaPlayerControllerState( val isVisible: Boolean, - val playableState: PlayableState.Playable, + val isPlaying: Boolean, + val progressInMillis: Long, + val durationInMillis: Long, + val isMuted: Boolean, ) diff --git a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt index 64b8ef241e..a5f3664941 100644 --- a/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt +++ b/libraries/mediaviewer/api/src/main/kotlin/io/element/android/libraries/mediaviewer/api/player/MediaPlayerControllerStateProvider.kt @@ -8,7 +8,6 @@ package io.element.android.libraries.mediaviewer.api.player import androidx.compose.ui.tooling.preview.PreviewParameterProvider -import io.element.android.libraries.mediaviewer.api.local.PlayableState open class MediaPlayerControllerStateProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( @@ -24,32 +23,15 @@ open class MediaPlayerControllerStateProvider : PreviewParameterProvider= 0 } ?: state.playableState.progressInMillis.toFloat(), + valueRange = 0f..state.durationInMillis.toFloat(), + value = lastSelectedValue.takeIf { it >= 0 } ?: state.progressInMillis.toFloat(), onValueChange = { lastSelectedValue = it }, @@ -103,8 +103,8 @@ fun MediaPlayerControllerView( }, useCustomLayout = true, ) - val formattedDuration = remember(state.playableState.durationInMillis) { - state.playableState.durationInMillis.toHumanReadableDuration() + val formattedDuration = remember(state.durationInMillis) { + state.durationInMillis.toHumanReadableDuration() } Text( modifier = Modifier @@ -118,7 +118,7 @@ fun MediaPlayerControllerView( IconButton( onClick = onToggleMute, ) { - if (state.playableState.isMuted) { + if (state.isMuted) { Icon( imageVector = CompoundIcons.VolumeOffSolid(), tint = ElementTheme.colors.iconPrimary,