From b23db4bab34699b8b5b1e5bd0a9127c413fa855b Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Sun, 21 Jun 2026 11:17:16 +0000 Subject: [PATCH] fix(player): keep seek bar thumb at target on release Previously, the Slider's value was switched from the local sliderPosition to the positionMs prop the instant onValueChangeFinished cleared isScrubbing. Because the prop had not yet caught up with the committed seek, the thumb visibly snapped back to the pre-seek position before jumping to the target. Drive the slider from sliderPosition unconditionally, sync sliderPosition from the prop via a LaunchedEffect only when not scrubbing, and pin sliderPosition to the committed target before clearing isScrubbing in onValueChangeFinished. --- .../ui/screen/player/components/PlayerSeekBar.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerSeekBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerSeekBar.kt index 50665b56..b8b3e399 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerSeekBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/player/components/PlayerSeekBar.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material3.Slider import androidx.compose.material3.SliderDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf @@ -33,7 +34,16 @@ fun PlayerSeekBar( val currentPosition = positionMs.coerceIn(0, safeDuration) var sliderPosition by remember { mutableFloatStateOf(currentPosition.toFloat()) } var isScrubbing by remember { mutableStateOf(false) } - val sliderValue = if (isScrubbing) sliderPosition else currentPosition.toFloat() + val sliderValue = sliderPosition + + // Keep sliderPosition in sync with the player's position when the user is not + // actively scrubbing. While scrubbing, the local drag value is preserved so the + // thumb does not snap back to a stale positionMs prop before the seek is committed. + LaunchedEffect(positionMs) { + if (!isScrubbing) { + sliderPosition = positionMs.toFloat() + } + } Box( modifier = modifier @@ -64,6 +74,7 @@ fun PlayerSeekBar( }, onValueChangeFinished = { val targetPosition = sliderPosition.toLong().coerceIn(0L, safeDuration) + sliderPosition = targetPosition.toFloat() isScrubbing = false onSeek(targetPosition) },