diff --git a/apps/web/src/app-effects.tsx b/apps/web/src/app-effects.tsx index 82a02d548..87f5f2ac8 100644 --- a/apps/web/src/app-effects.tsx +++ b/apps/web/src/app-effects.tsx @@ -22,6 +22,7 @@ import { useStore } from "./stores/app-store"; import { useStore as useUserStore } from "./stores/user-store"; import { useEditorStore } from "./stores/editor-store"; import { useStore as useAnnouncementStore } from "./stores/announcement-store"; +import { useStore as useSettingStore } from "./stores/setting-store"; import { resetNotices, scheduleBackups, @@ -44,6 +45,7 @@ import { desktop } from "./common/desktop-bridge"; import { BuyDialog } from "./dialogs/buy-dialog"; import { FeatureDialog } from "./dialogs/feature-dialog"; import { AnnouncementDialog } from "./dialogs/announcement-dialog"; +import { logger } from "./utils/logger"; type AppEffectsProps = { setShow: (show: boolean) => void; @@ -95,6 +97,9 @@ export default function AppEffects({ setShow }: AppEffectsProps) { await FeatureDialog.show({ featureName: "highlights" }); await scheduleBackups(); await scheduleFullBackups(); + if (useSettingStore.getState().isFullOfflineMode) + // NOTE: we deliberately don't await here because we don't want to pause execution. + db.attachments.cacheAttachments().catch(logger.error); })(); return () => { diff --git a/apps/web/src/interfaces/fs.ts b/apps/web/src/interfaces/fs.ts index 7b0eb8443..c750b35d3 100644 --- a/apps/web/src/interfaces/fs.ts +++ b/apps/web/src/interfaces/fs.ts @@ -564,6 +564,12 @@ async function exists(filename: string | FileHandle) { ); } +async function bulkExists(filenames: string[]) { + return Array.from( + new Set(filenames).difference(new Set(await streamablefs.list())).values() + ); +} + type FileMetadata = { key: SerializedKey; iv: string; @@ -666,7 +672,8 @@ export const FileStorage: IFileStorage = { exists, clearFileStorage, hashBase64, - getUploadedFileSize + getUploadedFileSize, + bulkExists }; function isSuccessStatusCode(statusCode: number) { diff --git a/apps/web/src/stores/app-store.ts b/apps/web/src/stores/app-store.ts index 529cc8a79..582a665c9 100644 --- a/apps/web/src/stores/app-store.ts +++ b/apps/web/src/stores/app-store.ts @@ -284,6 +284,7 @@ class AppStore extends BaseStore { this.updateSyncStatus("syncing"); try { + options.offlineMode = settingStore.get().isFullOfflineMode; const result = await db.sync(options); if (!result) return this.updateSyncStatus("failed"); diff --git a/apps/web/src/stores/setting-store.ts b/apps/web/src/stores/setting-store.ts index 8af1ac842..046d22c3a 100644 --- a/apps/web/src/stores/setting-store.ts +++ b/apps/web/src/stores/setting-store.ts @@ -40,7 +40,7 @@ class SettingStore extends BaseStore { doubleSpacedParagraphs = Config.get("doubleSpacedLines", true); markdownShortcuts = Config.get("markdownShortcuts", true); notificationsSettings = Config.get("notifications", { reminder: true }); - isFullOfflineMode = false; + isFullOfflineMode = Config.get("fullOfflineMode", false); zoomFactor = 1.0; privacyMode = false; @@ -73,8 +73,7 @@ class SettingStore extends BaseStore { customDns: await desktop?.integration.customDns.query(), zoomFactor: await desktop?.integration.zoomFactor.query(), autoUpdates: await desktop?.updater.autoUpdates.query(), - proxyRules: await desktop?.integration.proxyRules.query(), - isFullOfflineMode: await db.kv().read("fullOfflineMode") + proxyRules: await desktop?.integration.proxyRules.query() }); }; @@ -213,7 +212,7 @@ class SettingStore extends BaseStore { toggleFullOfflineMode = async () => { const isFullOfflineMode = this.get().isFullOfflineMode; this.set({ isFullOfflineMode: !isFullOfflineMode }); - await db.kv().write("fullOfflineMode", !isFullOfflineMode); + Config.set("fullOfflineMode", !isFullOfflineMode); }; }