Files
qbz/crates/qbz-slint/ui/favorites/FavoritesOfflineRail.slint
T
vicrodh 81587f4d17 feat(slint): playlist snapshot (names+membership) and offline favorites rail
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
2026-06-10 02:27:54 -06:00

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);
}
}
}
}
}
}