PlayableState.Playable should only contain data useful for other components.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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<MediaPlayerControllerState> {
|
||||
override val values: Sequence<MediaPlayerControllerState> = sequenceOf(
|
||||
@@ -24,32 +23,15 @@ open class MediaPlayerControllerStateProvider : PreviewParameterProvider<MediaPl
|
||||
|
||||
private fun aMediaPlayerControllerState(
|
||||
isVisible: Boolean = true,
|
||||
isPlaying: Boolean = false,
|
||||
isPlaying: Boolean = true,
|
||||
progressInMillis: Long = 0,
|
||||
// Default to 1 minute and 23 seconds
|
||||
durationInMillis: Long = 83_000,
|
||||
isMuted: Boolean = false,
|
||||
) = MediaPlayerControllerState(
|
||||
isVisible = isVisible,
|
||||
playableState = aPlayableState(
|
||||
isPlaying = isPlaying,
|
||||
progressInMillis = progressInMillis,
|
||||
durationInMillis = durationInMillis,
|
||||
isMuted = isMuted,
|
||||
),
|
||||
)
|
||||
|
||||
private fun aPlayableState(
|
||||
isPlaying: Boolean = false,
|
||||
progressInMillis: Long = 0,
|
||||
// Default to 1 minute and 23 seconds
|
||||
durationInMillis: Long = 83_000,
|
||||
isShowingControls: Boolean = false,
|
||||
isMuted: Boolean = false,
|
||||
) = PlayableState.Playable(
|
||||
isPlaying = isPlaying,
|
||||
progressInMillis = progressInMillis,
|
||||
durationInMillis = durationInMillis,
|
||||
isShowingControls = isShowingControls,
|
||||
isMuted = isMuted,
|
||||
)
|
||||
|
||||
@@ -66,7 +66,7 @@ fun MediaPlayerControllerView(
|
||||
IconButton(
|
||||
onClick = onTogglePlay,
|
||||
) {
|
||||
if (state.playableState.isPlaying) {
|
||||
if (state.isPlaying) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.PauseSolid(),
|
||||
tint = ElementTheme.colors.iconPrimary,
|
||||
@@ -84,7 +84,7 @@ fun MediaPlayerControllerView(
|
||||
modifier = Modifier
|
||||
.widthIn(min = 48.dp)
|
||||
.padding(horizontal = 8.dp),
|
||||
text = state.playableState.progressInMillis.toHumanReadableDuration(),
|
||||
text = state.progressInMillis.toHumanReadableDuration(),
|
||||
textAlign = TextAlign.Center,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
style = ElementTheme.typography.fontBodyXsMedium,
|
||||
@@ -92,8 +92,8 @@ fun MediaPlayerControllerView(
|
||||
var lastSelectedValue by remember { mutableFloatStateOf(-1f) }
|
||||
Slider(
|
||||
modifier = Modifier.weight(1f),
|
||||
valueRange = 0f..state.playableState.durationInMillis.toFloat(),
|
||||
value = lastSelectedValue.takeIf { it >= 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,
|
||||
|
||||
Reference in New Issue
Block a user