mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 23:21:59 +01:00
stop locating the playing queue entry by song id
The queue can hold the same song more than once (a song in both the context and the up-next block, a duplicate album track, ...), so resolving the playing entry by song id could match the wrong copy. - `PlaybackController.move` and `removeAt` now derive the current track's new position from the edit (block index / context play, read back through the updated snapshot so a moved anchor is accounted for) instead of `combinedIndexOf`/`combinedContextIndexOf`. - the queue view's playing highlight compares the row position to the playback position instead of the song id, so duplicates no longer both light up. Regression tests cover a move and a remove with a duplicate song in the context; both fail without the change. Still id-based, deliberately: `undo`'s canMirror guard (already position- guarded), the shuffle-state-changed branch of `shiftWindowLocked` (rare, needs the id to find the track after an arbitrary reorder) and the view's LazyColumn keys (cosmetic only).
This commit is contained in:
@@ -490,6 +490,42 @@ class PlaybackControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun movingWithADuplicateInTheContextKeepsThePlayingCopy() {
|
||||
seedAlbum(4, sourceId = 1)
|
||||
runBlocking { queues.replace(listOf(queues.albumEntry(1, "al1"), queues.songEntry(1, "s2"))) }
|
||||
controller.connect()
|
||||
await { controller.state.value.item != null }
|
||||
// Context is s1,s2,s3,s4,s2; play the second copy.
|
||||
controller.playAt(4)
|
||||
await { controller.state.value.position == 4L }
|
||||
|
||||
runBlocking { controller.move(0, 3) }
|
||||
|
||||
val snapshot = runBlocking { queues.snapshot() }
|
||||
val playing = controller.state.value.position!!
|
||||
assertTrue(runBlocking { queues.itemAt(snapshot, playing)?.song?.id } == "s2")
|
||||
// Still the second copy (flat index 4), not the first.
|
||||
assertEquals(4L, snapshot.flatContext(snapshot.contextPlay(playing)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingAnotherTrackWithADuplicateInTheContextKeepsThePlayingCopy() {
|
||||
seedAlbum(4, sourceId = 1)
|
||||
runBlocking { queues.replace(listOf(queues.albumEntry(1, "al1"), queues.songEntry(1, "s2"))) }
|
||||
controller.connect()
|
||||
await { controller.state.value.item != null }
|
||||
controller.playAt(4)
|
||||
await { controller.state.value.position == 4L }
|
||||
|
||||
runBlocking { controller.removeAt(0) }
|
||||
|
||||
val snapshot = runBlocking { queues.snapshot() }
|
||||
val playing = controller.state.value.position!!
|
||||
assertTrue(runBlocking { queues.itemAt(snapshot, playing)?.song?.id } == "s2")
|
||||
assertEquals(3L, snapshot.flatContext(snapshot.contextPlay(playing)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun playNextFromInsideTheBlockGoesAfterTheCurrentTrack() {
|
||||
seedAlbum(3, sourceId = 1)
|
||||
@@ -1637,6 +1673,29 @@ class PlaybackControllerTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingThePlayingAnchorWhileShuffledPlaysTheQueuedTrackNext() {
|
||||
seedAlbum(6, sourceId = 1)
|
||||
seedSong("x1", "al2")
|
||||
|
||||
controller.playAlbum(1, "al1", 2)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s3"
|
||||
}
|
||||
controller.addToQueue(1, QueueKind.Song, "x1")
|
||||
await { runBlocking { controller.upcomingItem()?.id } == "x1" }
|
||||
|
||||
controller.toggleShuffle()
|
||||
await { controller.state.value.shuffle }
|
||||
await { runBlocking { controller.upcomingItem()?.id } == "x1" }
|
||||
val current = controller.state.value.position!!
|
||||
|
||||
runBlocking { controller.removeAt(current) }
|
||||
|
||||
await { runBlocking { controller.upcomingItem()?.id } == "x1" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun removingThePlayingTrackWhileShuffledLeavesTheBlockReachable() {
|
||||
seedAlbum(6, sourceId = 1)
|
||||
|
||||
@@ -415,7 +415,7 @@ class AppScreenshotTest {
|
||||
rows =
|
||||
Fixtures.songItems.mapIndexed { index, item -> QueueRow(index.toLong(), index.toLong(), item) },
|
||||
ready = true,
|
||||
currentSongId = Fixtures.songItems[1].song.id,
|
||||
currentPosition = 1L,
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
onBack = {},
|
||||
onPlay = {},
|
||||
|
||||
Reference in New Issue
Block a user