diff --git a/docs/labs.md b/docs/labs.md index cad9c5dd7c1..7f69fca6e9a 100644 --- a/docs/labs.md +++ b/docs/labs.md @@ -112,3 +112,7 @@ Unreliable in encrypted rooms. ## Knock rooms (`feature_ask_to_join`) [In Development] Enables knock feature for rooms. This allows users to ask to join a room. + +## New room list (`feature_new_room_list`) [In Development] + +Enable the new room list that is currently in development. diff --git a/src/components/structures/LeftPanel.tsx b/src/components/structures/LeftPanel.tsx index 62cea32e45a..c67cea9b5ad 100644 --- a/src/components/structures/LeftPanel.tsx +++ b/src/components/structures/LeftPanel.tsx @@ -12,7 +12,7 @@ import classNames from "classnames"; import dis from "../../dispatcher/dispatcher"; import { _t } from "../../languageHandler"; -import RoomList from "../views/rooms/RoomList"; +import LegacyRoomList from "../views/rooms/LegacyRoomList"; import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../LegacyCallHandler"; import { HEADER_HEIGHT } from "../views/rooms/RoomSublist"; import { Action } from "../../dispatcher/actions"; @@ -36,6 +36,8 @@ import AccessibleButton, { type ButtonEvent } from "../views/elements/Accessible import PosthogTrackers from "../../PosthogTrackers"; import type PageType from "../../PageTypes"; import { Landmark, LandmarkNavigation } from "../../accessibility/LandmarkNavigation"; +import SettingsStore from "../../settings/SettingsStore"; +import { RoomListView } from "../views/rooms/RoomListView"; interface IProps { isMinimized: boolean; @@ -56,7 +58,7 @@ interface IState { export default class LeftPanel extends React.Component { private listContainerRef = createRef(); - private roomListRef = createRef(); + private roomListRef = createRef(); private focusedElement: Element | null = null; private isDoingStickyHeaders = false; @@ -377,8 +379,25 @@ export default class LeftPanel extends React.Component { } public render(): React.ReactNode { + const containerClasses = classNames({ + mx_LeftPanel: true, + mx_LeftPanel_minimized: this.props.isMinimized, + }); + + const roomListClasses = classNames("mx_LeftPanel_actualRoomListContainer", "mx_AutoHideScrollbar"); + const useNewRoomList = SettingsStore.getValue("feature_new_room_list"); + if (useNewRoomList) { + return ( +
+
+ +
+
+ ); + } + const roomList = ( - { /> ); - const containerClasses = classNames({ - mx_LeftPanel: true, - mx_LeftPanel_minimized: this.props.isMinimized, - }); - - const roomListClasses = classNames("mx_LeftPanel_actualRoomListContainer", "mx_AutoHideScrollbar"); - return (
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/LegacyRoomList.tsx similarity index 94% rename from src/components/views/rooms/RoomList.tsx rename to src/components/views/rooms/LegacyRoomList.tsx index af409f12cd1..1cfa49a0a58 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/LegacyRoomList.tsx @@ -9,26 +9,26 @@ Please see LICENSE files in the repository root for full details. import { EventType, type Room, RoomType } from "matrix-js-sdk/src/matrix"; import React, { type ComponentType, createRef, type ReactComponentElement, type SyntheticEvent } from "react"; -import { type IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; -import MatrixClientContext from "../../../contexts/MatrixClientContext"; -import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; -import { Action } from "../../../dispatcher/actions"; -import defaultDispatcher from "../../../dispatcher/dispatcher"; -import { type ActionPayload } from "../../../dispatcher/payloads"; -import { type ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload"; -import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; -import { useEventEmitterState } from "../../../hooks/useEventEmitter"; -import { _t, _td, type TranslationKey } from "../../../languageHandler"; -import { MatrixClientPeg } from "../../../MatrixClientPeg"; -import PosthogTrackers from "../../../PosthogTrackers"; -import SettingsStore from "../../../settings/SettingsStore"; -import { useFeatureEnabled } from "../../../hooks/useSettings"; -import { UIComponent } from "../../../settings/UIFeature"; -import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore"; -import { type ITagMap } from "../../../stores/room-list/algorithms/models"; -import { DefaultTagID, type TagID } from "../../../stores/room-list/models"; -import { UPDATE_EVENT } from "../../../stores/AsyncStore"; -import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; +import { type IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex.tsx"; +import MatrixClientContext from "../../../contexts/MatrixClientContext.tsx"; +import { shouldShowComponent } from "../../../customisations/helpers/UIComponents.ts"; +import { Action } from "../../../dispatcher/actions.ts"; +import defaultDispatcher from "../../../dispatcher/dispatcher.ts"; +import { type ActionPayload } from "../../../dispatcher/payloads.ts"; +import { type ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload.ts"; +import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload.ts"; +import { useEventEmitterState } from "../../../hooks/useEventEmitter.ts"; +import { _t, _td, type TranslationKey } from "../../../languageHandler.tsx"; +import { MatrixClientPeg } from "../../../MatrixClientPeg.ts"; +import PosthogTrackers from "../../../PosthogTrackers.ts"; +import SettingsStore from "../../../settings/SettingsStore.ts"; +import { useFeatureEnabled } from "../../../hooks/useSettings.ts"; +import { UIComponent } from "../../../settings/UIFeature.ts"; +import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore.ts"; +import { type ITagMap } from "../../../stores/room-list/algorithms/models.ts"; +import { DefaultTagID, type TagID } from "../../../stores/room-list/models.ts"; +import { UPDATE_EVENT } from "../../../stores/AsyncStore.ts"; +import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore.ts"; import { isMetaSpace, type ISuggestedRoom, @@ -36,26 +36,36 @@ import { type SpaceKey, UPDATE_SELECTED_SPACE, UPDATE_SUGGESTED_ROOMS, -} from "../../../stores/spaces"; -import SpaceStore from "../../../stores/spaces/SpaceStore"; -import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays"; -import { objectShallowClone, objectWithOnly } from "../../../utils/objects"; -import type ResizeNotifier from "../../../utils/ResizeNotifier"; -import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space"; -import { ChevronFace, ContextMenuTooltipButton, type MenuProps, useContextMenu } from "../../structures/ContextMenu"; -import RoomAvatar from "../avatars/RoomAvatar"; -import { BetaPill } from "../beta/BetaCard"; +} from "../../../stores/spaces/index.ts"; +import SpaceStore from "../../../stores/spaces/SpaceStore.ts"; +import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays.ts"; +import { objectShallowClone, objectWithOnly } from "../../../utils/objects.ts"; +import type ResizeNotifier from "../../../utils/ResizeNotifier.ts"; +import { + shouldShowSpaceInvite, + showAddExistingRooms, + showCreateNewRoom, + showSpaceInvite, +} from "../../../utils/space.tsx"; +import { + ChevronFace, + ContextMenuTooltipButton, + type MenuProps, + useContextMenu, +} from "../../structures/ContextMenu.tsx"; +import RoomAvatar from "../avatars/RoomAvatar.tsx"; +import { BetaPill } from "../beta/BetaCard.tsx"; import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList, -} from "../context_menus/IconizedContextMenu"; -import ExtraTile from "./ExtraTile"; -import RoomSublist, { type IAuxButtonProps } from "./RoomSublist"; -import { SdkContextClass } from "../../../contexts/SDKContext"; -import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; -import { getKeyBindingsManager } from "../../../KeyBindingsManager"; -import AccessibleButton from "../elements/AccessibleButton"; -import { Landmark, LandmarkNavigation } from "../../../accessibility/LandmarkNavigation"; +} from "../context_menus/IconizedContextMenu.tsx"; +import ExtraTile from "./ExtraTile.tsx"; +import RoomSublist, { type IAuxButtonProps } from "./RoomSublist.tsx"; +import { SdkContextClass } from "../../../contexts/SDKContext.ts"; +import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts.ts"; +import { getKeyBindingsManager } from "../../../KeyBindingsManager.ts"; +import AccessibleButton from "../elements/AccessibleButton.tsx"; +import { Landmark, LandmarkNavigation } from "../../../accessibility/LandmarkNavigation.ts"; import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../../LegacyCallHandler.tsx"; interface IProps { @@ -420,7 +430,7 @@ const TAG_AESTHETICS: TagAestheticsMap = { }, }; -export default class RoomList extends React.PureComponent { +export default class LegacyRoomList extends React.PureComponent { private dispatcherRef?: string; private treeRef = createRef(); diff --git a/src/components/views/rooms/RoomListView.tsx b/src/components/views/rooms/RoomListView.tsx new file mode 100644 index 00000000000..c5f593decf4 --- /dev/null +++ b/src/components/views/rooms/RoomListView.tsx @@ -0,0 +1,14 @@ +/* +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 React from "react"; + +type IProps = unknown; + +export const RoomListView: React.FC = (props: IProps) => { + return
New Room List
; +}; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3896d05e885..e4ae168757a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1499,6 +1499,7 @@ "location_share_live_description": "Temporary implementation. Locations persist in room history.", "mjolnir": "New ways to ignore people", "msc3531_hide_messages_pending_moderation": "Let moderators hide messages pending moderation.", + "new_room_list": "Enable new room list", "notification_settings": "New Notification Settings", "notification_settings_beta_caption": "Introducing a simpler way to change your notification settings. Customize your %(brand)s, just the way you like.", "notification_settings_beta_title": "Notification Settings", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index b2c20430632..439b0c112f5 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -205,6 +205,7 @@ export interface Settings { "feature_location_share_live": IFeature; "feature_dynamic_room_predecessors": IFeature; "feature_render_reaction_images": IFeature; + "feature_new_room_list": IFeature; "feature_ask_to_join": IFeature; "feature_notifications": IFeature; // These are in the feature namespace but aren't actually features @@ -623,6 +624,15 @@ export const SETTINGS: Settings = { supportedLevelsAreOrdered: true, default: false, }, + "feature_new_room_list": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG_PRIORITISED, + labsGroup: LabGroup.Ui, + displayName: _td("labs|new_room_list"), + description: _td("labs|under_active_development"), + isFeature: true, + default: false, + controller: new ReloadOnChangeController(), + }, /** * With the transition to Compound we are moving to a base font size * of 16px. We're taking the opportunity to move away from the `baseFontSize` diff --git a/src/stores/spaces/SpaceStore.ts b/src/stores/spaces/SpaceStore.ts index 2a2e8f08946..13179f8c86a 100644 --- a/src/stores/spaces/SpaceStore.ts +++ b/src/stores/spaces/SpaceStore.ts @@ -36,7 +36,7 @@ import { setDiff, setHasDiff } from "../../utils/sets"; import { Action } from "../../dispatcher/actions"; import { arrayHasDiff, arrayHasOrderChange, filterBoolean } from "../../utils/arrays"; import { reorderLexicographically } from "../../utils/stringOrderField"; -import { TAG_ORDER } from "../../components/views/rooms/RoomList"; +import { TAG_ORDER } from "../../components/views/rooms/LegacyRoomList"; import { type SettingUpdatedPayload } from "../../dispatcher/payloads/SettingUpdatedPayload"; import { isMetaSpace, diff --git a/test/unit-tests/components/views/rooms/RoomList-test.tsx b/test/unit-tests/components/views/rooms/LegacyRoomList-test.tsx similarity index 98% rename from test/unit-tests/components/views/rooms/RoomList-test.tsx rename to test/unit-tests/components/views/rooms/LegacyRoomList-test.tsx index 288f0c53e55..6103ba4f4d2 100644 --- a/test/unit-tests/components/views/rooms/RoomList-test.tsx +++ b/test/unit-tests/components/views/rooms/LegacyRoomList-test.tsx @@ -13,7 +13,7 @@ import userEvent from "@testing-library/user-event"; import { mocked } from "jest-mock"; import { type Room } from "matrix-js-sdk/src/matrix"; -import RoomList from "../../../../../src/components/views/rooms/RoomList"; +import LegacyRoomList from "../../../../../src/components/views/rooms/LegacyRoomList"; import ResizeNotifier from "../../../../../src/utils/ResizeNotifier"; import { MetaSpace } from "../../../../../src/stores/spaces"; import { shouldShowComponent } from "../../../../../src/customisations/helpers/UIComponents"; @@ -40,14 +40,14 @@ const getDMRoomsForUserId = jest.fn(); // @ts-ignore DMRoomMap.sharedInstance = { getUserIdForRoomId, getDMRoomsForUserId }; -describe("RoomList", () => { +describe("LegacyRoomList", () => { stubClient(); const client = MatrixClientPeg.safeGet(); const store = SpaceStore.instance; - function getComponent(props: Partial = {}): JSX.Element { + function getComponent(props: Partial = {}): JSX.Element { return ( -