97 lines
No EOL
2.9 KiB
Vue
97 lines
No EOL
2.9 KiB
Vue
<template>
|
|
<component
|
|
:is="rootComponent"
|
|
ref="root"
|
|
v-bind="{ ...$props, ...$attrs }">
|
|
<div class="bubble image-bubble" ref="imageRef">
|
|
<ImageWithProgress v-if="attachment"
|
|
:aspect-ratio="16 / 9"
|
|
ref="image"
|
|
:src="attachment.src ? attachment.src : attachment.thumbnail"
|
|
:cover="cover"
|
|
:contain="contain"
|
|
:loadingProgress="attachment.thumbnailProgress"
|
|
/>
|
|
</div>
|
|
<v-dialog v-model="dialog" :width="smAndUp ? '940px' : '90%'">
|
|
<ImageWithProgress :src="attachment?.src ? attachment.src : attachment?.thumbnail" :loadingProgress="attachment?.srcProgress" />
|
|
</v-dialog>
|
|
</component>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, inject, onMounted, ref, useTemplateRef, watch } from "vue";
|
|
import MessageIncoming from "./MessageIncoming.vue";
|
|
import MessageOutgoing from "./MessageOutgoing.vue";
|
|
import ImageWithProgress from "../../ImageWithProgress.vue";
|
|
import { useLazyLoad } from "./useLazyLoad";
|
|
import { useI18n } from "vue-i18n";
|
|
import { MessageEmits, MessageProps, useMessage } from "./useMessage";
|
|
import { EventAttachment } from "../../../models/eventAttachment";
|
|
import { useDisplay } from "vuetify";
|
|
import utils from "@/plugins/utils";
|
|
import Hammer from "hammerjs";
|
|
|
|
const { t } = useI18n()
|
|
const $matrix: any = inject('globalMatrix');
|
|
|
|
type RootType = InstanceType<typeof MessageOutgoing | typeof MessageIncoming>
|
|
const rootRef = useTemplateRef<RootType>("root");
|
|
const imageRef = useTemplateRef("imageRef");
|
|
|
|
const emits = defineEmits<MessageEmits>();
|
|
const props = defineProps<MessageProps>();
|
|
|
|
const cover = ref(true);
|
|
const contain = ref(false);
|
|
const dialog = ref(false);
|
|
|
|
const { smAndUp } = useDisplay();
|
|
|
|
const {
|
|
isVisible
|
|
} = useLazyLoad({ root: rootRef });
|
|
|
|
const {
|
|
event,
|
|
isIncoming,
|
|
attachment,
|
|
} = useMessage($matrix, t, props, emits, undefined);
|
|
|
|
const rootComponent = computed(() => {
|
|
return isIncoming.value ? MessageIncoming : MessageOutgoing;
|
|
})
|
|
|
|
watch([isVisible, attachment], ([_v, _a]: [_v: boolean, _a: EventAttachment | undefined]) => {
|
|
if (_v && _a) {
|
|
_a.loadThumbnail();
|
|
}
|
|
});
|
|
|
|
onMounted(() => {
|
|
const info = event.value?.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")) {
|
|
cover.value = true;
|
|
contain.value = false;
|
|
} else {
|
|
cover.value = false;
|
|
contain.value = true;
|
|
}
|
|
if (imageRef.value) {
|
|
const hammerInstance = utils.singleOrDoubleTabRecognizer(imageRef.value);
|
|
hammerInstance.on("singletap doubletap", (ev: Hammer.HammerInput) => {
|
|
if (ev.type === "singletap") {
|
|
attachment.value?.loadSrc();
|
|
dialog.value = true;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@use "@/assets/css/chat.scss" as *;
|
|
</style> |