queue view: stop reloading on edits, fix drag boundaries

- deleting a track no longer bumps the layout version, so the view does
  not reload and jump to the current track; the ViewModel already
  updates its rows.
- layout changes (re-anchor, enqueue, consume) now reconcile positions in
  place instead of calling open(), which cleared the rows and scrolled
  back to the cursor.
- section headers are separate list items and reordering maps by key, so
  the header no longer rides along with a dragged row (top flicker).
- disable the reorderable auto-scroll (scrollThreshold = 0). The library
  scrolls past the section boundary with no valid target, then abandons
  the scroll on release; without auto-scroll a drag stays put and drops
  in the last reachable slot.
- keep the current track when moving a queued track before it (eager
  dispatcher regression test).
This commit is contained in:
austinried
2026-10-04 00:30:00 +00:00
parent 5462b0f4ba
commit 50be4e79e0
3 changed files with 151 additions and 71 deletions
@@ -690,6 +690,49 @@ class PlaybackControllerTest {
eager.close()
}
@Test
fun movingAQueuedTrackBeforeTheCurrentDoesNotConsumeIt() {
seedAlbum(3, sourceId = 1)
seedSong("q1", "al2")
seedSong("q2", "al2")
seedSong("q3", "al2")
val eagerHandle = FakePlayerHandle()
val inline =
object : kotlinx.coroutines.CoroutineDispatcher() {
override fun dispatch(
context: kotlin.coroutines.CoroutineContext,
block: Runnable,
) = block.run()
}
val eager = PlaybackController(sources, queues, FakePlayerConnection(eagerHandle), dispatcher = inline)
eager.playAlbum(1, "al1", 0)
await {
eager.state.value.item
?.id == "s1"
}
eager.addToQueue(1, QueueKind.Song, "q1")
eager.addToQueue(1, QueueKind.Song, "q2")
eager.addToQueue(1, QueueKind.Song, "q3")
await { runBlocking { eager.upcomingItem()?.id } == "q1" }
eager.playAt(2)
await {
eager.state.value.item
?.id == "q2"
}
runBlocking { eager.move(3, 2) }
Thread.sleep(300)
assertEquals(
"q2",
eager.state.value.item
?.id,
)
assertEquals(3, runBlocking { queues.snapshot().upNext.size })
eager.close()
}
@Test
fun nextFollowsTheReorderedQueue() {
seedAlbum(3, sourceId = 1)