fix(library): correct Tracks viewport restoration
Restore the semantic anchor in viewport coordinates and suppress lazy-page requests while the ListView is being repositioned. This avoids treating content coordinates as screen offsets and prevents recursive page loads during restoration. cx
This commit is contained in:
2 files changed
+19
-4
No files matched your search
@@ -33,6 +33,9 @@ Item {
|
|||||||
// contentY change before that property turns true. All of those changes
|
// contentY change before that property turns true. All of those changes
|
||||||
// describe the same page miss and must collapse into one bridge call.
|
// describe the same page miss and must collapse into one bridge call.
|
||||||
property bool pageRequestPending: false
|
property bool pageRequestPending: false
|
||||||
|
// Programmatic viewport restoration emits the same Flickable signals as
|
||||||
|
// user input. Keep those signals from recursively requesting another page.
|
||||||
|
property bool restoringPageAnchor: false
|
||||||
// Invalidates a deferred viewport restore when another document/model
|
// Invalidates a deferred viewport restore when another document/model
|
||||||
// replacement wins before Qt's next event-loop turn.
|
// replacement wins before Qt's next event-loop turn.
|
||||||
property int entriesEpoch: 0
|
property int entriesEpoch: 0
|
||||||
@@ -40,6 +43,7 @@ Item {
|
|||||||
function requestNextPage(force) {
|
function requestNextPage(force) {
|
||||||
if (root.nativeModelActive
|
if (root.nativeModelActive
|
||||||
|| root.pageRequestPending
|
|| root.pageRequestPending
|
||||||
|
|| root.restoringPageAnchor
|
||||||
|| !QbzLocal.localTracksHasMore
|
|| !QbzLocal.localTracksHasMore
|
||||||
|| QbzLocal.localTracksLoadingMore
|
|| QbzLocal.localTracksLoadingMore
|
||||||
|| QbzLocal.localTracksLoading)
|
|| QbzLocal.localTracksLoading)
|
||||||
@@ -88,8 +92,12 @@ Item {
|
|||||||
return {
|
return {
|
||||||
"id": String(root.entries[i].row.id),
|
"id": String(root.entries[i].row.id),
|
||||||
// Position inside the viewport, including a partially clipped
|
// Position inside the viewport, including a partially clipped
|
||||||
// first row or a group header immediately above it.
|
// first row or a group header immediately above it. A ListView
|
||||||
"screenY": cell ? cell.mapToItem(list, 0, 0).y : 0
|
// delegate's y is in contentItem coordinates, so subtracting the
|
||||||
|
// viewport's contentY is the visual coordinate. mapToItem(list)
|
||||||
|
// preserves the content coordinate here and would add thousands
|
||||||
|
// of rows back into the restore calculation.
|
||||||
|
"screenY": cell ? cell.y - list.contentY : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,15 +123,17 @@ Item {
|
|||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
if (epoch !== root.entriesEpoch || root.nativeModelActive)
|
if (epoch !== root.entriesEpoch || root.nativeModelActive)
|
||||||
return
|
return
|
||||||
|
root.restoringPageAnchor = true
|
||||||
list.forceLayout()
|
list.forceLayout()
|
||||||
list.positionViewAtIndex(target, ListView.Beginning)
|
list.positionViewAtIndex(target, ListView.Beginning)
|
||||||
list.forceLayout()
|
list.forceLayout()
|
||||||
var cell = list.itemAtIndex(target)
|
var cell = list.itemAtIndex(target)
|
||||||
var currentScreenY = cell ? cell.mapToItem(list, 0, 0).y : 0
|
var currentScreenY = cell ? cell.y - list.contentY : 0
|
||||||
var wanted = list.contentY + currentScreenY - anchor.screenY
|
var wanted = list.contentY + currentScreenY - anchor.screenY
|
||||||
var minY = list.originY
|
var minY = list.originY
|
||||||
var maxY = minY + Math.max(0, list.contentHeight - list.height)
|
var maxY = minY + Math.max(0, list.contentHeight - list.height)
|
||||||
list.contentY = Math.max(minY, Math.min(wanted, maxY))
|
list.contentY = Math.max(minY, Math.min(wanted, maxY))
|
||||||
|
root.restoringPageAnchor = false
|
||||||
root.reportSoon()
|
root.reportSoon()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -528,7 +528,12 @@ mod phase_a_tests {
|
|||||||
let qml = include_str!("../qml/views/local/LocalTracksTab.qml");
|
let qml = include_str!("../qml/views/local/LocalTracksTab.qml");
|
||||||
assert!(qml.contains("function capturePageAnchor()"));
|
assert!(qml.contains("function capturePageAnchor()"));
|
||||||
assert!(qml.contains("String(root.entries[i].row.id)"));
|
assert!(qml.contains("String(root.entries[i].row.id)"));
|
||||||
assert!(qml.contains("cell.mapToItem(list, 0, 0).y"));
|
assert!(qml.contains("cell.y - list.contentY"));
|
||||||
|
assert!(!qml.contains("cell.mapToItem(list"));
|
||||||
|
assert!(qml.contains("|| root.restoringPageAnchor"));
|
||||||
|
assert!(qml.contains(
|
||||||
|
"var wanted = list.contentY + currentScreenY - anchor.screenY"
|
||||||
|
));
|
||||||
assert!(qml.contains("function restorePageAnchor(anchor, nextEntries, epoch)"));
|
assert!(qml.contains("function restorePageAnchor(anchor, nextEntries, epoch)"));
|
||||||
assert!(qml.contains("Qt.callLater(function ()"));
|
assert!(qml.contains("Qt.callLater(function ()"));
|
||||||
assert!(qml.contains("list.positionViewAtIndex(target, ListView.Beginning)"));
|
assert!(qml.contains("list.positionViewAtIndex(target, ListView.Beginning)"));
|
||||||
|
|||||||
Reference in new issue
Block a user