Support cancel for sending operation.

This commit is contained in:
N-Pex 2023-01-09 21:12:17 +01:00
parent 0602c4c72f
commit bb3aaf1bed
2 changed files with 90 additions and 57 deletions

View file

@ -375,7 +375,7 @@
<script> <script>
import Vue from "vue"; import Vue from "vue";
import { TimelineWindow, EventTimeline } from "matrix-js-sdk"; import { TimelineWindow, EventTimeline, AbortError } from "matrix-js-sdk";
import util from "../plugins/utils"; import util from "../plugins/utils";
import MessageOperations from "./messages/MessageOperations.vue"; import MessageOperations from "./messages/MessageOperations.vue";
import AvatarOperations from "./messages/AvatarOperations.vue"; import AvatarOperations from "./messages/AvatarOperations.vue";
@ -1078,7 +1078,11 @@ export default {
} }
}) })
.catch((err) => { .catch((err) => {
this.currentSendError = err.toLocaleString(); if (err instanceof AbortError || err === "Abort") {
this.currentSendError = null;
} else {
this.currentSendError = err.LocaleString();
}
this.currentSendOperation = null; this.currentSendOperation = null;
this.currentSendProgress = null; this.currentSendProgress = null;
}); });
@ -1088,7 +1092,7 @@ export default {
cancelSendAttachment() { cancelSendAttachment() {
this.$refs.attachment.value = null; this.$refs.attachment.value = null;
if (this.currentSendOperation) { if (this.currentSendOperation) {
this.currentSendOperation.reject("Canceled"); this.currentSendOperation.abort();
} }
this.currentSendOperation = null; this.currentSendOperation = null;
this.currentImageInput = null; this.currentImageInput = null;

View file

@ -26,6 +26,28 @@ var _browserCanRecordAudioF = function () {
} }
var _browserCanRecordAudio = _browserCanRecordAudioF(); var _browserCanRecordAudio = _browserCanRecordAudioF();
class AbortablePromise extends Promise {
constructor(executor) {
const aborter = {
aborted: false,
abortablePromise: undefined,
}
const normalExecutor = function (resolve, reject) {
executor(resolve, reject, aborter);
};
super(normalExecutor);
this.abort = () => {
aborter.aborted = true;
if (aborter.abortablePromise) {
aborter.abortablePromise.abort();
aborter.abortablePromise = undefined;
}
};
}
}
class Util { class Util {
getAttachment(matrixClient, event, progressCallback, asBlob = false) { getAttachment(matrixClient, event, progressCallback, asBlob = false) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -170,7 +192,7 @@ class Util {
} }
let senderContent = replyToEvent.getContent() let senderContent = replyToEvent.getContent()
const senderContentBody = Object.getOwnPropertyDescriptor(senderContent,'body') ? senderContent.body : Object.values(senderContent)[0].question.body const senderContentBody = Object.getOwnPropertyDescriptor(senderContent, 'body') ? senderContent.body : Object.values(senderContent)[0].question.body
// Prefix the content with reply info (seems to be a legacy thing) // Prefix the content with reply info (seems to be a legacy thing)
const prefix = senderContentBody.split('\n').map((item, index) => { const prefix = senderContentBody.split('\n').map((item, index) => {
return "> " + (index == 0 ? ("<" + replyToEvent.getSender() + "> ") : "") + item; return "> " + (index == 0 ? ("<" + replyToEvent.getSender() + "> ") : "") + item;
@ -195,7 +217,7 @@ class Util {
var idx = 0; var idx = 0;
let answerData = answers.map(a => { let answerData = answers.map(a => {
idx++; idx++;
return {id: "" + idx, 'org.matrix.msc1767.text': a.text } return { id: "" + idx, 'org.matrix.msc1767.text': a.text }
}); });
const content = { const content = {
'org.matrix.msc3381.poll.start': { 'org.matrix.msc3381.poll.start': {
@ -285,9 +307,14 @@ class Util {
} }
sendImage(matrixClient, roomId, file, onUploadProgress) { sendImage(matrixClient, roomId, file, onUploadProgress) {
return new Promise((resolve, reject) => { return new AbortablePromise((resolve, reject, aborter) => {
const abortionController = aborter;
var reader = new FileReader(); var reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
if (abortionController.aborted) {
reject("Aborted");
return;
}
const fileContents = e.target.result; const fileContents = e.target.result;
var data = new Uint8Array(fileContents); var data = new Uint8Array(fileContents);
@ -326,7 +353,8 @@ class Util {
if (!matrixClient.isRoomEncrypted(roomId)) { if (!matrixClient.isRoomEncrypted(roomId)) {
// Not encrypted. // Not encrypted.
matrixClient.uploadContent(data, opts) abortionController.abortablePromise = matrixClient.uploadContent(data, opts);
abortionController.abortablePromise
.then((response) => { .then((response) => {
messageContent.url = response.content_uri; messageContent.url = response.content_uri;
return this.sendMessage(matrixClient, roomId, "m.room.message", messageContent) return this.sendMessage(matrixClient, roomId, "m.room.message", messageContent)
@ -373,7 +401,8 @@ class Util {
// Encrypted data sent as octet-stream! // Encrypted data sent as octet-stream!
opts.type = "application/octet-stream"; opts.type = "application/octet-stream";
matrixClient.uploadContent(data, opts) abortionController.abortablePromise = matrixClient.uploadContent(data, opts);
abortionController.abortablePromise
.then((response) => { .then((response) => {
if (response.error) { if (response.error) {
return reject(response.error); return reject(response.error);
@ -604,57 +633,57 @@ class Util {
loadAvatarFromFile(event, onLoad) { loadAvatarFromFile(event, onLoad) {
if (event.target.files && event.target.files[0]) { if (event.target.files && event.target.files[0]) {
var reader = new FileReader(); var reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
const file = event.target.files[0]; const file = event.target.files[0];
if (file.type.startsWith("image/")) { if (file.type.startsWith("image/")) {
try { try {
var image = e.target.result; var image = e.target.result;
var dimens = sizeOf(dataUriToBuffer(e.target.result)); var dimens = sizeOf(dataUriToBuffer(e.target.result));
// Need to resize? // Need to resize?
const w = dimens.width; const w = dimens.width;
const h = dimens.height; const h = dimens.height;
if (w > 640 || h > 640) { if (w > 640 || h > 640) {
var aspect = w / h; var aspect = w / h;
var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed()); var newWidth = parseInt((w > h ? 640 : 640 * aspect).toFixed());
var newHeight = parseInt( var newHeight = parseInt(
(w > h ? 640 / aspect : 640).toFixed() (w > h ? 640 / aspect : 640).toFixed()
); );
var imageResize = new ImageResize({ var imageResize = new ImageResize({
format: "png", format: "png",
width: newWidth, width: newWidth,
height: newHeight, height: newHeight,
outputType: "blob", outputType: "blob",
}); });
imageResize imageResize
.play(event.target) .play(event.target)
.then((img) => { .then((img) => {
var resizedImageFile = new File([img], file.name, { var resizedImageFile = new File([img], file.name, {
type: img.type, type: img.type,
lastModified: Date.now(), lastModified: Date.now(),
}); });
var reader2 = new FileReader(); var reader2 = new FileReader();
reader2.onload = (e) => { reader2.onload = (e) => {
onLoad(e.target.result); onLoad(e.target.result);
}; };
reader2.readAsDataURL(resizedImageFile); reader2.readAsDataURL(resizedImageFile);
}) })
.catch((err) => { .catch((err) => {
console.error("Resize failed:", err); console.error("Resize failed:", err);
}); });
} else { } else {
onLoad(image); onLoad(image);
}
} catch (error) {
console.error("Failed to get image dimensions: " + error);
}
} }
} catch (error) { };
console.error("Failed to get image dimensions: " + error); reader.readAsDataURL(event.target.files[0]);
}
}
};
reader.readAsDataURL(event.target.files[0]);
} }
} }
/** /**
* Return number of whole days between the timestamps, at end of that day. * Return number of whole days between the timestamps, at end of that day.