From a59a3b633b9369d53682f13b0a884b1b2e89bc41 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Mon, 6 Jan 2025 19:19:02 +0100 Subject: [PATCH] Fix progress overridden by newly opened book (#117) --- apps/readest-app/package.json | 2 +- apps/readest-app/release-notes.json | 8 +++++ .../src/app/reader/hooks/useProgressSync.ts | 33 ++++++++++++++----- apps/readest-app/src/hooks/useSync.ts | 33 ++++++++++--------- apps/readest-app/src/libs/sync.ts | 6 ++-- 5 files changed, 54 insertions(+), 28 deletions(-) diff --git a/apps/readest-app/package.json b/apps/readest-app/package.json index a6819871..0808ee61 100644 --- a/apps/readest-app/package.json +++ b/apps/readest-app/package.json @@ -1,6 +1,6 @@ { "name": "@readest/readest-app", - "version": "0.9.0", + "version": "0.9.1", "private": true, "scripts": { "dev": "dotenv -e .env.tauri -- next dev", diff --git a/apps/readest-app/release-notes.json b/apps/readest-app/release-notes.json index 6f9f01c8..5b95e3e8 100644 --- a/apps/readest-app/release-notes.json +++ b/apps/readest-app/release-notes.json @@ -1,5 +1,13 @@ { "releases": { + "0.9.1": { + "date": "2025-01-06", + "notes": [ + "Restore window position and size when reopening app.", + "Swap font when downloading online fonts.", + "Fix layout issues on Windows and Linux." + ] + }, "0.9.0": { "date": "2025-01-04", "notes": [ diff --git a/apps/readest-app/src/app/reader/hooks/useProgressSync.ts b/apps/readest-app/src/app/reader/hooks/useProgressSync.ts index 7e20122c..36f4c011 100644 --- a/apps/readest-app/src/app/reader/hooks/useProgressSync.ts +++ b/apps/readest-app/src/app/reader/hooks/useProgressSync.ts @@ -21,6 +21,8 @@ export const useProgressSync = ( const { user } = useAuth(); const view = getView(bookKey); const config = getConfig(bookKey); + // flag to prevent accidental sync without first pulling the config + const configSynced = useRef(false); const pushConfig = (bookKey: string, config: BookConfig | null) => { if (!config || !user) return; @@ -31,13 +33,26 @@ export const useProgressSync = ( ); syncConfigs([compressedConfig], bookHash, 'push'); }; - - useEffect(() => { + const pullConfig = (bookKey: string) => { if (!user) return; const bookHash = bookKey.split('-')[0]!; syncConfigs([], bookHash, 'pull'); - return () => { + }; + const syncConfig = () => { + if (!configSynced.current) { + pullConfig(bookKey); + } else { pushConfig(bookKey, config); + } + }; + + useEffect(() => { + if (!user) return; + pullConfig(bookKey); + return () => { + if (configSynced.current) { + pushConfig(bookKey, config); + } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -46,18 +61,19 @@ export const useProgressSync = ( const syncTimeoutRef = useRef | null>(null); useEffect(() => { if (!config?.location || !user) return; + const now = Date.now(); const timeSinceLastSync = now - lastProgressSyncTime.current; - if (configSynced.current && timeSinceLastSync > SYNC_PROGRESS_INTERVAL_SEC * 1000) { + if (timeSinceLastSync > SYNC_PROGRESS_INTERVAL_SEC * 1000) { lastProgressSyncTime.current = now; - pushConfig(bookKey, config); + syncConfig(); } else { if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current); syncTimeoutRef.current = setTimeout( () => { lastProgressSyncTime.current = Date.now(); - pushConfig(bookKey, config); syncTimeoutRef.current = null; + syncConfig(); }, SYNC_PROGRESS_INTERVAL_SEC * 1000 - timeSinceLastSync, ); @@ -66,9 +82,9 @@ export const useProgressSync = ( }, [config]); // sync progress once when the book is opened - const configSynced = useRef(false); useEffect(() => { - if (!configSynced.current && syncedConfigs?.length > 0) { + if (!configSynced.current && syncedConfigs) { + configSynced.current = true; const syncedConfig = syncedConfigs.filter((c) => c.bookHash === bookKey.split('-')[0])[0]; if (syncedConfig) { const newConfig = deserializeConfig( @@ -77,7 +93,6 @@ export const useProgressSync = ( DEFAULT_BOOK_SEARCH_CONFIG, ); setConfig(bookKey, { ...config, ...newConfig }); - configSynced.current = true; if ((syncedConfig.progress?.[1] ?? 0) > 0 && (config?.progress?.[1] ?? 0) > 0) { const syncedFraction = syncedConfig.progress![0] / syncedConfig.progress![1]; const configFraction = config!.progress![0] / config!.progress![1]; diff --git a/apps/readest-app/src/hooks/useSync.ts b/apps/readest-app/src/hooks/useSync.ts index 9cee254d..4591148a 100644 --- a/apps/readest-app/src/hooks/useSync.ts +++ b/apps/readest-app/src/hooks/useSync.ts @@ -51,14 +51,15 @@ export function useSync(bookKey?: string) { ); const [syncing, setSyncing] = useState(false); + // null means unsynced, empty array means synced no changes const [syncResult, setSyncResult] = useState({ - books: [], - configs: [], - notes: [], + books: null, + configs: null, + notes: null, }); - const [syncedBooks, setSyncedBooks] = useState([]); - const [syncedConfigs, setSyncedConfigs] = useState([]); - const [syncedNotes, setSyncedNotes] = useState([]); + const [syncedBooks, setSyncedBooks] = useState(null); + const [syncedConfigs, setSyncedConfigs] = useState(null); + const [syncedNotes, setSyncedNotes] = useState(null); const { syncClient } = useSyncContext(); @@ -76,11 +77,11 @@ export function useSync(bookKey?: string) { try { const result = await syncClient.pullChanges(since, type, bookId); + setSyncResult({ ...syncResult, [type]: result[type] }); const records = result[type]; - if (!records.length) return; - const maxTime = computeMaxTimestamp(result[type]); + if (!records?.length) return; + const maxTime = computeMaxTimestamp(records); setLastSyncedAt(maxTime); - setSyncResult(result); switch (type) { case 'books': settings.lastSyncedAtBooks = maxTime; @@ -169,16 +170,18 @@ export function useSync(bookKey?: string) { useEffect(() => { if (!syncing && syncResult) { const { books: dbBooks, configs: dbBookConfigs, notes: dbBookNotes } = syncResult; - const books = dbBooks.map((dbBook) => transformsFromDB['books'](dbBook as unknown as DBBook)); - const configs = dbBookConfigs.map((dbBookConfig) => + const books = dbBooks?.map((dbBook) => + transformsFromDB['books'](dbBook as unknown as DBBook), + ); + const configs = dbBookConfigs?.map((dbBookConfig) => transformsFromDB['configs'](dbBookConfig as unknown as DBBookConfig), ); - const notes = dbBookNotes.map((dbBookNote) => + const notes = dbBookNotes?.map((dbBookNote) => transformsFromDB['notes'](dbBookNote as unknown as DBBookNote), ); - if (books.length) setSyncedBooks(books); - if (configs.length) setSyncedConfigs(configs); - if (notes.length) setSyncedNotes(notes); + if (books) setSyncedBooks(books); + if (configs) setSyncedConfigs(configs); + if (notes) setSyncedNotes(notes); } }, [syncResult, syncing]); diff --git a/apps/readest-app/src/libs/sync.ts b/apps/readest-app/src/libs/sync.ts index 7ca2edd9..b539d70a 100644 --- a/apps/readest-app/src/libs/sync.ts +++ b/apps/readest-app/src/libs/sync.ts @@ -18,9 +18,9 @@ interface BookConfigRecord extends BookDataRecord, BookConfig {} interface BookNoteRecord extends BookDataRecord, BookNote {} export interface SyncResult { - books: BookRecord[]; - notes: BookNoteRecord[]; - configs: BookConfigRecord[]; + books: BookRecord[] | null; + notes: BookNoteRecord[] | null; + configs: BookConfigRecord[] | null; } export interface SyncData {