Replace broadcast instance with SDKContext (#9824)

This commit is contained in:
Michael Weimann 2022-12-27 08:39:26 +01:00 committed by GitHub
parent 6c40e2476a
commit 5912c7a637
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 47 additions and 59 deletions

View file

@ -50,11 +50,8 @@ import UserIdentifierCustomisations from "../../customisations/UserIdentifier";
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload"; import { ViewHomePagePayload } from "../../dispatcher/payloads/ViewHomePagePayload";
import { Icon as LiveIcon } from "../../../res/img/element-icons/live.svg"; import { Icon as LiveIcon } from "../../../res/img/element-icons/live.svg";
import { import { VoiceBroadcastRecording, VoiceBroadcastRecordingsStoreEvent } from "../../voice-broadcast";
VoiceBroadcastRecording, import { SDKContext } from "../../contexts/SDKContext";
VoiceBroadcastRecordingsStore,
VoiceBroadcastRecordingsStoreEvent,
} from "../../voice-broadcast";
interface IProps { interface IProps {
isPanelCollapsed: boolean; isPanelCollapsed: boolean;
@ -87,21 +84,24 @@ const below = (rect: PartialDOMRect) => {
}; };
export default class UserMenu extends React.Component<IProps, IState> { export default 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();
private voiceBroadcastRecordingStore = VoiceBroadcastRecordingsStore.instance();
public constructor(props: IProps) { public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
super(props); super(props, context);
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.voiceBroadcastRecordingStore.hasCurrent(), showLiveAvatarAddon: this.context.voiceBroadcastRecordingsStore.hasCurrent(),
}; };
OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate); OwnProfileStore.instance.on(UPDATE_EVENT, this.onProfileUpdate);
@ -119,7 +119,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
}; };
public componentDidMount() { public componentDidMount() {
this.voiceBroadcastRecordingStore.on( this.context.voiceBroadcastRecordingsStore.on(
VoiceBroadcastRecordingsStoreEvent.CurrentChanged, VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
this.onCurrentVoiceBroadcastRecordingChanged, this.onCurrentVoiceBroadcastRecordingChanged,
); );
@ -133,7 +133,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.voiceBroadcastRecordingStore.off( this.context.voiceBroadcastRecordingsStore.off(
VoiceBroadcastRecordingsStoreEvent.CurrentChanged, VoiceBroadcastRecordingsStoreEvent.CurrentChanged,
this.onCurrentVoiceBroadcastRecordingChanged, this.onCurrentVoiceBroadcastRecordingChanged,
); );

View file

@ -54,7 +54,6 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom"; import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
import { Features } from "../../../settings/Settings"; import { Features } from "../../../settings/Settings";
import { VoiceMessageRecording } from "../../../audio/VoiceMessageRecording"; import { VoiceMessageRecording } from "../../../audio/VoiceMessageRecording";
import { VoiceBroadcastRecordingsStore } from "../../../voice-broadcast";
import { SendWysiwygComposer, sendMessage } from "./wysiwyg_composer/"; import { SendWysiwygComposer, sendMessage } from "./wysiwyg_composer/";
import { MatrixClientProps, withMatrixClientHOC } from "../../../contexts/MatrixClientContext"; import { MatrixClientProps, withMatrixClientHOC } from "../../../contexts/MatrixClientContext";
import { htmlToPlainText } from "../../../utils/room/htmlToPlaintext"; import { htmlToPlainText } from "../../../utils/room/htmlToPlaintext";
@ -604,7 +603,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
this.props.room, this.props.room,
MatrixClientPeg.get(), MatrixClientPeg.get(),
SdkContextClass.instance.voiceBroadcastPlaybacksStore, SdkContextClass.instance.voiceBroadcastPlaybacksStore,
VoiceBroadcastRecordingsStore.instance(), SdkContextClass.instance.voiceBroadcastRecordingsStore,
SdkContextClass.instance.voiceBroadcastPreRecordingStore, SdkContextClass.instance.voiceBroadcastPreRecordingStore,
); );
this.toggleButtonMenu(); this.toggleButtonMenu();

View file

@ -158,7 +158,7 @@ export class SdkContextClass {
public get voiceBroadcastRecordingsStore(): VoiceBroadcastRecordingsStore { public get voiceBroadcastRecordingsStore(): VoiceBroadcastRecordingsStore {
if (!this._VoiceBroadcastRecordingsStore) { if (!this._VoiceBroadcastRecordingsStore) {
this._VoiceBroadcastRecordingsStore = VoiceBroadcastRecordingsStore.instance(); this._VoiceBroadcastRecordingsStore = new VoiceBroadcastRecordingsStore();
} }
return this._VoiceBroadcastRecordingsStore; return this._VoiceBroadcastRecordingsStore;
} }
@ -172,7 +172,7 @@ export class SdkContextClass {
public get voiceBroadcastPlaybacksStore(): VoiceBroadcastPlaybacksStore { public get voiceBroadcastPlaybacksStore(): VoiceBroadcastPlaybacksStore {
if (!this._VoiceBroadcastPlaybacksStore) { if (!this._VoiceBroadcastPlaybacksStore) {
this._VoiceBroadcastPlaybacksStore = VoiceBroadcastPlaybacksStore.instance(); this._VoiceBroadcastPlaybacksStore = new VoiceBroadcastPlaybacksStore();
} }
return this._VoiceBroadcastPlaybacksStore; return this._VoiceBroadcastPlaybacksStore;
} }

View file

@ -66,7 +66,6 @@ import { ViewRoomPayload } from "../../dispatcher/payloads/ViewRoomPayload";
import Modal from "../../Modal"; import Modal from "../../Modal";
import ErrorDialog from "../../components/views/dialogs/ErrorDialog"; import ErrorDialog from "../../components/views/dialogs/ErrorDialog";
import { SdkContextClass } from "../../contexts/SDKContext"; import { SdkContextClass } from "../../contexts/SDKContext";
import { VoiceBroadcastRecordingsStore } from "../../voice-broadcast";
// TODO: Destroy all of this code // TODO: Destroy all of this code
@ -292,7 +291,7 @@ export class StopGapWidget extends EventEmitter {
this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal); this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal);
this.messaging.on(`action:${ElementWidgetActions.JoinCall}`, () => { this.messaging.on(`action:${ElementWidgetActions.JoinCall}`, () => {
// pause voice broadcast recording when any widget sends a "join" // pause voice broadcast recording when any widget sends a "join"
VoiceBroadcastRecordingsStore.instance().getCurrent()?.pause(); SdkContextClass.instance.voiceBroadcastRecordingsStore.getCurrent()?.pause();
}); });
// Always attach a handler for ViewRoom, but permission check it internally // Always attach a handler for ViewRoom, but permission check it internally

View file

@ -14,23 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import { MatrixEvent, RelationType } from "matrix-js-sdk/src/matrix"; import { MatrixEvent, RelationType } from "matrix-js-sdk/src/matrix";
import { import {
VoiceBroadcastRecordingBody, VoiceBroadcastRecordingBody,
VoiceBroadcastRecordingsStore,
shouldDisplayAsVoiceBroadcastRecordingTile, shouldDisplayAsVoiceBroadcastRecordingTile,
VoiceBroadcastInfoEventType, VoiceBroadcastInfoEventType,
VoiceBroadcastPlaybacksStore,
VoiceBroadcastPlaybackBody, VoiceBroadcastPlaybackBody,
VoiceBroadcastInfoState, VoiceBroadcastInfoState,
} from ".."; } from "..";
import { IBodyProps } from "../../components/views/messages/IBodyProps"; import { IBodyProps } from "../../components/views/messages/IBodyProps";
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { MatrixClientPeg } from "../../MatrixClientPeg";
import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper"; import { RelationsHelper, RelationsHelperEvent } from "../../events/RelationsHelper";
import { SDKContext } from "../../contexts/SDKContext";
export const VoiceBroadcastBody: React.FC<IBodyProps> = ({ mxEvent }) => { export const VoiceBroadcastBody: React.FC<IBodyProps> = ({ mxEvent }) => {
const sdkContext = useContext(SDKContext);
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
const [infoState, setInfoState] = useState(mxEvent.getContent()?.state || VoiceBroadcastInfoState.Stopped); const [infoState, setInfoState] = useState(mxEvent.getContent()?.state || VoiceBroadcastInfoState.Stopped);
@ -57,10 +57,10 @@ export const VoiceBroadcastBody: React.FC<IBodyProps> = ({ mxEvent }) => {
}); });
if (shouldDisplayAsVoiceBroadcastRecordingTile(infoState, client, mxEvent)) { if (shouldDisplayAsVoiceBroadcastRecordingTile(infoState, client, mxEvent)) {
const recording = VoiceBroadcastRecordingsStore.instance().getByInfoEvent(mxEvent, client); const recording = sdkContext.voiceBroadcastRecordingsStore.getByInfoEvent(mxEvent, client);
return <VoiceBroadcastRecordingBody recording={recording} />; return <VoiceBroadcastRecordingBody recording={recording} />;
} }
const playback = VoiceBroadcastPlaybacksStore.instance().getByInfoEvent(mxEvent, client); const playback = sdkContext.voiceBroadcastPlaybacksStore.getByInfoEvent(mxEvent, client);
return <VoiceBroadcastPlaybackBody playback={playback} />; return <VoiceBroadcastPlaybackBody playback={playback} />;
}; };

View file

@ -114,13 +114,4 @@ export class VoiceBroadcastPlaybacksStore
this.playbacks = new Map(); this.playbacks = new Map();
} }
public static readonly _instance = new VoiceBroadcastPlaybacksStore();
/**
* TODO Michael W: replace when https://github.com/matrix-org/matrix-react-sdk/pull/9293 has been merged
*/
public static instance() {
return VoiceBroadcastPlaybacksStore._instance;
}
} }

View file

@ -82,13 +82,4 @@ export class VoiceBroadcastRecordingsStore extends TypedEventEmitter<VoiceBroadc
this.clearCurrent(); this.clearCurrent();
} }
}; };
private static readonly cachedInstance = new VoiceBroadcastRecordingsStore();
/**
* TODO Michael W: replace when https://github.com/matrix-org/matrix-react-sdk/pull/9293 has been merged
*/
public static instance(): VoiceBroadcastRecordingsStore {
return VoiceBroadcastRecordingsStore.cachedInstance;
}
} }

View file

@ -18,18 +18,20 @@ import React from "react";
import { act, render, RenderResult } from "@testing-library/react"; import { act, render, RenderResult } from "@testing-library/react";
import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix";
import UserMenu from "../../../src/components/structures/UserMenu"; import UnwrappedUserMenu from "../../../src/components/structures/UserMenu";
import { stubClient } from "../../test-utils"; import { stubClient, wrapInSdkContext } from "../../test-utils";
import { import {
VoiceBroadcastInfoState, VoiceBroadcastInfoState,
VoiceBroadcastRecording, VoiceBroadcastRecording,
VoiceBroadcastRecordingsStore, VoiceBroadcastRecordingsStore,
} from "../../../src/voice-broadcast"; } from "../../../src/voice-broadcast";
import { mkVoiceBroadcastInfoStateEvent } from "../../voice-broadcast/utils/test-utils"; import { mkVoiceBroadcastInfoStateEvent } from "../../voice-broadcast/utils/test-utils";
import { TestSdkContext } from "../../TestSdkContext";
describe("<UserMenu>", () => { describe("<UserMenu>", () => {
let client: MatrixClient; let client: MatrixClient;
let renderResult: RenderResult; let renderResult: RenderResult;
let sdkContext: TestSdkContext;
let voiceBroadcastInfoEvent: MatrixEvent; let voiceBroadcastInfoEvent: MatrixEvent;
let voiceBroadcastRecording: VoiceBroadcastRecording; let voiceBroadcastRecording: VoiceBroadcastRecording;
let voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore; let voiceBroadcastRecordingsStore: VoiceBroadcastRecordingsStore;
@ -42,15 +44,19 @@ describe("<UserMenu>", () => {
client.getUserId() || "", client.getUserId() || "",
client.getDeviceId() || "", client.getDeviceId() || "",
); );
voiceBroadcastRecording = new VoiceBroadcastRecording(voiceBroadcastInfoEvent, client);
}); });
beforeEach(() => { beforeEach(() => {
voiceBroadcastRecordingsStore = VoiceBroadcastRecordingsStore.instance(); sdkContext = new TestSdkContext();
voiceBroadcastRecordingsStore = new VoiceBroadcastRecordingsStore();
sdkContext._VoiceBroadcastRecordingsStore = voiceBroadcastRecordingsStore;
voiceBroadcastRecording = new VoiceBroadcastRecording(voiceBroadcastInfoEvent, client);
}); });
describe("when rendered", () => { describe("when rendered", () => {
beforeEach(() => { beforeEach(() => {
const UserMenu = wrapInSdkContext(UnwrappedUserMenu, sdkContext);
renderResult = render(<UserMenu isPanelCollapsed={true} />); renderResult = render(<UserMenu isPanelCollapsed={true} />);
}); });

View file

@ -19,11 +19,13 @@ import { render, screen, fireEvent } from "@testing-library/react";
import { mocked } from "jest-mock"; import { mocked } from "jest-mock";
import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixClient } from "matrix-js-sdk/src/matrix";
import SpacePanel from "../../../../src/components/views/spaces/SpacePanel"; import UnwrappedSpacePanel from "../../../../src/components/views/spaces/SpacePanel";
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg"; import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
import { SpaceKey } from "../../../../src/stores/spaces"; import { SpaceKey } from "../../../../src/stores/spaces";
import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents"; import { shouldShowComponent } from "../../../../src/customisations/helpers/UIComponents";
import { UIComponent } from "../../../../src/settings/UIFeature"; import { UIComponent } from "../../../../src/settings/UIFeature";
import { wrapInSdkContext } from "../../../test-utils";
import { SdkContextClass } from "../../../../src/contexts/SDKContext";
jest.mock("../../../../src/stores/spaces/SpaceStore", () => { jest.mock("../../../../src/stores/spaces/SpaceStore", () => {
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
@ -49,6 +51,7 @@ describe("<SpacePanel />", () => {
isGuest: jest.fn(), isGuest: jest.fn(),
getAccountData: jest.fn(), getAccountData: jest.fn(),
} as unknown as MatrixClient; } as unknown as MatrixClient;
const SpacePanel = wrapInSdkContext(UnwrappedSpacePanel, SdkContextClass.instance);
beforeAll(() => { beforeAll(() => {
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient); jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);

View file

@ -1,5 +1,5 @@
/* /*
Copyright 2022 The Matrix.org Foundation C.I.C. Copyright 2022 The Matrix.org Foundation C.I.C
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -23,11 +23,8 @@ import { stubClient, mkRoom, mkEvent } from "../../test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg"; import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
import { StopGapWidget } from "../../../src/stores/widgets/StopGapWidget"; import { StopGapWidget } from "../../../src/stores/widgets/StopGapWidget";
import { ElementWidgetActions } from "../../../src/stores/widgets/ElementWidgetActions"; import { ElementWidgetActions } from "../../../src/stores/widgets/ElementWidgetActions";
import { import { VoiceBroadcastInfoEventType, VoiceBroadcastRecording } from "../../../src/voice-broadcast";
VoiceBroadcastInfoEventType, import { SdkContextClass } from "../../../src/contexts/SDKContext";
VoiceBroadcastRecording,
VoiceBroadcastRecordingsStore,
} from "../../../src/voice-broadcast";
jest.mock("matrix-widget-api/lib/ClientWidgetApi"); jest.mock("matrix-widget-api/lib/ClientWidgetApi");
@ -90,7 +87,9 @@ describe("StopGapWidget", () => {
}); });
voiceBroadcastRecording = new VoiceBroadcastRecording(voiceBroadcastInfoEvent, client); voiceBroadcastRecording = new VoiceBroadcastRecording(voiceBroadcastInfoEvent, client);
jest.spyOn(voiceBroadcastRecording, "pause"); jest.spyOn(voiceBroadcastRecording, "pause");
jest.spyOn(VoiceBroadcastRecordingsStore.instance(), "getCurrent").mockReturnValue(voiceBroadcastRecording); jest.spyOn(SdkContextClass.instance.voiceBroadcastRecordingsStore, "getCurrent").mockReturnValue(
voiceBroadcastRecording,
);
}); });
describe(`and receiving a action:${ElementWidgetActions.JoinCall} message`, () => { describe(`and receiving a action:${ElementWidgetActions.JoinCall} message`, () => {

View file

@ -20,19 +20,18 @@ import { mocked } from "jest-mock";
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { import {
VoiceBroadcastBody, VoiceBroadcastBody as UnwrappedVoiceBroadcastBody,
VoiceBroadcastInfoState, VoiceBroadcastInfoState,
VoiceBroadcastRecordingBody, VoiceBroadcastRecordingBody,
VoiceBroadcastRecordingsStore,
VoiceBroadcastRecording, VoiceBroadcastRecording,
VoiceBroadcastPlaybackBody, VoiceBroadcastPlaybackBody,
VoiceBroadcastPlayback, VoiceBroadcastPlayback,
VoiceBroadcastPlaybacksStore,
} from "../../../src/voice-broadcast"; } from "../../../src/voice-broadcast";
import { stubClient } from "../../test-utils"; import { 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";
import { SdkContextClass } from "../../../src/contexts/SDKContext";
jest.mock("../../../src/voice-broadcast/components/molecules/VoiceBroadcastRecordingBody", () => ({ jest.mock("../../../src/voice-broadcast/components/molecules/VoiceBroadcastRecordingBody", () => ({
VoiceBroadcastRecordingBody: jest.fn(), VoiceBroadcastRecordingBody: jest.fn(),
@ -57,6 +56,7 @@ describe("VoiceBroadcastBody", () => {
let testPlayback: VoiceBroadcastPlayback; let testPlayback: VoiceBroadcastPlayback;
const renderVoiceBroadcast = () => { const renderVoiceBroadcast = () => {
const VoiceBroadcastBody = wrapInSdkContext(UnwrappedVoiceBroadcastBody, SdkContextClass.instance);
render( render(
<VoiceBroadcastBody <VoiceBroadcastBody
mxEvent={infoEvent} mxEvent={infoEvent}
@ -66,7 +66,7 @@ describe("VoiceBroadcastBody", () => {
permalinkCreator={new RoomPermalinkCreator(room)} permalinkCreator={new RoomPermalinkCreator(room)}
/>, />,
); );
testRecording = VoiceBroadcastRecordingsStore.instance().getByInfoEvent(infoEvent, client); testRecording = SdkContextClass.instance.voiceBroadcastRecordingsStore.getByInfoEvent(infoEvent, client);
}; };
beforeEach(() => { beforeEach(() => {
@ -108,7 +108,7 @@ describe("VoiceBroadcastBody", () => {
return null; return null;
}); });
jest.spyOn(VoiceBroadcastRecordingsStore.instance(), "getByInfoEvent").mockImplementation( jest.spyOn(SdkContextClass.instance.voiceBroadcastRecordingsStore, "getByInfoEvent").mockImplementation(
(getEvent: MatrixEvent, getClient: MatrixClient): VoiceBroadcastRecording => { (getEvent: MatrixEvent, getClient: MatrixClient): VoiceBroadcastRecording => {
if (getEvent === infoEvent && getClient === client) { if (getEvent === infoEvent && getClient === client) {
return testRecording; return testRecording;
@ -118,7 +118,7 @@ describe("VoiceBroadcastBody", () => {
}, },
); );
jest.spyOn(VoiceBroadcastPlaybacksStore.instance(), "getByInfoEvent").mockImplementation( jest.spyOn(SdkContextClass.instance.voiceBroadcastPlaybacksStore, "getByInfoEvent").mockImplementation(
(getEvent: MatrixEvent): VoiceBroadcastPlayback => { (getEvent: MatrixEvent): VoiceBroadcastPlayback => {
if (getEvent === infoEvent) { if (getEvent === infoEvent) {
return testPlayback; return testPlayback;