diff --git a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt index e306f8ef..ed426a78 100644 --- a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt +++ b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt @@ -934,7 +934,17 @@ class PlaybackController( } val snapshot = current ?: return null val at = position ?: return null - if (!isOffline) return queueRepository.itemAt(snapshot, at + 1)?.toQueueItem() + 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() } + } downloads.awaitLoaded() val target = downloadedAtOrAfter(snapshot, at + 1) @@ -953,7 +963,15 @@ class PlaybackController( } val snapshot = current ?: return null val at = position ?: return null - if (!isOffline) return if (at <= 0) null else queueRepository.itemAt(snapshot, at - 1)?.toQueueItem() + if (!isOffline) { + val previous = + when { + at > 0 -> at - 1 + repeatMode == RepeatMode.All -> snapshot.size - 1 + else -> return null + } + return queueRepository.itemAt(snapshot, previous)?.toQueueItem() + } downloads.awaitLoaded() val target = downloadedAtOrBefore(snapshot, at - 1) diff --git a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt index e7a7275e..2b1e6a33 100644 --- a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt +++ b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt @@ -218,6 +218,61 @@ class PlaybackControllerTest { assertNull(runBlocking { controller.previousItem() }) } + @Test + fun previousItemWrapsToTheEndWithRepeatAll() { + seedAlbum(3, sourceId = 1) + controller.playAlbum(1, "al1", 0) + await { + controller.state.value.item + ?.id == "s1" + } + controller.cycleRepeat() + assertEquals(RepeatMode.All, controller.state.value.repeat) + + assertEquals("s3", runBlocking { controller.previousItem()?.id }) + } + + @Test + fun upcomingItemIsNullAtTheEndOfTheQueue() { + seedAlbum(3, sourceId = 1) + controller.playAlbum(1, "al1", 2) + await { + controller.state.value.item + ?.id == "s3" + } + + assertNull(runBlocking { controller.upcomingItem() }) + } + + @Test + fun upcomingItemWrapsToTheStartWithRepeatAll() { + seedAlbum(3, sourceId = 1) + controller.playAlbum(1, "al1", 2) + await { + controller.state.value.item + ?.id == "s3" + } + controller.cycleRepeat() + assertEquals(RepeatMode.All, controller.state.value.repeat) + + assertEquals("s1", runBlocking { controller.upcomingItem()?.id }) + } + + @Test + fun upcomingItemWrapsToTheStartWithRepeatOne() { + seedAlbum(3, sourceId = 1) + controller.playAlbum(1, "al1", 2) + await { + controller.state.value.item + ?.id == "s3" + } + controller.cycleRepeat() + controller.cycleRepeat() + assertEquals(RepeatMode.One, controller.state.value.repeat) + + assertEquals("s1", runBlocking { controller.upcomingItem()?.id }) + } + @Test fun previousTrackMovesBackEvenOncePreviousWouldRestart() { seedAlbum(3, sourceId = 1)