Fix progress overridden by newly opened book (#117)

This commit is contained in:
Huang Xin
2025-01-06 19:19:02 +01:00
committed by GitHub
parent cccd4c2b16
commit a59a3b633b
5 changed files with 54 additions and 28 deletions
+1 -1
View File
@@ -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",
+8
View File
@@ -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": [
@@ -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<ReturnType<typeof setTimeout> | 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];
+18 -15
View File
@@ -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<SyncResult>({
books: [],
configs: [],
notes: [],
books: null,
configs: null,
notes: null,
});
const [syncedBooks, setSyncedBooks] = useState<Book[]>([]);
const [syncedConfigs, setSyncedConfigs] = useState<BookConfig[]>([]);
const [syncedNotes, setSyncedNotes] = useState<BookNote[]>([]);
const [syncedBooks, setSyncedBooks] = useState<Book[] | null>(null);
const [syncedConfigs, setSyncedConfigs] = useState<BookConfig[] | null>(null);
const [syncedNotes, setSyncedNotes] = useState<BookNote[] | null>(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]);
+3 -3
View File
@@ -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 {