Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/17044.1

 Conflicts:
	src/stores/room-list/RoomListStore.ts
This commit is contained in:
Michael Telatynski 2021-05-07 10:40:07 +01:00
commit 6137162786
50 changed files with 928 additions and 361 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {sortBy, throttle} from "lodash";
import {ListIteratee, Many, sortBy, throttle} from "lodash";
import {EventType, RoomType} from "matrix-js-sdk/src/@types/event";
import {Room} from "matrix-js-sdk/src/models/room";
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
@ -56,15 +56,18 @@ const partitionSpacesAndRooms = (arr: Room[]): [Room[], Room[]] => { // [spaces,
}, [[], []]);
};
const getOrder = (ev: MatrixEvent): string | null => {
const content = ev.getContent();
if (typeof content.order === "string" && Array.from(content.order).every((c: string) => {
// For sorting space children using a validated `order`, `m.room.create`'s `origin_server_ts`, `room_id`
export const getOrder = (order: string, creationTs: number, roomId: string): Array<Many<ListIteratee<any>>> => {
let validatedOrder: string = null;
if (typeof order === "string" && Array.from(order).every((c: string) => {
const charCode = c.charCodeAt(0);
return charCode >= 0x20 && charCode <= 0x7F;
})) {
return content.order;
validatedOrder = order;
}
return null;
return [validatedOrder, creationTs, roomId];
}
const getRoomFn: FetchRoomFn = (room: Room) => {
@ -105,6 +108,13 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
return this._suggestedRooms;
}
/**
* Sets the active space, updates room list filters,
* optionally switches the user's room back to where they were when they last viewed that space.
* @param space which space to switch to.
* @param contextSwitch whether to switch the user's context,
* should not be done when the space switch is done implicitly due to another event like switching room.
*/
public async setActiveSpace(space: Room | null, contextSwitch = true) {
if (space === this.activeSpace || (space && !space?.isSpaceRoom())) return;
@ -186,9 +196,16 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
private getChildren(spaceId: string): Room[] {
const room = this.matrixClient?.getRoom(spaceId);
const childEvents = room?.currentState.getStateEvents(EventType.SpaceChild).filter(ev => ev.getContent()?.via);
return sortBy(childEvents, getOrder)
.map(ev => this.matrixClient.getRoom(ev.getStateKey()))
.filter(room => room?.getMyMembership() === "join" || room?.getMyMembership() === "invite") || [];
return sortBy(childEvents, ev => {
const roomId = ev.getStateKey();
const childRoom = this.matrixClient?.getRoom(roomId);
const createTs = childRoom?.currentState.getStateEvents(EventType.RoomCreate, "")?.getTs();
return getOrder(ev.getContent().order, createTs, roomId);
}).map(ev => {
return this.matrixClient.getRoom(ev.getStateKey());
}).filter(room => {
return room?.getMyMembership() === "join" || room?.getMyMembership() === "invite";
}) || [];
}
public getChildRooms(spaceId: string): Room[] {
@ -300,7 +317,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
// if the currently selected space no longer exists, remove its selection
if (this._activeSpace && detachedNodes.has(this._activeSpace)) {
this.setActiveSpace(null);
this.setActiveSpace(null, false);
}
this.onRoomsUpdate(); // TODO only do this if a change has happened
@ -383,6 +400,22 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
});
}, 100, {trailing: true, leading: true});
private switchToRelatedSpace = (roomId: string) => {
if (this.suggestedRooms.find(r => r.room_id === roomId)) return;
let parent = this.getCanonicalParent(roomId);
if (!parent) {
parent = this.rootSpaces.find(s => this.spaceFilteredRooms.get(s.roomId)?.has(roomId));
}
if (!parent) {
const parents = Array.from(this.parentMap.get(roomId) || []);
parent = parents.find(p => this.matrixClient.getRoom(p));
}
// don't trigger a context switch when we are switching a space to match the chosen room
this.setActiveSpace(parent || null, false);
};
private onRoom = (room: Room, newMembership?: string, oldMembership?: string) => {
const membership = newMembership || room.getMyMembership();
@ -397,6 +430,11 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
if (numSuggestedRooms !== this._suggestedRooms.length) {
this.emit(SUGGESTED_ROOMS, this._suggestedRooms);
}
// if the room currently being viewed was just joined then switch to its related space
if (newMembership === "join" && room.roomId === RoomViewStore.getRoomId()) {
this.switchToRelatedSpace(room.roomId);
}
}
return;
}
@ -415,7 +453,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
if (membership === "join" && room.roomId === RoomViewStore.getRoomId()) {
// if the user was looking at the space and then joined: select that space
this.setActiveSpace(room);
this.setActiveSpace(room, false);
}
};
@ -479,10 +517,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
// restore selected state from last session if any and still valid
const lastSpaceId = window.localStorage.getItem(ACTIVE_SPACE_LS_KEY);
if (lastSpaceId) {
const space = this.rootSpaces.find(s => s.roomId === lastSpaceId);
if (space) {
this.setActiveSpace(space);
}
this.setActiveSpace(this.matrixClient.getRoom(lastSpaceId));
}
}
@ -490,27 +525,18 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
if (!SettingsStore.getValue("feature_spaces")) return;
switch (payload.action) {
case "view_room": {
const room = this.matrixClient?.getRoom(payload.room_id);
// Don't auto-switch rooms when reacting to a context-switch
// as this is not helpful and can create loops of rooms/space switching
if (!room || payload.context_switch) break;
if (payload.context_switch) break;
if (room.isSpaceRoom()) {
const roomId = payload.room_id;
const room = this.matrixClient?.getRoom(roomId);
if (room?.isSpaceRoom()) {
// Don't context switch when navigating to the space room
// as it will cause you to end up in the wrong room
this.setActiveSpace(room, false);
} else if (!this.getSpaceFilteredRoomIds(this.activeSpace).has(room.roomId)) {
let parent = this.getCanonicalParent(room.roomId);
if (!parent) {
parent = this.rootSpaces.find(s => this.spaceFilteredRooms.get(s.roomId)?.has(room.roomId));
}
if (!parent) {
const parents = Array.from(this.parentMap.get(room.roomId) || []);
parent = parents.find(p => this.matrixClient.getRoom(p));
}
// don't trigger a context switch when we are switching a space to match the chosen room
this.setActiveSpace(parent || null, false);
} else if (!this.getSpaceFilteredRoomIds(this.activeSpace).has(roomId)) {
this.switchToRelatedSpace(roomId);
}
// Persist last viewed room from a space
@ -521,7 +547,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
}
case "after_leave_room":
if (this._activeSpace && payload.room_id === this._activeSpace.roomId) {
this.setActiveSpace(null);
this.setActiveSpace(null, false);
}
break;
}