mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
playback: share edge wrapping with the art predictions
Lift the wrap arithmetic out of next(), previous() and previousTrack() into nextPosition()/previousPosition() so upcomingItem()/previousItem() cannot drift from the actions again. A one-track queue no longer predicts itself as its own neighbour, online or offline: the wrap would land on the current position, and the actions are a no-op there, so the strip offered a dead swipe.
This commit is contained in:
@@ -693,12 +693,29 @@ class PlaybackController(
|
||||
}
|
||||
return
|
||||
}
|
||||
when {
|
||||
current < snapshot.size - 1 -> jumpTo(current + 1)
|
||||
repeatMode != RepeatMode.Off -> jumpTo(0)
|
||||
}
|
||||
nextPosition(snapshot, current)?.let { jumpTo(it) }
|
||||
}
|
||||
|
||||
private fun nextPosition(
|
||||
snapshot: QueueSnapshot,
|
||||
current: Long,
|
||||
): Long? =
|
||||
when {
|
||||
current < snapshot.size - 1 -> current + 1
|
||||
repeatMode != RepeatMode.Off -> 0L
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun previousPosition(
|
||||
snapshot: QueueSnapshot,
|
||||
current: Long,
|
||||
): Long? =
|
||||
when {
|
||||
current > 0 -> current - 1
|
||||
repeatMode == RepeatMode.All -> snapshot.size - 1
|
||||
else -> null
|
||||
}
|
||||
|
||||
private suspend fun consumeUpNext(position: Long) =
|
||||
startLock.withLock {
|
||||
val snapshot = snapshot ?: return@withLock
|
||||
@@ -784,19 +801,12 @@ class PlaybackController(
|
||||
}
|
||||
return
|
||||
}
|
||||
when {
|
||||
current > 0 -> {
|
||||
jumpTo(current - 1)
|
||||
}
|
||||
|
||||
repeatMode == RepeatMode.All -> {
|
||||
jumpTo(snapshot.size - 1)
|
||||
}
|
||||
|
||||
else -> {
|
||||
player.seekTo(0)
|
||||
refresh()
|
||||
}
|
||||
val target = previousPosition(snapshot, current)
|
||||
if (target != null) {
|
||||
jumpTo(target)
|
||||
} else {
|
||||
player.seekTo(0)
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,10 +824,7 @@ class PlaybackController(
|
||||
}
|
||||
return
|
||||
}
|
||||
when {
|
||||
current > 0 -> jumpTo(current - 1)
|
||||
repeatMode == RepeatMode.All -> jumpTo(snapshot.size - 1)
|
||||
}
|
||||
previousPosition(snapshot, current)?.let { jumpTo(it) }
|
||||
}
|
||||
|
||||
fun addToQueue(
|
||||
@@ -935,21 +942,15 @@ class PlaybackController(
|
||||
val snapshot = current ?: return null
|
||||
val at = position ?: return null
|
||||
if (!isOffline) {
|
||||
val next =
|
||||
if (at + 1 < snapshot.size) {
|
||||
at + 1
|
||||
} else if (repeatMode != RepeatMode.Off) {
|
||||
0L
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return next?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
return nextPosition(snapshot, at)
|
||||
?.takeIf { it != at }
|
||||
?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
}
|
||||
downloads.awaitLoaded()
|
||||
val target =
|
||||
downloadedAtOrAfter(snapshot, at + 1)
|
||||
?: if (repeatMode != RepeatMode.Off) downloadedAtOrAfter(snapshot, 0L) else null
|
||||
return target?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
return target?.takeIf { it != at }?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
}
|
||||
|
||||
suspend fun previousItem(): QueueItem? {
|
||||
@@ -964,19 +965,15 @@ class PlaybackController(
|
||||
val snapshot = current ?: return null
|
||||
val at = position ?: return null
|
||||
if (!isOffline) {
|
||||
val previous =
|
||||
when {
|
||||
at > 0 -> at - 1
|
||||
repeatMode == RepeatMode.All -> snapshot.size - 1
|
||||
else -> return null
|
||||
}
|
||||
return queueRepository.itemAt(snapshot, previous)?.toQueueItem()
|
||||
return previousPosition(snapshot, at)
|
||||
?.takeIf { it != at }
|
||||
?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
}
|
||||
downloads.awaitLoaded()
|
||||
val target =
|
||||
downloadedAtOrBefore(snapshot, at - 1)
|
||||
?: if (repeatMode == RepeatMode.All) downloadedAtOrBefore(snapshot, snapshot.size - 1) else null
|
||||
return target?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
return target?.takeIf { it != at }?.let { queueRepository.itemAt(snapshot, it)?.toQueueItem() }
|
||||
}
|
||||
|
||||
private fun play(
|
||||
|
||||
@@ -2262,6 +2262,38 @@ class PlaybackControllerTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aSingleTrackQueueHasNoAdjacentArtwork() {
|
||||
seedAlbum(1, sourceId = 1)
|
||||
controller.playAlbum(1, "al1", 0)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s1"
|
||||
}
|
||||
controller.cycleRepeat()
|
||||
assertEquals(RepeatMode.All, controller.state.value.repeat)
|
||||
|
||||
assertNull(runBlocking { controller.upcomingItem() })
|
||||
assertNull(runBlocking { controller.previousItem() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aSingleDownloadedTrackHasNoAdjacentArtworkWhenOffline() {
|
||||
seedAlbum(1, sourceId = 1)
|
||||
markDownloaded(1, "s1")
|
||||
setOffline()
|
||||
controller.playAlbum(1, "al1", 0)
|
||||
await {
|
||||
controller.state.value.item
|
||||
?.id == "s1"
|
||||
}
|
||||
controller.cycleRepeat()
|
||||
assertEquals(RepeatMode.All, controller.state.value.repeat)
|
||||
|
||||
assertNull(runBlocking { controller.upcomingItem() })
|
||||
assertNull(runBlocking { controller.previousItem() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun repeatAllLoopsAfterEndingWithRepeatOff() {
|
||||
seedAlbum(2, sourceId = 1)
|
||||
|
||||
Reference in New Issue
Block a user