Step 8.5: Isolate RightPanelStore from RoomViewStore

This commit is contained in:
Travis Ralston 2022-03-24 15:50:04 -06:00
parent 66401c844f
commit 4144d0ba57
7 changed files with 91 additions and 29 deletions

View file

@ -60,7 +60,13 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro
// Default implementation is to do nothing.
}
protected onDispatcherAction(payload: ActionPayload) {
// Default implementation is to do nothing.
}
private onAction = async (payload: ActionPayload) => {
this.onDispatcherAction(payload);
if (payload.action === 'MatrixActions.sync') {
// Only set the client on the transition into the PREPARED state.
// Everything after this is unnecessary (we only need to know once we have a client)

View file

@ -24,7 +24,7 @@ import { ViewRoom as ViewRoomEvent } from "matrix-analytics-events/types/typescr
import { JoinedRoom as JoinedRoomEvent } from "matrix-analytics-events/types/typescript/JoinedRoom";
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
import { Room } from "matrix-js-sdk/src/models/room";
import { ClientEvent } from "matrix-js-sdk/src/client";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
import dis from '../dispatcher/dispatcher';
import { MatrixClientPeg } from '../MatrixClientPeg';
@ -46,6 +46,7 @@ import { JoinRoomErrorPayload } from "../dispatcher/payloads/JoinRoomErrorPayloa
import { ViewRoomErrorPayload } from "../dispatcher/payloads/ViewRoomErrorPayload";
import RoomSettingsDialog from "../components/views/dialogs/RoomSettingsDialog";
import ErrorDialog from "../components/views/dialogs/ErrorDialog";
import { ActiveRoomChangedPayload } from "../dispatcher/payloads/ActiveRoomChangedPayload";
const NUM_JOIN_RETRY = 5;
@ -93,6 +94,7 @@ export class RoomViewStore extends Store<ActionPayload> {
public static readonly instance = new RoomViewStore();
private state = INITIAL_STATE; // initialize state
private forcedMatrixClient: MatrixClient;
// Keep these out of state to avoid causing excessive/recursive updates
private roomIdActivityListeners: Record<string, Listener[]> = {};
@ -101,6 +103,14 @@ export class RoomViewStore extends Store<ActionPayload> {
super(dis);
}
private get matrixClient(): MatrixClient {
return this.forcedMatrixClient || MatrixClientPeg.get();
}
public useUnitTestClient(client: MatrixClient) {
this.forcedMatrixClient = client;
}
public addRoomListener(roomId: string, fn: Listener) {
if (!this.roomIdActivityListeners[roomId]) this.roomIdActivityListeners[roomId] = [];
this.roomIdActivityListeners[roomId].push(fn);
@ -145,6 +155,14 @@ export class RoomViewStore extends Store<ActionPayload> {
if (lastRoomId !== this.state.roomId) {
if (lastRoomId) this.emitForRoom(lastRoomId, false);
if (this.state.roomId) this.emitForRoom(this.state.roomId, true);
// Fired so we can reduce dependency on event emitters to this store, which is relatively
// central to the application and can easily cause import cycles.
dis.dispatch({
action: Action.ActiveRoomChanged,
oldRoomId: lastRoomId,
newRoomId: this.state.roomId,
} as ActiveRoomChangedPayload);
}
this.__emitChange();
@ -197,7 +215,7 @@ export class RoomViewStore extends Store<ActionPayload> {
this.setState({ shouldPeek: false });
}
const cli = MatrixClientPeg.get();
const cli = this.matrixClient;
const updateMetrics = () => {
const room = cli.getRoom(payload.roomId);
@ -280,7 +298,7 @@ export class RoomViewStore extends Store<ActionPayload> {
trigger: payload.metricsTrigger,
viaKeyboard: payload.metricsViaKeyboard,
isDM: !!DMRoomMap.shared().getUserIdForRoomId(payload.room_id),
isSpace: MatrixClientPeg.get().getRoom(payload.room_id)?.isSpaceRoom(),
isSpace: this.matrixClient.getRoom(payload.room_id)?.isSpaceRoom(),
activeSpace,
});
}
@ -339,7 +357,7 @@ export class RoomViewStore extends Store<ActionPayload> {
wasContextSwitch: payload.context_switch,
});
try {
const result = await MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias);
const result = await this.matrixClient.getRoomIdForAlias(payload.room_alias);
storeRoomAliasInCache(payload.room_alias, result.room_id);
roomId = result.room_id;
} catch (err) {
@ -376,7 +394,7 @@ export class RoomViewStore extends Store<ActionPayload> {
joining: true,
});
const cli = MatrixClientPeg.get();
const cli = this.matrixClient;
// take a copy of roomAlias & roomId as they may change by the time the join is complete
const { roomAlias, roomId } = this.state;
const address = roomAlias || roomId;
@ -408,7 +426,7 @@ export class RoomViewStore extends Store<ActionPayload> {
}
private getInvitingUserId(roomId: string): string {
const cli = MatrixClientPeg.get();
const cli = this.matrixClient;
const room = cli.getRoom(roomId);
if (room && room.getMyMembership() === "invite") {
const myMember = room.getMember(cli.getUserId());
@ -433,7 +451,7 @@ export class RoomViewStore extends Store<ActionPayload> {
// only provide a better error message for invites
if (invitingUserId) {
// if the inviting user is on the same HS, there can only be one cause: they left.
if (invitingUserId.endsWith(`:${MatrixClientPeg.get().getDomain()}`)) {
if (invitingUserId.endsWith(`:${this.matrixClient.getDomain()}`)) {
msg = _t("The person who invited you already left the room.");
} else {
msg = _t("The person who invited you already left the room, or their server is offline.");

View file

@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { EventSubscription } from 'fbemitter';
import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { Optional } from "matrix-events-sdk";
import defaultDispatcher from '../../dispatcher/dispatcher';
import { pendingVerificationRequestForUser } from '../../verification';
@ -31,7 +31,9 @@ import {
IRightPanelCard,
IRightPanelForRoom,
} from './RightPanelStoreIPanelState';
import { RoomViewStore } from '../RoomViewStore';
import { ActionPayload } from "../../dispatcher/payloads";
import { Action } from "../../dispatcher/actions";
import { ActiveRoomChangedPayload } from "../../dispatcher/payloads/ActiveRoomChangedPayload";
/**
* A class for tracking the state of the right panel between layouts and
@ -41,30 +43,32 @@ import { RoomViewStore } from '../RoomViewStore';
*/
export default class RightPanelStore extends ReadyWatchingStore {
private static internalInstance: RightPanelStore;
private viewedRoomId: string;
private global?: IRightPanelForRoom = null;
private byRoom: {
[roomId: string]: IRightPanelForRoom;
} = {};
private roomStoreToken: EventSubscription;
private viewedRoomId: Optional<string>;
private constructor() {
super(defaultDispatcher);
}
protected async onReady(): Promise<any> {
this.roomStoreToken = RoomViewStore.instance.addListener(this.onRoomViewStoreUpdate);
this.matrixClient.on(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
this.viewedRoomId = RoomViewStore.instance.getRoomId();
this.loadCacheFromSettings();
this.emitAndUpdateSettings();
}
protected async onNotReady(): Promise<any> {
this.matrixClient.off(CryptoEvent.VerificationRequest, this.onVerificationRequestUpdate);
this.roomStoreToken.remove();
}
protected onDispatcherAction(payload: ActionPayload) {
if (payload.action !== Action.ActiveRoomChanged) return;
const changePayload = <ActiveRoomChangedPayload>payload;
this.handleViewedRoomChange(changePayload.oldRoomId, changePayload.newRoomId);
}
// Getters
@ -336,23 +340,20 @@ export default class RightPanelStore extends ReadyWatchingStore {
}
};
private onRoomViewStoreUpdate = () => {
const oldRoomId = this.viewedRoomId;
this.viewedRoomId = RoomViewStore.instance.getRoomId();
private handleViewedRoomChange(oldRoomId: Optional<string>, newRoomId: Optional<string>) {
this.viewedRoomId = newRoomId;
// load values from byRoomCache with the viewedRoomId.
this.loadCacheFromSettings();
// if we're switching to a room, clear out any stale MemberInfo cards
// when we're switching to a room, clear out any stale MemberInfo cards
// in order to fix https://github.com/vector-im/element-web/issues/21487
if (oldRoomId !== this.viewedRoomId) {
if (this.currentCard?.phase !== RightPanelPhases.EncryptionPanel) {
const panel = this.byRoom[this.viewedRoomId];
if (panel?.history) {
panel.history = panel.history.filter(
(card) => card.phase != RightPanelPhases.RoomMemberInfo &&
card.phase != RightPanelPhases.Room3pidMemberInfo,
);
}
if (this.currentCard?.phase !== RightPanelPhases.EncryptionPanel) {
const panel = this.byRoom[this.viewedRoomId];
if (panel?.history) {
panel.history = panel.history.filter(
(card) => card.phase != RightPanelPhases.RoomMemberInfo &&
card.phase != RightPanelPhases.Room3pidMemberInfo,
);
}
}
@ -374,7 +375,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
};
}
this.emitAndUpdateSettings();
};
}
private get isViewingRoom(): boolean {
return !!this.viewedRoomId;