Enable support for image, video and audio files
This commit is contained in:
parent
409213ceb4
commit
59c1b67b7d
8 changed files with 86 additions and 21 deletions
|
@ -34,6 +34,7 @@ export default class MAudioBody extends React.Component {
|
|||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
onPlayToggle() {
|
||||
this.setState({
|
||||
playing: !this.state.playing,
|
||||
|
@ -41,6 +42,7 @@ export default class MAudioBody extends React.Component {
|
|||
}
|
||||
|
||||
_getContentUrl() {
|
||||
if (this.props.mediaSrc) return this.props.mediaSrc;
|
||||
const media = mediaFromContent(this.props.mxEvent.getContent());
|
||||
if (media.isEncrypted) {
|
||||
return this.state.decryptedUrl;
|
||||
|
@ -49,6 +51,11 @@ export default class MAudioBody extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
getFileBody() {
|
||||
if (this.props.mediaSrc) return null;
|
||||
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const content = this.props.mxEvent.getContent();
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||
|
@ -101,11 +108,11 @@ export default class MAudioBody extends React.Component {
|
|||
}
|
||||
|
||||
const contentUrl = this._getContentUrl();
|
||||
|
||||
const fileBody = this.getFileBody();
|
||||
return (
|
||||
<span className="mx_MAudioBody">
|
||||
<audio src={contentUrl} controls />
|
||||
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />
|
||||
{ fileBody }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ export default class MFileBody extends React.Component {
|
|||
<span className="mx_MFileBody">
|
||||
{placeholder}
|
||||
<div className="mx_MFileBody_download">
|
||||
<div style={{display: "none"}}>
|
||||
<div style={{ display: "none" }}>
|
||||
{ /*
|
||||
* Add dummy copy of the "a" tag
|
||||
* We'll use it to learn how the download link
|
||||
|
@ -309,7 +309,7 @@ export default class MFileBody extends React.Component {
|
|||
if (this.props.tileShape === "file_grid") {
|
||||
return (
|
||||
<span className="mx_MFileBody">
|
||||
{placeholder}
|
||||
{ placeholder }
|
||||
<div className="mx_MFileBody_download">
|
||||
<a className="mx_MFileBody_downloadLink" {...downloadProps}>
|
||||
{ fileName }
|
||||
|
@ -323,7 +323,7 @@ export default class MFileBody extends React.Component {
|
|||
} else {
|
||||
return (
|
||||
<span className="mx_MFileBody">
|
||||
{placeholder}
|
||||
{ placeholder }
|
||||
<div className="mx_MFileBody_download">
|
||||
<a {...downloadProps}>
|
||||
<span className="mx_MFileBody_download_icon" />
|
||||
|
@ -336,7 +336,7 @@ export default class MFileBody extends React.Component {
|
|||
} else {
|
||||
const extra = text ? (': ' + text) : '';
|
||||
return <span className="mx_MFileBody">
|
||||
{placeholder}
|
||||
{ placeholder }
|
||||
{ _t("Invalid file%(extra)s", { extra: extra }) }
|
||||
</span>;
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ export default class MImageBody extends React.Component {
|
|||
|
||||
showImage() {
|
||||
localStorage.setItem("mx_ShowImage_" + this.props.mxEvent.getId(), "true");
|
||||
this.setState({showImage: true});
|
||||
this.setState({ showImage: true });
|
||||
this._downloadImage();
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,7 @@ export default class MImageBody extends React.Component {
|
|||
}
|
||||
|
||||
_getContentUrl() {
|
||||
if (this.props.mediaSrc) return this.props.mediaSrc;
|
||||
const media = mediaFromContent(this.props.mxEvent.getContent());
|
||||
if (media.isEncrypted) {
|
||||
return this.state.decryptedUrl;
|
||||
|
@ -296,7 +297,7 @@ export default class MImageBody extends React.Component {
|
|||
if (showImage) {
|
||||
// Don't download anything becaue we don't want to display anything.
|
||||
this._downloadImage();
|
||||
this.setState({showImage: true});
|
||||
this.setState({ showImage: true });
|
||||
}
|
||||
|
||||
this._afterComponentDidMount();
|
||||
|
@ -345,7 +346,7 @@ export default class MImageBody extends React.Component {
|
|||
imageElement = <HiddenImagePlaceholder />;
|
||||
} else {
|
||||
imageElement = (
|
||||
<img style={{display: 'none'}} src={thumbUrl} ref={this._image}
|
||||
<img style={{ display: 'none' }} src={thumbUrl} ref={this._image}
|
||||
alt={content.body}
|
||||
onError={this.onImageError}
|
||||
onLoad={this.onImageLoad}
|
||||
|
@ -449,6 +450,7 @@ export default class MImageBody extends React.Component {
|
|||
|
||||
// Overidden by MStickerBody
|
||||
getFileBody() {
|
||||
if (this.props.mediaSrc) return null;
|
||||
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />;
|
||||
}
|
||||
|
||||
|
@ -466,7 +468,7 @@ export default class MImageBody extends React.Component {
|
|||
|
||||
const contentUrl = this._getContentUrl();
|
||||
let thumbUrl;
|
||||
if (this._isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) {
|
||||
if ((this._isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) || this.props.mediaSrc) {
|
||||
thumbUrl = contentUrl;
|
||||
} else {
|
||||
thumbUrl = this._getThumbUrl();
|
||||
|
|
|
@ -29,6 +29,8 @@ interface IProps {
|
|||
mxEvent: any;
|
||||
/* called when the video has loaded */
|
||||
onHeightChanged: () => void;
|
||||
/* used to refer to the local file while exporting */
|
||||
mediaSrc?: string;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
@ -76,6 +78,7 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
private getContentUrl(): string|null {
|
||||
if (this.props.mediaSrc) return this.props.mediaSrc;
|
||||
const media = mediaFromContent(this.props.mxEvent.getContent());
|
||||
if (media.isEncrypted) {
|
||||
return this.state.decryptedUrl;
|
||||
|
@ -90,6 +93,9 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
|
||||
private getThumbUrl(): string|null {
|
||||
// there's no need of thumbnail when the content is local
|
||||
if (this.props.mediaSrc) return null;
|
||||
|
||||
const content = this.props.mxEvent.getContent();
|
||||
const media = mediaFromContent(content);
|
||||
if (media.isEncrypted) {
|
||||
|
@ -184,6 +190,11 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
this.props.onHeightChanged();
|
||||
}
|
||||
|
||||
private getFileBody = () => {
|
||||
if (this.props.mediaSrc) return null;
|
||||
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
const content = this.props.mxEvent.getContent();
|
||||
const autoplay = SettingsStore.getValue("autoplayGifsAndVideos");
|
||||
|
@ -197,7 +208,7 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
// Important: If we aren't autoplaying and we haven't decrypred it yet, show a video with a poster.
|
||||
// Important: If we aren't autoplaying and we haven't decrypted it yet, show a video with a poster.
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null && autoplay) {
|
||||
// Need to decrypt the attachment
|
||||
// The attachment is decrypted in componentDidMount.
|
||||
|
@ -229,6 +240,8 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
preload = "none";
|
||||
}
|
||||
}
|
||||
|
||||
const fileBody = this.getFileBody();
|
||||
return (
|
||||
<span className="mx_MVideoBody">
|
||||
<video
|
||||
|
@ -246,7 +259,7 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
|
|||
onPlay={this.videoOnPlay}
|
||||
>
|
||||
</video>
|
||||
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />
|
||||
{ fileBody }
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import MVoiceMessageBody from "./MVoiceMessageBody";
|
|||
|
||||
interface IProps {
|
||||
mxEvent: MatrixEvent;
|
||||
mediaSrc?: string;
|
||||
}
|
||||
|
||||
@replaceableComponent("views.messages.MVoiceOrAudioBody")
|
||||
|
@ -30,7 +31,7 @@ export default class MVoiceOrAudioBody extends React.PureComponent<IProps> {
|
|||
public render() {
|
||||
const isVoiceMessage = !!this.props.mxEvent.getContent()['org.matrix.msc2516.voice'];
|
||||
const voiceMessagesEnabled = SettingsStore.getValue("feature_voice_messages");
|
||||
if (isVoiceMessage && voiceMessagesEnabled) {
|
||||
if (isVoiceMessage && voiceMessagesEnabled && !this.props.mediaSrc) {
|
||||
return <MVoiceMessageBody {...this.props} />;
|
||||
} else {
|
||||
return <MAudioBody {...this.props} />;
|
||||
|
|
|
@ -44,6 +44,9 @@ export default class MessageEvent extends React.Component {
|
|||
/* the shape of the tile, used */
|
||||
tileShape: PropTypes.string,
|
||||
|
||||
/* to set source to local file path during export */
|
||||
mediaSrc: PropTypes.string,
|
||||
|
||||
/* the maximum image height to use, if the event is an image */
|
||||
maxImageHeight: PropTypes.number,
|
||||
|
||||
|
@ -120,6 +123,7 @@ export default class MessageEvent extends React.Component {
|
|||
highlightLink={this.props.highlightLink}
|
||||
showUrlPreview={this.props.showUrlPreview}
|
||||
tileShape={this.props.tileShape}
|
||||
mediaSrc={this.props.mediaSrc}
|
||||
maxImageHeight={this.props.maxImageHeight}
|
||||
replacingEventId={this.props.replacingEventId}
|
||||
editState={this.props.editState}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue