Add option to disable "infinite chapter scroll"

This commit is contained in:
schroda
2025-04-26 23:19:01 +02:00
parent f9930b94ca
commit beda5096d1
10 changed files with 67 additions and 20 deletions

View File

@@ -946,6 +946,10 @@
"stretch_image": "Toggle stretch image"
},
"image_preload_amount": "Preload images",
"infinite_scroll": {
"description": "Keep previous and upcoming chapters visible while reading in continuous reading modes, allowing seamless scrolling between chapters.",
"title": "Continuous chapter display"
},
"label": {
"behaviour": "Behaviour",
"fit_page_to_window": "Fit page to window",

View File

@@ -87,6 +87,7 @@ const APP_METADATA_OBJECT: Record<AppMetadataKeys, undefined> = {
showChapterNumber: undefined,
extensionLanguages: undefined,
showNsfw: undefined,
shouldUseInfiniteScroll: undefined,
};
export const VALID_APP_METADATA_KEYS = Object.keys(APP_METADATA_OBJECT);

View File

@@ -54,6 +54,18 @@ export const ReaderBehaviourSettings = ({
onChange={(_, checked) => updateSetting('shouldOffsetDoubleSpreads', checked)}
/>
)}
<CheckboxInput
label={
<Box>
<Typography>{t('reader.settings.infinite_scroll.title')}</Typography>
<Typography variant="body2" color="textDisabled">
{t('reader.settings.infinite_scroll.description')}
</Typography>
</Box>
}
checked={settings.shouldUseInfiniteScroll}
onChange={(_, checked) => updateSetting('shouldUseInfiniteScroll', checked)}
/>
<CheckboxInput
label={
<Box>

View File

@@ -64,6 +64,7 @@ const BaseReaderChapterViewer = ({
pageScaleMode,
shouldOffsetDoubleSpreads,
readingDirection,
shouldUseInfiniteScroll,
imagePreLoadAmount,
pageGap,
chapterId,
@@ -107,7 +108,12 @@ const BaseReaderChapterViewer = ({
Omit<ReaderPagerProps, 'pages' | 'totalPages' | 'pageLoadStates' | 'handleAsInitialRender' | 'resumeMode'> &
Pick<
IReaderSettings,
'readingMode' | 'shouldOffsetDoubleSpreads' | 'readingDirection' | 'readerWidth' | 'pageScaleMode'
| 'readingMode'
| 'shouldOffsetDoubleSpreads'
| 'readingDirection'
| 'readerWidth'
| 'pageScaleMode'
| 'shouldUseInfiniteScroll'
> &
Pick<ReaderStateChapters, 'setReaderStateChapters'> & {
updateCurrentPageIndex: ReturnType<typeof ReaderControls.useUpdateCurrentPageIndex>;
@@ -412,6 +418,7 @@ const BaseReaderChapterViewer = ({
<ReaderInfiniteScrollUpdateChapter
readingMode={readingMode}
readingDirection={readingDirection}
shouldUseInfiniteScroll={shouldUseInfiniteScroll}
chapterId={chapterId}
previousChapterId={previousChapterId}
nextChapterId={nextChapterId}

View File

@@ -9,13 +9,14 @@
import { memo } from 'react';
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
import { useReaderInfiniteScrollUpdateChapter } from '@/modules/reader/hooks/useReaderInfiniteScrollUpdateChapter.ts';
import { ReadingDirection, ReadingMode, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
import { IReaderSettings, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts';
import { ChapterIdInfo } from '@/modules/chapter/services/Chapters.ts';
const BaseReaderInfiniteScrollUpdateChapter = ({
readingMode,
readingDirection,
shouldUseInfiniteScroll,
chapterId,
previousChapterId,
nextChapterId,
@@ -27,19 +28,18 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
scrollbarXSize,
scrollbarYSize,
scrollElement,
}: Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> & {
readingMode: ReadingMode;
readingDirection: ReadingDirection;
chapterId: ChapterIdInfo['id'];
previousChapterId?: ChapterIdInfo['id'];
nextChapterId?: ChapterIdInfo['id'];
isPreviousChapterVisible: boolean;
isCurrentChapter: boolean;
isNextChapterVisible: boolean;
imageWrapper: HTMLElement | null;
openChapter: ReturnType<typeof ReaderControls.useOpenChapter>;
scrollElement: HTMLElement | null;
}) => {
}: Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> &
Pick<IReaderSettings, 'readingMode' | 'readingDirection' | 'shouldUseInfiniteScroll'> & {
chapterId: ChapterIdInfo['id'];
previousChapterId?: ChapterIdInfo['id'];
nextChapterId?: ChapterIdInfo['id'];
isPreviousChapterVisible: boolean;
isCurrentChapter: boolean;
isNextChapterVisible: boolean;
imageWrapper: HTMLElement | null;
openChapter: ReturnType<typeof ReaderControls.useOpenChapter>;
scrollElement: HTMLElement | null;
}) => {
useReaderInfiniteScrollUpdateChapter(
'first',
chapterId,
@@ -48,6 +48,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
isPreviousChapterVisible,
readingMode,
readingDirection,
shouldUseInfiniteScroll,
openChapter,
imageWrapper,
scrollbarXSize,
@@ -62,6 +63,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
isNextChapterVisible,
readingMode,
readingDirection,
shouldUseInfiniteScroll,
openChapter,
imageWrapper,
scrollbarXSize,

View File

@@ -94,6 +94,7 @@ const BaseReaderViewer = forwardRef(
setTransitionPageMode,
readingMode,
readingDirection,
shouldUseInfiniteScroll,
readerWidth,
pageScaleMode,
shouldOffsetDoubleSpreads,
@@ -134,6 +135,7 @@ const BaseReaderViewer = forwardRef(
IReaderSettings,
| 'readingMode'
| 'readingDirection'
| 'shouldUseInfiniteScroll'
| 'readerWidth'
| 'pageScaleMode'
| 'shouldOffsetDoubleSpreads'
@@ -408,6 +410,7 @@ const BaseReaderViewer = forwardRef(
pageScaleMode={pageScaleMode}
shouldOffsetDoubleSpreads={shouldOffsetDoubleSpreads}
readingDirection={readingDirection}
shouldUseInfiniteScroll={shouldUseInfiniteScroll}
updateCurrentPageIndex={isCurrentChapter ? updateCurrentPageIndex : noOp}
scrollIntoView={isCurrentChapter && visibleChapters.scrollIntoView}
resumeMode={getReaderChapterViewResumeMode(
@@ -465,6 +468,7 @@ export const ReaderViewer = withPropsFrom(
'setTransitionPageMode',
'readingMode',
'readingDirection',
'shouldUseInfiniteScroll',
'readerWidth',
'pageScaleMode',
'shouldOffsetDoubleSpreads',

View File

@@ -71,6 +71,7 @@ const GLOBAL_READER_SETTING_OBJECT: Record<keyof IReaderSettingsGlobal, undefine
shouldInformAboutMissingChapter: undefined,
shouldInformAboutScanlatorChange: undefined,
scrollAmount: undefined,
shouldUseInfiniteScroll: undefined,
};
export const GLOBAL_READER_SETTING_KEYS = Object.keys(GLOBAL_READER_SETTING_OBJECT);
@@ -155,6 +156,7 @@ export const DEFAULT_READER_SETTINGS: IReaderSettings = {
shouldInformAboutMissingChapter: true,
shouldInformAboutScanlatorChange: true,
scrollAmount: ReaderScrollAmount.LARGE,
shouldUseInfiniteScroll: true,
};
export const READER_PROGRESS_BAR_POSITION_TO_PLACEMENT: Record<ProgressBarPosition, TooltipProps['placement']> = {

View File

@@ -240,6 +240,7 @@ export const useReaderInfiniteScrollUpdateChapter = (
isChapterToOpenVisible: boolean,
readingMode: ReadingMode,
readingDirection: ReadingDirection,
shouldUseInfiniteScroll: boolean,
openChapter: ReturnType<typeof ReaderControls.useOpenChapter>,
image: HTMLElement | null,
scrollbarXSize: number,
@@ -250,7 +251,11 @@ export const useReaderInfiniteScrollUpdateChapter = (
image,
useCallback(
(entries) => {
if (!isContinuousReadingMode(readingMode) || chapterToOpenId === undefined) {
if (
!shouldUseInfiniteScroll ||
!isContinuousReadingMode(readingMode) ||
chapterToOpenId === undefined
) {
return;
}
@@ -297,6 +302,7 @@ export const useReaderInfiniteScrollUpdateChapter = (
isChapterToOpenVisible,
readingMode,
readingDirection,
shouldUseInfiniteScroll,
openChapter,
scrollbarXSize,
scrollbarYSize,

View File

@@ -175,8 +175,12 @@ export class ReaderControls {
scrollIntoView?: boolean,
) => void {
const { t } = useTranslation();
const { readingMode, shouldInformAboutMissingChapter, shouldInformAboutScanlatorChange } =
ReaderService.useSettings();
const {
readingMode,
shouldInformAboutMissingChapter,
shouldInformAboutScanlatorChange,
shouldUseInfiniteScroll,
} = ReaderService.useSettings();
const {
currentChapter,
previousChapter,
@@ -239,7 +243,7 @@ export class ReaderControls {
const isAlreadyLoaded =
lastLeadingChapterSourceOrder <= chapterToOpen.sourceOrder &&
lastTrailingChapterSourceOrder >= chapterToOpen.sourceOrder;
const keepRenderedChapters = !scrollIntoView || isAlreadyLoaded;
const keepRenderedChapters = shouldUseInfiniteScroll && (!scrollIntoView || isAlreadyLoaded);
if (keepRenderedChapters) {
setReaderStateChapters((prevState) =>
@@ -255,7 +259,10 @@ export class ReaderControls {
}
openChapter(chapterToOpen, {
resumeMode: getReaderOpenChapterResumeMode(isSpecificChapterMode, isPreviousChapter),
resumeMode: getReaderOpenChapterResumeMode(
isSpecificChapterMode || !keepRenderedChapters,
isPreviousChapter,
),
updateInitialChapter: !keepRenderedChapters,
});
} catch (error) {
@@ -274,6 +281,7 @@ export class ReaderControls {
shouldInformAboutScanlatorChange,
lastLeadingChapterSourceOrder,
lastTrailingChapterSourceOrder,
shouldUseInfiniteScroll,
],
);
}

View File

@@ -160,6 +160,7 @@ export interface IReaderSettingsGlobal {
shouldInformAboutMissingChapter: boolean;
shouldInformAboutScanlatorChange: boolean;
scrollAmount: ReaderScrollAmount;
shouldUseInfiniteScroll: boolean;
}
export interface IReaderSettingsManga {