File size: 2,526 Bytes
e327f0d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
 * WindowFileDrop — relays Tauri window-level file-drop events to the page.
 *
 * When the user drags files from the OS file manager onto the window, Tauri
 * emits a `tauri://drag-drop` event with the absolute paths. We re-emit a
 * DOM-level `hasarui:files-dropped` event carrying File objects so individual
 * pages (BatchUploader, InspectPage) can handle it without each subscribing
 * to a Tauri event.
 */
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { getCurrentWindow } from '@tauri-apps/api/window';
import { pathToFile } from '@/lib/commands';
import { MAX_FILE_SIZE_MB } from '@/lib/file-picker';

const IMAGE_EXT = /\.(jpe?g|png|webp)$/i;
const MAX_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
const isTauri = () => typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window;

export function WindowFileDrop() {
  const navigate = useNavigate();

  useEffect(() => {
    if (!isTauri()) return;
    const w = getCurrentWindow();
    let unlisten: (() => void) | null = null;
    (async () => {
      unlisten = await w.onDragDropEvent(async (e) => {
        const payload = e.payload as { type: string; paths?: string[] };
        if (payload.type !== 'drop' || !payload.paths) return;
        const paths = payload.paths.filter((p) => IMAGE_EXT.test(p));
        if (paths.length === 0) return;
        try {
          const all = await Promise.all(paths.map((p) => pathToFile(p)));
          const files = all.filter((f) => f.size <= MAX_BYTES);
          const rejected = all
            .filter((f) => f.size > MAX_BYTES)
            .map((f) => ({ name: f.name, size: f.size }));
          if (rejected.length) {
            window.dispatchEvent(
              new CustomEvent('hasarui:file-size-rejected', {
                detail: { rejected, maxMb: MAX_FILE_SIZE_MB },
              }),
            );
          }
          if (!files.length) return;
          window.dispatchEvent(
            new CustomEvent('hasarui:files-dropped', { detail: { files } }),
          );
          // If we're not on inspect/batch, route to inspect for convenience.
          const loc = window.location.pathname;
          if (!loc.startsWith('/inspect') && !loc.startsWith('/batch')) {
            navigate(files.length > 5 ? '/batch' : '/inspect');
          }
        } catch (err) {
          console.warn('Window drop failed:', err);
        }
      });
    })();
    return () => unlisten?.();
  }, [navigate]);

  return null;
}

export default WindowFileDrop;