From 0b2d09b79616394f5a7c2b247343356ffc1c5a18 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 30 Nov 2021 18:07:08 +0000 Subject: [PATCH] Only display rooms in the sliding window Buggy: some rooms disappear entirely for some reason. --- src/domain/session/SessionViewModel.js | 1 + .../session/leftpanel/LeftPanelViewModel.js | 9 +++-- src/matrix/Sync3.ts | 35 +++++++++++++++++-- src/matrix/room/BaseRoom.js | 5 +++ src/observable/list/SortedMapList.js | 15 +++++++- 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 5c405a3f..fdc96409 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -41,6 +41,7 @@ export class SessionViewModel extends ViewModel { invites: this._sessionContainer.session.invites, rooms: this._sessionContainer.session.rooms, compareFn: this._sessionContainer.sync.compare.bind(this._sessionContainer.sync), + includeRoomFn: this._sessionContainer.sync.includeRoom.bind(this._sessionContainer.sync), }))); this._settingsViewModel = null; this._roomViewModelObservable = null; diff --git a/src/domain/session/leftpanel/LeftPanelViewModel.js b/src/domain/session/leftpanel/LeftPanelViewModel.js index 036efb27..b0fd60c0 100644 --- a/src/domain/session/leftpanel/LeftPanelViewModel.js +++ b/src/domain/session/leftpanel/LeftPanelViewModel.js @@ -19,6 +19,7 @@ import {ViewModel} from "../../ViewModel.js"; import {RoomTileViewModel} from "./RoomTileViewModel.js"; import {InviteTileViewModel} from "./InviteTileViewModel.js"; import {RoomFilter} from "./RoomFilter.js"; +import {FilteredMap} from "../../../observable/map/FilteredMap.js"; import {ApplyMap} from "../../../observable/map/ApplyMap.js"; import {addPanelIfNeeded} from "../../navigation/index.js"; import { PlaceholderRoomTileViewModel } from "./PlaceholderRoomTileViewModel.js"; @@ -26,9 +27,13 @@ import { PlaceholderRoomTileViewModel } from "./PlaceholderRoomTileViewModel.js" export class LeftPanelViewModel extends ViewModel { constructor(options) { super(options); - const {rooms, invites, compareFn} = options; + const {rooms, invites, compareFn, includeRoomFn} = options; this._tileViewModelsMap = this._mapTileViewModels(rooms, invites); - this._tileViewModelsFilterMap = new ApplyMap(this._tileViewModelsMap); + this._tileViewModelsSlidingWindow = new FilteredMap(this._tileViewModelsMap, (r, roomId) => { + const include = includeRoomFn(roomId); + return include; + }); + this._tileViewModelsFilterMap = new ApplyMap(this._tileViewModelsSlidingWindow); this._tileViewModels = this._tileViewModelsFilterMap.sortValues((a, b) => a.compare(b)); this._currentTileVM = null; this._setupNavigation(); diff --git a/src/matrix/Sync3.ts b/src/matrix/Sync3.ts index 5c88d973..b95c0953 100644 --- a/src/matrix/Sync3.ts +++ b/src/matrix/Sync3.ts @@ -128,7 +128,7 @@ export class Sync3 { this.status = new ObservableValue(SyncStatus.Stopped); this.error = null; // Hydrogen only has 1 list currently (no DM section) so we only need 1 range - this.ranges = [[0, 49]]; + this.ranges = [[0, 4]]; this.roomIndexToRoomId = {}; this.roomIdToRoomIndex = {}; } @@ -155,7 +155,11 @@ export class Sync3 { } } - compare(roomIdA: string, roomIdB: string) { + includeRoom(roomId: string): boolean { + return this.roomIdToRoomIndex[roomId] !== undefined; + } + + compare(roomIdA: string, roomIdB: string): number { if (roomIdA === roomIdB) { return 0; } @@ -325,6 +329,9 @@ export class Sync3 { await syncTxn.complete(log); // Sync v3 specific + // work out which rooms are no longer being tracked (they'll be deleted in indexToRoom but exist in this.roomIndexToRoomId) + // and then force update those rooms to force the FilteredMap to re-evalute to remove them from the left panel room list + const deletedRoomIDs = deletedElements(Object.values(this.roomIndexToRoomId), Object.values(indexToRoom)); // atomically move all the rooms to their new positions // We need to do this BEFORE calling afterSync as that causes the room list to be sorted // which eventually causes Sync3.compare to be called, so we need it to be using the latest @@ -335,6 +342,17 @@ export class Sync3 { const index = Number(indexStr); this.roomIdToRoomIndex[indexToRoom[index]] = index; }); + if (deletedRoomIDs.length > 0) { + console.log("DELETED ", deletedRoomIDs); + } + + // now force update rooms which fell off the sliding window + deletedRoomIDs.forEach((roomId) => { + let room = this.session.rooms.get(roomId); + room.forceRefresh(); + }) + + // END sync v3 specific // update in-memory structs // this.session.afterSync(); // ??? @@ -528,6 +546,19 @@ const indexInRange = (ranges: number[][], i: number) => { return isInRange; }; +// returns the elements which exist in old but not in new +const deletedElements = (oldArr: string[], newArr: string[]): string[] => { + let set = {}; + oldArr.forEach((k) => { + set[k] = true; + }); + newArr.forEach((k) => { + delete set[k]; + }) + + return Object.keys(set); +} + export function tests() { return { "processSyncOps": assert => { diff --git a/src/matrix/room/BaseRoom.js b/src/matrix/room/BaseRoom.js index 93973b71..41a5dc5a 100644 --- a/src/matrix/room/BaseRoom.js +++ b/src/matrix/room/BaseRoom.js @@ -76,6 +76,11 @@ export class BaseRoom extends EventEmitter { return retryTimelineEntries; } + // Forcibly update this room in collections + forceRefresh() { + this._emitUpdate(); + } + /** * Used for retrying decryption from other sources than sync, like key backup. * @internal diff --git a/src/observable/list/SortedMapList.js b/src/observable/list/SortedMapList.js index 2421419e..6b486bd5 100644 --- a/src/observable/list/SortedMapList.js +++ b/src/observable/list/SortedMapList.js @@ -63,7 +63,20 @@ export class SortedMapList extends BaseObservableList { onRemove(key, value) { const pair = {key, value}; - const idx = sortedIndex(this._sortedPairs, pair, this._comparator); + // Don't call sortedIndex as it does a binary search for the removed item. + // Whilst that is faster than the O(n) search we're doing here, it's not valid to compare + // removed items as the system may have no ability to compare them at this point. + let idx = -1; + for (let i = 0; i < this._sortedPairs.length; i++) { + if (this._sortedPairs[i].key === key) { + idx = i; + break; + } + } + if (idx === -1) { + return; + } + console.log("removing ", key, idx, value); // assert key === this._sortedPairs[idx].key; this._sortedPairs.splice(idx, 1); this.emitRemove(idx, value);