Add AttachmentBatch for future removal of sendAttachmentsMixin
This commit is contained in:
parent
1d30d0633d
commit
fd82fd8840
5 changed files with 377 additions and 231 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { ComputedRef, Ref } from "vue";
|
||||
|
||||
export class UploadPromise<Type> {
|
||||
wrappedPromise: Promise<Type>;
|
||||
aborted: boolean = false;
|
||||
|
|
@ -49,3 +51,19 @@ export type Attachment = {
|
|||
proof?: any;
|
||||
sendInfo?: AttachmentSendInfo;
|
||||
};
|
||||
|
||||
export type AttachmentBatch = {
|
||||
sendingStatus: Ref<"initial" | "sending" | "sent" | "canceled" | "failed">;
|
||||
sendingRootEventId: Ref<string | undefined>;
|
||||
sendingPromise: Ref<Promise<any> | undefined>;
|
||||
attachments: Ref<Attachment[]>;
|
||||
attachmentsSentCount: ComputedRef<number>;
|
||||
attachmentsSending: ComputedRef<Attachment[]>;
|
||||
attachmentsSent: ComputedRef<Attachment[]>;
|
||||
addAttachment: (attachment: Attachment) => void;
|
||||
removeAttachment: (attachment: Attachment) => void;
|
||||
send: (message: string) => Promise<any>;
|
||||
cancel: () => void;
|
||||
cancelSendAttachment: (attachment: Attachment) => void;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { MatrixClient, MatrixEvent } from "matrix-js-sdk";
|
||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk";
|
||||
import { EventAttachment, KeanuEventExtension } from "./eventAttachment";
|
||||
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import { Counter, ModeOfOperation } from "aes-js";
|
||||
import { Attachment } from "./attachment";
|
||||
import { Attachment, AttachmentBatch, AttachmentSendInfo } from "./attachment";
|
||||
import proofmode from "../plugins/proofmode";
|
||||
import imageSize from "image-size";
|
||||
import imageResize from "image-resize";
|
||||
import { Reactive, reactive } from "vue";
|
||||
import { computed, isRef, Reactive, reactive, ref, Ref } from "vue";
|
||||
import utils from "@/plugins/utils";
|
||||
|
||||
export class AttachmentManager {
|
||||
matrixClient: MatrixClient;
|
||||
|
|
@ -33,6 +34,10 @@ export class AttachmentManager {
|
|||
.catch(() => {});
|
||||
}
|
||||
|
||||
public createUpload(room: Room) {
|
||||
return createUploadBatch(this.matrixClient, room);
|
||||
}
|
||||
|
||||
public createAttachment(file: File): Attachment {
|
||||
let a: Attachment = {
|
||||
status: "loading",
|
||||
|
|
@ -133,7 +138,7 @@ export class AttachmentManager {
|
|||
attachment.src = src;
|
||||
return src;
|
||||
});
|
||||
return attachment.srcPromise;
|
||||
return attachment.srcPromise;
|
||||
};
|
||||
attachment.loadThumbnail = () => {
|
||||
if (attachment.thumbnail) {
|
||||
|
|
@ -141,13 +146,13 @@ export class AttachmentManager {
|
|||
} else if (attachment.thumbnailPromise) {
|
||||
return attachment.thumbnailPromise;
|
||||
}
|
||||
attachment.thumbnailPromise = this._loadEventAttachmentOrThumbnail(event, true, (percent) => {
|
||||
attachment.thumbnailProgress = percent;
|
||||
}).then((thummbnail) => {
|
||||
attachment.thumbnail = thummbnail;
|
||||
return thummbnail;
|
||||
});
|
||||
return attachment.thumbnailPromise;
|
||||
attachment.thumbnailPromise = this._loadEventAttachmentOrThumbnail(event, true, (percent) => {
|
||||
attachment.thumbnailProgress = percent;
|
||||
}).then((thummbnail) => {
|
||||
attachment.thumbnail = thummbnail;
|
||||
return thummbnail;
|
||||
});
|
||||
return attachment.thumbnailPromise;
|
||||
};
|
||||
attachment.release = (src: boolean, thumbnail: boolean) => {
|
||||
// TODO - figure out logic
|
||||
|
|
@ -161,7 +166,7 @@ export class AttachmentManager {
|
|||
URL.revokeObjectURL(attachment.thumbnail);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
this.cache.set(event.getId(), attachment!);
|
||||
return attachment;
|
||||
}
|
||||
|
|
@ -292,3 +297,205 @@ export class AttachmentManager {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
const createUploadBatch = (matrixClient: MatrixClient, room: Room): AttachmentBatch => {
|
||||
const sendingStatus: Ref<"initial" | "sending" | "sent" | "canceled" | "failed"> = ref("initial");
|
||||
const sendingRootEventId: Ref<string | undefined> = ref(undefined);
|
||||
const sendingPromise: Ref<Promise<any> | undefined> = ref(undefined);
|
||||
const attachments: Ref<Attachment[]> = ref([]);
|
||||
|
||||
const attachmentsSentCount = computed(() => {
|
||||
return attachments.value.reduce((a, elem) => (elem.sendInfo?.status == "sent" ? a + 1 : a), 0);
|
||||
});
|
||||
|
||||
const attachmentsSending = computed(() => {
|
||||
return attachments.value.filter((elem) => elem.sendInfo?.status == "initial" || elem.sendInfo?.status == "sending");
|
||||
});
|
||||
|
||||
const attachmentsSent = computed(() => {
|
||||
sortSendingAttachments();
|
||||
return attachments.value.filter((elem) => elem.sendInfo?.status == "sent");
|
||||
});
|
||||
|
||||
const sortSendingAttachments = () => {
|
||||
attachments.value.sort((a, b) => (b.sendInfo?.statusDate ?? 0) - (a.sendInfo?.statusDate ?? 0));
|
||||
};
|
||||
|
||||
const addAttachment = (attachment: Attachment) => {
|
||||
if (sendingStatus.value == "initial") {
|
||||
attachments.value.push(attachment);
|
||||
}
|
||||
};
|
||||
|
||||
const removeAttachment = (attachment: Attachment) => {
|
||||
if (sendingStatus.value == "initial") {
|
||||
attachments.value = attachments.value.filter((a) => a !== attachment);
|
||||
}
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
if (sendingStatus.value !== "initial") {
|
||||
attachments.value.toReversed().forEach((attachment) => {
|
||||
cancelSendAttachment(attachment);
|
||||
});
|
||||
sendingStatus.value = "canceled";
|
||||
if (sendingRootEventId.value) {
|
||||
// Redact all media we already sent, plus the root event
|
||||
let promises = attachments.value.reduce((val: Promise<any>[], attachment: Attachment) => {
|
||||
if (attachment.sendInfo?.mediaEventId) {
|
||||
val.push(
|
||||
matrixClient.redactEvent(room.roomId, attachment.sendInfo!.mediaEventId, undefined, {
|
||||
reason: "cancel",
|
||||
})
|
||||
);
|
||||
}
|
||||
return val;
|
||||
}, [] as Promise<any>[]);
|
||||
if (sendingRootEventId.value) {
|
||||
promises.push(
|
||||
matrixClient.redactEvent(room.roomId, sendingRootEventId.value, undefined, {
|
||||
reason: "cancel",
|
||||
})
|
||||
);
|
||||
}
|
||||
Promise.allSettled(promises)
|
||||
.then(() => {
|
||||
console.log("Message redacted");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Redaction failed: ", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const cancelSendAttachment = (attachment: Attachment) => {
|
||||
if (attachment.sendInfo) {
|
||||
if (attachment.sendInfo.promise && attachment.sendInfo.status != "initial") {
|
||||
attachment.sendInfo.promise.abort();
|
||||
}
|
||||
attachment.sendInfo.status = "canceled";
|
||||
}
|
||||
};
|
||||
|
||||
const send = (message: string): Promise<any> => {
|
||||
sendingStatus.value = "sending";
|
||||
attachments.value.forEach((attachment) => {
|
||||
let sendInfo: AttachmentSendInfo = {
|
||||
status: "initial",
|
||||
statusDate: Date.now(),
|
||||
mediaEventId: undefined,
|
||||
progress: 0,
|
||||
randomRotation: 0,
|
||||
randomTranslationX: 0,
|
||||
randomTranslationY: 0,
|
||||
promise: undefined,
|
||||
};
|
||||
attachment.sendInfo = reactive(sendInfo);
|
||||
});
|
||||
|
||||
const sendingPromise = utils
|
||||
.sendTextMessage(matrixClient, room.roomId, message)
|
||||
.then((eventId: string) => {
|
||||
sendingRootEventId.value = eventId;
|
||||
|
||||
// Use the eventId as a thread root for all the media
|
||||
let promiseChain = Promise.resolve();
|
||||
const getItemPromise = (index: number) => {
|
||||
if (index < attachments.value.length) {
|
||||
const attachment = attachments.value[index];
|
||||
const item = attachment.sendInfo!;
|
||||
if (item.status !== "initial") {
|
||||
return getItemPromise(++index);
|
||||
}
|
||||
item.status = "sending";
|
||||
|
||||
let file = (() => {
|
||||
if (attachment.scaledFile && attachment.useScaled) {
|
||||
// Send scaled version of image instead!
|
||||
return attachment.scaledFile;
|
||||
} else {
|
||||
// Send actual file image when not scaled!
|
||||
return attachment.file;
|
||||
}
|
||||
})();
|
||||
|
||||
const itemPromise = utils
|
||||
.sendFile(
|
||||
matrixClient,
|
||||
room.roomId,
|
||||
file,
|
||||
({ loaded, total }: { loaded: number; total: number }) => {
|
||||
if (loaded == total) {
|
||||
item.progress = 100;
|
||||
} else if (total > 0) {
|
||||
item.progress = (100 * loaded) / total;
|
||||
}
|
||||
},
|
||||
eventId,
|
||||
attachment.dimensions
|
||||
)
|
||||
.then((mediaEventId: string) => {
|
||||
// Look at last item rotation, flipping the sign on this, so looks more like a true stack
|
||||
let signR = 1;
|
||||
let signX = 1;
|
||||
let signY = 1;
|
||||
if (attachmentsSent.value.length > 0) {
|
||||
if (attachmentsSent.value[0].sendInfo!.randomRotation >= 0) {
|
||||
signR = -1;
|
||||
}
|
||||
if (attachmentsSent.value[0].sendInfo!.randomTranslationX >= 0) {
|
||||
signX = -1;
|
||||
}
|
||||
if (attachmentsSent.value[0].sendInfo!.randomTranslationY >= 0) {
|
||||
signY = -1;
|
||||
}
|
||||
}
|
||||
item.randomRotation = signR * (2 + Math.random() * 10);
|
||||
item.randomTranslationX = signX * Math.random() * 20;
|
||||
item.randomTranslationY = signY * Math.random() * 20;
|
||||
item.mediaEventId = mediaEventId;
|
||||
item.status = "sent";
|
||||
item.statusDate = Date.now();
|
||||
})
|
||||
.catch((ignorederr: any) => {
|
||||
if (item.promise?.aborted) {
|
||||
item.status = "canceled";
|
||||
} else {
|
||||
console.error("ERROR", ignorederr);
|
||||
item.status = "failed";
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
item.promise = itemPromise;
|
||||
return itemPromise.then(() => getItemPromise(++index));
|
||||
} else return Promise.resolve();
|
||||
};
|
||||
|
||||
return promiseChain.then(() => getItemPromise(0));
|
||||
})
|
||||
.then(() => {
|
||||
sendingStatus.value = "sent";
|
||||
sendingRootEventId.value = undefined;
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error("ERROR", err);
|
||||
});
|
||||
return sendingPromise;
|
||||
};
|
||||
|
||||
return {
|
||||
sendingStatus,
|
||||
sendingRootEventId,
|
||||
sendingPromise,
|
||||
attachments,
|
||||
attachmentsSentCount,
|
||||
attachmentsSending,
|
||||
attachmentsSent,
|
||||
addAttachment,
|
||||
removeAttachment,
|
||||
send,
|
||||
cancel,
|
||||
cancelSendAttachment,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue