From 394e181854947f0be1d9e5b8f83a1edf3040da4d Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Tue, 9 Aug 2022 20:46:59 +0100
Subject: [PATCH] Define interface for RLS to ease wiring in Sliding Sync
 (#9150)

* Define iface for RLS

* Iterate interface
---
 src/@types/global.d.ts                        |   4 +-
 src/components/views/rooms/RoomSublist.tsx    |   2 +-
 src/stores/room-list/Interface.ts             | 107 ++++++++++++++++++
 src/stores/room-list/RoomListStore.ts         |  15 +--
 test/components/views/rooms/RoomList-test.tsx |   4 +-
 5 files changed, 118 insertions(+), 14 deletions(-)
 create mode 100644 src/stores/room-list/Interface.ts

diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts
index 7c595640fd..0075837111 100644
--- a/src/@types/global.d.ts
+++ b/src/@types/global.d.ts
@@ -23,7 +23,7 @@ import ContentMessages from "../ContentMessages";
 import { IMatrixClientPeg } from "../MatrixClientPeg";
 import ToastStore from "../stores/ToastStore";
 import DeviceListener from "../DeviceListener";
-import { RoomListStoreClass } from "../stores/room-list/RoomListStore";
+import { RoomListStore } from "../stores/room-list/Interface";
 import { PlatformPeg } from "../PlatformPeg";
 import RoomListLayoutStore from "../stores/room-list/RoomListLayoutStore";
 import { IntegrationManagers } from "../integrations/IntegrationManagers";
@@ -79,7 +79,7 @@ declare global {
         mxContentMessages: ContentMessages;
         mxToastStore: ToastStore;
         mxDeviceListener: DeviceListener;
-        mxRoomListStore: RoomListStoreClass;
+        mxRoomListStore: RoomListStore;
         mxRoomListLayoutStore: RoomListLayoutStore;
         mxPlatformPeg: PlatformPeg;
         mxIntegrationManagers: typeof IntegrationManagers;
diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx
index 677b63bcf9..bd09ecb4a0 100644
--- a/src/components/views/rooms/RoomSublist.tsx
+++ b/src/components/views/rooms/RoomSublist.tsx
@@ -372,7 +372,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
     };
 
     private onTagSortChanged = async (sort: SortAlgorithm) => {
-        await RoomListStore.instance.setTagSorting(this.props.tagId, sort);
+        RoomListStore.instance.setTagSorting(this.props.tagId, sort);
         this.forceUpdate();
     };
 
diff --git a/src/stores/room-list/Interface.ts b/src/stores/room-list/Interface.ts
new file mode 100644
index 0000000000..ab53870989
--- /dev/null
+++ b/src/stores/room-list/Interface.ts
@@ -0,0 +1,107 @@
+/*
+Copyright 2022 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 type { Room } from "matrix-js-sdk/src/models/room";
+import type { EventEmitter } from "events";
+import { ITagMap, ListAlgorithm, SortAlgorithm } from "./algorithms/models";
+import { RoomUpdateCause, TagID } from "./models";
+import { IFilterCondition } from "./filters/IFilterCondition";
+
+export enum RoomListStoreEvent {
+    // The event/channel which is called when the room lists have been changed.
+    ListsUpdate = "lists_update",
+}
+
+export interface RoomListStore extends EventEmitter {
+    /**
+     * Gets an ordered set of rooms for the all known tags.
+     * @returns {ITagMap} The cached list of rooms, ordered,
+     * for each tag. May be empty, but never null/undefined.
+     */
+    get orderedLists(): ITagMap;
+
+    /**
+     * Set the sort algorithm for the specified tag.
+     * @param tagId the tag to set the algorithm for
+     * @param sort the sort algorithm to set to
+     */
+    setTagSorting(tagId: TagID, sort: SortAlgorithm): void;
+
+    /**
+     * Get the sort algorithm for the specified tag.
+     * @param tagId tag to get the sort algorithm for
+     * @returns the sort algorithm
+     */
+    getTagSorting(tagId: TagID): SortAlgorithm;
+
+    /**
+     * Set the list algorithm for the specified tag.
+     * @param tagId the tag to set the algorithm for
+     * @param order the list algorithm to set to
+     */
+    setListOrder(tagId: TagID, order: ListAlgorithm): void;
+
+    /**
+     * Get the list algorithm for the specified tag.
+     * @param tagId tag to get the list algorithm for
+     * @returns the list algorithm
+     */
+    getListOrder(tagId: TagID): ListAlgorithm;
+
+    /**
+     * Regenerates the room whole room list, discarding any previous results.
+     *
+     * Note: This is only exposed externally for the tests. Do not call this from within
+     * the app.
+     * @param params.trigger Set to false to prevent a list update from being sent. Should only
+     * be used if the calling code will manually trigger the update.
+     */
+    regenerateAllLists(params: { trigger: boolean }): void;
+
+    /**
+     * Adds a filter condition to the room list store. Filters may be applied async,
+     * and thus might not cause an update to the store immediately.
+     * @param {IFilterCondition} filter The filter condition to add.
+     */
+    addFilter(filter: IFilterCondition): Promise<void>;
+
+    /**
+     * Removes a filter condition from the room list store. If the filter was
+     * not previously added to the room list store, this will no-op. The effects
+     * of removing a filter may be applied async and therefore might not cause
+     * an update right away.
+     * @param {IFilterCondition} filter The filter condition to remove.
+     */
+    removeFilter(filter: IFilterCondition): void;
+
+    /**
+     * Gets the tags for a room identified by the store. The returned set
+     * should never be empty, and will contain DefaultTagID.Untagged if
+     * the store is not aware of any tags.
+     * @param room The room to get the tags for.
+     * @returns The tags for the room.
+     */
+    getTagsForRoom(room: Room): TagID[];
+
+    /**
+     * Manually update a room with a given cause. This should only be used if the
+     * room list store would otherwise be incapable of doing the update itself. Note
+     * that this may race with the room list's regular operation.
+     * @param {Room} room The room to update.
+     * @param {RoomUpdateCause} cause The cause to update for.
+     */
+    manualRoomUpdate(room: Room, cause: RoomUpdateCause): Promise<void>;
+}
diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts
index c15567afdc..9083943ed9 100644
--- a/src/stores/room-list/RoomListStore.ts
+++ b/src/stores/room-list/RoomListStore.ts
@@ -37,18 +37,15 @@ import { RoomNotificationStateStore } from "../notifications/RoomNotificationSta
 import { VisibilityProvider } from "./filters/VisibilityProvider";
 import { SpaceWatcher } from "./SpaceWatcher";
 import { IRoomTimelineActionPayload } from "../../actions/MatrixActionCreators";
+import { RoomListStore as Interface, RoomListStoreEvent } from "./Interface";
 
 interface IState {
     // state is tracked in underlying classes
 }
 
-/**
- * The event/channel which is called when the room lists have been changed. Raised
- * with one argument: the instance of the store.
- */
-export const LISTS_UPDATE_EVENT = "lists_update";
+export const LISTS_UPDATE_EVENT = RoomListStoreEvent.ListsUpdate;
 
-export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
+export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements Interface {
     /**
      * Set to true if you're running tests on the store. Should not be touched in
      * any other environment.
@@ -365,7 +362,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
         this.algorithm.updatesInhibited = false;
     }
 
-    public async setTagSorting(tagId: TagID, sort: SortAlgorithm) {
+    public setTagSorting(tagId: TagID, sort: SortAlgorithm) {
         this.setAndPersistTagSorting(tagId, sort);
         this.updateFn.trigger();
     }
@@ -602,9 +599,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
 }
 
 export default class RoomListStore {
-    private static internalInstance: RoomListStoreClass;
+    private static internalInstance: Interface;
 
-    public static get instance(): RoomListStoreClass {
+    public static get instance(): Interface {
         if (!RoomListStore.internalInstance) {
             RoomListStore.internalInstance = new RoomListStoreClass();
         }
diff --git a/test/components/views/rooms/RoomList-test.tsx b/test/components/views/rooms/RoomList-test.tsx
index 7b9d3ee311..6fa3fe22cf 100644
--- a/test/components/views/rooms/RoomList-test.tsx
+++ b/test/components/views/rooms/RoomList-test.tsx
@@ -137,7 +137,7 @@ describe('RoomList', () => {
         client.getRoom.mockImplementation((roomId) => roomMap[roomId]);
 
         // Now that everything has been set up, prepare and update the store
-        await RoomListStore.instance.makeReady(client);
+        await (RoomListStore.instance as RoomListStoreClass).makeReady(client);
 
         done();
     });
@@ -150,7 +150,7 @@ describe('RoomList', () => {
         }
 
         await RoomListLayoutStore.instance.resetLayouts();
-        await RoomListStore.instance.resetStore();
+        await (RoomListStore.instance as RoomListStoreClass).resetStore();
 
         done();
     });