forked from akai/readest
Fix progress overridden by newly opened book (#117)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user