diff --git a/src/modules/reader/services/ReaderControls.ts b/src/modules/reader/services/ReaderControls.ts index 01b6b9c1..828bd8a1 100644 --- a/src/modules/reader/services/ReaderControls.ts +++ b/src/modules/reader/services/ReaderControls.ts @@ -24,7 +24,6 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R import { PageInViewportType, ProgressBarPosition, - ReaderResumeMode, ReaderTransitionPageMode, ReadingDirection, ReadingMode, @@ -44,8 +43,12 @@ import { useReaderTapZoneContext } from '@/modules/reader/contexts/ReaderTapZone import { TapZoneRegionType, TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts'; import { ReaderTapZoneService } from '@/modules/reader/services/ReaderTapZoneService.ts'; import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; -import { getReaderChapterFromCache } from '@/modules/reader/utils/Reader.utils.ts'; -import { Chapters } from '@/modules/chapter/services/Chapters.ts'; +import { + getReaderChapterFromCache, + getReaderOpenChapterResumeMode, + updateReaderStateVisibleChapters, +} from '@/modules/reader/utils/Reader.utils.ts'; +import { ChapterIdInfo, Chapters } from '@/modules/chapter/services/Chapters.ts'; import { DirectionOffset, TranslationKey } from '@/Base.types.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { TChapterReader } from '@/modules/chapter/Chapter.types.ts'; @@ -166,51 +169,82 @@ export class ReaderControls { } } - static useOpenChapter(): (offset: 'previous' | 'next') => void { + static useOpenChapter(): (offset: 'previous' | 'next' | ChapterIdInfo['id'], doTransitionCheck?: boolean) => void { const { t } = useTranslation(); const { readingMode, shouldInformAboutMissingChapter, shouldInformAboutScanlatorChange } = ReaderService.useSettings(); - const { currentChapter, previousChapter, nextChapter } = useReaderStateChaptersContext(); + const { currentChapter, previousChapter, nextChapter, chapters, setReaderStateChapters } = + useReaderStateChaptersContext(); - const openPreviousChapter = ReaderService.useNavigateToChapter(previousChapter, ReaderResumeMode.END); - const openNextChapter = ReaderService.useNavigateToChapter(nextChapter, ReaderResumeMode.START); + const openChapter = ReaderService.useNavigateToChapter(); return useCallback( - (offset) => { - switch (offset) { - case 'previous': - ReaderControls.checkNextChapterConsistency( - t, - offset, - currentChapter, - previousChapter, - shouldInformAboutMissingChapter, - shouldInformAboutScanlatorChange, - ) - .then(openPreviousChapter) - .catch(defaultPromiseErrorHandler('ReaderControls::checkNextChapterConsistency: previous')); - break; - case 'next': - ReaderControls.checkNextChapterConsistency( - t, - offset, - currentChapter, - nextChapter, - shouldInformAboutMissingChapter, - shouldInformAboutScanlatorChange, - ) - .then(openNextChapter) - .catch(defaultPromiseErrorHandler('ReaderControls::checkNextChapterConsistency: next')); - break; - default: - throw new Error(`Unexpected "offset" (${offset})`); + (offset, doTransitionCheck = true) => { + if (!currentChapter) { + return; } + + const isSpecificChapterMode = typeof offset === 'number'; + const isPreviousOffset = offset === 'previous'; + + const doesPreviousChapterExist = isPreviousOffset && !!previousChapter; + const doesNextChapterExist = !isPreviousOffset && !!nextChapter; + + const canOpenNextChapter = isSpecificChapterMode || doesPreviousChapterExist || doesNextChapterExist; + if (!canOpenNextChapter) { + return; + } + + const doOpenChapter = async () => { + const chapterToOpen = (() => { + if (isSpecificChapterMode) { + return chapters.find((chapter) => chapter.id === offset); + } + + if (isPreviousOffset) { + return previousChapter; + } + + return nextChapter; + })(); + + if (!chapterToOpen) { + return; + } + + const isPreviousChapter = chapterToOpen.sourceOrder < currentChapter.sourceOrder; + + try { + if (doTransitionCheck) { + await ReaderControls.checkNextChapterConsistency( + t, + isPreviousChapter ? 'previous' : 'next', + currentChapter, + chapterToOpen, + shouldInformAboutMissingChapter, + shouldInformAboutScanlatorChange, + ); + } + + setReaderStateChapters((prevState) => + updateReaderStateVisibleChapters(isPreviousChapter, prevState, chapterToOpen.sourceOrder), + ); + + openChapter( + chapterToOpen, + getReaderOpenChapterResumeMode(isSpecificChapterMode, isPreviousChapter), + ); + } catch (error) { + defaultPromiseErrorHandler('ReaderControls#useOpenChapter#doOpenChapter: '); + } + }; + + doOpenChapter().catch(defaultPromiseErrorHandler('ReaderControls#useOpenChapter')); }, [ t, currentChapter?.id, - openPreviousChapter, - openNextChapter, + openChapter, readingMode.value, shouldInformAboutMissingChapter, shouldInformAboutScanlatorChange, diff --git a/src/modules/reader/services/ReaderService.ts b/src/modules/reader/services/ReaderService.ts index 8809ab2d..adb5e6bc 100644 --- a/src/modules/reader/services/ReaderService.ts +++ b/src/modules/reader/services/ReaderService.ts @@ -75,19 +75,17 @@ export class ReaderService { return ReaderService.chapterUpdateQueues.get(id)!; } - static useNavigateToChapter(chapter?: TChapterReader, resumeMode?: ReaderResumeMode): () => void { + static useNavigateToChapter(): (chapter: TChapterReader, resumeMode?: ReaderResumeMode) => void { const navigate = useNavigate(); - return useCallback( - () => - chapter && - navigate(Chapters.getReaderUrl(chapter), { - replace: true, - state: { - resumeMode, - }, - }), - [chapter], - ); + + return useCallback((chapter, resumeMode) => { + navigate(Chapters.getReaderUrl(chapter), { + replace: true, + state: { + resumeMode, + }, + }); + }, []); } static downloadAhead( diff --git a/src/modules/reader/utils/Reader.utils.ts b/src/modules/reader/utils/Reader.utils.ts index 1654cc60..04301218 100644 --- a/src/modules/reader/utils/Reader.utils.ts +++ b/src/modules/reader/utils/Reader.utils.ts @@ -165,3 +165,18 @@ export const createUpdateReaderPageLoadState = return statePageLoadStates.toSpliced(index, 1, { url: pageLoadState.url, loaded: true }); }); }; + +export const getReaderOpenChapterResumeMode = ( + isSpecificChapterMode: boolean, + isPreviousChapter: boolean, +): ReaderResumeMode | undefined => { + if (!isSpecificChapterMode) { + return undefined; + } + + if (isPreviousChapter) { + return ReaderResumeMode.END; + } + + return ReaderResumeMode.START; +};