fix(qbz-qt): preserve collection builder viewport
cx
This commit is contained in:
1 file changed
+38
-24
@@ -41,7 +41,7 @@ Rectangle {
|
||||
|
||||
QbzTheme { id: theme }
|
||||
|
||||
readonly property var doc: parseDoc()
|
||||
property var doc: ({})
|
||||
function parseDoc() {
|
||||
try {
|
||||
return JSON.parse(QbzDisco.discoJson)
|
||||
@@ -49,6 +49,33 @@ Rectangle {
|
||||
return ({})
|
||||
}
|
||||
}
|
||||
|
||||
// `rows` is a plain JS array, so every Rust publish assigns a brand-new
|
||||
// ListView model. Capture the viewport BEFORE assigning `doc`; trying to
|
||||
// recover it from onRowsChanged is already too late because Qt may have
|
||||
// reset contentY during the binding update.
|
||||
property int documentEpoch: 0
|
||||
function applyDocument() {
|
||||
var next = root.parseDoc()
|
||||
var currentArtist = root.doc.artistId || ""
|
||||
var nextArtist = next.artistId || ""
|
||||
var preserve = nextArtist !== "" && nextArtist === currentArtist
|
||||
&& next.loading !== true
|
||||
var savedY = preserve ? rowList.contentY : 0
|
||||
root.documentEpoch += 1
|
||||
var epoch = root.documentEpoch
|
||||
root.doc = next
|
||||
Qt.callLater(function () {
|
||||
if (epoch !== root.documentEpoch)
|
||||
return
|
||||
rowList.forceLayout()
|
||||
var minY = rowList.originY
|
||||
var maxY = minY + Math.max(0,
|
||||
rowList.contentHeight - rowList.height)
|
||||
rowList.contentY = preserve
|
||||
? Math.max(minY, Math.min(savedY, maxY)) : minY
|
||||
})
|
||||
}
|
||||
function t(s) { return QbzSession.tr(s, QbzSession.trRev) }
|
||||
|
||||
// --- Document slices (spec 02 §5.8 DiscoDoc) --------------------------
|
||||
@@ -95,14 +122,12 @@ Rectangle {
|
||||
onLoadingChanged: if (root.loading) {
|
||||
root.nameEdited = false
|
||||
root.collectionName = ""
|
||||
// A fresh load is a fresh table: without this the preserved offset
|
||||
// (below) survives into the NEXT artist and `restoreScroll` opens his
|
||||
// discography already scrolled to the previous one's row. Slint's
|
||||
// Flickable lands at the top because `reset` empties the viewport.
|
||||
root.keepY = 0
|
||||
}
|
||||
Component.onCompleted: if (!root.nameEdited && root.collectionName === "")
|
||||
root.collectionName = root.defaultName
|
||||
Component.onCompleted: {
|
||||
root.applyDocument()
|
||||
if (!root.nameEdited && root.collectionName === "")
|
||||
root.collectionName = root.defaultName
|
||||
}
|
||||
|
||||
// Footer count. Rust pre-renders the ONE true plural in this domain with
|
||||
// `qbz_i18n::tf` and publishes it as `footerCount` (spec 01 §4/§8.7) —
|
||||
@@ -143,21 +168,6 @@ Rectangle {
|
||||
]
|
||||
}
|
||||
|
||||
// --- Scroll preservation ----------------------------------------------
|
||||
// Every mutation (a checkbox, an override, a re-sort) republishes the whole
|
||||
// DiscoDoc, so `groups` is a NEW array and QQuickItemView::setModel()
|
||||
// resets contentY to 0 — one checkbox click would throw the user from row
|
||||
// 40 to the top. Slint's Flickable keeps its viewport-y across the same
|
||||
// republish, so restoring it IS the parity behaviour.
|
||||
property real keepY: 0
|
||||
onRowsChanged: Qt.callLater(root.restoreScroll)
|
||||
function restoreScroll() {
|
||||
if (root.keepY <= 0 || rowList.contentY > 0)
|
||||
return
|
||||
rowList.contentY = Math.min(
|
||||
root.keepY, Math.max(0, rowList.contentHeight - rowList.height))
|
||||
}
|
||||
|
||||
// --- Everything above the table (the ListView header) ------------------
|
||||
Component {
|
||||
id: pageHead
|
||||
@@ -409,7 +419,6 @@ Rectangle {
|
||||
model: root.populated ? root.rows : []
|
||||
header: pageHead
|
||||
footer: bottomPad
|
||||
onContentYChanged: if (contentY > 0) root.keepY = contentY
|
||||
|
||||
// ONE row — a group's primary, or one of its alternates (:705-722).
|
||||
// Every field comes off the Rust row descriptor: `restOpacity` is
|
||||
@@ -427,6 +436,11 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: QbzDisco
|
||||
function onDiscoJsonChanged() { root.applyDocument() }
|
||||
}
|
||||
|
||||
// Back/forward scroll memory (controls/ScrollMemory.qml): reports
|
||||
// this container's offset while it is the live page, and restores it
|
||||
// when a back/forward step arms this route.
|
||||
|
||||
Reference in new issue
Block a user