From f0f740f4af4247106edb76bbb743de27a545d923 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 5 May 2025 01:26:27 +0200 Subject: [PATCH] Add option to disable transition pages The previous/next transition page of the first/last chapter will still be shown to indicate that there is no previous/next chapter --- public/locales/en.json | 1 + src/modules/metadata/Metadata.constants.ts | 2 + .../behaviour/ReaderBehaviourSettings.tsx | 5 ++ .../ReaderInfiniteScrollUpdateChapter.tsx | 11 ++- .../viewer/ReaderTransitionPage.tsx | 13 +++- .../constants/ReaderSettings.constants.tsx | 2 + .../useReaderInfiniteScrollUpdateChapter.ts | 70 +++++++++++++++++-- src/modules/reader/services/ReaderControls.ts | 5 +- src/modules/reader/types/Reader.types.ts | 1 + 9 files changed, 99 insertions(+), 11 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index 3eb013c6..bcd1c965 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -1007,6 +1007,7 @@ "rtl": "Right to left" }, "scroll_amount": "Scroll amount", + "show_transition_page": "Show transition page", "source_series": "Series settings", "tap_zones": { "edge": "Edge", diff --git a/src/modules/metadata/Metadata.constants.ts b/src/modules/metadata/Metadata.constants.ts index d70097e2..d1a05ae6 100644 --- a/src/modules/metadata/Metadata.constants.ts +++ b/src/modules/metadata/Metadata.constants.ts @@ -88,6 +88,7 @@ const APP_METADATA_OBJECT: Record = { extensionLanguages: undefined, showNsfw: undefined, shouldUseInfiniteScroll: undefined, + shouldShowTransitionPage: undefined, }; export const VALID_APP_METADATA_KEYS = Object.keys(APP_METADATA_OBJECT); @@ -164,6 +165,7 @@ export const GLOBAL_METADATA_KEYS: AppMetadataKeys[] = [ 'customFilter', 'shouldSkipDupChapters', 'hotkeys', + 'shouldShowTransitionPage', // manga // chapter list options diff --git a/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx b/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx index 7b9b5803..4c6bdf5c 100644 --- a/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx +++ b/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx @@ -102,6 +102,11 @@ export const ReaderBehaviourSettings = ({ checked={settings.shouldUseAutoWebtoonMode} onChange={(_, checked) => updateSetting('shouldUseAutoWebtoonMode', checked)} /> + updateSetting('shouldShowTransitionPage', checked)} + /> & + shouldShowTransitionPage, +}: Pick & + Pick & Pick & { chapterId: ChapterIdInfo['id']; previousChapterId?: ChapterIdInfo['id']; @@ -54,6 +57,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({ scrollbarXSize, scrollbarYSize, scrollElement, + shouldShowTransitionPage, ); useReaderInfiniteScrollUpdateChapter( 'last', @@ -69,6 +73,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({ scrollbarXSize, scrollbarYSize, scrollElement, + shouldShowTransitionPage, ); return null; @@ -76,6 +81,6 @@ const BaseReaderInfiniteScrollUpdateChapter = ({ export const ReaderInfiniteScrollUpdateChapter = withPropsFrom( memo(BaseReaderInfiniteScrollUpdateChapter), - [() => ({ openChapter: ReaderControls.useOpenChapter() })], - ['openChapter'], + [() => ({ openChapter: ReaderControls.useOpenChapter() }), ReaderService.useSettingsWithoutDefaultFlag], + ['openChapter', 'shouldShowTransitionPage'], ); diff --git a/src/modules/reader/components/viewer/ReaderTransitionPage.tsx b/src/modules/reader/components/viewer/ReaderTransitionPage.tsx index ea1b55e5..4f22f33c 100644 --- a/src/modules/reader/components/viewer/ReaderTransitionPage.tsx +++ b/src/modules/reader/components/viewer/ReaderTransitionPage.tsx @@ -84,6 +84,7 @@ const BaseReaderTransitionPage = ({ transitionPageMode, readingMode, backgroundColor, + shouldShowTransitionPage, manga, currentChapterName, currentChapterScanlator, @@ -95,7 +96,7 @@ const BaseReaderTransitionPage = ({ scrollbarYSize, readerNavBarWidth, handleBack, -}: Pick & +}: Pick & Pick & Pick & Pick & @@ -120,6 +121,15 @@ const BaseReaderTransitionPage = ({ const isFirstChapter = !!currentChapterName && !previousChapterName; const isLastChapter = !!currentChapterName && !nextChapterName; + const forceShowFirstChapterPreviousTransitionPage = isFirstChapter && type === ReaderTransitionPageMode.PREVIOUS; + const forceShowLastChapterNextTransitionPage = isLastChapter && type === ReaderTransitionPageMode.NEXT; + const forceShowTransitionPage = + forceShowFirstChapterPreviousTransitionPage || forceShowLastChapterNextTransitionPage; + + if (!shouldShowTransitionPage && !forceShowTransitionPage) { + return null; + } + if (!isTransitionPageVisible(type, transitionPageMode, readingMode)) { return null; } @@ -290,5 +300,6 @@ export const ReaderTransitionPage = withPropsFrom( 'transitionPageMode', 'readingMode', 'handleBack', + 'shouldShowTransitionPage', ], ); diff --git a/src/modules/reader/constants/ReaderSettings.constants.tsx b/src/modules/reader/constants/ReaderSettings.constants.tsx index 6db9d723..8393f983 100644 --- a/src/modules/reader/constants/ReaderSettings.constants.tsx +++ b/src/modules/reader/constants/ReaderSettings.constants.tsx @@ -72,6 +72,7 @@ const GLOBAL_READER_SETTING_OBJECT: Record = { diff --git a/src/modules/reader/hooks/useReaderInfiniteScrollUpdateChapter.ts b/src/modules/reader/hooks/useReaderInfiniteScrollUpdateChapter.ts index cc869b75..310f19db 100644 --- a/src/modules/reader/hooks/useReaderInfiniteScrollUpdateChapter.ts +++ b/src/modules/reader/hooks/useReaderInfiniteScrollUpdateChapter.ts @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts'; import { ReadingDirection, ReadingMode } from '@/modules/reader/types/Reader.types.ts'; import { @@ -140,13 +140,16 @@ const getElementIntersection = ( }; /** - * Will change the chapter to the previous or next one depending on the intersection of the first or last page. + * Will handle opening the previous or next chapter for infinite scrolling. * - * For the initial load of the previous chapter, the intersection of the first page is used, after the initial load - * of the previous chapter the intersection of the last page handles changing the chapter + * In case the "transition page" is not enabled, the "initial" load of the previous or next chapter is handled + * based on the scroll position. + * After the initial load, the last page of a chapter handles opening the correct chapter. * - * @example - * How it works: + * In case the "transition page" is enabled, for the initial load of the previous chapter, the intersection of the first + * page is used, after the initial load of the previous chapter the intersection of the last page handles changing the chapter. + * + * @example - How the intersection-based approach works: * |, _ = viewport * # = page * @@ -246,12 +249,62 @@ export const useReaderInfiniteScrollUpdateChapter = ( scrollbarXSize: number, scrollbarYSize: number, scrollElement: HTMLElement | null, + shouldShowTransitionPage: boolean, ) => { + useEffect(() => { + const isContinuousReadingModeActive = isContinuousReadingMode(readingMode); + const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode); + + if ( + shouldShowTransitionPage || + !scrollElement || + !isContinuousReadingModeActive || + !shouldUseInfiniteScroll || + !isCurrentChapter || + isChapterToOpenVisible || + chapterToOpenId === undefined + ) { + return () => {}; + } + + const onScroll = () => { + const isAtStartX = scrollElement.scrollLeft === 0; + const isAtEndX = scrollElement.scrollLeft === scrollElement.scrollWidth - scrollElement.clientWidth; + + const isAtStartY = scrollElement.scrollTop === 0; + const isAtEndY = scrollElement.scrollTop === scrollElement.scrollHeight - scrollElement.clientHeight; + + const isAtStart = isContinuousVerticalReadingModeActive ? isAtStartY : isAtStartX; + const isAtEnd = isContinuousVerticalReadingModeActive ? isAtEndY : isAtEndX; + + const loadPreviousChapter = pageType === 'first' && isAtStart; + const loadNextChapter = pageType === 'last' && isAtEnd; + + const loadChapter = loadPreviousChapter || loadNextChapter; + if (loadChapter) { + openChapter(chapterToOpenId, undefined, false); + } + }; + + scrollElement.addEventListener('scroll', onScroll); + return () => scrollElement.removeEventListener('scroll', onScroll); + }, [ + readingMode, + scrollElement, + shouldShowTransitionPage, + shouldUseInfiniteScroll, + isCurrentChapter, + isChapterToOpenVisible, + chapterToOpenId, + openChapter, + ]); + useIntersectionObserver( image, useCallback( (entries) => { if ( + // !shouldShowTransitionPage || !shouldUseInfiniteScroll || !isContinuousReadingMode(readingMode) || chapterToOpenId === undefined @@ -259,6 +312,10 @@ export const useReaderInfiniteScrollUpdateChapter = ( return; } + if (!shouldShowTransitionPage && !isChapterToOpenVisible) { + return; + } + const entry = entries[entries.length - 1]; const elementIntersectionInfo = getElementIntersectionInfo( @@ -303,6 +360,7 @@ export const useReaderInfiniteScrollUpdateChapter = ( readingMode, readingDirection, shouldUseInfiniteScroll, + shouldShowTransitionPage, openChapter, scrollbarXSize, scrollbarYSize, diff --git a/src/modules/reader/services/ReaderControls.ts b/src/modules/reader/services/ReaderControls.ts index 47db755f..a73504f2 100644 --- a/src/modules/reader/services/ReaderControls.ts +++ b/src/modules/reader/services/ReaderControls.ts @@ -359,7 +359,7 @@ export class ReaderControls { const { previousChapter, nextChapter } = useReaderStateChaptersContext(); const { setIsVisible: setIsOverlayVisible } = useReaderOverlayContext(); const { setShowPreview } = useReaderTapZoneContext(); - const { readingDirection, readingMode } = ReaderService.useSettings(); + const { readingDirection, readingMode, shouldShowTransitionPage } = ReaderService.useSettings(); const openChapter = ReaderControls.useOpenChapter(); const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]); @@ -404,9 +404,11 @@ export class ReaderControls { const areContinuousPagerTransitionPagesVisible = isContinuousReadingModeActive && isATransitionPageVisibleFlag; const isPreviousTransitionPageVisible = + !shouldShowTransitionPage || (!isContinuousReadingModeActive && transitionPageMode === ReaderTransitionPageMode.PREVIOUS) || areContinuousPagerTransitionPagesVisible; const isNextTransitionPageVisible = + !shouldShowTransitionPage || (!isContinuousReadingModeActive && transitionPageMode === ReaderTransitionPageMode.NEXT) || areContinuousPagerTransitionPagesVisible; @@ -466,6 +468,7 @@ export class ReaderControls { openChapter, !!previousChapter, !!nextChapter, + shouldShowTransitionPage, ], ); } diff --git a/src/modules/reader/types/Reader.types.ts b/src/modules/reader/types/Reader.types.ts index 6ffd281a..7a7dba52 100644 --- a/src/modules/reader/types/Reader.types.ts +++ b/src/modules/reader/types/Reader.types.ts @@ -161,6 +161,7 @@ export interface IReaderSettingsGlobal { shouldInformAboutScanlatorChange: boolean; scrollAmount: ReaderScrollAmount; shouldUseInfiniteScroll: boolean; + shouldShowTransitionPage: boolean; } export interface IReaderSettingsManga {