Store refactor: use non-global stores in components (#9293)
* Add Stores and StoresContext and use it in MatrixChat and RoomView Added a new kind of class: - Add God object `Stores` which will hold refs to all known stores and the `MatrixClient`. This object is NOT a singleton. - Add `StoresContext` to hold onto a ref of `Stores` for use inside components. `StoresContext` is created via: - Create `Stores` in `MatrixChat`, assigning the `MatrixClient` when we have one set. Currently sets the RVS to `RoomViewStore.instance`. - Wrap `MatrixChat`s `render()` function in a `StoresContext.Provider` so it can be used anywhere. `StoresContext` is currently only used in `RoomView` via the following changes: - Remove the HOC, which redundantly set `mxClient` as a prop. We don't need this as `RoomView` was using the client from `this.context`. - Change the type of context accepted from `MatrixClientContext` to `StoresContext`. - Modify alllll the places where `this.context` is used to interact with the client and suffix `.client`. - Modify places where we use `RoomViewStore.instance` and replace them with `this.context.roomViewStore`. This makes `RoomView` use a non-global instance of RVS. * Linting * SDKContext and make client an optional constructor arg * Move SDKContext to /src/contexts * Inject all RVS deps * Linting * Remove reset calls; deep copy the INITIAL_STATE to avoid test pollution * DI singletons used in RoomView; DI them in RoomView-test too * Initial RoomViewStore.instance after all files are imported to avoid cyclical deps * Lazily init stores to allow for circular dependencies Rather than stores accepting a list of other stores in their constructors, which doesn't work when A needs B and B needs A, make new-style stores simply accept Stores. When a store needs another store, they access it via `Stores` which then lazily constructs that store if it needs it. This breaks the circular dependency at constructor time, without needing to introduce wiring diagrams or any complex DI framework. * Delete RoomViewStore.instance Replaced with Stores.instance.roomViewStore * Linting * Move OverridableStores to test/TestStores * Rejig how eager stores get made; don't automatically do it else tests break * Linting * Linting and review comments * Fix new code to use Stores.instance * s/Stores/SdkContextClass/g * Update docs * Remove unused imports * Update src/stores/RoomViewStore.tsx Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * Remove empty c'tor to make sonar happy Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
84f2974b57
commit
e946674df3
36 changed files with 467 additions and 275 deletions
|
@ -44,21 +44,18 @@ import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
|||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||
import ContentMessages from '../../ContentMessages';
|
||||
import Modal from '../../Modal';
|
||||
import LegacyCallHandler, { LegacyCallHandlerEvent } from '../../LegacyCallHandler';
|
||||
import { LegacyCallHandlerEvent } from '../../LegacyCallHandler';
|
||||
import dis, { defaultDispatcher } from '../../dispatcher/dispatcher';
|
||||
import * as Rooms from '../../Rooms';
|
||||
import eventSearch, { searchPagination } from '../../Searching';
|
||||
import MainSplit from './MainSplit';
|
||||
import RightPanel from './RightPanel';
|
||||
import { RoomViewStore } from '../../stores/RoomViewStore';
|
||||
import RoomScrollStateStore, { ScrollState } from '../../stores/RoomScrollStateStore';
|
||||
import WidgetEchoStore from '../../stores/WidgetEchoStore';
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import MatrixClientContext, { MatrixClientProps, withMatrixClientHOC } from "../../contexts/MatrixClientContext";
|
||||
import { E2EStatus, shieldStatusForRoom } from '../../utils/ShieldUtils';
|
||||
import { Action } from "../../dispatcher/actions";
|
||||
import { IMatrixClientCreds } from "../../MatrixClientPeg";
|
||||
|
@ -76,12 +73,10 @@ import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
|||
import EffectsOverlay from "../views/elements/EffectsOverlay";
|
||||
import { containsEmoji } from '../../effects/utils';
|
||||
import { CHAT_EFFECTS } from '../../effects';
|
||||
import WidgetStore from "../../stores/WidgetStore";
|
||||
import { CallView } from "../views/voip/CallView";
|
||||
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||
import Notifier from "../../Notifier";
|
||||
import { showToast as showNotificationsToast } from "../../toasts/DesktopNotificationsToast";
|
||||
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
|
||||
import { Container, WidgetLayoutStore } from "../../stores/widgets/WidgetLayoutStore";
|
||||
import { getKeyBindingsManager } from '../../KeyBindingsManager';
|
||||
import { objectHasDiff } from "../../utils/objects";
|
||||
|
@ -120,6 +115,7 @@ import { RoomStatusBarUnsentMessages } from './RoomStatusBarUnsentMessages';
|
|||
import { LargeLoader } from './LargeLoader';
|
||||
import { VoiceBroadcastInfoEventType } from '../../voice-broadcast';
|
||||
import { isVideoRoom } from '../../utils/video-rooms';
|
||||
import { SDKContext } from '../../contexts/SDKContext';
|
||||
import { CallStore, CallStoreEvent } from "../../stores/CallStore";
|
||||
import { Call } from "../../models/Call";
|
||||
|
||||
|
@ -133,7 +129,7 @@ if (DEBUG) {
|
|||
debuglog = logger.log.bind(console);
|
||||
}
|
||||
|
||||
interface IRoomProps extends MatrixClientProps {
|
||||
interface IRoomProps {
|
||||
threepidInvite: IThreepidInvite;
|
||||
oobData?: IOOBData;
|
||||
|
||||
|
@ -381,13 +377,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
private messagePanel: TimelinePanel;
|
||||
private roomViewBody = createRef<HTMLDivElement>();
|
||||
|
||||
static contextType = MatrixClientContext;
|
||||
public context!: React.ContextType<typeof MatrixClientContext>;
|
||||
static contextType = SDKContext;
|
||||
public context!: React.ContextType<typeof SDKContext>;
|
||||
|
||||
constructor(props: IRoomProps, context: React.ContextType<typeof MatrixClientContext>) {
|
||||
constructor(props: IRoomProps, context: React.ContextType<typeof SDKContext>) {
|
||||
super(props, context);
|
||||
|
||||
const llMembers = context.hasLazyLoadMembersEnabled();
|
||||
const llMembers = context.client.hasLazyLoadMembersEnabled();
|
||||
this.state = {
|
||||
roomId: null,
|
||||
roomLoading: true,
|
||||
|
@ -422,7 +418,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
showJoinLeaves: true,
|
||||
showAvatarChanges: true,
|
||||
showDisplaynameChanges: true,
|
||||
matrixClientIsReady: context?.isInitialSyncComplete(),
|
||||
matrixClientIsReady: context.client?.isInitialSyncComplete(),
|
||||
mainSplitContentType: MainSplitContentType.Timeline,
|
||||
timelineRenderingType: TimelineRenderingType.Room,
|
||||
liveTimeline: undefined,
|
||||
|
@ -430,25 +426,25 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
};
|
||||
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
context.on(ClientEvent.Room, this.onRoom);
|
||||
context.on(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
context.on(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||
context.on(RoomEvent.Name, this.onRoomName);
|
||||
context.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
context.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
context.on(RoomEvent.MyMembership, this.onMyMembership);
|
||||
context.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||
context.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||
context.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
||||
context.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||
context.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||
context.client.on(ClientEvent.Room, this.onRoom);
|
||||
context.client.on(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
context.client.on(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||
context.client.on(RoomEvent.Name, this.onRoomName);
|
||||
context.client.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
context.client.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
context.client.on(RoomEvent.MyMembership, this.onMyMembership);
|
||||
context.client.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||
context.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||
context.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
||||
context.client.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||
context.client.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||
// Start listening for RoomViewStore updates
|
||||
RoomViewStore.instance.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
context.roomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
context.rightPanelStore.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
|
||||
WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||
WidgetStore.instance.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||
context.widgetStore.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||
|
||||
CallStore.instance.on(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
||||
|
||||
|
@ -501,16 +497,16 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
action: "appsDrawer",
|
||||
show: true,
|
||||
});
|
||||
if (WidgetLayoutStore.instance.hasMaximisedWidget(this.state.room)) {
|
||||
if (this.context.widgetLayoutStore.hasMaximisedWidget(this.state.room)) {
|
||||
// Show chat in right panel when a widget is maximised
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.Timeline });
|
||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline });
|
||||
}
|
||||
this.checkWidgets(this.state.room);
|
||||
};
|
||||
|
||||
private checkWidgets = (room: Room): void => {
|
||||
this.setState({
|
||||
hasPinnedWidgets: WidgetLayoutStore.instance.hasPinnedWidgets(room),
|
||||
hasPinnedWidgets: this.context.widgetLayoutStore.hasPinnedWidgets(room),
|
||||
mainSplitContentType: this.getMainSplitContentType(room),
|
||||
showApps: this.shouldShowApps(room),
|
||||
});
|
||||
|
@ -518,12 +514,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private getMainSplitContentType = (room: Room) => {
|
||||
if (
|
||||
(SettingsStore.getValue("feature_group_calls") && RoomViewStore.instance.isViewingCall())
|
||||
(SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall())
|
||||
|| isVideoRoom(room)
|
||||
) {
|
||||
return MainSplitContentType.Call;
|
||||
}
|
||||
if (WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
|
||||
if (this.context.widgetLayoutStore.hasMaximisedWidget(room)) {
|
||||
return MainSplitContentType.MaximisedWidget;
|
||||
}
|
||||
return MainSplitContentType.Timeline;
|
||||
|
@ -534,7 +530,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!initial && this.state.roomId !== RoomViewStore.instance.getRoomId()) {
|
||||
if (!initial && this.state.roomId !== this.context.roomViewStore.getRoomId()) {
|
||||
// RoomView explicitly does not support changing what room
|
||||
// is being viewed: instead it should just be re-mounted when
|
||||
// switching rooms. Therefore, if the room ID changes, we
|
||||
|
@ -549,45 +545,45 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const roomId = RoomViewStore.instance.getRoomId();
|
||||
const room = this.context.getRoom(roomId);
|
||||
const roomId = this.context.roomViewStore.getRoomId();
|
||||
const room = this.context.client.getRoom(roomId);
|
||||
|
||||
// This convoluted type signature ensures we get IntelliSense *and* correct typing
|
||||
const newState: Partial<IRoomState> & Pick<IRoomState, any> = {
|
||||
roomId,
|
||||
roomAlias: RoomViewStore.instance.getRoomAlias(),
|
||||
roomLoading: RoomViewStore.instance.isRoomLoading(),
|
||||
roomLoadError: RoomViewStore.instance.getRoomLoadError(),
|
||||
joining: RoomViewStore.instance.isJoining(),
|
||||
replyToEvent: RoomViewStore.instance.getQuotingEvent(),
|
||||
roomAlias: this.context.roomViewStore.getRoomAlias(),
|
||||
roomLoading: this.context.roomViewStore.isRoomLoading(),
|
||||
roomLoadError: this.context.roomViewStore.getRoomLoadError(),
|
||||
joining: this.context.roomViewStore.isJoining(),
|
||||
replyToEvent: this.context.roomViewStore.getQuotingEvent(),
|
||||
// we should only peek once we have a ready client
|
||||
shouldPeek: this.state.matrixClientIsReady && RoomViewStore.instance.shouldPeek(),
|
||||
shouldPeek: this.state.matrixClientIsReady && this.context.roomViewStore.shouldPeek(),
|
||||
showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId),
|
||||
showRedactions: SettingsStore.getValue("showRedactions", roomId),
|
||||
showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId),
|
||||
showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId),
|
||||
showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId),
|
||||
wasContextSwitch: RoomViewStore.instance.getWasContextSwitch(),
|
||||
wasContextSwitch: this.context.roomViewStore.getWasContextSwitch(),
|
||||
mainSplitContentType: room === null ? undefined : this.getMainSplitContentType(room),
|
||||
initialEventId: null, // default to clearing this, will get set later in the method if needed
|
||||
showRightPanel: RightPanelStore.instance.isOpenForRoom(roomId),
|
||||
showRightPanel: this.context.rightPanelStore.isOpenForRoom(roomId),
|
||||
activeCall: CallStore.instance.getActiveCall(roomId),
|
||||
};
|
||||
|
||||
if (
|
||||
this.state.mainSplitContentType !== MainSplitContentType.Timeline
|
||||
&& newState.mainSplitContentType === MainSplitContentType.Timeline
|
||||
&& RightPanelStore.instance.isOpen
|
||||
&& RightPanelStore.instance.currentCard.phase === RightPanelPhases.Timeline
|
||||
&& RightPanelStore.instance.roomPhaseHistory.some(card => (card.phase === RightPanelPhases.Timeline))
|
||||
&& this.context.rightPanelStore.isOpen
|
||||
&& this.context.rightPanelStore.currentCard.phase === RightPanelPhases.Timeline
|
||||
&& this.context.rightPanelStore.roomPhaseHistory.some(card => (card.phase === RightPanelPhases.Timeline))
|
||||
) {
|
||||
// We're returning to the main timeline, so hide the right panel timeline
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||
RightPanelStore.instance.togglePanel(this.state.roomId ?? null);
|
||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||
this.context.rightPanelStore.togglePanel(this.state.roomId ?? null);
|
||||
newState.showRightPanel = false;
|
||||
}
|
||||
|
||||
const initialEventId = RoomViewStore.instance.getInitialEventId();
|
||||
const initialEventId = this.context.roomViewStore.getInitialEventId();
|
||||
if (initialEventId) {
|
||||
let initialEvent = room?.findEventById(initialEventId);
|
||||
// The event does not exist in the current sync data
|
||||
|
@ -600,7 +596,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
// becomes available to fetch a whole thread
|
||||
if (!initialEvent) {
|
||||
initialEvent = await fetchInitialEvent(
|
||||
this.context,
|
||||
this.context.client,
|
||||
roomId,
|
||||
initialEventId,
|
||||
);
|
||||
|
@ -616,21 +612,21 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
action: Action.ShowThread,
|
||||
rootEvent: thread.rootEvent,
|
||||
initialEvent,
|
||||
highlighted: RoomViewStore.instance.isInitialEventHighlighted(),
|
||||
scroll_into_view: RoomViewStore.instance.initialEventScrollIntoView(),
|
||||
highlighted: this.context.roomViewStore.isInitialEventHighlighted(),
|
||||
scroll_into_view: this.context.roomViewStore.initialEventScrollIntoView(),
|
||||
});
|
||||
} else {
|
||||
newState.initialEventId = initialEventId;
|
||||
newState.isInitialEventHighlighted = RoomViewStore.instance.isInitialEventHighlighted();
|
||||
newState.initialEventScrollIntoView = RoomViewStore.instance.initialEventScrollIntoView();
|
||||
newState.isInitialEventHighlighted = this.context.roomViewStore.isInitialEventHighlighted();
|
||||
newState.initialEventScrollIntoView = this.context.roomViewStore.initialEventScrollIntoView();
|
||||
|
||||
if (thread && initialEvent?.isThreadRoot) {
|
||||
dis.dispatch<ShowThreadPayload>({
|
||||
action: Action.ShowThread,
|
||||
rootEvent: thread.rootEvent,
|
||||
initialEvent,
|
||||
highlighted: RoomViewStore.instance.isInitialEventHighlighted(),
|
||||
scroll_into_view: RoomViewStore.instance.initialEventScrollIntoView(),
|
||||
highlighted: this.context.roomViewStore.isInitialEventHighlighted(),
|
||||
scroll_into_view: this.context.roomViewStore.initialEventScrollIntoView(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -657,7 +653,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
if (!initial && this.state.shouldPeek && !newState.shouldPeek) {
|
||||
// Stop peeking because we have joined this room now
|
||||
this.context.stopPeeking();
|
||||
this.context.client.stopPeeking();
|
||||
}
|
||||
|
||||
// Temporary logging to diagnose https://github.com/vector-im/element-web/issues/4307
|
||||
|
@ -674,7 +670,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
// NB: This does assume that the roomID will not change for the lifetime of
|
||||
// the RoomView instance
|
||||
if (initial) {
|
||||
newState.room = this.context.getRoom(newState.roomId);
|
||||
newState.room = this.context.client.getRoom(newState.roomId);
|
||||
if (newState.room) {
|
||||
newState.showApps = this.shouldShowApps(newState.room);
|
||||
this.onRoomLoaded(newState.room);
|
||||
|
@ -784,7 +780,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
peekLoading: true,
|
||||
isPeeking: true, // this will change to false if peeking fails
|
||||
});
|
||||
this.context.peekInRoom(roomId).then((room) => {
|
||||
this.context.client.peekInRoom(roomId).then((room) => {
|
||||
if (this.unmounted) {
|
||||
return;
|
||||
}
|
||||
|
@ -817,7 +813,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
});
|
||||
} else if (room) {
|
||||
// Stop peeking because we have joined this room previously
|
||||
this.context.stopPeeking();
|
||||
this.context.client.stopPeeking();
|
||||
this.setState({ isPeeking: false });
|
||||
}
|
||||
}
|
||||
|
@ -835,7 +831,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
// Otherwise (in case the user set hideWidgetDrawer by clicking the button) follow the parameter.
|
||||
const isManuallyShown = hideWidgetDrawer ? hideWidgetDrawer === "false": true;
|
||||
|
||||
const widgets = WidgetLayoutStore.instance.getContainerWidgets(room, Container.Top);
|
||||
const widgets = this.context.widgetLayoutStore.getContainerWidgets(room, Container.Top);
|
||||
return isManuallyShown && widgets.length > 0;
|
||||
}
|
||||
|
||||
|
@ -848,7 +844,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
callState: callState,
|
||||
});
|
||||
|
||||
LegacyCallHandler.instance.on(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
this.context.legacyCallHandler.on(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
window.addEventListener('beforeunload', this.onPageUnload);
|
||||
}
|
||||
|
||||
|
@ -885,7 +881,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
// (We could use isMounted, but facebook have deprecated that.)
|
||||
this.unmounted = true;
|
||||
|
||||
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
this.context.legacyCallHandler.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
|
||||
// update the scroll map before we get unmounted
|
||||
if (this.state.roomId) {
|
||||
|
@ -893,47 +889,47 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
}
|
||||
|
||||
if (this.state.shouldPeek) {
|
||||
this.context.stopPeeking();
|
||||
this.context.client.stopPeeking();
|
||||
}
|
||||
|
||||
// stop tracking room changes to format permalinks
|
||||
this.stopAllPermalinkCreators();
|
||||
|
||||
dis.unregister(this.dispatcherRef);
|
||||
if (this.context) {
|
||||
this.context.removeListener(ClientEvent.Room, this.onRoom);
|
||||
this.context.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
this.context.removeListener(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||
this.context.removeListener(RoomEvent.Name, this.onRoomName);
|
||||
this.context.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
this.context.removeListener(RoomEvent.MyMembership, this.onMyMembership);
|
||||
this.context.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
this.context.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||
this.context.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||
this.context.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
||||
this.context.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||
this.context.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||
if (this.context.client) {
|
||||
this.context.client.removeListener(ClientEvent.Room, this.onRoom);
|
||||
this.context.client.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
this.context.client.removeListener(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||
this.context.client.removeListener(RoomEvent.Name, this.onRoomName);
|
||||
this.context.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
this.context.client.removeListener(RoomEvent.MyMembership, this.onMyMembership);
|
||||
this.context.client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||
this.context.client.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||
this.context.client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||
this.context.client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
||||
this.context.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||
this.context.client.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||
}
|
||||
|
||||
window.removeEventListener('beforeunload', this.onPageUnload);
|
||||
|
||||
RoomViewStore.instance.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
this.context.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
this.context.rightPanelStore.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
WidgetEchoStore.removeListener(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||
WidgetStore.instance.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||
this.context.widgetStore.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||
|
||||
this.props.resizeNotifier.off("isResizing", this.onIsResizing);
|
||||
|
||||
if (this.state.room) {
|
||||
WidgetLayoutStore.instance.off(
|
||||
this.context.widgetLayoutStore.off(
|
||||
WidgetLayoutStore.emissionForRoom(this.state.room),
|
||||
this.onWidgetLayoutChange,
|
||||
);
|
||||
}
|
||||
|
||||
CallStore.instance.off(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
||||
LegacyCallHandler.instance.off(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
this.context.legacyCallHandler.off(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||
|
||||
// cancel any pending calls to the throttled updated
|
||||
this.updateRoomMembers.cancel();
|
||||
|
@ -944,13 +940,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
if (this.viewsLocalRoom) {
|
||||
// clean up if this was a local room
|
||||
this.props.mxClient.store.removeRoom(this.state.room.roomId);
|
||||
this.context.client.store.removeRoom(this.state.room.roomId);
|
||||
}
|
||||
}
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
this.setState({
|
||||
showRightPanel: RightPanelStore.instance.isOpenForRoom(this.state.roomId),
|
||||
showRightPanel: this.context.rightPanelStore.isOpenForRoom(this.state.roomId),
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1017,7 +1013,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
break;
|
||||
case 'picture_snapshot':
|
||||
ContentMessages.sharedInstance().sendContentListToRoom(
|
||||
[payload.file], this.state.room.roomId, null, this.context);
|
||||
[payload.file], this.state.room.roomId, null, this.context.client);
|
||||
break;
|
||||
case 'notifier_enabled':
|
||||
case Action.UploadStarted:
|
||||
|
@ -1043,7 +1039,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
case 'MatrixActions.sync':
|
||||
if (!this.state.matrixClientIsReady) {
|
||||
this.setState({
|
||||
matrixClientIsReady: this.context?.isInitialSyncComplete(),
|
||||
matrixClientIsReady: this.context.client?.isInitialSyncComplete(),
|
||||
}, () => {
|
||||
// send another "initial" RVS update to trigger peeking if needed
|
||||
this.onRoomViewStoreUpdate(true);
|
||||
|
@ -1112,7 +1108,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private onLocalRoomEvent(roomId: string) {
|
||||
if (roomId !== this.state.room.roomId) return;
|
||||
createRoomFromLocalRoom(this.props.mxClient, this.state.room as LocalRoom);
|
||||
createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom);
|
||||
}
|
||||
|
||||
private onRoomTimeline = (ev: MatrixEvent, room: Room | null, toStartOfTimeline: boolean, removed, data) => {
|
||||
|
@ -1145,7 +1141,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
this.handleEffects(ev);
|
||||
}
|
||||
|
||||
if (ev.getSender() !== this.context.credentials.userId) {
|
||||
if (ev.getSender() !== this.context.client.credentials.userId) {
|
||||
// update unread count when scrolled up
|
||||
if (!this.state.searchResults && this.state.atEndOfLiveTimeline) {
|
||||
// no change
|
||||
|
@ -1165,7 +1161,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
};
|
||||
|
||||
private handleEffects = (ev: MatrixEvent) => {
|
||||
const notifState = RoomNotificationStateStore.instance.getRoomState(this.state.room);
|
||||
const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room);
|
||||
if (!notifState.isUnread) return;
|
||||
|
||||
CHAT_EFFECTS.forEach(effect => {
|
||||
|
@ -1202,7 +1198,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
private onRoomLoaded = (room: Room) => {
|
||||
if (this.unmounted) return;
|
||||
// Attach a widget store listener only when we get a room
|
||||
WidgetLayoutStore.instance.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
|
||||
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
|
||||
|
||||
this.calculatePeekRules(room);
|
||||
this.updatePreviewUrlVisibility(room);
|
||||
|
@ -1214,10 +1210,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
if (
|
||||
this.getMainSplitContentType(room) !== MainSplitContentType.Timeline
|
||||
&& RoomNotificationStateStore.instance.getRoomState(room).isUnread
|
||||
&& this.context.roomNotificationStateStore.getRoomState(room).isUnread
|
||||
) {
|
||||
// Automatically open the chat panel to make unread messages easier to discover
|
||||
RightPanelStore.instance.setCard({ phase: RightPanelPhases.Timeline }, true, room.roomId);
|
||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline }, true, room.roomId);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
|
@ -1244,7 +1240,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private async loadMembersIfJoined(room: Room) {
|
||||
// lazy load members if enabled
|
||||
if (this.context.hasLazyLoadMembersEnabled()) {
|
||||
if (this.context.client.hasLazyLoadMembersEnabled()) {
|
||||
if (room && room.getMyMembership() === 'join') {
|
||||
try {
|
||||
await room.loadMembersIfNeeded();
|
||||
|
@ -1270,7 +1266,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private updatePreviewUrlVisibility({ roomId }: Room) {
|
||||
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
|
||||
const key = this.context.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled';
|
||||
const key = this.context.client.isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled';
|
||||
this.setState({
|
||||
showUrlPreview: SettingsStore.getValue(key, roomId),
|
||||
});
|
||||
|
@ -1283,7 +1279,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
// Detach the listener if the room is changing for some reason
|
||||
if (this.state.room) {
|
||||
WidgetLayoutStore.instance.off(
|
||||
this.context.widgetLayoutStore.off(
|
||||
WidgetLayoutStore.emissionForRoom(this.state.room),
|
||||
this.onWidgetLayoutChange,
|
||||
);
|
||||
|
@ -1320,15 +1316,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
};
|
||||
|
||||
private async updateE2EStatus(room: Room) {
|
||||
if (!this.context.isRoomEncrypted(room.roomId)) return;
|
||||
if (!this.context.client.isRoomEncrypted(room.roomId)) return;
|
||||
|
||||
// If crypto is not currently enabled, we aren't tracking devices at all,
|
||||
// so we don't know what the answer is. Let's error on the safe side and show
|
||||
// a warning for this case.
|
||||
let e2eStatus = E2EStatus.Warning;
|
||||
if (this.context.isCryptoEnabled()) {
|
||||
if (this.context.client.isCryptoEnabled()) {
|
||||
/* At this point, the user has encryption on and cross-signing on */
|
||||
e2eStatus = await shieldStatusForRoom(this.context, room);
|
||||
e2eStatus = await shieldStatusForRoom(this.context.client, room);
|
||||
}
|
||||
|
||||
if (this.unmounted) return;
|
||||
|
@ -1374,7 +1370,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private updatePermissions(room: Room) {
|
||||
if (room) {
|
||||
const me = this.context.getUserId();
|
||||
const me = this.context.client.getUserId();
|
||||
const canReact = (
|
||||
room.getMyMembership() === "join" &&
|
||||
room.currentState.maySendEvent(EventType.Reaction, me)
|
||||
|
@ -1442,7 +1438,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
private onJoinButtonClicked = () => {
|
||||
// If the user is a ROU, allow them to transition to a PWLU
|
||||
if (this.context?.isGuest()) {
|
||||
if (this.context.client?.isGuest()) {
|
||||
// Join this room once the user has registered and logged in
|
||||
// (If we failed to peek, we may not have a valid room object.)
|
||||
dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
|
||||
|
@ -1499,13 +1495,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
};
|
||||
|
||||
private injectSticker(url: string, info: object, text: string, threadId: string | null) {
|
||||
if (this.context.isGuest()) {
|
||||
if (this.context.client.isGuest()) {
|
||||
dis.dispatch({ action: 'require_registration' });
|
||||
return;
|
||||
}
|
||||
|
||||
ContentMessages.sharedInstance()
|
||||
.sendStickerContentToRoom(url, this.state.room.roomId, threadId, info, text, this.context)
|
||||
.sendStickerContentToRoom(url, this.state.room.roomId, threadId, info, text, this.context.client)
|
||||
.then(undefined, (error) => {
|
||||
if (error.name === "UnknownDeviceError") {
|
||||
// Let the staus bar handle this
|
||||
|
@ -1578,7 +1574,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
return b.length - a.length;
|
||||
});
|
||||
|
||||
if (this.context.supportsExperimentalThreads()) {
|
||||
if (this.context.client.supportsExperimentalThreads()) {
|
||||
// Process all thread roots returned in this batch of search results
|
||||
// XXX: This won't work for results coming from Seshat which won't include the bundled relationship
|
||||
for (const result of results.results) {
|
||||
|
@ -1586,7 +1582,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
const bundledRelationship = event
|
||||
.getServerAggregatedRelation<IThreadBundledRelationship>(THREAD_RELATION_TYPE.name);
|
||||
if (!bundledRelationship || event.getThread()) continue;
|
||||
const room = this.context.getRoom(event.getRoomId());
|
||||
const room = this.context.client.getRoom(event.getRoomId());
|
||||
const thread = room.findThreadForEvent(event);
|
||||
if (thread) {
|
||||
event.setThread(thread);
|
||||
|
@ -1658,7 +1654,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
|
||||
const mxEv = result.context.getEvent();
|
||||
const roomId = mxEv.getRoomId();
|
||||
const room = this.context.getRoom(roomId);
|
||||
const room = this.context.client.getRoom(roomId);
|
||||
if (!room) {
|
||||
// if we do not have the room in js-sdk stores then hide it as we cannot easily show it
|
||||
// As per the spec, an all rooms search can create this condition,
|
||||
|
@ -1715,7 +1711,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
this.setState({
|
||||
rejecting: true,
|
||||
});
|
||||
this.context.leave(this.state.roomId).then(() => {
|
||||
this.context.client.leave(this.state.roomId).then(() => {
|
||||
dis.dispatch({ action: Action.ViewHomePage });
|
||||
this.setState({
|
||||
rejecting: false,
|
||||
|
@ -1742,13 +1738,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
});
|
||||
|
||||
try {
|
||||
const myMember = this.state.room.getMember(this.context.getUserId());
|
||||
const myMember = this.state.room.getMember(this.context.client.getUserId());
|
||||
const inviteEvent = myMember.events.member;
|
||||
const ignoredUsers = this.context.getIgnoredUsers();
|
||||
const ignoredUsers = this.context.client.getIgnoredUsers();
|
||||
ignoredUsers.push(inviteEvent.getSender()); // de-duped internally in the js-sdk
|
||||
await this.context.setIgnoredUsers(ignoredUsers);
|
||||
await this.context.client.setIgnoredUsers(ignoredUsers);
|
||||
|
||||
await this.context.leave(this.state.roomId);
|
||||
await this.context.client.leave(this.state.roomId);
|
||||
dis.dispatch({ action: Action.ViewHomePage });
|
||||
this.setState({
|
||||
rejecting: false,
|
||||
|
@ -1911,7 +1907,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
if (!this.state.room) {
|
||||
return null;
|
||||
}
|
||||
return LegacyCallHandler.instance.getCallForRoom(this.state.room.roomId);
|
||||
return this.context.legacyCallHandler.getCallForRoom(this.state.room.roomId);
|
||||
}
|
||||
|
||||
// this has to be a proper method rather than an unnamed function,
|
||||
|
@ -1924,7 +1920,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
const createEvent = this.state.room.currentState.getStateEvents(EventType.RoomCreate, "");
|
||||
if (!createEvent || !createEvent.getContent()['predecessor']) return null;
|
||||
|
||||
return this.context.getRoom(createEvent.getContent()['predecessor']['room_id']);
|
||||
return this.context.client.getRoom(createEvent.getContent()['predecessor']['room_id']);
|
||||
}
|
||||
|
||||
getHiddenHighlightCount() {
|
||||
|
@ -1953,7 +1949,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
Array.from(dataTransfer.files),
|
||||
this.state.room?.roomId ?? this.state.roomId,
|
||||
null,
|
||||
this.context,
|
||||
this.context.client,
|
||||
TimelineRenderingType.Room,
|
||||
);
|
||||
|
||||
|
@ -1970,7 +1966,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
}
|
||||
|
||||
private renderLocalRoomCreateLoader(): ReactElement {
|
||||
const names = this.state.room.getDefaultRoomName(this.props.mxClient.getUserId());
|
||||
const names = this.state.room.getDefaultRoomName(this.context.client.getUserId());
|
||||
return <RoomContext.Provider value={this.state}>
|
||||
<LocalRoomCreateLoader
|
||||
names={names}
|
||||
|
@ -2081,7 +2077,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
</ErrorBoundary>
|
||||
);
|
||||
} else {
|
||||
const myUserId = this.context.credentials.userId;
|
||||
const myUserId = this.context.client.credentials.userId;
|
||||
const myMember = this.state.room.getMember(myUserId);
|
||||
const inviteEvent = myMember ? myMember.events.member : null;
|
||||
let inviterName = _t("Unknown");
|
||||
|
@ -2162,7 +2158,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
const showRoomUpgradeBar = (
|
||||
roomVersionRecommendation &&
|
||||
roomVersionRecommendation.needsUpgrade &&
|
||||
this.state.room.userMayUpgradeRoom(this.context.credentials.userId)
|
||||
this.state.room.userMayUpgradeRoom(this.context.client.credentials.userId)
|
||||
);
|
||||
|
||||
const hiddenHighlightCount = this.getHiddenHighlightCount();
|
||||
|
@ -2174,7 +2170,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
searchInProgress={this.state.searchInProgress}
|
||||
onCancelClick={this.onCancelSearchClick}
|
||||
onSearch={this.onSearch}
|
||||
isRoomEncrypted={this.context.isRoomEncrypted(this.state.room.roomId)}
|
||||
isRoomEncrypted={this.context.client.isRoomEncrypted(this.state.room.roomId)}
|
||||
/>;
|
||||
} else if (showRoomUpgradeBar) {
|
||||
aux = <RoomUpgradeWarningBar room={this.state.room} />;
|
||||
|
@ -2236,7 +2232,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
const auxPanel = (
|
||||
<AuxPanel
|
||||
room={this.state.room}
|
||||
userId={this.context.credentials.userId}
|
||||
userId={this.context.client.credentials.userId}
|
||||
showApps={this.state.showApps}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
>
|
||||
|
@ -2397,7 +2393,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
mainSplitBody = <>
|
||||
<AppsDrawer
|
||||
room={this.state.room}
|
||||
userId={this.context.credentials.userId}
|
||||
userId={this.context.client.credentials.userId}
|
||||
resizeNotifier={this.props.resizeNotifier}
|
||||
showApps={true}
|
||||
/>
|
||||
|
@ -2451,7 +2447,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
onAppsClick = null;
|
||||
onForgetClick = null;
|
||||
onSearchClick = null;
|
||||
if (this.state.room.canInvite(this.context.credentials.userId)) {
|
||||
if (this.state.room.canInvite(this.context.client.credentials.userId)) {
|
||||
onInviteClick = this.onInviteClick;
|
||||
}
|
||||
viewingCall = true;
|
||||
|
@ -2493,5 +2489,4 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||
}
|
||||
}
|
||||
|
||||
const RoomViewWithMatrixClient = withMatrixClientHOC(RoomView);
|
||||
export default RoomViewWithMatrixClient;
|
||||
export default RoomView;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue