diff --git a/src/customisations/RoomList.ts b/src/customisations/RoomList.ts new file mode 100644 index 0000000000..758b212aa2 --- /dev/null +++ b/src/customisations/RoomList.ts @@ -0,0 +1,45 @@ +/* + * Copyright 2020 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"; + +// Populate this file with the details of your customisations when copying it. + +/** + * Determines if a room is visible in the room list or not. By default, + * all rooms are visible. Where special handling is performed by Element, + * those rooms will not be able to override their visibility in the room + * list - Element will make the decision without calling this function. + * + * This function should be as fast as possible to avoid slowing down the + * client. + * @param {Room} room The room to check the visibility of. + * @returns {boolean} True if the room should be visible, false otherwise. + */ +function isRoomVisible(room: Room): boolean { + return true; +} + +// This interface summarises all available customisation points and also marks +// them all as optional. This allows customisers to only define and export the +// customisations they need while still maintaining type safety. +export interface IRoomListCustomisations { + isRoomVisible?: typeof isRoomVisible; +} + +// A real customisation module will define and export one or more of the +// customisation points that make up the interface above. +export const RoomListCustomisations: IRoomListCustomisations = {}; diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index 0f3138fe9e..b2fe630760 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -34,6 +34,7 @@ import { MarkedExecution } from "../../utils/MarkedExecution"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import { NameFilterCondition } from "./filters/NameFilterCondition"; import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore"; +import { VisibilityProvider } from "./filters/VisibilityProvider"; interface IState { tagsEnabled?: boolean; @@ -401,6 +402,10 @@ export class RoomListStoreClass extends AsyncStoreWithClient { } private async handleRoomUpdate(room: Room, cause: RoomUpdateCause): Promise { + if (!VisibilityProvider.instance.isRoomVisible(room)) { + return; // don't do anything on rooms that aren't visible + } + const shouldUpdate = await this.algorithm.handleRoomUpdate(room, cause); if (shouldUpdate) { if (SettingsStore.getValue("advancedRoomListLogging")) { @@ -544,7 +549,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient { public async regenerateAllLists({trigger = true}) { console.warn("Regenerating all room lists"); - const rooms = this.matrixClient.getVisibleRooms(); + const rooms = this.matrixClient.getVisibleRooms() + .filter(r => VisibilityProvider.instance.isRoomVisible(r)); const customTags = new Set(); if (this.state.tagsEnabled) { for (const room of rooms) { diff --git a/src/stores/room-list/algorithms/Algorithm.ts b/src/stores/room-list/algorithms/Algorithm.ts index 439141edb4..25059aabe7 100644 --- a/src/stores/room-list/algorithms/Algorithm.ts +++ b/src/stores/room-list/algorithms/Algorithm.ts @@ -34,6 +34,7 @@ import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } f import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm"; import { getListAlgorithmInstance } from "./list-ordering"; import SettingsStore from "../../../settings/SettingsStore"; +import { VisibilityProvider } from "../filters/VisibilityProvider"; /** * Fired when the Algorithm has determined a list has been updated. @@ -188,6 +189,10 @@ export class Algorithm extends EventEmitter { // Note throughout: We need async so we can wait for handleRoomUpdate() to do its thing, // otherwise we risk duplicating rooms. + if (val && !VisibilityProvider.instance.isRoomVisible(val)) { + val = null; // the room isn't visible - lie to the rest of this function + } + // Set the last sticky room to indicate that we're in a change. The code throughout the // class can safely handle a null room, so this should be safe to do as a backup. this._lastStickyRoom = this._stickyRoom || {}; diff --git a/src/stores/room-list/filters/VisibilityProvider.ts b/src/stores/room-list/filters/VisibilityProvider.ts new file mode 100644 index 0000000000..553dd33ce0 --- /dev/null +++ b/src/stores/room-list/filters/VisibilityProvider.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2020 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 { RoomListCustomisations } from "../../../customisations/RoomList"; + +export class VisibilityProvider { + private static internalInstance: VisibilityProvider; + + private constructor() { + } + + public static get instance(): VisibilityProvider { + if (!VisibilityProvider.internalInstance) { + VisibilityProvider.internalInstance = new VisibilityProvider(); + } + return VisibilityProvider.internalInstance; + } + + public isRoomVisible(room: Room): boolean { + /* eslint-disable prefer-const */ + let isVisible = true; // Returned at the end of this function + let forced = false; // When true, this function won't bother calling the customisation points + /* eslint-enable prefer-const */ + + // ------ + // TODO: The `if` statements to control visibility of custom room types + // would go here. The remainder of this function assumes that the statements + // will be here. + // + // When removing this comment block, please remove the lint disable lines in the area. + // ------ + + const isVisibleFn = RoomListCustomisations.isRoomVisible; + if (!forced && isVisibleFn) { + isVisible = isVisibleFn(room); + } + + return isVisible; + } +}