From eba8b0f5bacb6762146eda9075e4f4e3e8e54e81 Mon Sep 17 00:00:00 2001 From: Tulir Asokan <tulir@maunium.net> Date: Tue, 12 Jul 2022 15:34:57 +0300 Subject: Add support for rendering captions in media messages --- src/components/views/messages/IBodyProps.ts | 2 ++ src/components/views/messages/MessageEvent.tsx | 15 +++++++++++++++ src/components/views/messages/TextualBody.tsx | 11 +++++++++++ src/utils/FileUtils.ts | 4 +++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/components/views/messages/IBodyProps.ts b/src/components/views/messages/IBodyProps.ts index e48ba96b56..3caeff225c 100644 --- a/src/components/views/messages/IBodyProps.ts +++ b/src/components/views/messages/IBodyProps.ts @@ -51,4 +51,6 @@ export interface IBodyProps { // Set to `true` to disable interactions (e.g. video controls) and to remove controls from the tab order. // This may be useful when displaying a preview of the event. inhibitInteraction?: boolean; + + OrigBodyType?: React.ComponentType<Partial<IBodyProps>>; } diff --git a/src/components/views/messages/MessageEvent.tsx b/src/components/views/messages/MessageEvent.tsx index 1a5d09e415..bfe908aacc 100644 --- a/src/components/views/messages/MessageEvent.tsx +++ b/src/components/views/messages/MessageEvent.tsx @@ -175,6 +175,15 @@ export default class MessageEvent extends React.Component<IProps> implements IMe } } + // @ts-ignore + const hasCaption = [MsgType.Image, MsgType.File, MsgType.Audio, MsgType.Video].includes(msgtype) + && content.filename && content.filename !== content.body; + let OrigBodyType; + if (hasCaption) { + OrigBodyType = BodyType + BodyType = CaptionBody + } + if (SettingsStore.getValue("feature_mjolnir")) { const key = `mx_mjolnir_render_${this.props.mxEvent.getRoomId()}__${this.props.mxEvent.getId()}`; const allowRender = localStorage.getItem(key) === "true"; @@ -208,7 +217,13 @@ export default class MessageEvent extends React.Component<IProps> implements IMe getRelationsForEvent={this.props.getRelationsForEvent} isSeeingThroughMessageHiddenForModeration={this.props.isSeeingThroughMessageHiddenForModeration} inhibitInteraction={this.props.inhibitInteraction} + OrigBodyType={OrigBodyType} /> ) : null; } } + +const CaptionBody: React.FunctionComponent<IBodyProps & {OrigBodyType: React.ComponentType<Partial<IBodyProps>>}> = ({OrigBodyType, ...props}) => (<div className="mx_EventTile_content"> + <OrigBodyType {...props}/> + <TextualBody {...{...props, ref: undefined}}/> +</div>) diff --git a/src/components/views/messages/TextualBody.tsx b/src/components/views/messages/TextualBody.tsx index 8b7bfb9a5a..a8890303f8 100644 --- a/src/components/views/messages/TextualBody.tsx +++ b/src/components/views/messages/TextualBody.tsx @@ -557,6 +557,9 @@ export default class TextualBody extends React.Component<IBodyProps, IState> { const isNotice = content.msgtype === MsgType.Notice; const isEmote = content.msgtype === MsgType.Emote; + // @ts-ignore + const isCaption = [MsgType.Image, MsgType.File, MsgType.Audio, MsgType.Video].includes(content.msgtype); + const willHaveWrapper = this.props.replacingEventId || this.props.isSeeingThroughMessageHiddenForModeration || isEmote; @@ -635,6 +638,14 @@ export default class TextualBody extends React.Component<IBodyProps, IState> { </div> ); } + if (isCaption) { + return ( + <div className="mx_MTextBody mx_EventTile_caption" onClick={this.onBodyLinkClick}> + { body } + { widgets } + </div> + ); + } return ( <div className="mx_MTextBody mx_EventTile_content" onClick={this.onBodyLinkClick}> {body} diff --git a/src/utils/FileUtils.ts b/src/utils/FileUtils.ts index 194cb31d20..0c0aec2138 100644 --- a/src/utils/FileUtils.ts +++ b/src/utils/FileUtils.ts @@ -38,7 +38,9 @@ export function presentableTextForFile( shortened = false, ): string { let text = fallbackText; - if (content.body?.length) { + if (content.filename?.length) { + text = content.filename + } else if (content.body?.length) { // The content body should be the name of the file including a // file extension. text = content.body; -- 2.46.2