Commit Graph
161 Commits
Author SHA1 Message Date
vicrodh a0f5cf2bf5 feat(shell): metaball ambient + translucent bars/panels/controls, drop carousel fades
Smoke rounds 3-4 (owner feedback). Checkpoint during iteration.

Ambient (the big one): rewrote ambient.wgsl from translating gaussian blobs to a
METABALL field (r²/d² summed + smoothstep iso-surface) with 2-octave domain warp
— lobes fuse/stretch/split like an amoeba / lava lamp (the Cider motion that was
missing), faster clock, more contrast.

Surfaces made background-aware (translucent when the dynamic background is on):
- Search results view (root + toolbar), artist Network panel + its tab-row
  header (transparent to avoid double-translucent compounding), JUMP TO bar
  (JumpNavBar bar-bg passed in — can't import ShellState without a cycle).
- Discover toolbars + tab pill + BrowseHeaderTools; SearchResultsView toolbar.
- CircleAction (shared: playlist/album/artist/etc. action buttons) on-surface
  secondary fill goes glass; playlist Sort dropdown; QbzSelect closed control.
- New app-background-bar-alpha knob (0.3, env QBZ_BG_BAR_ALPHA): thin bars go
  MORE transparent than panels (surface-alpha 0.5).
- Content well: frosted tint (0.22) + 1px hairline border → distinct panel.
- Album/Artist header gradient auto-suppressed under the dynamic background
  (they clashed); header text stays light on the dynamic backdrop.
- Discover carousel edge-fade "shadows" hidden when active (Carousel /
  PlaylistCarousel / ArtistCarousel / PinnedCarousel).

Base: 76ea5a82. Prior checkpoint: 4e405338.

cc
2026-07-17 08:08:33 -06:00
vicrodh 4e40533870 feat(shell): dynamic background shows through content area + livelier ambient
Smoke round 2 (owner feedback: content area was an opaque black slab, motion
imperceptible, ambient≈blurred).

- Content-area sweep: 27 content-view roots go transparent when the app
  background is active (was opaque Theme.surface-main covering the background) —
  Home/Discover/Album/Artist/Search-adjacent/Favorites/Playlist/LocalLibrary/
  MyQBZ/managers/etc. Content well (AppShell) transparent too.
- SongCard (NPB classic), search input box, cortinilla panel go translucent so
  they stop reading as opaque slabs over the background.
- ambient.wgsl: much faster + bigger blob travel + stronger domain warp +
  brighter/more saturated so the flow is obviously moving and clearly distinct
  from the blurred-art mode.
- Defaults: dim 0.35, surface-alpha 0.5.

Checkpoint during smoke iteration (owner-requested). Base: 76ea5a82.

cc
2026-07-17 02:42:59 -06:00
vicrodh 76ea5a82bb feat(shell): app-wide dynamic album-art background ("modo Cider")
Opt-in album-art background composited behind the whole shell, wgpu-tier
only. Appearance mode picker: Off | Ambient (GPU shader) | Blurred art.

- ambient.wgsl: new calm, low-energy album-colored scene (mode 7), drifting
  mesh-gradient of the primary/secondary/accent triad, no beat/transient.
  Registered in shader_underlay SHADER_SOURCES[5] + render_frame idx math.
- state.slint: AppearanceState app-background {modes,mode-index,available,
  dim,surface-alpha}; ImmersiveState.app-shader-mode (derived 1->7);
  ShellState.app-background-active (mode>0 && wgpu && has-track).
- visualizer.rs: drain renders shader-mode when immersive OPEN, else
  app-shader-mode (7=ambient) into the same shader-texture sink.
- AppShell: background layer at root z-bottom (Ambient=shader texture,
  Blurred=ImmersiveAtmosphere) + tunable dark scrim; shell chrome surfaces
  go translucent when active; viz-should-run extended to drive the drain.
- Whole-shell translucency: Sidebar/HeaderBar/PlayerBar(Small)/QueueSidebar/
  LyricsSidebar/SidebarNowPlayingDock + AppShell content well/frame/column.
- ui_prefs: persisted `app_background` (off|ambient|blurred), String-key
  pattern; appearance-select("app-background") write-back.
- Live-tunable knobs QBZ_BG_DIM / QBZ_BG_SURFACE_ALPHA (seeded at startup)
  so the look is dialed in one smoke session without a rebuild.
- i18n: 8 locales for the picker + warning; reduce-motion / D4 (no-track ->
  opaque theme) handled via derived active flag.

Design + signed decisions: qbz-nix-docs/specs/2026-07-16-app-wide-dynamic-background.md

cc
2026-07-16 23:50:40 -06:00
vicrodh c4ddca0223 fix(input): gate hotkeys while text inputs are focused
A use-site `changed has-focus` on a std-widgets LineEdit/TextEdit never
fires — has-focus is an alias into the inner TextInput (slint#7747) — so
typing a letter that doubles as a shortcut ran the action instead of
inserting the character. Sweep every text-input surface (search, import,
create/edit playlist & folder, tag editor, colour picker, settings
fields, QConnect dev modal, kiosk shell) and drive
UiFocusState.text-input-focused from a `guard-focused` probe property
that the change tracker does observe.

cc
2026-07-16 20:37:57 -06:00
vicrodh 134eddc1ae fix(share): resolve Song.link/Album.link via Deezer ISRC/UPC (#514)
The 2.0 port kept only the Odesli-by-URL path, which rejects Qobuz URLs
(400 could_not_resolve_entity), so album.link/Song.link never resolved
while the raw Qobuz link still copied fine. Restore the Tauri behaviour:
look the track up on Deezer by ISRC (album by UPC, with a leading-zero
retry) and build song.link/d/{id} / album.link/d/{id} from the match.

cc
2026-07-16 20:37:51 -06:00
vicrodh 8e57864bee fix(shell): #618 window identity/geometry + single-instance present; Plex refresh seed; wire discover/pinned state
Persist the Wayland app_id (set_xdg_app_id) and window geometry/maximized across
tray-hide and miniplayer round-trips so the pinned taskbar icon keeps grouping
and the size/position survive (#618); route the single-instance raise and MPRIS
Raise through a miniplayer-aware present() plus a dedicated D-Bus Present method.
Seed the Local Library Plex refresh button after login (not before, when the
per-user store is unbound). Also the shared wiring these features need in
main.rs / state.slint / app.slint / home.rs / artwork.rs (pinned globals + store
seed + mixed-artwork target, playlist-browse nav, sub-genre reload) and the
bundled i18n strings.

cc
2026-07-16 16:31:51 -06:00
vicrodh 288e982b44 fix(ui): sidebar dock margins, queue count footer, macOS NPB-small corner
Homologate the large-dock cover's side margins (16px each vs the visible content
bezel) and add a 4px bottom gap by trimming the FFT band 2px top/bottom. Move the
queue count out of the "Up Next" header into a fixed footer ("Showing X of Y
tracks", dropping the redundant "left"). On macOS, inset the flush-left NPB-small
art so the native rounded window corner stops clipping it.

cc
2026-07-16 16:31:39 -06:00
vicrodh f26d3e5e1d feat(settings): searchable theme dropdown
Enable the searchable QbzSelect on the theme picker (36 themes) — the search box
the migration deferred. Rides the #616 theme-filter (icon swap + list narrowing,
already on pre-release); the search filters within the active All/Dark/Light
facet.

cc
2026-07-16 16:31:39 -06:00
vicrodh 7138dafbdb feat(home): Pinned section — per-user store, mixed carousel, pin affordances
Users pin albums/artists/playlists to a configurable "Pinned" section on Home
and For You. New per-user SQLite pinned-items store (headless in qbz-app +
lifecycle wrapper), a mixed PinnedCarousel dispatching Album/ArtistGrid/Playlist
cards by kind, a rotated pin glyph (hover-only) on those cards, and Pin/Unpin
from the playlist header and the album/artist context menus. Local/Plex albums
resolve to their Local Library page (id-format routing) and render their real
covers via the mixed-source artwork dispatcher.

cc
2026-07-16 16:30:30 -06:00
vicrodh d87ae8a65f feat(discover): ArtistGridCard for mixed carousels, used app-wide
New 200x246 artist card (framed round portrait, follow/play/more hover overlay,
centered wrap-capable name with an optional reco subtitle) matching the album/
playlist card footprint. ArtistCarousel renders it by default across the app
(search "Most popular" hero included); the legacy 160x220 ArtistCard stays for
the label/award carousels whose artist actions don't apply.

cc
2026-07-16 16:30:30 -06:00
vicrodh 64920a76e4 feat(discover): Qobuz Playlists "View all" page + shared header tools
Port the Tauri playlist "View all": a new PlaylistBrowseView with the category
tag bar, search filter, genre filter and grid/list toggle, extracted into a
shared BrowseHeaderTools and a reusable PlaylistListRow. Restores the "Popular
albums" see-all and aligns PlaylistCarousel's "View all" affordance with the
standard carousels.

cc
2026-07-16 16:30:12 -06:00
vicrodh 897ba7128c feat(qbz-ui): settings export modal + Developer row (04 §4.2)
Add the desktop "Export settings…" surface for the qbzd daemon epic (T18):
a Developer-settings row that opens a modal with the single default-off
"Include Qobuz login and integration tokens" gate, its warning line, and a
Cancel/Export footer. Confirm() is a Rust callback (wired next). New
SettingsExportState/SettingsExportActions globals, exported from app.slint
so the Rust layer binds them, and the modal mounted in AppShell. New strings
translated across all 8 locales (en es de fr pt ru ja nl).

cc
2026-07-15 07:50:27 -06:00
vicrodh 8c50c16faa fix(offline): clarify that Clear cache keeps downloaded albums
After #606 the offline Clear-cache purges only the transient cache dirs (tracks/tracks-cmaf/artwork), never the organized downloaded albums — those are removed per-item from the offline manager. The old copy ('Remove every downloaded track. This cannot be undone.') was misleading. Relabels the row 'Clear cache', rewrites the description to say downloads are kept and point to the manager, and softens the toasts to 'Cache cleared' / 'Couldn't clear the cache'. 8 locales.

cc
2026-07-13 21:01:48 -06:00
vicrodh ba7be747a7 fix(immersive): persist volume on drag-end
The immersive VolumeBar only called set-volume (live) and never persist-volume, so a volume set in the immersive view was lost on restart/track-change. Adds a released(float) callback emitted on pointer-up, wired to NowPlayingState.persist-volume — parity with the NPB sliders. Pure .slint; persist-volume already exists in Rust.

cc
2026-07-13 21:01:48 -06:00
vicrodh 41f8578b78 feat(home): sort control for the Library Albums rail
Adds a compact dropdown in the Library Albums (favoriteAlbums) row header, left of the page chevrons: Recently added (default), First added (reverse), Random (shuffle). Reorders the cached base list in Rust with no re-fetch and re-fires artwork by the new index. Also corrects the stale HomeView comment that claimed the recently-played refresh lives in the toolbar (it is a row-header button). 8 locales updated.

cc
2026-07-13 21:01:48 -06:00
vicrodh 12dcedbc0f Merge branch 'pr/611' into integration/pr-review-smoke-2026-07-13 2026-07-13 14:14:09 -06:00
vicrodh a174e06119 feat(home): auto-refresh recently-played rails + a row refresh button
Home's recently-played albums/tracks only populated on a full home load, so
tracks played mid-session never appeared until restart. Re-read the LOCAL
store into the rails when a track is recorded while Home is visible, and on
Home re-mount if it went dirty — event-driven, no polling, cheap (small JSON
read + cached artwork). Also add a manual refresh button in each recently-
played row header next to the page chevrons (moved off the top toolbar, where
it crowded the discovery tab bar).

cc
2026-07-13 13:11:43 -06:00
vicrodh 8df8c18ab0 fix(theme): sync std-widgets Palette to the active QBZ theme
Native std-widgets (LineEdit/TextEdit) render from Slint's own Palette, which
we never synced to the QBZ theme, so on a light theme their text collided with
its own background (Settings input fields, effectively invisible). Add
Theme.is-dark (computed in Rust from the surface luminance, so it is correct
for static/auto/custom themes) and drive Palette.color-scheme from it in the
AppWindow: light/dark follow the theme, System stays `unknown` (follows the
OS). Reactive on theme change.

cc
2026-07-13 13:11:12 -06:00
vicrodh a9dff18d25 fix(ui): make CircleAction buttons visible on light themes
CircleAction defaults to hardcoded light-on-dark colors, so every instance
sitting on the normal page background (not over artwork) vanished on light
themes. Set on-surface: true on those clusters — Popular Tracks (artist +
label), the PlaylistView hero row, LocalAlbumView, AwardView,
PurchaseDetailView, MixtapeDetailView, FavoritesView, LocalLibraryView — so
they use theme-appropriate colors. Buttons over artwork/dark headers keep the
light-on-dark defaults.

cc
2026-07-13 13:11:12 -06:00
Afonso Jorge Ramos ec69bce17e feat(ui): open album from grid card title click 2026-07-13 16:45:42 +02:00
vicrodh fa161be525 fix(header): gradient height = header container (ends at divider), artist-page parity, action buttons readable with gradient off
The album header gradient was a fixed px that overshot the header/track-list divider on tall (description-bearing) headers; bind its height to the divider's y so it ends exactly at the header container's bottom at any size. Apply the same readable-text + gradient-to-boundary treatment to the artist page. And CircleAction gains an on-surface variant (theme-colored fill/border/icon) driven by the gradient toggle, so when the header gradient is off the action buttons are visible on light themes instead of white-on-white. Below-divider content untouched. Extends #491/#519.

cc
2026-07-13 07:50:46 -06:00
vicrodh c3523722f4 feat(local-library): add a Plex sync button to refresh media without restarting
Fetching new Plex music required restarting QBZ. Add a sync button in the Local Library header (gated on plex-available, with a busy spinner) that triggers the existing Plex re-sync (new plex_auth::sync_now over the persisted selected libraries) and refreshes the view. Strings in all 8 locales. Resolves #573.

cc
2026-07-13 04:44:08 -06:00
vicrodh 0f88361427 fix(album): readable header text on light themes + gradient reaches the divider
The header sits on the always-dark art atmosphere, but its text used Theme.text-* which is dark on a light theme = unreadable. Route the header title/artist/meta/description through hdr-strong/hdr-body colors that go white over the gradient and fall back to the theme colors when the gradient is off; below-divider text is untouched. The atmosphere also faded out above the divider on description-bearing headers — raise its height to 440px and push the fade start to 74% so it reaches the header/track-list divider. Addresses #491/#519.

cc
2026-07-13 04:28:26 -06:00
vicrodh f5a8afc0f2 fix(playlist): reorder via the existing row drag gesture, not a bespoke grip
The prior reorder reused only the DragGhost but re-implemented the drag gesture with its own grip + absolute-position math, which placed the ghost several px off the cursor. Remove the grip entirely and drive reorder off the SAME row-body drag that already adds a track to a sidebar playlist: it captures the source index on start, the shared DragGhost (positioned by the Rust DragActions path) follows the cursor exactly, the drop slot is read from DragState.pointer-y against the ListView's absolute-position (no row double-count), and releasing WITHIN the list reorders while releasing on a sidebar playlist still adds. Reverted the sidebar drop suppression + removed DragState.reorder.

cc
2026-07-13 02:45:10 -06:00
vicrodh 85e11d284a feat(quality): downgrade arrow + true-quality tooltip on the Now Playing badge
Follow-up to #590: playback now downgrades to the streaming-quality setting but the badge still showed the catalog max with no indicator. The poll loop already received the delivered stream's sample-rate/bit-depth in PlaybackEvent but dropped them; publish them plus a quality-downgraded flag (effective < catalog max, DSD-exempt on depth) and the true effective detail string. AudioStamp shows an amber down-arrow glyph when downgraded and a Source/Output hover tooltip; mirrored to the miniplayer. Strings translated in all 8 locales.

cc
2026-07-13 01:49:18 -06:00
vicrodh 6e58682aa6 fix(playlist): reuse the shared drag ghost for custom-order reorder
The bespoke reorder ghost read a row's absolute-position inside a ListView, which double-counts the row's own offset, so it only sat at the cursor for row 0 and flew off for the rest. Drive the app-wide DragState directly from the reorder gesture so the shared DragGhost (positioned in AppShell at the proven window coords) renders the reorder ghost; a new DragState.reorder flag keeps the sidebar from claiming it as an add-to-playlist drop and keeps the Rust DragActions path out of it. Removed the buggy local ghost. Reorder logic + persistence unchanged. (state.slint also carries the quality-badge fields for the next commit.)

cc
2026-07-13 01:29:09 -06:00
vicrodh 256b0d36a0 fix(volume): kill the slider rubberband on release
The live-drag thumb reverted to the round-tripped bound value on release; because that value echoes back asynchronously the thumb snapped to the stale position then to the fresh one (a rubberband bounce). The thumb now tracks drag-fraction, which stays put on release and re-syncs to the external value only when it changes on its own (MPRIS / keyboard) while not dragging.

cc
2026-07-13 00:19:51 -06:00
vicrodh a0cca35810 fix(volume): live drag state on the slider primitives so the thumb follows the pointer
The de-quantization (0.1% scale + f32-bits atomic) removed the stepping in the VALUE, but the thumb still derived from the round-tripped bound value, so it felt snappy/laggy during a drag. Give QbzSlider/QbzVerticalSlider a live drag fraction: while held, the thumb tracks the pointer position directly (continuous, no round-trip); on release it reverts to the bound value. The emitted value is still the nearest step to the pointer (round), now imperceptible at the 0.1% scale.

cc
2026-07-12 23:38:34 -06:00
vicrodh 42105eaf46 fix(volume): make the volume control fully fluid (de-quantize)
Volume snapped between 1% steps from two integer quantizers. UI: the volume sliders now use a 0..1000 scale so the shared int slider's round() lands on 0.1% (imperceptible). Runtime: the player volume atomic widened from integer-percent AtomicU64 to f32-bits AtomicU32 (same idiom as normalization_gain) so a continuous value no longer re-snaps on track restart / device switch / gapless. Bit-perfect untouched: 1.0f32 round-trips its bits, no gain multiply or ramp added to the protected ALSA-direct / DoP / JACK paths.

cc
2026-07-12 20:17:12 -06:00
vicrodh 2103bbd3eb feat(playlist): drag-and-drop reorder for custom-order tracks
Adds a dedicated drag HANDLE (grip) in the reorder gutter with the queue's drag gesture (6px threshold, absolute-position - root.y correction, three end paths incl. the changed-pressed safety net), so the row-body drag-to-sidebar stays intact. PlaylistView keeps component-local reorder state (slot math folds in the ListView viewport-y), a drop indicator and a floating ghost; commit fires PlaylistActions.reorder-track(from,to). Rust reuses the arbitrary-index persist path (repo::reorder for local, persist_custom for Qobuz) the arrows already back. Edge auto-scroll during drag is a follow-up TODO. Resolves #589.

cc
2026-07-12 20:17:12 -06:00
vicrodh ec8c487564 feat(lyrics): lite-fill display pref — static active-line highlight to cut CPU
The per-word karaoke sweep animates a clip rect ~60x/s, driving continuous full-window repaints (~4% CPU). Lite fill highlights the active line whole (no per-frame animation) so the surface only repaints on line changes. New toggle in the lyrics controls flyout, persisted via lyrics_prefs; default off (smooth karaoke). Kiosk / weak-GPU tiers force it on via ShellState.reduce-motion.

cc
2026-07-12 19:38:43 -06:00
vicrodh 5fa4e8bdd5 feat(kiosk): redesign Now Playing panel — dominant contain cover, compact meta, floating quality stamp
The cover is image-fit:contain filling the flex art area (no fragile parent-geometry math), so it is large and scales with the window. Toggle and meta rows get vertical-stretch:0 so only the art area takes the slack (nested layouts stretch greedily) — kills the dead space and the ~55px cover. Title toned to 20px, quality stamp floats on the transport row instead of owning a line. Cover<->Lyrics toggle; lyrics fill the panel width.

cc
2026-07-12 19:38:43 -06:00
vicrodh 5be0e2233a feat(kiosk): hide NPB layout/lyrics/queue controls; layout button toggles Desktop mode
In kiosk the layout-flyout would carry a single Desktop mode row that the fixed-height popup floats high above the button, so the layout button toggles straight to Desktop mode instead. Lyrics/Queue toggles are hidden (their panels aren't mounted in the kiosk shell; the queue lives in Now Playing).

cc
2026-07-12 13:07:40 -06:00
vicrodh 772fe42df2 feat(kiosk): Search "All" dashboard — most-popular hero + per-type previews
All is no longer a flat album grid: a polymorphic most-popular hero (artist/album/track) plus Artists/Albums/Tracks(6)/Playlists previews, each with a View all that jumps to that tab. Reads SearchState verbatim, mirroring the desktop hierarchy.

cc
2026-07-12 12:43:56 -06:00
vicrodh dabf4a88c8 feat(kiosk): Now Playing — queue/history tabs, cover<->lyrics toggle with synced follow
Left panel toggles cover/synced lyrics (reuses LyricsLinesView, gated on status==2 to dodge the geometry recursion footgun); right panel is a Queue/History list (Flickable+VerticalLayout so rows top-anchor). The lyrics-sync engine bailed unless a desktop/immersive surface was open, so a kiosk-lyrics-follow flag on ShellState widens lyrics_surface_open().

cc
2026-07-12 12:43:56 -06:00
vicrodh 8cdf26cd34 perf(kiosk): window the album grid so only visible cards mount
cc
2026-07-12 12:43:56 -06:00
vicrodh 26f9e3e1a2 feat(kiosk): shell — mount immersive overlay, hide transport on Now Playing, fixed footer, drop Search tile
The immersive overlay hangs inside AppShell, so the kiosk shell mounts its own copy. The transport bar is hidden on Now Playing (redundant there) and the content height no longer subtracts it then, so the NavRail stays pinned. Footer Search tile removed — the back-bar carries a persistent search field.

cc
2026-07-12 12:43:56 -06:00
vicrodh c36cea7445 feat(kiosk): lightweight KioskLocalLibrary + KioskMyQBZ views
KioskLocalLibrary (tabs Albums/Artists/Folders/Tracks, reading
LocalLibraryState, driving LocalLibraryActions; open-album routes to the
local-album detail) and KioskMyQBZ (Mixtapes/Collections tabs over
MyQbzState, MyQbzActions.open-card). Both reuse the shared kiosk cards/grid
+ ListView for tracks. Wired onto the local-library / mixtapes / collections
routes. With this every kiosk content view is the light version. Validated
via slintcheck. (v1: no album-window / tracks-load-more hooks yet.)

cc
2026-07-11 08:39:38 -06:00
vicrodh 9041b0e749 feat(kiosk): forward nav, window chrome, NPB gating, list windowing
- Add the forward nav button beside back (NavState.can-forward/request-forward).
- The kiosk back bar owns the window chrome (no HeaderBar): macOS leaves the
  ~78px traffic-light inset, Linux frameless draws the custom WindowControls
  on the right. OS-agnostic (the kiosk is not restricted to any platform).
- Hide ALL NPB view modes not compatible with kiosk (New/Classic/Small/Large
  + Miniplayer + Immersive) while in the kiosk profile; only the profile
  toggle remains.
- Track lists (Library/Search) use ListView so only the visible band mounts
  — the plain VerticalLayout spiked CPU on entry, which a Pi cannot afford.

cc
2026-07-11 08:16:24 -06:00
vicrodh 6032791be4 feat(kiosk): Now Playing centerpiece + NPB miniplayer/immersive consistency
KioskNowPlaying: a 50/50 full screen (big cover + title/artist + AudioStamp
+ SeekBar + the reused 7-control TransportControls on the left, the Up-Next
queue on the right), reading NowPlayingState/QueueState and calling
QueueState.panel-opened() on init. New ContentView.now-playing route; the
NavRail Now Playing tile navigates there instead of opening immersive. Also
hide the Miniplayer + Immersive items from the NPB view menu while in the
kiosk profile (todos o ninguno) so it is not a second-window/overlay mix.
Validated via slintcheck.

cc
2026-07-10 21:38:57 -06:00
vicrodh f1d965b04e feat(kiosk): live Kiosk<->Desktop toggle in the NPB layout menu
Add a "Kiosk mode" / "Desktop mode" item to both PlayerBarSmall and
PlayerBar view menus (label from the new ShellState.kiosk-profile flag).
It fires media-action("npb-view","","toggle-profile"); Rust flips the
persisted ui_prefs.profile and swaps the shell in place via set_screen
(KioskShell/AppShell share state, so no restart). The toggle keys off the
current screen, not kiosk_profile_active(), so a QBZ_PROFILE env override
doesnt pin it. ShellState.kiosk-profile is seeded at window setup.

cc
2026-07-10 21:17:12 -06:00
vicrodh dc51c62c7f feat(kiosk): add Local Library + MyQBZ tiles, center NavRail icons
NavRail grows to 8 tiles (Discover, Library, Local Library, MyQBZ, Search,
Now Playing, Visualizer, Settings) routing through the same header-menu
routes. Also center each tile's icon: a fixed-size Image does not center
itself in a VerticalLayout, so wrap it in a centering HorizontalLayout.

cc
2026-07-10 20:34:49 -06:00
vicrodh ad9a23bab6 feat(kiosk): lightweight KioskAlbum + KioskArtist detail views
Replace the reused AlbumPageView/ArtistPageView on the kiosk album/artist
routes with Pi-light detail: KioskAlbum (cover + title + tappable artist +
Play/Shuffle + number/title/duration track list, reading AlbumState) and
KioskArtist (round portrait + Play/Radio + discography as KioskCard shelves
per release section, skipping the \"other\" bucket, reading ArtistState). Both
bind the shared state so covers push in. Validated via slintcheck.

cc
2026-07-10 19:54:56 -06:00
vicrodh 172dbf8eb6 fix(kiosk): position NavRail tiles manually so they distribute
Layout-based attempts (child stretch, mount stretch, explicit HL width) all
left the tiles collapsed to icon width packed on the left. Position the 6
tiles by absolute x + explicit width derived from root.width instead; the
rail width comes from the KioskShell VerticalLayout, so the tiles now span
the panel evenly.

cc
2026-07-10 19:49:50 -06:00
vicrodh 45cbe24206 feat(kiosk): lightweight KioskSearch + KioskLibrary views
Replace the heavy reused SearchResultsView and FavoritesView on the kiosk
search/favorites routes with Pi-light versions built from the shared kiosk
cards: KioskAlbumGrid (wrapping grid of KioskCard), KioskArtistCard (round),
KioskTrackRow. KioskSearch tabs All/Albums/Tracks/Artists/Playlists reading
SearchState; KioskLibrary tabs Tracks/Albums/Artists/Playlists/Labels reading
FavoritesState. Both bind the shared models so the artwork pipeline pushes
covers in with no request hook (album covers windowed = first ~60 for now).
Validated via slintcheck.

cc
2026-07-10 19:21:48 -06:00
vicrodh f27d5e864c fix(kiosk): pin NavRail row to root.width so tiles distribute
The tiles still collapsed to the bottom-left even with per-tile
horizontal-stretch: a HorizontalLayout nested in the rail's VerticalLayout
was taking its preferred (content) width, not the rail width. Drop the
wrapper, make the tile row an explicit width: root.width child with the
hairline as an overlay, and the 6 tiles now spread evenly across the panel.

cc
2026-07-10 19:21:48 -06:00
vicrodh ce2db8cb54 feat(kiosk): lightweight KioskDiscover with simple cards
Replace the heavy reused HomeView on the kiosk home route with a Pi-light
Discover: KioskCard (square art + quality badge + title + artist, tap-to-
open, no hover/context-menu chrome) in horizontal shelves, reading the SAME
DiscoverState model so the artwork pipeline pushes covers in with no request
hook. Tab pill (Home/Editor's Picks/For You). First of the mockup-matching
lightweight views; also guards single-key hotkeys while typing in the kiosk
search field. Validated via slintcheck.

cc
2026-07-10 18:39:24 -06:00
vicrodh 01311db29c fix(kiosk): stretch NavRail tiles across the full width
The tiles collapsed to icon width, packed bottom-left with truncated labels
(a horizontal-stretch set only on the child component root is not honored by
the parent layout). Set horizontal-stretch at each mount site + fill the rail
height so the 6 tiles distribute evenly as full-height touch targets.

cc
2026-07-10 18:39:24 -06:00
vicrodh 408c945c44 feat(kiosk): persistent search field in the KioskShell back bar
The kiosk drops the HeaderBar (where the desktop search box lives), so add a
search LineEdit to the back bar: Enter submits through SearchActions.submit
(the same seam the header uses) and lands on the results view. This makes
Search functional end-to-end in kiosk (query -> SearchResultsView -> tap a
result -> the album/artist detail views mounted in P2). Validated via the
slintcheck stub.

cc
2026-07-10 15:02:38 -06:00
vicrodh af34a8e40c feat(kiosk): full ContentView route parity in KioskShell (P2)
Extend the KioskShell content mount to every ContentView route AppShell
hosts (discover-browse, recent-albums, local-album, artist-releases,
musician, label(-releases), award(-albums), location, purchases, purchase-
album, playlist(-manager), mixtapes, collections, mixtape-detail,
discography-builder, offline/blacklist managers, local-library, mix,
playlist) plus the offline placeholder + qobuz-view-blocked gate — a
verbatim copy of AppShell so navigation reaches the same real views by
construction. Discover, Search, and the album/artist detail views tapped
from them are functional. Validated through the Slint compiler (slintcheck
stub). ShellContent DRY extraction still deferred.

cc
2026-07-10 14:59:07 -06:00