feat(slint): offline button on every Qobuz track row + cache-whole-playlist

- TrackRow show-download now defaults to true: every Qobuz track row (album,
  artist, label, playlist, mix, search, favorites) carries the offline
  cloud/check button. Non-Qobuz surfaces (future Local Library / Plex) opt out
  by setting it false.
- Playlist header gains a "make offline" CircleAction -> ("playlist","cache")
  -> offline_cache::cache_playlist (get_playlist -> batch its tracks), mirroring
  the album-header action.

qbz-slint compiles clean.

cc
This commit is contained in:
vicrodh committed 2026-05-28 10:29:43 -06:00
1 parent 6572d6f33f
commit a7f2283c92
4 files changed
+52 -1

No files matched your search

+10
View File
@@ -2551,6 +2551,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
playback::play_tracks(runtime, weak, handle, tracks, idx);
});
}
("playlist", "cache") => {
if let Ok(pid) = id.parse::<u64>() {
offline_cache::cache_playlist(
runtime.clone(),
weak.clone(),
handle.clone(),
pid,
);
}
}
("playlist", "play-all") => {
let runtime = runtime.clone();
let weak = weak.clone();
+26
View File
@@ -310,6 +310,32 @@ pub fn cache_album(
});
}
/// Cache a whole playlist for offline playback: fetch its tracks, then batch.
pub fn cache_playlist(
runtime: Runtime,
weak: slint::Weak<AppWindow>,
handle: tokio::runtime::Handle,
playlist_id: u64,
) {
let inner = handle.clone();
handle.spawn(async move {
let pl = match runtime.core().get_playlist(playlist_id).await {
Ok(p) => p,
Err(e) => {
log::error!("[qbz-slint] cache playlist {playlist_id} failed: {e}");
crate::toast::error_weak(&weak, "Couldn't load that playlist");
return;
}
};
let tracks: Vec<qbz_models::Track> = pl.tracks.map(|c| c.items).unwrap_or_default();
if tracks.is_empty() {
crate::toast::error_weak(&weak, "This playlist has no playable tracks");
return;
}
cache_tracks(runtime, weak, inner, tracks);
});
}
/// Remove a track's offline copy (DB row + on-disk bundle/file + library row).
pub fn remove_cached(
_runtime: Runtime,
@@ -375,6 +375,18 @@ export component PlaylistView inherits Rectangle {
}
}
}
// Make the whole playlist available offline.
VerticalLayout {
horizontal-stretch: 0;
alignment: center;
CircleAction {
icon: @image-url("../assets/icons/cloud-download.svg");
enabled: PlaylistState.tracks.length > 0;
clicked => {
root.media-action("playlist", PlaylistState.id, "cache");
}
}
}
// Edit (rename / delete) — only the user's own.
if PlaylistState.is-owner: VerticalLayout {
horizontal-stretch: 0;
@@ -32,7 +32,10 @@ export component TrackRow inherits Rectangle {
in property <bool> show-artwork: true;
in property <bool> show-album: false;
in property <bool> show-favorite: false;
in property <bool> show-download: false;
// On by default: every Qobuz track row carries the offline cloud/check
// button. A non-Qobuz surface (future Local Library / Plex rows, which are
// already local) should set this false.
in property <bool> show-download: true;
in property <bool> multi-select-mode: false;
// Custom-order reorder controls (up/down chevrons) at the leading
// edge — used by the playlist custom sort.