Add option to open specific chapter via "useOpenChapter"

This commit is contained in:
schroda
2025-01-28 01:30:05 +01:00
parent 45b4874348
commit 4789a74785
3 changed files with 96 additions and 49 deletions

View File

@@ -24,7 +24,6 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R
import { import {
PageInViewportType, PageInViewportType,
ProgressBarPosition, ProgressBarPosition,
ReaderResumeMode,
ReaderTransitionPageMode, ReaderTransitionPageMode,
ReadingDirection, ReadingDirection,
ReadingMode, ReadingMode,
@@ -44,8 +43,12 @@ import { useReaderTapZoneContext } from '@/modules/reader/contexts/ReaderTapZone
import { TapZoneRegionType, TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts'; import { TapZoneRegionType, TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts';
import { ReaderTapZoneService } from '@/modules/reader/services/ReaderTapZoneService.ts'; import { ReaderTapZoneService } from '@/modules/reader/services/ReaderTapZoneService.ts';
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
import { getReaderChapterFromCache } from '@/modules/reader/utils/Reader.utils.ts'; import {
import { Chapters } from '@/modules/chapter/services/Chapters.ts'; 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 { DirectionOffset, TranslationKey } from '@/Base.types.ts';
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
import { TChapterReader } from '@/modules/chapter/Chapter.types.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 { t } = useTranslation();
const { readingMode, shouldInformAboutMissingChapter, shouldInformAboutScanlatorChange } = const { readingMode, shouldInformAboutMissingChapter, shouldInformAboutScanlatorChange } =
ReaderService.useSettings(); ReaderService.useSettings();
const { currentChapter, previousChapter, nextChapter } = useReaderStateChaptersContext(); const { currentChapter, previousChapter, nextChapter, chapters, setReaderStateChapters } =
useReaderStateChaptersContext();
const openPreviousChapter = ReaderService.useNavigateToChapter(previousChapter, ReaderResumeMode.END); const openChapter = ReaderService.useNavigateToChapter();
const openNextChapter = ReaderService.useNavigateToChapter(nextChapter, ReaderResumeMode.START);
return useCallback( return useCallback(
(offset) => { (offset, doTransitionCheck = true) => {
switch (offset) { if (!currentChapter) {
case 'previous': return;
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})`);
} }
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, t,
currentChapter?.id, currentChapter?.id,
openPreviousChapter, openChapter,
openNextChapter,
readingMode.value, readingMode.value,
shouldInformAboutMissingChapter, shouldInformAboutMissingChapter,
shouldInformAboutScanlatorChange, shouldInformAboutScanlatorChange,

View File

@@ -75,19 +75,17 @@ export class ReaderService {
return ReaderService.chapterUpdateQueues.get(id)!; return ReaderService.chapterUpdateQueues.get(id)!;
} }
static useNavigateToChapter(chapter?: TChapterReader, resumeMode?: ReaderResumeMode): () => void { static useNavigateToChapter(): (chapter: TChapterReader, resumeMode?: ReaderResumeMode) => void {
const navigate = useNavigate(); const navigate = useNavigate();
return useCallback(
() => return useCallback((chapter, resumeMode) => {
chapter && navigate(Chapters.getReaderUrl(chapter), {
navigate(Chapters.getReaderUrl(chapter), { replace: true,
replace: true, state: {
state: { resumeMode,
resumeMode, },
}, });
}), }, []);
[chapter],
);
} }
static downloadAhead( static downloadAhead(

View File

@@ -165,3 +165,18 @@ export const createUpdateReaderPageLoadState =
return statePageLoadStates.toSpliced(index, 1, { url: pageLoadState.url, loaded: true }); 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;
};