From eef5f762cb74802181c3d21bae01d440f77ae998 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:02:08 +0200 Subject: [PATCH] Fix infinite scroll loading previous chapter unintentionally on reader open This was only was noticeable in case the transition page was disabled. Due to potential layout shifts and scrolling the initial page into view, the infinite chapter logic got triggered and loaded the previous chapter. This is not a 100% guarantee that it won't happen, slow devices might still run into this issue --- CHANGELOG.md | 1 + .../useReaderInfiniteScrollUpdateChapter.ts | 21 +++++++++++++++++-- src/lib/HelperFunctions.ts | 13 ++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 651e6ae5..7654f327 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (**Reader**) Fix jumping back to the first page on window resize - (**Reader**) Fix chapter not getting marked as read in continuous reading mode in case the last page is not big enough to get marked as the current page - (**Reader**) Fix infinite scrolling sometimes not opening previous/next chapter +- (**Reader**) Fix infinite scroll immediately opening previous chapter with disabled transition page when opening reader - (**Reader**) Fix preserving scroll position with RTL reading direction and a language that is read RTL - (**Reader**) Fix missing gap between chapters in continuous vertical and horizontal reading modes with disabled transition page - (**Browse**) Fix showing only nsfw sources in the browse source page when the "show nsfw" setting is disabled diff --git a/src/features/reader/infinite-scroll/useReaderInfiniteScrollUpdateChapter.ts b/src/features/reader/infinite-scroll/useReaderInfiniteScrollUpdateChapter.ts index 6df9beb8..f301fa03 100644 --- a/src/features/reader/infinite-scroll/useReaderInfiniteScrollUpdateChapter.ts +++ b/src/features/reader/infinite-scroll/useReaderInfiniteScrollUpdateChapter.ts @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useRef } from 'react'; import { ReadingDirection, ReadingMode } from '@/features/reader/Reader.types.ts'; import { isContinuousReadingMode, @@ -17,6 +17,9 @@ import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts import { useIntersectionObserver } from '@/base/hooks/useIntersectionObserver.tsx'; import { getReaderScrollbarStore, useReaderSettingsStore } from '@/features/reader/stores/ReaderStore.ts'; import { ReaderControls } from '@/features/reader/services/ReaderControls.ts'; +import { d } from 'koration'; +import { maybeExecuteWithDelay } from '@/lib/HelperFunctions.ts'; +import { usePrevious } from '@mantine/hooks'; interface ElementIntersection { start: boolean; @@ -245,6 +248,10 @@ export const useReaderInfiniteScrollUpdateChapter = ( image: HTMLElement | null, scrollElement: HTMLElement | null, ) => { + const previousChapterId = usePrevious(chapterId); + const initialChapterIdRef = useRef(chapterId); + const eventListenerTimeoutRef = useRef(undefined); + const { readingMode, readingDirection, shouldUseInfiniteScroll, shouldShowTransitionPage } = useReaderSettingsStore( (state) => ({ readingMode: state.readingMode.value, @@ -259,6 +266,7 @@ export const useReaderInfiniteScrollUpdateChapter = ( const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode); if ( + !image || shouldShowTransitionPage || !scrollElement || !isContinuousReadingModeActive || @@ -297,7 +305,15 @@ export const useReaderInfiniteScrollUpdateChapter = ( } }; - scrollElement.addEventListener('scroll', onScroll, { passive: true }); + const isInitialChapterRender = + previousChapterId === undefined || + (initialChapterIdRef.current === chapterId && previousChapterId === chapterId); + clearTimeout(eventListenerTimeoutRef.current); + eventListenerTimeoutRef.current = maybeExecuteWithDelay( + () => scrollElement.addEventListener('scroll', onScroll, { passive: true }), + d(5).seconds.inWholeMilliseconds, + isInitialChapterRender, + ); return () => scrollElement.removeEventListener('scroll', onScroll); }, [ readingMode, @@ -307,6 +323,7 @@ export const useReaderInfiniteScrollUpdateChapter = ( isCurrentChapter, isChapterToOpenVisible, chapterToOpenId, + !!image, ]); useIntersectionObserver( diff --git a/src/lib/HelperFunctions.ts b/src/lib/HelperFunctions.ts index 92a4ec06..83e615d3 100644 --- a/src/lib/HelperFunctions.ts +++ b/src/lib/HelperFunctions.ts @@ -82,3 +82,16 @@ export const getNextRotationValue = ( return values[(indexOfValue + 1) % values.length]; }; + +export const maybeExecuteWithDelay = ( + action: () => void, + delay: number, + condition: boolean, +): NodeJS.Timeout | undefined => { + if (condition) { + return setTimeout(() => action(), delay); + } + + action(); + return undefined; +};