keanu-weblite/src/components/messages/composition/MessageImage.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>