fix: lyrics scroll — center active line only, remove drift phase

The 'drift to next line' animation moved the text while the user was
still reading/singing the current line, making it feel out of sync.
Now matches the web behavior: smooth-scroll to center the active line
when it changes, nothing more.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-06-17 01:39:51 +02:00
1 parent ec9c0add9e
commit eacce487df
1 file changed
+4 -13
@@ -411,21 +411,12 @@ fun NowPlayingScreen(
lyricsState.lines.indexOfLast { it.timeMs <= state.positionMs + 200L }.coerceAtLeast(0)
else -1
// Smooth continuous scroll: snap to active line, then drift toward the next
// Center the active line when it changes — matches web behavior (no drift)
LaunchedEffect(activeIdx) {
if (activeIdx < 0 || lyricsState.lines.isEmpty() || lyricsViewH == 0) return@LaunchedEffect
fun targetFor(idx: Int) = (lyricsPaddingPx + idx * lineHeightPx + lineHeightPx / 2f
- lyricsViewH * 0.30f).coerceAtLeast(0f).toInt()
// Phase 1: snap to the active line
lyricsScrollState.animateScrollTo(targetFor(activeIdx), tween(380, easing = FastOutSlowInEasing))
// Phase 2: drift to the next line's position over this line's remaining duration
val nextLine = lyricsState.lines.getOrNull(activeIdx + 1) ?: return@LaunchedEffect
val thisLine = lyricsState.lines[activeIdx]
val driftMs = (nextLine.timeMs - thisLine.timeMs - 380L).coerceIn(50L, 12_000L)
lyricsScrollState.animateScrollTo(targetFor(activeIdx + 1), tween(driftMs.toInt(), easing = LinearEasing))
val target = (lyricsPaddingPx + activeIdx * lineHeightPx + lineHeightPx / 2f
- lyricsViewH * 0.5f).coerceAtLeast(0f).toInt()
lyricsScrollState.animateScrollTo(target, tween(350, easing = FastOutSlowInEasing))
}
when {