UI refresh for uploaded files

Fixes https://github.com/vector-im/element-web/issues/16557
Fixes https://github.com/vector-im/element-web/issues/9482 (technically)

There's two changes in this:
1. The actual file body in the timeline now has a placeholder thing.
2. We're intentionally dropping all the "Travis uploaded a file" sender profile states.
This commit is contained in:
Travis Ralston 2021-03-04 20:07:48 -07:00
parent c73ad9e594
commit 5d6e3d5711
12 changed files with 88 additions and 23 deletions

View file

@ -105,7 +105,7 @@ export default class MAudioBody extends React.Component {
return (
<span className="mx_MAudioBody">
<audio src={contentUrl} controls />
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} />
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />
</span>
);
}

View file

@ -126,6 +126,12 @@ export default class MFileBody extends React.Component {
onHeightChanged: PropTypes.func,
/* the shape of the tile, used */
tileShape: PropTypes.string,
/* whether or not to show the default placeholder for the file. Defaults to true. */
showGenericPlaceholder: PropTypes.bool,
};
static defaultProps = {
showGenericPlaceholder: true,
};
constructor(props) {
@ -145,9 +151,10 @@ export default class MFileBody extends React.Component {
* link text.
*
* @param {Object} content The "content" key of the matrix event.
* @param {boolean} withSize Whether to include size information. Default true.
* @return {string} the human readable link text for the attachment.
*/
presentableTextForFile(content) {
presentableTextForFile(content, withSize = true) {
let linkText = _t("Attachment");
if (content.body && content.body.length > 0) {
// The content body should be the name of the file including a
@ -155,7 +162,7 @@ export default class MFileBody extends React.Component {
linkText = content.body;
}
if (content.info && content.info.size) {
if (content.info && content.info.size && withSize) {
// If we know the size of the file then add it as human readable
// string to the end of the link text so that the user knows how
// big a file they are downloading.
@ -218,6 +225,16 @@ export default class MFileBody extends React.Component {
const fileSize = content.info ? content.info.size : null;
const fileType = content.info ? content.info.mimetype : "application/octet-stream";
let placeholder = null;
if (this.props.showGenericPlaceholder) {
placeholder = (
<div className="mx_MFileBody_info">
<span className="mx_MFileBody_info_icon" />
<span className="mx_MFileBody_info_filename">{this.presentableTextForFile(content, false)}</span>
</div>
);
}
if (isEncrypted) {
if (this.state.decryptedBlob === null) {
// Need to decrypt the attachment
@ -248,6 +265,7 @@ export default class MFileBody extends React.Component {
// but it is not guaranteed between various browsers' settings.
return (
<span className="mx_MFileBody">
{placeholder}
<div className="mx_MFileBody_download">
<AccessibleButton onClick={decrypt}>
{ _t("Decrypt %(text)s", { text: text }) }
@ -278,6 +296,7 @@ export default class MFileBody extends React.Component {
// If the attachment is encrypted then put the link inside an iframe.
return (
<span className="mx_MFileBody">
{placeholder}
<div className="mx_MFileBody_download">
<div style={{display: "none"}}>
{ /*
@ -346,6 +365,7 @@ export default class MFileBody extends React.Component {
if (this.props.tileShape === "file_grid") {
return (
<span className="mx_MFileBody">
{placeholder}
<div className="mx_MFileBody_download">
<a className="mx_MFileBody_downloadLink" {...downloadProps}>
{ fileName }
@ -359,6 +379,7 @@ export default class MFileBody extends React.Component {
} else {
return (
<span className="mx_MFileBody">
{placeholder}
<div className="mx_MFileBody_download">
<a {...downloadProps}>
<img src={tintedDownloadImageURL} width="12" height="14" ref={this._downloadImage} />
@ -371,6 +392,7 @@ export default class MFileBody extends React.Component {
} else {
const extra = text ? (': ' + text) : '';
return <span className="mx_MFileBody">
{placeholder}
{ _t("Invalid file%(extra)s", { extra: extra }) }
</span>;
}

View file

@ -452,7 +452,7 @@ export default class MImageBody extends React.Component {
// Overidden by MStickerBody
getFileBody() {
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} />;
return <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />;
}
render() {

View file

@ -243,7 +243,7 @@ export default class MVideoBody extends React.PureComponent<IProps, IState> {
onPlay={this.videoOnPlay}
>
</video>
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} />
<MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} showGenericPlaceholder={false} />
</span>
);
}

View file

@ -25,7 +25,6 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
export default class SenderProfile extends React.Component {
static propTypes = {
mxEvent: PropTypes.object.isRequired, // event whose sender we're showing
text: PropTypes.string, // Text to show. Defaults to sender name
onClick: PropTypes.func,
};
@ -118,17 +117,10 @@ export default class SenderProfile extends React.Component {
{ flair }
</span>;
const content = this.props.text ?
<span>
<span className="mx_SenderProfile_aux">
{ _t(this.props.text, { senderName: () => nameElem }) }
</span>
</span> : nameFlair;
return (
<div className="mx_SenderProfile" dir="auto" onClick={this.props.onClick}>
<div className="mx_SenderProfile_hover">
{ content }
{ nameFlair }
</div>
</div>
);

View file

@ -768,15 +768,10 @@ export default class EventTile extends React.Component {
}
if (needsSenderProfile) {
let text = null;
if (!this.props.tileShape || this.props.tileShape === 'reply' || this.props.tileShape === 'reply_preview') {
if (msgtype === 'm.image') text = _td('%(senderName)s sent an image');
else if (msgtype === 'm.video') text = _td('%(senderName)s sent a video');
else if (msgtype === 'm.file') text = _td('%(senderName)s uploaded a file');
sender = <SenderProfile onClick={this.onSenderProfileClick}
mxEvent={this.props.mxEvent}
enableFlair={this.props.enableFlair && !text}
text={text} />;
enableFlair={this.props.enableFlair} />;
} else {
sender = <SenderProfile mxEvent={this.props.mxEvent} enableFlair={this.props.enableFlair} />;
}