fix(qbz-qt): finish compact album header layout

cx
This commit is contained in:
vicrodh committed 2026-08-25 23:58:45 -06:00
1 parent 6dd0f8da7f
commit bae1523abf
5 files changed
+144 -23

No files matched your search

+12 -4
View File
@@ -71,6 +71,10 @@ Rectangle {
/// Preserve the primary action palette while using the secondary action's
/// footprint. Album headers use this when their global compact mode is on.
property bool compactPrimary: false
/// Optional footprint for exceptionally dense hosts. Zero keeps the
/// canonical 44/32px sizes; compact album headers use 28px for every
/// action so Play no longer dominates the row.
property int diameterOverride: 0
property bool btnEnabled: true
/// While the action's work is in flight the glyph swaps for a spinning
/// arc (CircleAction.slint:18 / :77 — the reference has this arm and the
@@ -91,9 +95,11 @@ Rectangle {
readonly property string onSurfaceTint: "textPrimary"
readonly property bool largePrimary: primary && !compactPrimary
readonly property int resolvedDiameter: diameterOverride > 0
? diameterOverride : (largePrimary ? 44 : 32)
width: largePrimary ? 44 : 32
height: largePrimary ? 44 : 32
width: resolvedDiameter
height: resolvedDiameter
radius: width / 2
color: overlay
? (primary
@@ -159,8 +165,10 @@ Rectangle {
QbzIcon {
visible: !root.loading
name: root.name
width: root.largePrimary ? 19 : 15
height: root.largePrimary ? 19 : 15
width: root.diameterOverride > 0
? Math.round(root.resolvedDiameter * 0.46)
: (root.largePrimary ? 19 : 15)
height: width
// Whole-pixel centring, both axes — CircleAction.slint:67-68 rounds
// them explicitly for the same reason: 44-19 and 32-15 are both ODD,
// so `anchors.centerIn` lands the glyph on 12.5px / 8.5px and the
+8 -6
View File
@@ -130,6 +130,7 @@ Item {
property bool headerRound: false
property bool compactHeader: false
property int actionCount: 0
property real actionSize: 32
// "cardGrid" — cell pitch vs the card drawn inside it.
property real cellW: 220
property real cellH: 266
@@ -407,6 +408,7 @@ Item {
opacity: root.breathe
}
Rectangle {
visible: !root.compactHeader
y: root.compactHeader ? 34 : 23
width: root.compactHeader ? Math.min(parent.width, 260)
: Math.min(parent.width, 420)
@@ -416,7 +418,7 @@ Item {
opacity: root.breathe
}
Rectangle {
y: root.compactHeader ? 56 : 63
y: root.compactHeader ? 40 : 63
width: Math.min(parent.width, 300)
height: 14
radius: root.blockRadius
@@ -436,11 +438,11 @@ Item {
model: root.actionCount
delegate: Rectangle {
required property int index
x: index * 44
y: root.compactHeader ? 80 : 110
width: 32
height: 32
radius: 16
x: index * (root.actionSize + 12)
y: root.compactHeader ? 70 : 110
width: root.actionSize
height: root.actionSize
radius: root.actionSize / 2
color: theme.surfaceElevated
opacity: root.breathe
}
+67 -10
View File
@@ -767,9 +767,9 @@ Rectangle {
spacing: root.compactHeaderPref ? 4 : 12
Item { width: 1; height: root.compactHeaderPref ? 0 : 6 }
QbzSkeleton { variant: "block"; width: Math.min(420, parent.width); height: root.compactHeaderPref ? 24 : 30; cellIndex: 0; phase: skeletonPhase.on }
QbzSkeleton { variant: "block"; width: Math.min(260, parent.width); height: root.compactHeaderPref ? 16 : 18; cellIndex: 1; phase: skeletonPhase.on }
QbzSkeleton { visible: !root.compactHeaderPref; variant: "block"; width: Math.min(260, parent.width); height: 18; cellIndex: 1; phase: skeletonPhase.on }
QbzSkeleton { variant: "block"; width: Math.min(340, parent.width); height: 14; cellIndex: 2; phase: skeletonPhase.on }
Item { width: 1; height: root.compactHeaderPref ? 4 : 14 }
Item { width: 1; height: root.compactHeaderPref ? 10 : 14 }
Row {
spacing: 12
Repeater {
@@ -777,8 +777,8 @@ Rectangle {
delegate: QbzSkeleton {
required property int index
variant: "circle"
width: root.compactHeaderPref ? 32 : 44
height: root.compactHeaderPref ? 32 : 44
width: root.compactHeaderPref ? 28 : 44
height: width
cellIndex: index
phase: skeletonPhase.on
}
@@ -839,6 +839,7 @@ Rectangle {
height: Math.max(albumTitle.implicitHeight, 32)
Text {
id: albumTitle
visible: !root.compactHeaderPref
anchors.left: parent.left
anchors.right: headerModeButton.left
anchors.rightMargin: 12
@@ -849,13 +850,62 @@ Rectangle {
font.weight: theme.weightBold
elide: Text.ElideRight
}
Row {
id: compactHeading
visible: root.compactHeaderPref
anchors.left: parent.left
anchors.right: headerModeButton.left
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
spacing: 0
Text {
id: compactAlbumTitle
width: (albumHeader.artist || "") === ""
? compactHeading.width
: Math.min(implicitWidth,
Math.max(80, compactHeading.width * 0.62))
text: albumHeader.title || ""
color: root.hdrStrong
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
elide: Text.ElideRight
}
Text {
id: compactTitleSeparator
visible: (albumHeader.artist || "") !== ""
text: " • "
color: root.hdrBody
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
}
Text {
width: Math.max(0, compactHeading.width
- compactAlbumTitle.width
- compactTitleSeparator.width)
text: albumHeader.artist || ""
color: compactArtistArea.containsMouse
&& (albumHeader.artistId || "") !== ""
? root.hdrStrong : root.hdrBody
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
elide: Text.ElideRight
MouseArea {
id: compactArtistArea
anchors.fill: parent
enabled: (albumHeader.artistId || "") !== ""
hoverEnabled: true
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: QbzArtist.openArtist(albumHeader.artistId)
}
}
}
QbzIconButton {
id: headerModeButton
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: -4
btnSize: 26
iconSize: 13
btnSize: root.compactHeaderPref ? 22 : 26
iconSize: root.compactHeaderPref ? 11 : 13
name: root.compactHeaderPref ? "maximize-2" : "minimize-2"
tintOverride: root.hdrOverlay ? "white" : ""
onClicked: root.toggleCompactHeader()
@@ -870,12 +920,11 @@ Rectangle {
Item { width: 1; height: root.compactHeaderPref ? 2 : 4 }
// Credited-artist line (links + role suffixes).
Flow {
visible: !root.compactHeaderPref
width: parent.width
spacing: 0
Repeater {
model: root.compactHeaderPref
? [[albumHeader.artist || "", albumHeader.artistId || "", ""]]
: (albumHeader.credits || [])
model: albumHeader.credits || []
delegate: Row {
required property var modelData
required property int index
@@ -1004,7 +1053,7 @@ Rectangle {
}
}
Item { width: 1; height: root.compactHeaderPref ? 4 : 20 }
Item { width: 1; height: root.compactHeaderPref ? 10 : 20 }
// Action row — AlbumPageView.slint:504-640. One shared
// CircleAction for every button including Play (the
// hand-rolled 44px disc it used to be drifted from the
@@ -1016,6 +1065,7 @@ Rectangle {
QbzCircleAction {
primary: true
compactPrimary: root.compactHeaderPref
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
name: "play-fill"
anchors.verticalCenter: parent.verticalCenter
@@ -1023,6 +1073,7 @@ Rectangle {
}
QbzCircleAction {
name: "shuffle"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzPlayer.playAlbumShuffled(albumHeader.id)
@@ -1030,6 +1081,7 @@ Rectangle {
QbzCircleAction {
readonly property bool favorite: root.toggleState("album", albumHeader.isFavorite)
name: favorite ? "heart-filled" : "heart"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
active: favorite
anchors.verticalCenter: parent.verticalCenter
@@ -1043,6 +1095,7 @@ Rectangle {
// minimal track objects are enriched before play).
QbzCircleAction {
name: "radio"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
// A radio is a fetch + an enrich + a queue write,
// and until the first track resolves nothing on
@@ -1057,6 +1110,7 @@ Rectangle {
QbzCircleAction {
visible: albumHeader.hasBooklet === true
name: "book-open"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzAlbum.downloadBooklet()
@@ -1065,6 +1119,7 @@ Rectangle {
// BOTH kinds — myqbz_add_qt's Accepts engine).
QbzCircleAction {
name: "cassette-tape"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzAlbum.addToMixtape(albumHeader.id)
@@ -1073,6 +1128,7 @@ Rectangle {
// (AlbumInfoModal.qml, data via album_info_qt.rs).
QbzCircleAction {
name: "info"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
anchors.verticalCenter: parent.verticalCenter
onClicked: albumInfo.openFor(albumHeader.id)
@@ -1080,6 +1136,7 @@ Rectangle {
QbzCircleAction {
id: albumMenuBtn
name: "ellipsis"
diameterOverride: root.compactHeaderPref ? 28 : 0
overlay: root.hdrOverlay
anchors.verticalCenter: parent.verticalCenter
onClicked: function (mouse) { albumMenu.openAtCursor(albumMenuBtn, mouse.x, mouse.y) }
@@ -433,6 +433,7 @@ Rectangle {
coverGap: root.compactHeaderPref ? 20 : 32
compactHeader: root.compactHeaderPref
actionCount: 5
actionSize: root.compactHeaderPref ? 28 : 32
phase: root.skelPhase
}
LocalAlbumHeader {
@@ -82,6 +82,7 @@ Row {
height: Math.max(localAlbumTitle.implicitHeight, 32)
Text {
id: localAlbumTitle
visible: !root.compact
anchors.left: parent.left
anchors.right: localHeaderModeButton.left
anchors.rightMargin: 12
@@ -92,13 +93,59 @@ Row {
font.weight: theme.weightBold
elide: Text.ElideRight
}
Row {
id: compactHeading
visible: root.compact
anchors.left: parent.left
anchors.right: localHeaderModeButton.left
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
spacing: 0
Text {
id: compactAlbumTitle
width: !root.album || (root.album.artist || "") === ""
? compactHeading.width
: Math.min(implicitWidth,
Math.max(80, compactHeading.width * 0.62))
text: root.album ? (root.album.title || "") : ""
color: theme.textPrimary
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
elide: Text.ElideRight
}
Text {
id: compactTitleSeparator
visible: root.album && (root.album.artist || "") !== ""
text: " • "
color: theme.textSecondary
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
}
Text {
width: Math.max(0, compactHeading.width
- compactAlbumTitle.width - compactTitleSeparator.width)
text: root.album ? (root.album.artist || "") : ""
color: compactArtistArea.containsMouse
? theme.textPrimary : theme.textSecondary
font.pixelSize: theme.fontSection
font.weight: theme.weightBold
elide: Text.ElideRight
MouseArea {
id: compactArtistArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: if (root.album) root.openArtist(root.album.artist)
}
}
}
QbzIconButton {
id: localHeaderModeButton
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: -4
btnSize: 26
iconSize: 13
btnSize: root.compact ? 22 : 26
iconSize: root.compact ? 11 : 13
name: root.compact ? "maximize-2" : "minimize-2"
onClicked: root.compactToggled()
HoverHandler { id: localHeaderModeHover }
@@ -111,6 +158,7 @@ Row {
}
Item { width: 1; height: root.compact ? 2 : 4 }
Row {
visible: !root.compact
spacing: 8
Text {
text: root.album ? (root.album.artist || "") : ""
@@ -181,7 +229,7 @@ Row {
font.pixelSize: theme.fontBody
elide: Text.ElideRight
}
Item { width: 1; height: root.compact ? 4 : 20 }
Item { width: 1; height: root.compact ? 10 : 20 }
// ---- Local action row ----
Row {
@@ -190,26 +238,31 @@ Row {
name: "play-fill"
primary: true
compactPrimary: root.compact
diameterOverride: root.compact ? 28 : 0
onClicked: QbzLocal.albumSelectedAction("play", "")
}
QbzCircleAction {
name: "shuffle"
diameterOverride: root.compact ? 28 : 0
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzLocal.albumSelectedAction("shuffle", "")
}
// ASSET GAP: Slint uses `pencil`; the Qt set ships pen-line.
QbzCircleAction {
name: "pen-line"
diameterOverride: root.compact ? 28 : 0
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzLocal.albumEditTags(root.album.id)
}
QbzCircleAction {
name: "list-plus"
diameterOverride: root.compact ? 28 : 0
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzLocal.albumAddToPlaylist(root.album.id)
}
QbzCircleAction {
name: "cassette-tape"
diameterOverride: root.compact ? 28 : 0
anchors.verticalCenter: parent.verticalCenter
onClicked: QbzLocal.albumAddToMixtape(root.album.id)
}