address the bulk download review

- Cancelling a list while its download loop was still enqueueing missed every
  song queued after the cancel looked. The loop now holds the lock for the whole
  queue, so a cancel waits for it to finish and then removes all of it. That
  needed the enqueue helper split into a locked entry point and a body the loop
  can call while already holding the lock — calling the locked one from inside
  the lock deadlocked, which is what hung the tests.
- An empty resolved list now says so instead of doing nothing.
- One song failing to enqueue no longer aborts the rest of the batch.
- The artist actions resolve through the albums the artist page lists, matching
  what is on screen, rather than through songs.artistId, which for a guest on a
  compilation enqueued nothing.
- Bulk actions are one `applyAction` on the repository, so the three view models
  and both screens stop repeating the same dispatch.
- Tests: the playlist and artist resolve paths, a Running row counted as
  downloading, the action dispatch, and the action rule moved to a plain unit
  test.
This commit is contained in:
austinried
2026-10-04 00:30:02 +00:00
parent b2b92a388e
commit bf561075a2
15 changed files with 178 additions and 99 deletions
@@ -3,6 +3,7 @@ package com.subtracks.ui.library
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.subtracks.data.model.Album
import com.subtracks.data.model.BulkDownloadAction
import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.model.Disc
import com.subtracks.data.model.DownloadList
@@ -46,18 +47,10 @@ class AlbumDetailViewModel(
.flatMapLatest { downloadRepository.status(it, DownloadList.Album, albumId) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), ListDownloadStatus())
fun downloadAll() {
viewModelScope.launch { downloadRepository.downloadAll(sourceId.first(), DownloadList.Album, albumId) }
}
fun cancelDownloads() {
viewModelScope.launch { downloadRepository.cancelAll(sourceId.first(), DownloadList.Album, albumId) }
}
fun deleteDownloads() {
fun onDownloadAction(action: BulkDownloadAction) {
viewModelScope.launch {
downloadRepository.deleteAll(sourceId.first(), DownloadList.Album, albumId)
playbackController.refreshMediaItems()
downloadRepository.applyAction(sourceId.first(), DownloadList.Album, albumId, action)
if (action == BulkDownloadAction.Delete) playbackController.refreshMediaItems()
}
}