Load the window around the whole view, not around its first cell
The bottom row of the grid was often blank, at a scroll position the user could sit at indefinitely. Two numbers decided when the loaded window follows the view, they lived in different languages, and they disagreed. The grid loaded three screenfuls and Rust held the window still until the first visible cell was three quarters of the way through them. Three quarters of three screenfuls is 2.25, and the view itself is one screenful tall — so the bottom of the screen had already travelled a quarter of a screenful past the last loaded cell before anything moved. Those rows are not in the model, so nothing is drawn for them. The same margin was wrong upward, and exactly so. The window is placed a quarter of itself behind the view, and the margin then declared the view too close to the top at precisely that distance: every single row scrolled upward re-read the catalog, rebuilt all 360 cells and re-queried their badges and ratings, and so did the row after it. So the grid now reports what it shows — a screenful, counting the row the scroll position has cut in half, which `visible-rows` alone undercounts and which is exactly the row reported missing — and Rust owns the rest: four screenfuls loaded, placed a quarter back, and moved once the view comes within half a screenful of an edge of them. One decision in one place, and the test now walks the view the length of the library and asserts the window covers it at every step. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+24
-12
@@ -1089,9 +1089,15 @@ export component LibraryGrid inherits Rectangle {
|
||||
/// The grid scrolled: the first visible image's ordinal in the library.
|
||||
/// Rust answers by loading the window around that position.
|
||||
callback scrolled(int);
|
||||
/// The viewport can now hold a different number of cells — a resize, or a
|
||||
/// column-count change. Rust resizes the loaded window to match.
|
||||
callback capacity-changed(int);
|
||||
/// How many cells the viewport can show at once changed — a resize, or a
|
||||
/// column-count change.
|
||||
///
|
||||
/// The *screenful*, not the window to load. How many screenfuls are held
|
||||
/// around it, and how close the view may come to an edge of them before
|
||||
/// the window moves, are one decision and it is made in Rust — split
|
||||
/// across the two languages they drifted apart, and the gap between them
|
||||
/// was rows on screen that no loaded cell covered.
|
||||
callback viewport-cells-changed(int);
|
||||
|
||||
// Thumbnail progress is no longer reported here: the batch belongs to a
|
||||
// window of the grid rather than to anything the user asked for, and the
|
||||
@@ -1506,16 +1512,22 @@ export component LibraryGrid inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// How many cells the viewport holds, plus a screenful either side so
|
||||
// scrolling has loaded rows to move into rather than blank ones.
|
||||
//
|
||||
// Derived rather than a constant: a fixed window is simultaneously too
|
||||
// small on a maximised 4K window — where three screenfuls fit inside it —
|
||||
// and wasteful on a narrow one.
|
||||
// How tall a screenful is, in rows. Measured rather than fixed: the same
|
||||
// constant is simultaneously too small on a maximised 4K window and
|
||||
// wasteful on a narrow one, and everything the loaded window does is
|
||||
// expressed as a multiple of this.
|
||||
property <int> visible-rows:
|
||||
max(1, ceil(grid-area.height / (cell-size + Theme.gap)));
|
||||
property <int> capacity: root.columns * (root.visible-rows * 3);
|
||||
changed capacity => { root.capacity-changed(root.capacity); }
|
||||
/// Cells the viewport shows at once, counting the row the scroll position
|
||||
/// has cut in half.
|
||||
///
|
||||
/// `visible-rows` is a ceiling on a grid whose first row starts at the top
|
||||
/// of the viewport, and the grid is only ever aligned like that at rest at
|
||||
/// the very top. Scrolled anywhere else, a part-row hangs off each end and
|
||||
/// the viewport touches one row more than that — the row this used to
|
||||
/// undercount is the bottom one, which is the row reported missing.
|
||||
property <int> viewport-cells: root.columns * (root.visible-rows + 1);
|
||||
changed viewport-cells => { root.viewport-cells-changed(root.viewport-cells); }
|
||||
/// Rows the *whole library* occupies, which is what the scrollbar spans.
|
||||
property <int> total-rows: ceil(root.total / max(1, columns));
|
||||
|
||||
@@ -2183,7 +2195,7 @@ export component LibraryGrid inherits Rectangle {
|
||||
//
|
||||
// Creating it on `timeline.length > 0` made the sidebar's 96px
|
||||
// appear the moment the first dates were recorded, which narrowed
|
||||
// the grid — changing `columns` and `capacity`, both of which call
|
||||
// the grid — changing `columns` and `viewport-cells`, both of which call
|
||||
// back into Rust to reload the window. The first sweep flush
|
||||
// therefore landed a reload storm on top of the initial thumbnail
|
||||
// batch. Reserving the column costs 96px on an undated library and
|
||||
|
||||
Reference in New Issue
Block a user