Add infinite scroll to reader

This commit is contained in:
schroda
2025-01-28 02:16:00 +01:00
parent 4789a74785
commit 4a9d2903b8
20 changed files with 1068 additions and 238 deletions

View File

@@ -7,7 +7,7 @@
*/
import Box from '@mui/material/Box';
import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { memo, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useDefaultReaderSettings } from '@/modules/reader/services/ReaderSettingsMetadata.ts';
@@ -33,7 +33,7 @@ import { ReaderHotkeys } from '@/modules/reader/components/ReaderHotkeys.tsx';
import {
IReaderSettings,
IReaderSettingsWithDefaultFlag,
ReaderResumeMode,
ReaderOpenChapterLocationState,
ReaderStateChapters,
TReaderAutoScrollContext,
TReaderStateMangaContext,
@@ -49,7 +49,6 @@ import { useReaderAutoScrollContext } from '@/modules/reader/contexts/ReaderAuto
import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts';
import { useReaderTapZoneContext } from '@/modules/reader/contexts/ReaderTapZoneContext.tsx';
import { useReaderResetStates } from '@/modules/reader/hooks/useReaderResetStates.ts';
import { useReaderSetPagesState } from '@/modules/reader/hooks/useReaderSetPagesState.ts';
import { useReaderSetSettingsState } from '@/modules/reader/hooks/useReaderSetSettingsState.ts';
import { useReaderShowSettingPreviewOnChange } from '@/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts';
import { useReaderSetChaptersState } from '@/modules/reader/hooks/useReaderSetChaptersState.ts';
@@ -70,9 +69,9 @@ const BaseReader = ({
shouldShowReadingModePreview,
shouldShowTapZoneLayoutPreview,
setSettings,
initialChapter,
chapterForDuplicatesHandling,
currentChapter,
mangaChapters,
setReaderStateChapters,
firstPageUrl,
totalPages,
@@ -94,7 +93,10 @@ const BaseReader = ({
'shouldSkipDupChapters' | 'backgroundColor' | 'shouldShowReadingModePreview' | 'shouldShowTapZoneLayoutPreview'
> &
Pick<IReaderSettingsWithDefaultFlag, 'readingMode' | 'tapZoneLayout' | 'tapZoneInvertMode'> &
Pick<ReaderStateChapters, 'chapterForDuplicatesHandling' | 'currentChapter' | 'mangaChapters' | 'setReaderStateChapters'> &
Pick<
ReaderStateChapters,
'initialChapter' | 'chapterForDuplicatesHandling' | 'currentChapter' | 'setReaderStateChapters'
> &
Pick<
ReaderStatePages,
| 'totalPages'
@@ -111,9 +113,7 @@ const BaseReader = ({
cancelAutoScroll: TReaderAutoScrollContext['cancel'];
}) => {
const { t } = useTranslation();
const { resumeMode } = useLocation<{
resumeMode: ReaderResumeMode;
}>().state ?? { resumeMode: ReaderResumeMode.START };
const { updateInitialChapter } = useLocation<ReaderOpenChapterLocationState>().state ?? {};
const scrollElementRef = useRef<HTMLDivElement | null>(null);
@@ -128,20 +128,6 @@ const BaseReader = ({
const mangaResponse = requestManager.useGetManga<GetMangaReaderQuery>(GET_MANGA_READER, mangaId);
const chaptersResponse = requestManager.useGetMangaChapters<GetChaptersReaderQuery>(GET_CHAPTERS_READER, mangaId);
const [arePagesFetched, setArePagesFetched] = useState(false);
const [fetchPages, pagesResponse] = requestManager.useGetChapterPagesFetch(-1);
const doFetchPages = useCallback(() => {
if (!currentChapter) {
return;
}
setArePagesFetched(false);
fetchPages({ variables: { input: { chapterId: currentChapter.id } } }).catch(
defaultPromiseErrorHandler('Reader::fetchPages'),
);
}, [fetchPages, currentChapter?.id]);
const {
metadata: defaultSettingsMetadata,
@@ -149,21 +135,13 @@ const BaseReader = ({
request: defaultSettingsResponse,
} = useDefaultReaderSettings();
const doesChapterExist =
!chaptersResponse.loading &&
!chaptersResponse.error &&
chapterSourceOrder >= 0 &&
chapterSourceOrder <= mangaChapters.length;
const isLoading =
currentChapter === undefined ||
!areSettingsSet ||
mangaResponse.loading ||
chaptersResponse.loading ||
defaultSettingsResponse.loading ||
pagesResponse.loading ||
(doesChapterExist && !arePagesFetched && !chaptersResponse.error && !pagesResponse.error);
const error = mangaResponse.error ?? chaptersResponse.error ?? defaultSettingsResponse.error ?? pagesResponse.error;
defaultSettingsResponse.loading;
const error = mangaResponse.error ?? chaptersResponse.error ?? defaultSettingsResponse.error;
useLayoutEffect(() => {
if (!manga || !currentChapter) {
@@ -174,11 +152,6 @@ const BaseReader = ({
setTitle(`${manga.title}: ${currentChapter.name}`);
}, [t, mangaId, chapterSourceOrder, manga, currentChapter]);
useEffect(() => {
doFetchPages();
return () => setArePagesFetched(false);
}, [currentChapter?.id]);
useEffect(() => {
setManga(mangaResponse.data?.manga);
}, [mangaResponse.data?.manga]);
@@ -197,19 +170,6 @@ const BaseReader = ({
setSettings,
cancelAutoScroll,
);
useReaderSetPagesState(
pagesResponse,
resumeMode,
currentChapter,
setArePagesFetched,
setTotalPages,
setPages,
setPageUrls,
setPageLoadStates,
setCurrentPageIndex,
setPageToScrollToIndex,
setTransitionPageMode,
);
useReaderSetSettingsState(
mangaResponse,
defaultSettingsResponse,
@@ -232,6 +192,7 @@ const BaseReader = ({
useReaderSetChaptersState(
chaptersResponse,
chapterSourceOrder,
updateInitialChapter ? undefined : initialChapter,
chapterForDuplicatesHandling,
setReaderStateChapters,
shouldSkipDupChapters,
@@ -283,10 +244,6 @@ const BaseReader = ({
if (chaptersResponse.error) {
chaptersResponse.refetch().catch(defaultPromiseErrorHandler('Reader::refetchChapters'));
}
if (pagesResponse.error) {
doFetchPages();
}
}}
/>
);
@@ -311,10 +268,6 @@ const BaseReader = ({
return <EmptyViewAbsoluteCentered message={t('reader.error.label.chapter_not_found')} />;
}
if (currentChapter && !currentChapter?.pageCount) {
return <EmptyViewAbsoluteCentered message={t('reader.error.label.no_pages_found')} retry={doFetchPages} />;
}
if (!manga || !currentChapter) {
return null;
}
@@ -395,9 +348,9 @@ export const Reader = withPropsFrom(
'shouldShowReadingModePreview',
'shouldShowTapZoneLayoutPreview',
'setSettings',
'initialChapter',
'chapterForDuplicatesHandling',
'currentChapter',
'mangaChapters',
'setReaderStateChapters',
'firstPageUrl',
'totalPages',