feat(slint): local playlist reorder and favorite/hide organization

Reorder: repo gains reorder(from, to) with remove-then-insert semantics
and contiguity preservation (5 tests); the local detail wires the existing
per-row chevron path (shown under Default sort - the repo order IS the
editable order; the Custom sort entry hides for locals since the custom-
order sidecar is u64-keyed) with optimistic model swap and off-thread
persistence.

Organization: additive favorite/hidden columns on local_playlists
(pragma-guarded migration + 2 tests incl. pre-migration shape), manager
cards render real heart/eye state and locals participate in the
visible/hidden toolbar filter, hidden locals drop from the sidebar while
staying reachable through the manager's hidden filter. Folder membership
for locals stays out of scope (folder tables are Qobuz-keyed).

main.rs wiring for these actions rides the next commit (shared file with
the in-flight favorites-rail batch).

cc
This commit is contained in:
vicrodh committed 2026-06-10 02:10:33 -06:00
1 parent 7d5f6658df
commit 23129cb98e
6 files changed
+433 -21

No files matched your search

@@ -532,8 +532,11 @@ export component PlaylistView inherits Rectangle {
chosen => { PlaylistActions.set-sort("duration"); }
}
// Manual order — enables the per-row
// up/down reorder controls.
SortOption {
// up/down reorder controls. Hidden on
// LOCAL playlists (B2): their Default
// order IS the editable repo order, so
// a separate custom sidecar is moot.
if !PlaylistState.is-local: SortOption {
label: @tr("Custom");
active: PlaylistState.sort-field == "custom";
chosen => { PlaylistActions.set-sort("custom"); }
@@ -663,7 +666,11 @@ export component PlaylistView inherits Rectangle {
show-artwork: true;
show-album: true;
show-favorite: true;
show-reorder: PlaylistState.sort-field == "custom";
// Custom sort (Qobuz sidecar order) — or, on a LOCAL
// playlist, the Default sort: its natural order IS the
// editable repo order (B2), written via repo::reorder.
show-reorder: PlaylistState.sort-field == "custom"
|| (PlaylistState.is-local && PlaylistState.sort-field == "default");
multi-select-mode: PlaylistState.multi-select-mode;
media-action(kind, id, action) => {
if (action == "play") {