Remove unused code left over from the old search (#8947)

This commit is contained in:
Janne Mareike Koschinski 2022-06-30 17:14:49 +02:00 committed by GitHub
parent 424d33d4b0
commit 328d7ea5eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 102 additions and 466 deletions

View file

@ -217,14 +217,6 @@ $roomListCollapsedWidth: 68px;
} }
} }
.mx_LeftPanel_roomListFilterCount {
font-size: $font-13px;
font-weight: $font-semi-bold;
margin-left: 12px;
margin-top: 14px;
margin-bottom: -4px; // to counteract the normal roomListWrapper margin-top
}
.mx_LeftPanel_roomListWrapper { .mx_LeftPanel_roomListWrapper {
// Make the y-scrollbar more responsive // Make the y-scrollbar more responsive
padding-right: 2px; padding-right: 2px;

View file

@ -14,35 +14,30 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ComponentType, createRef, ReactComponentElement, RefObject } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomType, EventType } from "matrix-js-sdk/src/@types/event";
import * as fbEmitter from "fbemitter"; import * as fbEmitter from "fbemitter";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { Room } from "matrix-js-sdk/src/models/room";
import React, { ComponentType, createRef, ReactComponentElement, RefObject } from "react";
import { _t, _td } from "../../../languageHandler";
import { IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex"; import { IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex";
import ResizeNotifier from "../../../utils/ResizeNotifier"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { RoomViewStore } from "../../../stores/RoomViewStore"; import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { _t, _td } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import PosthogTrackers from "../../../PosthogTrackers";
import SettingsStore from "../../../settings/SettingsStore";
import { UIComponent } from "../../../settings/UIFeature";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { ITagMap } from "../../../stores/room-list/algorithms/models"; import { ITagMap } from "../../../stores/room-list/algorithms/models";
import { DefaultTagID, TagID } from "../../../stores/room-list/models"; import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import defaultDispatcher from "../../../dispatcher/dispatcher"; import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import RoomSublist, { IAuxButtonProps } from "./RoomSublist"; import { RoomViewStore } from "../../../stores/RoomViewStore";
import { ActionPayload } from "../../../dispatcher/payloads";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import ExtraTile from "./ExtraTile";
import { Action } from "../../../dispatcher/actions";
import { ViewRoomDeltaPayload } from "../../../dispatcher/payloads/ViewRoomDeltaPayload";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
import { BetaPill } from "../beta/BetaCard";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import { import {
isMetaSpace, isMetaSpace,
ISuggestedRoom, ISuggestedRoom,
@ -51,17 +46,21 @@ import {
UPDATE_SELECTED_SPACE, UPDATE_SELECTED_SPACE,
UPDATE_SUGGESTED_ROOMS, UPDATE_SUGGESTED_ROOMS,
} from "../../../stores/spaces"; } from "../../../stores/spaces";
import SpaceStore from "../../../stores/spaces/SpaceStore";
import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space"; import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
import RoomAvatar from "../avatars/RoomAvatar";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { UIComponent } from "../../../settings/UIFeature";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu"; import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import RoomAvatar from "../avatars/RoomAvatar";
import SettingsStore from "../../../settings/SettingsStore"; import { BetaPill } from "../beta/BetaCard";
import PosthogTrackers from "../../../PosthogTrackers"; import IconizedContextMenu, {
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import ExtraTile from "./ExtraTile";
import RoomSublist, { IAuxButtonProps } from "./RoomSublist";
interface IProps { interface IProps {
onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void; onKeyDown: (ev: React.KeyboardEvent, state: IRovingTabIndexState) => void;
@ -76,7 +75,6 @@ interface IProps {
interface IState { interface IState {
sublists: ITagMap; sublists: ITagMap;
isNameFiltering: boolean;
currentRoomId?: string; currentRoomId?: string;
suggestedRooms: ISuggestedRoom[]; suggestedRooms: ISuggestedRoom[];
} }
@ -403,7 +401,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
this.state = { this.state = {
sublists: {}, sublists: {},
isNameFiltering: !!RoomListStore.instance.getFirstNameFilterCondition(),
suggestedRooms: SpaceStore.instance.suggestedRooms, suggestedRooms: SpaceStore.instance.suggestedRooms,
}; };
} }
@ -480,8 +477,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const previousListIds = Object.keys(this.state.sublists); const previousListIds = Object.keys(this.state.sublists);
const newListIds = Object.keys(newLists); const newListIds = Object.keys(newLists);
const isNameFiltering = !!RoomListStore.instance.getFirstNameFilterCondition(); let doUpdate = arrayHasDiff(previousListIds, newListIds);
let doUpdate = this.state.isNameFiltering !== isNameFiltering || arrayHasDiff(previousListIds, newListIds);
if (!doUpdate) { if (!doUpdate) {
// so we didn't have the visible sublists change, but did the contents of those // so we didn't have the visible sublists change, but did the contents of those
// sublists change significantly enough to break the sticky headers? Probably, so // sublists change significantly enough to break the sticky headers? Probably, so
@ -503,33 +499,12 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const newSublists = objectWithOnly(newLists, newListIds); const newSublists = objectWithOnly(newLists, newListIds);
const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v)); const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v));
this.setState({ sublists, isNameFiltering }, () => { this.setState({ sublists }, () => {
this.props.onResize(); this.props.onResize();
}); });
} }
}; };
private onStartChat = (ev: ButtonEvent) => {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
defaultDispatcher.dispatch({ action: "view_create_chat", initialText });
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuCreateChatItem", ev);
};
private onExplore = (ev: ButtonEvent) => {
if (!isMetaSpace(this.props.activeSpace)) {
defaultDispatcher.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.props.activeSpace,
metricsTrigger: undefined, // other
});
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", ev);
} else {
const initialText = RoomListStore.instance.getFirstNameFilterCondition()?.search;
defaultDispatcher.dispatch({ action: Action.ViewRoomDirectory, initialText });
PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuExploreRoomsItem", ev);
}
};
private renderSuggestedRooms(): ReactComponentElement<typeof ExtraTile>[] { private renderSuggestedRooms(): ReactComponentElement<typeof ExtraTile>[] {
return this.state.suggestedRooms.map(room => { return this.state.suggestedRooms.map(room => {
const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room"); const name = room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room");
@ -573,8 +548,8 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
private renderSublists(): React.ReactElement[] { private renderSublists(): React.ReactElement[] {
// show a skeleton UI if the user is in no rooms and they are not filtering and have no suggested rooms // show a skeleton UI if the user is in no rooms and they are not filtering and have no suggested rooms
const showSkeleton = !this.state.isNameFiltering && !this.state.suggestedRooms?.length && const showSkeleton = !this.state.suggestedRooms?.length &&
Object.values(RoomListStore.instance.unfilteredLists).every(list => !list?.length); Object.values(RoomListStore.instance.orderedLists).every(list => !list?.length);
return TAG_ORDER return TAG_ORDER
.map(orderedTagId => { .map(orderedTagId => {
@ -636,29 +611,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
} }
public render() { public render() {
let explorePrompt: JSX.Element;
if (!this.props.isMinimized) {
if (this.state.isNameFiltering) {
explorePrompt = <div className="mx_RoomList_explorePrompt">
<div>{ _t("Can't see what you're looking for?") }</div>
<AccessibleButton
className="mx_RoomList_explorePrompt_startChat"
kind="link"
onClick={this.onStartChat}
>
{ _t("Start a new chat") }
</AccessibleButton>
<AccessibleButton
className="mx_RoomList_explorePrompt_explore"
kind="link"
onClick={this.onExplore}
>
{ !isMetaSpace(this.props.activeSpace) ? _t("Explore rooms") : _t("Explore all public rooms") }
</AccessibleButton>
</div>;
}
}
const sublists = this.renderSublists(); const sublists = this.renderSublists();
return ( return (
<RovingTabIndexProvider handleHomeEnd handleUpDown onKeyDown={this.props.onKeyDown}> <RovingTabIndexProvider handleHomeEnd handleUpDown onKeyDown={this.props.onKeyDown}>
@ -673,7 +625,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
ref={this.treeRef} ref={this.treeRef}
> >
{ sublists } { sublists }
{ explorePrompt }
</div> </div>
) } ) }
</RovingTabIndexProvider> </RovingTabIndexProvider>

View file

@ -14,35 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { useContext, useEffect, useState } from "react";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event"; import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { ClientEvent } from "matrix-js-sdk/src/client"; import { ClientEvent } from "matrix-js-sdk/src/client";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import React, { useContext, useEffect, useState } from "react";
import { _t } from "../../../languageHandler"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { useDispatcher } from "../../../hooks/useDispatcher";
import { useEventEmitterState, useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter"; import { useEventEmitterState, useTypedEventEmitter, useTypedEventEmitterState } from "../../../hooks/useEventEmitter";
import { useFeatureEnabled } from "../../../hooks/useSettings"; import { useFeatureEnabled } from "../../../hooks/useSettings";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import { _t } from "../../../languageHandler";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu"; import PosthogTrackers from "../../../PosthogTrackers";
import SpaceContextMenu from "../context_menus/SpaceContextMenu"; import { UIComponent } from "../../../settings/UIFeature";
import { HomeButtonContextMenu } from "../spaces/SpacePanel";
import IconizedContextMenu, {
IconizedContextMenuOption,
IconizedContextMenuOptionList,
} from "../context_menus/IconizedContextMenu";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import {
shouldShowSpaceInvite,
showAddExistingRooms,
showCreateNewRoom,
showCreateNewSubspace,
showSpaceInvite,
} from "../../../utils/space";
import { Action } from "../../../dispatcher/actions";
import { useDispatcher } from "../../../hooks/useDispatcher";
import InlineSpinner from "../elements/InlineSpinner";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { import {
getMetaSpaceName, getMetaSpaceName,
MetaSpace, MetaSpace,
@ -50,13 +37,24 @@ import {
UPDATE_HOME_BEHAVIOUR, UPDATE_HOME_BEHAVIOUR,
UPDATE_SELECTED_SPACE, UPDATE_SELECTED_SPACE,
} from "../../../stores/spaces"; } from "../../../stores/spaces";
import TooltipTarget from "../elements/TooltipTarget"; import SpaceStore from "../../../stores/spaces/SpaceStore";
import {
shouldShowSpaceInvite,
showAddExistingRooms,
showCreateNewRoom,
showCreateNewSubspace,
showSpaceInvite,
} from "../../../utils/space";
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
import { BetaPill } from "../beta/BetaCard"; import { BetaPill } from "../beta/BetaCard";
import PosthogTrackers from "../../../PosthogTrackers"; import IconizedContextMenu, {
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; IconizedContextMenuOption,
import { useWebSearchMetrics } from "../dialogs/spotlight/SpotlightDialog"; IconizedContextMenuOptionList,
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents"; } from "../context_menus/IconizedContextMenu";
import { UIComponent } from "../../../settings/UIFeature"; import SpaceContextMenu from "../context_menus/SpaceContextMenu";
import InlineSpinner from "../elements/InlineSpinner";
import TooltipTarget from "../elements/TooltipTarget";
import { HomeButtonContextMenu } from "../spaces/SpacePanel";
const contextMenuBelow = (elementRect: DOMRect) => { const contextMenuBelow = (elementRect: DOMRect) => {
// align the context menu's icons with the icon which opened the context menu // align the context menu's icons with the icon which opened the context menu
@ -131,15 +129,6 @@ const RoomListHeader = ({ onVisibilityChange }: IProps) => {
const videoRoomsEnabled = useFeatureEnabled("feature_video_rooms"); const videoRoomsEnabled = useFeatureEnabled("feature_video_rooms");
const pendingActions = usePendingActions(); const pendingActions = usePendingActions();
const filterCondition = RoomListStore.instance.getFirstNameFilterCondition();
const count = useEventEmitterState(RoomListStore.instance, LISTS_UPDATE_EVENT, () => {
if (filterCondition) {
return Object.values(RoomListStore.instance.orderedLists).flat(1).length;
} else {
return null;
}
});
const canShowMainMenu = activeSpace || spaceKey === MetaSpace.Home; const canShowMainMenu = activeSpace || spaceKey === MetaSpace.Home;
useEffect(() => { useEffect(() => {
@ -149,22 +138,13 @@ const RoomListHeader = ({ onVisibilityChange }: IProps) => {
} }
}, [closeMainMenu, canShowMainMenu, mainMenuDisplayed]); }, [closeMainMenu, canShowMainMenu, mainMenuDisplayed]);
// we pass null for the queryLength to inhibit the metrics hook for when there is no filterCondition
useWebSearchMetrics(count, filterCondition ? filterCondition.search.length : null, false);
const spaceName = useTypedEventEmitterState(activeSpace, RoomEvent.Name, () => activeSpace?.name); const spaceName = useTypedEventEmitterState(activeSpace, RoomEvent.Name, () => activeSpace?.name);
useEffect(() => { useEffect(() => {
if (onVisibilityChange) { if (onVisibilityChange) {
onVisibilityChange(); onVisibilityChange();
} }
}, [count, onVisibilityChange]); }, [onVisibilityChange]);
if (typeof count === "number") {
return <div className="mx_LeftPanel_roomListFilterCount">
{ _t("%(count)s results", { count }) }
</div>;
}
const canAddRooms = activeSpace?.currentState?.maySendStateEvent(EventType.SpaceChild, cli.getUserId()); const canAddRooms = activeSpace?.currentState?.maySendStateEvent(EventType.SpaceChild, cli.getUserId());

View file

@ -16,45 +16,44 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import * as React from "react";
import { ComponentType, createRef, ReactComponentElement } from "react";
import { normalize } from "matrix-js-sdk/src/utils";
import { Room } from "matrix-js-sdk/src/models/room";
import classNames from 'classnames'; import classNames from 'classnames';
import { Dispatcher } from "flux";
import { Room } from "matrix-js-sdk/src/models/room";
import { Enable, Resizable } from "re-resizable"; import { Enable, Resizable } from "re-resizable";
import { Direction } from "re-resizable/lib/resizer"; import { Direction } from "re-resizable/lib/resizer";
import { Dispatcher } from "flux"; import * as React from "react";
import { ComponentType, createRef, ReactComponentElement } from "react";
import { polyfillTouchEvent } from "../../../@types/polyfill";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
import { Action } from "../../../dispatcher/actions";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { ActionPayload } from "../../../dispatcher/payloads";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import AccessibleButton from "../../views/elements/AccessibleButton"; import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
import RoomTile from "./RoomTile"; import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
import { ListLayout } from "../../../stores/room-list/ListLayout"; import { ListLayout } from "../../../stores/room-list/ListLayout";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays";
import { objectExcluding, objectHasDiff } from "../../../utils/objects";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import ContextMenu, { import ContextMenu, {
ChevronFace, ChevronFace,
ContextMenuTooltipButton, ContextMenuTooltipButton,
StyledMenuItemCheckbox, StyledMenuItemCheckbox,
StyledMenuItemRadio, StyledMenuItemRadio,
} from "../../structures/ContextMenu"; } from "../../structures/ContextMenu";
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore"; import AccessibleButton from "../../views/elements/AccessibleButton";
import { ListAlgorithm, SortAlgorithm } from "../../../stores/room-list/algorithms/models";
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
import defaultDispatcher from "../../../dispatcher/dispatcher";
import { Action } from "../../../dispatcher/actions";
import NotificationBadge from "./NotificationBadge";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { ActionPayload } from "../../../dispatcher/payloads";
import { polyfillTouchEvent } from "../../../@types/polyfill";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
import RoomListLayoutStore from "../../../stores/room-list/RoomListLayoutStore";
import { arrayFastClone, arrayHasOrderChange } from "../../../utils/arrays";
import { objectExcluding, objectHasDiff } from "../../../utils/objects";
import ExtraTile from "./ExtraTile"; import ExtraTile from "./ExtraTile";
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState"; import NotificationBadge from "./NotificationBadge";
import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import RoomTile from "./RoomTile";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS const SHOW_N_BUTTON_HEIGHT = 28; // As defined by CSS
const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
@ -99,7 +98,6 @@ interface IState {
isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered isExpanded: boolean; // used for the for expand of the sublist when the room list is being filtered
height: number; height: number;
rooms: Room[]; rooms: Room[];
filteredExtraTiles?: ReactComponentElement<typeof ExtraTile>[];
} }
export default class RoomSublist extends React.Component<IProps, IState> { export default class RoomSublist extends React.Component<IProps, IState> {
@ -109,7 +107,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private layout: ListLayout; private layout: ListLayout;
private heightAtStart: number; private heightAtStart: number;
private isBeingFiltered: boolean;
private notificationState: ListNotificationState; private notificationState: ListNotificationState;
constructor(props: IProps) { constructor(props: IProps) {
@ -117,12 +114,11 @@ export default class RoomSublist extends React.Component<IProps, IState> {
this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId); this.layout = RoomListLayoutStore.instance.getLayoutFor(this.props.tagId);
this.heightAtStart = 0; this.heightAtStart = 0;
this.isBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition();
this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId); this.notificationState = RoomNotificationStateStore.instance.getListState(this.props.tagId);
this.state = { this.state = {
contextMenuPosition: null, contextMenuPosition: null,
isResizing: false, isResizing: false,
isExpanded: this.isBeingFiltered ? this.isBeingFiltered : !this.layout.isCollapsed, isExpanded: !this.layout.isCollapsed,
height: 0, // to be fixed in a moment, we need `rooms` to calculate this. height: 0, // to be fixed in a moment, we need `rooms` to calculate this.
rooms: arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []), rooms: arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []),
}; };
@ -156,9 +152,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
} }
private get extraTiles(): ReactComponentElement<typeof ExtraTile>[] | null { private get extraTiles(): ReactComponentElement<typeof ExtraTile>[] | null {
if (this.state.filteredExtraTiles) {
return this.state.filteredExtraTiles;
}
if (this.props.extraTiles) { if (this.props.extraTiles) {
return this.props.extraTiles; return this.props.extraTiles;
} }
@ -179,7 +172,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
} }
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) { public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
const prevExtraTiles = prevState.filteredExtraTiles || prevProps.extraTiles; const prevExtraTiles = prevProps.extraTiles;
// as the rooms can come in one by one we need to reevaluate // as the rooms can come in one by one we need to reevaluate
// the amount of available rooms to cap the amount of requested visible rooms by the layout // the amount of available rooms to cap the amount of requested visible rooms by the layout
if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) { if (RoomSublist.calcNumTiles(prevState.rooms, prevExtraTiles) !== this.numTiles) {
@ -203,7 +196,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
// If we're supposed to handle extra tiles, take the performance hit and re-render all the // If we're supposed to handle extra tiles, take the performance hit and re-render all the
// time so we don't have to consider them as part of the visible room optimization. // time so we don't have to consider them as part of the visible room optimization.
const prevExtraTiles = this.props.extraTiles || []; const prevExtraTiles = this.props.extraTiles || [];
const nextExtraTiles = (nextState.filteredExtraTiles || nextProps.extraTiles) || []; const nextExtraTiles = nextProps.extraTiles || [];
if (prevExtraTiles.length > 0 || nextExtraTiles.length > 0) { if (prevExtraTiles.length > 0 || nextExtraTiles.length > 0) {
return true; return true;
} }
@ -260,32 +253,12 @@ export default class RoomSublist extends React.Component<IProps, IState> {
private onListsUpdated = () => { private onListsUpdated = () => {
const stateUpdates: IState & any = {}; // &any is to avoid a cast on the initializer const stateUpdates: IState & any = {}; // &any is to avoid a cast on the initializer
if (this.props.extraTiles) {
const nameCondition = RoomListStore.instance.getFirstNameFilterCondition();
if (nameCondition) {
stateUpdates.filteredExtraTiles = this.props.extraTiles
.filter(t => nameCondition.matches(normalize(t.props.displayName || "")));
} else if (this.state.filteredExtraTiles) {
stateUpdates.filteredExtraTiles = null;
}
}
const currentRooms = this.state.rooms; const currentRooms = this.state.rooms;
const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []); const newRooms = arrayFastClone(RoomListStore.instance.orderedLists[this.props.tagId] || []);
if (arrayHasOrderChange(currentRooms, newRooms)) { if (arrayHasOrderChange(currentRooms, newRooms)) {
stateUpdates.rooms = newRooms; stateUpdates.rooms = newRooms;
} }
const isStillBeingFiltered = !!RoomListStore.instance.getFirstNameFilterCondition();
if (isStillBeingFiltered !== this.isBeingFiltered) {
this.isBeingFiltered = isStillBeingFiltered;
if (isStillBeingFiltered) {
stateUpdates.isExpanded = true;
} else {
stateUpdates.isExpanded = !this.layout.isCollapsed;
}
}
if (Object.keys(stateUpdates).length > 0) { if (Object.keys(stateUpdates).length > 0) {
this.setState(stateUpdates); this.setState(stateUpdates);
} }
@ -418,7 +391,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
room = this.state.rooms && this.state.rooms[0]; room = this.state.rooms && this.state.rooms[0];
} else { } else {
// find the first room with a count of the same colour as the badge count // find the first room with a count of the same colour as the badge count
room = RoomListStore.instance.unfilteredLists[this.props.tagId].find((r: Room) => { room = RoomListStore.instance.orderedLists[this.props.tagId].find((r: Room) => {
const notifState = this.notificationState.getForRoom(r); const notifState = this.notificationState.getForRoom(r);
return notifState.count > 0 && notifState.color === this.notificationState.color; return notifState.count > 0 && notifState.color === this.notificationState.color;
}); });

View file

@ -1791,11 +1791,6 @@
"Historical": "Historical", "Historical": "Historical",
"Suggested Rooms": "Suggested Rooms", "Suggested Rooms": "Suggested Rooms",
"Empty room": "Empty room", "Empty room": "Empty room",
"Can't see what you're looking for?": "Can't see what you're looking for?",
"Start a new chat": "Start a new chat",
"Explore all public rooms": "Explore all public rooms",
"%(count)s results|other": "%(count)s results",
"%(count)s results|one": "%(count)s result",
"Add space": "Add space", "Add space": "Add space",
"You do not have permissions to add spaces to this space": "You do not have permissions to add spaces to this space", "You do not have permissions to add spaces to this space": "You do not have permissions to add spaces to this space",
"Join public room": "Join public room", "Join public room": "Join public room",

View file

@ -26,14 +26,13 @@ import { IListOrderingMap, ITagMap, ITagSortingMap, ListAlgorithm, SortAlgorithm
import { ActionPayload } from "../../dispatcher/payloads"; import { ActionPayload } from "../../dispatcher/payloads";
import defaultDispatcher from "../../dispatcher/dispatcher"; import defaultDispatcher from "../../dispatcher/dispatcher";
import { readReceiptChangeIsFor } from "../../utils/read-receipts"; import { readReceiptChangeIsFor } from "../../utils/read-receipts";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./filters/IFilterCondition"; import { FILTER_CHANGED, IFilterCondition } from "./filters/IFilterCondition";
import { RoomViewStore } from "../RoomViewStore"; import { RoomViewStore } from "../RoomViewStore";
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm"; import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership"; import { EffectiveMembership, getEffectiveMembership } from "../../utils/membership";
import RoomListLayoutStore from "./RoomListLayoutStore"; import RoomListLayoutStore from "./RoomListLayoutStore";
import { MarkedExecution } from "../../utils/MarkedExecution"; import { MarkedExecution } from "../../utils/MarkedExecution";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient"; import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
import { NameFilterCondition } from "./filters/NameFilterCondition";
import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore"; import { RoomNotificationStateStore } from "../notifications/RoomNotificationStateStore";
import { VisibilityProvider } from "./filters/VisibilityProvider"; import { VisibilityProvider } from "./filters/VisibilityProvider";
import { SpaceWatcher } from "./SpaceWatcher"; import { SpaceWatcher } from "./SpaceWatcher";
@ -58,7 +57,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
private initialListsGenerated = false; private initialListsGenerated = false;
private algorithm = new Algorithm(); private algorithm = new Algorithm();
private filterConditions: IFilterCondition[] = [];
private prefilterConditions: IFilterCondition[] = []; private prefilterConditions: IFilterCondition[] = [];
private updateFn = new MarkedExecution(() => { private updateFn = new MarkedExecution(() => {
for (const tagId of Object.keys(this.orderedLists)) { for (const tagId of Object.keys(this.orderedLists)) {
@ -78,11 +76,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
new SpaceWatcher(this); new SpaceWatcher(this);
} }
public get unfilteredLists(): ITagMap {
if (!this.algorithm) return {}; // No tags yet.
return this.algorithm.getUnfilteredRooms();
}
public get orderedLists(): ITagMap { public get orderedLists(): ITagMap {
if (!this.algorithm) return {}; // No tags yet. if (!this.algorithm) return {}; // No tags yet.
return this.algorithm.getOrderedRooms(); return this.algorithm.getOrderedRooms();
@ -91,7 +84,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
// Intended for test usage // Intended for test usage
public async resetStore() { public async resetStore() {
await this.reset(); await this.reset();
this.filterConditions = [];
this.prefilterConditions = []; this.prefilterConditions = [];
this.initialListsGenerated = false; this.initialListsGenerated = false;
@ -502,9 +494,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
let rooms = this.matrixClient.getVisibleRooms().filter(r => VisibilityProvider.instance.isRoomVisible(r)); let rooms = this.matrixClient.getVisibleRooms().filter(r => VisibilityProvider.instance.isRoomVisible(r));
// if spaces are enabled only consider the prefilter conditions when there are no runtime conditions if (this.prefilterConditions.length > 0) {
// for the search all spaces feature
if (this.prefilterConditions.length > 0 && !this.filterConditions.length) {
rooms = rooms.filter(r => { rooms = rooms.filter(r => {
for (const filter of this.prefilterConditions) { for (const filter of this.prefilterConditions) {
if (!filter.isVisible(r)) { if (!filter.isVisible(r)) {
@ -556,20 +546,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
*/ */
public async addFilter(filter: IFilterCondition): Promise<void> { public async addFilter(filter: IFilterCondition): Promise<void> {
let promise = Promise.resolve(); let promise = Promise.resolve();
if (filter.kind === FilterKind.Prefilter) {
filter.on(FILTER_CHANGED, this.onPrefilterUpdated); filter.on(FILTER_CHANGED, this.onPrefilterUpdated);
this.prefilterConditions.push(filter); this.prefilterConditions.push(filter);
promise = this.recalculatePrefiltering(); promise = this.recalculatePrefiltering();
} else {
this.filterConditions.push(filter);
// Runtime filters with spaces disable prefiltering for the search all spaces feature.
// this has to be awaited so that `setKnownRooms` is called in time for the `addFilterCondition` below
// this way the runtime filters are only evaluated on one dataset and not both.
await this.recalculatePrefiltering();
if (this.algorithm) {
this.algorithm.addFilterCondition(filter);
}
}
promise.then(() => this.updateFn.trigger()); promise.then(() => this.updateFn.trigger());
} }
@ -582,20 +561,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
*/ */
public removeFilter(filter: IFilterCondition): void { public removeFilter(filter: IFilterCondition): void {
let promise = Promise.resolve(); let promise = Promise.resolve();
let idx = this.filterConditions.indexOf(filter);
let removed = false; let removed = false;
if (idx >= 0) { const idx = this.prefilterConditions.indexOf(filter);
this.filterConditions.splice(idx, 1);
if (this.algorithm) {
this.algorithm.removeFilterCondition(filter);
}
// Runtime filters with spaces disable prefiltering for the search all spaces feature
promise = this.recalculatePrefiltering();
removed = true;
}
idx = this.prefilterConditions.indexOf(filter);
if (idx >= 0) { if (idx >= 0) {
filter.off(FILTER_CHANGED, this.onPrefilterUpdated); filter.off(FILTER_CHANGED, this.onPrefilterUpdated);
this.prefilterConditions.splice(idx, 1); this.prefilterConditions.splice(idx, 1);
@ -608,20 +575,6 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
} }
} }
/**
* Gets the first (and ideally only) name filter condition. If one isn't present,
* this returns null.
* @returns The first name filter condition, or null if none.
*/
public getFirstNameFilterCondition(): NameFilterCondition | null {
for (const filter of this.filterConditions) {
if (filter instanceof NameFilterCondition) {
return filter;
}
}
return null;
}
/** /**
* Gets the tags for a room identified by the store. The returned set * Gets the tags for a room identified by the store. The returned set
* should never be empty, and will contain DefaultTagID.Untagged if * should never be empty, and will contain DefaultTagID.Untagged if

View file

@ -30,7 +30,6 @@ import {
ListAlgorithm, ListAlgorithm,
SortAlgorithm, SortAlgorithm,
} from "./models"; } from "./models";
import { FILTER_CHANGED, IFilterCondition } from "../filters/IFilterCondition";
import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } from "../../../utils/membership"; import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } from "../../../utils/membership";
import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm"; import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm";
import { getListAlgorithmInstance } from "./list-ordering"; import { getListAlgorithmInstance } from "./list-ordering";
@ -67,7 +66,6 @@ interface IStickyRoom {
export class Algorithm extends EventEmitter { export class Algorithm extends EventEmitter {
private _cachedRooms: ITagMap = {}; private _cachedRooms: ITagMap = {};
private _cachedStickyRooms: ITagMap = {}; // a clone of the _cachedRooms, with the sticky room private _cachedStickyRooms: ITagMap = {}; // a clone of the _cachedRooms, with the sticky room
private filteredRooms: ITagMap = {};
private _stickyRoom: IStickyRoom = null; private _stickyRoom: IStickyRoom = null;
private _lastStickyRoom: IStickyRoom = null; // only not-null when changing the sticky room private _lastStickyRoom: IStickyRoom = null; // only not-null when changing the sticky room
private sortAlgorithms: ITagSortingMap; private sortAlgorithms: ITagSortingMap;
@ -77,8 +75,6 @@ export class Algorithm extends EventEmitter {
private roomIdsToTags: { private roomIdsToTags: {
[roomId: string]: TagID[]; [roomId: string]: TagID[];
} = {}; } = {};
private allowedByFilter: Map<IFilterCondition, Room[]> = new Map<IFilterCondition, Room[]>();
private allowedRoomsByFilters: Set<Room> = new Set<Room>();
/** /**
* Set to true to suspend emissions of algorithm updates. * Set to true to suspend emissions of algorithm updates.
@ -107,13 +103,8 @@ export class Algorithm extends EventEmitter {
return !!this.sortAlgorithms; return !!this.sortAlgorithms;
} }
protected get hasFilters(): boolean {
return this.allowedByFilter.size > 0;
}
protected set cachedRooms(val: ITagMap) { protected set cachedRooms(val: ITagMap) {
this._cachedRooms = val; this._cachedRooms = val;
this.recalculateFilteredRooms();
this.recalculateStickyRoom(); this.recalculateStickyRoom();
this.recalculateVideoRoom(); this.recalculateVideoRoom();
} }
@ -151,7 +142,6 @@ export class Algorithm extends EventEmitter {
const algorithm: OrderingAlgorithm = this.algorithms[tagId]; const algorithm: OrderingAlgorithm = this.algorithms[tagId];
algorithm.setSortAlgorithm(sort); algorithm.setSortAlgorithm(sort);
this._cachedRooms[tagId] = algorithm.orderedRooms; this._cachedRooms[tagId] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(tagId); // update filter to re-sort the list
this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tagId); this.recalculateVideoRoom(tagId);
} }
@ -171,40 +161,10 @@ export class Algorithm extends EventEmitter {
algorithm.setRooms(this._cachedRooms[tagId]); algorithm.setRooms(this._cachedRooms[tagId]);
this._cachedRooms[tagId] = algorithm.orderedRooms; this._cachedRooms[tagId] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(tagId); // update filter to re-sort the list
this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed this.recalculateStickyRoom(tagId); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tagId); this.recalculateVideoRoom(tagId);
} }
public addFilterCondition(filterCondition: IFilterCondition): void {
// Populate the cache of the new filter
this.allowedByFilter.set(filterCondition, this.rooms.filter(r => filterCondition.isVisible(r)));
this.recalculateFilteredRooms();
filterCondition.on(FILTER_CHANGED, this.handleFilterChange.bind(this));
}
public removeFilterCondition(filterCondition: IFilterCondition): void {
filterCondition.off(FILTER_CHANGED, this.handleFilterChange.bind(this));
if (this.allowedByFilter.has(filterCondition)) {
this.allowedByFilter.delete(filterCondition);
this.recalculateFilteredRooms();
// If we removed the last filter, tell consumers that we've "updated" our filtered
// view. This will trick them into getting the complete room list.
if (!this.hasFilters && !this.updatesInhibited) {
this.emit(LIST_UPDATED_EVENT);
}
}
}
private handleFilterChange() {
this.recalculateFilteredRooms();
// re-emit the update so the list store can fire an off-cycle update if needed
if (this.updatesInhibited) return;
this.emit(FILTER_CHANGED);
}
private updateStickyRoom(val: Room) { private updateStickyRoom(val: Room) {
this.doUpdateStickyRoom(val); this.doUpdateStickyRoom(val);
this._lastStickyRoom = null; // clear to indicate we're done changing this._lastStickyRoom = null; // clear to indicate we're done changing
@ -318,8 +278,6 @@ export class Algorithm extends EventEmitter {
// We update the filtered rooms just in case, as otherwise users will end up visiting // We update the filtered rooms just in case, as otherwise users will end up visiting
// a room while filtering and it'll disappear. We don't update the filter earlier in // a room while filtering and it'll disappear. We don't update the filter earlier in
// this function simply because we don't have to. // this function simply because we don't have to.
this.recalculateFilteredRoomsForTag(tag);
if (lastStickyRoom && lastStickyRoom.tag !== tag) this.recalculateFilteredRoomsForTag(lastStickyRoom.tag);
this.recalculateStickyRoom(); this.recalculateStickyRoom();
this.recalculateVideoRoom(tag); this.recalculateVideoRoom(tag);
if (lastStickyRoom && lastStickyRoom.tag !== tag) this.recalculateVideoRoom(lastStickyRoom.tag); if (lastStickyRoom && lastStickyRoom.tag !== tag) this.recalculateVideoRoom(lastStickyRoom.tag);
@ -334,7 +292,6 @@ export class Algorithm extends EventEmitter {
*/ */
public updateVideoRoom = () => { public updateVideoRoom = () => {
// In case we're unsticking a video room, sort it back into natural order // In case we're unsticking a video room, sort it back into natural order
this.recalculateFilteredRooms();
this.recalculateStickyRoom(); this.recalculateStickyRoom();
this.recalculateVideoRoom(); this.recalculateVideoRoom();
@ -345,63 +302,6 @@ export class Algorithm extends EventEmitter {
this.emit(LIST_UPDATED_EVENT, true); this.emit(LIST_UPDATED_EVENT, true);
}; };
protected recalculateFilteredRooms() {
if (!this.hasFilters) {
return;
}
logger.warn("Recalculating filtered room list");
const filters = Array.from(this.allowedByFilter.keys());
const newMap: ITagMap = {};
for (const tagId of Object.keys(this.cachedRooms)) {
// Cheaply clone the rooms so we can more easily do operations on the list.
// We optimize our lookups by trying to reduce sample size as much as possible
// to the rooms we know will be deduped by the Set.
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
this.tryInsertStickyRoomToFilterSet(rooms, tagId);
const remainingRooms = rooms.map(r => r);
const allowedRoomsInThisTag = [];
for (const filter of filters) {
const filteredRooms = remainingRooms.filter(r => filter.isVisible(r));
for (const room of filteredRooms) {
const idx = remainingRooms.indexOf(room);
if (idx >= 0) remainingRooms.splice(idx, 1);
allowedRoomsInThisTag.push(room);
}
}
newMap[tagId] = allowedRoomsInThisTag;
}
const allowedRooms = Object.values(newMap).reduce((rv, v) => { rv.push(...v); return rv; }, <Room[]>[]);
this.allowedRoomsByFilters = new Set(allowedRooms);
this.filteredRooms = newMap;
if (this.updatesInhibited) return;
this.emit(LIST_UPDATED_EVENT);
}
protected recalculateFilteredRoomsForTag(tagId: TagID): void {
if (!this.hasFilters) return; // don't bother doing work if there's nothing to do
delete this.filteredRooms[tagId];
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
this.tryInsertStickyRoomToFilterSet(rooms, tagId);
const filteredRooms = rooms.filter(r => this.allowedRoomsByFilters.has(r));
if (filteredRooms.length > 0) {
this.filteredRooms[tagId] = filteredRooms;
}
}
protected tryInsertStickyRoomToFilterSet(rooms: Room[], tagId: TagID) {
if (!this._stickyRoom || !this._stickyRoom.room || this._stickyRoom.tag !== tagId) return;
const position = this._stickyRoom.position;
if (position >= rooms.length) {
rooms.push(this._stickyRoom.room);
} else {
rooms.splice(position, 0, this._stickyRoom.room);
}
}
private initCachedStickyRooms() { private initCachedStickyRooms() {
this._cachedStickyRooms = {}; this._cachedStickyRooms = {};
for (const tagId of Object.keys(this.cachedRooms)) { for (const tagId of Object.keys(this.cachedRooms)) {
@ -520,18 +420,11 @@ export class Algorithm extends EventEmitter {
} }
/** /**
* Gets an ordered set of rooms for the all known tags, filtered. * Gets an ordered set of rooms for the all known tags.
* @returns {ITagMap} The cached list of rooms, ordered, * @returns {ITagMap} The cached list of rooms, ordered,
* for each tag. May be empty, but never null/undefined. * for each tag. May be empty, but never null/undefined.
*/ */
public getOrderedRooms(): ITagMap { public getOrderedRooms(): ITagMap {
if (!this.hasFilters) {
return this._cachedStickyRooms || this.cachedRooms;
}
return this.filteredRooms;
}
public getUnfilteredRooms(): ITagMap {
return this._cachedStickyRooms || this.cachedRooms; return this._cachedStickyRooms || this.cachedRooms;
} }
@ -543,11 +436,8 @@ export class Algorithm extends EventEmitter {
* for each tag. May be empty, but never null/undefined. * for each tag. May be empty, but never null/undefined.
*/ */
private getOrderedRoomsWithoutSticky(): ITagMap { private getOrderedRoomsWithoutSticky(): ITagMap {
if (!this.hasFilters) {
return this.cachedRooms; return this.cachedRooms;
} }
return this.filteredRooms;
}
/** /**
* Seeds the Algorithm with a set of rooms. The algorithm will discard all * Seeds the Algorithm with a set of rooms. The algorithm will discard all
@ -775,7 +665,6 @@ export class Algorithm extends EventEmitter {
if (!algorithm) throw new Error(`No algorithm for ${rmTag}`); if (!algorithm) throw new Error(`No algorithm for ${rmTag}`);
algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved); algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved);
this._cachedRooms[rmTag] = algorithm.orderedRooms; this._cachedRooms[rmTag] = algorithm.orderedRooms;
this.recalculateFilteredRoomsForTag(rmTag); // update filter to re-sort the list
this.recalculateStickyRoom(rmTag); // update sticky room to make sure it moves if needed this.recalculateStickyRoom(rmTag); // update sticky room to make sure it moves if needed
this.recalculateVideoRoom(rmTag); this.recalculateVideoRoom(rmTag);
} }
@ -852,7 +741,6 @@ export class Algorithm extends EventEmitter {
this._cachedRooms[tag] = algorithm.orderedRooms; this._cachedRooms[tag] = algorithm.orderedRooms;
// Flag that we've done something // Flag that we've done something
this.recalculateFilteredRoomsForTag(tag); // update filter to re-sort the list
this.recalculateStickyRoom(tag); // update sticky room to make sure it appears if needed this.recalculateStickyRoom(tag); // update sticky room to make sure it appears if needed
this.recalculateVideoRoom(tag); this.recalculateVideoRoom(tag);
changed = true; changed = true;

View file

@ -19,21 +19,6 @@ import { EventEmitter } from "events";
export const FILTER_CHANGED = "filter_changed"; export const FILTER_CHANGED = "filter_changed";
export enum FilterKind {
/**
* A prefilter is one which coarsely determines which rooms are
* available for runtime filtering/rendering. Typically this will
* be things like Space selection.
*/
Prefilter,
/**
* Runtime filters operate on the data set exposed by prefilters.
* Typically these are dynamic values like room name searching.
*/
Runtime,
}
/** /**
* A filter condition for the room list, determining if a room * A filter condition for the room list, determining if a room
* should be shown or not. * should be shown or not.
@ -47,11 +32,6 @@ export enum FilterKind {
* as a change in the user's input), this emits FILTER_CHANGED. * as a change in the user's input), this emits FILTER_CHANGED.
*/ */
export interface IFilterCondition extends EventEmitter { export interface IFilterCondition extends EventEmitter {
/**
* The kind of filter this presents.
*/
kind: FilterKind;
/** /**
* Determines if a given room should be visible under this * Determines if a given room should be visible under this
* condition. * condition.

View file

@ -1,72 +0,0 @@
/*
Copyright 2020, 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 { EventEmitter } from "events";
import { normalize } from "matrix-js-sdk/src/utils";
import { throttle } from "lodash";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
/**
* A filter condition for the room list which reveals rooms of a particular
* name, or associated name (like a room alias).
*/
export class NameFilterCondition extends EventEmitter implements IFilterCondition {
private _search = "";
constructor() {
super();
}
public get kind(): FilterKind {
return FilterKind.Runtime;
}
public get search(): string {
return this._search;
}
public set search(val: string) {
this._search = val;
this.callUpdate();
}
private callUpdate = throttle(() => {
this.emit(FILTER_CHANGED);
}, 200, { trailing: true, leading: true });
public isVisible(room: Room): boolean {
const lcFilter = this.search.toLowerCase();
if (this.search[0] === '#') {
// Try and find rooms by alias
if (room.getCanonicalAlias() && room.getCanonicalAlias().toLowerCase().startsWith(lcFilter)) {
return true;
}
if (room.getAltAliases().some(a => a.toLowerCase().startsWith(lcFilter))) {
return true;
}
}
if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name
return this.matches(room.normalizedName);
}
public matches(normalizedName: string): boolean {
return normalizedName.includes(normalize(this.search));
}
}

View file

@ -17,7 +17,7 @@ limitations under the License.
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition"; import { FILTER_CHANGED, IFilterCondition } from "./IFilterCondition";
import { IDestroyable } from "../../../utils/IDestroyable"; import { IDestroyable } from "../../../utils/IDestroyable";
import SpaceStore from "../../spaces/SpaceStore"; import SpaceStore from "../../spaces/SpaceStore";
import { isMetaSpace, MetaSpace, SpaceKey } from "../../spaces"; import { isMetaSpace, MetaSpace, SpaceKey } from "../../spaces";
@ -36,10 +36,6 @@ export class SpaceFilterCondition extends EventEmitter implements IFilterConditi
private showPeopleInSpace = true; private showPeopleInSpace = true;
private space: SpaceKey = MetaSpace.Home; private space: SpaceKey = MetaSpace.Home;
public get kind(): FilterKind {
return FilterKind.Prefilter;
}
public isVisible(room: Room): boolean { public isVisible(room: Room): boolean {
return SpaceStore.instance.isRoomInSpace(this.space, room.roomId); return SpaceStore.instance.isRoomInSpace(this.space, room.roomId);
} }

View file

@ -187,7 +187,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
metricsTrigger: "WebSpacePanelNotificationBadge", metricsTrigger: "WebSpacePanelNotificationBadge",
}); });
} else { } else {
const lists = RoomListStore.instance.unfilteredLists; const lists = RoomListStore.instance.orderedLists;
for (let i = 0; i < TAG_ORDER.length; i++) { for (let i = 0; i < TAG_ORDER.length; i++) {
const t = TAG_ORDER[i]; const t = TAG_ORDER[i];
const listRooms = lists[t]; const listRooms = lists[t];