feat(qt): polarity-aware ambient veil and weak-ramp hardening for light themes
The ambient legibility scrim was a fixed BLACK layer at ambientDim — right for dark themes, but over a LIGHT theme it pushed the field to mid luminance, the worst ground for dark text, and the grey secondary/muted ramp drowned. Light themes now veil with their own near-white surfaceMain a notch stronger, with the in-shader (mode 1) and in-atmosphere (mode 2) darkening turned off there; dark themes keep the exact previous look. QbzTheme additionally steps textSecondary/textMuted toward textPrimary while ambient is on under a light theme, so the weak ramp keeps a contrast floor everywhere without call-site changes. cc
This commit is contained in:
3 files changed
+59
-12
No files matched your search
@@ -61,6 +61,11 @@ Item {
|
||||
property color accent: QbzShell.ambientAccent
|
||||
// Set false by the host to freeze the clock (inactive / hidden).
|
||||
property bool running: true
|
||||
// The in-shader legibility dim (multiply toward black). The host lowers
|
||||
// it to 0 on LIGHT themes, where darkening is the wrong direction — the
|
||||
// polarity-aware veil rectangle above the field takes over there
|
||||
// (AppShell, 2026-08-31).
|
||||
property real dim: QbzShell.ambientDim
|
||||
|
||||
// True unless the window is minimized or hidden — see the GATING RULE at
|
||||
// the top. Focus is deliberately NOT part of this.
|
||||
@@ -183,8 +188,9 @@ Item {
|
||||
property real resX: root.resW
|
||||
property real resY: root.resH
|
||||
// The dark legibility scrim, applied inside the program rather than as
|
||||
// a second full-window Rectangle above it — see the shader.
|
||||
property real dim: QbzShell.ambientDim
|
||||
// a second full-window Rectangle above it — see the shader. Host-fed:
|
||||
// 0 on light themes (the veil rectangle handles legibility there).
|
||||
property real dim: root.dim
|
||||
|
||||
onStatusChanged: {
|
||||
if (status === ShaderEffect.Error)
|
||||
|
||||
@@ -69,20 +69,32 @@ Rectangle {
|
||||
readonly property bool ambientModeOn: root.ambientOn && QbzShell.ambientMode === 1
|
||||
readonly property bool blurredModeOn: root.ambientOn && QbzShell.ambientMode === 2
|
||||
|
||||
// Mode 1 — the album-triad metaball field, plus the tunable dark scrim
|
||||
// that keeps chrome text legible over a bright album palette
|
||||
// (QBZ_BG_DIM, default 0.35). The scrim is mode 1 ONLY: mode 2's
|
||||
// atmosphere applies the same dim internally (AppShell.slint:236).
|
||||
// --- The polarity-aware legibility veil (owner, 2026-08-31) ------------
|
||||
// The old scrim was a fixed BLACK layer at ambientDim — tuned for dark
|
||||
// themes, where dark ground + light text is exactly right. Over a LIGHT
|
||||
// theme the same dark scrim pushed the field to MID luminance, the worst
|
||||
// possible ground for dark text (the weak grey ramp died completely).
|
||||
// Light themes therefore veil with their own near-white surfaceMain, a
|
||||
// notch stronger, and the in-shader/in-atmosphere darkening is turned
|
||||
// OFF there (darkening and then whitening would just grey the field).
|
||||
// Dark themes keep the exact previous look.
|
||||
readonly property real veilStrength: theme.isDark
|
||||
? QbzShell.ambientDim
|
||||
: Math.min(0.72, QbzShell.ambientDim + 0.2)
|
||||
|
||||
// Mode 1 — the album-triad metaball field, plus the veil that keeps text
|
||||
// legible over a bright album palette (QBZ_BG_DIM, default 0.35).
|
||||
AmbientField {
|
||||
anchors.fill: parent
|
||||
visible: root.ambientModeOn
|
||||
running: root.ambientModeOn
|
||||
dim: theme.isDark ? QbzShell.ambientDim : 0.0
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: root.ambientModeOn
|
||||
color: "#000000"
|
||||
opacity: QbzShell.ambientDim
|
||||
color: theme.isDark ? "#000000" : theme.surfaceMain
|
||||
opacity: root.veilStrength
|
||||
}
|
||||
|
||||
// Mode 2 — Blurred art: the SAME ImmersiveAtmosphere the immersive view
|
||||
@@ -90,14 +102,23 @@ Rectangle {
|
||||
// reuses the identical component). `animated` follows the transport, so a
|
||||
// paused player holds the static pose instead of drifting forever, and the
|
||||
// fallback is the plain cover for a track whose atmosphere bitmap has not
|
||||
// been generated yet.
|
||||
// been generated yet. On light themes its internal dark dim is disabled
|
||||
// and the veil below provides the legibility layer instead (the
|
||||
// atmosphere's baked gradient scrim stays — it reads as depth under the
|
||||
// light veil, not as darkness).
|
||||
ImmersiveAtmosphere {
|
||||
anchors.fill: parent
|
||||
visible: root.blurredModeOn
|
||||
source: root.blurredModeOn ? QbzImmersive.atmosphereUrl : ""
|
||||
fallbackSource: root.blurredModeOn ? QbzPlayer.npArtworkPath : ""
|
||||
animated: root.blurredModeOn && QbzPlayer.npPlaying
|
||||
dim: QbzShell.ambientDim
|
||||
dim: theme.isDark ? QbzShell.ambientDim : 0.0
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: root.blurredModeOn && !theme.isDark
|
||||
color: theme.surfaceMain
|
||||
opacity: root.veilStrength
|
||||
}
|
||||
|
||||
// The host ApplicationWindow (custom chrome: drag / maximize / resize).
|
||||
|
||||
Reference in new issue
Block a user