add an offline mode that stays on the downloaded library

This commit is contained in:
austinried
2026-10-04 00:30:04 +00:00
parent 92637deb48
commit 8cccee7065
18 changed files with 537 additions and 60 deletions
@@ -349,6 +349,44 @@ class LibraryDaoTest {
assertEquals(3, dao.albumsByName(sourceId, 0, "").page().size)
}
@Test
fun offlineListQueriesReturnOnlyCompletedDownloads() =
runTest {
val sourceId = source()
val dao = db.libraryDao()
dao.upsertAlbums(listOf(album(sourceId, "al-1", "Album", year = null, starred = null)))
dao.upsertSongs(
listOf(
song(sourceId, "s1", "One", starred = null, track = 1),
song(sourceId, "s2", "Two", starred = null, track = 2),
song(sourceId, "s3", "Three", starred = null, track = 3),
),
)
dao.upsertPlaylists(listOf(playlist(sourceId, "pl-1", "List", created = 0, changed = 0)))
dao.upsertPlaylistSongs(
listOf(
PlaylistSong(sourceId, "pl-1", "s1", 0),
PlaylistSong(sourceId, "pl-1", "s2", 1),
PlaylistSong(sourceId, "pl-1", "s3", 2),
),
)
db.downloadDao().upsert(SongDownload(sourceId, "s1", DownloadStatus.Completed))
db.downloadDao().upsert(SongDownload(sourceId, "s2", DownloadStatus.Queued))
db.downloadDao().upsert(SongDownload(sourceId, "s3", DownloadStatus.Completed))
assertEquals(listOf("s1", "s3"), dao.songsByAlbumDownloaded(sourceId, "al-1").first().map { it.id })
assertEquals(listOf("s1", "s3"), dao.downloadedAlbumSongIds(sourceId, "al-1"))
assertEquals(listOf("s1", "s3"), dao.downloadedPlaylistSongIds(sourceId, "pl-1"))
assertEquals(
listOf("s1", "s3"),
dao.playlistSongsDownloaded(sourceId, "pl-1").page().map { it.song.id },
)
assertEquals(
listOf("al-1"),
dao.albumsForArtistDownloaded(sourceId, "ar-1").first().map { it.id },
)
}
@Test
fun searchMatchesInfixCaseInsensitivelyAndFallsBackToAScanBelowThreeCharacters() =
runTest {
@@ -244,6 +244,35 @@ class SourceRepositoryTest {
assertTrue("expected the server url, was ${ref.url}", ref.url.startsWith("http"))
}
@Test
fun offlineModeDisablesNetworkAndStreaming() =
runBlocking {
repository.addSource("server", "http://a.example/", "u", "p", true)
val sourceId = awaitActiveSourceId()
repository.setOfflineMode(true)
withTimeout(5_000) { repository.offline.first { it } }
assertEquals(null, repository.streamUri("s1", 1_000L, StreamQuality()))
assertEquals(null, repository.networkCoverArt(sourceId, "art-1", false))
assertEquals(null, repository.downloadUri(sourceId, "s1"))
assertEquals(null, repository.activeMusicSource())
assertEquals(null, repository.coverArt("art-1"))
}
@Test
fun offlineModeStillServesDownloadedArtwork() =
runBlocking {
repository.addSource("server", "http://a.example/", "u", "p", true)
val sourceId = awaitActiveSourceId()
artwork.write(sourceId, coverArtKey(sourceId, "art-1", false), byteArrayOf(1, 2, 3))
repository.setOfflineMode(true)
withTimeout(5_000) { repository.offline.first { it } }
val ref = repository.coverArt("art-1")
assertTrue("expected the stored file, was ${ref?.url}", ref?.url?.startsWith("file:") == true)
}
private suspend fun awaitActiveSourceId(): Long = withTimeout(5_000) { repository.activeSourceId().first { it != null }!! }
private suspend fun awaitCoverArt(coverArt: String): CoverArtRef =
@@ -224,4 +224,15 @@ class SyncManagerTest {
"<song id=\"s1\" title=\"Song One\" albumId=\"al1\" artistId=\"ar1\" track=\"1\"/>" +
"</searchResult3></subsonic-response>"
}
@Test
fun aSyncRequestWhileOfflineIsRefusedWithoutTouchingTheNetwork() =
runBlocking {
sourceRepository.setOfflineMode(true)
withTimeout(5_000) { sourceRepository.offline.first { it } }
manager.requestSync()
val status = withTimeout(10_000) { manager.status.first { it is SyncStatus.Failed } }
assertEquals("Offline mode is on", (status as SyncStatus.Failed).message)
}
}