Merge pull request #767 from vector-im/bwindels/download-media

Menu option to download attached image or video of event
This commit is contained in:
Bruno Windels 2022-06-25 18:21:17 +00:00 committed by GitHub
commit ad8ad22cc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 10 deletions

View file

@ -27,6 +27,29 @@ export class BaseMediaTile extends BaseMessageTile {
this._decryptedFile = null; this._decryptedFile = null;
this._isVisible = false; this._isVisible = false;
this._error = null; this._error = null;
this._downloading = false;
this._downloadError = null;
}
async downloadMedia() {
if (this._downloading || this.isPending) {
return;
}
const content = this._getContent();
const filename = content.body;
this._downloading = true;
this.emitChange("status");
let blob;
try {
blob = await this._mediaRepository.downloadAttachment(content);
this.platform.saveFileAs(blob, filename);
} catch (err) {
this._downloadError = err;
} finally {
blob?.dispose();
this._downloading = false;
}
this.emitChange("status");
} }
get isUploading() { get isUploading() {
@ -38,7 +61,7 @@ export class BaseMediaTile extends BaseMessageTile {
return pendingEvent && Math.round((pendingEvent.attachmentsSentBytes / pendingEvent.attachmentsTotalBytes) * 100); return pendingEvent && Math.round((pendingEvent.attachmentsSentBytes / pendingEvent.attachmentsTotalBytes) * 100);
} }
get sendStatus() { get status() {
const {pendingEvent} = this._entry; const {pendingEvent} = this._entry;
switch (pendingEvent?.status) { switch (pendingEvent?.status) {
case SendStatus.Waiting: case SendStatus.Waiting:
@ -53,6 +76,12 @@ export class BaseMediaTile extends BaseMessageTile {
case SendStatus.Error: case SendStatus.Error:
return this.i18n`Error: ${pendingEvent.error.message}`; return this.i18n`Error: ${pendingEvent.error.message}`;
default: default:
if (this._downloadError) {
return `Download failed`;
}
if (this._downloading) {
return this.i18n`Downloading…`;
}
return ""; return "";
} }
} }

View file

@ -233,7 +233,7 @@ only loads when the top comes into view*/
align-self: stretch; align-self: stretch;
} }
.Timeline_messageBody .media > .sendStatus { .Timeline_messageBody .media > .status {
align-self: end; align-self: end;
justify-self: start; justify-self: start;
font-size: 0.8em; font-size: 0.8em;
@ -251,7 +251,7 @@ only loads when the top comes into view*/
} }
.Timeline_messageBody .media > time, .Timeline_messageBody .media > time,
.Timeline_messageBody .media > .sendStatus { .Timeline_messageBody .media > .status {
color: var(--text-color); color: var(--text-color);
display: block; display: block;
padding: 2px; padding: 2px;

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import {BaseMessageView} from "./BaseMessageView.js"; import {BaseMessageView} from "./BaseMessageView.js";
import {Menu} from "../../../general/Menu.js";
export class BaseMediaView extends BaseMessageView { export class BaseMediaView extends BaseMessageView {
renderMessageBody(t, vm) { renderMessageBody(t, vm) {
@ -35,24 +36,39 @@ export class BaseMediaView extends BaseMessageView {
this.renderMedia(t, vm), this.renderMedia(t, vm),
t.time(vm.date + " " + vm.time), t.time(vm.date + " " + vm.time),
]; ];
const status = t.div({
className: {
status: true,
hidden: vm => !vm.status
},
}, vm => vm.status);
children.push(status);
if (vm.isPending) { if (vm.isPending) {
const sendStatus = t.div({
className: {
sendStatus: true,
hidden: vm => !vm.sendStatus
},
}, vm => vm.sendStatus);
const progress = t.progress({ const progress = t.progress({
min: 0, min: 0,
max: 100, max: 100,
value: vm => vm.uploadPercentage, value: vm => vm.uploadPercentage,
className: {hidden: vm => !vm.isUploading} className: {hidden: vm => !vm.isUploading}
}); });
children.push(sendStatus, progress); children.push(progress);
} }
return t.div({className: "Timeline_messageBody"}, [ return t.div({className: "Timeline_messageBody"}, [
t.div({className: "media", style: `max-width: ${vm.width}px`}, children), t.div({className: "media", style: `max-width: ${vm.width}px`}, children),
t.if(vm => vm.error, t => t.p({className: "error"}, vm.error)) t.if(vm => vm.error, t => t.p({className: "error"}, vm.error))
]); ]);
} }
createMenuOptions(vm) {
const options = super.createMenuOptions(vm);
if (!vm.isPending) {
let label;
switch (vm.shape) {
case "image": label = vm.i18n`Download image`; break;
case "video": label = vm.i18n`Download video`; break;
default: label = vm.i18n`Download media`; break;
}
options.push(Menu.option(label, () => vm.downloadMedia()));
}
return options;
}
} }