Files
qbz/crates/qbz-slint/ui/myqbz/MyQbzShared.slint
T
vicrodh 0b20a1a86a fix(myqbz): visual homologation — app components, colors, scrollbar, resolveItems
Per the user's visual review. Replaces the reinvented MyQBZ controls with the
app's existing primitives and resolves the per-item data left unresolved.

Cross-cutting (all MyQBZ views):
- Removed the per-view "Back" header (the app uses the global < > nav).
- 32px L/R content padding so the ListScrollbar never rides over rows/cards.
- Homologated page padding + Typography tokens to Favorites/LocalLibrary.
- No more blue accent-filled pills / non-app colors.

Component homologation (deleted the reinvented locals + dead code):
- Grid/list + detail view-mode toggle -> the app ViewToggle (ToggleButton,
  surface-hover active, never accent). Builder ORDER-BY segmented de-blued too.
- Sort/filter -> QbzSelect (sm); search -> ExpandableSearch (sm); "+ New" ->
  NewActionBtn (surface-elevated circle, single centered glyph). Header "+ New"
  hidden when empty so the empty-state CTA is the only one (no duplicate).
- Deleted PrimaryCta / MyQbzSearch / ControlBtn / ViewSeg / ViewModeGroup /
  SortItem / ColMenuItem + the hand-rolled sort/filter popups + reset.

Data (resolveItems, was deferred):
- Quality column populated from the resolved tracks (QualityBadgeFull).
- New ui/primitives/SourceGlyph.slint: full-color Qobuz/Plex glyphs + a
  text-muted local hard-drive -- distinguishes Local vs Plex, no accent blob.
  Reused in the detail + builder rows.
- Type column shows the real release type (ALBUM/EP/SINGLE), not always ALBUM.
- Local/Plex album art now loads in the detail rows (split artwork dispatch).
- Collection grid card renders custom_artwork_path.
- Builder rows: 44px + a hairline so quality badges read separated.

Backend crates untouched. cargo check -p qbz-slint green.

cc
2026-06-09 12:35:03 -06:00

164 lines
5.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Shared MyQBZ index widgets — the grid card + list row + the two small
// app-homologated toolbar wrappers (the grid/list ViewToggle and the "+ New"
// action button), reused 1:1 by both MixtapesView and CollectionsView.
//
// HOMOLOGATION: the toolbar controls are the app's own primitives. The
// reinvented PrimaryCta (blue accent-filled pill), MyQbzSearch (fixed-width
// always-open box), ControlBtn (bordered button) and ViewSeg/ViewModeGroup
// (accent-filled segment) were DELETED — the index views now use
// ExpandableSearch + QbzSelect directly and the two small wrappers below
// (copied verbatim from Favorites/LocalLibrary). No accent-filled action pill.
import { Theme } from "../foundation/semantic-colors.slint";
import { Typography } from "../foundation/typography.slint";
import { Radius } from "../foundation/radius.slint";
import { MixtapeCardItem } from "../state.slint";
import { QbzIcon } from "../primitives/QbzIcon.slint";
import { ToggleButton } from "../primitives/ToggleButton.slint";
import { CollectionMosaic } from "CollectionMosaic.slint";
// --- "+ New" action button ----------------------------------------------
// The app's secondary header action idiom (LocalLibrary's gear CircleIconBtn):
// a 28×28 surface-elevated circle with a plus glyph — NEVER an accent fill.
// Replaces the deleted blue PrimaryCta.
export component NewActionBtn inherits Rectangle {
callback clicked();
width: 28px;
height: 28px;
border-radius: 14px;
background: ta.has-hover ? Theme.surface-hover : Theme.surface-elevated;
QbzIcon {
source: @image-url("../assets/icons/plus.svg");
width: 15px;
height: 15px;
x: Math.round((parent.width - self.width) / 2 / 1px) * 1px;
y: Math.round((parent.height - self.height) / 2 / 1px) * 1px;
tint: Theme.text-primary;
}
ta := TouchArea {
mouse-cursor: pointer;
clicked => { root.clicked(); }
}
}
// --- Grid/list view toggle ----------------------------------------------
// Verbatim from FavoritesView/LocalLibraryView's `ViewToggle`: a 60×30
// surface-elevated rounded box holding two `ToggleButton { sm: true }`.
// ADR-008: small-radius rectangle, NOT a pill; active = surface-hover, never
// accent.
export component ViewToggle inherits Rectangle {
in property <string> view; // "grid" | "list"
callback set-view(string);
width: 60px;
height: 30px;
border-radius: 6px;
background: Theme.surface-elevated;
clip: true;
HorizontalLayout {
ToggleButton {
icon: @image-url("../assets/icons/list.svg");
active: root.view == "list";
sm: true;
clicked => { root.set-view("list"); }
}
ToggleButton {
icon: @image-url("../assets/icons/layout-grid.svg");
active: root.view == "grid";
sm: true;
clicked => { root.set-view("grid"); }
}
}
}
// --- Grid card ----------------------------------------------------------
// 208px column; 12px padding -> 184px mosaic. Muted subtitle (Typography.legal,
// no accent eyebrow) + 2-line name (Typography.body) + album-count meta.
export component MyQbzCard inherits Rectangle {
in property <MixtapeCardItem> item;
callback clicked();
width: 208px;
height: 184px + 12px + 12px + 18px + 2 * 20px + 18px + 12px;
border-radius: 8px;
background: card-ta.has-hover ? Theme.surface-hover : Theme.surface-card;
border-width: 1px;
border-color: card-ta.has-hover ? Theme.surface-hover : Theme.surface-elevated;
VerticalLayout {
padding: 12px;
spacing: 8px;
alignment: start;
CollectionMosaic {
item: root.item;
size: 184px;
}
Rectangle { height: 2px; }
// card-name — 2-line clamp (reserve 2 lines so cards align).
Text {
text: root.item.name;
color: Theme.text-primary;
font-size: Typography.body;
font-weight: Typography.semibold;
wrap: word-wrap;
overflow: elide;
height: 40px;
width: 100%;
}
// Muted subtitle: kind label + count (no uppercase accent eyebrow).
Text {
text: root.item.label + " · " + root.item.meta;
color: Theme.text-muted;
font-size: Typography.legal;
}
}
card-ta := TouchArea {
mouse-cursor: pointer;
clicked => { root.clicked(); }
}
}
// --- List row -----------------------------------------------------------
// 48px cover + name (single-line ellipsis) + sub (label · count).
export component MyQbzListRow inherits Rectangle {
in property <MixtapeCardItem> item;
callback clicked();
height: 64px;
border-radius: 6px;
background: row-ta.has-hover ? Theme.surface-hover : transparent;
HorizontalLayout {
padding-left: 12px;
padding-right: 12px;
spacing: 12px;
alignment: start;
VerticalLayout {
alignment: center;
CollectionMosaic {
item: root.item;
size: 48px;
}
}
VerticalLayout {
alignment: center;
spacing: 2px;
horizontal-stretch: 1;
Text {
text: root.item.name;
color: Theme.text-primary;
font-size: Typography.body;
font-weight: Typography.semibold;
overflow: elide;
width: 100%;
}
Text {
text: root.item.label + " · " + root.item.meta;
color: Theme.text-muted;
font-size: Typography.legal;
overflow: elide;
width: 100%;
}
}
}
row-ta := TouchArea {
mouse-cursor: pointer;
clicked => { root.clicked(); }
}
}