From 75dfb67754641e76718fbb0ea97f10b2c4505e1e Mon Sep 17 00:00:00 2001 From: kura Date: Fri, 1 May 2026 23:38:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8B=96=E5=85=A5=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 57 +++++++++++++++++++++++++++++++ src/components/SubtitleEditor.vue | 2 +- src/locales/en.ts | 3 ++ src/locales/zh-CN.ts | 3 ++ src/style.css | 49 ++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/App.vue b/src/App.vue index b84bf37..53299a3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n' import { invoke } from '@tauri-apps/api/core' import { open } from '@tauri-apps/plugin-dialog' import { listen, type UnlistenFn } from '@tauri-apps/api/event' +import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' import TaskQueue from './components/TaskQueue.vue' import SubtitleEditor from './components/SubtitleEditor.vue' import { useTaskStore } from './stores/tasks' @@ -71,7 +72,9 @@ const translationConfig = ref({ const pending = ref(false) const feedback = ref('') const showAdvanced = ref(false) +const isDragging = ref(false) let unlistenMenuAction: UnlistenFn | null = null +let dragDropUnlistenFn: UnlistenFn | null = null const selectedTask = computed(() => taskStore.selectedTask) const hasTranslationKey = computed(() => translationConfig.value.apiKey.trim().length > 0) @@ -80,6 +83,7 @@ onMounted(() => { taskStore.initialize() void loadDefaultModelPaths() void bindMenuActions() + void initDragDrop() }) onUnmounted(() => { @@ -87,6 +91,10 @@ onUnmounted(() => { unlistenMenuAction() unlistenMenuAction = null } + if (dragDropUnlistenFn) { + dragDropUnlistenFn() + dragDropUnlistenFn = null + } }) watch(locale, (newLocale) => { @@ -219,6 +227,43 @@ async function handlePickFiles() { } } +function getFileExtension(filePath: string): string { + const lastDot = filePath.lastIndexOf('.') + if (lastDot === -1) return '' + return filePath.slice(lastDot + 1).toLowerCase() +} + +function isMediaFile(filePath: string): boolean { + const ext = getFileExtension(filePath) + return MEDIA_EXTENSIONS.includes(ext as typeof MEDIA_EXTENSIONS[number]) +} + +async function initDragDrop() { + try { + dragDropUnlistenFn = await getCurrentWebviewWindow().onDragDropEvent((event) => { + if (event.payload.type === 'enter' || event.payload.type === 'over') { + isDragging.value = true + } else if (event.payload.type === 'leave') { + isDragging.value = false + } else if (event.payload.type === 'drop') { + isDragging.value = false + const mediaFiles = event.payload.paths.filter(isMediaFile) + if (mediaFiles.length === 0) { + feedback.value = t('app.feedback.noMediaFiles') + return + } + if (mediaFiles.length !== event.payload.paths.length) { + const skipped = event.payload.paths.length - mediaFiles.length + feedback.value = t('app.feedback.someFilesSkipped', { count: skipped }) + } + void submitFiles(mediaFiles) + } + }) + } catch (error) { + console.error('Failed to initialize drag-drop:', error) + } +} + async function handleFiles(event: Event) { const input = event.target as HTMLInputElement const files = Array.from(input.files ?? []) @@ -264,6 +309,18 @@ async function handleTranslateFromEditor() {