mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
keep the artist sort index and bound the offline queue-view scan
This commit is contained in:
@@ -82,8 +82,8 @@ internal const val ARTISTS_SELECT =
|
|||||||
|
|
||||||
internal const val ARTIST_ORDER_BY_NAME = "name COLLATE NOCASE, id"
|
internal const val ARTIST_ORDER_BY_NAME = "name COLLATE NOCASE, id"
|
||||||
internal const val ARTIST_ORDER_BY_NAME_REVERSED = "name COLLATE NOCASE DESC, id DESC"
|
internal const val ARTIST_ORDER_BY_NAME_REVERSED = "name COLLATE NOCASE DESC, id DESC"
|
||||||
internal const val ARTIST_ORDER_BY_ALBUM_COUNT = "albumCount DESC, name COLLATE NOCASE, id"
|
internal const val ARTIST_ORDER_BY_ALBUM_COUNT = "artists.albumCount DESC, name COLLATE NOCASE, id"
|
||||||
internal const val ARTIST_ORDER_BY_ALBUM_COUNT_REVERSED = "albumCount ASC, name COLLATE NOCASE DESC, id DESC"
|
internal const val ARTIST_ORDER_BY_ALBUM_COUNT_REVERSED = "artists.albumCount ASC, name COLLATE NOCASE DESC, id DESC"
|
||||||
internal const val ARTIST_ORDER_BY_STARRED = "starred DESC NULLS LAST, name COLLATE NOCASE, id"
|
internal const val ARTIST_ORDER_BY_STARRED = "starred DESC NULLS LAST, name COLLATE NOCASE, id"
|
||||||
internal const val ARTIST_ORDER_BY_STARRED_REVERSED = "starred ASC NULLS LAST, name COLLATE NOCASE DESC, id DESC"
|
internal const val ARTIST_ORDER_BY_STARRED_REVERSED = "starred ASC NULLS LAST, name COLLATE NOCASE DESC, id DESC"
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,12 @@ private const val POSITION_TIMEOUT_MS = 1_000L
|
|||||||
|
|
||||||
internal const val QUEUE_WINDOW_ROWS = QUEUE_CHUNK * 3
|
internal const val QUEUE_WINDOW_ROWS = QUEUE_CHUNK * 3
|
||||||
|
|
||||||
|
// Offline the view hides non-downloaded rows, so resolving a contiguous position range can span far
|
||||||
|
// more than it shows. Cap the positions resolved per load (and per reconcile) so a sparse large
|
||||||
|
// playlist cannot make the view resolve the whole queue; online every position is shown, so the cap
|
||||||
|
// is never reached.
|
||||||
|
private const val MAX_SCAN_POSITIONS = QUEUE_WINDOW_ROWS * 4
|
||||||
|
|
||||||
data class QueueRow(
|
data class QueueRow(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val position: Long,
|
val position: Long,
|
||||||
@@ -158,7 +164,8 @@ class QueueViewModel(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
val start = (rows.minOfOrNull { it.position } ?: 0L).coerceIn(0, snapshot.size - 1)
|
val start = (rows.minOfOrNull { it.position } ?: 0L).coerceIn(0, snapshot.size - 1)
|
||||||
val end = (rows.maxOfOrNull { it.position } ?: (start + QUEUE_CHUNK - 1)).coerceIn(start, snapshot.size - 1)
|
val rawEnd = (rows.maxOfOrNull { it.position } ?: (start + QUEUE_CHUNK - 1)).coerceIn(start, snapshot.size - 1)
|
||||||
|
val end = rawEnd.coerceAtMost(start + MAX_SCAN_POSITIONS - 1)
|
||||||
val loaded = queueRepository.range(snapshot, start, end).filter(::visible)
|
val loaded = queueRepository.range(snapshot, start, end).filter(::visible)
|
||||||
val reused = reusedIds()
|
val reused = reusedIds()
|
||||||
val updated = loaded.map { rowFor(it, reused) }
|
val updated = loaded.map { rowFor(it, reused) }
|
||||||
@@ -180,9 +187,11 @@ class QueueViewModel(
|
|||||||
val snapshot = queueRepository.snapshot()
|
val snapshot = queueRepository.snapshot()
|
||||||
val collected = mutableListOf<QueueWindowItem>()
|
val collected = mutableListOf<QueueWindowItem>()
|
||||||
var end = first - 1
|
var end = first - 1
|
||||||
while (end >= 0L && collected.size < QUEUE_CHUNK) {
|
var scanned = 0L
|
||||||
|
while (end >= 0L && collected.size < QUEUE_CHUNK && scanned < MAX_SCAN_POSITIONS) {
|
||||||
val start = (end - QUEUE_CHUNK + 1).coerceAtLeast(0)
|
val start = (end - QUEUE_CHUNK + 1).coerceAtLeast(0)
|
||||||
collected.addAll(0, queueRepository.range(snapshot, start, end).filter(::visible))
|
collected.addAll(0, queueRepository.range(snapshot, start, end).filter(::visible))
|
||||||
|
scanned += end - start + 1
|
||||||
end = start - 1
|
end = start - 1
|
||||||
}
|
}
|
||||||
if (collected.isEmpty()) return@withLock
|
if (collected.isEmpty()) return@withLock
|
||||||
@@ -201,9 +210,11 @@ class QueueViewModel(
|
|||||||
if (last >= snapshot.size - 1) return@withLock
|
if (last >= snapshot.size - 1) return@withLock
|
||||||
val collected = mutableListOf<QueueWindowItem>()
|
val collected = mutableListOf<QueueWindowItem>()
|
||||||
var start = last + 1
|
var start = last + 1
|
||||||
while (start < snapshot.size && collected.size < QUEUE_CHUNK) {
|
var scanned = 0L
|
||||||
|
while (start < snapshot.size && collected.size < QUEUE_CHUNK && scanned < MAX_SCAN_POSITIONS) {
|
||||||
val to = (start + QUEUE_CHUNK - 1).coerceAtMost(snapshot.size - 1)
|
val to = (start + QUEUE_CHUNK - 1).coerceAtMost(snapshot.size - 1)
|
||||||
collected.addAll(queueRepository.range(snapshot, start, to).filter(::visible))
|
collected.addAll(queueRepository.range(snapshot, start, to).filter(::visible))
|
||||||
|
scanned += to - start + 1
|
||||||
start = to + 1
|
start = to + 1
|
||||||
}
|
}
|
||||||
if (collected.isEmpty()) return@withLock
|
if (collected.isEmpty()) return@withLock
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ class LibraryDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun downloadedFilterSortsArtistsByTheirDownloadedAlbumCount() =
|
fun downloadedFilterShowsDownloadedAlbumCountsButSortsByTheSyncedCount() =
|
||||||
runTest {
|
runTest {
|
||||||
val sourceId = source()
|
val sourceId = source()
|
||||||
val dao = db.libraryDao()
|
val dao = db.libraryDao()
|
||||||
@@ -448,15 +448,11 @@ class LibraryDaoTest {
|
|||||||
db.downloadDao().upsert(SongDownload(sourceId, it, DownloadStatus.Completed))
|
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).
|
// ar-1 has two downloaded albums, ar-2 one. The list still orders by the synced count
|
||||||
assertEquals(
|
// (so the album-count index stays usable) but reports the downloaded count.
|
||||||
listOf("ar-1", "ar-2"),
|
val filtered = dao.artistsByAlbumCount(sourceId, 0, "", downloadedFilter = 1).page()
|
||||||
dao.artistsByAlbumCount(sourceId, 0, "", downloadedFilter = 1).page().map { it.id },
|
assertEquals(listOf("ar-2", "ar-1"), filtered.map { it.id })
|
||||||
)
|
assertEquals(listOf(1L, 2L), filtered.map { it.albumCount })
|
||||||
assertEquals(
|
|
||||||
listOf("ar-2", "ar-1"),
|
|
||||||
dao.artistsByAlbumCount(sourceId, 0, "").page().map { it.id },
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user