scrubTimeline
Tap and drag over a timeline, through the scrub protocol the player needs.
A press begins a scrub and seeks to what is under it, every drag seeks again inside that scrub, and lifting off ends it and settles on the exact frame. Seeking on each drag delta without this cancels its own in-flight seeks, so the decoder never catches up and the picture stops moving while the finger does.
A gesture that ends without lifting off still ends the scrub, whether the pointer is cancelled or the timeline leaves the composition under the finger, so the player is never left scrubbing with nothing driving it.
val scrub = rememberScrubState(player)
Column {
TimelineRuler(
scale = timeline.scale,
modifier = Modifier.scrubTimeline(scrub, timeline.scale, timeline::scrollPx),
scrollPx = timeline::scrollPx,
)
FilmstripStrip(frames = frames, grid = timeline.grid, state = timeline.listState)
}Parameters
The protocol the gesture drives.
What turns the gesture's x into a source time.
How far the timeline under the gesture has scrolled. The lambda itself is fixed when the gesture's coroutine starts, so read the values it needs inside it. One that closes over a number read during composition keeps that number for the whole gesture.
Where the player's zero sits on the timeline's clock, so timelineTime == playerTime + sourceOffset() . Read inside the gesture for the same reason as scrollPx, so a trim handle moving mid-gesture is honoured by the next drag.