mark fragment in storage when start of timeline is reached

so we don't keep looping to fetch more messages
when scrolled all the way up
This commit is contained in:
Bruno Windels 2020-08-17 17:41:10 +02:00
parent 1261ac05d1
commit 37597e2acb
6 changed files with 44 additions and 5 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2020 Bruno Windels <bruno@windels.cloud> Copyright 2020 Bruno Windels <bruno@windels.cloud>
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -42,13 +43,16 @@ export class TimelineViewModel {
this._tiles = new TilesCollection(timeline.entries, tilesCreator({room, ownUserId})); this._tiles = new TilesCollection(timeline.entries, tilesCreator({room, ownUserId}));
} }
// doesn't fill gaps, only loads stored entries/tiles /**
loadAtTop() { * @return {bool} startReached if the start of the timeline was reached
*/
async loadAtTop() {
const firstTile = this._tiles.getFirst(); const firstTile = this._tiles.getFirst();
if (firstTile.shape === "gap") { if (firstTile.shape === "gap") {
return firstTile.fill(); return firstTile.fill();
} else { } else {
return this._timeline.loadAtTop(50); await this._timeline.loadAtTop(50);
return false;
} }
} }

View file

@ -41,6 +41,8 @@ export class GapTile extends SimpleTile {
this.emitChange("isLoading"); this.emitChange("isLoading");
} }
} }
// edgeReached will have been updated by fillGap
return this._entry.edgeReached;
} }
updateEntry(entry, params) { updateEntry(entry, params) {

View file

@ -83,6 +83,9 @@ export class Room extends EventEmitter {
/** @public */ /** @public */
async fillGap(fragmentEntry, amount) { async fillGap(fragmentEntry, amount) {
if (fragmentEntry.edgeReached) {
return;
}
const response = await this._hsApi.messages(this._roomId, { const response = await this._hsApi.messages(this._roomId, {
from: fragmentEntry.token, from: fragmentEntry.token,
dir: fragmentEntry.direction.asApiString(), dir: fragmentEntry.direction.asApiString(),

View file

@ -60,7 +60,7 @@ export class FragmentBoundaryEntry extends BaseEntry {
} }
get isGap() { get isGap() {
return !!this.token; return !!this.token && !this.edgeReached;
} }
get token() { get token() {
@ -79,6 +79,25 @@ export class FragmentBoundaryEntry extends BaseEntry {
} }
} }
get edgeReached() {
if (this.started) {
return this.fragment.startReached;
} else {
return this.fragment.endReached;
}
}
set edgeReached(reached) {
if (this.started) {
this.fragment.startReached = reached;
} else {
this.fragment.endReached = reached;
}
}
get linkedFragmentId() { get linkedFragmentId() {
if (this.started) { if (this.started) {
return this.fragment.previousId; return this.fragment.previousId;

View file

@ -178,6 +178,14 @@ export class GapWriter {
if (fragmentEntry.token !== start) { if (fragmentEntry.token !== start) {
throw new Error("start is not equal to prev_batch or next_batch"); throw new Error("start is not equal to prev_batch or next_batch");
} }
// begin (or end) of timeline reached
if (chunk.length === 0) {
fragmentEntry.edgeReached = true;
await txn.timelineFragments.update(fragmentEntry.fragment);
return {entries: [fragmentEntry], fragments: []};
}
// find last event in fragment so we get the eventIndex to begin creating keys at // find last event in fragment so we get the eventIndex to begin creating keys at
let lastKey = await this._findFragmentEdgeEventKey(fragmentEntry, txn); let lastKey = await this._findFragmentEdgeEventKey(fragmentEntry, txn);
// find out if any event in chunk is already present using findFirstOrLastOccurringEventId // find out if any event in chunk is already present using findFirstOrLastOccurringEventId

View file

@ -45,7 +45,10 @@ export class TimelineList extends ListView {
while (predicate()) { while (predicate()) {
// fill, not enough content to fill timeline // fill, not enough content to fill timeline
this._topLoadingPromise = this._viewModel.loadAtTop(); this._topLoadingPromise = this._viewModel.loadAtTop();
await this._topLoadingPromise; const startReached = await this._topLoadingPromise;
if (startReached) {
break;
}
} }
} }
catch (err) { catch (err) {