address offline review: refresh, cursor, and cold-start fixes

This commit is contained in:
austinried
2026-10-04 00:30:04 +00:00
parent a36b310f95
commit 15e09d8097
5 changed files with 126 additions and 28 deletions
@@ -419,6 +419,46 @@ class LibraryDaoTest {
)
}
@Test
fun downloadedFilterSortsArtistsByTheirDownloadedAlbumCount() =
runTest {
val sourceId = source()
val dao = db.libraryDao()
dao.upsertArtists(
listOf(
artist(sourceId, "ar-1", "One", albumCount = 1),
artist(sourceId, "ar-2", "Two", albumCount = 3),
),
)
dao.upsertAlbums(
listOf(
album(sourceId, "a1", "A1", year = null, starred = null),
album(sourceId, "a2", "A2", year = null, starred = null),
album(sourceId, "b1", "B1", year = null, starred = null).copy(artistId = "ar-2"),
),
)
dao.upsertSongs(
listOf(
song(sourceId, "s-a1", "A1", starred = null).copy(albumId = "a1"),
song(sourceId, "s-a2", "A2", starred = null).copy(albumId = "a2"),
song(sourceId, "s-b1", "B1", starred = null).copy(albumId = "b1", artistId = "ar-2"),
),
)
listOf("s-a1", "s-a2", "s-b1").forEach {
db.downloadDao().upsert(SongDownload(sourceId, it, DownloadStatus.Completed))
}
// ar-1 has two downloaded albums, ar-2 one; by synced count ar-2 (3) leads ar-1 (1).
assertEquals(
listOf("ar-1", "ar-2"),
dao.artistsByAlbumCount(sourceId, 0, "", downloadedFilter = 1).page().map { it.id },
)
assertEquals(
listOf("ar-2", "ar-1"),
dao.artistsByAlbumCount(sourceId, 0, "").page().map { it.id },
)
}
@Test
fun downloadedFilterReportsTheDownloadedSongCountForPlaylists() =
runTest {
@@ -2497,6 +2497,74 @@ class PlaybackControllerTest {
)
}
@Test
fun offlineRemovingThePlayingTrackPlaysTheNextDownloaded() {
seedAlbum(4, sourceId = 1)
markDownloaded(1, "s1")
markDownloaded(1, "s3")
setOffline()
controller.playAlbum(1, "al1", 0)
await {
controller.state.value.item
?.id == "s1"
}
runBlocking { controller.removeAt(0) }
await {
controller.state.value.item
?.id == "s3"
}
assertEquals(
"s3",
controller.state.value.item
?.id,
)
assertEquals(1L, controller.state.value.position)
}
@Test
fun offlineDeletingADownloadDropsItFromTheWindow() {
seedAlbum(3, sourceId = 1)
markDownloaded(1, "s1")
markDownloaded(1, "s2")
markDownloaded(1, "s3")
setOffline()
controller.playAlbum(1, "al1", 0)
await { handle.items.map { it.id } == listOf("s1", "s2", "s3") }
runBlocking { downloads.remove(1, "s2") }
controller.refreshMediaItems()
await { handle.items.none { it.id == "s2" } }
assertEquals(listOf("s1", "s3"), handle.items.map { it.id })
}
@Test
fun offlinePreviousSkipsToThePreviousDownloaded() {
seedAlbum(5, sourceId = 1)
markDownloaded(1, "s1")
markDownloaded(1, "s4")
setOffline()
controller.playAlbum(1, "al1", 3)
await {
controller.state.value.item
?.id == "s4"
}
controller.previous()
await {
controller.state.value.item
?.id == "s1"
}
assertEquals(
"s1",
controller.state.value.item
?.id,
)
}
@Test
fun offlinePlayStartsAtTheNearestDownloadedWhenTheTargetIsNotDownloaded() {
seedAlbum(60, sourceId = 1)
@@ -2764,14 +2832,18 @@ class PlaybackControllerTest {
songId: String,
) {
val file = File(downloadsDir, "$sourceId/$songId")
runBlocking {
downloads.reconcile()
db.downloadDao().upsert(SongDownload(sourceId, songId, DownloadStatus.Completed))
file.parentFile?.mkdirs()
file.writeBytes(byteArrayOf(1))
downloads.reconcile()
val deadline = System.nanoTime() + 15_000_000_000L
while (System.nanoTime() < deadline) {
runBlocking {
db.downloadDao().upsert(SongDownload(sourceId, songId, DownloadStatus.Completed))
file.parentFile?.mkdirs()
file.writeBytes(byteArrayOf(1))
downloads.reconcile()
}
if (downloads.localUri(songId) != null) return
Thread.sleep(10)
}
await { downloads.localUri(songId) != null }
assertTrue("Timed out marking $songId downloaded", downloads.localUri(songId) != null)
}
private fun setOffline() {