Rebuild both Settings panels to match the Tauri app — every option
present, on the correct tab, and fully functional (persisted and
applied to the live player).
Audio: streaming quality, limit-quality-to-device, maximum sample rate,
backend, output device, ALSA plugin, hardware volume, exclusive mode,
reserve DAC, DAC passthrough, force bit-perfect, allow quality
fallback, sync-on-startup, lock output device, and a reset button.
Conditional rows (ALSA plugin, hardware volume, max sample rate, force
bit-perfect, lock output device) are gated on Rust-computed flags.
Playback: continue-after-track, show context icon, gapless, restore
session, resume position, stream uncached, initial buffer size (slider),
streaming only, quality-retry behavior. Note gapless and the streaming
options live on the Playback tab though the qbz-audio struct stores them.
- ui_prefs.rs: JSON store for the frontend-only streaming-quality pref
- QbzSlider primitive for the integer buffer-size control
- volume normalization row removed (Tauri hides it)
Caveat: toggling reserve-DAC persists and is read live, but re-arming
the device reservation guard mid-session needs a player-side API that
does not exist yet; it takes effect on next launch.
cc
Add a navigation history so pages can be walked back and forward.
- nav.rs: a back/forward stack of NavEntry (home, album, artist,
settings); record() on fresh navigation, go_back/go_forward to walk it
- NavButtons: a [<] [>] pair styled like the Discover tab group; inline
beside the Discover tabs and in place of the per-page Back button on
album, artist and settings views
- All navigation routes through Rust (open-album/-artist record entries;
the gear and header menu use NavState.request-settings) so the history
stays accurate; back/forward re-apply entries, re-loading entity pages
- AppShell listens for the mouse back/forward buttons
- can-back / can-forward drive the buttons' enabled state
Also in this round:
- Album header description: render a pre-truncated short string so it
wraps to a couple of lines instead of overflowing the header; the full
text stays in the Read-more modal
- Header queue button uses an ordered-list icon (the previous one read
as a playlist)
cc
The right-controls HorizontalLayout had no explicit width, so a layout
left to fill its parent reported the full header width — the right
anchor `x` then resolved to a negative offset and the queue/lyrics/
hamburger buttons piled up over the Discover tab. Give the row an
explicit width so it anchors correctly.
cc
The header user element is now just the hamburger icon. The menu it
opens leads with a user row showing the display name and the Qobuz
subscription tier, carried through from the login/restore session.
cc
Add a first cut of context menus, opened from the "more" (ellipsis)
button on Discover album cards and on album track rows.
- ContextMenu / ContextMenuItem primitives (PopupWindow-hosted panel)
- AlbumCard: the overlay action buttons are now interactive (they gate
their pointer handling so non-hovered cards still open on click); the
more button opens a menu — Open album, Play, Add to queue, Add to
favorites
- TrackRow: a hover-revealed more button opens a menu — Play, Add to
queue, Add to favorites; AlbumTrackItem and TrackData carry the
track id
- Menu actions bubble up as a single media-action(kind, id, action)
callback through the shell; main.rs logs it for now — playback and
favorites wiring lands with the playback session
- user and list-plus icons
cc
The three header columns shared free space by stretch but kept their
own preferred widths, so the wide tab row pushed the center column —
and the search field with it — off true window center. Anchor the
tabs left and the user element right, and position the search field
absolutely at the window center instead.
cc
Introduce the Settings page, reachable from the Discover gear and the
header menu. Two sub-sections backed by the existing UI-agnostic stores.
- Audio panel: backend, output device and sample-rate dropdowns;
toggles for exclusive mode, DAC passthrough, PipeWire force
bit-perfect, gapless, normalization and quality fallback
- Playback panel: autoplay mode, show context icon, remember session
and resume position
- settings.rs controller owns AudioSettingsStore + PlaybackPreferencesStore
at the shared global path; persists changes and applies audio ones to
the live Player (reload_settings, plus reinit_device for routing-
critical changes); a backend switch re-enumerates output devices
- QbzToggle (switch) and QbzSelect (PopupWindow dropdown) primitives,
SettingRow layout helper, chevron-down icon
- SettingsState global, ContentView::settings, settings-bool /
settings-select callbacks wired through the shell
cc
Clicking an artist (from the album page's artist line) opens the
artist detail view: a circular portrait, name, biography, action
buttons, a Popular Tracks list, and a Discography carousel.
- artist.rs: fetches the artist page via QbzCore::get_artist_page and
maps name, biography (HTML-stripped), portrait URL, top tracks and
releases; the portrait loads through the shared image cache.
- ArtistPageView.slint reuses AlbumCard for the discography (through
the Carousel) and AlbumTrackItem for the track list.
- NavState becomes a three-way ContentView (home / album / artist) and
AppShell routes the content region accordingly. The album page's
artist line and the artist page's release cards are navigable.
cc
- Removes the hairline borders around the content region; the chrome
and content surface colors already delineate the regions cleanly.
- Carousels gain edge-fade gradients: clipped cards dissolve into the
content background at the left and right edges, shown only when there
is more to page in that direction — like Cider's row edges.
cc
The header is now three equal sections — navigation tabs (left), the
search field (center, so it lands at the window center), and the user
element (right) — fixing the tabs stretching to full width under the
search field.
- Nav tabs regain Lucide icons (compass, library, hard-drive,
cassette-tape) and use a 12px label.
- The user element uses a hamburger icon instead of the QBZ logo, which
aliased badly as a scaled PNG.
- Responsive: below 1140px the tabs drop their icons; below 960px the
search field narrows to 70%.
cc
- Replace every Unicode glyph placeholder with Lucide icons via QbzIcon
(player transport, carousel nav, album-card overlay, album-page
actions, gear, search, checkbox, sidebar).
- Header: the search field is centered to the window width and gets a
search icon; the header and player bar now use the elevated surface,
so all chrome (header, sidebar, player bar) shares one color over the
darker content area.
- The sidebar user card moves to the header as a user element (name +
QBZ logo) that opens a dropdown — Settings, Keyboard Shortcuts,
Documentation, Report an Issue, About, plus Log Out and Close. Log Out
clears the session and returns to login; Close quits the app.
- Content ScrollViews disable the horizontal scrollbar — no view scrolls
horizontally, so the phantom reserved lane is gone.
cc
Clicking an album card opens the album detail view: a back button,
the album header (224px artwork, title, artist, and info line — year,
label, genre, track count, duration — plus play / shuffle / favorite /
more action buttons), and the track list with a column header (#,
title, artist, duration, quality).
- album.rs: fetches the album via QbzCore::get_album, maps it (info
line, per-track quality tier, durations) onto the AlbumState global,
and loads the header artwork through the shared image cache.
- AlbumPageView.slint, with NavState driving the shell content region
between Home and the album page.
- Album clicks bubble AlbumCard -> Carousel -> HomeView -> AppShell ->
AppWindow -> main; the back button returns to Home.
cc
- The sidebar now uses the elevated surface (#1a1a1a) over the #0f0f0f
content area, matching the QBZ dark theme (--bg-secondary over
--bg-primary).
- Discover Home gains a proper 56px toolbar with a bottom border: the
tab pill on the left, a "Filter by genre" button and a settings gear
on the right. The toolbar is fixed; only the section carousels scroll
below it.
cc
After sign-in the app loads the real Qobuz discover index and renders
the Home view: a time-based greeting with the user's name, the tab
pill (Home / Editor's Picks / For You), and discover sections — New
Releases, Press Accolades, Ideal Discography, Qobuzissimes, Albums of
the Week — each a horizontally scrolling row of album cards.
- state.slint: AlbumCardItem / DiscoverSection structs, HomeState global.
- discover/: AlbumCard (artwork area, award ribbon, title, artist,
quality badge), SectionRow, HomeView.
- home.rs: discover-index fetch and mapping (award-ribbon priority,
quality string), greeting, and event-loop model application. Unit
tests for ribbon, quality, and greeting logic.
- AppShell content region is now the HomeView.
Album artwork images load in the next increment (artwork pipeline);
cards currently show the elevated placeholder. No fixtures — all data
is the live discover index.
cc
Wires real authentication. "Sign in via Browser" now runs the actual
Qobuz OAuth flow with no Tauri and no WebView: opens the system
browser, captures the authorization code on a one-shot localhost
listener, exchanges it via QbzCore's Qobuz client, and activates a
real per-user session through AppRuntime.
- adapter.rs: SlintAdapter implements FrontendAdapter.
- auth.rs: system-browser OAuth, mirrors v2_start_system_browser_oauth
without Tauri. Includes a query-param parse test.
- main.rs: tokio runtime; sign-in / offline callbacks run real async
work and navigate to the shell on success.
- Sidebar: placeholder playlist fixtures removed.
qbz-slint now depends on qbz-app, qbz-core, and qbz-models.
cc
M1 progress. Adds the post-login shell: HeaderBar (nav tabs and
search), Sidebar (playlists list and user card), PlayerBar (transport,
now-playing, volume), and AppShell composing them with the content
region as a placeholder.
app.slint gains an AppScreen enum; clicking sign-in or start-offline
navigates login -> shell (no real auth yet — that is M2). New layout
foundation tokens (sidebar width, header/player-bar heights) plus
border and hover semantic colors.
cc