Add logic to retry all errored pages
This commit is contained in:
@@ -30,11 +30,14 @@ interface IProps {
|
|||||||
imgStyle?: SxProps<Theme>;
|
imgStyle?: SxProps<Theme>;
|
||||||
|
|
||||||
onLoad?: () => void;
|
onLoad?: () => void;
|
||||||
|
onError?: () => void;
|
||||||
|
|
||||||
shouldDecode?: boolean;
|
shouldDecode?: boolean;
|
||||||
useFetchApi?: boolean;
|
useFetchApi?: boolean;
|
||||||
|
|
||||||
priority?: Priority;
|
priority?: Priority;
|
||||||
|
|
||||||
|
retryKeyPrefix?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTMLImageElement | null>) => {
|
export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTMLImageElement | null>) => {
|
||||||
@@ -45,9 +48,11 @@ export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTML
|
|||||||
src,
|
src,
|
||||||
alt,
|
alt,
|
||||||
onLoad,
|
onLoad,
|
||||||
|
onError,
|
||||||
spinnerStyle: { small, ...spinnerStyle } = {},
|
spinnerStyle: { small, ...spinnerStyle } = {},
|
||||||
imgStyle,
|
imgStyle,
|
||||||
priority,
|
priority,
|
||||||
|
retryKeyPrefix,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -63,6 +68,10 @@ export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTML
|
|||||||
setIsLoading(loading);
|
setIsLoading(loading);
|
||||||
setHasError(error);
|
setHasError(error);
|
||||||
|
|
||||||
|
if (error && !loading && !aborted) {
|
||||||
|
onError?.();
|
||||||
|
}
|
||||||
|
|
||||||
if (!loading && !error && !aborted) {
|
if (!loading && !error && !aborted) {
|
||||||
onLoad?.();
|
onLoad?.();
|
||||||
}
|
}
|
||||||
@@ -114,7 +123,7 @@ export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTML
|
|||||||
clearTimeout(cacheTimeout);
|
clearTimeout(cacheTimeout);
|
||||||
imageRequest.abortRequest(new Error('Component was unmounted'));
|
imageRequest.abortRequest(new Error('Component was unmounted'));
|
||||||
};
|
};
|
||||||
}, [src, imgLoadRetryKey, showMissingImageIcon, shouldLoad]);
|
}, [src, imgLoadRetryKey, retryKeyPrefix, showMissingImageIcon, shouldLoad]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -134,7 +143,7 @@ export const SpinnerImage = forwardRef((props: IProps, imgRef: ForwardedRef<HTML
|
|||||||
) : (
|
) : (
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
key={`${src}_${imgLoadRetryKey}`}
|
key={`${src}_${imgLoadRetryKey}_${retryKeyPrefix}`}
|
||||||
sx={[
|
sx={[
|
||||||
...(Array.isArray(imgStyle) ? (imgStyle ?? []) : [imgStyle]),
|
...(Array.isArray(imgStyle) ? (imgStyle ?? []) : [imgStyle]),
|
||||||
applyStyles(!imageSourceUrl || isLoading || hasError, {
|
applyStyles(!imageSourceUrl || isLoading || hasError, {
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ export const ReaderNavBarDesktop = ({ isVisible, openSettings }: ReaderNavBarDes
|
|||||||
const { setReaderNavBarWidth } = useNavBarContext();
|
const { setReaderNavBarWidth } = useNavBarContext();
|
||||||
const { manga } = useReaderStateMangaContext();
|
const { manga } = useReaderStateMangaContext();
|
||||||
const { chapters, currentChapter, nextChapter, previousChapter } = useReaderStateChaptersContext();
|
const { chapters, currentChapter, nextChapter, previousChapter } = useReaderStateChaptersContext();
|
||||||
const { pages, currentPageIndex } = userReaderStatePagesContext();
|
const { pages, currentPageIndex, pageLoadStates, setPageLoadStates, setRetryFailedPagesKeyPrefix } =
|
||||||
|
userReaderStatePagesContext();
|
||||||
|
|
||||||
const getOptionForDirection = useGetOptionForDirection();
|
const getOptionForDirection = useGetOptionForDirection();
|
||||||
|
|
||||||
@@ -118,7 +119,12 @@ export const ReaderNavBarDesktop = ({ isVisible, openSettings }: ReaderNavBarDes
|
|||||||
mangaTitle={manga.title}
|
mangaTitle={manga.title}
|
||||||
chapterTitle={currentChapter.name}
|
chapterTitle={currentChapter.name}
|
||||||
/>
|
/>
|
||||||
<ReaderNavBarDesktopActions currentChapter={currentChapter} />
|
<ReaderNavBarDesktopActions
|
||||||
|
currentChapter={currentChapter}
|
||||||
|
pageLoadStates={pageLoadStates}
|
||||||
|
setPageLoadStates={setPageLoadStates}
|
||||||
|
setRetryFailedPagesKeyPrefix={setRetryFailedPagesKeyPrefix}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<LoadingPlaceholder />
|
<LoadingPlaceholder />
|
||||||
|
|||||||
@@ -15,13 +15,14 @@ import BookmarkBorderIcon from '@mui/icons-material/BookmarkBorder';
|
|||||||
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
|
||||||
import DownloadIcon from '@mui/icons-material/Download';
|
import DownloadIcon from '@mui/icons-material/Download';
|
||||||
import ReplayIcon from '@mui/icons-material/Replay';
|
import ReplayIcon from '@mui/icons-material/Replay';
|
||||||
import { useMemo } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapter/services/Chapters.ts';
|
import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapter/services/Chapters.ts';
|
||||||
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx';
|
import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx';
|
||||||
import { DownloadStatusFieldsFragment } from '@/lib/graphql/generated/graphql.ts';
|
import { DownloadStatusFieldsFragment } from '@/lib/graphql/generated/graphql.ts';
|
||||||
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
|
||||||
const DownloadButton = ({
|
const DownloadButton = ({
|
||||||
currentChapter,
|
currentChapter,
|
||||||
@@ -60,11 +61,17 @@ const DownloadButton = ({
|
|||||||
|
|
||||||
export const ReaderNavBarDesktopActions = ({
|
export const ReaderNavBarDesktopActions = ({
|
||||||
currentChapter,
|
currentChapter,
|
||||||
}: Required<Pick<ReaderStateChapters, 'currentChapter'>>) => {
|
pageLoadStates,
|
||||||
|
setPageLoadStates,
|
||||||
|
setRetryFailedPagesKeyPrefix,
|
||||||
|
}: Required<Pick<ReaderStateChapters, 'currentChapter'>> &
|
||||||
|
Pick<ReaderStatePages, 'pageLoadStates' | 'setPageLoadStates' | 'setRetryFailedPagesKeyPrefix'>) => {
|
||||||
const { id, isBookmarked, realUrl } = currentChapter ?? { id: -1, isBookmarked: false, realUrl: '' };
|
const { id, isBookmarked, realUrl } = currentChapter ?? { id: -1, isBookmarked: false, realUrl: '' };
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const pageRetryKeyPrefix = useRef<number>(0);
|
||||||
|
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
const queue = downloaderData?.downloadStatus.queue ?? [];
|
||||||
|
|
||||||
@@ -73,6 +80,11 @@ export const ReaderNavBarDesktopActions = ({
|
|||||||
[queue, id],
|
[queue, id],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const haveSomePagesFailedToLoad = useMemo(
|
||||||
|
() => pageLoadStates.some((pageLoadState) => pageLoadState.error),
|
||||||
|
[pageLoadStates],
|
||||||
|
);
|
||||||
|
|
||||||
const bookmarkAction: Extract<ChapterAction, 'unbookmark' | 'bookmark'> = isBookmarked ? 'unbookmark' : 'bookmark';
|
const bookmarkAction: Extract<ChapterAction, 'unbookmark' | 'bookmark'> = isBookmarked ? 'unbookmark' : 'bookmark';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -83,7 +95,17 @@ export const ReaderNavBarDesktopActions = ({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={t('reader.button.retry_load_pages')}>
|
<Tooltip title={t('reader.button.retry_load_pages')}>
|
||||||
<IconButton color="inherit">
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
setPageLoadStates((statePageLoadStates) =>
|
||||||
|
statePageLoadStates.map((pageLoadState) => ({ loaded: pageLoadState.loaded })),
|
||||||
|
);
|
||||||
|
setRetryFailedPagesKeyPrefix(`${pageRetryKeyPrefix.current}`);
|
||||||
|
pageRetryKeyPrefix.current = (pageRetryKeyPrefix.current + 1) % 1000;
|
||||||
|
}}
|
||||||
|
disabled={!haveSomePagesFailedToLoad}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
<ReplayIcon />
|
<ReplayIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ export const StandardReaderProgressBar = () => {
|
|||||||
backgroundColor: lighten(theme.palette.background.paper, 0.1),
|
backgroundColor: lighten(theme.palette.background.paper, 0.1),
|
||||||
}),
|
}),
|
||||||
...applyStyles(
|
...applyStyles(
|
||||||
pageLoadStates[primary.index] &&
|
pageLoadStates[primary.index]?.loaded &&
|
||||||
(!secondary || pageLoadStates[secondary.index]),
|
(!secondary || pageLoadStates[secondary.index]?.loaded),
|
||||||
{
|
{
|
||||||
backgroundColor: darken(theme.palette.background.paper, 0.35),
|
backgroundColor: darken(theme.palette.background.paper, 0.35),
|
||||||
...theme.applyStyles('dark', {
|
...theme.applyStyles('dark', {
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ export const ReaderPage = forwardRef(
|
|||||||
doublePage = false,
|
doublePage = false,
|
||||||
position,
|
position,
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
|
retryKeyPrefix,
|
||||||
...props
|
...props
|
||||||
}: Omit<ComponentProps<typeof SpinnerImage>, 'ref' | 'spinnerStyle' | 'imgStyle'> & {
|
}: Omit<ComponentProps<typeof SpinnerImage>, 'ref' | 'spinnerStyle' | 'imgStyle'> & {
|
||||||
display: boolean;
|
display: boolean;
|
||||||
doublePage?: boolean;
|
doublePage?: boolean;
|
||||||
position?: 'left' | 'right';
|
position?: 'left' | 'right';
|
||||||
onLoad?: () => void;
|
|
||||||
},
|
},
|
||||||
ref: ForwardedRef<HTMLImageElement | null>,
|
ref: ForwardedRef<HTMLImageElement | null>,
|
||||||
) => {
|
) => {
|
||||||
@@ -71,6 +71,7 @@ export const ReaderPage = forwardRef(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SpinnerImage
|
<SpinnerImage
|
||||||
|
key={retryKeyPrefix}
|
||||||
{...props}
|
{...props}
|
||||||
shouldLoad={shouldLoad}
|
shouldLoad={shouldLoad}
|
||||||
shouldDecode
|
shouldDecode
|
||||||
|
|||||||
@@ -47,8 +47,10 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
setPages,
|
setPages,
|
||||||
totalPages,
|
totalPages,
|
||||||
pageUrls,
|
pageUrls,
|
||||||
|
pageLoadStates,
|
||||||
setPageLoadStates,
|
setPageLoadStates,
|
||||||
transitionPageMode,
|
transitionPageMode,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
} = userReaderStatePagesContext();
|
} = userReaderStatePagesContext();
|
||||||
const { readingMode, shouldOffsetDoubleSpreads, readingDirection } = ReaderService.useSettings();
|
const { readingMode, shouldOffsetDoubleSpreads, readingDirection } = ReaderService.useSettings();
|
||||||
const { setScrollbarXSize, setScrollbarYSize } = useReaderScrollbarContext();
|
const { setScrollbarXSize, setScrollbarYSize } = useReaderScrollbarContext();
|
||||||
@@ -227,6 +229,8 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
currentPageIndex={currentPageIndex}
|
currentPageIndex={currentPageIndex}
|
||||||
pages={actualPages}
|
pages={actualPages}
|
||||||
transitionPageMode={transitionPageMode}
|
transitionPageMode={transitionPageMode}
|
||||||
|
pageLoadStates={pageLoadStates}
|
||||||
|
retryFailedPagesKeyPrefix={retryFailedPagesKeyPrefix}
|
||||||
imageRefs={imageRefs}
|
imageRefs={imageRefs}
|
||||||
onLoad={(pagesIndex, isPrimary = true) => {
|
onLoad={(pagesIndex, isPrimary = true) => {
|
||||||
const page = actualPages[pagesIndex];
|
const page = actualPages[pagesIndex];
|
||||||
@@ -240,7 +244,14 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
img.src = url;
|
img.src = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPageLoadStates((pageLoadStates) => pageLoadStates.toSpliced(index, 1, true));
|
setPageLoadStates((statePageLoadStates) =>
|
||||||
|
statePageLoadStates.toSpliced(index, 1, { loaded: true }),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
onError={(pageIndex) => {
|
||||||
|
setPageLoadStates((statePageLoadStates) =>
|
||||||
|
statePageLoadStates.toSpliced(pageIndex, 1, { loaded: false, error: true }),
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const BasePager = ({
|
|||||||
imageRefs,
|
imageRefs,
|
||||||
createPage,
|
createPage,
|
||||||
slots,
|
slots,
|
||||||
}: ReaderPagerProps & {
|
}: Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix'> & {
|
||||||
createPage: (
|
createPage: (
|
||||||
page: ReaderStatePages['pages'][number],
|
page: ReaderStatePages['pages'][number],
|
||||||
pagesIndex: number,
|
pagesIndex: number,
|
||||||
|
|||||||
@@ -37,7 +37,13 @@ const getPagePosition = (
|
|||||||
return isLtrReadingDirection ? 'right' : 'left';
|
return isLtrReadingDirection ? 'right' : 'left';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReaderDoublePagedPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
export const ReaderDoublePagedPager = ({
|
||||||
|
onLoad,
|
||||||
|
onError,
|
||||||
|
pageLoadStates,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
...props
|
||||||
|
}: ReaderPagerProps) => {
|
||||||
const { currentPageIndex, pages, totalPages } = props;
|
const { currentPageIndex, pages, totalPages } = props;
|
||||||
|
|
||||||
const { readingDirection } = ReaderService.useSettings();
|
const { readingDirection } = ReaderService.useSettings();
|
||||||
@@ -63,10 +69,12 @@ export const ReaderDoublePagedPager = ({ onLoad, ...props }: ReaderPagerProps) =
|
|||||||
{createReaderPage(
|
{createReaderPage(
|
||||||
page,
|
page,
|
||||||
() => onLoad?.(pagesIndex),
|
() => onLoad?.(pagesIndex),
|
||||||
|
() => onError?.(primary.index),
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
shouldDisplay && isPrimaryPage,
|
shouldDisplay && isPrimaryPage,
|
||||||
currentPage.primary.index,
|
currentPage.primary.index,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
pageLoadStates[primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
hasSecondaryPage
|
hasSecondaryPage
|
||||||
? getPagePosition('first', themeDirection, readingDirection.value)
|
? getPagePosition('first', themeDirection, readingDirection.value)
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -76,10 +84,12 @@ export const ReaderDoublePagedPager = ({ onLoad, ...props }: ReaderPagerProps) =
|
|||||||
createReaderPage(
|
createReaderPage(
|
||||||
{ ...page, primary: { ...page.secondary! } },
|
{ ...page, primary: { ...page.secondary! } },
|
||||||
() => onLoad?.(pagesIndex, false),
|
() => onLoad?.(pagesIndex, false),
|
||||||
|
() => onError?.(secondary.index),
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
shouldDisplay && isSecondaryPage,
|
shouldDisplay && isSecondaryPage,
|
||||||
currentSecondaryPageIndex,
|
currentSecondaryPageIndex,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
pageLoadStates[secondary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
getPagePosition('second', themeDirection, readingDirection.value),
|
getPagePosition('second', themeDirection, readingDirection.value),
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -13,7 +13,13 @@ import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
|||||||
import { ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
|
|
||||||
export const ReaderHorizontalPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
export const ReaderHorizontalPager = ({
|
||||||
|
onLoad,
|
||||||
|
onError,
|
||||||
|
pageLoadStates,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
...props
|
||||||
|
}: ReaderPagerProps) => {
|
||||||
const { currentPageIndex, totalPages } = props;
|
const { currentPageIndex, totalPages } = props;
|
||||||
|
|
||||||
const { pageGap, readingDirection } = ReaderService.useSettings();
|
const { pageGap, readingDirection } = ReaderService.useSettings();
|
||||||
@@ -28,10 +34,12 @@ export const ReaderHorizontalPager = ({ onLoad, ...props }: ReaderPagerProps) =>
|
|||||||
createReaderPage(
|
createReaderPage(
|
||||||
page,
|
page,
|
||||||
() => onLoad?.(pagesIndex),
|
() => onLoad?.(pagesIndex),
|
||||||
|
() => onError?.(page.primary.index),
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
true,
|
true,
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
setRef,
|
setRef,
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.ts
|
|||||||
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
|
|
||||||
export const ReaderPagedPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
export const ReaderPagedPager = ({
|
||||||
|
onLoad,
|
||||||
|
onError,
|
||||||
|
pageLoadStates,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
...props
|
||||||
|
}: ReaderPagerProps) => {
|
||||||
const { currentPageIndex, totalPages } = props;
|
const { currentPageIndex, totalPages } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -20,10 +26,12 @@ export const ReaderPagedPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
|||||||
createReaderPage(
|
createReaderPage(
|
||||||
page,
|
page,
|
||||||
() => onLoad?.(pagesIndex),
|
() => onLoad?.(pagesIndex),
|
||||||
|
() => onError?.(page.primary.index),
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
shouldDisplay && currentPageIndex === page.primary.index,
|
shouldDisplay && currentPageIndex === page.primary.index,
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
slots={{
|
slots={{
|
||||||
|
|||||||
@@ -11,7 +11,13 @@ import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.ts
|
|||||||
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
|
|
||||||
export const ReaderVerticalPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
export const ReaderVerticalPager = ({
|
||||||
|
onLoad,
|
||||||
|
onError,
|
||||||
|
pageLoadStates,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
...props
|
||||||
|
}: ReaderPagerProps) => {
|
||||||
const { currentPageIndex, totalPages } = props;
|
const { currentPageIndex, totalPages } = props;
|
||||||
|
|
||||||
const { pageGap } = ReaderService.useSettings();
|
const { pageGap } = ReaderService.useSettings();
|
||||||
@@ -23,10 +29,12 @@ export const ReaderVerticalPager = ({ onLoad, ...props }: ReaderPagerProps) => {
|
|||||||
createReaderPage(
|
createReaderPage(
|
||||||
page,
|
page,
|
||||||
() => onLoad?.(pagesIndex),
|
() => onLoad?.(pagesIndex),
|
||||||
|
() => onError?.(page.primary.index),
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
true,
|
true,
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
setRef,
|
setRef,
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export const ReaderStatePagesContext = createContext<ReaderStatePages>({
|
|||||||
setPages: () => undefined,
|
setPages: () => undefined,
|
||||||
transitionPageMode: ReaderTransitionPageMode.NONE,
|
transitionPageMode: ReaderTransitionPageMode.NONE,
|
||||||
setTransitionPageMode: () => undefined,
|
setTransitionPageMode: () => undefined,
|
||||||
|
retryFailedPagesKeyPrefix: '',
|
||||||
|
setRetryFailedPagesKeyPrefix: () => undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const userReaderStatePagesContext = () => useContext(ReaderStatePagesContext);
|
export const userReaderStatePagesContext = () => useContext(ReaderStatePagesContext);
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ export const ReaderStatePagesContextProvider = ({ children }: { children: ReactN
|
|||||||
const [transitionPageMode, setTransitionPageMode] = useState<TContext['transitionPageMode']>(
|
const [transitionPageMode, setTransitionPageMode] = useState<TContext['transitionPageMode']>(
|
||||||
ReaderTransitionPageMode.NONE,
|
ReaderTransitionPageMode.NONE,
|
||||||
);
|
);
|
||||||
|
const [retryFailedPagesKeyPrefix, setRetryFailedPagesKeyPrefix] =
|
||||||
|
useState<TContext['retryFailedPagesKeyPrefix']>('');
|
||||||
|
|
||||||
const value = useMemo(
|
const value = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@@ -40,8 +42,19 @@ export const ReaderStatePagesContextProvider = ({ children }: { children: ReactN
|
|||||||
setPages,
|
setPages,
|
||||||
transitionPageMode,
|
transitionPageMode,
|
||||||
setTransitionPageMode,
|
setTransitionPageMode,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
setRetryFailedPagesKeyPrefix,
|
||||||
}),
|
}),
|
||||||
[totalPages, pages, currentPageIndex, pageToScrollToIndex, pageUrls, pageLoadStates, transitionPageMode],
|
[
|
||||||
|
totalPages,
|
||||||
|
pages,
|
||||||
|
currentPageIndex,
|
||||||
|
pageToScrollToIndex,
|
||||||
|
pageUrls,
|
||||||
|
pageLoadStates,
|
||||||
|
transitionPageMode,
|
||||||
|
retryFailedPagesKeyPrefix,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return <ReaderStatePagesContext.Provider value={value}>{children}</ReaderStatePagesContext.Provider>;
|
return <ReaderStatePagesContext.Provider value={value}>{children}</ReaderStatePagesContext.Provider>;
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export const Reader = () => {
|
|||||||
setTotalPages(pagesPayload.chapter.pageCount);
|
setTotalPages(pagesPayload.chapter.pageCount);
|
||||||
setPages(createPagesData(pages));
|
setPages(createPagesData(pages));
|
||||||
setPageUrls(pages);
|
setPageUrls(pages);
|
||||||
setPageLoadStates(pages.map(() => false));
|
setPageLoadStates(pages.map(() => ({ loaded: false })));
|
||||||
setCurrentPageIndex(initialReaderPageIndex);
|
setCurrentPageIndex(initialReaderPageIndex);
|
||||||
setPageToScrollToIndex(initialReaderPageIndex);
|
setPageToScrollToIndex(initialReaderPageIndex);
|
||||||
} else {
|
} else {
|
||||||
@@ -156,7 +156,7 @@ export const Reader = () => {
|
|||||||
setTotalPages(0);
|
setTotalPages(0);
|
||||||
setPages([createPageData('', 0)]);
|
setPages([createPageData('', 0)]);
|
||||||
setPageUrls([]);
|
setPageUrls([]);
|
||||||
setPageLoadStates([]);
|
setPageLoadStates([{ loaded: false }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransitionPageMode(ReaderTransitionPageMode.NONE);
|
setTransitionPageMode(ReaderTransitionPageMode.NONE);
|
||||||
|
|||||||
@@ -209,9 +209,18 @@ export enum ReaderHotkey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ReaderPagerProps
|
export interface ReaderPagerProps
|
||||||
extends Pick<ReaderStatePages, 'currentPageIndex' | 'pages' | 'totalPages' | 'transitionPageMode'> {
|
extends Pick<
|
||||||
|
ReaderStatePages,
|
||||||
|
| 'currentPageIndex'
|
||||||
|
| 'pages'
|
||||||
|
| 'totalPages'
|
||||||
|
| 'transitionPageMode'
|
||||||
|
| 'pageLoadStates'
|
||||||
|
| 'retryFailedPagesKeyPrefix'
|
||||||
|
> {
|
||||||
imageRefs: MutableRefObject<(HTMLElement | null)[]>;
|
imageRefs: MutableRefObject<(HTMLElement | null)[]>;
|
||||||
onLoad?: (pagesIndex: number, isPrimary?: boolean) => void;
|
onLoad?: (pagesIndex: number, isPrimary?: boolean) => void;
|
||||||
|
onError?: (pageIndex: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PageInViewportType {
|
export enum PageInViewportType {
|
||||||
|
|||||||
@@ -31,12 +31,14 @@ export interface ReaderStatePages {
|
|||||||
setPageToScrollToIndex: React.Dispatch<React.SetStateAction<number>>;
|
setPageToScrollToIndex: React.Dispatch<React.SetStateAction<number>>;
|
||||||
pageUrls: string[];
|
pageUrls: string[];
|
||||||
setPageUrls: React.Dispatch<React.SetStateAction<string[]>>;
|
setPageUrls: React.Dispatch<React.SetStateAction<string[]>>;
|
||||||
pageLoadStates: boolean[];
|
pageLoadStates: { loaded: boolean; error?: boolean }[];
|
||||||
setPageLoadStates: React.Dispatch<React.SetStateAction<boolean[]>>;
|
setPageLoadStates: React.Dispatch<React.SetStateAction<{ loaded: boolean; error?: boolean }[]>>;
|
||||||
pages: PageData[];
|
pages: PageData[];
|
||||||
setPages: React.Dispatch<React.SetStateAction<PageData[]>>;
|
setPages: React.Dispatch<React.SetStateAction<PageData[]>>;
|
||||||
transitionPageMode: ReaderTransitionPageMode;
|
transitionPageMode: ReaderTransitionPageMode;
|
||||||
setTransitionPageMode: React.Dispatch<React.SetStateAction<ReaderTransitionPageMode>>;
|
setTransitionPageMode: React.Dispatch<React.SetStateAction<ReaderTransitionPageMode>>;
|
||||||
|
retryFailedPagesKeyPrefix: string;
|
||||||
|
setRetryFailedPagesKeyPrefix: React.Dispatch<React.SetStateAction<string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReaderProgressBarProps
|
export interface ReaderProgressBarProps
|
||||||
|
|||||||
@@ -202,10 +202,12 @@ const getPageDownloadPriority = (currentPageIndex: number, pageIndex: number, to
|
|||||||
export const createReaderPage = (
|
export const createReaderPage = (
|
||||||
{ primary: { index, alt, url } }: ReaderStatePages['pages'][number],
|
{ primary: { index, alt, url } }: ReaderStatePages['pages'][number],
|
||||||
onLoad: () => void,
|
onLoad: () => void,
|
||||||
|
onError: (() => void) | undefined,
|
||||||
shouldLoad: boolean,
|
shouldLoad: boolean,
|
||||||
display: boolean,
|
display: boolean,
|
||||||
currentPageIndex: number,
|
currentPageIndex: number,
|
||||||
totalPages: number,
|
totalPages: number,
|
||||||
|
retryKeyPrefix?: string,
|
||||||
position?: 'left' | 'right',
|
position?: 'left' | 'right',
|
||||||
isDoublePage?: boolean,
|
isDoublePage?: boolean,
|
||||||
setRef?: (ref: HTMLElement | null) => void,
|
setRef?: (ref: HTMLElement | null) => void,
|
||||||
@@ -219,8 +221,10 @@ export const createReaderPage = (
|
|||||||
priority={getPageDownloadPriority(currentPageIndex, index, totalPages)}
|
priority={getPageDownloadPriority(currentPageIndex, index, totalPages)}
|
||||||
position={position}
|
position={position}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
|
onError={onError}
|
||||||
doublePage={isDoublePage}
|
doublePage={isDoublePage}
|
||||||
shouldLoad={shouldLoad}
|
shouldLoad={shouldLoad}
|
||||||
|
retryKeyPrefix={retryKeyPrefix}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user