consume a finished queued track without reloading the window

Advancing naturally out of an up-next track rebuilt the whole window,
which reset the already-playing next track back to its start — audible
as the first second repeating. Remove the finished item from the player
in place (as the context edit path already does) and recentre instead,
so the current item and its prepared source survive. Regression test
asserts no setWindow on a natural advance out of a queued track.
This commit is contained in:
austinried
2026-10-04 00:30:00 +00:00
parent 3e459e4c84
commit bff16e0dd1
2 changed files with 39 additions and 1 deletions
@@ -554,7 +554,17 @@ class PlaybackController(
endedHandled = false
val next = if (position < updated.size) position else 0L
queueRepository.setCursor(next)
loadWindow(next, autoplay = true)
val player = player
if (next == position && player != null && position - windowStart in 0 until player.itemCount) {
updating = true
player.removeAt((position - windowStart).toInt())
updating = false
windowEnd--
shiftWindowLocked(next)
refresh(next)
} else {
loadWindow(next, autoplay = true)
}
}
fun previous() {
@@ -823,6 +823,34 @@ class PlaybackControllerTest {
eager.close()
}
@Test
fun naturallyAdvancingOutOfAQueuedTrackDoesNotReloadTheWindow() {
seedAlbum(3, sourceId = 1)
seedSong("x1", "al2")
controller.playAlbum(1, "al1", 0)
await {
controller.state.value.item
?.id == "s1"
}
controller.addToQueue(1, QueueKind.Song, "x1")
await { runBlocking { controller.upcomingItem()?.id } == "x1" }
controller.next()
await {
controller.state.value.item
?.id == "x1"
}
handle.operations.clear()
handle.advanceTo(handle.currentIndex + 1)
await {
controller.state.value.item
?.id == "s2"
}
assertFalse(handle.operations.any { it.startsWith("setWindow") })
}
@Test
fun nextFollowsTheReorderedQueue() {
seedAlbum(3, sourceId = 1)