Prefer MatrixClientContext over MatrixClientPeg (#10986)

This commit is contained in:
Michael Telatynski 2023-06-14 13:42:07 +01:00 committed by GitHub
parent b40f29f04c
commit 9c48487d85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 120 additions and 87 deletions

View file

@ -20,7 +20,6 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import Modal from "../../Modal"; import Modal from "../../Modal";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
import ErrorDialog from "../views/dialogs/ErrorDialog"; import ErrorDialog from "../views/dialogs/ErrorDialog";
@ -30,6 +29,7 @@ import Spinner from "../views/elements/Spinner";
import ResizeNotifier from "../../utils/ResizeNotifier"; import ResizeNotifier from "../../utils/ResizeNotifier";
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases"; import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage"; import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage";
import MatrixClientContext from "../../contexts/MatrixClientContext";
interface IProps { interface IProps {
userId: string; userId: string;
@ -42,6 +42,9 @@ interface IState {
} }
export default class UserView extends React.Component<IProps, IState> { export default class UserView extends React.Component<IProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
@ -65,11 +68,10 @@ export default class UserView extends React.Component<IProps, IState> {
} }
private async loadProfileInfo(): Promise<void> { private async loadProfileInfo(): Promise<void> {
const cli = MatrixClientPeg.get();
this.setState({ loading: true }); this.setState({ loading: true });
let profileInfo: Awaited<ReturnType<MatrixClient["getProfileInfo"]>>; let profileInfo: Awaited<ReturnType<MatrixClient["getProfileInfo"]>>;
try { try {
profileInfo = await cli.getProfileInfo(this.props.userId); profileInfo = await this.context.getProfileInfo(this.props.userId);
} catch (err) { } catch (err) {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("Could not load user profile"), title: _t("Could not load user profile"),

View file

@ -25,13 +25,13 @@ import { formatTime } from "../../../DateUtils";
import { pillifyLinks, unmountPills } from "../../../utils/pillify"; import { pillifyLinks, unmountPills } from "../../../utils/pillify";
import { tooltipifyLinks, unmountTooltips } from "../../../utils/tooltipify"; import { tooltipifyLinks, unmountTooltips } from "../../../utils/tooltipify";
import { _t } from "../../../languageHandler"; import { _t } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
import RedactedBody from "./RedactedBody"; import RedactedBody from "./RedactedBody";
import AccessibleButton from "../elements/AccessibleButton"; import AccessibleButton from "../elements/AccessibleButton";
import ConfirmAndWaitRedactDialog from "../dialogs/ConfirmAndWaitRedactDialog"; import ConfirmAndWaitRedactDialog from "../dialogs/ConfirmAndWaitRedactDialog";
import ViewSource from "../../structures/ViewSource"; import ViewSource from "../../structures/ViewSource";
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
function getReplacedContent(event: MatrixEvent): IContent { function getReplacedContent(event: MatrixEvent): IContent {
const originalContent = event.getOriginalContent(); const originalContent = event.getOriginalContent();
@ -52,14 +52,18 @@ interface IState {
} }
export default class EditHistoryMessage extends React.PureComponent<IProps, IState> { export default class EditHistoryMessage extends React.PureComponent<IProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private content = createRef<HTMLDivElement>(); private content = createRef<HTMLDivElement>();
private pills: Element[] = []; private pills: Element[] = [];
private tooltips: Element[] = []; private tooltips: Element[] = [];
public constructor(props: IProps) { public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props); super(props);
this.context = context;
const cli = MatrixClientPeg.get(); const cli = this.context;
const userId = cli.getSafeUserId(); const userId = cli.getSafeUserId();
const event = this.props.mxEvent; const event = this.props.mxEvent;
const room = cli.getRoom(event.getRoomId()); const room = cli.getRoom(event.getRoomId());
@ -74,7 +78,7 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
private onRedactClick = async (): Promise<void> => { private onRedactClick = async (): Promise<void> => {
const event = this.props.mxEvent; const event = this.props.mxEvent;
const cli = MatrixClientPeg.get(); const cli = this.context;
Modal.createDialog( Modal.createDialog(
ConfirmAndWaitRedactDialog, ConfirmAndWaitRedactDialog,
@ -102,7 +106,7 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
private pillifyLinks(): void { private pillifyLinks(): void {
// not present for redacted events // not present for redacted events
if (this.content.current) { if (this.content.current) {
pillifyLinks(MatrixClientPeg.get(), this.content.current.children, this.props.mxEvent, this.pills); pillifyLinks(this.context, this.content.current.children, this.props.mxEvent, this.pills);
} }
} }

View file

@ -27,7 +27,6 @@ import { User } from "matrix-js-sdk/src/models/user";
import EncryptionInfo from "./EncryptionInfo"; import EncryptionInfo from "./EncryptionInfo";
import VerificationPanel from "./VerificationPanel"; import VerificationPanel from "./VerificationPanel";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { ensureDMExists } from "../../../createRoom"; import { ensureDMExists } from "../../../createRoom";
import { useTypedEventEmitter } from "../../../hooks/useEventEmitter"; import { useTypedEventEmitter } from "../../../hooks/useEventEmitter";
import Modal from "../../../Modal"; import Modal from "../../../Modal";
@ -35,6 +34,7 @@ import { _t } from "../../../languageHandler";
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases"; import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
import RightPanelStore from "../../../stores/right-panel/RightPanelStore"; import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
import ErrorDialog from "../dialogs/ErrorDialog"; import ErrorDialog from "../dialogs/ErrorDialog";
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
// cancellation codes which constitute a key mismatch // cancellation codes which constitute a key mismatch
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"]; const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
@ -49,6 +49,7 @@ interface IProps {
} }
const EncryptionPanel: React.FC<IProps> = (props: IProps) => { const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
const cli = useMatrixClientContext();
const { verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted } = props; const { verificationRequest, verificationRequestPromise, member, onClose, layout, isRoomEncrypted } = props;
const [request, setRequest] = useState(verificationRequest); const [request, setRequest] = useState(verificationRequest);
// state to show a spinner immediately after clicking "start verification", // state to show a spinner immediately after clicking "start verification",
@ -106,7 +107,6 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
const onStartVerification = useCallback(async (): Promise<void> => { const onStartVerification = useCallback(async (): Promise<void> => {
setRequesting(true); setRequesting(true);
const cli = MatrixClientPeg.get();
let verificationRequest_: VerificationRequest; let verificationRequest_: VerificationRequest;
try { try {
const roomId = await ensureDMExists(cli, member.userId); const roomId = await ensureDMExists(cli, member.userId);
@ -135,14 +135,12 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
}); });
} }
if (!RightPanelStore.instance.isOpen) RightPanelStore.instance.togglePanel(null); if (!RightPanelStore.instance.isOpen) RightPanelStore.instance.togglePanel(null);
}, [member]); }, [cli, member]);
const requested: boolean = const requested: boolean =
(!request && isRequesting) || (!request && isRequesting) ||
(!!request && (phase === PHASE_REQUESTED || phase === PHASE_UNSENT || phase === undefined)); (!!request && (phase === PHASE_REQUESTED || phase === PHASE_UNSENT || phase === undefined));
const isSelfVerification = request const isSelfVerification = request ? request.isSelfVerification : member.userId === cli.getUserId();
? request.isSelfVerification
: member.userId === MatrixClientPeg.get().getUserId();
if (!request || requested) { if (!request || requested) {
const initiatedByMe = (!request && isRequesting) || (!!request && request.initiatedByMe); const initiatedByMe = (!request && isRequesting) || (!!request && request.initiatedByMe);

View file

@ -17,12 +17,13 @@ limitations under the License.
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import BridgeTile from "../../BridgeTile"; import BridgeTile from "../../BridgeTile";
import SettingsTab from "../SettingsTab"; import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSection } from "../../shared/SettingsSection";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
const BRIDGE_EVENT_TYPES = [ const BRIDGE_EVENT_TYPES = [
"uk.half-shot.bridge", "uk.half-shot.bridge",
@ -36,14 +37,16 @@ interface IProps {
} }
export default class BridgeSettingsTab extends React.Component<IProps> { export default class BridgeSettingsTab extends React.Component<IProps> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private renderBridgeCard(event: MatrixEvent, room: Room | null): ReactNode { private renderBridgeCard(event: MatrixEvent, room: Room | null): ReactNode {
const content = event.getContent(); const content = event.getContent();
if (!room || !content?.channel || !content.protocol) return null; if (!room || !content?.channel || !content.protocol) return null;
return <BridgeTile key={event.getId()} room={room} ev={event} />; return <BridgeTile key={event.getId()} room={room} ev={event} />;
} }
public static getBridgeStateEvents(roomId: string): MatrixEvent[] { public static getBridgeStateEvents(client: MatrixClient, roomId: string): MatrixEvent[] {
const client = MatrixClientPeg.get();
const roomState = client.getRoom(roomId)?.currentState; const roomState = client.getRoom(roomId)?.currentState;
if (!roomState) return []; if (!roomState) return [];
@ -53,7 +56,7 @@ export default class BridgeSettingsTab extends React.Component<IProps> {
public render(): React.ReactNode { public render(): React.ReactNode {
// This settings tab will only be invoked if the following function returns more // This settings tab will only be invoked if the following function returns more
// than 0 events, so no validation is needed at this stage. // than 0 events, so no validation is needed at this stage.
const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.props.room.roomId); const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.context, this.props.room.roomId);
const room = this.props.room; const room = this.props.room;
let content: JSX.Element; let content: JSX.Element;

View file

@ -18,7 +18,6 @@ import React, { createRef } from "react";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton"; import AccessibleButton, { ButtonEvent } from "../../../elements/AccessibleButton";
import Notifier from "../../../../../Notifier"; import Notifier from "../../../../../Notifier";
import SettingsStore from "../../../../../settings/SettingsStore"; import SettingsStore from "../../../../../settings/SettingsStore";
@ -116,7 +115,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
type = "audio/ogg"; type = "audio/ogg";
} }
const { content_uri: url } = await MatrixClientPeg.get().uploadContent(this.state.uploadedFile, { const { content_uri: url } = await this.context.uploadContent(this.state.uploadedFile, {
type, type,
}); });

View file

@ -25,7 +25,6 @@ import { IContent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/matrix"; import { Room } from "matrix-js-sdk/src/matrix";
import { _t, _td } from "../../../../../languageHandler"; import { _t, _td } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import AccessibleButton from "../../../elements/AccessibleButton"; import AccessibleButton from "../../../elements/AccessibleButton";
import Modal from "../../../../../Modal"; import Modal from "../../../../../Modal";
import ErrorDialog from "../../../dialogs/ErrorDialog"; import ErrorDialog from "../../../dialogs/ErrorDialog";
@ -38,6 +37,7 @@ import SdkConfig, { DEFAULTS } from "../../../../../SdkConfig";
import { AddPrivilegedUsers } from "../../AddPrivilegedUsers"; import { AddPrivilegedUsers } from "../../AddPrivilegedUsers";
import SettingsTab from "../SettingsTab"; import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSection } from "../../shared/SettingsSection";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
interface IEventShowOpts { interface IEventShowOpts {
isState?: boolean; isState?: boolean;
@ -91,16 +91,17 @@ interface IBannedUserProps {
} }
export class BannedUser extends React.Component<IBannedUserProps> { export class BannedUser extends React.Component<IBannedUserProps> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private onUnbanClick = (): void => { private onUnbanClick = (): void => {
MatrixClientPeg.get() this.context.unban(this.props.member.roomId, this.props.member.userId).catch((err) => {
.unban(this.props.member.roomId, this.props.member.userId) logger.error("Failed to unban: " + err);
.catch((err) => { Modal.createDialog(ErrorDialog, {
logger.error("Failed to unban: " + err); title: _t("Error"),
Modal.createDialog(ErrorDialog, { description: _t("Failed to unban"),
title: _t("Error"),
description: _t("Failed to unban"),
});
}); });
});
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
@ -136,12 +137,15 @@ interface IProps {
} }
export default class RolesRoomSettingsTab extends React.Component<IProps> { export default class RolesRoomSettingsTab extends React.Component<IProps> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public componentDidMount(): void { public componentDidMount(): void {
MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); this.context.on(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
const client = MatrixClientPeg.get(); const client = this.context;
if (client) { if (client) {
client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate); client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
@ -173,7 +177,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
} }
private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => { private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => {
const client = MatrixClientPeg.get(); const client = this.context;
const room = this.props.room; const room = this.props.room;
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
let plContent = plEvent?.getContent() ?? {}; let plContent = plEvent?.getContent() ?? {};
@ -215,7 +219,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
}; };
private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => { private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => {
const client = MatrixClientPeg.get(); const client = this.context;
const room = this.props.room; const room = this.props.room;
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, ""); const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
let plContent = plEvent?.getContent() ?? {}; let plContent = plEvent?.getContent() ?? {};
@ -241,7 +245,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
const client = MatrixClientPeg.get(); const client = this.context;
const room = this.props.room; const room = this.props.room;
const isSpaceRoom = room.isSpaceRoom(); const isSpaceRoom = room.isSpaceRoom();

View file

@ -21,7 +21,6 @@ import { RoomState } from "matrix-js-sdk/src/models/room-state";
import { Room } from "matrix-js-sdk/src/matrix"; import { Room } from "matrix-js-sdk/src/matrix";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import SettingsSubsection from "../../shared/SettingsSubsection"; import SettingsSubsection from "../../shared/SettingsSubsection";
import SettingsTab from "../SettingsTab"; import SettingsTab from "../SettingsTab";
@ -38,14 +37,17 @@ const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]); const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]);
const [content, events, maySend] = useRoomState( const [content, events, maySend] = useRoomState(
room, room,
useCallback((state: RoomState) => { useCallback(
const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent(); (state: RoomState) => {
return [ const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent();
content ?? {}, return [
content?.["events"] ?? {}, content ?? {},
state?.maySendStateEvent(EventType.RoomPowerLevels, MatrixClientPeg.get().getSafeUserId()), content?.["events"] ?? {},
]; state?.maySendStateEvent(EventType.RoomPowerLevels, room.client.getSafeUserId()),
}, []), ];
},
[room.client],
),
); );
const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => { const [elementCallEnabled, setElementCallEnabled] = useState<boolean>(() => {
@ -69,12 +71,12 @@ const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ room }) => {
events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel; events[ElementCall.MEMBER_EVENT_TYPE.name] = adminLevel;
} }
MatrixClientPeg.get().sendStateEvent(room.roomId, EventType.RoomPowerLevels, { room.client.sendStateEvent(room.roomId, EventType.RoomPowerLevels, {
events: events, events: events,
...content, ...content,
}); });
}, },
[room.roomId, content, events, isPublic], [room.client, room.roomId, content, events, isPublic],
); );
const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand; const brand = SdkConfig.get("element_call").brand ?? DEFAULTS.element_call.brand;

View file

@ -19,7 +19,6 @@ import React, { ChangeEvent, ReactNode } from "react";
import { _t } from "../../../../../languageHandler"; import { _t } from "../../../../../languageHandler";
import SdkConfig from "../../../../../SdkConfig"; import SdkConfig from "../../../../../SdkConfig";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import SettingsStore from "../../../../../settings/SettingsStore"; import SettingsStore from "../../../../../settings/SettingsStore";
import SettingsFlag from "../../../elements/SettingsFlag"; import SettingsFlag from "../../../elements/SettingsFlag";
import Field from "../../../elements/Field"; import Field from "../../../elements/Field";
@ -34,6 +33,7 @@ import ImageSizePanel from "../../ImageSizePanel";
import SettingsTab from "../SettingsTab"; import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSection } from "../../shared/SettingsSection";
import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
interface IProps {} interface IProps {}
@ -49,6 +49,9 @@ interface IState {
} }
export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> { export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!");
private unmounted = false; private unmounted = false;
@ -66,7 +69,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
public async componentDidMount(): Promise<void> { public async componentDidMount(): Promise<void> {
// Fetch the current user profile for the message preview // Fetch the current user profile for the message preview
const client = MatrixClientPeg.get(); const client = this.context;
const userId = client.getUserId()!; const userId = client.getUserId()!;
const profileInfo = await client.getProfileInfo(userId); const profileInfo = await client.getProfileInfo(userId);
if (this.unmounted) return; if (this.unmounted) return;

View file

@ -33,7 +33,6 @@ import SpellCheckSettings from "../../SpellCheckSettings";
import AccessibleButton from "../../../elements/AccessibleButton"; import AccessibleButton from "../../../elements/AccessibleButton";
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog"; import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
import PlatformPeg from "../../../../../PlatformPeg"; import PlatformPeg from "../../../../../PlatformPeg";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import Modal from "../../../../../Modal"; import Modal from "../../../../../Modal";
import dis from "../../../../../dispatcher/dispatcher"; import dis from "../../../../../dispatcher/dispatcher";
import { Service, ServicePolicyPair, startTermsFlow } from "../../../../../Terms"; import { Service, ServicePolicyPair, startTermsFlow } from "../../../../../Terms";
@ -102,14 +101,15 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
private readonly dispatcherRef: string; private readonly dispatcherRef: string;
public constructor(props: IProps) { public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props); super(props);
this.context = context;
this.state = { this.state = {
language: languageHandler.getCurrentLanguage(), language: languageHandler.getCurrentLanguage(),
spellCheckEnabled: false, spellCheckEnabled: false,
spellCheckLanguages: [], spellCheckLanguages: [],
haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl()), haveIdServer: Boolean(this.context.getIdentityServerUrl()),
idServerHasUnsignedTerms: false, idServerHasUnsignedTerms: false,
requiredPolicyInfo: { requiredPolicyInfo: {
// This object is passed along to a component for handling // This object is passed along to a component for handling
@ -151,7 +151,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(MatrixClientPeg.get().getIdentityServerUrl()) }); this.setState({ haveIdServer: Boolean(this.context.getIdentityServerUrl()) });
this.getThreepidState(); this.getThreepidState();
} }
}; };
@ -165,7 +165,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
}; };
private async getCapabilities(): Promise<void> { private async getCapabilities(): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = this.context;
const serverSupportsSeparateAddAndBind = await cli.doesServerSupportSeparateAddAndBind(); const serverSupportsSeparateAddAndBind = await cli.doesServerSupportSeparateAddAndBind();
@ -184,7 +184,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
} }
private async getThreepidState(): Promise<void> { private async getThreepidState(): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = this.context;
// Check to see if terms need accepting // Check to see if terms need accepting
this.checkTerms(); this.checkTerms();
@ -195,7 +195,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
try { try {
threepids = await getThreepidsWithBindStatus(cli); threepids = await getThreepidsWithBindStatus(cli);
} catch (e) { } catch (e) {
const idServerUrl = MatrixClientPeg.get().getIdentityServerUrl(); const idServerUrl = this.context.getIdentityServerUrl();
logger.warn( logger.warn(
`Unable to reach identity server at ${idServerUrl} to check ` + `for 3PIDs bindings in Settings`, `Unable to reach identity server at ${idServerUrl} to check ` + `for 3PIDs bindings in Settings`,
); );
@ -211,7 +211,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 = MatrixClientPeg.get().getIdentityServerUrl(); const idServerUrl = this.context.getIdentityServerUrl();
if (!this.state.haveIdServer || !idServerUrl) { if (!this.state.haveIdServer || !idServerUrl) {
this.setState({ idServerHasUnsignedTerms: false }); this.setState({ idServerHasUnsignedTerms: false });
return; return;

View file

@ -19,7 +19,6 @@ import { logger } from "matrix-js-sdk/src/logger";
import AccessibleButton from "../../../elements/AccessibleButton"; import AccessibleButton from "../../../elements/AccessibleButton";
import { _t, getCurrentLanguage } from "../../../../../languageHandler"; import { _t, getCurrentLanguage } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import SdkConfig from "../../../../../SdkConfig"; import SdkConfig from "../../../../../SdkConfig";
import createRoom from "../../../../../createRoom"; import createRoom from "../../../../../createRoom";
import Modal from "../../../../../Modal"; import Modal from "../../../../../Modal";
@ -77,7 +76,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
private getVersionInfo(): { appVersion: string; olmVersion: string } { private getVersionInfo(): { appVersion: string; olmVersion: string } {
const brand = SdkConfig.get().brand; const brand = SdkConfig.get().brand;
const appVersion = this.state.appVersion || "unknown"; const appVersion = this.state.appVersion || "unknown";
const olmVersionTuple = MatrixClientPeg.get().olmVersion; const olmVersionTuple = this.context.olmVersion;
const olmVersion = olmVersionTuple const olmVersion = olmVersionTuple
? `${olmVersionTuple[0]}.${olmVersionTuple[1]}.${olmVersionTuple[2]}` ? `${olmVersionTuple[0]}.${olmVersionTuple[1]}.${olmVersionTuple[2]}`
: "<not-enabled>"; : "<not-enabled>";
@ -94,12 +93,10 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
// Dev note: please keep this log line, it's useful when troubleshooting a MatrixClient suddenly // Dev note: please keep this log line, it's useful when troubleshooting a MatrixClient suddenly
// stopping in the middle of the logs. // stopping in the middle of the logs.
logger.log("Clear cache & reload clicked"); logger.log("Clear cache & reload clicked");
MatrixClientPeg.get().stopClient(); this.context.stopClient();
MatrixClientPeg.get() this.context.store.deleteAllData().then(() => {
.store.deleteAllData() PlatformPeg.get()?.reload();
.then(() => { });
PlatformPeg.get()?.reload();
});
}; };
private onBugReport = (): void => { private onBugReport = (): void => {
@ -362,19 +359,19 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
{_t( {_t(
"Homeserver is <code>%(homeserverUrl)s</code>", "Homeserver is <code>%(homeserverUrl)s</code>",
{ {
homeserverUrl: MatrixClientPeg.get().getHomeserverUrl(), homeserverUrl: this.context.getHomeserverUrl(),
}, },
{ {
code: (sub) => <code>{sub}</code>, code: (sub) => <code>{sub}</code>,
}, },
)} )}
</SettingsSubsectionText> </SettingsSubsectionText>
{MatrixClientPeg.get().getIdentityServerUrl() && ( {this.context.getIdentityServerUrl() && (
<SettingsSubsectionText> <SettingsSubsectionText>
{_t( {_t(
"Identity server is <code>%(identityServerUrl)s</code>", "Identity server is <code>%(identityServerUrl)s</code>",
{ {
identityServerUrl: MatrixClientPeg.get().getIdentityServerUrl(), identityServerUrl: this.context.getIdentityServerUrl(),
}, },
{ {
code: (sub) => <code>{sub}</code>, code: (sub) => <code>{sub}</code>,
@ -391,8 +388,8 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
" Do not share it with anyone.", " Do not share it with anyone.",
)} )}
</b> </b>
<CopyableText getTextToCopy={() => MatrixClientPeg.get().getAccessToken()}> <CopyableText getTextToCopy={() => this.context.getAccessToken()}>
{MatrixClientPeg.get().getAccessToken()} {this.context.getAccessToken()}
</CopyableText> </CopyableText>
</details> </details>
</SettingsSubsectionText> </SettingsSubsectionText>

View file

@ -23,7 +23,6 @@ import { _t } from "../../../../../languageHandler";
import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler"; import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler";
import Field from "../../../elements/Field"; import Field from "../../../elements/Field";
import AccessibleButton from "../../../elements/AccessibleButton"; import AccessibleButton from "../../../elements/AccessibleButton";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
import { SettingLevel } from "../../../../../settings/SettingLevel"; import { SettingLevel } from "../../../../../settings/SettingLevel";
import SettingsFlag from "../../../elements/SettingsFlag"; import SettingsFlag from "../../../elements/SettingsFlag";
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
@ -31,6 +30,7 @@ import { requestMediaPermissions } from "../../../../../utils/media/requestMedia
import SettingsTab from "../SettingsTab"; import SettingsTab from "../SettingsTab";
import { SettingsSection } from "../../shared/SettingsSection"; import { SettingsSection } from "../../shared/SettingsSection";
import SettingsSubsection from "../../shared/SettingsSubsection"; import SettingsSubsection from "../../shared/SettingsSubsection";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
interface IState { interface IState {
mediaDevices: IMediaDevices | null; mediaDevices: IMediaDevices | null;
@ -58,6 +58,9 @@ const mapDeviceKindToHandlerValue = (deviceKind: MediaDeviceKindEnum): string |
}; };
export default class VoiceUserSettingsTab extends React.Component<{}, IState> { export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
public constructor(props: {}) { public constructor(props: {}) {
super(props); super(props);
@ -114,11 +117,11 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
}; };
private changeWebRtcMethod = (p2p: boolean): void => { private changeWebRtcMethod = (p2p: boolean): void => {
MatrixClientPeg.get().setForceTURN(!p2p); this.context.setForceTURN(!p2p);
}; };
private changeFallbackICEServerAllowed = (allow: boolean): void => { private changeFallbackICEServerAllowed = (allow: boolean): void => {
MatrixClientPeg.get().setFallbackICEServerAllowed(allow); this.context.setFallbackICEServerAllowed(allow);
}; };
private renderDeviceOptions(devices: Array<MediaDeviceInfo>, category: MediaDeviceKindEnum): Array<JSX.Element> { private renderDeviceOptions(devices: Array<MediaDeviceInfo>, category: MediaDeviceKindEnum): Array<JSX.Element> {

View file

@ -16,10 +16,10 @@ limitations under the License.
import { ClientEvent } from "matrix-js-sdk/src/matrix"; import { ClientEvent } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { useEventEmitterState } from "./useEventEmitter"; import { useEventEmitterState } from "./useEventEmitter";
import { useMatrixClientContext } from "../contexts/MatrixClientContext";
export function useInitialSyncComplete(): boolean { export function useInitialSyncComplete(): boolean {
const cli = MatrixClientPeg.get(); const cli = useMatrixClientContext();
return useEventEmitterState(cli, ClientEvent.Sync, () => cli.isInitialSyncComplete()); return useEventEmitterState(cli, ClientEvent.Sync, () => cli.isInitialSyncComplete());
} }

View file

@ -18,9 +18,9 @@ import { logger } from "matrix-js-sdk/src/logger";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix"; import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { Notifier } from "../Notifier"; import { Notifier } from "../Notifier";
import DMRoomMap from "../utils/DMRoomMap"; import DMRoomMap from "../utils/DMRoomMap";
import { useMatrixClientContext } from "../contexts/MatrixClientContext";
export interface UserOnboardingContext { export interface UserOnboardingContext {
hasAvatar: boolean; hasAvatar: boolean;
@ -47,7 +47,7 @@ function useRefOf<T extends any[], R>(value: (...values: T) => R): (...values: T
function useUserOnboardingContextValue<T>(defaultValue: T, callback: (cli: MatrixClient) => Promise<T>): T { function useUserOnboardingContextValue<T>(defaultValue: T, callback: (cli: MatrixClient) => Promise<T>): T {
const [value, setValue] = useState<T>(defaultValue); const [value, setValue] = useState<T>(defaultValue);
const cli = MatrixClientPeg.get(); const cli = useMatrixClientContext();
const handler = useRefOf(callback); const handler = useRefOf(callback);

View file

@ -25,13 +25,13 @@ import {
VoiceBroadcastInfoState, VoiceBroadcastInfoState,
} from ".."; } from "..";
import { IBodyProps } from "../../components/views/messages/IBodyProps"; import { IBodyProps } from "../../components/views/messages/IBodyProps";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper"; import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
import { SDKContext } from "../../contexts/SDKContext"; import { SDKContext } from "../../contexts/SDKContext";
import { useMatrixClientContext } from "../../contexts/MatrixClientContext";
export const VoiceBroadcastBody: React.FC<IBodyProps> = ({ mxEvent }) => { export const VoiceBroadcastBody: React.FC<IBodyProps> = ({ mxEvent }) => {
const sdkContext = useContext(SDKContext); const sdkContext = useContext(SDKContext);
const client = MatrixClientPeg.get(); const client = useMatrixClientContext();
const [infoState, setInfoState] = useState(mxEvent.getContent()?.state || VoiceBroadcastInfoState.Stopped); const [infoState, setInfoState] = useState(mxEvent.getContent()?.state || VoiceBroadcastInfoState.Stopped);
useEffect(() => { useEffect(() => {

View file

@ -19,7 +19,7 @@ import { render } from "@testing-library/react";
import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import { MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import BridgeSettingsTab from "../../../../../../src/components/views/settings/tabs/room/BridgeSettingsTab"; import BridgeSettingsTab from "../../../../../../src/components/views/settings/tabs/room/BridgeSettingsTab";
import { getMockClientWithEventEmitter } from "../../../../../test-utils"; import { getMockClientWithEventEmitter, withClientContextRenderOptions } from "../../../../../test-utils";
describe("<BridgeSettingsTab />", () => { describe("<BridgeSettingsTab />", () => {
const userId = "@alice:server.org"; const userId = "@alice:server.org";
@ -28,7 +28,8 @@ describe("<BridgeSettingsTab />", () => {
}); });
const roomId = "!room:server.org"; const roomId = "!room:server.org";
const getComponent = (room: Room) => render(<BridgeSettingsTab room={room} />); const getComponent = (room: Room) =>
render(<BridgeSettingsTab room={room} />, withClientContextRenderOptions(client));
it("renders when room is not bridging messages to any platform", () => { it("renders when room is not bridging messages to any platform", () => {
const room = new Room(roomId, client, userId); const room = new Room(roomId, client, userId);

View file

@ -24,7 +24,7 @@ import { mocked } from "jest-mock";
import { RoomMember } from "matrix-js-sdk/src/matrix"; import { RoomMember } from "matrix-js-sdk/src/matrix";
import RolesRoomSettingsTab from "../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab"; import RolesRoomSettingsTab from "../../../../../../src/components/views/settings/tabs/room/RolesRoomSettingsTab";
import { mkStubRoom, stubClient } from "../../../../../test-utils"; import { mkStubRoom, withClientContextRenderOptions, stubClient } from "../../../../../test-utils";
import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg"; import { MatrixClientPeg } from "../../../../../../src/MatrixClientPeg";
import { VoiceBroadcastInfoEventType } from "../../../../../../src/voice-broadcast"; import { VoiceBroadcastInfoEventType } from "../../../../../../src/voice-broadcast";
import SettingsStore from "../../../../../../src/settings/SettingsStore"; import SettingsStore from "../../../../../../src/settings/SettingsStore";
@ -37,7 +37,7 @@ describe("RolesRoomSettingsTab", () => {
let room: Room; let room: Room;
const renderTab = (propRoom: Room = room): RenderResult => { const renderTab = (propRoom: Room = room): RenderResult => {
return render(<RolesRoomSettingsTab room={propRoom} />); return render(<RolesRoomSettingsTab room={propRoom} />, withClientContextRenderOptions(cli));
}; };
const getVoiceBroadcastsSelect = (): HTMLElement => { const getVoiceBroadcastsSelect = (): HTMLElement => {

View file

@ -16,9 +16,10 @@ limitations under the License.
import { render } from "@testing-library/react"; import { render } from "@testing-library/react";
import React from "react"; import React from "react";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import AppearanceUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/AppearanceUserSettingsTab"; import AppearanceUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/AppearanceUserSettingsTab";
import { stubClient } from "../../../../../test-utils"; import { withClientContextRenderOptions, stubClient } from "../../../../../test-utils";
// Fake random strings to give a predictable snapshot // Fake random strings to give a predictable snapshot
jest.mock("matrix-js-sdk/src/randomstring", () => ({ jest.mock("matrix-js-sdk/src/randomstring", () => ({
@ -26,12 +27,14 @@ jest.mock("matrix-js-sdk/src/randomstring", () => ({
})); }));
describe("AppearanceUserSettingsTab", () => { describe("AppearanceUserSettingsTab", () => {
let client: MatrixClient;
beforeEach(() => { beforeEach(() => {
stubClient(); client = stubClient();
}); });
it("should render", () => { it("should render", () => {
const { asFragment } = render(<AppearanceUserSettingsTab />); const { asFragment } = render(<AppearanceUserSettingsTab />, withClientContextRenderOptions(client));
expect(asFragment()).toMatchSnapshot(); expect(asFragment()).toMatchSnapshot();
}); });
}); });

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from "react"; import React from "react";
import { act, render, RenderResult } from "@testing-library/react"; import { act, render, RenderResult } from "@testing-library/react";
import { filterConsole, stubClient } from "../../../test-utils"; import { filterConsole, withClientContextRenderOptions, stubClient } from "../../../test-utils";
import { UserOnboardingPage } from "../../../../src/components/views/user-onboarding/UserOnboardingPage"; import { UserOnboardingPage } from "../../../../src/components/views/user-onboarding/UserOnboardingPage";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import SdkConfig from "../../../../src/SdkConfig"; import SdkConfig from "../../../../src/SdkConfig";
@ -34,7 +34,7 @@ jest.mock("../../../../src/components/structures/HomePage", () => ({
describe("UserOnboardingPage", () => { describe("UserOnboardingPage", () => {
const renderComponent = async (): Promise<RenderResult> => { const renderComponent = async (): Promise<RenderResult> => {
const renderResult = render(<UserOnboardingPage />); const renderResult = render(<UserOnboardingPage />, withClientContextRenderOptions(MatrixClientPeg.safeGet()));
await act(async () => { await act(async () => {
jest.runAllTimers(); jest.runAllTimers();
}); });

View file

@ -16,6 +16,7 @@ limitations under the License.
import React, { ComponentType, Ref } from "react"; import React, { ComponentType, Ref } from "react";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { RenderOptions } from "@testing-library/react";
import { MatrixClientPeg as peg } from "../../src/MatrixClientPeg"; import { MatrixClientPeg as peg } from "../../src/MatrixClientPeg";
import MatrixClientContext from "../../src/contexts/MatrixClientContext"; import MatrixClientContext from "../../src/contexts/MatrixClientContext";
@ -57,3 +58,15 @@ export function wrapInSdkContext<T>(
} }
}; };
} }
/**
* Test helper to generate React testing library render options for wrapping with a MatrixClientContext.Provider
* @param client the MatrixClient instance to expose via the provider
*/
export function withClientContextRenderOptions(client: MatrixClient): RenderOptions {
return {
wrapper: ({ children }) => (
<MatrixClientContext.Provider value={client}>{children}</MatrixClientContext.Provider>
),
};
}

View file

@ -28,7 +28,7 @@ import {
VoiceBroadcastPlayback, VoiceBroadcastPlayback,
VoiceBroadcastRecordingsStore, VoiceBroadcastRecordingsStore,
} from "../../../src/voice-broadcast"; } from "../../../src/voice-broadcast";
import { stubClient, wrapInSdkContext } from "../../test-utils"; import { withClientContextRenderOptions, stubClient, wrapInSdkContext } from "../../test-utils";
import { mkVoiceBroadcastInfoStateEvent } from "../utils/test-utils"; import { mkVoiceBroadcastInfoStateEvent } from "../utils/test-utils";
import { MediaEventHelper } from "../../../src/utils/MediaEventHelper"; import { MediaEventHelper } from "../../../src/utils/MediaEventHelper";
import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks"; import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks";
@ -66,6 +66,7 @@ describe("VoiceBroadcastBody", () => {
onMessageAllowed={() => {}} onMessageAllowed={() => {}}
permalinkCreator={new RoomPermalinkCreator(room)} permalinkCreator={new RoomPermalinkCreator(room)}
/>, />,
withClientContextRenderOptions(client),
); );
testRecording = SdkContextClass.instance.voiceBroadcastRecordingsStore.getByInfoEvent(infoEvent, client); testRecording = SdkContextClass.instance.voiceBroadcastRecordingsStore.getByInfoEvent(infoEvent, client);
}; };