Refactor and Move RedactedBodyView To Shared Components (#32772)
* refactoring and creation of shared-components for reductedBodyView * move redacted message rendering to shared MVVM view * Update snapshots + fix lint errors * Remove MatrixClientPeg and use reguler react matrix client context * Stop resyncing redacted body view models with mxEvent * Fix redacted_because test fixtures for stricter event typing * Simplify redacted body client access * Watch timestamp setting in redacted body view model * Refactor redacted and decryption failure body factories into MBodyFactory * Prettier Fix * Refactor FileBody into same pattern for consitancy
This commit is contained in:
@@ -16,12 +16,12 @@ import { editBodyDiffToHtml } from "../../../utils/MessageDiffUtils";
|
||||
import { formatTime } from "../../../DateUtils";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import Modal from "../../../Modal";
|
||||
import RedactedBody from "./RedactedBody";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import ConfirmAndWaitRedactDialog from "../dialogs/ConfirmAndWaitRedactDialog";
|
||||
import ViewSource from "../../structures/ViewSource";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { RedactedBodyFactory } from "./MBodyFactory";
|
||||
|
||||
function getReplacedContent(event: MatrixEvent): IContent {
|
||||
const originalContent = event.getOriginalContent();
|
||||
@@ -151,7 +151,7 @@ export default class EditHistoryMessage extends React.PureComponent<IProps, ISta
|
||||
const content = getReplacedContent(mxEvent);
|
||||
let contentContainer;
|
||||
if (mxEvent.isRedacted()) {
|
||||
contentContainer = <RedactedBody mxEvent={this.props.mxEvent} />;
|
||||
contentContainer = <RedactedBodyFactory mxEvent={this.props.mxEvent} />;
|
||||
} else {
|
||||
let contentElements;
|
||||
if (this.props.previousEdit) {
|
||||
|
||||
@@ -25,6 +25,8 @@ export interface IBodyProps {
|
||||
|
||||
showUrlPreview?: boolean;
|
||||
forExport?: boolean;
|
||||
// Whether file-style rendering should show the info row / placeholder.
|
||||
showFileInfo?: boolean;
|
||||
maxImageHeight?: number;
|
||||
replacingEventId?: string;
|
||||
editState?: EditorStateTransfer;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { PlaybackManager } from "../../../audio/PlaybackManager";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import MediaProcessingError from "./shared/MediaProcessingError";
|
||||
import { AudioPlayerViewModel } from "../../../viewmodels/audio/AudioPlayerViewModel";
|
||||
import { FileBodyViewFactory, renderMBody } from "./MBodyFactory";
|
||||
import { FileBodyFactory, renderMBody } from "./MBodyFactory";
|
||||
|
||||
interface IState {
|
||||
error?: boolean;
|
||||
@@ -111,7 +111,7 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
|
||||
return (
|
||||
<span className="mx_MAudioBody">
|
||||
<AudioPlayer playback={this.state.playback} mediaName={this.props.mxEvent.getContent().body} />
|
||||
{this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyViewFactory)}
|
||||
{this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyFactory)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,30 +7,28 @@ Please see LICENSE files in the repository root for full details.
|
||||
|
||||
import React, { type JSX, type RefObject, useContext, useEffect, useRef } from "react";
|
||||
import { MsgType } from "matrix-js-sdk/src/matrix";
|
||||
import { FileBodyView, useCreateAutoDisposedViewModel } from "@element-hq/web-shared-components";
|
||||
import {
|
||||
DecryptionFailureBodyView,
|
||||
FileBodyView,
|
||||
RedactedBodyView,
|
||||
useCreateAutoDisposedViewModel,
|
||||
} from "@element-hq/web-shared-components";
|
||||
|
||||
import { type IBodyProps } from "./IBodyProps";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import { LocalDeviceVerificationStateContext } from "../../../contexts/LocalDeviceVerificationStateContext";
|
||||
import { DecryptionFailureBodyViewModel } from "../../../viewmodels/message-body/DecryptionFailureBodyViewModel";
|
||||
import { FileBodyViewModel } from "../../../viewmodels/message-body/FileBodyViewModel";
|
||||
import { RedactedBodyViewModel } from "../../../viewmodels/message-body/RedactedBodyViewModel";
|
||||
|
||||
interface FileBodyViewProps {
|
||||
/*
|
||||
* Whether file-style message bodies should render their info row/placeholder.
|
||||
* Used by file-body rendering paths (for example FileBodyViewModel via MBodyFactory).
|
||||
*/
|
||||
showFileInfo?: boolean;
|
||||
}
|
||||
type MBodyComponent = React.ComponentType<IBodyProps>;
|
||||
|
||||
type MBodyComponent = React.ComponentType<IBodyProps & FileBodyViewProps>;
|
||||
|
||||
// Adapter that binds RoomContext data and lifecycle updates to the
|
||||
// FileBody view model before rendering the shared view component.
|
||||
function FileBodyViewWrapped({
|
||||
export function FileBodyFactory({
|
||||
mxEvent,
|
||||
mediaEventHelper,
|
||||
forExport,
|
||||
showFileInfo,
|
||||
}: IBodyProps & FileBodyViewProps): JSX.Element {
|
||||
}: Pick<IBodyProps, "mxEvent" | "mediaEventHelper" | "forExport" | "showFileInfo">): JSX.Element {
|
||||
const { timelineRenderingType } = useContext(RoomContext);
|
||||
const refIFrame = useRef<HTMLIFrameElement>(null) as RefObject<HTMLIFrameElement>;
|
||||
const refLink = useRef<HTMLAnchorElement>(null) as RefObject<HTMLAnchorElement>;
|
||||
@@ -61,19 +59,41 @@ function FileBodyViewWrapped({
|
||||
return <FileBodyView vm={vm} refIFrame={refIFrame} refLink={refLink} className="mx_MFileBody" />;
|
||||
}
|
||||
|
||||
// Exported for explicit fallback usage where callers want file-body rendering.
|
||||
export const FileBodyViewFactory: MBodyComponent = (props) => <FileBodyViewWrapped {...props} />;
|
||||
export function RedactedBodyFactory({ mxEvent, ref }: Pick<IBodyProps, "mxEvent" | "ref">): JSX.Element {
|
||||
const vm = useCreateAutoDisposedViewModel(() => new RedactedBodyViewModel({ mxEvent }));
|
||||
|
||||
useEffect(() => {
|
||||
vm.setEvent(mxEvent);
|
||||
}, [mxEvent, vm]);
|
||||
|
||||
return <RedactedBodyView vm={vm} ref={ref} className="mx_RedactedBody" />;
|
||||
}
|
||||
|
||||
export function DecryptionFailureBodyFactory({ mxEvent, ref }: Pick<IBodyProps, "mxEvent" | "ref">): JSX.Element {
|
||||
const verificationState = useContext(LocalDeviceVerificationStateContext);
|
||||
const vm = useCreateAutoDisposedViewModel(
|
||||
() =>
|
||||
new DecryptionFailureBodyViewModel({
|
||||
decryptionFailureCode: mxEvent.decryptionFailureReason,
|
||||
verificationState,
|
||||
}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
vm.setDecryptionFailureCode(mxEvent.decryptionFailureReason);
|
||||
vm.setVerificationState(verificationState);
|
||||
}, [mxEvent, verificationState, vm]);
|
||||
|
||||
return <DecryptionFailureBodyView vm={vm} ref={ref} className="mx_DecryptionFailureBody mx_EventTile_content" />;
|
||||
}
|
||||
|
||||
// Message body factory registry.
|
||||
// Start small: only m.file currently routes to the new FileBodyView path.
|
||||
const MESSAGE_BODY_TYPES = new Map<string, MBodyComponent>([[MsgType.File, FileBodyViewFactory]]);
|
||||
const MESSAGE_BODY_TYPES = new Map<string, MBodyComponent>([[MsgType.File, FileBodyFactory]]);
|
||||
|
||||
// Render a body using the picked factory.
|
||||
// Falls back to the provided factory when msgtype has no specific handler.
|
||||
export function renderMBody(
|
||||
props: IBodyProps & FileBodyViewProps,
|
||||
fallbackFactory?: MBodyComponent,
|
||||
): JSX.Element | null {
|
||||
export function renderMBody(props: IBodyProps, fallbackFactory?: MBodyComponent): JSX.Element | null {
|
||||
const BodyType = MESSAGE_BODY_TYPES.get(props.mxEvent.getContent().msgtype as string) ?? fallbackFactory;
|
||||
if (!BodyType) {
|
||||
return null;
|
||||
|
||||
@@ -36,7 +36,7 @@ import { DecryptError, DownloadError } from "../../../utils/DecryptFile";
|
||||
import { HiddenMediaPlaceholder } from "./HiddenMediaPlaceholder";
|
||||
import { useMediaVisible } from "../../../hooks/useMediaVisible";
|
||||
import { isMimeTypeAllowed } from "../../../utils/blobs.ts";
|
||||
import { FileBodyViewFactory, renderMBody } from "./MBodyFactory";
|
||||
import { FileBodyFactory, renderMBody } from "./MBodyFactory";
|
||||
|
||||
enum Placeholder {
|
||||
NoImage,
|
||||
@@ -651,7 +651,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {
|
||||
this.context.timelineRenderingType === TimelineRenderingType.Thread ||
|
||||
this.context.timelineRenderingType === TimelineRenderingType.ThreadsList;
|
||||
if (!hasMessageActionBar) {
|
||||
return renderMBody({ ...this.props, showFileInfo: false }, FileBodyViewFactory);
|
||||
return renderMBody({ ...this.props, showFileInfo: false }, FileBodyFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ export class MImageBodyInner extends React.Component<IProps, IState> {
|
||||
!isMimeTypeAllowed(content.info?.mimetype ?? "") &&
|
||||
!content.info?.thumbnail_info
|
||||
) {
|
||||
return renderMBody(this.props, FileBodyViewFactory);
|
||||
return renderMBody(this.props, FileBodyFactory);
|
||||
}
|
||||
|
||||
if (this.state.error) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContex
|
||||
import MediaProcessingError from "./shared/MediaProcessingError";
|
||||
import { HiddenMediaPlaceholder } from "./HiddenMediaPlaceholder";
|
||||
import { useMediaVisible } from "../../../hooks/useMediaVisible";
|
||||
import { FileBodyViewFactory, renderMBody } from "./MBodyFactory";
|
||||
import { FileBodyFactory, renderMBody } from "./MBodyFactory";
|
||||
|
||||
interface IState {
|
||||
decryptedUrl: string | null;
|
||||
@@ -246,7 +246,7 @@ class MVideoBodyInner extends React.PureComponent<IProps, IState> {
|
||||
|
||||
private getFileBody = (): ReactNode => {
|
||||
if (this.props.forExport) return null;
|
||||
return this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyViewFactory);
|
||||
return this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyFactory);
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { isVoiceMessage } from "../../../utils/EventUtils";
|
||||
import { PlaybackQueue } from "../../../audio/PlaybackQueue";
|
||||
import { type Playback } from "../../../audio/Playback";
|
||||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import { FileBodyViewFactory, renderMBody } from "./MBodyFactory";
|
||||
import { FileBodyFactory, renderMBody } from "./MBodyFactory";
|
||||
|
||||
export default class MVoiceMessageBody extends MAudioBody {
|
||||
public static contextType = RoomContext;
|
||||
@@ -54,7 +54,7 @@ export default class MVoiceMessageBody extends MAudioBody {
|
||||
return (
|
||||
<span className="mx_MVoiceMessageBody">
|
||||
<RecordingPlayback playback={this.state.playback} />
|
||||
{this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyViewFactory)}
|
||||
{this.showFileBody && renderMBody({ ...this.props, showFileInfo: false }, FileBodyFactory)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import mime from "mime";
|
||||
import React, { type JSX, createRef, useContext, useEffect } from "react";
|
||||
import React, { createRef } from "react";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import {
|
||||
EventType,
|
||||
@@ -18,12 +18,9 @@ import {
|
||||
M_POLL_START,
|
||||
type IContent,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { useCreateAutoDisposedViewModel, DecryptionFailureBodyView } from "@element-hq/web-shared-components";
|
||||
|
||||
import { LocalDeviceVerificationStateContext } from "../../../contexts/LocalDeviceVerificationStateContext";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { Mjolnir } from "../../../mjolnir/Mjolnir";
|
||||
import RedactedBody from "./RedactedBody";
|
||||
import UnknownBody from "./UnknownBody";
|
||||
import { type IMediaBody } from "./IMediaBody";
|
||||
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
|
||||
@@ -38,8 +35,7 @@ import MLocationBody from "./MLocationBody";
|
||||
import MjolnirBody from "./MjolnirBody";
|
||||
import MBeaconBody from "./MBeaconBody";
|
||||
import { type GetRelationsForEvent, type IEventTileOps } from "../rooms/EventTile";
|
||||
import { DecryptionFailureBodyViewModel } from "../../../viewmodels/message-body/DecryptionFailureBodyViewModel";
|
||||
import { FileBodyViewFactory, renderMBody } from "./MBodyFactory";
|
||||
import { DecryptionFailureBodyFactory, FileBodyFactory, RedactedBodyFactory, renderMBody } from "./MBodyFactory";
|
||||
|
||||
// onMessageAllowed is handled internally
|
||||
interface IProps extends Omit<IBodyProps, "onMessageAllowed" | "mediaEventHelper"> {
|
||||
@@ -67,7 +63,7 @@ const baseBodyTypes = new Map<string, React.ComponentType<IBodyProps>>([
|
||||
[MsgType.Notice, TextualBody],
|
||||
[MsgType.Emote, TextualBody],
|
||||
[MsgType.Image, MImageBody],
|
||||
[MsgType.File, (props: IBodyProps) => renderMBody(props, FileBodyViewFactory)!],
|
||||
[MsgType.File, (props: IBodyProps) => renderMBody(props, FileBodyFactory)!],
|
||||
[MsgType.Audio, MVoiceOrAudioBody],
|
||||
[MsgType.Video, MVideoBody],
|
||||
]);
|
||||
@@ -246,11 +242,11 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
|
||||
const content = this.props.mxEvent.getContent();
|
||||
const type = this.props.mxEvent.getType();
|
||||
const msgtype = content.msgtype;
|
||||
let BodyType: React.ComponentType<IBodyProps> = RedactedBody;
|
||||
let BodyType: React.ComponentType<IBodyProps> = RedactedBodyFactory;
|
||||
if (!this.props.mxEvent.isRedacted()) {
|
||||
// only resolve BodyType if event is not redacted
|
||||
if (this.props.mxEvent.isDecryptionFailure()) {
|
||||
BodyType = DecryptionFailureBodyWrapper;
|
||||
BodyType = DecryptionFailureBodyFactory;
|
||||
} else if (type && this.evTypes.has(type)) {
|
||||
BodyType = this.evTypes.get(type)!;
|
||||
} else if (msgtype && this.bodyTypes.has(msgtype)) {
|
||||
@@ -330,22 +326,3 @@ const CaptionBody: React.FunctionComponent<IBodyProps & { WrappedBodyType: React
|
||||
<TextualBody {...{ ...props, ref: undefined }} />
|
||||
</div>
|
||||
);
|
||||
|
||||
/**
|
||||
* Bridge decryption-failure events into the view model using current local verification state.
|
||||
* This wrapper can be removed after MessageEvent has been changed to a function component.
|
||||
*/
|
||||
function DecryptionFailureBodyWrapper({ mxEvent, ref }: IBodyProps): JSX.Element {
|
||||
const verificationState = useContext(LocalDeviceVerificationStateContext);
|
||||
const vm = useCreateAutoDisposedViewModel(
|
||||
() =>
|
||||
new DecryptionFailureBodyViewModel({
|
||||
decryptionFailureCode: mxEvent.decryptionFailureReason,
|
||||
verificationState,
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
vm.setVerificationState(verificationState);
|
||||
}, [verificationState, vm]);
|
||||
return <DecryptionFailureBodyView vm={vm} ref={ref} className="mx_DecryptionFailureBody mx_EventTile_content" />;
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import React, { useContext, type JSX } from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { DeleteIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { formatFullDate } from "../../../DateUtils";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { type IBodyProps } from "./IBodyProps";
|
||||
|
||||
const RedactedBody = ({ mxEvent, ref }: IBodyProps): JSX.Element => {
|
||||
const cli: MatrixClient = useContext(MatrixClientContext);
|
||||
let text = _t("timeline|self_redaction");
|
||||
const unsigned = mxEvent.getUnsigned();
|
||||
const redactedBecauseUserId = unsigned && unsigned.redacted_because && unsigned.redacted_because.sender;
|
||||
if (redactedBecauseUserId && redactedBecauseUserId !== mxEvent.getSender()) {
|
||||
const room = cli.getRoom(mxEvent.getRoomId());
|
||||
const sender = room && room.getMember(redactedBecauseUserId);
|
||||
text = _t("timeline|redaction", { name: sender ? sender.name : redactedBecauseUserId });
|
||||
}
|
||||
|
||||
const showTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
|
||||
const fullDate = unsigned.redacted_because
|
||||
? formatFullDate(new Date(unsigned.redacted_because.origin_server_ts), showTwelveHour)
|
||||
: undefined;
|
||||
const titleText = fullDate ? _t("timeline|redacted|tooltip", { date: fullDate }) : undefined;
|
||||
|
||||
return (
|
||||
<span className="mx_RedactedBody" ref={ref} title={titleText}>
|
||||
<DeleteIcon />
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default RedactedBody;
|
||||
@@ -50,7 +50,6 @@ import { uniqueId, uniqBy } from "lodash";
|
||||
import { CircleIcon, CheckCircleIcon, ThreadsIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||
import {
|
||||
useCreateAutoDisposedViewModel,
|
||||
DecryptionFailureBodyView,
|
||||
MessageTimestampView,
|
||||
PinnedMessageBadge,
|
||||
ReactionsRowButtonView,
|
||||
@@ -58,7 +57,6 @@ import {
|
||||
useViewModel,
|
||||
} from "@element-hq/web-shared-components";
|
||||
|
||||
import { LocalDeviceVerificationStateContext } from "../../../contexts/LocalDeviceVerificationStateContext";
|
||||
import ReplyChain from "../elements/ReplyChain";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
@@ -88,7 +86,6 @@ import { MediaEventHelper } from "../../../utils/MediaEventHelper";
|
||||
import { type ButtonEvent } from "../elements/AccessibleButton";
|
||||
import { copyPlaintext } from "../../../utils/strings";
|
||||
import { DecryptionFailureTracker } from "../../../DecryptionFailureTracker";
|
||||
import RedactedBody from "../messages/RedactedBody";
|
||||
import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { shouldDisplayReply } from "../../../utils/Reply";
|
||||
import PosthogTrackers from "../../../PosthogTrackers";
|
||||
@@ -105,7 +102,6 @@ import { Icon as LateIcon } from "../../../../res/img/sensor.svg";
|
||||
import PinningUtils from "../../../utils/PinningUtils";
|
||||
import { EventPreview } from "./EventPreview";
|
||||
import { ElementCallEventType } from "../../../call-types";
|
||||
import { DecryptionFailureBodyViewModel } from "../../../viewmodels/message-body/DecryptionFailureBodyViewModel";
|
||||
import { E2eMessageSharedIcon } from "./EventTile/E2eMessageSharedIcon.tsx";
|
||||
import { E2ePadlock, E2ePadlockIcon } from "./EventTile/E2ePadlock.tsx";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
@@ -116,6 +112,7 @@ import {
|
||||
import { ReactionsRowButtonViewModel } from "../../../viewmodels/message-body/ReactionsRowButtonViewModel";
|
||||
import { MAX_ITEMS_WHEN_LIMITED, ReactionsRowViewModel } from "../../../viewmodels/message-body/ReactionsRowViewModel";
|
||||
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
||||
import { DecryptionFailureBodyFactory, RedactedBodyFactory } from "../messages/MBodyFactory";
|
||||
|
||||
export type GetRelationsForEvent = (
|
||||
eventId: string,
|
||||
@@ -1401,9 +1398,9 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
||||
<div className={lineClasses} key="mx_EventTile_line">
|
||||
<div className="mx_EventTile_body">
|
||||
{this.props.mxEvent.isRedacted() ? (
|
||||
<RedactedBody mxEvent={this.props.mxEvent} />
|
||||
<RedactedBodyFactory mxEvent={this.props.mxEvent} />
|
||||
) : this.props.mxEvent.isDecryptionFailure() ? (
|
||||
<DecryptionFailureBodyWrapper mxEvent={this.props.mxEvent} />
|
||||
<DecryptionFailureBodyFactory mxEvent={this.props.mxEvent} />
|
||||
) : (
|
||||
<EventPreview mxEvent={this.props.mxEvent} />
|
||||
)}
|
||||
@@ -1600,26 +1597,6 @@ function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge decryption-failure events into the view model using current local verification state.
|
||||
* This wrapper can be removed after EventTile has been changed to a function component.
|
||||
*/
|
||||
function DecryptionFailureBodyWrapper({ mxEvent }: { mxEvent: MatrixEvent }): JSX.Element {
|
||||
const verificationState = useContext(LocalDeviceVerificationStateContext);
|
||||
const vm = useCreateAutoDisposedViewModel(
|
||||
() =>
|
||||
new DecryptionFailureBodyViewModel({
|
||||
decryptionFailureCode: mxEvent.decryptionFailureReason,
|
||||
verificationState,
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
vm.setVerificationState(verificationState);
|
||||
}, [verificationState, vm]);
|
||||
|
||||
return <DecryptionFailureBodyView vm={vm} className="mx_DecryptionFailureBody mx_EventTile_content" />;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps MessageTimestampView with a view model synced to the provided props.
|
||||
* This wrapper can be removed after EventTile has been changed to a function component.
|
||||
|
||||
@@ -26,7 +26,7 @@ import { renderReplyTile } from "../../../events/EventTileFactory";
|
||||
import { type GetRelationsForEvent } from "../rooms/EventTile";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { type IBodyProps } from "../messages/IBodyProps";
|
||||
import { FileBodyViewFactory, renderMBody } from "../messages/MBodyFactory";
|
||||
import { FileBodyFactory, renderMBody } from "../messages/MBodyFactory";
|
||||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
@@ -130,7 +130,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
|
||||
);
|
||||
}
|
||||
|
||||
const ReplyTileFileBody: React.ComponentType<IBodyProps> = (props) => renderMBody(props, FileBodyViewFactory);
|
||||
const ReplyTileFileBody: React.ComponentType<IBodyProps> = (props) => renderMBody(props, FileBodyFactory);
|
||||
|
||||
const msgtypeOverrides: Record<string, React.ComponentType<IBodyProps>> = {
|
||||
[MsgType.Image]: MImageReplyBody,
|
||||
|
||||
Reference in New Issue
Block a user