feat(locallibrary): Albums tab — server-paginated chunked grid
First Local Library data slice. The Albums tab browses the metadata-grouped local albums via the performant server-paginated path (the same query Tauri's chunked store uses), reusing the shared AlbumCollectionView grid — no new rendering. Scales past the documented ~16K-row Tracks freeze by never materializing the full set. - local_library.rs: map_local_album (LocalAlbum -> the plain album_map AlbumCard, Send-safe; the non-Send slint::Image conversion via to_item happens on the UI thread), local_quality (Hz -> kHz), sort_params; a blocking fetch_albums_page over LibraryDatabase::get_albums_metadata_page (spawn_blocking); apply/append + reload/ensure/load_more driven by an ALBUMS_GEN generation guard so a search/sort/retry can't be clobbered by a stale in-flight page. - LocalLibraryView.slint: Albums body reusing AlbumCollectionView (grid, show-favorite: false), a search + sort toolbar (both server-side), auto load-more on scroll-near-bottom (DiscoverBrowse pattern), and loading / error+retry / empty states. - Local covers: ArtworkTarget::LocalAlbumCard + spawn_local_loads resolve the on-disk cover path through the source-aware ArtworkRef::LocalFile pipeline; the target carries the generation so a cover decoded after a reload is dropped instead of landing on a replaced row. - state.slint: LocalLibraryState album fields + LocalLibraryActions callbacks. - main.rs: navigate_local_library lazily loads page 1 on first visit; the on_albums_* callbacks wire search/sort/load-more/retry (open-album / open-artist / album-action are TODO no-ops until the detail + playback slices). List/group/A-Z/quality filters, album detail, and playback are later slices. include_qobuz_downloads mirrors the show_in_library setting default (true). Built green (cargo check -p qbz-slint); runtime smoke-test pending. cc
This commit is contained in:
5 files changed
+677
-11
No files matched your search
@@ -344,6 +344,25 @@ export global LocalLibraryState {
|
||||
in property <int> artist-count: 0;
|
||||
in property <int> track-count: 0;
|
||||
in property <int> folder-count: 0;
|
||||
|
||||
// --- Albums tab (server-paginated, metadata-grouped local albums) ----
|
||||
// `albums` is the accumulated paged set (also the artwork target). Sort
|
||||
// + search are pushed to SQL (the performant path); paging fetches the
|
||||
// next chunk on scroll. List / group / A-Z / filters land with the next
|
||||
// slice — this slice ships the chunked grid.
|
||||
in property <[AlbumCardItem]> albums: [];
|
||||
in property <int> albums-total: 0;
|
||||
in property <bool> albums-loading: false; // initial page fetch
|
||||
in property <bool> albums-loading-more: false; // subsequent pages
|
||||
in property <bool> albums-has-more: false;
|
||||
in property <bool> albums-load-failed: false;
|
||||
in-out property <int> albums-next-offset: 0;
|
||||
in-out property <string> albums-search: "";
|
||||
// "artist-asc" | "artist-desc" | "title-asc" | "title-desc"
|
||||
// | "year-desc" | "year-asc"
|
||||
in-out property <string> albums-sort: "artist-asc";
|
||||
// "grid" | "list" — the list view toggle lands with the next slice.
|
||||
in-out property <string> albums-view-mode: "grid";
|
||||
}
|
||||
|
||||
export global LocalLibraryActions {
|
||||
@@ -352,6 +371,23 @@ export global LocalLibraryActions {
|
||||
callback select-tab(string /* "albums"|"artists"|"folders"|"tracks" */);
|
||||
// Open Settings > Local Library (the gear button — management lives there).
|
||||
callback open-settings();
|
||||
|
||||
// --- Albums tab ---
|
||||
// Re-query page 1 with the current search text (server-side LIKE).
|
||||
callback albums-search(string /* query */);
|
||||
// Set the sort key + re-query page 1 (server-side ORDER BY).
|
||||
callback albums-set-sort(string /* sort key */);
|
||||
// Fetch + append the next page (driven by scroll-near-bottom).
|
||||
callback albums-load-more();
|
||||
// Retry after a load error.
|
||||
callback albums-retry();
|
||||
// Open a local album's detail view (lands with the album-detail slice).
|
||||
callback open-album(string /* album id */);
|
||||
// Open an artist (lands with the Artists slice).
|
||||
callback open-artist(string /* artist id */);
|
||||
// Per-card action (play / queue / play-next) — lands with the playback
|
||||
// slice. Wired now so the shared AlbumCollectionView contract is honored.
|
||||
callback album-action(string /* album id */, string /* action */);
|
||||
}
|
||||
|
||||
// Global toast state, driven by crate::toast. The Toast overlay (mounted
|
||||
|
||||
Reference in new issue
Block a user