Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit a70be45

Browse files
committed
Experiment switching the Home Space out for an All rooms space
1 parent 4823794 commit a70be45

File tree

8 files changed

+49
-149
lines changed

8 files changed

+49
-149
lines changed

src/components/structures/RoomSearch.tsx

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
import * as React from "react";
1818
import { createRef } from "react";
1919
import classNames from "classnames";
20-
import { Room } from "matrix-js-sdk/src/models/room";
2120

2221
import defaultDispatcher from "../../dispatcher/dispatcher";
2322
import { _t } from "../../languageHandler";
@@ -27,8 +26,8 @@ import { Action } from "../../dispatcher/actions";
2726
import RoomListStore from "../../stores/room-list/RoomListStore";
2827
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
2928
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
30-
import {replaceableComponent} from "../../utils/replaceableComponent";
31-
import SpaceStore, {UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES} from "../../stores/SpaceStore";
29+
import { replaceableComponent } from "../../utils/replaceableComponent";
30+
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore";
3231

3332
interface IProps {
3433
isMinimized: boolean;
@@ -42,7 +41,6 @@ interface IProps {
4241
interface IState {
4342
query: string;
4443
focused: boolean;
45-
inSpaces: boolean;
4644
}
4745

4846
@replaceableComponent("structures.RoomSearch")
@@ -57,13 +55,11 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
5755
this.state = {
5856
query: "",
5957
focused: false,
60-
inSpaces: false,
6158
};
6259

6360
this.dispatcherRef = defaultDispatcher.register(this.onAction);
6461
// clear filter when changing spaces, in future we may wish to maintain a filter per-space
6562
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.clearInput);
66-
SpaceStore.instance.on(UPDATE_TOP_LEVEL_SPACES, this.onSpaces);
6763
}
6864

6965
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>): void {
@@ -84,15 +80,8 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
8480
public componentWillUnmount() {
8581
defaultDispatcher.unregister(this.dispatcherRef);
8682
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.clearInput);
87-
SpaceStore.instance.off(UPDATE_TOP_LEVEL_SPACES, this.onSpaces);
8883
}
8984

90-
private onSpaces = (spaces: Room[]) => {
91-
this.setState({
92-
inSpaces: spaces.length > 0,
93-
});
94-
};
95-
9685
private onAction = (payload: ActionPayload) => {
9786
if (payload.action === 'view_room' && payload.clear_search) {
9887
this.clearInput();
@@ -164,11 +153,6 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
164153
'mx_RoomSearch_inputExpanded': this.state.query || this.state.focused,
165154
});
166155

167-
let placeholder = _t("Filter");
168-
if (this.state.inSpaces) {
169-
placeholder = _t("Filter all spaces");
170-
}
171-
172156
let icon = (
173157
<div className='mx_RoomSearch_icon' />
174158
);
@@ -182,7 +166,7 @@ export default class RoomSearch extends React.PureComponent<IProps, IState> {
182166
onBlur={this.onBlur}
183167
onChange={this.onChange}
184168
onKeyDown={this.onKeyDown}
185-
placeholder={placeholder}
169+
placeholder={_t("Filter")}
186170
autoComplete="off"
187171
/>
188172
);

src/components/views/rooms/RoomListNumResults.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import React, {useState} from "react";
1919
import { _t } from "../../../languageHandler";
2020
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../../stores/room-list/RoomListStore";
2121
import {useEventEmitter} from "../../../hooks/useEventEmitter";
22-
import SpaceStore from "../../../stores/SpaceStore";
2322

2423
const RoomListNumResults: React.FC = () => {
2524
const [count, setCount] = useState<number>(null);
@@ -35,10 +34,7 @@ const RoomListNumResults: React.FC = () => {
3534
if (typeof count !== "number") return null;
3635

3736
return <div className="mx_LeftPanel_roomListFilterCount">
38-
{ SpaceStore.instance.spacePanelSpaces.length
39-
? _t("%(count)s results in all spaces", { count })
40-
: _t("%(count)s results", { count })
41-
}
37+
{ _t("%(count)s results", { count }) }
4238
</div>;
4339
};
4440

src/components/views/spaces/SpacePanel.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,27 @@ import {SpaceItem} from "./SpaceTreeLevel";
2626
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
2727
import {useEventEmitter} from "../../../hooks/useEventEmitter";
2828
import SpaceStore, {
29-
HOME_SPACE,
3029
UPDATE_INVITED_SPACES,
3130
UPDATE_SELECTED_SPACE,
3231
UPDATE_TOP_LEVEL_SPACES,
3332
} from "../../../stores/SpaceStore";
3433
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
35-
import {SpaceNotificationState} from "../../../stores/notifications/SpaceNotificationState";
3634
import NotificationBadge from "../rooms/NotificationBadge";
3735
import {
3836
RovingAccessibleButton,
3937
RovingAccessibleTooltipButton,
4038
RovingTabIndexProvider,
4139
} from "../../../accessibility/RovingTabIndex";
4240
import {Key} from "../../../Keyboard";
41+
import {RoomNotificationStateStore} from "../../../stores/notifications/RoomNotificationStateStore";
42+
import {NotificationState} from "../../../stores/notifications/NotificationState";
4343

4444
interface IButtonProps {
4545
space?: Room;
4646
className?: string;
4747
selected?: boolean;
4848
tooltip?: string;
49-
notificationState?: SpaceNotificationState;
49+
notificationState?: NotificationState;
5050
isNarrow?: boolean;
5151
onClick(): void;
5252
}
@@ -212,8 +212,8 @@ const SpacePanel = () => {
212212
className="mx_SpaceButton_home"
213213
onClick={() => SpaceStore.instance.setActiveSpace(null)}
214214
selected={!activeSpace}
215-
tooltip={_t("Home")}
216-
notificationState={SpaceStore.instance.getNotificationState(HOME_SPACE)}
215+
tooltip={_t("All rooms")}
216+
notificationState={RoomNotificationStateStore.instance.globalState}
217217
isNarrow={isPanelCollapsed}
218218
/>
219219
{ invites.map(s => <SpaceItem

src/i18n/strings/en_EN.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@
10111011
"Create": "Create",
10121012
"Expand space panel": "Expand space panel",
10131013
"Collapse space panel": "Collapse space panel",
1014-
"Home": "Home",
1014+
"All rooms": "All rooms",
10151015
"Click to copy": "Click to copy",
10161016
"Copied!": "Copied!",
10171017
"Failed to copy": "Failed to copy",
@@ -1552,8 +1552,6 @@
15521552
"Explore all public rooms": "Explore all public rooms",
15531553
"Quick actions": "Quick actions",
15541554
"Use the + to make a new room or explore existing ones below": "Use the + to make a new room or explore existing ones below",
1555-
"%(count)s results in all spaces|other": "%(count)s results in all spaces",
1556-
"%(count)s results in all spaces|one": "%(count)s result in all spaces",
15571555
"%(count)s results|other": "%(count)s results",
15581556
"%(count)s results|one": "%(count)s result",
15591557
"This room": "This room",
@@ -2014,10 +2012,10 @@
20142012
"Continue with %(provider)s": "Continue with %(provider)s",
20152013
"Sign in with single sign-on": "Sign in with single sign-on",
20162014
"And %(count)s more...|other": "And %(count)s more...",
2015+
"Home": "Home",
20172016
"Enter a server name": "Enter a server name",
20182017
"Looks good": "Looks good",
20192018
"Can't find this server or its room list": "Can't find this server or its room list",
2020-
"All rooms": "All rooms",
20212019
"Your server": "Your server",
20222020
"Are you sure you want to remove <b>%(serverName)s</b>": "Are you sure you want to remove <b>%(serverName)s</b>",
20232021
"Remove server": "Remove server",
@@ -2619,7 +2617,6 @@
26192617
"If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.": "If you can't find the room you're looking for, ask for an invite or <a>Create a new room</a>.",
26202618
"Explore rooms in %(communityName)s": "Explore rooms in %(communityName)s",
26212619
"Filter": "Filter",
2622-
"Filter all spaces": "Filter all spaces",
26232620
"Clear filter": "Clear filter",
26242621
"Filter rooms and people": "Filter rooms and people",
26252622
"You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.": "You can't send any messages until you review and agree to <consentLink>our terms and conditions</consentLink>.",

src/stores/SpaceStore.tsx

Lines changed: 14 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,23 @@ import {RoomNotificationStateStore} from "./notifications/RoomNotificationStateS
3131
import {DefaultTagID} from "./room-list/models";
3232
import {EnhancedMap, mapDiff} from "../utils/maps";
3333
import {setHasDiff} from "../utils/sets";
34-
import {objectDiff} from "../utils/objects";
35-
import {arrayHasDiff} from "../utils/arrays";
3634
import {ISpaceSummaryEvent, ISpaceSummaryRoom} from "../components/structures/SpaceRoomDirectory";
3735
import RoomViewStore from "./RoomViewStore";
3836

39-
type SpaceKey = string | symbol;
40-
4137
interface IState {}
4238

4339
const ACTIVE_SPACE_LS_KEY = "mx_active_space";
4440

45-
export const HOME_SPACE = Symbol("home-space");
4641
export const SUGGESTED_ROOMS = Symbol("suggested-rooms");
4742

4843
export const UPDATE_TOP_LEVEL_SPACES = Symbol("top-level-spaces");
4944
export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
5045
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
51-
// Space Room ID/HOME_SPACE will be emitted when a Space's children change
46+
// Space Room ID will be emitted when a Space's children change
5247

5348
const MAX_SUGGESTED_ROOMS = 20;
5449

55-
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "home_space"}`;
50+
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "ALL_ROOMS"}`;
5651

5752
const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces, rooms]
5853
return arr.reduce((result, room: Room) => {
@@ -83,15 +78,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
8378

8479
// The spaces representing the roots of the various tree-like hierarchies
8580
private rootSpaces: Room[] = [];
86-
// The list of rooms not present in any currently joined spaces
87-
private orphanedRooms = new Set<string>();
8881
// Map from room ID to set of spaces which list it as a child
8982
private parentMap = new EnhancedMap<string, Set<string>>();
90-
// Map from space key to SpaceNotificationState instance representing that space
91-
private notificationStateMap = new Map<SpaceKey, SpaceNotificationState>();
83+
// Map from spaceId to SpaceNotificationState instance representing that space
84+
private notificationStateMap = new Map<string, SpaceNotificationState>();
9285
// Map from space key to Set of room IDs that should be shown as part of that space's filter
93-
private spaceFilteredRooms = new Map<string | symbol, Set<string>>();
94-
// The space currently selected in the Space Panel - if null then `Home` is selected
86+
private spaceFilteredRooms = new Map<string, Set<string>>();
87+
// The space currently selected in the Space Panel - if null then All Rooms is selected
9588
private _activeSpace?: Room = null;
9689
private _suggestedRooms: ISpaceSummaryRoom[] = [];
9790
private _invitedSpaces = new Set<Room>();
@@ -227,7 +220,10 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
227220
}
228221

229222
public getSpaceFilteredRoomIds = (space: Room | null): Set<string> => {
230-
return this.spaceFilteredRooms.get(space?.roomId || HOME_SPACE) || new Set();
223+
if (!space) {
224+
return new Set(this.matrixClient.getVisibleRooms().map(r => r.roomId));
225+
}
226+
return this.spaceFilteredRooms.get(space.roomId) || new Set();
231227
};
232228

233229
private rebuild = throttle(() => {
@@ -258,7 +254,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
258254
});
259255
});
260256

261-
const [rootSpaces, orphanedRooms] = partitionSpacesAndRooms(Array.from(unseenChildren));
257+
const [rootSpaces] = partitionSpacesAndRooms(Array.from(unseenChildren));
262258

263259
// somewhat algorithm to handle full-cycles
264260
const detachedNodes = new Set<Room>(spaces);
@@ -299,7 +295,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
299295
// rootSpaces.push(space);
300296
// });
301297

302-
this.orphanedRooms = new Set(orphanedRooms);
303298
this.rootSpaces = rootSpaces;
304299
this.parentMap = backrefs;
305300

@@ -320,25 +315,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
320315
this.rebuild();
321316
}
322317

323-
private showInHomeSpace = (room: Room) => {
324-
if (room.isSpaceRoom()) return false;
325-
return !this.parentMap.get(room.roomId)?.size // put all orphaned rooms in the Home Space
326-
|| DMRoomMap.shared().getUserIdForRoomId(room.roomId) // put all DMs in the Home Space
327-
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite) // show all favourites
328-
};
329-
330-
// Update a given room due to its tag changing (e.g DM-ness or Fav-ness)
331-
// This can only change whether it shows up in the HOME_SPACE or not
332-
private onRoomUpdate = (room: Room) => {
333-
if (this.showInHomeSpace(room)) {
334-
this.spaceFilteredRooms.get(HOME_SPACE)?.add(room.roomId);
335-
this.emit(HOME_SPACE);
336-
} else if (!this.orphanedRooms.has(room.roomId)) {
337-
this.spaceFilteredRooms.get(HOME_SPACE)?.delete(room.roomId);
338-
this.emit(HOME_SPACE);
339-
}
340-
};
341-
342318
private onSpaceMembersChange = (ev: MatrixEvent) => {
343319
// skip this update if we do not have a DM with this user
344320
if (DMRoomMap.shared().getDMRoomsForUserId(ev.getStateKey()).length < 1) return;
@@ -352,16 +328,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
352328
const oldFilteredRooms = this.spaceFilteredRooms;
353329
this.spaceFilteredRooms = new Map();
354330

355-
// put all room invites in the Home Space
356-
const invites = visibleRooms.filter(r => !r.isSpaceRoom() && r.getMyMembership() === "invite");
357-
this.spaceFilteredRooms.set(HOME_SPACE, new Set<string>(invites.map(room => room.roomId)));
358-
359-
visibleRooms.forEach(room => {
360-
if (this.showInHomeSpace(room)) {
361-
this.spaceFilteredRooms.get(HOME_SPACE).add(room.roomId);
362-
}
363-
});
364-
365331
this.rootSpaces.forEach(s => {
366332
// traverse each space tree in DFS to build up the supersets as you go up,
367333
// reusing results from like subtrees.
@@ -408,13 +374,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
408374
// Update NotificationStates
409375
this.getNotificationState(s)?.setRooms(visibleRooms.filter(room => {
410376
if (roomIds.has(room.roomId)) {
411-
// Don't aggregate notifications for DMs except in the Home Space
412-
if (s !== HOME_SPACE) {
413-
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
414-
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
415-
}
416-
417-
return true;
377+
return !DMRoomMap.shared().getUserIdForRoomId(room.roomId)
378+
|| RoomListStore.instance.getTagsForRoom(room).includes(DefaultTagID.Favourite);
418379
}
419380

420381
return false;
@@ -475,8 +436,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
475436
// TODO confirm this after implementing parenting behaviour
476437
if (room.isSpaceRoom()) {
477438
this.onSpaceUpdate();
478-
} else {
479-
this.onRoomUpdate(room);
480439
}
481440
this.emit(room.roomId);
482441
break;
@@ -489,38 +448,8 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
489448
}
490449
};
491450

492-
private onRoomAccountData = (ev: MatrixEvent, room: Room, lastEvent?: MatrixEvent) => {
493-
if (ev.getType() === EventType.Tag && !room.isSpaceRoom()) {
494-
// If the room was in favourites and now isn't or the opposite then update its position in the trees
495-
const oldTags = lastEvent?.getContent()?.tags || {};
496-
const newTags = ev.getContent()?.tags || {};
497-
if (!!oldTags[DefaultTagID.Favourite] !== !!newTags[DefaultTagID.Favourite]) {
498-
this.onRoomUpdate(room);
499-
}
500-
}
501-
}
502-
503-
private onAccountData = (ev: MatrixEvent, lastEvent: MatrixEvent) => {
504-
if (ev.getType() === EventType.Direct) {
505-
const lastContent = lastEvent.getContent();
506-
const content = ev.getContent();
507-
508-
const diff = objectDiff<Record<string, string[]>>(lastContent, content);
509-
// filter out keys which changed by reference only by checking whether the sets differ
510-
const changed = diff.changed.filter(k => arrayHasDiff(lastContent[k], content[k]));
511-
// DM tag changes, refresh relevant rooms
512-
new Set([...diff.added, ...diff.removed, ...changed]).forEach(roomId => {
513-
const room = this.matrixClient?.getRoom(roomId);
514-
if (room) {
515-
this.onRoomUpdate(room);
516-
}
517-
});
518-
}
519-
};
520-
521451
protected async reset() {
522452
this.rootSpaces = [];
523-
this.orphanedRooms = new Set();
524453
this.parentMap = new EnhancedMap();
525454
this.notificationStateMap = new Map();
526455
this.spaceFilteredRooms = new Map();
@@ -535,8 +464,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
535464
this.matrixClient.removeListener("Room", this.onRoom);
536465
this.matrixClient.removeListener("Room.myMembership", this.onRoom);
537466
this.matrixClient.removeListener("RoomState.events", this.onRoomState);
538-
this.matrixClient.removeListener("Room.accountData", this.onRoomAccountData);
539-
this.matrixClient.removeListener("accountData", this.onAccountData);
540467
}
541468
await this.reset();
542469
}
@@ -546,8 +473,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
546473
this.matrixClient.on("Room", this.onRoom);
547474
this.matrixClient.on("Room.myMembership", this.onRoom);
548475
this.matrixClient.on("RoomState.events", this.onRoomState);
549-
this.matrixClient.on("Room.accountData", this.onRoomAccountData);
550-
this.matrixClient.on("accountData", this.onAccountData);
551476

552477
await this.onSpaceUpdate(); // trigger an initial update
553478

@@ -602,7 +527,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
602527
}
603528
}
604529

605-
public getNotificationState(key: SpaceKey): SpaceNotificationState {
530+
public getNotificationState(key: string): SpaceNotificationState {
606531
if (this.notificationStateMap.has(key)) {
607532
return this.notificationStateMap.get(key);
608533
}

0 commit comments

Comments
 (0)