From 0649a1c89e40edab3b91ab3dcbd68226679de74a Mon Sep 17 00:00:00 2001 From: James Brunton Date: Thu, 13 Nov 2025 15:07:34 +0000 Subject: [PATCH] Redesign file opening to be simpler --- frontend/src-tauri/src/lib.rs | 14 +-- .../src/desktop/hooks/useAppInitialization.ts | 87 ++++++------------- frontend/src/desktop/hooks/useOpenedFile.ts | 31 +++---- 3 files changed, 52 insertions(+), 80 deletions(-) diff --git a/frontend/src-tauri/src/lib.rs b/frontend/src-tauri/src/lib.rs index c6b264e56..02343b290 100644 --- a/frontend/src-tauri/src/lib.rs +++ b/frontend/src-tauri/src/lib.rs @@ -32,9 +32,6 @@ pub fn run() { // Store file for later retrieval (in case frontend isn't ready yet) add_opened_file(arg.clone()); - // Also emit event for immediate handling if frontend is ready - let _ = app.emit("file-opened", arg.clone()); - // Bring the existing window to front if let Some(window) = app.get_webview_window("main") { let _ = window.set_focus(); @@ -42,6 +39,9 @@ pub fn run() { } } } + + // Emit a generic notification that files were added (frontend will re-read storage) + let _ = app.emit("files-changed", ()); })) .setup(|_app| { add_log("🚀 Tauri app setup started".to_string()); @@ -75,6 +75,7 @@ pub fn run() { #[cfg(target_os = "macos")] RunEvent::Opened { urls } => { add_log(format!("📂 Tauri file opened event: {:?}", urls)); + let mut added_files = false; for url in urls { let url_str = url.as_str(); if url_str.starts_with("file://") { @@ -82,11 +83,14 @@ pub fn run() { if file_path.ends_with(".pdf") { add_log(format!("📂 Processing opened PDF: {}", file_path)); add_opened_file(file_path.to_string()); - // Use unified event name for consistency across platforms - let _ = app_handle.emit("file-opened", file_path.to_string()); + added_files = true; } } } + // Emit a generic notification that files were added (frontend will re-read storage) + if added_files { + let _ = app_handle.emit("files-changed", ()); + } } _ => { // Only log unhandled events in debug mode to reduce noise diff --git a/frontend/src/desktop/hooks/useAppInitialization.ts b/frontend/src/desktop/hooks/useAppInitialization.ts index a34547bcd..f237102bc 100644 --- a/frontend/src/desktop/hooks/useAppInitialization.ts +++ b/frontend/src/desktop/hooks/useAppInitialization.ts @@ -20,75 +20,42 @@ export function useAppInitialization(): void { // Handle files opened with app (Tauri mode) const { openedFilePaths, loading: openedFileLoading } = useOpenedFile(); - // Track if we've already loaded the initial files to prevent duplicate loads - const initialFilesLoadedRef = useRef(false); - // Load opened files and add directly to FileContext useEffect(() => { - if (openedFilePaths.length > 0 && !openedFileLoading && !initialFilesLoadedRef.current) { - initialFilesLoadedRef.current = true; - - const loadOpenedFiles = async () => { - try { - const filesArray: File[] = []; - - // Load all files in parallel - await Promise.all( - openedFilePaths.map(async (filePath) => { - try { - const fileData = await fileOpenService.readFileAsArrayBuffer(filePath); - if (fileData) { - const file = new File([fileData.arrayBuffer], fileData.fileName, { - type: 'application/pdf' - }); - filesArray.push(file); - console.log('[Desktop] Loaded file:', fileData.fileName); - } - } catch (error) { - console.error('[Desktop] Failed to load file:', filePath, error); - } - }) - ); - - if (filesArray.length > 0) { - // Add all files to FileContext at once - await addFiles(filesArray); - console.log(`[Desktop] ${filesArray.length} opened file(s) added to FileContext`); - } - } catch (error) { - console.error('[Desktop] Failed to load opened files:', error); - } - }; - - loadOpenedFiles(); + if (openedFilePaths.length === 0 || openedFileLoading) { + return; } - }, [openedFilePaths, openedFileLoading, addFiles]); - // Listen for runtime file-opened events (from second instances on Windows/Linux) - useEffect(() => { - const handleRuntimeFileOpen = async (filePath: string) => { + const loadOpenedFiles = async () => { try { - console.log('[Desktop] Runtime file-opened event received:', filePath); - const fileData = await fileOpenService.readFileAsArrayBuffer(filePath); - if (fileData) { - // Create a File object from the ArrayBuffer - const file = new File([fileData.arrayBuffer], fileData.fileName, { - type: 'application/pdf' - }); + const filesArray: File[] = []; - // Add directly to FileContext - await addFiles([file]); - console.log('[Desktop] Runtime opened file added to FileContext:', fileData.fileName); + await Promise.all( + openedFilePaths.map(async (filePath) => { + try { + const fileData = await fileOpenService.readFileAsArrayBuffer(filePath); + if (fileData) { + const file = new File([fileData.arrayBuffer], fileData.fileName, { + type: 'application/pdf' + }); + filesArray.push(file); + console.log('[Desktop] Loaded file:', fileData.fileName); + } + } catch (error) { + console.error('[Desktop] Failed to load file:', filePath, error); + } + }) + ); + + if (filesArray.length > 0) { + await addFiles(filesArray); + console.log(`[Desktop] ${filesArray.length} opened file(s) added to FileContext`); } } catch (error) { - console.error('[Desktop] Failed to load runtime opened file:', error); + console.error('[Desktop] Failed to load opened files:', error); } }; - // Set up event listener and get cleanup function - const unlisten = fileOpenService.onFileOpened(handleRuntimeFileOpen); - - // Clean up listener on unmount - return unlisten; - }, [addFiles]); + loadOpenedFiles(); + }, [openedFilePaths, openedFileLoading, addFiles]); } diff --git a/frontend/src/desktop/hooks/useOpenedFile.ts b/frontend/src/desktop/hooks/useOpenedFile.ts index 48565010f..6347ef736 100644 --- a/frontend/src/desktop/hooks/useOpenedFile.ts +++ b/frontend/src/desktop/hooks/useOpenedFile.ts @@ -1,45 +1,46 @@ import { useState, useEffect } from 'react'; import { fileOpenService } from '@app/services/fileOpenService'; +import { listen } from '@tauri-apps/api/event'; export function useOpenedFile() { const [openedFilePaths, setOpenedFilePaths] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { - const checkForOpenedFile = async () => { - console.log('🔍 Checking for opened file(s)...'); + // Function to read and process files from storage + const readFilesFromStorage = async () => { + console.log('🔍 Reading files from storage...'); try { const filePaths = await fileOpenService.getOpenedFiles(); console.log('🔍 fileOpenService.getOpenedFiles() returned:', filePaths); if (filePaths.length > 0) { - console.log(`✅ App opened with ${filePaths.length} file(s):`, filePaths); + console.log(`✅ Found ${filePaths.length} file(s) in storage:`, filePaths); setOpenedFilePaths(filePaths); - - // Clear the files from service state after consuming them await fileOpenService.clearOpenedFiles(); - } else { - console.log('â„šī¸ No files were opened with the app'); } - } catch (error) { - console.error('❌ Failed to check for opened files:', error); + console.error('❌ Failed to read files from storage:', error); } finally { setLoading(false); } }; - checkForOpenedFile(); + // Read files on mount + readFilesFromStorage(); - // Listen for runtime file open events (abstracted through service) - const unlistenRuntimeEvents = fileOpenService.onFileOpened((filePath: string) => { - console.log('📂 Runtime file open event:', filePath); - setOpenedFilePaths(prev => [...prev, filePath]); + // Listen for files-changed events (when new files are added to storage) + let unlisten: (() => void) | undefined; + listen('files-changed', async () => { + console.log('📂 files-changed event received, re-reading storage...'); + await readFilesFromStorage(); + }).then(unlistenFn => { + unlisten = unlistenFn; }); // Cleanup function return () => { - unlistenRuntimeEvents(); + if (unlisten) unlisten(); }; }, []);