Work on attachments
This commit is contained in:
parent
ec79a33eab
commit
842c87dc96
28 changed files with 2714 additions and 798 deletions
|
|
@ -1,36 +1,38 @@
|
|||
<template>
|
||||
<message-incoming v-bind="{...$props, ...$attrs}">
|
||||
<message-incoming v-bind="{ ...$props, ...$attrs }">
|
||||
<div class="bubble image-bubble" ref="imageRef">
|
||||
<v-img
|
||||
<ImageWithProgress
|
||||
:aspect-ratio="16 / 9"
|
||||
ref="image"
|
||||
:src="src"
|
||||
:src="src ? src : thumbnailSrc"
|
||||
:cover="cover"
|
||||
:contain="contain"
|
||||
:loadingProgress="thumbnailProgress"
|
||||
/>
|
||||
</div>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
:width="$vuetify.display.smAndUp ? '940px' : '90%'"
|
||||
>
|
||||
<v-img :src="src"/>
|
||||
<v-dialog v-model="dialog" :width="$vuetify.display.smAndUp ? '940px' : '90%'">
|
||||
<ImageWithProgress :src="src ? src : thumbnailSrc" :loadingProgress="srcProgress" />
|
||||
</v-dialog>
|
||||
</message-incoming>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import util from "../../plugins/utils";
|
||||
import MessageIncoming from './MessageIncoming.vue';
|
||||
import ImageWithProgress from "../ImageWithProgress.vue";
|
||||
import MessageIncoming from "./MessageIncoming.vue";
|
||||
|
||||
export default {
|
||||
extends: MessageIncoming,
|
||||
components: { MessageIncoming },
|
||||
components: { MessageIncoming, ImageWithProgress },
|
||||
data() {
|
||||
return {
|
||||
src: undefined,
|
||||
thumbnailSrc: undefined,
|
||||
srcProgress: -1,
|
||||
thumbnailProgress: -1,
|
||||
cover: true,
|
||||
contain: false,
|
||||
dialog: false
|
||||
dialog: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -39,48 +41,57 @@ export default {
|
|||
const hammerInstance = util.singleOrDoubleTabRecognizer(element);
|
||||
|
||||
hammerInstance.on("singletap doubletap", (ev) => {
|
||||
if(ev.type === 'singletap') {
|
||||
if (ev.type === "singletap") {
|
||||
this.$matrix.attachmentManager
|
||||
.loadEventAttachment(
|
||||
this.event,
|
||||
(percent) => {
|
||||
this.srcProgress = percent;
|
||||
},
|
||||
this
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch attachment: ", err);
|
||||
});
|
||||
this.dialog = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
//console.log("Mounted with event:", JSON.stringify(this.event.getContent()));
|
||||
const width = this.$refs.image.$el.clientWidth;
|
||||
const height = (width * 9) / 16;
|
||||
util
|
||||
.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, this.event, this.$config, width, height)
|
||||
.then((url) => {
|
||||
const info = this.event.getContent().info;
|
||||
// JPEGs use cover, PNG and GIF ect contain. This is because PNG and GIF are expected to
|
||||
// be stickers and small emoji type things.
|
||||
if (info && info.mimetype && info.mimetype.startsWith("image/jp")) {
|
||||
this.cover = true;
|
||||
this.contain = false;
|
||||
} else {
|
||||
this.cover = false;
|
||||
this.contain = true;
|
||||
}
|
||||
this.src = url;
|
||||
if(this.$refs.imageRef) {
|
||||
this.initMessageInImageHammerJs(this.$refs.imageRef);
|
||||
}
|
||||
})
|
||||
const info = this.event.getContent().info;
|
||||
// JPEGs use cover, PNG and GIF ect contain. This is because PNG and GIF are expected to
|
||||
// be stickers and small emoji type things.
|
||||
if (info && info.mimetype && info.mimetype.startsWith("image/jp")) {
|
||||
this.cover = true;
|
||||
this.contain = false;
|
||||
} else {
|
||||
this.cover = false;
|
||||
this.contain = true;
|
||||
}
|
||||
if (this.$refs.imageRef) {
|
||||
this.initMessageInImageHammerJs(this.$refs.imageRef);
|
||||
}
|
||||
|
||||
this.$matrix.attachmentManager
|
||||
.loadEventThumbnail(
|
||||
this.event,
|
||||
(percent) => {
|
||||
this.thumbnailProgress = percent;
|
||||
},
|
||||
this
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.src) {
|
||||
const objectUrl = this.src;
|
||||
this.src = null;
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
this.$matrix.attachmentManager.releaseEvent(this.event);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/assets/css/chat.scss" as *;
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,35 +3,48 @@
|
|||
<div class="bubble">
|
||||
<div class="original-message" v-if="inReplyToText">
|
||||
<div class="original-message-sender">{{ inReplyToSender }}</div>
|
||||
<div
|
||||
class="original-message-text"
|
||||
v-html="linkify($sanitize(inReplyToText))"
|
||||
/>
|
||||
<div class="original-message-text" v-html="linkify($sanitize(inReplyToText))" />
|
||||
</div>
|
||||
|
||||
<div class="message">
|
||||
<SwipeableThumbnailsView :items="items" v-if="!event.isRedacted() && room.displayType == ROOM_TYPE_CHANNEL" v-bind="$attrs" />
|
||||
<SwipeableThumbnailsView
|
||||
:items="items"
|
||||
v-if="!event.isRedacted() && room.displayType == ROOM_TYPE_CHANNEL"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
<v-container v-else-if="!event.isRedacted()" fluid class="imageCollection">
|
||||
<v-row wrap>
|
||||
<v-col v-for="({ size, item }) in layoutedItems()" :key="item.event.getId()" :cols="size">
|
||||
<ThumbnailView :item="item" :previewOnly="true" v-on:itemclick="onItemClick($event)" />
|
||||
<v-col v-for="{ size, item } in layoutedItems()" :key="item.event.getId()" :cols="size">
|
||||
<ThumbnailView :item="item" :previewOnly="true" v-on:itemclick="onItemClick($event)" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<i v-if="event.isRedacted()" class="deleted-text">
|
||||
<v-icon :color="this.senderIsAdminOrModerator(this.event) ? 'white' : ''" size="small">block</v-icon>
|
||||
{{ redactedBySomeoneElse(event) ? $t('message.incoming_message_deleted_text') : $t('message.outgoing_message_deleted_text')}}
|
||||
{{
|
||||
redactedBySomeoneElse(event)
|
||||
? $t("message.incoming_message_deleted_text")
|
||||
: $t("message.outgoing_message_deleted_text")
|
||||
}}
|
||||
</i>
|
||||
<span v-html="linkify($sanitize(messageText))" v-else-if="messageText" />
|
||||
<span class="edit-marker" v-if="event.replacingEventId() && !event.isRedacted()">
|
||||
{{ $t('message.edited') }}
|
||||
{{ $t("message.edited") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<GalleryItemsView :originalEvent="originalEvent" :items="items" :initialItem="showItem" v-if="!!showItem" v-on:close="showItem = null" />
|
||||
<GalleryItemsView
|
||||
:originalEvent="originalEvent"
|
||||
:items="items"
|
||||
:initialItem="showItem"
|
||||
v-if="!!showItem"
|
||||
v-on:close="showItem = null"
|
||||
/>
|
||||
</message-incoming>
|
||||
<component v-else-if="items.length == 1" :is="componentFn(items[0].event)"
|
||||
v-bind="{...$props, ...$attrs}"
|
||||
<component
|
||||
v-else-if="items.length == 1"
|
||||
:is="componentFn(items[0].event)"
|
||||
v-bind="{ ...$props, ...$attrs }"
|
||||
:originalEvent="items[0].event"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -40,24 +53,33 @@
|
|||
import MessageIncoming from "./MessageIncoming.vue";
|
||||
import messageMixin from "./messageMixin";
|
||||
import util, { ROOM_TYPE_CHANNEL, ROOM_TYPE_FILE_MODE } from "../../plugins/utils";
|
||||
import GalleryItemsView from '../file_mode/GalleryItemsView.vue';
|
||||
import ThumbnailView from '../file_mode/ThumbnailView.vue';
|
||||
import GalleryItemsView from "../file_mode/GalleryItemsView.vue";
|
||||
import ThumbnailView from "../file_mode/ThumbnailView.vue";
|
||||
import SwipeableThumbnailsView from "./channel/SwipeableThumbnailsView.vue";
|
||||
import { reactive } from "vue";
|
||||
|
||||
export default {
|
||||
extends: MessageIncoming,
|
||||
components: { MessageIncoming, GalleryItemsView, ThumbnailView, SwipeableThumbnailsView },
|
||||
components: {
|
||||
MessageIncoming,
|
||||
GalleryItemsView,
|
||||
ThumbnailView,
|
||||
SwipeableThumbnailsView,
|
||||
},
|
||||
mixins: [messageMixin],
|
||||
data() {
|
||||
return {
|
||||
ROOM_TYPE_CHANNEL: ROOM_TYPE_CHANNEL,
|
||||
items: [],
|
||||
showItem: null,
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(
|
||||
this.event.getId(),
|
||||
util.threadMessageType(),
|
||||
"m.room.message"
|
||||
);
|
||||
if (!this.thread) {
|
||||
this.event.on("Event.relationsCreated", this.onRelationsCreated);
|
||||
}
|
||||
|
|
@ -67,42 +89,66 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
forceMultiview() {
|
||||
return this.room.displayType == ROOM_TYPE_FILE_MODE || (this.room.displayType == ROOM_TYPE_CHANNEL && this.items.length == 1 && util.isFileTypePDF(this.items[0].event));
|
||||
}
|
||||
return (
|
||||
this.room.displayType == ROOM_TYPE_FILE_MODE ||
|
||||
(this.room.displayType == ROOM_TYPE_CHANNEL &&
|
||||
this.items.length == 1 &&
|
||||
util.isFileTypePDF(this.items[0].event))
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onRelationsCreated() {
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(
|
||||
this.event.getId(),
|
||||
util.threadMessageType(),
|
||||
"m.room.message"
|
||||
);
|
||||
this.event.off("Event.relationsCreated", this.onRelationsCreated);
|
||||
},
|
||||
onItemClick(event) {
|
||||
this.showItem = event.item;
|
||||
},
|
||||
processThread() {
|
||||
this.$emit('layout-change', () => {
|
||||
this.items = this.timelineSet.relations.getAllChildEventsForEvent(this.event.getId())
|
||||
.filter(e => !e.isRedacted() && util.downloadableTypes().includes(e.getContent().msgtype))
|
||||
.map(e => {
|
||||
let ret = reactive({
|
||||
event: e,
|
||||
src: null,
|
||||
});
|
||||
ret.promise = this.$matrix.matrixClient.decryptEventIfNeeded(e)
|
||||
.then(() => util.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, e, this.$config, 100, 100))
|
||||
.then((url) => {
|
||||
ret.src = url;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
if (!this.event.isRedacted()) {
|
||||
this.$emit(
|
||||
"layout-change",
|
||||
() => {
|
||||
const items = this.timelineSet.relations
|
||||
.getAllChildEventsForEvent(this.event.getId())
|
||||
.filter((e) => !e.isRedacted() && util.downloadableTypes().includes(e.getContent().msgtype));
|
||||
|
||||
this.items = items.map((e) => {
|
||||
let ret = reactive({
|
||||
event: e,
|
||||
src: null,
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
}, this.$el);
|
||||
if (items.length > 1) {
|
||||
ret.promise = this.$matrix.matrixClient
|
||||
.decryptEventIfNeeded(e)
|
||||
.then(() =>
|
||||
util.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, e, this.$config, 100, 100)
|
||||
)
|
||||
.then((url) => {
|
||||
ret.src = url;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
},
|
||||
this.$el
|
||||
);
|
||||
}
|
||||
},
|
||||
layoutedItems() {
|
||||
if (!this.items || this.items.length == 0) { return [] }
|
||||
if (!this.items || this.items.length == 0) {
|
||||
return [];
|
||||
}
|
||||
let array = this.items.slice(0);
|
||||
let rows = []
|
||||
let rows = [];
|
||||
while (array.length > 0) {
|
||||
if (array.length >= 7) {
|
||||
rows.push({ size: 6, item: array[0] });
|
||||
|
|
@ -127,12 +173,12 @@ export default {
|
|||
array = array.slice(1);
|
||||
}
|
||||
}
|
||||
return rows
|
||||
return rows;
|
||||
},
|
||||
downloadAll() {
|
||||
this.items.forEach(item => util.download(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, item.event));
|
||||
}
|
||||
}
|
||||
this.items.forEach((item) => util.download(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, item.event));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -159,4 +205,4 @@ export default {
|
|||
padding: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,36 +1,38 @@
|
|||
<template>
|
||||
<message-outgoing v-bind="{ ...$props, ...$attrs }">
|
||||
<div class="bubble image-bubble" ref="imageRef">
|
||||
<v-img
|
||||
<ImageWithProgress
|
||||
:aspect-ratio="16 / 9"
|
||||
ref="image"
|
||||
:src="src"
|
||||
:src="src ? src : thumbnailSrc"
|
||||
:cover="cover"
|
||||
:contain="contain"
|
||||
:loadingProgress="thumbnailProgress"
|
||||
/>
|
||||
</div>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
:width="$vuetify.display.smAndUp ? '940px' : '90%'"
|
||||
>
|
||||
<v-img :src="src"/>
|
||||
<v-dialog v-model="dialog" :width="$vuetify.display.smAndUp ? '940px' : '90%'">
|
||||
<ImageWithProgress :src="src ? src : thumbnailSrc" :loadingProgress="srcProgress" />
|
||||
</v-dialog>
|
||||
</message-outgoing>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import util from "../../plugins/utils";
|
||||
import ImageWithProgress from "../ImageWithProgress.vue";
|
||||
import MessageOutgoing from "./MessageOutgoing.vue";
|
||||
|
||||
export default {
|
||||
extends: MessageOutgoing,
|
||||
components: { MessageOutgoing },
|
||||
components: { MessageOutgoing, ImageWithProgress },
|
||||
data() {
|
||||
return {
|
||||
src: undefined,
|
||||
thumbnailSrc: undefined,
|
||||
srcProgress: -1,
|
||||
thumbnailProgress: -1,
|
||||
cover: true,
|
||||
contain: false,
|
||||
dialog: false
|
||||
dialog: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -39,47 +41,56 @@ export default {
|
|||
const hammerInstance = util.singleOrDoubleTabRecognizer(element);
|
||||
|
||||
hammerInstance.on("singletap doubletap", (ev) => {
|
||||
if(ev.type === 'singletap') {
|
||||
if (ev.type === "singletap") {
|
||||
this.$matrix.attachmentManager
|
||||
.loadEventAttachment(
|
||||
this.event,
|
||||
(percent) => {
|
||||
this.srcProgress = percent;
|
||||
},
|
||||
this
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch attachment: ", err);
|
||||
});
|
||||
this.dialog = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const width = this.$refs.image.$el.clientWidth;
|
||||
const height = (width * 9) / 16;
|
||||
util
|
||||
.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, this.event, this.$config, width, height)
|
||||
.then((url) => {
|
||||
const info = this.event.getContent().info;
|
||||
// JPEGs use cover, PNG and GIF ect contain. This is because PNG and GIF are expected to
|
||||
// be stickers and small emoji type things.
|
||||
if (info && info.mimetype && info.mimetype.startsWith("image/jp")) {
|
||||
this.cover = true;
|
||||
this.contain = false;
|
||||
} else {
|
||||
this.cover = false;
|
||||
this.contain = true;
|
||||
}
|
||||
this.src = url;
|
||||
if(this.$refs.imageRef) {
|
||||
this.initMessageOutImageHammerJs(this.$refs.imageRef);
|
||||
}
|
||||
})
|
||||
const info = this.event.getContent().info;
|
||||
// JPEGs use cover, PNG and GIF ect contain. This is because PNG and GIF are expected to
|
||||
// be stickers and small emoji type things.
|
||||
if (info && info.mimetype && info.mimetype.startsWith("image/jp")) {
|
||||
this.cover = true;
|
||||
this.contain = false;
|
||||
} else {
|
||||
this.cover = false;
|
||||
this.contain = true;
|
||||
}
|
||||
if (this.$refs.imageRef) {
|
||||
this.initMessageOutImageHammerJs(this.$refs.imageRef);
|
||||
}
|
||||
|
||||
this.$matrix.attachmentManager
|
||||
.loadEventThumbnail(
|
||||
this.event,
|
||||
(percent) => {
|
||||
this.thumbnailProgress = percent;
|
||||
},
|
||||
this
|
||||
)
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
});
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.src) {
|
||||
const objectUrl = this.src;
|
||||
this.src = null;
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
this.$matrix.attachmentManager.releaseEvent(this.event);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@use "@/assets/css/chat.scss" as *;
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -3,46 +3,46 @@
|
|||
<div class="bubble">
|
||||
<div class="original-message" v-if="inReplyToText">
|
||||
<div class="original-message-sender">{{ inReplyToSender }}</div>
|
||||
<div
|
||||
class="original-message-text"
|
||||
v-html="linkify($sanitize(inReplyToText))"
|
||||
/>
|
||||
<div class="original-message-text" v-html="linkify($sanitize(inReplyToText))" />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="message">
|
||||
<SwipeableThumbnailsView :items="items" v-if="!event.isRedacted() && room.displayType == ROOM_TYPE_CHANNEL" v-bind="$attrs" />
|
||||
<SwipeableThumbnailsView :items="items" v-if="!event.isRedacted() && room.displayType == ROOM_TYPE_CHANNEL"
|
||||
v-bind="$attrs" />
|
||||
<v-container v-else-if="!event.isRedacted()" fluid class="imageCollection">
|
||||
<v-row wrap>
|
||||
<v-col v-for="({ size, item }) in layoutedItems()" :key="item.event.getId()" :cols="size">
|
||||
<v-col v-for="{ size, item } in layoutedItems()" :key="item.event.getId()" :cols="size">
|
||||
<ThumbnailView :item="item" :previewOnly="true" v-on:itemclick="onItemClick($event)" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
<i v-if="event.isRedacted()" class="deleted-text">
|
||||
<v-icon size="small">block</v-icon>
|
||||
{{ redactedBySomeoneElse(event) ? $t('message.incoming_message_deleted_text') : $t('message.outgoing_message_deleted_text')}}
|
||||
{{
|
||||
redactedBySomeoneElse(event)
|
||||
? $t("message.incoming_message_deleted_text")
|
||||
: $t("message.outgoing_message_deleted_text")
|
||||
}}
|
||||
</i>
|
||||
<span v-html="linkify($sanitize(messageText))" v-else-if="messageText" />
|
||||
<span class="edit-marker" v-if="event.replacingEventId() && !event.isRedacted()">
|
||||
{{ $t('message.edited') }}
|
||||
{{ $t("message.edited") }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<GalleryItemsView :originalEvent="originalEvent" :items="items" :initialItem="showItem" v-if="!!showItem" v-on:close="showItem = null" />
|
||||
<GalleryItemsView :originalEvent="originalEvent" :items="items" :initialItem="showItem" v-if="!!showItem"
|
||||
v-on:close="showItem = null" />
|
||||
</message-outgoing>
|
||||
<component v-else-if="items.length == 1" :is="componentFn(items[0].event)"
|
||||
v-bind="{...$props, ...$attrs}"
|
||||
:originalEvent="items[0].event"
|
||||
/>
|
||||
<component v-else-if="items.length == 1" :is="componentFn(items[0].event)" v-bind="{ ...$props, ...$attrs }"
|
||||
:originalEvent="items[0].event" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MessageOutgoing from "./MessageOutgoing.vue";
|
||||
import messageMixin from "./messageMixin";
|
||||
import util, { ROOM_TYPE_CHANNEL } from "../../plugins/utils";
|
||||
import GalleryItemsView from '../file_mode/GalleryItemsView.vue';
|
||||
import ThumbnailView from '../file_mode/ThumbnailView.vue';
|
||||
import GalleryItemsView from "../file_mode/GalleryItemsView.vue";
|
||||
import ThumbnailView from "../file_mode/ThumbnailView.vue";
|
||||
import SwipeableThumbnailsView from "./channel/SwipeableThumbnailsView.vue";
|
||||
import { reactive } from "vue";
|
||||
|
||||
|
|
@ -55,10 +55,14 @@ export default {
|
|||
ROOM_TYPE_CHANNEL: ROOM_TYPE_CHANNEL,
|
||||
items: [],
|
||||
showItem: null,
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(
|
||||
this.event.getId(),
|
||||
util.threadMessageType(),
|
||||
"m.room.message"
|
||||
);
|
||||
if (!this.thread) {
|
||||
this.event.on("Event.relationsCreated", this.onRelationsCreated);
|
||||
}
|
||||
|
|
@ -68,42 +72,65 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
forceMultiview() {
|
||||
return this.room.displayType == ROOM_TYPE_CHANNEL && this.items.length == 1 && util.isFileTypePDF(this.items[0].event);
|
||||
}
|
||||
return (
|
||||
this.room.displayType == ROOM_TYPE_CHANNEL && this.items.length == 1 && util.isFileTypePDF(this.items[0].event)
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onRelationsCreated() {
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
||||
this.thread = this.timelineSet.relations.getChildEventsForEvent(
|
||||
this.event.getId(),
|
||||
util.threadMessageType(),
|
||||
"m.room.message"
|
||||
);
|
||||
this.event.off("Event.relationsCreated", this.onRelationsCreated);
|
||||
},
|
||||
onItemClick(event) {
|
||||
this.showItem = event.item;
|
||||
},
|
||||
processThread() {
|
||||
this.$emit('layout-change', () => {
|
||||
this.items = this.timelineSet.relations.getAllChildEventsForEvent(this.event.getId())
|
||||
.filter(e => !e.isRedacted() && util.downloadableTypes().includes(e.getContent().msgtype))
|
||||
.map(e => {
|
||||
let ret = reactive({
|
||||
event: e,
|
||||
src: null,
|
||||
});
|
||||
ret.promise = this.$matrix.matrixClient.decryptEventIfNeeded(e)
|
||||
.then(() => util.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, e, this.$config, 100, 100))
|
||||
.then((url) => {
|
||||
ret.src = url;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
if (!this.event.isRedacted()) {
|
||||
this.$emit(
|
||||
"layout-change",
|
||||
() => {
|
||||
const items = this.timelineSet.relations
|
||||
.getAllChildEventsForEvent(this.event.getId())
|
||||
.filter((e) => !e.isRedacted() && util.downloadableTypes().includes(e.getContent().msgtype));
|
||||
|
||||
this.items = items.map((e) => {
|
||||
let ret = reactive({
|
||||
event: e,
|
||||
src: null,
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
}, this.$el);
|
||||
if (items.length > 1) {
|
||||
// Only do if items more than one. If one, the individual component in <component> above will do the work.
|
||||
//
|
||||
ret.promise = this.$matrix.matrixClient
|
||||
.decryptEventIfNeeded(e)
|
||||
.then(() =>
|
||||
util.getThumbnail(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, e, this.$config, 100, 100)
|
||||
)
|
||||
.then((url) => {
|
||||
ret.src = url;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Failed to fetch thumbnail: ", err);
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
},
|
||||
this.$el
|
||||
);
|
||||
}
|
||||
},
|
||||
layoutedItems() {
|
||||
if (!this.items || this.items.length == 0) { return [] }
|
||||
if (!this.items || this.items.length == 0) {
|
||||
return [];
|
||||
}
|
||||
let array = this.items.slice(0);
|
||||
let rows = []
|
||||
let rows = [];
|
||||
while (array.length > 0) {
|
||||
if (array.length >= 7) {
|
||||
rows.push({ size: 6, item: array[0] });
|
||||
|
|
@ -128,9 +155,9 @@ export default {
|
|||
array = array.slice(1);
|
||||
}
|
||||
}
|
||||
return rows
|
||||
return rows;
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
|
@ -165,4 +192,4 @@ export default {
|
|||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ export default {
|
|||
}
|
||||
if (newValue) {
|
||||
newValue.on("Relations.add", this.onAddRelation);
|
||||
this.processThread();
|
||||
}
|
||||
this.processThread();
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue