Qobuz playlist snapshot, captured opportunistically with zero new API traffic: every online sidebar/manager list load upserts id+name+owner+ track_count for the user's playlists; opening a playlist detail online full-replaces its membership track ids (refusing playlists never listed, so viewed public playlists don't land). Offline consumers: synthesized sidebar/manager entries resolve the persisted name (killing the cold-start 'Playlist (N local)' fallback when a snapshot exists), and the mixed- playlist offline detail now renders the snapshot tracks that are playable (snapshot intersect cached intersect grace) from the offline-cache index - snapshot block first in snapshot order, sidecar local/plex block after. D11 availability widens: a playlist with zero sidecar rows but cached snapshot tracks now shows offline. 4 repo tests. Offline favorites rail: the Favorites placeholder gains an 'Available offline (N)' block - disk-cached favorite ids intersected with the offline-cache READY index and LocalLibrary qobuz_download copies, compact rows with the offline cover chain, click plays the rail as a queue through the cache tier. Shared OfflinePlaceholder gains an @children slot; only the Favorites mount injects the rail. Single commit: the two features interleave in main.rs/state wiring and ship together to keep every commit compiling. cc
50 lines
2.0 KiB
Plaintext
50 lines
2.0 KiB
Plaintext
// B9 — "playable favorites" rail, shown INSIDE the offline placeholder on
|
|
// the Favorites view only (the AppShell mounts it as the placeholder's
|
|
// children — ADR-010: both `if`s live at the AppShell mount site). Lists
|
|
// the favorite tracks that are still playable offline (offline-cache READY
|
|
// copies + library qobuz_download rows, intersected with the disk-seeded
|
|
// favorite set on the Rust side) as compact SlimCard rows; clicking a row
|
|
// plays the whole rail from there through the offline-capable queue path.
|
|
//
|
|
// Collapses to nothing while the list is empty, so the placeholder then
|
|
// reads exactly like the generic one.
|
|
|
|
import { Theme } from "../foundation/semantic-colors.slint";
|
|
import { Typography } from "../foundation/typography.slint";
|
|
import { OfflineFavoritesState, OfflineFavoritesActions } from "../state.slint";
|
|
import { SlimCard } from "../discover/SlimCard.slint";
|
|
import { ListView } from "std-widgets.slint";
|
|
|
|
export component FavoritesOfflineRail inherits VerticalLayout {
|
|
init => {
|
|
OfflineFavoritesActions.load();
|
|
}
|
|
|
|
property <int> count: OfflineFavoritesState.tracks.length;
|
|
|
|
if root.count > 0: Rectangle { height: 28px; }
|
|
if root.count > 0: HorizontalLayout {
|
|
alignment: center;
|
|
VerticalLayout {
|
|
spacing: 8px;
|
|
Text {
|
|
text: @tr("Available offline") + " (\{root.count})";
|
|
color: Theme.text-primary;
|
|
font-size: Typography.body;
|
|
font-weight: Typography.semibold;
|
|
}
|
|
ListView {
|
|
width: 480px;
|
|
// Up to five 60px rows visible; longer lists scroll inside.
|
|
height: Math.min(root.count, 5) * 60px;
|
|
for item in OfflineFavoritesState.tracks: SlimCard {
|
|
item: item;
|
|
clicked(id) => {
|
|
OfflineFavoritesActions.play(id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|