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
This commit is contained in:
schroda
2026-06-16 18:02:08 +02:00
parent 5cdc161d46
commit eef5f762cb
3 changed files with 33 additions and 2 deletions

View File

@@ -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 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 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 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 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 - (**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 - (**Browse**) Fix showing only nsfw sources in the browse source page when the "show nsfw" setting is disabled

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * 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 { ReadingDirection, ReadingMode } from '@/features/reader/Reader.types.ts';
import { import {
isContinuousReadingMode, isContinuousReadingMode,
@@ -17,6 +17,9 @@ import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts
import { useIntersectionObserver } from '@/base/hooks/useIntersectionObserver.tsx'; import { useIntersectionObserver } from '@/base/hooks/useIntersectionObserver.tsx';
import { getReaderScrollbarStore, useReaderSettingsStore } from '@/features/reader/stores/ReaderStore.ts'; import { getReaderScrollbarStore, useReaderSettingsStore } from '@/features/reader/stores/ReaderStore.ts';
import { ReaderControls } from '@/features/reader/services/ReaderControls.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 { interface ElementIntersection {
start: boolean; start: boolean;
@@ -245,6 +248,10 @@ export const useReaderInfiniteScrollUpdateChapter = (
image: HTMLElement | null, image: HTMLElement | null,
scrollElement: HTMLElement | null, scrollElement: HTMLElement | null,
) => { ) => {
const previousChapterId = usePrevious(chapterId);
const initialChapterIdRef = useRef(chapterId);
const eventListenerTimeoutRef = useRef<NodeJS.Timeout>(undefined);
const { readingMode, readingDirection, shouldUseInfiniteScroll, shouldShowTransitionPage } = useReaderSettingsStore( const { readingMode, readingDirection, shouldUseInfiniteScroll, shouldShowTransitionPage } = useReaderSettingsStore(
(state) => ({ (state) => ({
readingMode: state.readingMode.value, readingMode: state.readingMode.value,
@@ -259,6 +266,7 @@ export const useReaderInfiniteScrollUpdateChapter = (
const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode); const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode);
if ( if (
!image ||
shouldShowTransitionPage || shouldShowTransitionPage ||
!scrollElement || !scrollElement ||
!isContinuousReadingModeActive || !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); return () => scrollElement.removeEventListener('scroll', onScroll);
}, [ }, [
readingMode, readingMode,
@@ -307,6 +323,7 @@ export const useReaderInfiniteScrollUpdateChapter = (
isCurrentChapter, isCurrentChapter,
isChapterToOpenVisible, isChapterToOpenVisible,
chapterToOpenId, chapterToOpenId,
!!image,
]); ]);
useIntersectionObserver( useIntersectionObserver(

View File

@@ -82,3 +82,16 @@ export const getNextRotationValue = <Value>(
return values[(indexOfValue + 1) % values.length]; 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;
};