feat(qt): overAmbient legibility mode for the quality badge and track info

Immersive surfaces sit directly on the ambient field, where theme tokens
have no contrast guarantee — a light cover washed the split Track Info
panel and the quality badges out completely. QualityBadgeFull,
TrackInfoBody, InfoMetaCell and InfoCreditCell gain an opt-in overAmbient
mode: fixed light text with the restrained native shadow the lyrics
surfaces already use, and the badge swaps the theme surface for its own
translucent dark scrim covering only the chip. Defaults stay off, so the
desktop modal and every themed mount are untouched. The immersive Track
Info panel and song card opt in.

cc
This commit is contained in:
vicrodh committed 2026-08-31 15:03:09 -06:00
1 parent 68eeb10173
commit 9493993124
6 files changed
+90 -22

No files matched your search

+11 -2
View File
@@ -19,6 +19,10 @@ Column {
/// dictating its width.
property int colW: 280
/// Immersive-panel legibility mode (see TrackInfoBody.qml): fixed light
/// colors + native shadow instead of the theme tokens.
property bool overAmbient: false
signal nameClicked(string name, string roleRaw)
QbzTheme { id: theme }
@@ -29,7 +33,9 @@ Column {
Text {
width: cc.colW
text: cc.cell ? (cc.cell.role || "") : ""
color: theme.textMuted
color: cc.overAmbient ? "#b3ffffff" : theme.textMuted
style: cc.overAmbient ? Text.Raised : Text.Normal
styleColor: "#b0000000"
font.pixelSize: 11
font.weight: theme.weightSemibold
font.letterSpacing: 0.5
@@ -49,7 +55,10 @@ Column {
id: nameText
width: cc.colW
text: nameRow.modelData
color: nameArea.containsMouse ? theme.accent : theme.textPrimary
color: nameArea.containsMouse ? theme.accent
: (cc.overAmbient ? "#f2ffffff" : theme.textPrimary)
style: cc.overAmbient ? Text.Raised : Text.Normal
styleColor: "#b0000000"
font.pixelSize: 14
wrapMode: Text.WordWrap
}
+6 -1
View File
@@ -19,6 +19,9 @@ Column {
id: mc
property string label: ""
property int cellWidth: 0
/// Immersive-panel legibility mode (see TrackInfoBody.qml): fixed light
/// label + native shadow instead of the theme token.
property bool overAmbient: false
QbzTheme { id: theme }
@@ -28,7 +31,9 @@ Column {
Text {
width: mc.cellWidth
text: mc.label
color: theme.textMuted
color: mc.overAmbient ? "#b3ffffff" : theme.textMuted
style: mc.overAmbient ? Text.Raised : Text.Normal
styleColor: "#b0000000"
font.pixelSize: 11
font.weight: theme.weightSemibold
font.letterSpacing: 0.5
+56 -14
View File
@@ -24,6 +24,18 @@ Column {
QbzTheme { id: theme }
/// Legibility mode for the immersive split panel (2026-08-31 visual
/// cleanup): there the body sits directly on the ambient field, where
/// theme tokens have no contrast guarantee over a light cover. On, every
/// text uses a fixed light color plus the restrained native shadow the
/// lyrics surfaces use. The desktop modal keeps the theme (default off).
property bool overAmbient: false
readonly property color cPrimary: overAmbient ? "#f2ffffff" : theme.textPrimary
readonly property color cMuted: overAmbient ? "#b3ffffff" : theme.textMuted
readonly property color cRule: overAmbient ? "#2effffff" : theme.surfaceElevated
readonly property int cStyle: overAmbient ? Text.Raised : Text.Normal
readonly property color cShadow: "#b0000000"
readonly property var doc: host ? host.doc : ({})
// ---- Loading ---------------------------------------------------------
@@ -36,7 +48,9 @@ Column {
anchors.centerIn: parent
width: Math.max(0, parent.width - 120)
text: QbzSession.tr("Loading track info...", QbzSession.trRev)
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: theme.fontBody
horizontalAlignment: Text.AlignHCenter
}
@@ -55,14 +69,18 @@ Column {
Text {
width: parent.width
text: QbzSession.tr("Failed to load track info", QbzSession.trRev)
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: theme.fontBody
horizontalAlignment: Text.AlignHCenter
}
Text {
width: parent.width
text: body.host ? body.host.errorText : ""
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: theme.fontLegal
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
@@ -99,7 +117,9 @@ Column {
Text {
width: parent.width
text: body.doc.title || ""
color: theme.textPrimary
color: body.cPrimary
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 16
font.weight: theme.weightSemibold
wrapMode: Text.WordWrap
@@ -108,7 +128,9 @@ Column {
visible: (body.doc.album || "") !== ""
width: parent.width
text: body.doc.album || ""
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: theme.fontLegal
elide: Text.ElideRight
}
@@ -121,7 +143,9 @@ Column {
id: artistText
text: body.doc.artist || ""
color: (body.doc.artistId || "") !== ""
? theme.accent : theme.textPrimary
? theme.accent : body.cPrimary
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 16
font.weight: theme.weightSemibold
}
@@ -149,7 +173,9 @@ Column {
width: 18
height: 18
anchors.centerIn: parent
tintName: closeArea.containsMouse ? "textPrimary" : "muted"
tintName: body.overAmbient
? (closeArea.containsMouse ? "white" : "muted")
: (closeArea.containsMouse ? "textPrimary" : "muted")
}
MouseArea {
id: closeArea
@@ -177,22 +203,28 @@ Column {
spacing: 24
InfoMetaCell {
cellWidth: loadedCol.metaColW
overAmbient: body.overAmbient
label: QbzSession.tr("Duration", QbzSession.trRev)
Text {
width: loadedCol.metaColW
text: body.doc.duration || ""
color: theme.textPrimary
color: body.cPrimary
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 14
elide: Text.ElideRight
}
}
InfoMetaCell {
cellWidth: loadedCol.metaColW
overAmbient: body.overAmbient
label: QbzSession.tr("Quality", QbzSession.trRev)
Text {
width: loadedCol.metaColW
text: body.doc.quality || ""
color: theme.textPrimary
color: body.cPrimary
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 14
elide: Text.ElideRight
}
@@ -202,11 +234,14 @@ Column {
InfoMetaCell {
visible: (body.doc.isrc || "") !== ""
cellWidth: loadedCol.metaColW
overAmbient: body.overAmbient
label: "ISRC"
Text {
width: loadedCol.metaColW
text: body.doc.isrc || ""
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 14
elide: Text.ElideRight
}
@@ -228,6 +263,7 @@ Column {
spacing: 24
InfoMetaCell {
cellWidth: loadedCol.metaColW
overAmbient: body.overAmbient
label: QbzSession.tr("Label", QbzSession.trRev)
Item {
width: loadedCol.metaColW
@@ -238,7 +274,9 @@ Column {
text: body.doc.label || ""
color: (labelArea.containsMouse
&& (body.doc.labelId || "") !== "")
? theme.accent : theme.textPrimary
? theme.accent : body.cPrimary
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 14
elide: Text.ElideRight
}
@@ -265,7 +303,7 @@ Column {
visible: body.host && body.host.credits.length > 0
width: parent.width
height: 1
color: theme.surfaceElevated
color: body.cRule
}
Item {
visible: body.host && body.host.credits.length > 0
@@ -284,6 +322,7 @@ Column {
delegate: InfoCreditCell {
required property var modelData
colW: loadedCol.creditsColW
overAmbient: body.overAmbient
cell: modelData
onNameClicked: function (n, r) { body.host.openMusician(n, r) }
}
@@ -297,6 +336,7 @@ Column {
delegate: InfoCreditCell {
required property var modelData
colW: loadedCol.creditsColW
overAmbient: body.overAmbient
cell: modelData
onNameClicked: function (n, r) { body.host.openMusician(n, r) }
}
@@ -314,7 +354,7 @@ Column {
visible: (body.doc.copyright || "") !== ""
width: parent.width
height: 1
color: theme.surfaceElevated
color: body.cRule
}
Item {
visible: (body.doc.copyright || "") !== ""
@@ -325,7 +365,9 @@ Column {
visible: (body.doc.copyright || "") !== ""
width: parent.width
text: body.doc.copyright || ""
color: theme.textMuted
color: body.cMuted
style: body.cStyle
styleColor: body.cShadow
font.pixelSize: 12
wrapMode: Text.WordWrap
}