From 7145c33fbb5159d0b1e700baa6a69720e9024360 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:08:58 +0100 Subject: [PATCH] Preserve current page on reader width change only when necessary The pages only change in size with specific "page scale modes". Thus, if these modes are not active, the scroll position will not be lost. There are different cases were even with these modes active, the scroll position won't get lost (e.g. "fit width" while no page is larger than the available width), but handling these would be too cumbersome. Ideally the relative scroll position would be preserved, however, from testing a little that seems to not work too well --- .../reader/components/viewer/ReaderViewer.tsx | 1 + .../hooks/useReaderPreserveScrollPosition.ts | 41 ++++++++++++++----- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/modules/reader/components/viewer/ReaderViewer.tsx b/src/modules/reader/components/viewer/ReaderViewer.tsx index 9dae69a0..ed4b73be 100644 --- a/src/modules/reader/components/viewer/ReaderViewer.tsx +++ b/src/modules/reader/components/viewer/ReaderViewer.tsx @@ -292,6 +292,7 @@ const BaseReaderViewer = forwardRef( readingDirection, readerNavBarWidth, setPageToScrollToIndex, + pageScaleMode, ); useLayoutEffect(() => { diff --git a/src/modules/reader/hooks/useReaderPreserveScrollPosition.ts b/src/modules/reader/hooks/useReaderPreserveScrollPosition.ts index 471a0ca1..d466fb85 100644 --- a/src/modules/reader/hooks/useReaderPreserveScrollPosition.ts +++ b/src/modules/reader/hooks/useReaderPreserveScrollPosition.ts @@ -8,12 +8,18 @@ import { RefObject, useCallback, useEffect, useLayoutEffect, useRef } from 'react'; import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts'; -import { ReaderStateChapters, ReadingDirection, ReadingMode } from '@/modules/reader/types/Reader.types.ts'; +import { + ReaderPageScaleMode, + ReaderStateChapters, + ReadingDirection, + ReadingMode, +} from '@/modules/reader/types/Reader.types.ts'; import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts'; import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx'; import { getPreviousNextChapterVisibility } from '@/modules/reader/utils/Reader.utils.ts'; import { TChapterReader } from '@/modules/chapter/Chapter.types.ts'; import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types'; +import { isReaderWidthEditable } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; export const useReaderPreserveScrollPosition = ( scrollElementRef: RefObject, @@ -27,6 +33,7 @@ export const useReaderPreserveScrollPosition = ( readingDirection: ReadingDirection, readerNavBarWidth: number, setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'], + pageScaleMode: ReaderPageScaleMode, ) => { const scrollPosition = useRef({ left: 0, top: 0, scrollWidth: 0, scrollHeight: 0 }); const readerNavBarWidthRef = useRef(readerNavBarWidth); @@ -51,6 +58,7 @@ export const useReaderPreserveScrollPosition = ( return () => element.removeEventListener('scroll', onScroll); }, []); + // on rendering previous chapter (infinite scroll in continuous reading modes) useLayoutEffect(() => { const scrollElement = scrollElementRef.current; const { left, top, scrollWidth, scrollHeight } = scrollPosition.current; @@ -98,22 +106,35 @@ export const useReaderPreserveScrollPosition = ( scrollElement.scrollTo(newLeft, newTop); }, [currentChapterId]); - const onSizeReset = useCallback(() => { - if (!isContinuousReadingModeActive) return; + const onAvailableReaderWidthChange = useCallback(() => { + if (!isContinuousReadingModeActive) { + return; + } + + if (!isReaderWidthEditable(pageScaleMode)) { + return; + } + setPageToScrollToIndex(pageIndex); - }, [isContinuousReadingModeActive, pageIndex]); + }, [isContinuousReadingModeActive, pageIndex, pageScaleMode]); + // on window resize useEffect(() => { - window.addEventListener('resize', onSizeReset); - return () => window.removeEventListener('resize', onSizeReset); - }, [onSizeReset]); + window.addEventListener('resize', onAvailableReaderWidthChange); + return () => window.removeEventListener('resize', onAvailableReaderWidthChange); + }, [onAvailableReaderWidthChange]); + // on reader nav bar static setting change useEffect(() => { - if (readerNavBarWidthRef.current === readerNavBarWidth) return; - onSizeReset(); + if (readerNavBarWidthRef.current === readerNavBarWidth) { + return; + } + readerNavBarWidthRef.current = readerNavBarWidth; - }, [onSizeReset, readerNavBarWidth]); + onAvailableReaderWidthChange(); + }, [onAvailableReaderWidthChange, readerNavBarWidth]); + // on reading mode change useLayoutEffect(() => { setPageToScrollToIndex(pageIndex); }, [readingMode]);