Fix media seeking flicker (#6434)

This commit is contained in:
bxdxnn
2026-03-23 18:03:50 +03:00
committed by GitHub
parent 9074692189
commit a261156c7c
5 changed files with 40 additions and 7 deletions

View File

@@ -121,6 +121,7 @@ private fun ExoPlayerMediaAudioView(
durationInMillis = 0,
canMute = false,
isMuted = false,
seekingToMillis = null,
)
)
}
@@ -171,15 +172,21 @@ private fun ExoPlayerMediaAudioView(
LaunchedEffect(exoPlayer.isPlaying) {
if (exoPlayer.isPlaying) {
while (true) {
val position = exoPlayer.currentPosition
val seekingTo = mediaPlayerControllerState.seekingToMillis
mediaPlayerControllerState = mediaPlayerControllerState.copy(
progressInMillis = exoPlayer.currentPosition,
progressInMillis = position,
seekingToMillis = if (seekingTo != null && position >= seekingTo) null else seekingTo,
)
delay(200)
}
} else {
// Ensure we render the final state
val position = exoPlayer.currentPosition
val seekingTo = mediaPlayerControllerState.seekingToMillis
mediaPlayerControllerState = mediaPlayerControllerState.copy(
progressInMillis = exoPlayer.currentPosition,
progressInMillis = position,
seekingToMillis = if (seekingTo != null && position >= seekingTo) null else seekingTo,
)
}
}
@@ -294,6 +301,9 @@ private fun ExoPlayerMediaAudioView(
exoPlayer.togglePlay()
},
onSeekChange = {
mediaPlayerControllerState = mediaPlayerControllerState.copy(
seekingToMillis = it.toLong(),
)
exoPlayer.seekToEnsurePlaying(it.toLong())
},
onToggleMute = {

View File

@@ -18,7 +18,16 @@ data class MediaPlayerControllerState(
val durationInMillis: Long,
val canMute: Boolean,
val isMuted: Boolean,
val seekingToMillis: Long?,
) {
/**
* The progress in milliseconds to display. When [seekingToMillis] is non-null (during a seek operation),
* this returns the target seek position. Once the player catches up to the seek position,
* [seekingToMillis] is cleared (set to null) and this returns [progressInMillis] again.
*/
val displayProgressInMillis: Long
get() = seekingToMillis ?: progressInMillis
@FloatRange(from = 0.0, to = 1.0)
val progressAsFloat = (progressInMillis.toFloat() / durationInMillis.toFloat()).coerceIn(0f, 1f)
val progressAsFloat = (displayProgressInMillis.toFloat() / durationInMillis.toFloat()).coerceIn(0f, 1f)
}

View File

@@ -34,6 +34,7 @@ private fun aMediaPlayerControllerState(
durationInMillis: Long = 83_000,
canMute: Boolean = true,
isMuted: Boolean = false,
seekingToMillis: Long? = null,
) = MediaPlayerControllerState(
isVisible = isVisible,
isPlaying = isPlaying,
@@ -42,4 +43,5 @@ private fun aMediaPlayerControllerState(
durationInMillis = durationInMillis,
canMute = canMute,
isMuted = isMuted,
seekingToMillis = seekingToMillis,
)

View File

@@ -126,7 +126,7 @@ fun MediaPlayerControllerView(
modifier = Modifier
.widthIn(min = 48.dp)
.padding(horizontal = 8.dp),
text = state.progressInMillis.toHumanReadableDuration(),
text = state.displayProgressInMillis.toHumanReadableDuration(),
textAlign = TextAlign.Center,
color = ElementTheme.colors.textPrimary,
style = ElementTheme.typography.fontBodyXsMedium,
@@ -135,7 +135,9 @@ fun MediaPlayerControllerView(
Slider(
modifier = Modifier.weight(1f),
valueRange = 0f..state.durationInMillis.toFloat(),
value = lastSelectedValue.takeIf { it >= 0 } ?: state.progressInMillis.toFloat(),
value = lastSelectedValue.takeIf { it >= 0 }
?: state.seekingToMillis?.toFloat()
?: state.progressInMillis.toFloat(),
onValueChange = {
lastSelectedValue = it
},

View File

@@ -108,6 +108,7 @@ private fun ExoPlayerMediaVideoView(
durationInMillis = 0,
canMute = true,
isMuted = false,
seekingToMillis = null,
)
)
}
@@ -225,6 +226,9 @@ private fun ExoPlayerMediaVideoView(
},
onSeekChange = {
autoHideController++
mediaPlayerControllerState = mediaPlayerControllerState.copy(
seekingToMillis = it.toLong(),
)
exoPlayer.seekToEnsurePlaying(it.toLong())
},
onToggleMute = {
@@ -242,15 +246,21 @@ private fun ExoPlayerMediaVideoView(
LaunchedEffect(exoPlayer.isPlaying) {
if (exoPlayer.isPlaying) {
while (true) {
val position = exoPlayer.currentPosition
val seekingTo = mediaPlayerControllerState.seekingToMillis
mediaPlayerControllerState = mediaPlayerControllerState.copy(
progressInMillis = exoPlayer.currentPosition,
progressInMillis = position,
seekingToMillis = if (seekingTo != null && position >= seekingTo) null else seekingTo,
)
delay(200)
}
} else {
// Ensure we render the final state
val position = exoPlayer.currentPosition
val seekingTo = mediaPlayerControllerState.seekingToMillis
mediaPlayerControllerState = mediaPlayerControllerState.copy(
progressInMillis = exoPlayer.currentPosition,
progressInMillis = position,
seekingToMillis = if (seekingTo != null && position >= seekingTo) null else seekingTo,
)
}
}