keanu-weblite/src/components/file_mode/ThumbnailView.vue

165 lines
4.5 KiB
Vue
Raw Normal View History

2023-10-25 10:44:25 +00:00
<template>
<div ref="thumbnailRef" style="width: 100%; height: 100%">
2025-07-10 09:46:07 +02:00
<v-responsive v-if="isVideo && (source || poster)" :class="{ 'thumbnail-item': true, preview: previewOnly }">
<video :src="source" :poster="poster" :controls="!previewOnly" class="w-100 h-100">
2025-06-09 09:44:49 +02:00
{{ $t("fallbacks.video_file") }}
</video>
</v-responsive>
<ImageWithProgress
v-else-if="isImage"
2025-06-09 09:44:49 +02:00
:aspect-ratio="previewOnly ? 16 / 9 : undefined"
:class="{ 'thumbnail-item': true, preview: previewOnly }"
:src="source"
2025-06-09 09:44:49 +02:00
:contain="!previewOnly"
:cover="previewOnly"
:loadingProgress="loadingProgress"
2025-06-09 09:44:49 +02:00
/>
<div v-else :class="{ 'thumbnail-item': true, preview: previewOnly, 'file-item': true }">
<v-icon :class="fileTypeIconClass">{{ fileTypeIcon }}</v-icon>
<div class="file-name">{{ $$sanitize(fileName) }}</div>
2025-06-09 09:44:49 +02:00
<div class="file-size">{{ fileSize }}</div>
2023-10-25 10:44:25 +00:00
</div>
2025-06-09 09:44:49 +02:00
</div>
2023-10-25 10:44:25 +00:00
</template>
<script setup lang="ts">
import utils from "../../plugins/utils";
import { computed, inject, onBeforeUnmount, onMounted, Ref, ref, useTemplateRef, watch } from "vue";
2025-06-09 09:44:49 +02:00
import { EventAttachment } from "../../models/eventAttachment";
import { useThumbnail } from "../messages/composition/useThumbnail";
import { Attachment } from "../../models/attachment";
2025-07-15 10:02:14 +02:00
import ImageWithProgress from "../ImageWithProgress.vue";
2023-12-04 11:29:23 +01:00
const $$sanitize: any = inject("globalSanitize");
const thumbnailRef = useTemplateRef("thumbnailRef");
interface ThumbnailProps {
item?: EventAttachment;
file?: Attachment;
previewOnly?: boolean;
}
2025-06-09 09:44:49 +02:00
type ThumbnailEmits = {
(event: "itemclick", value: { item: EventAttachment }): void;
};
const props = defineProps<ThumbnailProps>();
const { item, file, previewOnly = false } = props;
const emits = defineEmits<ThumbnailEmits>();
let { isVideo, isImage, fileTypeIcon, fileTypeIconClass, fileName, fileSize } = useThumbnail(file?.file ?? item?.event);
const fileURL: Ref<string | undefined> = ref(undefined);
2025-07-15 10:02:14 +02:00
const source: Ref<string | undefined> = ref(undefined);
2025-07-10 09:46:07 +02:00
const poster: Ref<string | undefined> = ref(undefined);
2025-07-15 10:02:14 +02:00
const updateSource = () => {
if (props.item) {
if (isVideo.value || props.item.src) {
source.value = props.item.src;
} else if (previewOnly) {
props.item.loadThumbnail().then((url) => {
source.value = url.data;
})
} else if (isImage.value) {
props.item.loadSrc().then((url) => {
source.value = url.data;
})
}
} else if (props.file) {
if (fileURL.value) {
URL.revokeObjectURL(fileURL.value);
}
fileURL.value = URL.createObjectURL(props.file.file);
source.value = fileURL.value;
} else {
source.value = undefined;
}
};
2025-07-10 09:46:07 +02:00
const updatePoster = () => {
if (props.item && isVideo.value) {
if (props.item.thumbnail) {
poster.value = props.item.thumbnail;
} else {
props.item
.loadThumbnail()
.then((url) => {
poster.value = url.data;
})
.catch(() => {
poster.value = undefined;
});
}
}
};
2025-07-15 10:02:14 +02:00
updateSource();
2025-07-10 09:46:07 +02:00
updatePoster();
2025-07-15 10:02:14 +02:00
watch(props, (props: ThumbnailProps) => {
const updates = useThumbnail(props.file?.file ?? props.item?.event);
isVideo.value = updates.isVideo.value;
isImage.value = updates.isImage.value;
fileTypeIcon = updates.fileTypeIcon;
fileTypeIconClass = updates.fileTypeIconClass;
fileName = updates.fileName;
fileSize = updates.fileSize;
2025-07-15 10:02:14 +02:00
updateSource();
2025-07-10 09:46:07 +02:00
updatePoster();
});
const loadingProgress = computed(() => {
if (item) {
return previewOnly ? item.thumbnailProgress : item.srcProgress;
}
return -1;
});
onMounted(() => {
if (thumbnailRef.value && (item as EventAttachment)) {
const hammerInstance = utils.singleOrDoubleTabRecognizer(thumbnailRef.value);
hammerInstance.on("singletap doubletap", (ev: any) => {
if (ev.type === "singletap") {
emits("itemclick", { item: item as EventAttachment });
}
});
}
if (!previewOnly && item && (item as EventAttachment)) {
(item as EventAttachment).loadSrc();
}
});
onBeforeUnmount(() => {
if (fileURL.value) {
URL.revokeObjectURL(fileURL.value);
fileURL.value = undefined;
}
2025-06-09 09:44:49 +02:00
});
2023-10-25 10:44:25 +00:00
</script>
<style lang="scss">
@use "@/assets/css/chat.scss" as *;
2023-10-25 10:44:25 +00:00
.thumbnail-item {
2025-06-09 09:44:49 +02:00
width: 100%;
height: 100%;
margin: 0;
padding: 0;
2023-10-25 10:44:25 +00:00
}
.file-item {
2025-06-09 09:44:49 +02:00
display: flex;
align-items: center;
justify-content: center;
font-size: 0.6rem;
flex-direction: column;
padding: 20px;
.v-icon {
margin-bottom: 10px;
color: currentColor;
}
2023-10-25 10:44:25 +00:00
}
2025-06-09 09:44:49 +02:00
</style>