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:
6 files changed
+90
-22
No files matched your search
@@ -35,6 +35,11 @@ Item {
|
||||
property bool bare: false
|
||||
/// ~20%-smaller variant for the now-playing stamp.
|
||||
property bool compact: false
|
||||
/// Legibility mode for hosts sitting ON the ambient/immersive backdrop
|
||||
/// (2026-08-31 visual cleanup): the chip swaps the theme surface for its
|
||||
/// own translucent dark scrim — covering only the badge, keeping the
|
||||
/// background visible — and fixed light text, so it reads over ANY cover.
|
||||
property bool overAmbient: false
|
||||
/// Extra proportional scale on top of `compact` (1.0 = none).
|
||||
property real scaleFactor: 1.0
|
||||
/// Cap for the text column, in px. 0 = uncapped, which is what every
|
||||
@@ -67,9 +72,10 @@ Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
color: root.bare ? "transparent" : theme.surfaceHover
|
||||
color: root.bare ? "transparent"
|
||||
: (root.overAmbient ? "#8c000000" : theme.surfaceHover)
|
||||
border.width: root.bare ? 0 : 1
|
||||
border.color: theme.borderSubtle
|
||||
border.color: root.overAmbient ? "#33ffffff" : theme.borderSubtle
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -102,7 +108,7 @@ Item {
|
||||
visible: !root.isHiRes
|
||||
anchors.centerIn: parent
|
||||
name: root.tier === "mp3" ? "mp3" : "cd"
|
||||
tintName: "muted"
|
||||
tintName: root.overAmbient ? "white" : "muted"
|
||||
width: root.iconSide
|
||||
height: root.iconSide
|
||||
}
|
||||
@@ -128,7 +134,7 @@ Item {
|
||||
id: tierText
|
||||
width: parent.width
|
||||
text: root.tierLabel
|
||||
color: theme.textSecondary
|
||||
color: root.overAmbient ? "#e6ffffff" : theme.textSecondary
|
||||
font.pixelSize: Math.max(1, Math.round((root.compact ? 7 : 8) * root.sf))
|
||||
font.weight: Font.Thin
|
||||
font.letterSpacing: 0.5
|
||||
@@ -139,7 +145,7 @@ Item {
|
||||
id: detailText
|
||||
width: parent.width
|
||||
text: root.detail
|
||||
color: theme.textMuted
|
||||
color: root.overAmbient ? "#b3ffffff" : theme.textMuted
|
||||
font.pixelSize: Math.max(1, Math.round((root.compact ? 8 : 9) * root.sf))
|
||||
font.weight: Font.Thin
|
||||
horizontalAlignment: root.bare ? Text.AlignHCenter : Text.AlignLeft
|
||||
|
||||
@@ -131,6 +131,7 @@ Item {
|
||||
id: badge
|
||||
x: root.metaW - width
|
||||
y: titleRow.height + 3 + subRow.height + 3
|
||||
overAmbient: true
|
||||
tier: QbzPlayer.npQualityTier
|
||||
detail: QbzPlayer.npQualityDetail
|
||||
showIcon: true
|
||||
|
||||
@@ -105,6 +105,8 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
text: QbzSession.tr("No track selected", QbzSession.trRev)
|
||||
color: "#b3ffffff"
|
||||
style: Text.Raised
|
||||
styleColor: "#b0000000"
|
||||
font.pixelSize: 18
|
||||
}
|
||||
|
||||
@@ -123,6 +125,9 @@ Item {
|
||||
id: body
|
||||
host: host
|
||||
width: flick.width
|
||||
// The panel sits on the ambient field — fixed light colors
|
||||
// + native shadow (2026-08-31 visual cleanup).
|
||||
overAmbient: true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user