feat: attachment preview
Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useUser } from '@KTXC'
|
||||
import { useMailUiStore } from '@/stores/mailUiStore'
|
||||
import type { EntityObject, MessageObject } from '@MailManager/models'
|
||||
import { SecurityLevel } from '@/utile/emailSanitizer'
|
||||
import { useMailUiStore } from '@/stores/mailUiStore'
|
||||
import { mediaViewerCanDisplay, mediaViewerComponent } from '@/services/mediaViewer'
|
||||
import type { MediaViewerItem } from '@/types/mediaViewer'
|
||||
import ReaderEmpty from './reader/ReaderEmpty.vue'
|
||||
import ReaderToolbar from './reader/ReaderToolbar.vue'
|
||||
import ReaderHeader from './reader/ReaderHeader.vue'
|
||||
@@ -28,10 +30,14 @@ const emit = defineEmits<{
|
||||
const { getSetting } = useUser()
|
||||
const mailUiStore = useMailUiStore()
|
||||
|
||||
// Per-message overrides
|
||||
// Security overrides
|
||||
const allowImages = ref(false)
|
||||
const overrideSecurityLevel = ref<SecurityLevel | null>(null)
|
||||
|
||||
// Viewer state
|
||||
const showViewer = ref(false)
|
||||
const viewerIndex = ref(0)
|
||||
|
||||
// Computed
|
||||
const message = computed<MessageObject | null>(() => {
|
||||
return props.entity?.properties ?? null
|
||||
@@ -55,12 +61,35 @@ const effectiveSecurityLevel = computed(() => {
|
||||
return overrideSecurityLevel.value ?? securityLevel.value
|
||||
})
|
||||
|
||||
// Preview state
|
||||
const previewDialog = computed(() => mediaViewerComponent('dialog'))
|
||||
const previewItems = computed<MediaViewerItem[]>(() => {
|
||||
const attachments = message.value?.attachments ?? []
|
||||
const items: MediaViewerItem[] = []
|
||||
attachments.forEach((attachment, index) => {
|
||||
if (!mediaViewerCanDisplay(attachment.type)) return
|
||||
items.push({
|
||||
id: attachment.partId || attachment.blobId || attachment.cid || `att-${index}`,
|
||||
title: attachment.name || 'Attachment',
|
||||
mime: attachment.type || '',
|
||||
size: attachment.size ?? null,
|
||||
meta: { index, attachment },
|
||||
})
|
||||
})
|
||||
return items
|
||||
})
|
||||
|
||||
// Reset overrides when message changes
|
||||
watch(() => props.entity, () => {
|
||||
allowImages.value = allowImagesDefault.value
|
||||
overrideSecurityLevel.value = null
|
||||
})
|
||||
|
||||
// Close the viewer when switching messages.
|
||||
watch(() => props.entity, () => {
|
||||
showViewer.value = false
|
||||
})
|
||||
|
||||
// Toggle images for current message only
|
||||
const toggleImages = () => {
|
||||
allowImages.value = !allowImages.value
|
||||
@@ -113,6 +142,22 @@ const handleFlag = () => {
|
||||
const handleCompose = () => {
|
||||
emit('compose')
|
||||
}
|
||||
|
||||
const handlePreview = (index: number) => {
|
||||
const pos = previewItems.value.findIndex(item => item.meta.index === index)
|
||||
if (pos < 0) return
|
||||
viewerIndex.value = pos
|
||||
showViewer.value = true
|
||||
}
|
||||
|
||||
const handleViewerRetrieve = (item: MediaViewerItem): Promise<Blob> => {
|
||||
if (!props.entity) return Promise.reject(new Error('No message selected'))
|
||||
return mailUiStore.attachmentBlob(props.entity, item.meta.attachment)
|
||||
}
|
||||
|
||||
const handleViewerDownload = (item: MediaViewerItem) => {
|
||||
if (props.entity) mailUiStore.downloadMessage(props.entity, item.meta.index)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -135,7 +180,7 @@ const handleCompose = () => {
|
||||
@move="handleMove"
|
||||
@delete="handleDelete"
|
||||
@flag="handleFlag"
|
||||
@download="handleDownload()"
|
||||
@download="handleDownload"
|
||||
@toggle-images="toggleImages"
|
||||
@set-security-level="setSecurityLevel"
|
||||
/>
|
||||
@@ -144,7 +189,8 @@ const handleCompose = () => {
|
||||
<div class="message-content">
|
||||
<ReaderHeader
|
||||
:entity="props.entity"
|
||||
@download-attachment="handleDownload"
|
||||
@download="handleDownload"
|
||||
@preview="handlePreview"
|
||||
/>
|
||||
|
||||
<v-divider />
|
||||
@@ -155,6 +201,19 @@ const handleCompose = () => {
|
||||
:allow-images="allowImages"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Inline attachment viewer (provided by the media_viewer module) -->
|
||||
<component
|
||||
:is="previewDialog"
|
||||
v-if="previewDialog"
|
||||
v-model="showViewer"
|
||||
:items="previewItems"
|
||||
:index="viewerIndex"
|
||||
:source="handleViewerRetrieve"
|
||||
:download="handleViewerDownload"
|
||||
:navigation="true"
|
||||
@update:index="viewerIndex = $event"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user