**Track-row buttons did nothing.** Declaration order is z-order in QML, and the row-wide MouseArea added for right-click was declared last — so it covered the heart, cloud and menu buttons and swallowed their presses. propagateComposedEvents cannot rescue that: a press is not a composed event, which is why only the row's own double-click still worked. **Covers appeared only after a scroll.** Three compounding defects, not one. The window report fired on contentY and on model change, both of which happen while the tab body is still hidden behind its loading flag, so the report that mattered hit the not-visible early return and was discarded with nothing to re-fire it. The debounce reset on every change, so a burst of mount-time reports kept pushing its trailing edge out. And a single pending slot meant that when two surfaces are mounted at once — the artist rail and that artist's grid — the second overwrote the first, so one pane was never requested at all. Eviction had the same shape: each report deleted everything outside its own array, so the two panes deleted each other's covers. **Latest release had no cover** because the artist page's collector skipped it, along with Appears On and the playlists strip. **Light themes.** The mechanism is Slint's, from 2.0.2 and issue #638: the on-surface arm on circle actions, header-light deciding the header foreground only when a dark backdrop is actually painted, and the circular backing behind the track-row play glyph. Ported as specified rather than approximated. Two icons rendered in their SVG's own colour because they pointed at the raw asset instead of a baked tint — a sweep found the rest of that class. **Navigation flyouts** exist, one component serving both the sidebar and the header nav modes. **Filter by genre and the Discover sort now work**, everywhere the control is drawn. The genre ids were already a parameter on the discover fetch that the port always passed empty. cc
67 lines
2.8 KiB
QML
67 lines
2.8 KiB
QML
// QbzIconButton — the square icon button (Slint BarControls IconButton /
|
|
// HeaderIconButton), consolidated in phase 22 from PlayerBar.BarIconBtn +
|
|
// NowPlayingBarSmall.BarIconBtn (verbatim twins), QueuePanel.PanelIconBtn
|
|
// and HeaderBar.HeaderIconBtn.
|
|
// Arms: `btnSize` (32 default; 30 compact panels, 36 header), `iconSize`,
|
|
// `active` (accent glyph), `activeBackground` (HeaderBar: elevated fill
|
|
// when active), `btnEnabled` (dims 0.3 + muted glyph, disarms).
|
|
//
|
|
// LIGHT-THEME CORRECTNESS: the glyph tints are PRE-BAKED SVG colours
|
|
// (assets/icons/<tint>/) — "primary" is literally #ffffff and "secondary"
|
|
// #cccccc, i.e. the DARK theme's text-primary / text-secondary frozen into
|
|
// the asset. On a light theme those render near-white on a light surface and
|
|
// the whole button set disappears, which is the reported bug. The bake is
|
|
// therefore chosen from the LIVE token's lightness instead of being
|
|
// hardcoded: bright token -> the light bake, dark token -> the dark bake.
|
|
// TODO(glue): the durable home for this is a QbzTheme.tintFor(token) helper
|
|
// (or real runtime tinting in QbzIcon) — see the report; it is duplicated in
|
|
// FavToggle / TransportControls / SongCard until then.
|
|
|
|
import QtQuick
|
|
import com.blitzfc.qbz
|
|
import "../theme"
|
|
|
|
Rectangle {
|
|
id: btn
|
|
property string name: ""
|
|
property int btnSize: 32
|
|
property int iconSize: 16
|
|
property bool active: false
|
|
property bool activeBackground: false
|
|
property bool btnEnabled: true
|
|
signal clicked()
|
|
|
|
QbzTheme { id: theme }
|
|
|
|
// Bake that actually matches Theme.text-primary / text-secondary in the
|
|
// ACTIVE theme (BarControls.slint IconButton: hover -> text-primary,
|
|
// idle -> text-secondary). text-muted maps to the "muted" bake in both
|
|
// polarities: #888888 is mid-grey and reads on light and dark alike.
|
|
readonly property string tintStrong: theme.textPrimary.hslLightness > 0.5 ? "primary" : "black"
|
|
readonly property string tintWeak: theme.textSecondary.hslLightness > 0.5 ? "secondary" : "muted"
|
|
|
|
width: btnSize
|
|
height: btnSize
|
|
radius: theme.radiusSm
|
|
opacity: btnEnabled ? 1.0 : 0.3
|
|
color: (biArea.containsMouse && btnEnabled) ? theme.surfaceHover
|
|
: (active && activeBackground) ? theme.surfaceElevated : "transparent"
|
|
QbzIcon {
|
|
name: parent.name
|
|
width: parent.iconSize
|
|
height: parent.iconSize
|
|
anchors.centerIn: parent
|
|
tintName: !parent.btnEnabled ? "muted"
|
|
: parent.active ? "accent"
|
|
: biArea.containsMouse ? btn.tintStrong : btn.tintWeak
|
|
}
|
|
MouseArea {
|
|
id: biArea
|
|
anchors.fill: parent
|
|
enabled: parent.btnEnabled
|
|
hoverEnabled: true
|
|
cursorShape: parent.btnEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
onClicked: if (parent.btnEnabled) parent.clicked()
|
|
}
|
|
}
|