Add Space Panel with Room List filtering
This commit is contained in:
parent
7030c636f0
commit
f21aedc6cf
14 changed files with 796 additions and 31 deletions
|
@ -35,6 +35,7 @@ import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
|
|||
import { NameFilterCondition } from "./filters/NameFilterCondition";
|
||||
import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore";
|
||||
import { VisibilityProvider } from "./filters/VisibilityProvider";
|
||||
import { SpaceWatcher } from "./SpaceWatcher";
|
||||
|
||||
interface IState {
|
||||
tagsEnabled?: boolean;
|
||||
|
@ -56,7 +57,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
private initialListsGenerated = false;
|
||||
private algorithm = new Algorithm();
|
||||
private filterConditions: IFilterCondition[] = [];
|
||||
private tagWatcher = new TagWatcher(this);
|
||||
private tagWatcher: TagWatcher;
|
||||
private spaceWatcher: SpaceWatcher;
|
||||
private updateFn = new MarkedExecution(() => {
|
||||
for (const tagId of Object.keys(this.orderedLists)) {
|
||||
RoomNotificationStateStore.instance.getListState(tagId).setRooms(this.orderedLists[tagId]);
|
||||
|
@ -77,6 +79,15 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
RoomViewStore.addListener(() => this.handleRVSUpdate({}));
|
||||
this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
||||
this.algorithm.on(FILTER_CHANGED, this.onAlgorithmFilterUpdated);
|
||||
this.setupWatchers();
|
||||
}
|
||||
|
||||
private setupWatchers() {
|
||||
if (SettingsStore.getValue("feature_spaces")) {
|
||||
this.spaceWatcher = new SpaceWatcher(this);
|
||||
} else {
|
||||
this.tagWatcher = new TagWatcher(this);
|
||||
}
|
||||
}
|
||||
|
||||
public get unfilteredLists(): ITagMap {
|
||||
|
@ -92,9 +103,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
// Intended for test usage
|
||||
public async resetStore() {
|
||||
await this.reset();
|
||||
this.tagWatcher = new TagWatcher(this);
|
||||
this.filterConditions = [];
|
||||
this.initialListsGenerated = false;
|
||||
this.setupWatchers();
|
||||
|
||||
this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
||||
this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated);
|
||||
|
@ -554,8 +565,12 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
|
|||
public async regenerateAllLists({trigger = true}) {
|
||||
console.warn("Regenerating all room lists");
|
||||
|
||||
const rooms = this.matrixClient.getVisibleRooms()
|
||||
.filter(r => VisibilityProvider.instance.isRoomVisible(r));
|
||||
const rooms = [
|
||||
...this.matrixClient.getVisibleRooms(),
|
||||
// also show space invites in the room list
|
||||
...this.matrixClient.getRooms().filter(r => r.isSpaceRoom() && r.getMyMembership() === "invite"),
|
||||
].filter(r => VisibilityProvider.instance.isRoomVisible(r));
|
||||
|
||||
const customTags = new Set<TagID>();
|
||||
if (this.state.tagsEnabled) {
|
||||
for (const room of rooms) {
|
||||
|
|
39
src/stores/room-list/SpaceWatcher.ts
Normal file
39
src/stores/room-list/SpaceWatcher.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import { RoomListStoreClass } from "./RoomListStore";
|
||||
import { SpaceFilterCondition } from "./filters/SpaceFilterCondition";
|
||||
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../SpaceStore";
|
||||
|
||||
/**
|
||||
* Watches for changes in spaces to manage the filter on the provided RoomListStore
|
||||
*/
|
||||
export class SpaceWatcher {
|
||||
private filter = new SpaceFilterCondition();
|
||||
private activeSpace: Room = SpaceStore.instance.activeSpace;
|
||||
|
||||
constructor(private store: RoomListStoreClass) {
|
||||
this.filter.updateSpace(this.activeSpace); // get the filter into a consistent state
|
||||
store.addFilter(this.filter);
|
||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdated);
|
||||
}
|
||||
|
||||
private onSelectedSpaceUpdated = (activeSpace) => {
|
||||
this.filter.updateSpace(this.activeSpace = activeSpace);
|
||||
};
|
||||
}
|
|
@ -186,6 +186,9 @@ export class Algorithm extends EventEmitter {
|
|||
}
|
||||
|
||||
private async doUpdateStickyRoom(val: Room) {
|
||||
// no-op sticky rooms
|
||||
if (val?.isSpaceRoom() && val.getMyMembership() !== "invite") val = null;
|
||||
|
||||
// Note throughout: We need async so we can wait for handleRoomUpdate() to do its thing,
|
||||
// otherwise we risk duplicating rooms.
|
||||
|
||||
|
|
69
src/stores/room-list/filters/SpaceFilterCondition.ts
Normal file
69
src/stores/room-list/filters/SpaceFilterCondition.ts
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from "events";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "./IFilterCondition";
|
||||
import { IDestroyable } from "../../../utils/IDestroyable";
|
||||
import SpaceStore, {HOME_SPACE} from "../../SpaceStore";
|
||||
import { setHasDiff } from "../../../utils/sets";
|
||||
|
||||
/**
|
||||
* A filter condition for the room list which reveals rooms which
|
||||
* are a member of a given space or if no space is selected shows:
|
||||
* + Orphaned rooms (ones not in any space you are a part of)
|
||||
* + All DMs
|
||||
*/
|
||||
export class SpaceFilterCondition extends EventEmitter implements IFilterCondition, IDestroyable {
|
||||
private roomIds = new Set<Room>();
|
||||
private space: Room = null;
|
||||
|
||||
public get relativePriority(): FilterPriority {
|
||||
// Lowest priority so we can coarsely find rooms.
|
||||
return FilterPriority.Lowest;
|
||||
}
|
||||
|
||||
public isVisible(room: Room): boolean {
|
||||
return this.roomIds.has(room.roomId);
|
||||
}
|
||||
|
||||
private onStoreUpdate = async (): Promise<void> => {
|
||||
const beforeRoomIds = this.roomIds;
|
||||
this.roomIds = SpaceStore.instance.getSpaceFilteredRoomIds(this.space);
|
||||
|
||||
if (setHasDiff(beforeRoomIds, this.roomIds)) {
|
||||
// XXX: Room List Store has a bug where rooms which are synced after the filter is set
|
||||
// are excluded from the filter, this is a workaround for it.
|
||||
this.emit(FILTER_CHANGED);
|
||||
setTimeout(() => {
|
||||
this.emit(FILTER_CHANGED);
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
private getSpaceEventKey = (space: Room | null) => space ? space.roomId : HOME_SPACE;
|
||||
|
||||
public updateSpace(space: Room) {
|
||||
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
|
||||
SpaceStore.instance.on(this.getSpaceEventKey(this.space = space), this.onStoreUpdate);
|
||||
this.onStoreUpdate(); // initial update from the change to the space
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
SpaceStore.instance.off(this.getSpaceEventKey(this.space), this.onStoreUpdate);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue