Compare commits
15 commits
Author | SHA1 | Date | |
---|---|---|---|
|
dab3ba9f74 | ||
|
d0b34ef2ca | ||
|
e94a9b36b3 | ||
|
f662a25c8b | ||
|
60a92cf6b7 | ||
|
b2a8b243ec | ||
|
a8a04d4036 | ||
|
7e8c0109ae | ||
|
b979e11ef5 | ||
|
20616f5983 | ||
|
345560ed97 | ||
|
57fa292583 | ||
|
177ef43ebf | ||
|
ebafd8c42b | ||
|
b648b87687 |
2 changed files with 59 additions and 2 deletions
|
@ -47,6 +47,58 @@ export class TimelineViewModel extends ViewModel {
|
|||
this._requestedEndTile = null;
|
||||
this._requestScheduled = false;
|
||||
this._showJumpDown = false;
|
||||
this._watchMap = new WeakMap();
|
||||
}
|
||||
|
||||
async watchForGapFill(gapPromise, gapTile, depth = 0) {
|
||||
this._watchMap.set(gapTile, true);
|
||||
if (depth >= 10) {
|
||||
console.error("watchForGapFill exceeded a recursive depth of 10");
|
||||
return;
|
||||
}
|
||||
let hasSeenUpdate = false;
|
||||
const checkForUpdate = (idx, tile) => {
|
||||
if (tile.shape !== "gap") {
|
||||
/*
|
||||
It's possible that this method executes before the GapTile has been rendered,
|
||||
so don't count the GapTile as an update.
|
||||
Usually happens when onScroll() is triggered by a non-timeline UI change,
|
||||
eg: SessionStatusView being rendered
|
||||
*/
|
||||
hasSeenUpdate = true;
|
||||
}
|
||||
}
|
||||
const subscription = {
|
||||
onAdd: (idx, tile) => checkForUpdate(idx, tile),
|
||||
onRemove: (idx, tile) => checkForUpdate(idx, tile),
|
||||
onUpdate: () => { /* shouldn't be called */ },
|
||||
onMove: () => { /* shouldn't be called */ },
|
||||
onReset: () => { /* shouldn't be called */ }
|
||||
};
|
||||
this.tiles.subscribe(subscription);
|
||||
let gapResult;
|
||||
try {
|
||||
gapResult = await gapPromise;
|
||||
}
|
||||
finally {
|
||||
this.tiles.unsubscribe(subscription);
|
||||
}
|
||||
if (!gapResult) {
|
||||
/*
|
||||
If gapResult resolves to false, then the gap is already being filled
|
||||
and is thus being tracked for updates by a previous invocation of this method
|
||||
*/
|
||||
this._watchMap.set(gapTile, false);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
We may have seen an update, but did the corresponding call to watchForGapFill from
|
||||
that update already return?
|
||||
*/
|
||||
const hasNextInvocationReturned = !this._watchMap.get(gapTile);
|
||||
if (!hasSeenUpdate || hasNextInvocationReturned) {
|
||||
this.watchForGapFill(gapTile.notifyVisible(), gapTile, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** if this.tiles is empty, call this with undefined for both startTile and endTile */
|
||||
|
@ -73,7 +125,10 @@ export class TimelineViewModel extends ViewModel {
|
|||
const startIndex = this._tiles.getTileIndex(this._startTile);
|
||||
const endIndex = this._tiles.getTileIndex(this._endTile);
|
||||
for (const tile of this._tiles.sliceIterator(startIndex, endIndex + 1)) {
|
||||
tile.notifyVisible();
|
||||
const gapPromise = tile.notifyVisible();
|
||||
if (gapPromise) {
|
||||
this.watchForGapFill(gapPromise, tile);
|
||||
}
|
||||
}
|
||||
loadTop = startIndex < 10;
|
||||
this._setShowJumpDown(endIndex < (this._tiles.length - 1));
|
||||
|
|
|
@ -42,11 +42,13 @@ export class GapTile extends SimpleTile {
|
|||
this._loading = false;
|
||||
this.emitChange("isLoading");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
notifyVisible() {
|
||||
this.fill();
|
||||
return this.fill();
|
||||
}
|
||||
|
||||
get isAtTop() {
|
||||
|
|
Reference in a new issue