Flat mode now has the full toolbar: search, sort (artist/title/year),
group-by (off/letter/artist) and a grid/list view toggle, driven by a
derive_folders() pass that mirrors favorites::derive_albums over the
directory-grouped album set (folders-visible / folders-grouped).
Tree mode is a new two-pane filesystem browser: a flattened FolderNode
list in the left rail (lazy one-level expand via list_folder_children,
collapse drops the descendant block, recursive track counts gate the
chevron) and a detail pane on the right showing the selected folder's
direct tracks plus immediate subfolders, with Play all (recursive) and
per-track play scoped to the folder's direct list. A flat/tree segmented
toggle switches modes; the tree loads its roots lazily on first switch.
Slint has no native TreeView, so the tree is a depth-indented ListView of
visible nodes spliced on expand/collapse. No pills (ADR-008): underline
tabs, small-radius rectangles and an accent selection bar.
cc
LocalLibrary track rows (Tracks tab + local album detail) no longer carry the
favorite or offline-cache columns — they don't apply to local content. Instead
they show a subtle per-source indicator (local -> hard-drive tinted; qobuz
offline / plex -> their mark), small + flat rather than the bold album-card
badge (mirrors Tauri's track-row local indicator). TrackItem gains a `source`
field, set by every constructor (Qobuz surfaces -> "qobuz"; map_local_track ->
local/qobuz/plex); TrackRow gains `show-source`.
Also fixes Qobuz AlbumView: the track list had a Favorite column header but the
rows never rendered the heart (show-favorite defaulted false). AlbumPageView
now sets show-favorite + show-download for Qobuz albums (matching the header)
and the source indicator for local albums, with the column header switched to
match each.
cc
Fills the last empty tab: a full-loaded grid of artists (get_artists_with_filter)
with album/track counts, inline circular cards (placeholder icon for now). All
four Local Library tabs (Albums / Tracks / Folders / Artists) now browse. The
navigate match is exhaustive over LibTab. Artist images, click-to-detail, and
name-merge dedup (Tauri's artistMergeResult) are later slices.
cc
Fills the Folders tab: a full-loaded grid of albums grouped by directory
(get_albums_with_full_filter), via the shared AlbumCollectionView (grid +
source badge), covers loaded from disk, loaded once on first visit. Clicking
a folder album opens its detail + plays it — navigate_local_album and
play_local_album now resolve tracks via fetch_album_tracks_blocking, which
tries the metadata grouping (Albums tab) then the folder grouping (Folders
tab), so both album views work. New ArtworkTarget::LocalFolderCard applies
covers to the folders model.
Tree mode (two-pane lazy folder tree) + folder search/sort are later slices.
cc
The Tracks list scrollbar sat inside the 32px content padding (too far into
the content). Move it to the view's true right edge — the position the Albums
grid already uses, which is the standard for chrome-bezel views: a padded
VerticalLayout holds the ListView while the ListScrollbar floats at the
full-width edge.
cc
Adds the Tracks browse tab. Each page is a search_with_filter_page query
(new paged variant of search_with_filter) appended on scroll-near-bottom, so
the list never materializes the whole table — the documented ~16K-row Tracks
freeze. Reuses the shared TrackRow in a virtualized ListView + ListScrollbar
(the Favorites Tracks pattern) and the Albums controller's generation-guard
(TRACKS_GEN) so a search/retry can't be clobbered by a stale in-flight page.
- qbz-library: search_with_filter_page(query, offset, limit, include_qobuz,
exclude_network) — same ordering as search_with_filter, LIMIT/OFFSET.
- local_library.rs: map_local_track (LocalTrack is Send -> crosses
spawn_blocking; TrackItem built on the UI thread), fetch_tracks_page,
apply/append, reload/ensure/load_more (TRACKS_GEN-guarded).
- LocalLibraryView.slint: Tracks body (ListView + TrackRow, show-artwork off
per Tauri's perf default, show-favorite/show-download off) + a search
toolbar + loading/error/empty states.
- state.slint + main.rs: tracks state/actions + lazy load on first visit +
search/load-more/retry wiring.
Group-by, multi-select/bulk, and per-row playback land with the source-aware
playback slice (track-action is a stub, like Albums). Built green
(cargo check -p qbz-slint); runtime smoke-test pending.
cc
Two fixes from the first Albums-grid test pass.
Offline/folder covers (the reported "cover exists in the folder but isn't
shown"): some albums — offline-cached CMAF bundles and folder downloads —
have no artwork_path in the index even though a cover.jpg sits in the track
folder (older offline-cache downloads didn't backfill it). Add a frontend-
agnostic LibraryDatabase::resolve_album_cover_fallback(group_key) that finds
a representative track, derives its folder (the path itself for a CMAF bundle
dir, else the parent), and returns <folder>/cover.jpg when it exists. The
Slint Albums mapper calls it whenever the album has no artwork. Verified
against the live index: it resolves the folder covers that exist on disk
(FLAC-layout + CMAF-with-cover). Older CMAF bundles that never downloaded a
cover (segments only) still show the placeholder — those need a cover
re-fetch (offline-cache maintenance), tracked separately.
Source badge: the Local Library album card now shows the always-visible
source badge inside the artwork (bottom-right) — a hard-drive glyph for local
files, the Qobuz logo for offline copies, the Plex logo for Plex. Added
AlbumCard.show-source-badge (default off; threaded through AlbumCollectionView
/AlbumGrid) + AlbumCard.source; album_map now carries the real source and
map_local_album maps user->local / qobuz_download / plex. Small rounded
square, not a pill (ADR-008). Logos copied into the Slint icon assets.
Built green (cargo check -p qbz-slint); runtime smoke-test pending.
cc
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
The nav-scaffolding view (c50ae171) invented its own chrome: a title+stats
header with no NavButtons (so no back/forward history nav), plus a tab bar
of border-radius:18px pill chips — an ADR-008 violation. Rebuild it 1:1 on
the app's mandatory fixed-chrome header (the same FavoritesView/Discover
use):
- Row 1: NavButtons (back/forward) + "Local Library" title (left), the tab
menu floated right. Tabs are underline tabs (LibTab/LibTabMenu mirroring
FavTab/FavTabMenu) — no pills.
- The settings gear becomes a standalone icon-only circle matching
NavButtons (the one circular shape ADR-008 permits), routing to
Settings > Local Library.
- Row 2 (per-tab actions + toolbar) is established with vertical-stretch:0
so it doesn't inflate while empty; filled per slice (Albums next).
- 1px divider, then a single scrolling content area with a placeholder.
Wiring (select-tab / open-settings, nav, mount) is unchanged — only the
.slint chrome was rebuilt.
cc