group download status per entity for the library tabs

The detail heroes ask for one entity's status at a time. The list surfaces
need every status on screen at once, so add one grouped flow per tab that
returns a lookup of entity id to counts, which the tiles and rows read the way
song rows read the per-song map.
This commit is contained in:
austinried
2026-10-04 00:30:03 +00:00
parent d89b9e3a47
commit edbcbeb380
4 changed files with 116 additions and 0 deletions
@@ -4,6 +4,7 @@ import androidx.room3.Dao
import androidx.room3.Query
import androidx.room3.Upsert
import com.subtracks.data.model.DownloadArtwork
import com.subtracks.data.model.EntityDownloadStatus
import com.subtracks.data.model.ListDownloadStatus
import com.subtracks.data.model.SongDownload
import kotlinx.coroutines.flow.Flow
@@ -57,6 +58,44 @@ interface DownloadDao {
albumId: String,
): Flow<ListDownloadStatus>
@Query(
"SELECT songs.albumId AS id, " +
"COUNT(songs.id) AS total, " +
"COALESCE(SUM(CASE WHEN song_downloads.status = 'Completed' THEN 1 ELSE 0 END), 0) AS downloaded, " +
"COALESCE(SUM(CASE WHEN song_downloads.status IN ('Queued', 'Running') THEN 1 ELSE 0 END), 0) AS downloading " +
"FROM songs " +
"LEFT JOIN song_downloads ON song_downloads.sourceId = songs.sourceId AND song_downloads.songId = songs.id " +
"WHERE songs.sourceId = :sourceId AND songs.albumId IS NOT NULL " +
"GROUP BY songs.albumId",
)
fun albumStatuses(sourceId: Long): Flow<List<EntityDownloadStatus>>
@Query(
"SELECT albums.artistId AS id, " +
"COUNT(songs.id) AS total, " +
"COALESCE(SUM(CASE WHEN song_downloads.status = 'Completed' THEN 1 ELSE 0 END), 0) AS downloaded, " +
"COALESCE(SUM(CASE WHEN song_downloads.status IN ('Queued', 'Running') THEN 1 ELSE 0 END), 0) AS downloading " +
"FROM songs " +
"JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
"LEFT JOIN song_downloads ON song_downloads.sourceId = songs.sourceId AND song_downloads.songId = songs.id " +
"WHERE songs.sourceId = :sourceId AND albums.artistId IS NOT NULL " +
"GROUP BY albums.artistId",
)
fun artistStatuses(sourceId: Long): Flow<List<EntityDownloadStatus>>
@Query(
"SELECT playlist_songs.playlistId AS id, " +
"COUNT(DISTINCT songs.id) AS total, " +
"COUNT(DISTINCT CASE WHEN song_downloads.status = 'Completed' THEN songs.id END) AS downloaded, " +
"COUNT(DISTINCT CASE WHEN song_downloads.status IN ('Queued', 'Running') THEN songs.id END) AS downloading " +
"FROM playlist_songs " +
"JOIN songs ON songs.sourceId = playlist_songs.sourceId AND songs.id = playlist_songs.songId " +
"LEFT JOIN song_downloads ON song_downloads.sourceId = songs.sourceId AND song_downloads.songId = songs.id " +
"WHERE playlist_songs.sourceId = :sourceId " +
"GROUP BY playlist_songs.playlistId",
)
fun playlistStatuses(sourceId: Long): Flow<List<EntityDownloadStatus>>
@Query(
"SELECT d.sourceId AS sourceId, s.albumId AS albumId, s.artistId AS artistId, " +
"al.id AS albumRow, al.coverArt AS albumCoverArt, " +
@@ -52,6 +52,15 @@ data class ListDownloadStatus(
val complete: Boolean get() = total > 0 && downloaded == total
}
data class EntityDownloadStatus(
val id: String,
val total: Long = 0,
val downloaded: Long = 0,
val downloading: Long = 0,
) {
fun toListStatus(): ListDownloadStatus = ListDownloadStatus(total, downloaded, downloading)
}
data class DownloadArtwork(
val sourceId: Long,
val albumId: String?,
@@ -185,6 +185,16 @@ class DownloadRepository(
DownloadList.Artist -> db.downloadDao().artistStatus(sourceId, refId)
}
fun statuses(
sourceId: Long,
list: DownloadList,
): Flow<Map<String, ListDownloadStatus>> =
when (list) {
DownloadList.Album -> db.downloadDao().albumStatuses(sourceId)
DownloadList.Playlist -> db.downloadDao().playlistStatuses(sourceId)
DownloadList.Artist -> db.downloadDao().artistStatuses(sourceId)
}.map { rows -> rows.associate { it.id to it.toListStatus() } }
suspend fun downloadAll(
sourceId: Long,
list: DownloadList,