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:
Šimon Brandner 2021-07-21 15:33:06 +02:00
commit e8760736ba
No known key found for this signature in database
GPG key ID: 55C211A1226CB17D
327 changed files with 4637 additions and 3095 deletions

View file

@ -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>
);