Files
qbz/crates/qbz-qt/qml/shell/FavToggle.qml
T
vicrodh 81c43a114e fix(qt): glyph colours follow the theme, on light palettes and on accent fills
Two defects with one cause: a tint name that means a frozen hex.

"primary" is the legacy alias of literal #ffffff, not Theme.text-primary,
so every control passing it drew a white glyph. On the eleven light
themes that is white-on-light -- the header back/forward chevrons, the
sidebar toggle and the carousel arrows the owner marked. They now pass
the theme-following names, which icon_tint_qt bakes at runtime.

The stale `hslLightness > 0.5 ? "primary" : "black"` workarounds that
predate the runtime tinter collapse into those names, and the qrc floor
underneath them becomes polarity-aware: dir_for() returns "" whenever
the cache dir is unavailable, a bake fails or the theme document has not
been published, and that path used to resolve textPrimary straight back
to the white bake -- reproducing the bug it was fixing, app-wide, in the
degraded state.

On accent fills the fix is a deviation from Slint, approved by the owner
after measurement. A fixed white glyph on Theme.accent falls under 2.6:1
on 16 of the 35 shipped palettes, including high-contrast at 1.70:1 and
wcag-dark at 1.82:1 -- the two themes whose reason to exist is contrast.
Slint hardcodes #ffffff there (CircleAction.slint:72 and three others),
so the bug is upstream. accentText alone is not the answer either: it is
picked for the theme's text ramp and gives 2.56:1 on Rose Pine Dawn,
worse than the black it replaces. So QbzTheme picks the best-contrast
tint by real sRGB luminance against the live accent, and the labels
beside those glyphs use its colour twin -- BrowseGenreButton and
LibraryView were drawing a white glyph next to an accentText label
inside the same pill.

Rounds out the two parity items the same files owe: QbzNavButton gains
the ambient arm from Carousel.slint (wired at the six carousel sites,
not left dead), and QbzCircleAction rounds its glyph to whole pixels the
way CircleAction.slint does.

cc
2026-07-29 10:30:43 -06:00

51 lines
1.8 KiB
QML

// FavToggle — the inline favorite heart the Classic bar mounts next to "+"
// (Tauri's `.control-btn` heart with fill=currentColor when favorited),
// extracted verbatim from PlayerBar.qml (phase 25 size split).
//
// NOT a QbzIconButton: that control only tints accent/primary/secondary/muted
// and the favorited heart must take the theme's `favorite` red (Slint
// TransportControls uses Theme.favorite the same way).
import QtQuick
import com.blitzfc.qbz
import "../theme"
Rectangle {
id: root
/// Favorite state of the now-playing track (QueueState.now-playing-favorite
/// in Slint) — the host bar already parses the queue document.
property bool favorite: false
QbzTheme { id: theme }
// TransportControls.slint's fav-ta: hover -> Theme.text-primary, idle ->
// Theme.text-secondary. Both are runtime-tinted (see QbzIconButton's
// header), so they ARE those tokens; the fill under them is
// `surface-hover`/transparent, a theme surface.
readonly property string tintStrong: "textPrimary"
readonly property string tintWeak: "secondary"
width: 32
height: 32
radius: theme.radiusSm
opacity: QbzPlayer.npHasTrack ? 1.0 : 0.3
color: (favArea.containsMouse && QbzPlayer.npHasTrack) ? theme.surfaceHover : "transparent"
QbzIcon {
name: root.favorite ? "heart-filled" : "heart"
width: 16
height: 16
anchors.centerIn: parent
tintName: root.favorite ? "favorite"
: (favArea.containsMouse ? root.tintStrong : root.tintWeak)
}
MouseArea {
id: favArea
anchors.fill: parent
hoverEnabled: true
cursorShape: QbzPlayer.npHasTrack ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: if (QbzPlayer.npHasTrack && QbzPlayer.npTrackId !== "")
QbzQueue.queueToggleFavorite("track", QbzPlayer.npTrackId)
}
}