forked from mystiq/hydrogen-web
let tiles know when they become visible & load more tiles close to top
This commit is contained in:
parent
f4b4638ea8
commit
7578bfa3d9
4 changed files with 61 additions and 6 deletions
|
@ -236,6 +236,22 @@ export class TilesCollection extends BaseObservableList {
|
||||||
getFirst() {
|
getFirst() {
|
||||||
return this._tiles[0];
|
return this._tiles[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTileIndex(searchTile) {
|
||||||
|
const idx = sortedIndex(this._tiles, searchTile, (searchTile, tile) => {
|
||||||
|
// negate result because we're switching the order of the params
|
||||||
|
return searchTile.compare(tile);
|
||||||
|
});
|
||||||
|
const foundTile = this._tiles[idx];
|
||||||
|
if (foundTile?.compare(searchTile) === 0) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sliceIterator(start, end) {
|
||||||
|
return this._tiles.slice(start, end)[Symbol.iterator]();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import {ObservableArray} from "../../../../observable/list/ObservableArray.js";
|
import {ObservableArray} from "../../../../observable/list/ObservableArray.js";
|
||||||
|
|
|
@ -42,10 +42,41 @@ export class TimelineViewModel extends ViewModel {
|
||||||
const {timeline, tilesCreator} = options;
|
const {timeline, tilesCreator} = options;
|
||||||
this._timeline = this.track(timeline);
|
this._timeline = this.track(timeline);
|
||||||
this._tiles = new TilesCollection(timeline.entries, tilesCreator);
|
this._tiles = new TilesCollection(timeline.entries, tilesCreator);
|
||||||
this._timeline.loadAtTop(50);
|
this._startTile = null;
|
||||||
|
this._endTile = null;
|
||||||
|
this._topLoadingPromise = null;
|
||||||
|
this._bottomLoadingPromise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisibleTileRange(startTile, endTile) {
|
setVisibleTileRange(startTile, endTile, isViewportFilled) {
|
||||||
|
// we should async batch things here?
|
||||||
|
|
||||||
|
// this will prevent a (small) inserted tile from being marked visible, won't it?
|
||||||
|
if (this._startTile === startTile && this._endTile === endTile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// old tiles could have been removed from tilescollection once we support unloading
|
||||||
|
const oldStartIndex = this._startTile ? this._tiles.getTileIndex(this._startTile) : Number.MAX_SAFE_INTEGER;
|
||||||
|
const oldEndIndex = this._endTile ? this._tiles.getTileIndex(this._endTile) : Number.MIN_SAFE_INTEGER;
|
||||||
|
const newStartIndex = this._tiles.getTileIndex(startTile);
|
||||||
|
const newEndIndex = this._tiles.getTileIndex(endTile);
|
||||||
|
|
||||||
|
const minIndex = Math.min(oldStartIndex, newStartIndex);
|
||||||
|
const maxIndex = Math.max(oldEndIndex, newEndIndex);
|
||||||
|
|
||||||
|
let index = minIndex;
|
||||||
|
for (const tile of this._tiles.sliceIterator(minIndex, maxIndex)) {
|
||||||
|
const isVisible = index >= newStartIndex && index <= newEndIndex;
|
||||||
|
tile.setVisible(isVisible);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isViewportFilled || (newStartIndex < 5 && !this._topLoadingPromise)) {
|
||||||
|
this._topLoadingPromise = this._timeline.loadAtTop(10).then(() => {
|
||||||
|
this._topLoadingPromise = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get tiles() {
|
get tiles() {
|
||||||
|
|
|
@ -83,6 +83,10 @@ export class SimpleTile extends ViewModel {
|
||||||
return this._entry;
|
return this._entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compare(tile) {
|
||||||
|
return this.upperEntry.compare(tile.upperEntry);
|
||||||
|
}
|
||||||
|
|
||||||
compareEntry(entry) {
|
compareEntry(entry) {
|
||||||
return this._entry.compare(entry);
|
return this._entry.compare(entry);
|
||||||
}
|
}
|
||||||
|
@ -119,6 +123,10 @@ export class SimpleTile extends ViewModel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setVisible(isVisible) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this.setUpdateEmit(null);
|
this.setUpdateEmit(null);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|
|
@ -86,7 +86,7 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
tiles.style.setProperty("margin-top", `${missingTilesHeight}px`);
|
tiles.style.setProperty("margin-top", `${missingTilesHeight}px`);
|
||||||
// we don't have enough tiles to fill the viewport, so set all as visible
|
// we don't have enough tiles to fill the viewport, so set all as visible
|
||||||
const len = this.value.tiles.length;
|
const len = this.value.tiles.length;
|
||||||
this.updateVisibleRange(0, len - 1);
|
this.updateVisibleRange(0, len - 1, false);
|
||||||
} else {
|
} else {
|
||||||
tiles.style.removeProperty("margin-top");
|
tiles.style.removeProperty("margin-top");
|
||||||
if (this.stickToBottom) {
|
if (this.stickToBottom) {
|
||||||
|
@ -123,14 +123,14 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
|
||||||
bottomNodeIndex = anchoredNodeIndex;
|
bottomNodeIndex = anchoredNodeIndex;
|
||||||
}
|
}
|
||||||
let topNodeIndex = findFirstNodeIndexAtOrBelow(tiles, scrollTop, bottomNodeIndex);
|
let topNodeIndex = findFirstNodeIndexAtOrBelow(tiles, scrollTop, bottomNodeIndex);
|
||||||
this.updateVisibleRange(topNodeIndex, bottomNodeIndex);
|
this.updateVisibleRange(topNodeIndex, bottomNodeIndex, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateVisibleRange(startIndex: number, endIndex: number) {
|
private updateVisibleRange(startIndex: number, endIndex: number, isViewportFilled: boolean) {
|
||||||
const firstVisibleChild = this.tilesView!.getChildInstanceByIndex(startIndex);
|
const firstVisibleChild = this.tilesView!.getChildInstanceByIndex(startIndex);
|
||||||
const lastVisibleChild = this.tilesView!.getChildInstanceByIndex(endIndex);
|
const lastVisibleChild = this.tilesView!.getChildInstanceByIndex(endIndex);
|
||||||
if (firstVisibleChild && lastVisibleChild) {
|
if (firstVisibleChild && lastVisibleChild) {
|
||||||
this.value.setVisibleTileRange(firstVisibleChild.value, lastVisibleChild.value);
|
this.value.setVisibleTileRange(firstVisibleChild.value, lastVisibleChild.value, isViewportFilled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue