Add seek acceleration to TV seekbar on held D-pad

Consecutive same-direction presses ramp up the jump amount: first 2 presses use
the profile seek interval, presses 3-7 triple it, and presses 8+ sextuple it.
Direction change or focus loss resets the counter. This lets quick taps do fine
scrubbing while holding the key covers large spans fast.
This commit is contained in:
KhooLy 2026-07-03 12:45:24 +03:00
parent 88d7e22ec2
commit 0e3882eff8

View file

@ -51,6 +51,8 @@ fun TVSeekbar(
) {
var isFocused by remember { mutableStateOf(false) }
var internalPos by remember { mutableFloatStateOf(position.toFloat()) }
var consecutivePresses by remember { mutableIntStateOf(0) }
var lastPressDirection by remember { mutableIntStateOf(0) }
val seekbarAccent = FluxaColors.accent
val seekPreview = rememberSeekThumbnail(LocalSeekSurfaceView.current, internalPos.toLong(), isFocused, position, isPlaying, onScrubSeek)
@ -73,29 +75,37 @@ fun TVSeekbar(
.fillMaxWidth()
.height(48.dp)
.focusRequester(focusRequester)
.onFocusChanged {
isFocused = it.isFocused
onScrubbing(it.isFocused, internalPos.toLong())
.onFocusChanged { focusState ->
isFocused = focusState.isFocused
if (!focusState.isFocused) { consecutivePresses = 0; lastPressDirection = 0 }
onScrubbing(focusState.isFocused, internalPos.toLong())
}
.focusProperties { up = playPauseFocusRequester }
.focusable()
.onKeyEvent {
.onKeyEvent {
if (it.type == KeyEventType.KeyDown) {
when (it.key) {
Key.DirectionLeft -> {
internalPos = (internalPos - seekBackwardMs).coerceAtLeast(0f)
Key.DirectionLeft -> {
if (lastPressDirection != -1) { consecutivePresses = 0; lastPressDirection = -1 }
consecutivePresses++
val multiplier = when { consecutivePresses >= 8 -> 6L; consecutivePresses >= 3 -> 3L; else -> 1L }
internalPos = (internalPos - seekBackwardMs * multiplier).coerceAtLeast(0f)
onScrubbing(true, internalPos.toLong())
true
true
}
Key.DirectionRight -> {
internalPos = (internalPos + seekForwardMs).coerceAtMost(duration.toFloat())
Key.DirectionRight -> {
if (lastPressDirection != 1) { consecutivePresses = 0; lastPressDirection = 1 }
consecutivePresses++
val multiplier = when { consecutivePresses >= 8 -> 6L; consecutivePresses >= 3 -> 3L; else -> 1L }
internalPos = (internalPos + seekForwardMs * multiplier).coerceAtMost(duration.toFloat())
onScrubbing(true, internalPos.toLong())
true
true
}
Key.Enter, Key.DirectionCenter -> {
Key.Enter, Key.DirectionCenter -> {
consecutivePresses = 0; lastPressDirection = 0
onSeek(internalPos.toLong())
onScrubbing(false, internalPos.toLong())
true
true
}
else -> false
}