fix(qt): NPB Small mounts the shared song card
The Small bar hand-rolled a reduced copy of the song card inline: album art plus a two-line title/artist block. All three features the owner reported missing live in SongCard.qml and only there -- the "layers" playback-context glyph with open-context(), the album name in the meta row, and the hover area that publishes the floating art preview. The overlay itself was already mounted shell-level with no bar-mode gate; it simply never had a writer while Small was loaded. PlayerBarSmall.slint mounts the shared SongCard with text-center, so this is the port catching up rather than a redesign: art-size 37, art-border 3px surface-card, show-badges false, title 13px, art-text-gap 9. The 18px meta row fits the 39px controls row with ~1px clearance, and the loading scrim on the cover comes along with it, as it does in Slint. Also folds the responsive tier arms into shared helpers so the four bar modes cannot drift apart on the 1366/1920 breakpoints. cc
This commit is contained in:
4 files changed
+51
-89
No files matched your search
@@ -253,7 +253,7 @@ Rectangle {
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.centerIn: parent
|
||||
tintName: tmCloseArea.containsMouse ? "primary" : "muted"
|
||||
tintName: tmCloseArea.containsMouse ? "textPrimary" : "muted"
|
||||
}
|
||||
MouseArea {
|
||||
id: tmCloseArea
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
//
|
||||
// 3px full-width top seekbar (3-color: background / cache / progress),
|
||||
// then the symmetric 3-column controls row (~39px):
|
||||
// LEFT — 37px album art + 2-line title/artist + fixed time column
|
||||
// LEFT — the SHARED shell/SongCard.qml in its text-center (Small) arm
|
||||
// (37px bordered cover + 13px title over the [layers] · artist ·
|
||||
// album meta row) + the fixed 40px time column
|
||||
// CENTER — transport cluster (info · shuffle · prev · play · next ·
|
||||
// repeat · +)
|
||||
// RIGHT — AudioStamp · Connect · Cast · Settings · ViewMode · Lyrics ·
|
||||
@@ -47,14 +49,16 @@ Rectangle {
|
||||
|
||||
// Responsive side fraction — IDENTICAL to PlayerBarSmall's mechanism:
|
||||
// LEFT and RIGHT columns share this fraction so the CENTER transport
|
||||
// column lands PLAY on the window centre.
|
||||
// width < 1366 -> 39% | 22% | 39%
|
||||
// 1366..<1920 -> 30% | 40% | 30%
|
||||
// width >= 1920 -> 25% | 50% | 25%
|
||||
property real sideFrac: root.width >= 1920 ? 0.25 : (root.width >= 1366 ? 0.30 : 0.39)
|
||||
// column lands PLAY on the window centre. The breakpoints (39/30/25 at
|
||||
// 1366 / 1920) are the SHARED theme token, so this bar and PlayerBar can
|
||||
// never drift apart — see QbzTheme.npbSideFrac.
|
||||
// `root.width` IS the window width: the bar is anchored left-to-right on
|
||||
// the shell root, exactly like PlayerBarSmall.slint reads its own root.
|
||||
property real sideFrac: theme.npbSideFrac(root.width)
|
||||
property real colCentre: 1.0 - 2.0 * root.sideFrac
|
||||
// WIDE = inline horizontal volume slider; NARROW = button-only.
|
||||
property bool volumeWide: root.width >= 1366
|
||||
// Same 1366 edge as the side fraction (PlayerBarSmall.slint:152).
|
||||
property bool volumeWide: root.width >= theme.npbBreakMid
|
||||
|
||||
// Favorite state of the now-playing track (Slint:
|
||||
// QueueState.now-playing-favorite) — the queue document carries it on its
|
||||
@@ -181,7 +185,7 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height - 3
|
||||
|
||||
// ---- LEFT column: art + title/artist + time column ---------
|
||||
// ---- LEFT column: SongCard + Sep + time column --------------
|
||||
Item {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
@@ -193,81 +197,37 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
// Song card: 37px art (3px surface-card border, flush to
|
||||
// the window's left edge) + tight 2-line text block.
|
||||
// Song card: the SHARED shell/SongCard.qml in its
|
||||
// text-center arm — 37px cover (3px surface-card border,
|
||||
// flush to the window's left edge) + the 13px title over
|
||||
// the [layers] · artist · album meta row. 1:1 with
|
||||
// PlayerBarSmall.slint:238-267, which mounts the very same
|
||||
// SongCard with these exact knobs.
|
||||
//
|
||||
// This REPLACES a hand-rolled 2-line copy (art + title +
|
||||
// artist Text) that silently dropped three things living
|
||||
// only inside SongCard: the context glyph, the album link
|
||||
// and the floating cover preview (SongCard's artHover is
|
||||
// the ONLY writer of QbzShell.artPreviewShow, so the
|
||||
// shell's ArtPreviewOverlay was simply never armed in
|
||||
// Small). Rule 5 — reuse, don't fork.
|
||||
//
|
||||
// Width = the column minus the Sep + time column, so the
|
||||
// title elides at exactly the free space.
|
||||
Item {
|
||||
// title and the meta budget elide at exactly the free
|
||||
// space. Height = the 39px controls row: BOTH must be
|
||||
// explicit, because SongCard's own defaults are 200x74 and
|
||||
// a 74px card would push the 37px cover off-centre.
|
||||
SongCard {
|
||||
height: parent.height
|
||||
width: parent.width - (QbzPlayer.npHasTrack ? 59 : 0)
|
||||
|
||||
Rectangle {
|
||||
id: artBox
|
||||
width: 37
|
||||
height: 37
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: 6
|
||||
border.width: 3
|
||||
border.color: theme.surfaceCard
|
||||
color: theme.surfaceElevated
|
||||
clip: true
|
||||
|
||||
RoundedImage {
|
||||
anchors.fill: parent
|
||||
source: QbzPlayer.npArtworkPath
|
||||
radius: 6
|
||||
}
|
||||
// Idle (no track): a STATIC album glyph
|
||||
// placeholder (50% of the art size, muted).
|
||||
QbzIcon {
|
||||
visible: !QbzPlayer.npHasTrack
|
||||
name: "music"
|
||||
width: 18.5
|
||||
height: 18.5
|
||||
anchors.centerIn: parent
|
||||
tintName: "muted"
|
||||
}
|
||||
}
|
||||
|
||||
// Title + artist — constrained to the art's inner
|
||||
// height (37 − 2×3 = 31px) and vertically centred
|
||||
// (SongCard text-center).
|
||||
Column {
|
||||
id: metaBlock
|
||||
width: Math.max(0, parent.width - 37 - 9)
|
||||
height: 31
|
||||
anchors.left: artBox.right
|
||||
anchors.leftMargin: 9
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 1
|
||||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: QbzPlayer.npHasTrack
|
||||
? QbzPlayer.npTitle : QbzSession.tr("Nothing playing", QbzSession.trRev)
|
||||
color: theme.textPrimary
|
||||
font.pixelSize: 13
|
||||
font.weight: theme.weightMedium
|
||||
elide: Text.ElideRight
|
||||
// Title -> Track Info (SongCard.slint fires
|
||||
// track-info from the title). Child of the
|
||||
// Text so it takes no room in the Column.
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: root.qobuzTrack ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: root.openTrackInfo()
|
||||
}
|
||||
}
|
||||
Text {
|
||||
visible: QbzPlayer.npHasTrack
|
||||
width: parent.width
|
||||
text: QbzPlayer.npArtist
|
||||
color: theme.textMuted
|
||||
font.pixelSize: 11
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
artSize: 37
|
||||
artBorderWidth: 3
|
||||
artBorderColor: theme.surfaceCard
|
||||
artTextGap: 9
|
||||
titleFontSize: 13
|
||||
showBadges: false
|
||||
textCenter: true
|
||||
onTrackInfoRequested: root.openTrackInfo()
|
||||
}
|
||||
|
||||
// Separator: song-card | time column (8px toward the
|
||||
|
||||
@@ -71,8 +71,12 @@ Rectangle {
|
||||
|
||||
// Responsive zones (PlayerBar.slint). Classic fixes col-side at 0.324;
|
||||
// New/Large use the width-driven side fraction. Both keep the two side
|
||||
// columns EQUAL so the centre column stays dead centre.
|
||||
property real sideFrac: root.width >= 1920 ? 0.25 : (root.width >= 1366 ? 0.30 : 0.39)
|
||||
// columns EQUAL so the centre column stays dead centre. The breakpoints
|
||||
// are the SHARED theme token (QbzTheme.npbSideFrac) — the Small bar reads
|
||||
// the same one, so the two bars cannot drift apart.
|
||||
// `root.width` IS the window width: the bar is anchored left-to-right on
|
||||
// the shell root, exactly like PlayerBar.slint reads its own root.
|
||||
property real sideFrac: theme.npbSideFrac(root.width)
|
||||
property real colSide: isClassic ? 0.324 : sideFrac
|
||||
property real colCentre: 1.0 - 2.0 * colSide
|
||||
// The docked-cover width the Large seek arm + song card must clear
|
||||
|
||||
@@ -87,12 +87,10 @@ Rectangle {
|
||||
|
||||
QbzTheme { id: theme }
|
||||
|
||||
// Bake matching the LIVE Theme.text-primary (SongCard.slint:504 tints the
|
||||
// context-stack glyph text-primary on hover, text-muted idle). A
|
||||
// hardcoded bake name is a dark-theme-only colour — see QbzIconButton's
|
||||
// header. text-muted keeps the "muted" bake: #888888 reads on both
|
||||
// polarities.
|
||||
readonly property string tintStrong: theme.textPrimary.hslLightness > 0.5 ? "primary" : "black"
|
||||
// SongCard.slint:504 tints the context-stack glyph text-primary on hover,
|
||||
// text-muted idle. Both are runtime-tinted (see QbzIconButton's header),
|
||||
// so this is the live token, not a fixed bake picked by lightness.
|
||||
readonly property string tintStrong: "textPrimary"
|
||||
|
||||
width: 200
|
||||
height: glass ? 64 : 74
|
||||
|
||||
Reference in new issue
Block a user