diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 1df84ad344..154a6504c6 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -47,6 +47,7 @@ import { type DeepReadonly } from "./common"; import type MatrixChat from "../components/structures/MatrixChat"; import { type InitialCryptoSetupStore } from "../stores/InitialCryptoSetupStore"; import { type ModuleApiType } from "../modules/Api.ts"; +import type RoomListStoreV3 from "../stores/room-list-v3/RoomListStoreV3.ts"; /* eslint-disable @typescript-eslint/naming-convention */ @@ -99,6 +100,7 @@ declare global { mxToastStore: ToastStore; mxDeviceListener: DeviceListener; mxRoomListStore: RoomListStore; + mxRoomListStoreV3: RoomListStoreV3; mxRoomListLayoutStore: RoomListLayoutStore; mxPlatformPeg: PlatformPeg; mxIntegrationManagers: typeof IntegrationManagers; diff --git a/src/stores/room-list-v3/RoomListStoreV3.ts b/src/stores/room-list-v3/RoomListStoreV3.ts new file mode 100644 index 0000000000..10791dd9f4 --- /dev/null +++ b/src/stores/room-list-v3/RoomListStoreV3.ts @@ -0,0 +1,69 @@ +/* +Copyright 2025 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import type { EmptyObject, Room } from "matrix-js-sdk/src/matrix"; +import type { MatrixDispatcher } from "../../dispatcher/dispatcher"; +import type { ActionPayload } from "../../dispatcher/payloads"; +import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; +import SettingsStore from "../../settings/SettingsStore"; +import { VisibilityProvider } from "../room-list/filters/VisibilityProvider"; +import defaultDispatcher from "../../dispatcher/dispatcher"; +import { LISTS_UPDATE_EVENT } from "../room-list/RoomListStore"; +import { RoomSkipList } from "./skip-list/RoomSkipList"; +import { RecencySorter } from "./skip-list/sorters/RecencySorter"; + +export class RoomListStoreV3Class extends AsyncStoreWithClient { + private roomSkipList?: RoomSkipList; + private readonly msc3946ProcessDynamicPredecessor: boolean; + + public constructor(dispatcher: MatrixDispatcher) { + super(dispatcher); + this.msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors"); + } + + public getSortedRooms(): Room[] { + if (this.roomSkipList?.initialized) return Array.from(this.roomSkipList); + else return []; + } + + protected async onReady(): Promise { + if (this.roomSkipList?.initialized || !this.matrixClient) return; + const sorter = new RecencySorter(this.matrixClient.getSafeUserId() ?? ""); + this.roomSkipList = new RoomSkipList(sorter); + const rooms = this.fetchRoomsFromSdk(); + if (!rooms) return; + this.roomSkipList.seed(rooms); + this.emit(LISTS_UPDATE_EVENT); + } + + protected async onAction(payload: ActionPayload): Promise { + return; + } + + private fetchRoomsFromSdk(): Room[] | null { + if (!this.matrixClient) return null; + let rooms = this.matrixClient.getVisibleRooms(this.msc3946ProcessDynamicPredecessor); + rooms = rooms.filter((r) => VisibilityProvider.instance.isRoomVisible(r)); + return rooms; + } +} + +export default class RoomListStoreV3 { + private static internalInstance: RoomListStoreV3Class; + + public static get instance(): RoomListStoreV3Class { + if (!RoomListStoreV3.internalInstance) { + const instance = new RoomListStoreV3Class(defaultDispatcher); + instance.start(); + RoomListStoreV3.internalInstance = instance; + } + + return this.internalInstance; + } +} + +window.mxRoomListStoreV3 = RoomListStoreV3.instance;