import { useEffect } from "react"; import { listen } from "@tauri-apps/api/event"; import { openUrl } from "@tauri-apps/plugin-opener"; import { getCurrentWindow } from "@tauri-apps/api/window"; import { Library } from "./components/Library"; import { EditorView } from "./components/EditorView"; import { BackupSettings } from "./components/BackupSettings"; import { ExportPreview } from "./components/ExportPreview"; import { UpdateDialog } from "./components/UpdateDialog"; import { useBook } from "./store/useBook"; import { useBackup } from "./store/useBackup"; import { useExportPreview } from "./store/useExportPreview"; import { isDesktop } from "./ipc"; import { createAndOpenBook, lastBookId, loadBook, saveBook } from "./library"; import { runExport } from "./export/run"; import { checkForUpdates } from "./updater"; function App() { const book = useBook((s) => s.book); const openBook = useBook((s) => s.openBook); useEffect(() => { if (!isDesktop) return; checkForUpdates(true); const unlisten = listen("menu-action", (event) => { const state = useBook.getState(); if (event.payload === "new-book") createAndOpenBook(state.openBook, state.setNotice); else if (event.payload === "export-pdf") { if (useBook.getState().book) useExportPreview.getState().openPreview(); } else if (event.payload === "export-epub") runExport("epub"); else if (event.payload === "check-updates") checkForUpdates(false); else if (event.payload === "report-issue") openUrl("https://github.com/priyanshujain/margin/issues").catch(() => {}); }); const unlistenWarn = listen("pdf-warnings", (event) => { useBook.getState().setNotice(`PDF exported with warnings:\n${event.payload}`); }); return () => { unlisten.then((stop) => stop()); unlistenWarn.then((stop) => stop()); }; }, []); useEffect(() => { if (!isDesktop) return; const win = getCurrentWindow(); const unlisten = win.onCloseRequested(async (event) => { const { book, dirty } = useBook.getState(); const { connected } = useBackup.getState(); if ((!book || !dirty) && !connected) return; event.preventDefault(); if (book && dirty) await saveBook(book).catch(() => {}); if (connected) useBackup.getState().backup(true); win.destroy(); }); return () => { unlisten.then((stop) => stop()); }; }, []); useEffect(() => { if (!isDesktop) return; const unlisten = listen<{ ok: boolean; error: string | null }>("gdrive-auth", (event) => { useBackup.getState().handleAuthEvent(event.payload.ok, event.payload.error); }); return () => { unlisten.then((stop) => stop()); }; }, []); useEffect(() => { if (!isDesktop) return; let first = true; const tick = async () => { await useBackup.getState().refresh(); const state = useBackup.getState(); if (!state.connected || state.needsReauth) return; if (first) { first = false; state.sync(true); } else if (state.pending) { state.backup(true); } }; tick(); const id = setInterval(tick, 15 * 60 * 1000); return () => clearInterval(id); }, []); useEffect(() => { if (!isDesktop) return; const id = lastBookId(); if (!id || useBook.getState().book) return; loadBook(id) .then((last) => { if (!useBook.getState().book) useBook.getState().openBook(last); }) .catch(() => {}); }, []); return ( <> {book ? : } {isDesktop && } {isDesktop && } {isDesktop && } ); } export default App;