diff --git a/src/components/RoomExport.vue b/src/components/RoomExport.vue
index be0e401..a7d60b9 100644
--- a/src/components/RoomExport.vue
+++ b/src/components/RoomExport.vue
@@ -26,9 +26,16 @@
-
+
@@ -54,16 +61,12 @@
-
-
\ No newline at end of file
diff --git a/src/components/messages/MessageIncomingImage.vue b/src/components/messages/MessageIncomingImage.vue
deleted file mode 100644
index 29a7422..0000000
--- a/src/components/messages/MessageIncomingImage.vue
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/messages/MessageIncomingVideo.vue b/src/components/messages/MessageIncomingVideo.vue
deleted file mode 100644
index 6ddbe13..0000000
--- a/src/components/messages/MessageIncomingVideo.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('message.download_progress',{percentage: downloadProgress}) }}
-
-
-
-
- {{ fileName }}
-
-
- {{ fileSize }}
-
-
download
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/components/messages/MessageOutgoingFile.vue b/src/components/messages/MessageOutgoingFile.vue
deleted file mode 100644
index fe454fa..0000000
--- a/src/components/messages/MessageOutgoingFile.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
{{ inReplyToSender }}
-
-
-
-
-
-
- {{ $t('message.edited') }}
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/components/messages/MessageOutgoingImage.vue b/src/components/messages/MessageOutgoingImage.vue
deleted file mode 100644
index 65d0c64..0000000
--- a/src/components/messages/MessageOutgoingImage.vue
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/messages/MessageOutgoingVideo.vue b/src/components/messages/MessageOutgoingVideo.vue
deleted file mode 100644
index b8a8b7d..0000000
--- a/src/components/messages/MessageOutgoingVideo.vue
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
- {{ $t('message.download_progress',{percentage: downloadProgress}) }}
-
-
-
-
- {{ fileName }}
-
-
- {{ fileSize }}
-
-
download
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/components/messages/composition/MessageFile.vue b/src/components/messages/composition/MessageFile.vue
new file mode 100644
index 0000000..175a2b6
--- /dev/null
+++ b/src/components/messages/composition/MessageFile.vue
@@ -0,0 +1,55 @@
+
+
+
+ {{ inOut }}
+
+
{{ inReplyToSender }}
+
+
+
+
+
+ {{ $t("message.edited") }}
+
+
+
+
+
+
+
+
diff --git a/src/components/messages/composition/MessageImage.vue b/src/components/messages/composition/MessageImage.vue
new file mode 100644
index 0000000..9ae44c6
--- /dev/null
+++ b/src/components/messages/composition/MessageImage.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/messages/composition/MessageIncoming.vue b/src/components/messages/composition/MessageIncoming.vue
index 5201b6f..ce42566 100644
--- a/src/components/messages/composition/MessageIncoming.vue
+++ b/src/components/messages/composition/MessageIncoming.vue
@@ -31,7 +31,7 @@
-
-
-
diff --git a/src/components/messages/composition/MessageIncomingThread.vue b/src/components/messages/composition/MessageThread.vue
similarity index 85%
rename from src/components/messages/composition/MessageIncomingThread.vue
rename to src/components/messages/composition/MessageThread.vue
index 131c4bd..a5ab107 100644
--- a/src/components/messages/composition/MessageIncomingThread.vue
+++ b/src/components/messages/composition/MessageThread.vue
@@ -1,9 +1,9 @@
-
@@ -25,7 +25,7 @@
- block
+ block
{{
redactedBySomeoneElse(event)
? $t("message.incoming_message_deleted_text")
@@ -45,10 +45,10 @@
v-if="!!showItem"
v-on:close="showItem = undefined"
/>
-
+
@@ -56,26 +56,29 @@
diff --git a/src/components/messages/composition/MessageVideo.vue b/src/components/messages/composition/MessageVideo.vue
new file mode 100644
index 0000000..dd878f0
--- /dev/null
+++ b/src/components/messages/composition/MessageVideo.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+ {{ $t('message.download_progress',{percentage: attachment.srcProgress}) }}
+
+
+
+
+ {{ attachment?.name }}
+
+
+ {{ prettyBytes(attachment.srcSize) }}
+
+
attachment?.loadSrc()">download
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/components/messages/composition/useLazyLoad.ts b/src/components/messages/composition/useLazyLoad.ts
new file mode 100644
index 0000000..35651e0
--- /dev/null
+++ b/src/components/messages/composition/useLazyLoad.ts
@@ -0,0 +1,39 @@
+import { ComponentInstance, onBeforeUnmount, Ref, ref, ShallowRef, watch } from "vue";
+import Intersect, { ObserveDirectiveBinding } from "vuetify/directives/intersect";
+
+export const useLazyLoad = (props: { root: Readonly>> }) => {
+ const isVisible: Ref = ref(false);
+ const binding: Ref = ref(undefined);
+
+ watch(
+ props.root,
+ (newval: ComponentInstance) => {
+ if (newval && !binding.value) {
+ const binding: ObserveDirectiveBinding = {
+ modifiers: {
+ once: false,
+ quiet: false,
+ },
+ value(isIntersecting, entries, observer) {
+ isVisible.value = isIntersecting;
+ },
+ instance: newval,
+ oldValue: undefined,
+ dir: {},
+ };
+ Intersect.mounted(newval.$el, binding);
+ }
+ },
+ { immediate: true }
+ );
+
+ onBeforeUnmount(() => {
+ if (binding.value && binding.value.instance) {
+ Intersect.unmounted(binding.value.instance.$el, binding.value);
+ }
+ });
+
+ return {
+ isVisible,
+ };
+};
diff --git a/src/components/messages/composition/messageMixin.ts b/src/components/messages/composition/useMessage.ts
similarity index 96%
rename from src/components/messages/composition/messageMixin.ts
rename to src/components/messages/composition/useMessage.ts
index 1b9906b..e0b8cfe 100644
--- a/src/components/messages/composition/messageMixin.ts
+++ b/src/components/messages/composition/useMessage.ts
@@ -8,14 +8,14 @@ linkify.options.defaults.target = { url: "_blank" };
import { computed, onBeforeUnmount, Ref, ref, watch } from "vue";
import { EventTimelineSet, Relations, RelationsEvent } from "matrix-js-sdk";
-import { KeanuEvent, KeanuRoom } from "../../../models/eventAttachment";
+import { EventAttachment, KeanuEvent, KeanuRoom } from "../../../models/eventAttachment";
export interface MessageProps {
room: KeanuRoom;
originalEvent: KeanuEvent;
nextEvent: KeanuEvent | null | undefined;
timelineSet: EventTimelineSet;
- componentFn: (event: KeanuEvent) => any;
+ componentFn: (event: KeanuEvent, forExport: boolean) => any;
}
export type MessageEmits = {
@@ -33,8 +33,11 @@ export const useMessage = (
processThread?: () => void
) => {
const event: Ref = ref(undefined);
+ const attachment: Ref = ref(undefined);
const thread: Ref = ref(undefined);
+ const isIncoming = ref(props.originalEvent.getSender() != $matrix.currentUserId);
+
onBeforeUnmount(() => {
thread.value = undefined;
});
@@ -43,6 +46,7 @@ export const useMessage = (
props.originalEvent,
(originalEvent) => {
event.value = originalEvent;
+ attachment.value = $matrix.attachmentManager.getEventAttachment(event.value);
// Check not null and not {}
if (originalEvent && originalEvent.isBeingDecrypted && originalEvent.isBeingDecrypted()) {
@@ -355,6 +359,8 @@ export const useMessage = (
return {
event,
+ isIncoming,
+ attachment,
thread,
validEvent,
diff --git a/src/components/messages/export/MessageIncomingThreadExport.vue b/src/components/messages/export/MessageIncomingThreadExport.vue
deleted file mode 100644
index 70c15c2..0000000
--- a/src/components/messages/export/MessageIncomingThreadExport.vue
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/components/messages/export/MessageOutgoingThreadExport.vue b/src/components/messages/export/MessageOutgoingThreadExport.vue
deleted file mode 100644
index 4feee8d..0000000
--- a/src/components/messages/export/MessageOutgoingThreadExport.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/models/attachmentManager.ts b/src/models/attachmentManager.ts
index 8a25c51..9dfafac 100644
--- a/src/models/attachmentManager.ts
+++ b/src/models/attachmentManager.ts
@@ -1,5 +1,5 @@
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk";
-import { EventAttachment, KeanuEventExtension } from "./eventAttachment";
+import { EventAttachment, EventAttachmentLoadSrcOptions, EventAttachmentUrlType, KeanuEvent, KeanuEventExtension } from "./eventAttachment";
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import { Counter, ModeOfOperation } from "aes-js";
import { Attachment, AttachmentBatch, AttachmentSendInfo } from "./attachment";
@@ -113,44 +113,68 @@ export class AttachmentManager {
return attachment;
}
- public getEventAttachment(event: MatrixEvent & KeanuEventExtension): Reactive {
+ private getFileName(event: KeanuEvent) {
+ const content = event.getContent();
+ return (content.body || content.filename || "").toLowerCase();
+ }
+
+ private getSrcFileSize(event: KeanuEvent) {
+ const content = event.getContent();
+ if (content.info) {
+ return content.info.size;
+ }
+ return 0;
+ }
+
+
+ public getEventAttachment(event: KeanuEvent): Reactive {
let entry = this.cache.get(event.getId());
if (entry !== undefined) {
return entry;
}
+
+ const fileSize = this.getSrcFileSize(event);
+
const attachment: Reactive = reactive({
event: event,
+ name: this.getFileName(event),
+ srcSize: fileSize,
srcProgress: -1,
thumbnailProgress: -1,
+ autoDownloadable: fileSize <= this.maxSizeAutoDownloads,
loadSrc: () => Promise.reject("Not implemented"),
loadThumbnail: () => Promise.reject("Not implemented"),
release: () => Promise.reject("Not implemented"),
});
- attachment.loadSrc = () => {
- if (attachment.src) {
- return Promise.resolve(attachment.src);
+ attachment.loadSrc = (options?: EventAttachmentLoadSrcOptions) => {
+ if (attachment.src && !options?.asBlob) {
+ return Promise.resolve({data: attachment.src, type: "src"});
} else if (attachment.srcPromise) {
return attachment.srcPromise;
}
- attachment.srcPromise = this._loadEventAttachmentOrThumbnail(event, false, (percent) => {
+ attachment.srcPromise = this._loadEventAttachmentOrThumbnail(event, false, !!options?.asBlob, (percent) => {
attachment.srcProgress = percent;
- }).then((src) => {
- attachment.src = src;
- return src;
+ }).then((res) => {
+ attachment.src = res.data as string;
+ return res;
});
return attachment.srcPromise;
};
attachment.loadThumbnail = () => {
if (attachment.thumbnail) {
- return Promise.resolve(attachment.thumbnail);
+ return Promise.resolve({data: attachment.thumbnail, type: "thumbnail"});
} else if (attachment.thumbnailPromise) {
return attachment.thumbnailPromise;
}
- attachment.thumbnailPromise = this._loadEventAttachmentOrThumbnail(event, true, (percent) => {
+ attachment.thumbnailPromise = this._loadEventAttachmentOrThumbnail(event, true, false, (percent) => {
attachment.thumbnailProgress = percent;
- }).then((thummbnail) => {
- attachment.thumbnail = thummbnail;
- return thummbnail;
+ }).then((res) => {
+ attachment.thumbnail = res.data as string;
+ if (res.type == "src") {
+ // Downloaded the src as thumb, so set "src" as well!
+ attachment.src = res.data as string;
+ }
+ return res;
});
return attachment.thumbnailPromise;
};
@@ -174,10 +198,13 @@ export class AttachmentManager {
private async _loadEventAttachmentOrThumbnail(
event: MatrixEvent & KeanuEventExtension,
thumbnail: boolean,
+ asBlob: boolean,
progress?: (percent: number) => void
- ): Promise {
+ ): Promise<{data: string | Blob, type: EventAttachmentUrlType}> {
await this.matrixClient.decryptEventIfNeeded(event);
+ let urltype: EventAttachmentUrlType = thumbnail ? "thumbnail" : "src";
+
const content = event.getContent();
var url = null;
var mime = "image/png";
@@ -227,7 +254,7 @@ export class AttachmentManager {
content.file &&
content.file.url &&
event.getContent()?.info?.size > 0 &&
- event.getContent()?.info?.size < this.maxSizeAutoDownloads
+ (!thumbnail || event.getContent()?.info?.size < this.maxSizeAutoDownloads)
) {
// No thumb, use real url
file = content.file;
@@ -241,6 +268,7 @@ export class AttachmentManager {
this.useAuthedMedia
);
mime = file.mimetype;
+ urltype = "src";
}
if (url == null) {
@@ -263,7 +291,8 @@ export class AttachmentManager {
const response = await axios.get(url, options);
const bytes = decrypt ? await this.decryptData(file, response) : { buffer: response.data };
- return URL.createObjectURL(new Blob([bytes.buffer], { type: mime }));
+ const blob = new Blob([bytes.buffer], { type: mime });
+ return {data: asBlob ? blob : URL.createObjectURL(blob), type: urltype};
}
private b64toBuffer(val: any) {
diff --git a/src/models/eventAttachment.ts b/src/models/eventAttachment.ts
index c30b745..2289bad 100644
--- a/src/models/eventAttachment.ts
+++ b/src/models/eventAttachment.ts
@@ -8,16 +8,24 @@ export type KeanuEventExtension = {
replyEvent?: MatrixEvent & KeanuEventExtension;
}
+export type EventAttachmentUrlType = "src" | "thumbnail";
+export type EventAttachmentLoadSrcOptions = {
+ asBlob?: boolean;
+}
+
export type EventAttachment = {
event: MatrixEvent & KeanuEventExtension;
+ name: string;
src?: string;
- thumbnail?: string;
- srcPromise?: Promise;
- thumbnailPromise?: Promise;
+ srcSize: number;
srcProgress: number;
+ srcPromise?: Promise<{data: string | Blob, type: EventAttachmentUrlType}>;
+ thumbnail?: string;
thumbnailProgress: number;
- loadSrc: () => void;
- loadThumbnail: () => Promise;
+ thumbnailPromise?: Promise<{data: string | Blob, type: EventAttachmentUrlType}>;
+ autoDownloadable: boolean;
+ loadSrc: (options?: EventAttachmentLoadSrcOptions) => Promise<{data: string | Blob, type: EventAttachmentUrlType}>;
+ loadThumbnail: () => Promise<{data: string | Blob, type: EventAttachmentUrlType}>;
release: (src: boolean, thumbnail: boolean) => void;
};