feat(slint): playlist collage + custom artwork + edit description

Wires qbz-library into the Slint app (new library_db module) so the
local, Tauri-shared organization data is read/written from the same
per-user library.db (<data_dir>/qbz/users/<id>/library.db). The DB is
opened per-operation on a blocking thread (rusqlite Connection is
!Send).

  - Header collage: the playlist cover is now a 4-up collage of the
    first tracks' covers (Tauri parity); falls back to the server
    image, then the first track, then a placeholder.
  - Custom artwork: owner-only buttons on the cover set/clear a custom
    image. Set copies the picked file into <cache_dir>/qbz/artwork and
    stores the path in playlist_settings.custom_artwork_path (shared
    with Tauri); it's loaded directly from disk and overrides the
    collage.
  - Edit description: the edit modal gains a description field
    (prefilled), saved through update_playlist alongside the name.

cc
This commit is contained in:
vicrodh committed 2026-05-22 08:30:16 -06:00
1 parent 5aae0195f6
commit 5ac5c60c57
7 files changed
+338 -10

No files matched your search

@@ -6,7 +6,7 @@ import { Typography } from "../foundation/typography.slint";
import { Radius } from "../foundation/radius.slint";
import { EditPlaylistState, EditPlaylistActions } from "../state.slint";
import { QbzIcon } from "QbzIcon.slint";
import { LineEdit } from "std-widgets.slint";
import { LineEdit, TextEdit } from "std-widgets.slint";
export component EditPlaylistModal inherits Rectangle {
visible: EditPlaylistState.open;
@@ -71,6 +71,17 @@ export component EditPlaylistModal inherits Rectangle {
}
}
Text {
text: @tr("Description");
color: Theme.text-muted;
font-size: Typography.legal;
}
desc-input := TextEdit {
height: 90px;
wrap: word-wrap;
text <=> EditPlaylistState.description;
}
HorizontalLayout {
spacing: 10px;
// Delete (destructive, left).