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._requestedEndTile = null;
|
||||||
this._requestScheduled = false;
|
this._requestScheduled = false;
|
||||||
this._showJumpDown = 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 */
|
/** 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 startIndex = this._tiles.getTileIndex(this._startTile);
|
||||||
const endIndex = this._tiles.getTileIndex(this._endTile);
|
const endIndex = this._tiles.getTileIndex(this._endTile);
|
||||||
for (const tile of this._tiles.sliceIterator(startIndex, endIndex + 1)) {
|
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;
|
loadTop = startIndex < 10;
|
||||||
this._setShowJumpDown(endIndex < (this._tiles.length - 1));
|
this._setShowJumpDown(endIndex < (this._tiles.length - 1));
|
||||||
|
|
|
@ -42,11 +42,13 @@ export class GapTile extends SimpleTile {
|
||||||
this._loading = false;
|
this._loading = false;
|
||||||
this.emitChange("isLoading");
|
this.emitChange("isLoading");
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyVisible() {
|
notifyVisible() {
|
||||||
this.fill();
|
return this.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
get isAtTop() {
|
get isAtTop() {
|
||||||
|
|
Reference in a new issue