fix(player): make song info responsive

cx
This commit is contained in:
vicrodh committed 2026-08-22 22:26:32 -06:00
1 parent 4e955a2b8b
commit 5160ddf6c1
4 files changed
+77 -22

No files matched your search

+5 -2
View File
@@ -27,8 +27,11 @@ ApplicationWindow {
// This was the title-truncation bug: at the old hardcoded 1280 the
// now-playing bar sat one responsive tier below the Slint build on the same
// machine (1280 < 1366 -> side fraction 0.39 instead of 0.30), so the
// Classic song card capped at ~446px instead of 560 and elided titles ~114px
// early. The tier thresholds were right; the window was the wrong size.
// Classic song card received ~446px instead of the larger mid-tier runway
// and elided titles early. The tier thresholds were right; the window was
// the wrong size. The card now also measures its live neighbouring controls,
// so restored geometry and in-bar allocation solve different parts of the
// same problem rather than relying on a fixed card cap.
//
// These stay plain bindings so the size is correct before the window maps.
// The WM's own resizes write `width`/`height` from C++ — that does not
+13 -2
View File
@@ -272,15 +272,23 @@ Rectangle {
// === B. CONTROLS ROW — symmetric 3 columns =======================
Item {
id: controlsLayout
width: parent.width
height: parent.height - 3
// Intrinsic boundary of the centred transport. The metadata/time
// group may use every pixel before it, regardless of how wide the
// nominal centre zone is at this window size.
readonly property real transportLeft:
centreZone.x + centreTransport.x
// ---- LEFT column: SongCard + Sep + time column --------------
Item {
id: leftZone
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: (root.width - 6) * root.sideFrac
width: Math.max(0, controlsLayout.transportLeft - 8)
// No clip: the Row sums to exactly this column (width-59 + 19
// + 40, spacing 0) and the two time Texts above are now
// bounded, which was the only escape path.
@@ -311,7 +319,8 @@ Rectangle {
// a 74px card would push the 37px cover off-centre.
SongCard {
height: parent.height
width: parent.width - (QbzPlayer.npHasTrack ? 59 : 0)
width: Math.max(0,
parent.width - (QbzPlayer.npHasTrack ? 59 : 0))
artSize: 37
artBorderWidth: 3
artBorderColor: theme.surfaceCard
@@ -365,6 +374,7 @@ Rectangle {
// ---- CENTER column: transport, window-centred --------------
Item {
id: centreZone
anchors.left: parent.left
anchors.leftMargin: (root.width - 6) * root.sideFrac
anchors.top: parent.top
@@ -376,6 +386,7 @@ Rectangle {
// Small bar's own copy was a byte-for-byte twin of the full
// bar's at playCircle:false / classicActions:false.
TransportControls {
id: centreTransport
anchors.centerIn: parent
height: 34
playCircle: false
+45 -13
View File
@@ -14,7 +14,7 @@
// Classic uses a fixed 32.4/35.2/32.4 split (col-side 0.324).
//
// New (0): LEFT SongCard · CENTER transport (filled disc) · RIGHT cluster
// Classic (1): LEFT transport · CENTER glass SongCard (<=560px) · RIGHT cluster
// Classic (1): LEFT transport · elastic glass SongCard · RIGHT cluster
// Large (3): LEFT SongCard WITHOUT the cover (it lives in the sidebar
// dock, shifted right to clear it) · CENTER transport ·
// RIGHT inline AudioStamp + cluster.
@@ -394,23 +394,40 @@ Rectangle {
// --- Controls: the responsive symmetric zones -----------------------
Item {
id: controlsLayout
width: parent.width
height: parent.height - 38
// The three zones keep PLAY centred and the right cluster pinned,
// but the SongCard is sized against the controls themselves, not
// against an arbitrary zone edge. This lets metadata consume the
// centre column's empty runway without ever crossing transport.
readonly property real transportLeft:
centreZone.x + centreTransport.x
readonly property real classicTransportRight: Math.min(
leftZone.x + leftZone.width,
leftZone.x + classicTransport.x + classicTransport.width)
readonly property real rightControlsLeft:
rightZone.x + Math.max(0, rightControls.x)
// LEFT column.
Item {
id: leftZone
anchors.left: parent.left
anchors.leftMargin: 6
width: (parent.width - 12) * root.colSide
height: parent.height
clip: true
// New (0) AND Large (3): the song card (Large drops the cover
// — it lives in the dock — and shifts right to clear it).
// — it lives in the dock — and shifts right to clear it). Its
// right edge follows the ACTUAL transport bounds; subtracting
// the 240px dock from this zone was the old Large-mode bug that
// left long titles only ~260px on a 1700px window.
SongCard {
visible: !root.isClassic
x: root.largeActive ? root.dockWidth + 8 : 0
width: parent.width - x
width: Math.max(0,
controlsLayout.transportLeft - 10 - leftZone.x - x)
anchors.verticalCenter: parent.verticalCenter
showArt: !root.largeActive
showBadges: !root.largeActive
@@ -419,6 +436,7 @@ Rectangle {
// Classic: transport cluster hugging the left edge (plain
// play glyph + inline favorite, the Tauri arrangement).
TransportControls {
id: classicTransport
visible: root.isClassic
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
@@ -433,6 +451,7 @@ Rectangle {
// CENTRE column.
Item {
id: centreZone
x: 6 + (parent.width - 12) * root.colSide
width: (parent.width - 12) * root.colCentre
height: parent.height
@@ -441,6 +460,7 @@ Rectangle {
// New (0) AND Large (3): centred transport, PLAY on the
// window centre.
TransportControls {
id: centreTransport
visible: !root.isClassic
anchors.centerIn: parent
playCircle: true
@@ -448,20 +468,12 @@ Rectangle {
onAddRequested: function (anchorItem) { addMenu.openBelowRight(anchorItem) }
onTrackInfoRequested: root.openTrackInfo()
}
// Classic: the contained glass song card (<=560px cap).
SongCard {
visible: root.isClassic
glass: true
width: Math.min(parent.width, 560)
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
onTrackInfoRequested: root.openTrackInfo()
}
}
// RIGHT column — secondary actions + volume, clustered at the
// right wall.
Item {
id: rightZone
anchors.right: parent.right
anchors.rightMargin: 6
width: (parent.width - 12) * root.colSide
@@ -469,6 +481,7 @@ Rectangle {
clip: true
Row {
id: rightControls
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 1
@@ -638,6 +651,25 @@ Rectangle {
}
}
}
// Classic lives between the REAL left transport and right action
// cluster. It may use at most 90% of that live gap, centred: the
// remaining 5% on each side keeps both the cover edge and the
// in-card AudioStamp visibly detached from their neighbour controls.
// Unlike the old fixed 560px cap this still scales with volume
// steppers, remote state and the actual window width.
SongCard {
visible: root.isClassic
glass: true
readonly property real availableWidth: Math.max(0,
controlsLayout.rightControlsLeft
- controlsLayout.classicTransportRight)
width: availableWidth * 0.90
x: controlsLayout.classicTransportRight
+ (availableWidth - width) / 2
anchors.verticalCenter: parent.verticalCenter
onTrackInfoRequested: root.openTrackInfo()
}
}
Item { width: 1; height: 6 }
+14 -5
View File
@@ -46,6 +46,14 @@ Rectangle {
// full-height, space-distributed column.
property bool textCenter: false
// Furniture is admitted by intrinsic fit, not by a window breakpoint.
// When a host becomes genuinely narrow, metadata keeps the runway and the
// cover/stamp yield before either can sit on top of text.
readonly property bool stampFits: root.width >= stamp.width + 24
readonly property bool effectiveShowArt: root.showArt
&& root.width >= root.artSize + root.artTextGap
+ (stamp.visible ? stamp.width + 4 : 0)
/// Title clicked — the host opens the Track Info modal.
signal trackInfoRequested()
@@ -116,8 +124,8 @@ Rectangle {
spacing: 0
Item {
visible: root.showArt
width: root.showArt ? root.artSize : 0
visible: root.effectiveShowArt
width: root.effectiveShowArt ? root.artSize : 0
height: parent.height
Rectangle {
width: root.artSize
@@ -186,10 +194,11 @@ Rectangle {
}
}
}
Item { width: root.showArt ? root.artTextGap : 0; height: 1 }
Item { width: root.effectiveShowArt ? root.artTextGap : 0; height: 1 }
Column {
width: parent.width - (root.showArt ? root.artSize + root.artTextGap : 0)
width: Math.max(0, parent.width
- (root.effectiveShowArt ? root.artSize + root.artTextGap : 0))
anchors.verticalCenter: parent.verticalCenter
// textCenter tightens the inter-line gap to 1px so the two lines
// read as one block beside the small cover (SongCard.slint:333);
@@ -350,7 +359,7 @@ Rectangle {
SongCardStamp {
id: stamp
visible: root.showBadges && QbzPlayer.npHasTrack
visible: root.showBadges && root.stampFits && QbzPlayer.npHasTrack
anchors.right: parent.right
// Classic (glass) insets the stamp by pad + stamp-right-margin
// (2px each) so it clears the visible card border.