fix(qbz-qt): finish compact album header layout
cx
This commit is contained in:
5 files changed
+144
-23
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user