From 4da2f67b75bf4062c4c2eddd602d9653e928c023 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 21 Feb 2026 14:57:00 +0100 Subject: [PATCH] Fix page shift when toggling "offset double spreads" setting The pages should get shifted to - the left when enabling - the right when disabling the setting. Currently, the "page push" is inverted. This can cause the page that is most likely being read to get pushed out of the screen. Which then requires the user to change the page. Example: Active page: 1+2 Enable setting: -> 2 (currently) instead of -> 1 --- CHANGELOG.md | 1 + src/features/reader/Reader.types.ts | 6 ++- src/features/reader/hotkeys/ReaderHotkeys.tsx | 5 +-- .../ReaderNavBarDesktopQuickSettings.tsx | 4 +- src/features/reader/services/ReaderService.ts | 37 +++++++++++++++++++ .../reader/stores/ReaderPagesStore.ts | 15 ++++++++ .../reader/viewer/ReaderChapterViewer.tsx | 14 +++++-- src/features/reader/viewer/ReaderViewer.tsx | 3 ++ 8 files changed, 74 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae61822a..da9058f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (**Library**) Fix total library size chip color in light mode - (**Browse**) Fix missing pinned sources in the source language filter - (**Browse**) Fix incorrectly showing "local source" source in the source language filter (the local source can't be disabled) +- (**Reader**) Fix page shift when toggling the "offset double spreads" setting (currently: enable: shift to the right; disable: shift to the left – now: inverted) ## [20251230.01] (r2937) - 2025-12-30 diff --git a/src/features/reader/Reader.types.ts b/src/features/reader/Reader.types.ts index 8e579f05..648ce079 100644 --- a/src/features/reader/Reader.types.ts +++ b/src/features/reader/Reader.types.ts @@ -306,7 +306,11 @@ export interface ReaderStatePages { setPageToScrollToIndex: (total: number | null) => void; pageUrls: string[]; setPageUrls: (urls: string[]) => void; - pageLoadStates: { url: string; loaded: boolean; error?: boolean }[]; + pageSpreadStates: ReaderPageSpreadState[]; + setPageSpreadStates: ( + set: ((prevStates: ReaderPageSpreadState[]) => ReaderPageSpreadState[]) | ReaderPageSpreadState[], + ) => void; + pageLoadStates: ReaderPageLoadState[]; setPageLoadStates: ( set: ((prevStates: ReaderPageLoadState[]) => ReaderPageLoadState[]) | ReaderPageLoadState[], ) => void; diff --git a/src/features/reader/hotkeys/ReaderHotkeys.tsx b/src/features/reader/hotkeys/ReaderHotkeys.tsx index c1d96b9b..98027365 100644 --- a/src/features/reader/hotkeys/ReaderHotkeys.tsx +++ b/src/features/reader/hotkeys/ReaderHotkeys.tsx @@ -149,10 +149,7 @@ export const ReaderHotkeys = ({ ReaderService.updateSetting('shouldStretchPage', !getReaderSettingsStore().shouldStretchPage.value), ); useHotkeys(hotkeys[ReaderHotkey.OFFSET_SPREAD_PAGES], () => - ReaderService.updateSetting( - 'shouldOffsetDoubleSpreads', - !getReaderSettingsStore().shouldOffsetDoubleSpreads.value, - ), + ReaderService.setOffsetDoubleSpreads(!getReaderSettingsStore().shouldOffsetDoubleSpreads.value), ); useHotkeys(hotkeys[ReaderHotkey.CYCLE_READING_MODE], () => { updateSettingCycleThrough( diff --git a/src/features/reader/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopQuickSettings.tsx b/src/features/reader/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopQuickSettings.tsx index 32786e7e..65b24551 100644 --- a/src/features/reader/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopQuickSettings.tsx +++ b/src/features/reader/overlay/navigation/desktop/quick-settings/ReaderNavBarDesktopQuickSettings.tsx @@ -43,9 +43,7 @@ const BaseReaderNavBarDesktopQuickSettings = ({ openSettings }: Pick - ReaderService.updateSetting('shouldOffsetDoubleSpreads', value) - } + setShouldOffsetDoubleSpreads={(value) => ReaderService.setOffsetDoubleSpreads(value)} /> = { ltr: 'rtl', @@ -237,6 +239,41 @@ export class ReaderService { : DIRECTION_TO_INVERTED[direction]; } + /** + * Updates the setting and updated the current page index accordingly. + * + * In case the current page is a spread page, the page index won't get changed. + * + * Enable: + * Push pages to the left + * + * Page 3+2 -> Page 2+1 - the third page gets pushed to the left, out of the screen + * + * Disable: + * Push pages to the right + * + * Page 3+2 -> Page 4+3 - the second page gets pushed to the right, out of the screen + */ + static setOffsetDoubleSpreads(shouldOffset: boolean): void { + const { pages, currentPageIndex, pageSpreadStates } = getReaderPagesStore(); + const { readingMode } = getReaderSettingsStore(); + + const isDoublePageMode = readingMode.value === ReadingMode.DOUBLE_PAGE; + const isSpreadPage = !!pageSpreadStates[currentPageIndex]?.isSpread; + + const updatePageIndex = isDoublePageMode && !isSpreadPage; + if (!updatePageIndex) { + ReaderService.updateSetting('shouldOffsetDoubleSpreads', shouldOffset); + return; + } + + const page = getPage(currentPageIndex, pages); + const updatedPageIndex = shouldOffset ? page.primary.index : currentPageIndex; + + getReaderPagesStore().setCurrentPageIndex(updatedPageIndex); + ReaderService.updateSetting('shouldOffsetDoubleSpreads', shouldOffset); + } + /** * Writes the change immediately to the cache and sends a mutation in case "commit" is true. */ diff --git a/src/features/reader/stores/ReaderPagesStore.ts b/src/features/reader/stores/ReaderPagesStore.ts index 6acc4290..a8ab0269 100644 --- a/src/features/reader/stores/ReaderPagesStore.ts +++ b/src/features/reader/stores/ReaderPagesStore.ts @@ -22,6 +22,7 @@ export const READER_DEFAULT_PAGES_STATE: Omit< | 'setPageToScrollToIndex' | 'setTotalPages' | 'setPageUrls' + | 'setPageSpreadStates' | 'setPageLoadStates' | 'setPages' | 'setTransitionPageMode' @@ -32,6 +33,7 @@ export const READER_DEFAULT_PAGES_STATE: Omit< currentPageIndex: 0, pageToScrollToIndex: null, pageUrls: [], + pageSpreadStates: [{ url: '', isSpread: false }], pageLoadStates: [{ url: '', loaded: false }], pages: [ { @@ -85,6 +87,19 @@ export const createReaderPagesStoreSlice = ( undefined, createActionName('setPageUrls'), ), + setPageSpreadStates: (spreadStates) => + set( + (draft) => { + if (typeof spreadStates === 'function') { + draft.pages.pageSpreadStates = spreadStates(get().pages.pageSpreadStates); + return; + } + + draft.pages.pageSpreadStates = spreadStates; + }, + undefined, + createActionName('setPageSpreadStates'), + ), setPageLoadStates: (loadStates) => set( (draft) => { diff --git a/src/features/reader/viewer/ReaderChapterViewer.tsx b/src/features/reader/viewer/ReaderChapterViewer.tsx index a4bd3c74..b23e4ba3 100644 --- a/src/features/reader/viewer/ReaderChapterViewer.tsx +++ b/src/features/reader/viewer/ReaderChapterViewer.tsx @@ -50,6 +50,7 @@ const BaseReaderChapterViewer = ({ currentPageIndex, setPages: setContextPages, setPageUrls: setContextPageUrls, + setPageSpreadStates: setContextPageSpreadStates, setPageLoadStates: setContextPageLoadStates, setTotalPages: setContextTotalPages, setCurrentPageIndex: setContextCurrentPageIndex, @@ -93,6 +94,7 @@ const BaseReaderChapterViewer = ({ | 'currentPageIndex' | 'setPages' | 'setPageUrls' + | 'setPageSpreadStates' | 'setPageLoadStates' | 'setTotalPages' | 'setCurrentPageIndex' @@ -140,7 +142,7 @@ const BaseReaderChapterViewer = ({ READER_DEFAULT_PAGES_STATE.pageLoadStates, ); const [pagesToSpreadState, setPagesToSpreadState] = useState( - pageLoadStates.map(({ url }) => ({ url, isSpread: false })), + READER_DEFAULT_PAGES_STATE.pageSpreadStates, ); const ref = useRef(null); @@ -201,7 +203,13 @@ const BaseReaderChapterViewer = ({ () => createUpdateReaderPageLoadState( actualPages, - setPagesToSpreadState, + (value) => { + if (isCurrentChapterRef.current) { + setContextPageSpreadStates(value); + } + + setPagesToSpreadState(value); + }, (value) => { if (isCurrentChapterRef.current) { setContextPageLoadStates(value); @@ -270,7 +278,7 @@ const BaseReaderChapterViewer = ({ (value) => updateState(value, setPages, setContextPages), (value) => updateState(value, setPageUrls, setContextPageUrls), (value) => updateState(value, setPageLoadStates, setContextPageLoadStates), - (value) => updateState(value, setPagesToSpreadState, noOp), + (value) => updateState(value, setPagesToSpreadState, setContextPageSpreadStates), (value) => updateState(value, noOp, setContextCurrentPageIndex), (value) => { if ((isInitialChapter && !arePagesFetched) || scrollIntoView) { diff --git a/src/features/reader/viewer/ReaderViewer.tsx b/src/features/reader/viewer/ReaderViewer.tsx index b6524b3b..d43a87ca 100644 --- a/src/features/reader/viewer/ReaderViewer.tsx +++ b/src/features/reader/viewer/ReaderViewer.tsx @@ -82,6 +82,7 @@ const BaseReaderViewer = ({ totalPages, setPages, setPageUrls, + setPageSpreadStates, setPageLoadStates, setTotalPages, setCurrentPageIndex, @@ -96,6 +97,7 @@ const BaseReaderViewer = ({ totalPages: state.pages.totalPages, setPages: state.pages.setPages, setPageUrls: state.pages.setPageUrls, + setPageSpreadStates: state.pages.setPageSpreadStates, setPageLoadStates: state.pages.setPageLoadStates, setTotalPages: state.pages.setTotalPages, setCurrentPageIndex: state.pages.setCurrentPageIndex, @@ -381,6 +383,7 @@ const BaseReaderViewer = ({ imageRefs={imageRefs} setPages={setPages} setPageUrls={setPageUrls} + setPageSpreadStates={setPageSpreadStates} setPageLoadStates={setPageLoadStates} setTotalPages={setTotalPages} setCurrentPageIndex={setCurrentPageIndex}