Merge remote-tracking branch 'upstream/develop' into fix/file-label-behaviour
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
commit
e8760736ba
327 changed files with 4637 additions and 3095 deletions
|
@ -1,6 +1,5 @@
|
|||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2015 - 2021 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2018, 2019 Michael Telatynski <7t3chguy@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -21,7 +20,6 @@ import { Blurhash } from "react-blurhash";
|
|||
|
||||
import MFileBody from './MFileBody';
|
||||
import Modal from '../../../Modal';
|
||||
import { decryptFile } from '../../../utils/DecryptFile';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
|
@ -29,24 +27,10 @@ import InlineSpinner from '../elements/InlineSpinner';
|
|||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import { mediaFromContent } from "../../../customisations/Media";
|
||||
import { BLURHASH_FIELD } from "../../../ContentMessages";
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
|
||||
import { IMediaEventContent } from '../../../customisations/models/IMediaEventContent';
|
||||
import ImageView from '../elements/ImageView';
|
||||
import { SyncState } from 'matrix-js-sdk/src/sync.api';
|
||||
|
||||
export interface IProps {
|
||||
/* the MatrixEvent to show */
|
||||
mxEvent: MatrixEvent;
|
||||
/* called when the image has loaded */
|
||||
onHeightChanged(): void;
|
||||
|
||||
/* the maximum image height to use */
|
||||
maxImageHeight?: number;
|
||||
|
||||
/* the permalinkCreator */
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
}
|
||||
import { IBodyProps } from "./IBodyProps";
|
||||
|
||||
interface IState {
|
||||
decryptedUrl?: string;
|
||||
|
@ -64,12 +48,12 @@ interface IState {
|
|||
}
|
||||
|
||||
@replaceableComponent("views.messages.MImageBody")
|
||||
export default class MImageBody extends React.Component<IProps, IState> {
|
||||
export default class MImageBody extends React.Component<IBodyProps, IState> {
|
||||
static contextType = MatrixClientContext;
|
||||
private unmounted = true;
|
||||
private image = createRef<HTMLImageElement>();
|
||||
|
||||
constructor(props: IProps) {
|
||||
constructor(props: IBodyProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -257,38 +241,23 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private downloadImage(): void {
|
||||
const content = this.props.mxEvent.getContent();
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||
let thumbnailPromise = Promise.resolve(null);
|
||||
if (content.info && content.info.thumbnail_file) {
|
||||
thumbnailPromise = decryptFile(
|
||||
content.info.thumbnail_file,
|
||||
).then(function(blob) {
|
||||
return URL.createObjectURL(blob);
|
||||
private async downloadImage() {
|
||||
if (this.props.mediaEventHelper.media.isEncrypted && this.state.decryptedUrl === null) {
|
||||
try {
|
||||
const thumbnailUrl = await this.props.mediaEventHelper.thumbnailUrl.value;
|
||||
this.setState({
|
||||
decryptedUrl: await this.props.mediaEventHelper.sourceUrl.value,
|
||||
decryptedThumbnailUrl: thumbnailUrl,
|
||||
decryptedBlob: await this.props.mediaEventHelper.sourceBlob.value,
|
||||
});
|
||||
}
|
||||
let decryptedBlob;
|
||||
thumbnailPromise.then((thumbnailUrl) => {
|
||||
return decryptFile(content.file).then(function(blob) {
|
||||
decryptedBlob = blob;
|
||||
return URL.createObjectURL(blob);
|
||||
}).then((contentUrl) => {
|
||||
if (this.unmounted) return;
|
||||
this.setState({
|
||||
decryptedUrl: contentUrl,
|
||||
decryptedThumbnailUrl: thumbnailUrl,
|
||||
decryptedBlob: decryptedBlob,
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
} catch (err) {
|
||||
if (this.unmounted) return;
|
||||
console.warn("Unable to decrypt attachment: ", err);
|
||||
// Set a placeholder image when we can't decrypt the image.
|
||||
this.setState({
|
||||
error: err,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,29 +269,15 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
localStorage.getItem("mx_ShowImage_" + this.props.mxEvent.getId()) === "true";
|
||||
|
||||
if (showImage) {
|
||||
// Don't download anything becaue we don't want to display anything.
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
this.downloadImage();
|
||||
this.setState({ showImage: true });
|
||||
}
|
||||
|
||||
this._afterComponentDidMount();
|
||||
}
|
||||
|
||||
// To be overridden by subclasses (e.g. MStickerBody) for further
|
||||
// initialisation after componentDidMount
|
||||
_afterComponentDidMount() {
|
||||
} // else don't download anything because we don't want to display anything.
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unmounted = true;
|
||||
this.context.removeListener('sync', this.onClientSync);
|
||||
|
||||
if (this.state.decryptedUrl) {
|
||||
URL.revokeObjectURL(this.state.decryptedUrl);
|
||||
}
|
||||
if (this.state.decryptedThumbnailUrl) {
|
||||
URL.revokeObjectURL(this.state.decryptedThumbnailUrl);
|
||||
}
|
||||
}
|
||||
|
||||
protected messageContent(
|
||||
|
@ -406,8 +361,6 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
|
||||
const thumbnail = (
|
||||
<div className="mx_MImageBody_thumbnail_container" style={{ maxHeight: maxHeight + "px", maxWidth: maxWidth + "px" }} >
|
||||
{ /* Calculate aspect ratio, using %padding will size _container correctly */ }
|
||||
<div style={{ paddingBottom: forcedHeight ? (forcedHeight + "px") : ((100 * infoHeight / infoWidth) + '%') }} />
|
||||
{ showPlaceholder &&
|
||||
<div className="mx_MImageBody_thumbnail" style={{
|
||||
// Constrain width here so that spinner appears central to the loaded thumbnail
|
||||
|
@ -432,7 +385,7 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
// Overidden by MStickerBody
|
||||
protected wrapImage(contentUrl: string, children: JSX.Element): JSX.Element {
|
||||
return <a href={contentUrl} onClick={this.onClick}>
|
||||
{children}
|
||||
{ children }
|
||||
</a>;
|
||||
}
|
||||
|
||||
|
@ -440,9 +393,9 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
protected getPlaceholder(width: number, height: number): JSX.Element {
|
||||
const blurhash = this.props.mxEvent.getContent().info[BLURHASH_FIELD];
|
||||
if (blurhash) return <Blurhash hash={blurhash} width={width} height={height} />;
|
||||
return <div className="mx_MImageBody_thumbnail_spinner">
|
||||
return (
|
||||
<InlineSpinner w={32} h={32} />
|
||||
</div>;
|
||||
);
|
||||
}
|
||||
|
||||
// Overidden by MStickerBody
|
||||
|
@ -452,7 +405,10 @@ export default class MImageBody extends React.Component<IProps, IState> {
|
|||
|
||||
// Overidden by MStickerBody
|
||||
protected getFileBody(): string | JSX.Element {
|
||||
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />;
|
||||
// We only ever need the download bar if we're appearing outside of the timeline
|
||||
if (this.props.tileShape) {
|
||||
return <MFileBody {...this.props} showGenericPlaceholder={false} />;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -499,7 +455,7 @@ export class HiddenImagePlaceholder extends React.PureComponent<PlaceholderIProp
|
|||
<div className={className} style={{ maxWidth: maxWidth }}>
|
||||
<div className='mx_HiddenImagePlaceholder_button'>
|
||||
<span className='mx_HiddenImagePlaceholder_eye' />
|
||||
<span>{_t("Show image")}</span>
|
||||
<span>{ _t("Show image") }</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue