From 8a90635666ffb10a7a537d20842a6b83382946d6 Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Mon, 28 Sep 2026 12:08:55 +0000 Subject: [PATCH] keep the playing context and window across an offline toggle --- .../subtracks/playback/PlaybackController.kt | 9 ++- .../playback/PlaybackControllerTest.kt | 65 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt index 4d5efea9..363dc834 100644 --- a/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt +++ b/app/src/main/kotlin/com/subtracks/playback/PlaybackController.kt @@ -146,6 +146,7 @@ class PlaybackController( private val offline: Boolean get() = sourceRepository.offline.value private var windowPositions = LongArray(0) private var windowFiltered = false + private var contextOverride: QueueContext? = null init { scope.launch { @@ -154,7 +155,7 @@ class PlaybackController( } } scope.launch { - sourceRepository.offline.drop(1).collect { reloadForOffline() } + sourceRepository.offline.collect { reloadForOffline() } } scope.launch { sourceRepository.quality.drop(1).collect { @@ -243,6 +244,7 @@ class PlaybackController( disableShuffle: Boolean = false, ) { if (!offline) { + contextOverride = null play(listOf(entry), start, disableShuffle) return } @@ -252,12 +254,14 @@ class PlaybackController( showMessage("Nothing downloaded for offline playback") return@launch } + contextOverride = QueueContext(entry.kind, entry.sourceId, entry.refId) play(entries, start, disableShuffle = true) } } private fun shuffleContext(entry: QueueEntry) { if (!offline) { + contextOverride = null shufflePlay(listOf(entry)) return } @@ -267,6 +271,7 @@ class PlaybackController( showMessage("Nothing downloaded for offline playback") return@launch } + contextOverride = QueueContext(entry.kind, entry.sourceId, entry.refId) shufflePlay(entries) } } @@ -1019,6 +1024,7 @@ class PlaybackController( windowEnd = -1 windowPositions = LongArray(0) windowFiltered = false + contextOverride = null lastPosition = null lastEdit = null player?.run { @@ -1387,6 +1393,7 @@ class PlaybackController( } private fun contextAt(position: Long?): QueueContext? { + contextOverride?.let { return it } val snapshot = snapshot ?: return null val play = position?.let { snapshot.anchorContextPlay(it) } ?: return null val entry = snapshot.locateContext(play)?.first ?: return null diff --git a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt index d3989968..1ea842e1 100644 --- a/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt +++ b/app/src/test/kotlin/com/subtracks/playback/PlaybackControllerTest.kt @@ -73,7 +73,7 @@ class PlaybackControllerTest { networkMode = MutableStateFlow(NetworkMode.Wifi) sources = SourceRepository(db, OkHttpClient(), prefs, ArtworkStore(File(context.cacheDir, "art")), networkMode = networkMode) queues = QueueRepository(db) - downloadsDir = File(context.cacheDir, "downloads") + downloadsDir = File(context.cacheDir, "downloads-${System.nanoTime()}") downloads = DownloadRepository( db, @@ -2495,6 +2495,69 @@ class PlaybackControllerTest { ) } + @Test + fun offlinePlayAlbumKeepsTheAlbumAsThePlayingContext() { + seedAlbum(4, sourceId = 1) + markDownloaded(1, "s1") + markDownloaded(1, "s3") + setOffline() + + controller.playAlbum(1, "al1", 0) + + await { + controller.state.value.context + ?.kind == QueueKind.Album + } + assertEquals( + QueueKind.Album, + controller.state.value.context + ?.kind, + ) + assertEquals( + "al1", + controller.state.value.context + ?.refId, + ) + } + + @Test + fun offlineUpNextPlaysAndIsConsumed() { + seedAlbum(8, sourceId = 1) + seedSong("x1", "al2") + (1..8).filter { it != 2 }.forEach { markDownloaded(1, "s$it") } + markDownloaded(1, "x1") + + controller.playAlbum(1, "al1", 3) + await { + controller.state.value.item + ?.id == "s4" + } + + setOffline() + await { handle.items.map { it.id } == listOf("s1", "s3", "s4", "s5", "s6", "s7", "s8") } + + controller.addToQueue(1, QueueKind.Song, "x1") + await { runBlocking { queues.snapshot().upNextSize } == 1L } + + controller.next() + await { + controller.state.value.item + ?.id == "x1" + } + + controller.next() + await { runBlocking { queues.snapshot().upNextSize } == 0L } + await { + controller.state.value.item + ?.id == "s5" + } + assertEquals( + "s5", + controller.state.value.item + ?.id, + ) + } + @Test fun offlinePlayAlbumBuildsADownloadedOnlyQueue() { seedAlbum(4, sourceId = 1)