Improve image preloading of previous/next chapter pages

The previous/next chapter only ever preloaded the first page, ignoring available preload contingent.
I.e., if all leading/trailing pages of the current chapter were loaded, the reader did not keep preloading the previous/next chapters pages
This commit is contained in:
schroda
2026-06-04 15:32:11 +02:00
parent 802079ef3d
commit ad7e7f1771
6 changed files with 48 additions and 3 deletions

View File

@@ -363,6 +363,7 @@ export interface ReaderPagerProps
resumeMode: ReaderResumeMode;
handleAsInitialRender: boolean;
ref?: Ref<HTMLDivElement>;
currentChapterRemainingPages: number;
}
export enum PageInViewportType {

View File

@@ -81,6 +81,7 @@ const BaseReaderChapterViewer = ({
minWidth,
minHeight,
scrollElement,
currentChapterRemainingPages,
}: Pick<ReaderStatePages, 'currentPageIndex' | 'transitionPageMode' | 'retryFailedPagesKeyPrefix'> &
Omit<ReaderPagerProps, 'pages' | 'totalPages' | 'pageLoadStates' | 'handleAsInitialRender' | 'resumeMode'> &
Pick<
@@ -433,6 +434,7 @@ const BaseReaderChapterViewer = ({
isPreloadMode={isPreloadMode}
resumeMode={resumeMode}
handleAsInitialRender={scrollIntoView}
currentChapterRemainingPages={currentChapterRemainingPages}
/>
{showNextTransitionPage && (
<ReaderTransitionPage chapterId={chapterId} type={ReaderTransitionPageMode.NEXT} />

View File

@@ -51,6 +51,7 @@ import {
useReaderSettingsStore,
} from '@/features/reader/stores/ReaderStore.ts';
import { STABLE_EMPTY_OBJECT } from '@/base/Base.constants.ts';
import { getPage } from '@/features/reader/overlay/progress-bar/ReaderProgressBar.utils.tsx';
const READING_MODE_TO_IN_VIEWPORT_TYPE: Record<ReadingMode, PageInViewportType> = {
[ReadingMode.SINGLE_PAGE]: PageInViewportType.X,
@@ -290,10 +291,13 @@ const BaseReaderViewer = ({
const isCurrentChapter = chapter.id === currentChapter.id;
const isPreviousChapter = chapter.id === chaptersToRender[currentChapterIndex + 1]?.id;
const isNextChapter = chapter.id === chaptersToRender[currentChapterIndex - 1]?.id;
const isAdjacentChapterToCurrentChapter = isPreviousChapter || isNextChapter;
const isLeadingChapter = initialChapter.sourceOrder > chapter.sourceOrder;
const isTrailingChapter = initialChapter.sourceOrder < chapter.sourceOrder;
const isLastLeadingChapter = visibleChapters.lastLeadingChapterSourceOrder === chapter.sourceOrder;
const isLastTrailingChapter = visibleChapters.lastTrailingChapterSourceOrder === chapter.sourceOrder;
const isPreloadMode =
(isLastLeadingChapter && visibleChapters.isLeadingChapterPreloadMode) ||
(isLastTrailingChapter && visibleChapters.isTrailingChapterPreloadMode);
@@ -306,6 +310,29 @@ const BaseReaderViewer = ({
const isChapterSizeSourceChapter = chapter.id === minChapterSizeSourceChapterId;
const currentChapterCurrentPageIndex = isAdjacentChapterToCurrentChapter
? getReaderChapterViewerCurrentPageIndex(
currentPageIndex,
currentChapter,
currentChapter,
true,
isCurrentChapterReady,
initialChapter.sourceOrder > currentChapter.sourceOrder,
initialChapter.sourceOrder < currentChapter.sourceOrder,
visibleChapters,
)
: -1;
const currentChapterCurrentPagesIndex = isAdjacentChapterToCurrentChapter
? getPage(currentChapterCurrentPageIndex, pages).pagesIndex
: -1;
const currentChapterRemainingLeadingPages = currentChapterCurrentPagesIndex;
const currentChapterRemainingTrailingPages = pages.length - 1 - currentChapterCurrentPagesIndex;
const currentChapterRemainingPages = isNextChapter
? currentChapterRemainingTrailingPages
: currentChapterRemainingLeadingPages;
return (
<ReaderChapterViewer
key={chapter.id}
@@ -315,6 +342,7 @@ const BaseReaderViewer = ({
isPreviousChapterVisible={previousNextChapterVisibility.previous}
isNextChapterVisible={previousNextChapterVisibility.next}
lastPageRead={coerceIn(chapter.lastPageRead, 0, chapter.pageCount - 1)}
currentChapterRemainingPages={currentChapterRemainingPages}
currentPageIndex={getReaderChapterViewerCurrentPageIndex(
currentPageIndex,
chapter,

View File

@@ -533,12 +533,12 @@ export const isSpreadPage = (image: HTMLImageElement): boolean => {
};
const MIN_PREVIOUS_NEXT_CHAPTER_IMAGE_LOAD_AMOUNT = 0;
const MAX_PREVIOUS_NEXT_CHAPTER_IMAGE_LOAD_AMOUNT = 1;
const getImagePreLoadAmount = (
isCurrentChapter: boolean,
isPreviousChapter: boolean,
isNextChapter: boolean,
imagePreLoadAmount: number,
currentChapterRemainingPages: number,
): number => {
if (isCurrentChapter) {
return imagePreLoadAmount;
@@ -546,7 +546,7 @@ const getImagePreLoadAmount = (
if (isPreviousChapter || isNextChapter) {
return coerceIn(
MAX_PREVIOUS_NEXT_CHAPTER_IMAGE_LOAD_AMOUNT,
imagePreLoadAmount - currentChapterRemainingPages,
MIN_PREVIOUS_NEXT_CHAPTER_IMAGE_LOAD_AMOUNT,
imagePreLoadAmount,
);
@@ -557,6 +557,7 @@ const getImagePreLoadAmount = (
const PREVIOUS_IMAGE_LOAD_AMOUNT = 2;
export const getPageIndexesToLoad = (
currentChapterRemainingPages: number,
currentPageIndex: number,
pages: ReaderStatePages['pages'],
previousCurrentPageIndex: number,
@@ -576,6 +577,7 @@ export const getPageIndexesToLoad = (
isPreviousChapter,
isNextChapter,
imagePreLoadAmount,
currentChapterRemainingPages,
);
const directionInvert = previousCurrentPageIndex <= currentPageIndex && !isPreviousChapter ? 1 : -1;

View File

@@ -40,6 +40,7 @@ const BaseBasePager = ({
resumeMode,
handleAsInitialRender,
ref,
currentChapterRemainingPages,
}: Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix' | 'isPreloadMode'> &
Pick<IReaderSettings, 'readingMode' | 'imagePreLoadAmount'> & {
createPage: (
@@ -67,6 +68,7 @@ const BaseBasePager = ({
const pagesIndexesToRender = useMemo(
() =>
getPageIndexesToLoad(
currentChapterRemainingPages,
currentPageIndex,
pages,
previousCurrentPageIndex.current,
@@ -76,7 +78,16 @@ const BaseBasePager = ({
isPreviousChapter,
isNextChapter,
),
[currentPageIndex, pages, imagePreLoadAmount, readingMode, isCurrentChapter, isPreviousChapter, isNextChapter],
[
currentChapterRemainingPages,
currentPageIndex,
pages,
imagePreLoadAmount,
readingMode,
isCurrentChapter,
isPreviousChapter,
isNextChapter,
],
);
useEffect(() => {
if (isCurrentChapter) {