Files
qbz/crates/qbz-slint/ui/state.slint
T
vicrodh 12ed5a7c4a feat(slint): browser-like back/forward navigation history
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
2026-05-18 20:17:54 -06:00

149 lines
5.1 KiB
Plaintext

// Shared UI state — structs and globals the Rust controllers populate.
//
// The Rust side builds these models on a worker thread, then sets them
// on the global from the Slint event loop (see src/home.rs, src/main.rs).
export struct AlbumCardItem {
id: string,
title: string,
artist: string,
genre: string, // shown in the hover overlay
year: string, // shown in the hover overlay
quality-tier: string, // "hires" | "cd" | "" — drives the badge icon
quality-label: string, // "Hi-Res: 24-bit / 96 kHz" — badge hover tooltip
ribbon: string,
ribbon-kind: string, // "press" | "qobuzissime" | "albumOfTheWeek" | ""
artwork-url: string,
artwork: image, // empty until the artwork pipeline resolves it
}
export struct DiscoverSection {
title: string,
albums: [AlbumCardItem],
}
// Compact "slim" card item — a small thumbnail with a title/subtitle,
// optionally rank-numbered (Popular albums, Recently Played).
export struct SlimItem {
id: string,
title: string,
subtitle: string,
rank: string, // "" = no rank
artwork-url: string,
artwork: image,
}
// Discover / Home screen state.
export global HomeState {
in property <[DiscoverSection]> sections: [];
in property <[SlimItem]> popular: [];
in property <[SlimItem]> recent: [];
in property <[AlbumCardItem]> recent-albums: [];
in property <bool> loading: false;
}
export struct AlbumTrackItem {
id: string,
number: string,
title: string,
artist: string,
duration: string,
quality-tier: string,
explicit: bool,
}
// Album detail screen state.
export global AlbumState {
in property <string> id;
in property <string> title;
in property <string> artist;
in property <string> artist-id;
in property <string> info-line;
in property <string> quality-tier;
// "24-bit / 96 kHz" — quality-badge detail line.
in property <string> quality-detail;
// Editorial description / review (HTML stripped). May be empty.
in property <string> description;
// Truncated description for the header; full text lives in the modal.
in property <string> description-short;
in property <image> artwork;
// Artwork-derived tint for the header gradient.
in property <color> header-color: #181820;
in property <string> label;
in property <[string]> awards: [];
in property <[AlbumTrackItem]> tracks: [];
in property <bool> loading: false;
}
// Album-view actions wired to Rust callbacks.
export global AlbumActions {
// Filter the visible track list by a query (client-side).
callback search(string);
}
// Which content view the shell shows.
export enum ContentView { home, album, artist, settings }
// Settings screen state. Audio and Playback preferences are loaded from
// the persistence stores by the Rust settings controller and pushed here;
// changes flow back through the settings-bool / settings-select callbacks.
export global SettingsState {
// Sub-section: 0 = Audio, 1 = Playback.
in-out property <int> section: 0;
in property <bool> loading: true;
// Audio — dropdowns. Each list is paired with a selected index; the
// Rust controller owns the index -> value mapping.
in-out property <[string]> backends: [];
in-out property <int> backend-index: 0;
in-out property <[string]> devices: [];
in-out property <int> device-index: 0;
in-out property <[string]> sample-rates: [];
in-out property <int> sample-rate-index: 0;
// Audio — toggles.
in-out property <bool> exclusive-mode: false;
in-out property <bool> dac-passthrough: false;
in-out property <bool> pw-force-bitperfect: false;
in-out property <bool> gapless: true;
in-out property <bool> normalization: false;
in-out property <bool> allow-quality-fallback: false;
// Playback.
in-out property <[string]> autoplay-modes: [];
in-out property <int> autoplay-index: 0;
in-out property <bool> show-context-icon: false;
in-out property <bool> persist-session: false;
in-out property <bool> resume-position: false;
}
export global NavState {
in-out property <ContentView> view: ContentView.home;
// Browser-like history flags, driven by the Rust nav module.
in property <bool> can-back: false;
in property <bool> can-forward: false;
// Navigation requests routed to Rust so history is recorded.
callback request-back();
callback request-forward();
callback request-settings();
}
// Artist detail screen state.
export global ArtistState {
in property <string> name;
in property <string> bio;
in property <image> artwork;
// Artwork-derived tint for the header gradient.
in property <color> header-color: #181820;
in property <[AlbumTrackItem]> top-tracks: [];
// Releases grouped into titled sections (Albums, EPs & Singles, ...).
in property <[DiscoverSection]> release-sections: [];
in property <bool> loading: false;
}
// Authenticated user, for the header user element.
export global SessionState {
in property <string> user-name: "";
in property <string> subscription: "";
}