You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-08-09 08:42:50 +03:00
Remove legacy consumers of the SDKContext in favour of HOCs
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
@@ -58,7 +58,6 @@ import AudioFeedArrayForLegacyCall from "../views/voip/AudioFeedArrayForLegacyCa
|
|||||||
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
||||||
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import RoomView from "./RoomView";
|
import RoomView from "./RoomView";
|
||||||
import type { RoomView as RoomViewType } from "./RoomView";
|
|
||||||
import ToastContainer from "./ToastContainer";
|
import ToastContainer from "./ToastContainer";
|
||||||
import UserView from "./UserView";
|
import UserView from "./UserView";
|
||||||
import BackdropPanel from "./BackdropPanel";
|
import BackdropPanel from "./BackdropPanel";
|
||||||
@@ -132,7 +131,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||||||
public static displayName = "LoggedInView";
|
public static displayName = "LoggedInView";
|
||||||
|
|
||||||
protected readonly _matrixClient: MatrixClient;
|
protected readonly _matrixClient: MatrixClient;
|
||||||
protected readonly _roomView: React.RefObject<RoomViewType>;
|
protected readonly _roomView: React.RefObject<React.ComponentRef<typeof RoomView>>;
|
||||||
protected readonly _resizeContainer: React.RefObject<HTMLDivElement>;
|
protected readonly _resizeContainer: React.RefObject<HTMLDivElement>;
|
||||||
protected readonly resizeHandler: React.RefObject<HTMLDivElement>;
|
protected readonly resizeHandler: React.RefObject<HTMLDivElement>;
|
||||||
protected layoutWatcherRef?: string;
|
protected layoutWatcherRef?: string;
|
||||||
|
@@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createRef, ReactElement, ReactNode, RefObject, useContext } from "react";
|
import React, { createRef, forwardRef, ReactElement, ReactNode, RefObject, useContext } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import {
|
import {
|
||||||
IRecommendedVersion,
|
IRecommendedVersion,
|
||||||
@@ -157,6 +157,7 @@ interface IRoomProps {
|
|||||||
|
|
||||||
// Called with the credentials of a registered user (if they were a ROU that transitioned to PWLU)
|
// Called with the credentials of a registered user (if they were a ROU that transitioned to PWLU)
|
||||||
onRegistered?(credentials: IMatrixClientCreds): void;
|
onRegistered?(credentials: IMatrixClientCreds): void;
|
||||||
|
context: React.ContextType<typeof SDKContext>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This defines the content of the mainSplit.
|
// This defines the content of the mainSplit.
|
||||||
@@ -399,7 +400,7 @@ function LocalRoomCreateLoader(props: ILocalRoomCreateLoaderProps): ReactElement
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
private readonly askToJoinEnabled: boolean;
|
private readonly askToJoinEnabled: boolean;
|
||||||
private readonly dispatcherRef: string;
|
private readonly dispatcherRef: string;
|
||||||
private settingWatchers: string[];
|
private settingWatchers: string[];
|
||||||
@@ -412,19 +413,16 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
private messagePanel: TimelinePanel | null = null;
|
private messagePanel: TimelinePanel | null = null;
|
||||||
private roomViewBody = createRef<HTMLDivElement>();
|
private roomViewBody = createRef<HTMLDivElement>();
|
||||||
|
|
||||||
public static contextType = SDKContext;
|
public constructor(props: IRoomProps) {
|
||||||
public context!: React.ContextType<typeof SDKContext>;
|
super(props);
|
||||||
|
|
||||||
public constructor(props: IRoomProps, context: React.ContextType<typeof SDKContext>) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.askToJoinEnabled = SettingsStore.getValue("feature_ask_to_join");
|
this.askToJoinEnabled = SettingsStore.getValue("feature_ask_to_join");
|
||||||
|
|
||||||
if (!context.client) {
|
if (!props.context.client) {
|
||||||
throw new Error("Unable to create RoomView without MatrixClient");
|
throw new Error("Unable to create RoomView without MatrixClient");
|
||||||
}
|
}
|
||||||
|
|
||||||
const llMembers = context.client.hasLazyLoadMembersEnabled();
|
const llMembers = props.context.client.hasLazyLoadMembersEnabled();
|
||||||
this.state = {
|
this.state = {
|
||||||
roomId: undefined,
|
roomId: undefined,
|
||||||
roomLoading: true,
|
roomLoading: true,
|
||||||
@@ -458,7 +456,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
showJoinLeaves: true,
|
showJoinLeaves: true,
|
||||||
showAvatarChanges: true,
|
showAvatarChanges: true,
|
||||||
showDisplaynameChanges: true,
|
showDisplaynameChanges: true,
|
||||||
matrixClientIsReady: context.client?.isInitialSyncComplete(),
|
matrixClientIsReady: props.context.client?.isInitialSyncComplete(),
|
||||||
mainSplitContentType: MainSplitContentType.Timeline,
|
mainSplitContentType: MainSplitContentType.Timeline,
|
||||||
timelineRenderingType: TimelineRenderingType.Room,
|
timelineRenderingType: TimelineRenderingType.Room,
|
||||||
liveTimeline: undefined,
|
liveTimeline: undefined,
|
||||||
@@ -470,25 +468,25 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
context.client.on(ClientEvent.Room, this.onRoom);
|
props.context.client.on(ClientEvent.Room, this.onRoom);
|
||||||
context.client.on(RoomEvent.Timeline, this.onRoomTimeline);
|
props.context.client.on(RoomEvent.Timeline, this.onRoomTimeline);
|
||||||
context.client.on(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
props.context.client.on(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||||
context.client.on(RoomEvent.Name, this.onRoomName);
|
props.context.client.on(RoomEvent.Name, this.onRoomName);
|
||||||
context.client.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
props.context.client.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||||
context.client.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
props.context.client.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||||
context.client.on(RoomEvent.MyMembership, this.onMyMembership);
|
props.context.client.on(RoomEvent.MyMembership, this.onMyMembership);
|
||||||
context.client.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
props.context.client.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||||
context.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
props.context.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||||
context.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
props.context.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
||||||
context.client.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
props.context.client.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||||
context.client.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
props.context.client.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||||
// Start listening for RoomViewStore updates
|
// Start listening for RoomViewStore updates
|
||||||
context.roomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
props.context.roomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||||
|
|
||||||
context.rightPanelStore.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
props.context.rightPanelStore.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
|
|
||||||
WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||||
context.widgetStore.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
props.context.widgetStore.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||||
|
|
||||||
CallStore.instance.on(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
CallStore.instance.on(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
||||||
|
|
||||||
@@ -545,9 +543,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
action: "appsDrawer",
|
action: "appsDrawer",
|
||||||
show: true,
|
show: true,
|
||||||
});
|
});
|
||||||
if (this.context.widgetLayoutStore.hasMaximisedWidget(this.state.room)) {
|
if (this.props.context.widgetLayoutStore.hasMaximisedWidget(this.state.room)) {
|
||||||
// Show chat in right panel when a widget is maximised
|
// Show chat in right panel when a widget is maximised
|
||||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline });
|
this.props.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline });
|
||||||
}
|
}
|
||||||
this.checkWidgets(this.state.room);
|
this.checkWidgets(this.state.room);
|
||||||
};
|
};
|
||||||
@@ -559,15 +557,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
* This solves the issue if some people decide to start a conference and click the call button at the same time.
|
* This solves the issue if some people decide to start a conference and click the call button at the same time.
|
||||||
*/
|
*/
|
||||||
private doMaybeRemoveOwnJitsiWidget(): void {
|
private doMaybeRemoveOwnJitsiWidget(): void {
|
||||||
if (!this.state.roomId || !this.state.room || !this.context.client) return;
|
if (!this.state.roomId || !this.state.room || !this.props.context.client) return;
|
||||||
|
|
||||||
const apps = this.context.widgetStore.getApps(this.state.roomId);
|
const apps = this.props.context.widgetStore.getApps(this.state.roomId);
|
||||||
const jitsiApps = apps.filter((app) => app.eventId && WidgetType.JITSI.matches(app.type));
|
const jitsiApps = apps.filter((app) => app.eventId && WidgetType.JITSI.matches(app.type));
|
||||||
|
|
||||||
// less than two Jitsi widgets → nothing to do
|
// less than two Jitsi widgets → nothing to do
|
||||||
if (jitsiApps.length < 2) return;
|
if (jitsiApps.length < 2) return;
|
||||||
|
|
||||||
const currentUserId = this.context.client.getSafeUserId();
|
const currentUserId = this.props.context.client.getSafeUserId();
|
||||||
const createdByCurrentUser = jitsiApps.find((apps) => apps.creatorUserId === currentUserId);
|
const createdByCurrentUser = jitsiApps.find((apps) => apps.creatorUserId === currentUserId);
|
||||||
|
|
||||||
// no Jitsi widget from current user → nothing to do
|
// no Jitsi widget from current user → nothing to do
|
||||||
@@ -598,13 +596,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
createdByCurrentUserTs - lastCreatedByOtherTs < PREVENT_MULTIPLE_JITSI_WITHIN
|
createdByCurrentUserTs - lastCreatedByOtherTs < PREVENT_MULTIPLE_JITSI_WITHIN
|
||||||
) {
|
) {
|
||||||
// more than one Jitsi widget with the last one from the current user → remove it
|
// more than one Jitsi widget with the last one from the current user → remove it
|
||||||
WidgetUtils.setRoomWidget(this.context.client, this.state.roomId, createdByCurrentUser.id);
|
WidgetUtils.setRoomWidget(this.props.context.client, this.state.roomId, createdByCurrentUser.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkWidgets = (room: Room): void => {
|
private checkWidgets = (room: Room): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
hasPinnedWidgets: this.context.widgetLayoutStore.hasPinnedWidgets(room),
|
hasPinnedWidgets: this.props.context.widgetLayoutStore.hasPinnedWidgets(room),
|
||||||
mainSplitContentType: this.getMainSplitContentType(room),
|
mainSplitContentType: this.getMainSplitContentType(room),
|
||||||
showApps: this.shouldShowApps(room),
|
showApps: this.shouldShowApps(room),
|
||||||
});
|
});
|
||||||
@@ -612,12 +610,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private getMainSplitContentType = (room: Room): MainSplitContentType => {
|
private getMainSplitContentType = (room: Room): MainSplitContentType => {
|
||||||
if (
|
if (
|
||||||
(SettingsStore.getValue("feature_group_calls") && this.context.roomViewStore.isViewingCall()) ||
|
(SettingsStore.getValue("feature_group_calls") && this.props.context.roomViewStore.isViewingCall()) ||
|
||||||
isVideoRoom(room)
|
isVideoRoom(room)
|
||||||
) {
|
) {
|
||||||
return MainSplitContentType.Call;
|
return MainSplitContentType.Call;
|
||||||
}
|
}
|
||||||
if (this.context.widgetLayoutStore.hasMaximisedWidget(room)) {
|
if (this.props.context.widgetLayoutStore.hasMaximisedWidget(room)) {
|
||||||
return MainSplitContentType.MaximisedWidget;
|
return MainSplitContentType.MaximisedWidget;
|
||||||
}
|
}
|
||||||
return MainSplitContentType.Timeline;
|
return MainSplitContentType.Timeline;
|
||||||
@@ -628,8 +626,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomLoadError = this.context.roomViewStore.getRoomLoadError() ?? undefined;
|
const roomLoadError = this.props.context.roomViewStore.getRoomLoadError() ?? undefined;
|
||||||
if (!initial && !roomLoadError && this.state.roomId !== this.context.roomViewStore.getRoomId()) {
|
if (!initial && !roomLoadError && this.state.roomId !== this.props.context.roomViewStore.getRoomId()) {
|
||||||
// RoomView explicitly does not support changing what room
|
// RoomView explicitly does not support changing what room
|
||||||
// is being viewed: instead it should just be re-mounted when
|
// is being viewed: instead it should just be re-mounted when
|
||||||
// switching rooms. Therefore, if the room ID changes, we
|
// switching rooms. Therefore, if the room ID changes, we
|
||||||
@@ -644,51 +642,51 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const roomId = this.context.roomViewStore.getRoomId() ?? null;
|
const roomId = this.props.context.roomViewStore.getRoomId() ?? null;
|
||||||
const room = this.context.client?.getRoom(roomId ?? undefined) ?? undefined;
|
const room = this.props.context.client?.getRoom(roomId ?? undefined) ?? undefined;
|
||||||
|
|
||||||
const newState: Partial<IRoomState> = {
|
const newState: Partial<IRoomState> = {
|
||||||
roomId: roomId ?? undefined,
|
roomId: roomId ?? undefined,
|
||||||
roomAlias: this.context.roomViewStore.getRoomAlias() ?? undefined,
|
roomAlias: this.props.context.roomViewStore.getRoomAlias() ?? undefined,
|
||||||
roomLoading: this.context.roomViewStore.isRoomLoading(),
|
roomLoading: this.props.context.roomViewStore.isRoomLoading(),
|
||||||
roomLoadError,
|
roomLoadError,
|
||||||
joining: this.context.roomViewStore.isJoining(),
|
joining: this.props.context.roomViewStore.isJoining(),
|
||||||
replyToEvent: this.context.roomViewStore.getQuotingEvent() ?? undefined,
|
replyToEvent: this.props.context.roomViewStore.getQuotingEvent() ?? undefined,
|
||||||
// we should only peek once we have a ready client
|
// we should only peek once we have a ready client
|
||||||
shouldPeek: this.state.matrixClientIsReady && this.context.roomViewStore.shouldPeek(),
|
shouldPeek: this.state.matrixClientIsReady && this.props.context.roomViewStore.shouldPeek(),
|
||||||
showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId),
|
showReadReceipts: SettingsStore.getValue("showReadReceipts", roomId),
|
||||||
showRedactions: SettingsStore.getValue("showRedactions", roomId),
|
showRedactions: SettingsStore.getValue("showRedactions", roomId),
|
||||||
showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId),
|
showJoinLeaves: SettingsStore.getValue("showJoinLeaves", roomId),
|
||||||
showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId),
|
showAvatarChanges: SettingsStore.getValue("showAvatarChanges", roomId),
|
||||||
showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId),
|
showDisplaynameChanges: SettingsStore.getValue("showDisplaynameChanges", roomId),
|
||||||
wasContextSwitch: this.context.roomViewStore.getWasContextSwitch(),
|
wasContextSwitch: this.props.context.roomViewStore.getWasContextSwitch(),
|
||||||
mainSplitContentType: room ? this.getMainSplitContentType(room) : undefined,
|
mainSplitContentType: room ? this.getMainSplitContentType(room) : undefined,
|
||||||
initialEventId: undefined, // default to clearing this, will get set later in the method if needed
|
initialEventId: undefined, // default to clearing this, will get set later in the method if needed
|
||||||
showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false,
|
showRightPanel: roomId ? this.props.context.rightPanelStore.isOpenForRoom(roomId) : false,
|
||||||
threadRightPanel: roomId
|
threadRightPanel: roomId
|
||||||
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
|
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
|
||||||
this.context.rightPanelStore.currentCardForRoom(roomId).phase!,
|
this.props.context.rightPanelStore.currentCardForRoom(roomId).phase!,
|
||||||
)
|
)
|
||||||
: false,
|
: false,
|
||||||
activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null,
|
activeCall: roomId ? CallStore.instance.getActiveCall(roomId) : null,
|
||||||
promptAskToJoin: this.context.roomViewStore.promptAskToJoin(),
|
promptAskToJoin: this.props.context.roomViewStore.promptAskToJoin(),
|
||||||
viewRoomOpts: this.context.roomViewStore.getViewRoomOpts(),
|
viewRoomOpts: this.props.context.roomViewStore.getViewRoomOpts(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.state.mainSplitContentType !== MainSplitContentType.Timeline &&
|
this.state.mainSplitContentType !== MainSplitContentType.Timeline &&
|
||||||
newState.mainSplitContentType === MainSplitContentType.Timeline &&
|
newState.mainSplitContentType === MainSplitContentType.Timeline &&
|
||||||
this.context.rightPanelStore.isOpen &&
|
this.props.context.rightPanelStore.isOpen &&
|
||||||
this.context.rightPanelStore.currentCard.phase === RightPanelPhases.Timeline &&
|
this.props.context.rightPanelStore.currentCard.phase === RightPanelPhases.Timeline &&
|
||||||
this.context.rightPanelStore.roomPhaseHistory.some((card) => card.phase === RightPanelPhases.Timeline)
|
this.props.context.rightPanelStore.roomPhaseHistory.some((card) => card.phase === RightPanelPhases.Timeline)
|
||||||
) {
|
) {
|
||||||
// We're returning to the main timeline, so hide the right panel timeline
|
// We're returning to the main timeline, so hide the right panel timeline
|
||||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.RoomSummary });
|
this.props.context.rightPanelStore.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||||
this.context.rightPanelStore.togglePanel(this.state.roomId ?? null);
|
this.props.context.rightPanelStore.togglePanel(this.state.roomId ?? null);
|
||||||
newState.showRightPanel = false;
|
newState.showRightPanel = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialEventId = this.context.roomViewStore.getInitialEventId() ?? this.state.initialEventId;
|
const initialEventId = this.props.context.roomViewStore.getInitialEventId() ?? this.state.initialEventId;
|
||||||
if (initialEventId) {
|
if (initialEventId) {
|
||||||
let initialEvent = room?.findEventById(initialEventId);
|
let initialEvent = room?.findEventById(initialEventId);
|
||||||
// The event does not exist in the current sync data
|
// The event does not exist in the current sync data
|
||||||
@@ -699,8 +697,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
// and the root event.
|
// and the root event.
|
||||||
// The rest will be lost for now, until the aggregation API on the server
|
// The rest will be lost for now, until the aggregation API on the server
|
||||||
// becomes available to fetch a whole thread
|
// becomes available to fetch a whole thread
|
||||||
if (!initialEvent && this.context.client && roomId) {
|
if (!initialEvent && this.props.context.client && roomId) {
|
||||||
initialEvent = (await fetchInitialEvent(this.context.client, roomId, initialEventId)) ?? undefined;
|
initialEvent =
|
||||||
|
(await fetchInitialEvent(this.props.context.client, roomId, initialEventId)) ?? undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have an initial event, we want to reset the event pixel offset to ensure it ends up visible
|
// If we have an initial event, we want to reset the event pixel offset to ensure it ends up visible
|
||||||
@@ -714,13 +713,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
action: Action.ShowThread,
|
action: Action.ShowThread,
|
||||||
rootEvent: thread.rootEvent,
|
rootEvent: thread.rootEvent,
|
||||||
initialEvent,
|
initialEvent,
|
||||||
highlighted: this.context.roomViewStore.isInitialEventHighlighted(),
|
highlighted: this.props.context.roomViewStore.isInitialEventHighlighted(),
|
||||||
scroll_into_view: this.context.roomViewStore.initialEventScrollIntoView(),
|
scroll_into_view: this.props.context.roomViewStore.initialEventScrollIntoView(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
newState.initialEventId = initialEventId;
|
newState.initialEventId = initialEventId;
|
||||||
newState.isInitialEventHighlighted = this.context.roomViewStore.isInitialEventHighlighted();
|
newState.isInitialEventHighlighted = this.props.context.roomViewStore.isInitialEventHighlighted();
|
||||||
newState.initialEventScrollIntoView = this.context.roomViewStore.initialEventScrollIntoView();
|
newState.initialEventScrollIntoView = this.props.context.roomViewStore.initialEventScrollIntoView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,7 +744,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
if (!initial && this.state.shouldPeek && !newState.shouldPeek) {
|
if (!initial && this.state.shouldPeek && !newState.shouldPeek) {
|
||||||
// Stop peeking because we have joined this room now
|
// Stop peeking because we have joined this room now
|
||||||
this.context.client?.stopPeeking();
|
this.props.context.client?.stopPeeking();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary logging to diagnose https://github.com/vector-im/element-web/issues/4307
|
// Temporary logging to diagnose https://github.com/vector-im/element-web/issues/4307
|
||||||
@@ -766,7 +765,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
// NB: This does assume that the roomID will not change for the lifetime of
|
// NB: This does assume that the roomID will not change for the lifetime of
|
||||||
// the RoomView instance
|
// the RoomView instance
|
||||||
if (initial) {
|
if (initial) {
|
||||||
newState.room = this.context.client!.getRoom(newState.roomId) || undefined;
|
newState.room = this.props.context.client!.getRoom(newState.roomId) || undefined;
|
||||||
if (newState.room) {
|
if (newState.room) {
|
||||||
newState.showApps = this.shouldShowApps(newState.room);
|
newState.showApps = this.shouldShowApps(newState.room);
|
||||||
this.onRoomLoaded(newState.room);
|
this.onRoomLoaded(newState.room);
|
||||||
@@ -897,7 +896,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
peekLoading: true,
|
peekLoading: true,
|
||||||
isPeeking: true, // this will change to false if peeking fails
|
isPeeking: true, // this will change to false if peeking fails
|
||||||
});
|
});
|
||||||
this.context.client
|
this.props.context.client
|
||||||
?.peekInRoom(roomId)
|
?.peekInRoom(roomId)
|
||||||
.then((room) => {
|
.then((room) => {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
@@ -934,7 +933,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
});
|
});
|
||||||
} else if (room) {
|
} else if (room) {
|
||||||
// Stop peeking because we have joined this room previously
|
// Stop peeking because we have joined this room previously
|
||||||
this.context.client?.stopPeeking();
|
this.props.context.client?.stopPeeking();
|
||||||
this.setState({
|
this.setState({
|
||||||
isPeeking: false,
|
isPeeking: false,
|
||||||
canAskToJoin: this.askToJoinEnabled && room.getJoinRule() === JoinRule.Knock,
|
canAskToJoin: this.askToJoinEnabled && room.getJoinRule() === JoinRule.Knock,
|
||||||
@@ -955,7 +954,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
// Otherwise (in case the user set hideWidgetDrawer by clicking the button) follow the parameter.
|
// Otherwise (in case the user set hideWidgetDrawer by clicking the button) follow the parameter.
|
||||||
const isManuallyShown = hideWidgetDrawer ? hideWidgetDrawer === "false" : true;
|
const isManuallyShown = hideWidgetDrawer ? hideWidgetDrawer === "false" : true;
|
||||||
|
|
||||||
const widgets = this.context.widgetLayoutStore.getContainerWidgets(room, Container.Top);
|
const widgets = this.props.context.widgetLayoutStore.getContainerWidgets(room, Container.Top);
|
||||||
return isManuallyShown && widgets.length > 0;
|
return isManuallyShown && widgets.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,7 +967,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
callState,
|
callState,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.context.legacyCallHandler.on(LegacyCallHandlerEvent.CallState, this.onCallState);
|
this.props.context.legacyCallHandler.on(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||||
window.addEventListener("beforeunload", this.onPageUnload);
|
window.addEventListener("beforeunload", this.onPageUnload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,7 +1004,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
// (We could use isMounted, but facebook have deprecated that.)
|
// (We could use isMounted, but facebook have deprecated that.)
|
||||||
this.unmounted = true;
|
this.unmounted = true;
|
||||||
|
|
||||||
this.context.legacyCallHandler.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
this.props.context.legacyCallHandler.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||||
|
|
||||||
// update the scroll map before we get unmounted
|
// update the scroll map before we get unmounted
|
||||||
if (this.state.roomId) {
|
if (this.state.roomId) {
|
||||||
@@ -1013,47 +1012,53 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.shouldPeek) {
|
if (this.state.shouldPeek) {
|
||||||
this.context.client?.stopPeeking();
|
this.props.context.client?.stopPeeking();
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop tracking room changes to format permalinks
|
// stop tracking room changes to format permalinks
|
||||||
this.stopAllPermalinkCreators();
|
this.stopAllPermalinkCreators();
|
||||||
|
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
if (this.context.client) {
|
if (this.props.context.client) {
|
||||||
this.context.client.removeListener(ClientEvent.Room, this.onRoom);
|
this.props.context.client.removeListener(ClientEvent.Room, this.onRoom);
|
||||||
this.context.client.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
this.props.context.client.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
|
||||||
this.context.client.removeListener(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
this.props.context.client.removeListener(RoomEvent.TimelineReset, this.onRoomTimelineReset);
|
||||||
this.context.client.removeListener(RoomEvent.Name, this.onRoomName);
|
this.props.context.client.removeListener(RoomEvent.Name, this.onRoomName);
|
||||||
this.context.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
this.props.context.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||||
this.context.client.removeListener(RoomEvent.MyMembership, this.onMyMembership);
|
this.props.context.client.removeListener(RoomEvent.MyMembership, this.onMyMembership);
|
||||||
this.context.client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
|
this.props.context.client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||||
this.context.client.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
this.props.context.client.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
|
||||||
this.context.client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
this.props.context.client.removeListener(
|
||||||
this.context.client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
|
CryptoEvent.DeviceVerificationChanged,
|
||||||
this.context.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
this.onDeviceVerificationChanged,
|
||||||
this.context.client.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
);
|
||||||
|
this.props.context.client.removeListener(
|
||||||
|
CryptoEvent.UserTrustStatusChanged,
|
||||||
|
this.onUserVerificationChanged,
|
||||||
|
);
|
||||||
|
this.props.context.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
|
||||||
|
this.props.context.client.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.removeEventListener("beforeunload", this.onPageUnload);
|
window.removeEventListener("beforeunload", this.onPageUnload);
|
||||||
|
|
||||||
this.context.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
this.props.context.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||||
|
|
||||||
this.context.rightPanelStore.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
this.props.context.rightPanelStore.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
WidgetEchoStore.removeListener(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
WidgetEchoStore.removeListener(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||||
this.context.widgetStore.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
this.props.context.widgetStore.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||||
|
|
||||||
this.props.resizeNotifier.off("isResizing", this.onIsResizing);
|
this.props.resizeNotifier.off("isResizing", this.onIsResizing);
|
||||||
|
|
||||||
if (this.state.room) {
|
if (this.state.room) {
|
||||||
this.context.widgetLayoutStore.off(
|
this.props.context.widgetLayoutStore.off(
|
||||||
WidgetLayoutStore.emissionForRoom(this.state.room),
|
WidgetLayoutStore.emissionForRoom(this.state.room),
|
||||||
this.onWidgetLayoutChange,
|
this.onWidgetLayoutChange,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallStore.instance.off(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
CallStore.instance.off(CallStoreEvent.ActiveCalls, this.onActiveCalls);
|
||||||
this.context.legacyCallHandler.off(LegacyCallHandlerEvent.CallState, this.onCallState);
|
this.props.context.legacyCallHandler.off(LegacyCallHandlerEvent.CallState, this.onCallState);
|
||||||
|
|
||||||
// cancel any pending calls to the throttled updated
|
// cancel any pending calls to the throttled updated
|
||||||
this.updateRoomMembers.cancel();
|
this.updateRoomMembers.cancel();
|
||||||
@@ -1064,17 +1069,17 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
if (this.viewsLocalRoom && this.state.room) {
|
if (this.viewsLocalRoom && this.state.room) {
|
||||||
// clean up if this was a local room
|
// clean up if this was a local room
|
||||||
this.context.client?.store.removeRoom(this.state.room.roomId);
|
this.props.context.client?.store.removeRoom(this.state.room.roomId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRightPanelStoreUpdate = (): void => {
|
private onRightPanelStoreUpdate = (): void => {
|
||||||
const { roomId } = this.state;
|
const { roomId } = this.state;
|
||||||
this.setState({
|
this.setState({
|
||||||
showRightPanel: roomId ? this.context.rightPanelStore.isOpenForRoom(roomId) : false,
|
showRightPanel: roomId ? this.props.context.rightPanelStore.isOpenForRoom(roomId) : false,
|
||||||
threadRightPanel: roomId
|
threadRightPanel: roomId
|
||||||
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
|
? [RightPanelPhases.ThreadView, RightPanelPhases.ThreadPanel].includes(
|
||||||
this.context.rightPanelStore.currentCardForRoom(roomId).phase!,
|
this.props.context.rightPanelStore.currentCardForRoom(roomId).phase!,
|
||||||
)
|
)
|
||||||
: false,
|
: false,
|
||||||
});
|
});
|
||||||
@@ -1131,7 +1136,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onAction = async (payload: ActionPayload): Promise<void> => {
|
private onAction = async (payload: ActionPayload): Promise<void> => {
|
||||||
if (!this.context.client) return;
|
if (!this.props.context.client) return;
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case "message_sent":
|
case "message_sent":
|
||||||
this.checkDesktopNotifications();
|
this.checkDesktopNotifications();
|
||||||
@@ -1151,7 +1156,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
[payload.file],
|
[payload.file],
|
||||||
roomId,
|
roomId,
|
||||||
undefined,
|
undefined,
|
||||||
this.context.client,
|
this.props.context.client,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1183,7 +1188,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
if (!this.state.matrixClientIsReady) {
|
if (!this.state.matrixClientIsReady) {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
matrixClientIsReady: !!this.context.client?.isInitialSyncComplete(),
|
matrixClientIsReady: !!this.props.context.client?.isInitialSyncComplete(),
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
// send another "initial" RVS update to trigger peeking if needed
|
// send another "initial" RVS update to trigger peeking if needed
|
||||||
@@ -1296,8 +1301,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onLocalRoomEvent(roomId: string): void {
|
private onLocalRoomEvent(roomId: string): void {
|
||||||
if (!this.context.client || !this.state.room || roomId !== this.state.room.roomId) return;
|
if (!this.props.context.client || !this.state.room || roomId !== this.state.room.roomId) return;
|
||||||
createRoomFromLocalRoom(this.context.client, this.state.room as LocalRoom);
|
createRoomFromLocalRoom(this.props.context.client, this.state.room as LocalRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRoomTimeline = (
|
private onRoomTimeline = (
|
||||||
@@ -1336,7 +1341,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
this.handleEffects(ev);
|
this.handleEffects(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.context.client && ev.getSender() !== this.context.client.getSafeUserId()) {
|
if (this.props.context.client && ev.getSender() !== this.props.context.client.getSafeUserId()) {
|
||||||
// update unread count when scrolled up
|
// update unread count when scrolled up
|
||||||
if (!this.state.search && this.state.atEndOfLiveTimeline) {
|
if (!this.state.search && this.state.atEndOfLiveTimeline) {
|
||||||
// no change
|
// no change
|
||||||
@@ -1357,7 +1362,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private handleEffects = (ev: MatrixEvent): void => {
|
private handleEffects = (ev: MatrixEvent): void => {
|
||||||
if (!this.state.room) return;
|
if (!this.state.room) return;
|
||||||
const notifState = this.context.roomNotificationStateStore.getRoomState(this.state.room);
|
const notifState = this.props.context.roomNotificationStateStore.getRoomState(this.state.room);
|
||||||
if (!notifState.isUnread) return;
|
if (!notifState.isUnread) return;
|
||||||
|
|
||||||
CHAT_EFFECTS.forEach((effect) => {
|
CHAT_EFFECTS.forEach((effect) => {
|
||||||
@@ -1400,7 +1405,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
private onRoomLoaded = (room: Room): void => {
|
private onRoomLoaded = (room: Room): void => {
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
// Attach a widget store listener only when we get a room
|
// Attach a widget store listener only when we get a room
|
||||||
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
|
this.props.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
|
||||||
|
|
||||||
this.calculatePeekRules(room);
|
this.calculatePeekRules(room);
|
||||||
this.updatePreviewUrlVisibility(room);
|
this.updatePreviewUrlVisibility(room);
|
||||||
@@ -1413,10 +1418,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
this.getMainSplitContentType(room) !== MainSplitContentType.Timeline &&
|
this.getMainSplitContentType(room) !== MainSplitContentType.Timeline &&
|
||||||
this.context.roomNotificationStateStore.getRoomState(room).isUnread
|
this.props.context.roomNotificationStateStore.getRoomState(room).isUnread
|
||||||
) {
|
) {
|
||||||
// Automatically open the chat panel to make unread messages easier to discover
|
// Automatically open the chat panel to make unread messages easier to discover
|
||||||
this.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline }, true, room.roomId);
|
this.props.context.rightPanelStore.setCard({ phase: RightPanelPhases.Timeline }, true, room.roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -1446,7 +1451,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private async loadMembersIfJoined(room: Room): Promise<void> {
|
private async loadMembersIfJoined(room: Room): Promise<void> {
|
||||||
// lazy load members if enabled
|
// lazy load members if enabled
|
||||||
if (this.context.client?.hasLazyLoadMembersEnabled()) {
|
if (this.props.context.client?.hasLazyLoadMembersEnabled()) {
|
||||||
if (room && room.getMyMembership() === KnownMembership.Join) {
|
if (room && room.getMyMembership() === KnownMembership.Join) {
|
||||||
try {
|
try {
|
||||||
await room.loadMembersIfNeeded();
|
await room.loadMembersIfNeeded();
|
||||||
@@ -1472,7 +1477,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private updatePreviewUrlVisibility({ roomId }: Room): void {
|
private updatePreviewUrlVisibility({ roomId }: Room): void {
|
||||||
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
|
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
|
||||||
const key = this.context.client?.isRoomEncrypted(roomId) ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
|
const key = this.props.context.client?.isRoomEncrypted(roomId)
|
||||||
|
? "urlPreviewsEnabled_e2ee"
|
||||||
|
: "urlPreviewsEnabled";
|
||||||
this.setState({
|
this.setState({
|
||||||
showUrlPreview: SettingsStore.getValue(key, roomId),
|
showUrlPreview: SettingsStore.getValue(key, roomId),
|
||||||
});
|
});
|
||||||
@@ -1485,7 +1492,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
// Detach the listener if the room is changing for some reason
|
// Detach the listener if the room is changing for some reason
|
||||||
if (this.state.room) {
|
if (this.state.room) {
|
||||||
this.context.widgetLayoutStore.off(
|
this.props.context.widgetLayoutStore.off(
|
||||||
WidgetLayoutStore.emissionForRoom(this.state.room),
|
WidgetLayoutStore.emissionForRoom(this.state.room),
|
||||||
this.onWidgetLayoutChange,
|
this.onWidgetLayoutChange,
|
||||||
);
|
);
|
||||||
@@ -1525,15 +1532,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private async updateE2EStatus(room: Room): Promise<void> {
|
private async updateE2EStatus(room: Room): Promise<void> {
|
||||||
if (!this.context.client?.isRoomEncrypted(room.roomId)) return;
|
if (!this.props.context.client?.isRoomEncrypted(room.roomId)) return;
|
||||||
|
|
||||||
// If crypto is not currently enabled, we aren't tracking devices at all,
|
// 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
|
// so we don't know what the answer is. Let's error on the safe side and show
|
||||||
// a warning for this case.
|
// a warning for this case.
|
||||||
let e2eStatus = E2EStatus.Warning;
|
let e2eStatus = E2EStatus.Warning;
|
||||||
if (this.context.client.isCryptoEnabled()) {
|
if (this.props.context.client.isCryptoEnabled()) {
|
||||||
/* At this point, the user has encryption on and cross-signing on */
|
/* At this point, the user has encryption on and cross-signing on */
|
||||||
e2eStatus = await shieldStatusForRoom(this.context.client, room);
|
e2eStatus = await shieldStatusForRoom(this.props.context.client, room);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.unmounted) return;
|
if (this.unmounted) return;
|
||||||
@@ -1578,8 +1585,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private updatePermissions(room: Room): void {
|
private updatePermissions(room: Room): void {
|
||||||
if (room && this.context.client) {
|
if (room && this.props.context.client) {
|
||||||
const me = this.context.client.getSafeUserId();
|
const me = this.props.context.client.getSafeUserId();
|
||||||
const canReact =
|
const canReact =
|
||||||
room.getMyMembership() === KnownMembership.Join &&
|
room.getMyMembership() === KnownMembership.Join &&
|
||||||
room.currentState.maySendEvent(EventType.Reaction, me);
|
room.currentState.maySendEvent(EventType.Reaction, me);
|
||||||
@@ -1635,7 +1642,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private onJoinButtonClicked = (): void => {
|
private onJoinButtonClicked = (): void => {
|
||||||
// If the user is a ROU, allow them to transition to a PWLU
|
// If the user is a ROU, allow them to transition to a PWLU
|
||||||
if (this.context.client?.isGuest()) {
|
if (this.props.context.client?.isGuest()) {
|
||||||
// Join this room once the user has registered and logged in
|
// Join this room once the user has registered and logged in
|
||||||
// (If we failed to peek, we may not have a valid room object.)
|
// (If we failed to peek, we may not have a valid room object.)
|
||||||
dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
|
dis.dispatch<DoAfterSyncPreparedPayload<ViewRoomPayload>>({
|
||||||
@@ -1702,14 +1709,14 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private injectSticker(url: string, info: object, text: string, threadId: string | null): void {
|
private injectSticker(url: string, info: object, text: string, threadId: string | null): void {
|
||||||
const roomId = this.getRoomId();
|
const roomId = this.getRoomId();
|
||||||
if (!this.context.client || !roomId) return;
|
if (!this.props.context.client || !roomId) return;
|
||||||
if (this.context.client.isGuest()) {
|
if (this.props.context.client.isGuest()) {
|
||||||
dis.dispatch({ action: "require_registration" });
|
dis.dispatch({ action: "require_registration" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentMessages.sharedInstance()
|
ContentMessages.sharedInstance()
|
||||||
.sendStickerContentToRoom(url, roomId, threadId, info, text, this.context.client)
|
.sendStickerContentToRoom(url, roomId, threadId, info, text, this.props.context.client)
|
||||||
.then(undefined, (error) => {
|
.then(undefined, (error) => {
|
||||||
if (error.name === "UnknownDeviceError") {
|
if (error.name === "UnknownDeviceError") {
|
||||||
// Let the staus bar handle this
|
// Let the staus bar handle this
|
||||||
@@ -1722,7 +1729,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
const roomId = scope === SearchScope.Room ? this.getRoomId() : undefined;
|
const roomId = scope === SearchScope.Room ? this.getRoomId() : undefined;
|
||||||
debuglog("sending search request");
|
debuglog("sending search request");
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const promise = eventSearch(this.context.client!, term, roomId, abortController.signal);
|
const promise = eventSearch(this.props.context.client!, term, roomId, abortController.signal);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
search: {
|
search: {
|
||||||
@@ -1768,7 +1775,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
rejecting: true,
|
rejecting: true,
|
||||||
});
|
});
|
||||||
this.context.client?.leave(roomId).then(
|
this.props.context.client?.leave(roomId).then(
|
||||||
() => {
|
() => {
|
||||||
dis.dispatch({ action: Action.ViewHomePage });
|
dis.dispatch({ action: Action.ViewHomePage });
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -1797,13 +1804,13 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const myMember = this.state.room!.getMember(this.context.client!.getSafeUserId());
|
const myMember = this.state.room!.getMember(this.props.context.client!.getSafeUserId());
|
||||||
const inviteEvent = myMember!.events.member;
|
const inviteEvent = myMember!.events.member;
|
||||||
const ignoredUsers = this.context.client!.getIgnoredUsers();
|
const ignoredUsers = this.props.context.client!.getIgnoredUsers();
|
||||||
ignoredUsers.push(inviteEvent!.getSender()!); // de-duped internally in the js-sdk
|
ignoredUsers.push(inviteEvent!.getSender()!); // de-duped internally in the js-sdk
|
||||||
await this.context.client!.setIgnoredUsers(ignoredUsers);
|
await this.props.context.client!.setIgnoredUsers(ignoredUsers);
|
||||||
|
|
||||||
await this.context.client!.leave(this.state.roomId!);
|
await this.props.context.client!.leave(this.state.roomId!);
|
||||||
dis.dispatch({ action: Action.ViewHomePage });
|
dis.dispatch({ action: Action.ViewHomePage });
|
||||||
this.setState({
|
this.setState({
|
||||||
rejecting: false,
|
rejecting: false,
|
||||||
@@ -1968,7 +1975,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
if (!this.state.room) {
|
if (!this.state.room) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.context.legacyCallHandler.getCallForRoom(this.state.room.roomId);
|
return this.props.context.legacyCallHandler.getCallForRoom(this.state.room.roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this has to be a proper method rather than an unnamed function,
|
// this has to be a proper method rather than an unnamed function,
|
||||||
@@ -1979,7 +1986,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private getOldRoom(): Room | null {
|
private getOldRoom(): Room | null {
|
||||||
const { roomId } = this.state.room?.findPredecessor(this.state.msc3946ProcessDynamicPredecessor) || {};
|
const { roomId } = this.state.room?.findPredecessor(this.state.msc3946ProcessDynamicPredecessor) || {};
|
||||||
return this.context.client?.getRoom(roomId) || null;
|
return this.props.context.client?.getRoom(roomId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHiddenHighlightCount(): number {
|
public getHiddenHighlightCount(): number {
|
||||||
@@ -2006,12 +2013,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
|
|
||||||
private onFileDrop = async (dataTransfer: DataTransfer): Promise<void> => {
|
private onFileDrop = async (dataTransfer: DataTransfer): Promise<void> => {
|
||||||
const roomId = this.getRoomId();
|
const roomId = this.getRoomId();
|
||||||
if (!roomId || !this.context.client) return;
|
if (!roomId || !this.props.context.client) return;
|
||||||
await ContentMessages.sharedInstance().sendContentListToRoom(
|
await ContentMessages.sharedInstance().sendContentListToRoom(
|
||||||
Array.from(dataTransfer.files),
|
Array.from(dataTransfer.files),
|
||||||
roomId,
|
roomId,
|
||||||
undefined,
|
undefined,
|
||||||
this.context.client,
|
this.props.context.client,
|
||||||
TimelineRenderingType.Room,
|
TimelineRenderingType.Room,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -2029,8 +2036,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderLocalRoomCreateLoader(localRoom: LocalRoom): ReactNode {
|
private renderLocalRoomCreateLoader(localRoom: LocalRoom): ReactNode {
|
||||||
if (!this.state.room || !this.context?.client) return null;
|
if (!this.state.room || !this.props.context?.client) return null;
|
||||||
const names = this.state.room.getDefaultRoomName(this.context.client.getSafeUserId());
|
const names = this.state.room.getDefaultRoomName(this.props.context.client.getSafeUserId());
|
||||||
return (
|
return (
|
||||||
<RoomContext.Provider value={this.state}>
|
<RoomContext.Provider value={this.state}>
|
||||||
<LocalRoomCreateLoader localRoom={localRoom} names={names} resizeNotifier={this.props.resizeNotifier} />
|
<LocalRoomCreateLoader localRoom={localRoom} names={names} resizeNotifier={this.props.resizeNotifier} />
|
||||||
@@ -2099,7 +2106,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
if (!this.context.client) return null;
|
if (!this.props.context.client) return null;
|
||||||
|
|
||||||
if (this.state.room instanceof LocalRoom) {
|
if (this.state.room instanceof LocalRoom) {
|
||||||
if (this.state.room.state === LocalRoomState.CREATING) {
|
if (this.state.room.state === LocalRoomState.CREATING) {
|
||||||
@@ -2209,7 +2216,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const myUserId = this.context.client.getSafeUserId();
|
const myUserId = this.props.context.client.getSafeUserId();
|
||||||
const myMember = this.state.room.getMember(myUserId);
|
const myMember = this.state.room.getMember(myUserId);
|
||||||
const inviteEvent = myMember ? myMember.events.member : null;
|
const inviteEvent = myMember ? myMember.events.member : null;
|
||||||
let inviterName = _t("room|inviter_unknown");
|
let inviterName = _t("room|inviter_unknown");
|
||||||
@@ -2313,7 +2320,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
const showRoomUpgradeBar =
|
const showRoomUpgradeBar =
|
||||||
roomVersionRecommendation &&
|
roomVersionRecommendation &&
|
||||||
roomVersionRecommendation.needsUpgrade &&
|
roomVersionRecommendation.needsUpgrade &&
|
||||||
this.state.room.userMayUpgradeRoom(this.context.client.getSafeUserId());
|
this.state.room.userMayUpgradeRoom(this.props.context.client.getSafeUserId());
|
||||||
|
|
||||||
const hiddenHighlightCount = this.getHiddenHighlightCount();
|
const hiddenHighlightCount = this.getHiddenHighlightCount();
|
||||||
|
|
||||||
@@ -2325,7 +2332,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
searchInProgress={this.state.search?.inProgress}
|
searchInProgress={this.state.search?.inProgress}
|
||||||
onCancelClick={this.onCancelSearchClick}
|
onCancelClick={this.onCancelSearchClick}
|
||||||
onSearch={this.onSearch}
|
onSearch={this.onSearch}
|
||||||
isRoomEncrypted={this.context.client.isRoomEncrypted(this.state.room.roomId)}
|
isRoomEncrypted={this.props.context.client.isRoomEncrypted(this.state.room.roomId)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (showRoomUpgradeBar) {
|
} else if (showRoomUpgradeBar) {
|
||||||
@@ -2393,7 +2400,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
const auxPanel = (
|
const auxPanel = (
|
||||||
<AuxPanel
|
<AuxPanel
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
userId={this.context.client.getSafeUserId()}
|
userId={this.props.context.client.getSafeUserId()}
|
||||||
showApps={this.state.showApps}
|
showApps={this.state.showApps}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
>
|
>
|
||||||
@@ -2546,7 +2553,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
<>
|
<>
|
||||||
<AppsDrawer
|
<AppsDrawer
|
||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
userId={this.context.client.getSafeUserId()}
|
userId={this.props.context.client.getSafeUserId()}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
showApps={true}
|
showApps={true}
|
||||||
role="main"
|
role="main"
|
||||||
@@ -2563,7 +2570,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
room={this.state.room}
|
room={this.state.room}
|
||||||
resizing={this.state.resizing}
|
resizing={this.state.resizing}
|
||||||
waitForCall={isVideoRoom(this.state.room)}
|
waitForCall={isVideoRoom(this.state.room)}
|
||||||
skipLobby={this.context.roomViewStore.skipCallLobby() ?? false}
|
skipLobby={this.props.context.roomViewStore.skipCallLobby() ?? false}
|
||||||
role="main"
|
role="main"
|
||||||
/>
|
/>
|
||||||
{previewBar}
|
{previewBar}
|
||||||
@@ -2593,15 +2600,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
onAppsClick = null;
|
onAppsClick = null;
|
||||||
onForgetClick = null;
|
onForgetClick = null;
|
||||||
onSearchClick = null;
|
onSearchClick = null;
|
||||||
if (this.state.room.canInvite(this.context.client.getSafeUserId())) {
|
if (this.state.room.canInvite(this.props.context.client.getSafeUserId())) {
|
||||||
onInviteClick = this.onInviteClick;
|
onInviteClick = this.onInviteClick;
|
||||||
}
|
}
|
||||||
viewingCall = true;
|
viewingCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const myMember = this.state.room!.getMember(this.context.client!.getSafeUserId());
|
const myMember = this.state.room!.getMember(this.props.context.client!.getSafeUserId());
|
||||||
const showForgetButton =
|
const showForgetButton =
|
||||||
!this.context.client.isGuest() &&
|
!this.props.context.client.isGuest() &&
|
||||||
(([KnownMembership.Leave, KnownMembership.Ban] as Array<string>).includes(myMembership) ||
|
(([KnownMembership.Leave, KnownMembership.Ban] as Array<string>).includes(myMembership) ||
|
||||||
myMember?.isKicked());
|
myMember?.isKicked());
|
||||||
|
|
||||||
@@ -2665,4 +2672,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RoomView;
|
export default forwardRef<RoomView, Omit<IRoomProps, "context">>((props, ref) => (
|
||||||
|
<SDKContext.Consumer>{(context) => <RoomView {...props} context={context} ref={ref} />}</SDKContext.Consumer>
|
||||||
|
));
|
||||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createRef, ReactNode } from "react";
|
import React, { createRef, forwardRef, ReactNode } from "react";
|
||||||
import { Room } from "matrix-js-sdk/src/matrix";
|
import { Room } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
@@ -56,6 +56,7 @@ import { shouldShowFeedback } from "../../utils/Feedback";
|
|||||||
interface IProps {
|
interface IProps {
|
||||||
isPanelCollapsed: boolean;
|
isPanelCollapsed: boolean;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
context: React.ContextType<typeof SDKContext>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PartialDOMRect = Pick<DOMRect, "width" | "left" | "top" | "height">;
|
type PartialDOMRect = Pick<DOMRect, "width" | "left" | "top" | "height">;
|
||||||
@@ -84,25 +85,21 @@ const below = (rect: PartialDOMRect): MenuProps => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class UserMenu extends React.Component<IProps, IState> {
|
class UserMenu extends React.Component<IProps, IState> {
|
||||||
public static contextType = SDKContext;
|
|
||||||
public context!: React.ContextType<typeof SDKContext>;
|
|
||||||
|
|
||||||
private dispatcherRef?: string;
|
private dispatcherRef?: string;
|
||||||
private themeWatcherRef?: string;
|
private themeWatcherRef?: string;
|
||||||
private readonly dndWatcherRef?: string;
|
private readonly dndWatcherRef?: string;
|
||||||
private buttonRef: React.RefObject<HTMLButtonElement> = createRef();
|
private buttonRef: React.RefObject<HTMLButtonElement> = createRef();
|
||||||
|
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
|
public constructor(props: IProps) {
|
||||||
super(props, context);
|
super(props);
|
||||||
|
|
||||||
this.context = context;
|
|
||||||
this.state = {
|
this.state = {
|
||||||
contextMenuPosition: null,
|
contextMenuPosition: null,
|
||||||
isDarkTheme: this.isUserOnDarkTheme(),
|
isDarkTheme: this.isUserOnDarkTheme(),
|
||||||
isHighContrast: this.isUserOnHighContrastTheme(),
|
isHighContrast: this.isUserOnHighContrastTheme(),
|
||||||
selectedSpace: SpaceStore.instance.activeSpaceRoom,
|
selectedSpace: SpaceStore.instance.activeSpaceRoom,
|
||||||
showLiveAvatarAddon: this.context.voiceBroadcastRecordingsStore.hasCurrent(),
|
showLiveAvatarAddon: this.props.context.voiceBroadcastRecordingsStore.hasCurrent(),
|
||||||
};
|
};
|
||||||
|
|
||||||
OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate);
|
OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate);
|
||||||
@@ -110,7 +107,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get hasHomePage(): boolean {
|
private get hasHomePage(): boolean {
|
||||||
return !!getHomePageUrl(SdkConfig.get(), this.context.client!);
|
return !!getHomePageUrl(SdkConfig.get(), this.props.context.client!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCurrentVoiceBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null): void => {
|
private onCurrentVoiceBroadcastRecordingChanged = (recording: VoiceBroadcastRecording | null): void => {
|
||||||
@@ -120,7 +117,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.context.voiceBroadcastRecordingsStore.on(
|
this.props.context.voiceBroadcastRecordingsStore.on(
|
||||||
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
||||||
this.onCurrentVoiceBroadcastRecordingChanged,
|
this.onCurrentVoiceBroadcastRecordingChanged,
|
||||||
);
|
);
|
||||||
@@ -134,7 +131,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||||||
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
|
if (this.dispatcherRef) defaultDispatcher.unregister(this.dispatcherRef);
|
||||||
OwnProfileStore.instance.off(UPDATE_EVENT, this.onProfileUpdate);
|
OwnProfileStore.instance.off(UPDATE_EVENT, this.onProfileUpdate);
|
||||||
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
|
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.onSelectedSpaceUpdate);
|
||||||
this.context.voiceBroadcastRecordingsStore.off(
|
this.props.context.voiceBroadcastRecordingsStore.off(
|
||||||
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
|
||||||
this.onCurrentVoiceBroadcastRecordingChanged,
|
this.onCurrentVoiceBroadcastRecordingChanged,
|
||||||
);
|
);
|
||||||
@@ -496,3 +493,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default forwardRef<UserMenu, Omit<IProps, "context">>((props, ref) => (
|
||||||
|
<SDKContext.Consumer>{(context) => <UserMenu {...props} context={context} ref={ref} />}</SDKContext.Consumer>
|
||||||
|
));
|
||||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ChangeEvent, SyntheticEvent } from "react";
|
import React, { ChangeEvent, forwardRef, SyntheticEvent } from "react";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { Optional } from "matrix-events-sdk";
|
import { Optional } from "matrix-events-sdk";
|
||||||
import { LoginFlow, MatrixError, SSOAction, SSOFlow } from "matrix-js-sdk/src/matrix";
|
import { LoginFlow, MatrixError, SSOAction, SSOFlow } from "matrix-js-sdk/src/matrix";
|
||||||
@@ -60,6 +60,7 @@ interface IProps {
|
|||||||
|
|
||||||
// Called when the SSO login completes
|
// Called when the SSO login completes
|
||||||
onTokenLoginCompleted: () => void;
|
onTokenLoginCompleted: () => void;
|
||||||
|
context: React.ContextType<typeof SDKContext>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
@@ -70,14 +71,9 @@ interface IState {
|
|||||||
flows: LoginFlow[];
|
flows: LoginFlow[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class SoftLogout extends React.Component<IProps, IState> {
|
class SoftLogout extends React.Component<IProps, IState> {
|
||||||
public static contextType = SDKContext;
|
public constructor(props: IProps) {
|
||||||
public context!: React.ContextType<typeof SDKContext>;
|
super(props);
|
||||||
|
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.context = context;
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
loginView: LoginView.Loading,
|
loginView: LoginView.Loading,
|
||||||
@@ -104,7 +100,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
|||||||
if (!wipeData) return;
|
if (!wipeData) return;
|
||||||
|
|
||||||
logger.log("Clearing data from soft-logged-out session");
|
logger.log("Clearing data from soft-logged-out session");
|
||||||
Lifecycle.logout(this.context.oidcClientStore);
|
Lifecycle.logout(this.props.context.oidcClientStore);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -338,3 +334,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default forwardRef<SoftLogout, Omit<IProps, "context">>((props, ref) => (
|
||||||
|
<SDKContext.Consumer>{(context) => <SoftLogout {...props} context={context} ref={ref} />}</SDKContext.Consumer>
|
||||||
|
));
|
||||||
|
@@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React, { forwardRef } from "react";
|
||||||
import {
|
import {
|
||||||
MatrixEvent,
|
MatrixEvent,
|
||||||
Room,
|
Room,
|
||||||
@@ -66,6 +66,7 @@ interface IProps {
|
|||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
onClose(): void;
|
onClose(): void;
|
||||||
onSearchQueryChanged: (query: string) => void;
|
onSearchQueryChanged: (query: string) => void;
|
||||||
|
context: React.ContextType<typeof SDKContext>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
@@ -77,18 +78,16 @@ interface IState {
|
|||||||
truncateAtInvited: number;
|
truncateAtInvited: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class MemberList extends React.Component<IProps, IState> {
|
class MemberList extends React.Component<IProps, IState> {
|
||||||
private readonly showPresence: boolean;
|
private readonly showPresence: boolean;
|
||||||
private mounted = false;
|
private mounted = false;
|
||||||
|
|
||||||
public static contextType = SDKContext;
|
|
||||||
public context!: React.ContextType<typeof SDKContext>;
|
|
||||||
private tiles: Map<string, MemberTile> = new Map();
|
private tiles: Map<string, MemberTile> = new Map();
|
||||||
|
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
|
public constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = this.getMembersState([], []);
|
this.state = this.getMembersState([], []);
|
||||||
this.showPresence = context?.memberListStore.isPresenceEnabled() ?? true;
|
this.showPresence = props.context?.memberListStore.isPresenceEnabled() ?? true;
|
||||||
this.mounted = true;
|
this.mounted = true;
|
||||||
this.listenForMembersChanges();
|
this.listenForMembersChanges();
|
||||||
}
|
}
|
||||||
@@ -218,7 +217,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||||||
if (showLoadingSpinner) {
|
if (showLoadingSpinner) {
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
}
|
}
|
||||||
const { joined, invited } = await this.context.memberListStore.loadMemberList(
|
const { joined, invited } = await this.props.context.memberListStore.loadMemberList(
|
||||||
this.props.roomId,
|
this.props.roomId,
|
||||||
this.props.searchQuery,
|
this.props.searchQuery,
|
||||||
);
|
);
|
||||||
@@ -449,3 +448,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||||||
inviteToRoom(room);
|
inviteToRoom(room);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default forwardRef<MemberList, Omit<IProps, "context">>((props, ref) => (
|
||||||
|
<SDKContext.Consumer>{(context) => <MemberList {...props} context={context} ref={ref} />}</SDKContext.Consumer>
|
||||||
|
));
|
||||||
|
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { forwardRef, ReactNode } from "react";
|
||||||
import { SERVICE_TYPES, HTTPError, IThreepid, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
import { SERVICE_TYPES, HTTPError, IThreepid, ThreepidMedium } from "matrix-js-sdk/src/matrix";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
@@ -61,6 +61,7 @@ import { SDKContext } from "../../../../../contexts/SDKContext";
|
|||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
closeSettingsFn: () => void;
|
closeSettingsFn: () => void;
|
||||||
|
context: React.ContextType<typeof SDKContext>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
@@ -92,17 +93,13 @@ interface IState {
|
|||||||
canMake3pidChanges: boolean;
|
canMake3pidChanges: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class GeneralUserSettingsTab extends React.Component<IProps, IState> {
|
class GeneralUserSettingsTab extends React.Component<IProps, IState> {
|
||||||
public static contextType = SDKContext;
|
|
||||||
public context!: React.ContextType<typeof SDKContext>;
|
|
||||||
|
|
||||||
private readonly dispatcherRef: string;
|
private readonly dispatcherRef: string;
|
||||||
|
|
||||||
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
|
public constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.context = context;
|
|
||||||
|
|
||||||
const cli = this.context.client!;
|
const cli = this.props.context.client!;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
language: languageHandler.getCurrentLanguage(),
|
language: languageHandler.getCurrentLanguage(),
|
||||||
@@ -151,7 +148,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
|
|
||||||
private onAction = (payload: ActionPayload): void => {
|
private onAction = (payload: ActionPayload): void => {
|
||||||
if (payload.action === "id_server_changed") {
|
if (payload.action === "id_server_changed") {
|
||||||
this.setState({ haveIdServer: Boolean(this.context.client!.getIdentityServerUrl()) });
|
this.setState({ haveIdServer: Boolean(this.props.context.client!.getIdentityServerUrl()) });
|
||||||
this.getThreepidState();
|
this.getThreepidState();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -165,7 +162,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
};
|
};
|
||||||
|
|
||||||
private async getCapabilities(): Promise<void> {
|
private async getCapabilities(): Promise<void> {
|
||||||
const cli = this.context.client!;
|
const cli = this.props.context.client!;
|
||||||
|
|
||||||
const capabilities = await cli.getCapabilities(); // this is cached
|
const capabilities = await cli.getCapabilities(); // this is cached
|
||||||
const changePasswordCap = capabilities["m.change_password"];
|
const changePasswordCap = capabilities["m.change_password"];
|
||||||
@@ -175,8 +172,8 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
// the enabled flag value.
|
// the enabled flag value.
|
||||||
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;
|
const canChangePassword = !changePasswordCap || changePasswordCap["enabled"] !== false;
|
||||||
|
|
||||||
await this.context.oidcClientStore.readyPromise; // wait for the store to be ready
|
await this.props.context.oidcClientStore.readyPromise; // wait for the store to be ready
|
||||||
const externalAccountManagementUrl = this.context.oidcClientStore.accountManagementEndpoint;
|
const externalAccountManagementUrl = this.props.context.oidcClientStore.accountManagementEndpoint;
|
||||||
// https://spec.matrix.org/v1.7/client-server-api/#m3pid_changes-capability
|
// https://spec.matrix.org/v1.7/client-server-api/#m3pid_changes-capability
|
||||||
// We support as far back as v1.1 which doesn't have m.3pid_changes
|
// We support as far back as v1.1 which doesn't have m.3pid_changes
|
||||||
// so the behaviour for when it is missing has to be assume true
|
// so the behaviour for when it is missing has to be assume true
|
||||||
@@ -186,7 +183,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getThreepidState(): Promise<void> {
|
private async getThreepidState(): Promise<void> {
|
||||||
const cli = this.context.client!;
|
const cli = this.props.context.client!;
|
||||||
|
|
||||||
// Check to see if terms need accepting
|
// Check to see if terms need accepting
|
||||||
this.checkTerms();
|
this.checkTerms();
|
||||||
@@ -213,7 +210,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
private async checkTerms(): Promise<void> {
|
private async checkTerms(): Promise<void> {
|
||||||
// By starting the terms flow we get the logic for checking which terms the user has signed
|
// By starting the terms flow we get the logic for checking which terms the user has signed
|
||||||
// for free. So we might as well use that for our own purposes.
|
// for free. So we might as well use that for our own purposes.
|
||||||
const idServerUrl = this.context.client!.getIdentityServerUrl();
|
const idServerUrl = this.props.context.client!.getIdentityServerUrl();
|
||||||
if (!this.state.haveIdServer || !idServerUrl) {
|
if (!this.state.haveIdServer || !idServerUrl) {
|
||||||
this.setState({ idServerHasUnsignedTerms: false });
|
this.setState({ idServerHasUnsignedTerms: false });
|
||||||
return;
|
return;
|
||||||
@@ -223,7 +220,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
try {
|
try {
|
||||||
const idAccessToken = await authClient.getAccessToken({ check: false });
|
const idAccessToken = await authClient.getAccessToken({ check: false });
|
||||||
await startTermsFlow(
|
await startTermsFlow(
|
||||||
this.context.client!,
|
this.props.context.client!,
|
||||||
[new Service(SERVICE_TYPES.IS, idServerUrl, idAccessToken!)],
|
[new Service(SERVICE_TYPES.IS, idServerUrl, idAccessToken!)],
|
||||||
(policiesAndServices, agreedUrls, extraClassNames) => {
|
(policiesAndServices, agreedUrls, extraClassNames) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -573,3 +570,9 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default forwardRef<GeneralUserSettingsTab, Omit<IProps, "context">>((props, ref) => (
|
||||||
|
<SDKContext.Consumer>
|
||||||
|
{(context) => <GeneralUserSettingsTab {...props} context={context} ref={ref} />}
|
||||||
|
</SDKContext.Consumer>
|
||||||
|
));
|
||||||
|
@@ -53,7 +53,7 @@ import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
|||||||
import { Action } from "../../../src/dispatcher/actions";
|
import { Action } from "../../../src/dispatcher/actions";
|
||||||
import dis, { defaultDispatcher } from "../../../src/dispatcher/dispatcher";
|
import dis, { defaultDispatcher } from "../../../src/dispatcher/dispatcher";
|
||||||
import { ViewRoomPayload } from "../../../src/dispatcher/payloads/ViewRoomPayload";
|
import { ViewRoomPayload } from "../../../src/dispatcher/payloads/ViewRoomPayload";
|
||||||
import { RoomView as _RoomView } from "../../../src/components/structures/RoomView";
|
import _RoomView from "../../../src/components/structures/RoomView";
|
||||||
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
|
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
|
||||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||||
@@ -112,7 +112,7 @@ describe("RoomView", () => {
|
|||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const mountRoomView = async (ref?: RefObject<_RoomView>): Promise<RenderResult> => {
|
const mountRoomView = async (ref?: RefObject<React.ComponentRef<typeof _RoomView>>): Promise<RenderResult> => {
|
||||||
if (stores.roomViewStore.getRoomId() !== room.roomId) {
|
if (stores.roomViewStore.getRoomId() !== room.roomId) {
|
||||||
const switchedRoom = new Promise<void>((resolve) => {
|
const switchedRoom = new Promise<void>((resolve) => {
|
||||||
const subFn = () => {
|
const subFn = () => {
|
||||||
@@ -185,8 +185,8 @@ describe("RoomView", () => {
|
|||||||
await flushPromises();
|
await flushPromises();
|
||||||
return roomView;
|
return roomView;
|
||||||
};
|
};
|
||||||
const getRoomViewInstance = async (): Promise<_RoomView> => {
|
const getRoomViewInstance = async (): Promise<React.ComponentRef<typeof _RoomView>> => {
|
||||||
const ref = createRef<_RoomView>();
|
const ref = createRef<React.ComponentRef<typeof _RoomView>>();
|
||||||
await mountRoomView(ref);
|
await mountRoomView(ref);
|
||||||
return ref.current!;
|
return ref.current!;
|
||||||
};
|
};
|
||||||
@@ -197,7 +197,7 @@ describe("RoomView", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("when there is an old room", () => {
|
describe("when there is an old room", () => {
|
||||||
let instance: _RoomView;
|
let instance: React.ComponentRef<typeof _RoomView>;
|
||||||
let oldRoom: Room;
|
let oldRoom: Room;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -596,7 +596,7 @@ describe("RoomView", () => {
|
|||||||
|
|
||||||
const eventMapper = (obj: Partial<IEvent>) => new MatrixEvent(obj);
|
const eventMapper = (obj: Partial<IEvent>) => new MatrixEvent(obj);
|
||||||
|
|
||||||
const roomViewRef = createRef<_RoomView>();
|
const roomViewRef = createRef<React.ComponentRef<typeof _RoomView>>();
|
||||||
const { container, getByText, findByLabelText } = await mountRoomView(roomViewRef);
|
const { container, getByText, findByLabelText } = await mountRoomView(roomViewRef);
|
||||||
// @ts-ignore - triggering a search organically is a lot of work
|
// @ts-ignore - triggering a search organically is a lot of work
|
||||||
roomViewRef.current!.setState({
|
roomViewRef.current!.setState({
|
||||||
@@ -657,7 +657,7 @@ describe("RoomView", () => {
|
|||||||
|
|
||||||
const eventMapper = (obj: Partial<IEvent>) => new MatrixEvent(obj);
|
const eventMapper = (obj: Partial<IEvent>) => new MatrixEvent(obj);
|
||||||
|
|
||||||
const roomViewRef = createRef<_RoomView>();
|
const roomViewRef = createRef<React.ComponentRef<typeof _RoomView>>();
|
||||||
const { container, getByText, findByLabelText } = await mountRoomView(roomViewRef);
|
const { container, getByText, findByLabelText } = await mountRoomView(roomViewRef);
|
||||||
// @ts-ignore - triggering a search organically is a lot of work
|
// @ts-ignore - triggering a search organically is a lot of work
|
||||||
roomViewRef.current!.setState({
|
roomViewRef.current!.setState({
|
||||||
|
@@ -59,7 +59,7 @@ describe("MemberList", () => {
|
|||||||
let client: MatrixClient;
|
let client: MatrixClient;
|
||||||
let root: RenderResult;
|
let root: RenderResult;
|
||||||
let memberListRoom: Room;
|
let memberListRoom: Room;
|
||||||
let memberList: MemberList;
|
let memberList: React.ComponentRef<typeof MemberList>;
|
||||||
|
|
||||||
let adminUsers: RoomMember[] = [];
|
let adminUsers: RoomMember[] = [];
|
||||||
let moderatorUsers: RoomMember[] = [];
|
let moderatorUsers: RoomMember[] = [];
|
||||||
@@ -214,7 +214,7 @@ describe("MemberList", () => {
|
|||||||
memberListRoom.currentState.members[member.userId] = member;
|
memberListRoom.currentState.members[member.userId] = member;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gatherWrappedRef = (r: MemberList) => {
|
const gatherWrappedRef = (r: React.ComponentRef<typeof MemberList>) => {
|
||||||
memberList = r;
|
memberList = r;
|
||||||
};
|
};
|
||||||
const context = new TestSdkContext();
|
const context = new TestSdkContext();
|
||||||
|
Reference in New Issue
Block a user