diff --git a/crates/qbz-qt/qml/views/ArtistView.qml b/crates/qbz-qt/qml/views/ArtistView.qml index 3d87a6c2e..fe0f90cb3 100644 --- a/crates/qbz-qt/qml/views/ArtistView.qml +++ b/crates/qbz-qt/qml/views/ArtistView.qml @@ -41,6 +41,7 @@ import com.blitzfc.qbz import "../cards" import "../controls" import "../rows" +import "../shell" import "../theme" Rectangle { @@ -865,6 +866,28 @@ Rectangle { // paint. Arrivals are coalesced into ONE rebind per frame — the same fix // LocalLibraryView carries, at O(n) instead of O(n²), with the covers // still appearing progressively (16ms granularity is invisible). + // --- Track info for the Popular Tracks rows (2026-09-13) --------------- + // ONE lazy modal per artist view (the full Popup tree must not exist per + // row). Activated on demand, torn down on close (Qt.callLater so the + // Popup is not destroyed mid-signal) — the same shape rows/TrackRow.qml + // carries per row. + Loader { + id: artistTrackInfo + active: false + sourceComponent: TrackInfoModal { } + } + Connections { + target: artistTrackInfo.item + ignoreUnknownSignals: true + function onClosed() { Qt.callLater(function () { artistTrackInfo.active = false }) } + } + function openTrackInfo(trackId) { + if (!trackId || trackId === "") + return + artistTrackInfo.active = true + artistTrackInfo.item.openFor(trackId) + } + property var _coverInbox: ({}) Timer { id: coverFlush @@ -1688,11 +1711,11 @@ Rectangle { // `controls/CardMenu.qml`, the same primitive rows/TrackRow.qml opens. // // ABSENT, not dead (the same discipline TrackRow applies): the radio - // pair, Share Qobuz link / Song.link and Track info. The first two - // need bridge seams that do not exist; the last needs the shared - // row's lazy Loader (a TrackInfoModal), and duplicating those per - // artist row is exactly the fork-drift this file already paid for - // once. (The offline block IS wired — it needs no Loader.) + // pair and Share Qobuz link / Song.link, which need bridge seams that + // do not exist. Track info IS wired (2026-09-13) through ONE lazy + // TrackInfoModal per artist view (`artistTrackInfo` below), not one + // per row — the per-row Loader rows/TrackRow.qml carries is what this + // comment used to refuse to duplicate. CardMenu { id: popMenu menuWidth: 224 @@ -1749,6 +1772,8 @@ Rectangle { m.push({ "label": t("Go to album", r), "icon": "disc-3", "action": "go-album" }) if ((popRow.row.artistId || "") !== "") m.push({ "label": t("Go to artist", r), "icon": "user", "action": "go-artist" }) + if (!popRow.pulled) + m.push({ "label": t("Track info", r), "icon": "info", "action": "track-info" }) return m } onPicked: function (a) { @@ -1781,6 +1806,7 @@ Rectangle { else if (a === "recache") QbzPlayer.recacheTrack(id) else if (a === "go-album") QbzAlbum.openAlbum(popRow.row.albumId) else if (a === "go-artist") QbzArtist.openArtist(popRow.row.artistId) + else if (a === "track-info") root.openTrackInfo(id) } } @@ -2759,29 +2785,26 @@ Rectangle { onAction: function (id) { root.bulkAction(id) } } + // Air between the sticky JUMP TO bar's rule and the row. + Item { visible: topTracks.length > 0; width: 1; height: 8 } Row { property string anchorId: "popular-tracks" visible: topTracks.length > 0 width: parent.width spacing: 12 Text { - width: parent.width - 44 - 32 - 32 - 3 * 12 + width: parent.width - 32 - 32 - 32 - 3 * 12 anchors.verticalCenter: parent.verticalCenter text: QbzSession.tr("Popular Tracks", QbzSession.trRev) color: theme.textPrimary font.pixelSize: theme.fontHeading font.weight: theme.weightSemibold } - // ArtistPageView.slint:732-737 mounts the SHARED - // CircleAction here — `primary: true` plus an explicit - // `on-surface: true` with the .slint's own reason on the - // line above it: "Plain page background (below the header - // divider) — theme-aware variant so it reads on light - // themes." The port hand-rolled a 44px accent disc - // instead, which duplicated the control AND bypassed that - // arm. `overlay` defaults false = the on-surface arm. + // The SHARED CircleAction, in the same plain 32px outlined + // form as its two siblings (2026-09-13): the filled 44px + // accent disc the .slint carried here clashed with them + // and butted the JUMP TO bar's rule. QbzCircleAction { - primary: true name: "play-fill" anchors.verticalCenter: parent.verticalCenter onClicked: QbzPlayer.playArtistTop(false)