fix(sync): keep view settings device-local and exclude them from sync (#4672)

This commit is contained in:
Huang Xin
2026-06-20 09:13:03 +08:00
committed by GitHub
parent b9a3ee725f
commit 5f561504e3
2 changed files with 6 additions and 16 deletions
@@ -37,7 +37,6 @@ const h = vi.hoisted(() => {
user: { id: 'u1' },
syncConfigsMock: vi.fn(async () => {}),
syncBooksMock: vi.fn(async () => {}),
setConfigMock: vi.fn(),
cfiCompareMock: vi.fn((_a: string, _b: string) => 0),
view: { renderer: { getContents: () => [], primaryIndex: 0 }, goTo: vi.fn() },
state: {
@@ -67,7 +66,7 @@ vi.mock('@/hooks/useTranslation', () => ({
vi.mock('@/store/bookDataStore', () => ({
useBookDataStore: h.makeStore({
getConfig: () => h.config,
setConfig: h.setConfigMock,
setConfig: vi.fn(),
getBookData: () => ({ book: h.book }),
}),
}));
@@ -142,7 +141,6 @@ beforeEach(() => {
vi.useFakeTimers();
h.syncConfigsMock.mockClear();
h.syncBooksMock.mockClear();
h.setConfigMock.mockClear();
h.view.goTo.mockClear();
h.cfiCompareMock.mockReset();
h.cfiCompareMock.mockReturnValue(0);
@@ -247,11 +245,10 @@ describe('useProgressSync', () => {
renderHook(() => useProgressSync('h1-view1'));
await advance(0);
// Not navigated to, and not persisted into the local config (the local
// 'cfi-loc' is kept instead of the malformed remote value).
// The malformed remote location is discarded so it can't move the reader.
// (Config is no longer merged from sync — only reading progress drives
// navigation — so the local position is left untouched.)
expect(h.view.goTo).not.toHaveBeenCalled();
const persisted = h.setConfigMock.mock.calls.at(-1)?.[1] as { location?: string } | undefined;
expect(persisted?.location).toBe('cfi-loc');
});
test('navigates to a well-formed newer synced location', async () => {
@@ -27,7 +27,6 @@ export const useProgressSync = (bookKey: string) => {
// to the WHOLE bookDataStore — saveConfig writes booksData on every
// throttled save and would otherwise re-render the entire reader subtree.
const getConfig = useBookDataStore((s) => s.getConfig);
const setConfig = useBookDataStore((s) => s.setConfig);
const getBookData = useBookDataStore((s) => s.getBookData);
const getView = useReaderStore((s) => s.getView);
const setHoveredBookKey = useReaderStore((s) => s.setHoveredBookKey);
@@ -238,14 +237,8 @@ export const useProgressSync = (bookKey: string) => {
remoteCFILocation = candidateCFI;
}
}
const filteredSyncedConfig = Object.fromEntries(
Object.entries(syncedConfig).filter(([_, value]) => value !== null && value !== undefined),
);
if (syncedConfig.updatedAt >= config.updatedAt) {
setConfig(bookKey, { ...config, ...filteredSyncedConfig });
} else {
setConfig(bookKey, { ...filteredSyncedConfig, ...config });
}
// Currently, only reading progress is synced.
// TODO: Configuration sync will be handled through a more robust profile-based solution in the future.
if (remoteCFILocation && configCFI) {
if (CFI.compare(configCFI, remoteCFILocation) < 0) {
// While previewing a deep-link target, do NOT yank the view to the