mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
keep the block in place when the anchor is removed while a queued track plays
`adjustAnchorOnRemove` moved the anchor to the canonical predecessor of the removed track, which in a shuffled queue is an unrelated play position, so removing the context anchor while playing a queued track teleported the up-next block somewhere random (and out of view). When the removed context track is the anchor, move the anchor to the track before it in play order (or -1), so the block stays where it sits. This also covers removing the playing context anchor, so the controller's separate re-anchor is no longer needed and is removed.
This commit is contained in:
@@ -465,9 +465,17 @@ class QueueRepository(
|
|||||||
// tracks that remain keep their positions.
|
// tracks that remain keep their positions.
|
||||||
val order = snapshot.shuffle ?: return
|
val order = snapshot.shuffle ?: return
|
||||||
val flat = snapshot.flatContext(play) ?: return
|
val flat = snapshot.flatContext(play) ?: return
|
||||||
|
val predecessor = if (play <= 0L) -1L else snapshot.flatContext(play - 1L) ?: -1L
|
||||||
shuffleRemoved = order.withRemoved(order.domainFor(flat))
|
shuffleRemoved = order.withRemoved(order.domainFor(flat))
|
||||||
write(compact(removeEntry(snapshot.entries, flat)).map { it.entry })
|
write(compact(removeEntry(snapshot.entries, flat)).map { it.entry })
|
||||||
adjustAnchorOnRemove(flat)
|
if (cursorRow().upNextAnchor == flat) {
|
||||||
|
// The removed track carried the block; move the anchor to the track before it in
|
||||||
|
// play order so the block stays in place instead of jumping to the canonical
|
||||||
|
// predecessor, which in a shuffled queue is an unrelated position.
|
||||||
|
setUpNextAnchor(if (predecessor > flat) predecessor - 1 else predecessor)
|
||||||
|
} else {
|
||||||
|
adjustAnchorOnRemove(flat)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val removed = compact(removeEntry(snapshot.entries, play))
|
val removed = compact(removeEntry(snapshot.entries, play))
|
||||||
write(removed.map { it.entry })
|
write(removed.map { it.entry })
|
||||||
|
|||||||
@@ -344,18 +344,6 @@ class PlaybackController(
|
|||||||
lastEdit = ReloadUndo(entries, cursor, snapshot.shuffleSeed, upNext, snapshot.upNextAnchor)
|
lastEdit = ReloadUndo(entries, cursor, snapshot.shuffleSeed, upNext, snapshot.upNextAnchor)
|
||||||
return@withLock
|
return@withLock
|
||||||
}
|
}
|
||||||
// The block floats behind the currently playing context track, so removing that track
|
|
||||||
// removes its anchor. Re-anchor the block to the track that now precedes the removed
|
|
||||||
// slot in play order, so it takes the slot and plays next, rather than the anchor
|
|
||||||
// landing wherever `adjustAnchorOnRemove` left it.
|
|
||||||
if (snapshot.shuffled && position == current && !wasUpNext && updated.upNextSize > 0L) {
|
|
||||||
val play = snapshot.contextPlay(current)
|
|
||||||
val predecessor = play - 1L
|
|
||||||
val anchor = if (predecessor < 0L) -1L else updated.flatContext(predecessor) ?: -1L
|
|
||||||
queueRepository.setUpNextAnchor(anchor)
|
|
||||||
updated = readSnapshot()
|
|
||||||
this.snapshot = updated
|
|
||||||
}
|
|
||||||
// Derive the current track's new position from the edit. Resolving its song id after
|
// Derive the current track's new position from the edit. Resolving its song id after
|
||||||
// the edit can match an identical song elsewhere (a duplicate in the context or the
|
// the edit can match an identical song elsewhere (a duplicate in the context or the
|
||||||
// block), so use positions throughout. Removing the playing track resumes at the same
|
// block), so use positions throughout. Removing the playing track resumes at the same
|
||||||
|
|||||||
@@ -1670,6 +1670,32 @@ class PlaybackControllerTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun removingTheAnchorWhilePlayingABlockTrackKeepsTheBlockInPlace() {
|
||||||
|
seedShuffledQueue(seed = 5L)
|
||||||
|
seedSong("x1", "al2")
|
||||||
|
controller.addToQueue(1, QueueKind.Song, "x1")
|
||||||
|
await { runBlocking { controller.upcomingItem()?.id } == "x1" }
|
||||||
|
|
||||||
|
controller.playAt(1)
|
||||||
|
await {
|
||||||
|
controller.state.value.item
|
||||||
|
?.id == "x1"
|
||||||
|
}
|
||||||
|
val before = runBlocking { queues.snapshot() }
|
||||||
|
|
||||||
|
runBlocking { controller.removeAt(before.anchorPlay) }
|
||||||
|
|
||||||
|
val after = runBlocking { queues.snapshot() }
|
||||||
|
assertEquals(-1L, after.anchorPlay)
|
||||||
|
assertEquals("x1", runBlocking { queues.itemAt(after, 0)?.song?.id })
|
||||||
|
assertEquals(
|
||||||
|
"x1",
|
||||||
|
controller.state.value.item
|
||||||
|
?.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun removingThePlayingTrackWhileShuffledPlaysTheNextShuffledTrack() {
|
fun removingThePlayingTrackWhileShuffledPlaysTheNextShuffledTrack() {
|
||||||
seedShuffledQueue(seed = 12345L)
|
seedShuffledQueue(seed = 12345L)
|
||||||
|
|||||||
Reference in New Issue
Block a user