diff --git a/src/modules/reader/components/viewer/ReaderPage.tsx b/src/modules/reader/components/viewer/ReaderPage.tsx index 8c097870..339da444 100644 --- a/src/modules/reader/components/viewer/ReaderPage.tsx +++ b/src/modules/reader/components/viewer/ReaderPage.tsx @@ -6,10 +6,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { ComponentProps, ForwardedRef, forwardRef, memo } from 'react'; +import { ComponentProps, memo, useCallback } from 'react'; import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx'; import { ReaderService } from '@/modules/reader/services/ReaderService.ts'; -import { IReaderSettings, ReaderCustomFilter, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts'; +import { + IReaderSettings, + ReaderCustomFilter, + ReaderPagerProps, + TReaderScrollbarContext, +} from '@/modules/reader/types/Reader.types.ts'; import { getImageMarginStyling, getImagePlaceholderStyling, @@ -49,97 +54,100 @@ const getCustomFilterString = (customFilter: ReaderCustomFilter): string => }) .join(' '); -const BaseReaderPage = forwardRef( - ( - { - display, - doublePage = false, - position, - marginTop, - shouldLoad, - readingMode, - customFilter, - pageScaleMode, - shouldStretchPage, - readerWidth, - scrollbarXSize, - scrollbarYSize, - ...props - }: Omit, 'ref' | 'spinnerStyle' | 'imgStyle'> & - Pick< - IReaderSettings, - 'readingMode' | 'customFilter' | 'pageScaleMode' | 'shouldStretchPage' | 'readerWidth' - > & - Pick & { - display: boolean; - doublePage?: boolean; - position?: 'left' | 'right'; - marginTop?: number; - }, - ref: ForwardedRef, - ) => { - const isTabletWidth = MediaQuery.useIsTabletWidth(); +const BaseReaderPage = ({ + pageIndex, + pagesIndex, + isPrimaryPage, + display, + doublePage = false, + position, + marginTop, + shouldLoad, + readingMode, + customFilter, + pageScaleMode, + shouldStretchPage, + readerWidth, + scrollbarXSize, + scrollbarYSize, + onLoad, + onError, + setRef, + ...props +}: Omit, 'ref' | 'spinnerStyle' | 'imgStyle' | 'onLoad' | 'onError'> & + Pick & + Pick & { + pageIndex: number; + pagesIndex: number; + isPrimaryPage: boolean; + display: boolean; + doublePage?: boolean; + position?: 'left' | 'right'; + marginTop?: number; + onLoad: ReaderPagerProps['onLoad']; + onError: ReaderPagerProps['onError']; + setRef?: (pagesIndex: number, ref: HTMLElement | null) => void; + }) => { + const isTabletWidth = MediaQuery.useIsTabletWidth(); - if (!display && !shouldLoad) { - return null; - } + const handleLoad = useCallback(() => onLoad?.(pagesIndex, isPrimaryPage), [onLoad, pagesIndex, isPrimaryPage]); + const handleError = useCallback(() => onError?.(pageIndex), [onError, pageIndex]); + const updateRef = useCallback((element: HTMLElement | null) => setRef?.(pagesIndex, element), [pagesIndex, setRef]); - return ( - - ); - }, -); + if (!display && !shouldLoad) { + return null; + } + + return ( + + ); +}; export const ReaderPage = withPropsFrom( memo(BaseReaderPage), diff --git a/src/modules/reader/components/viewer/ReaderViewer.tsx b/src/modules/reader/components/viewer/ReaderViewer.tsx index 3c1d9e14..6b649464 100644 --- a/src/modules/reader/components/viewer/ReaderViewer.tsx +++ b/src/modules/reader/components/viewer/ReaderViewer.tsx @@ -10,6 +10,7 @@ import { ForwardedRef, forwardRef, memo, + useCallback, useEffect, useImperativeHandle, useLayoutEffect, @@ -162,6 +163,30 @@ const BaseReaderViewer = forwardRef( const inViewportType = READING_MODE_TO_IN_VIEWPORT_TYPE[readingMode]; + const onLoad = useCallback( + (pagesIndex: number, isPrimary: boolean = true) => { + const page = actualPages[pagesIndex]; + const { index, url } = isPrimary ? page.primary : page.secondary!; + + if (readingMode === ReadingMode.DOUBLE_PAGE) { + const img = new Image(); + img.onload = () => { + setPagesToSpreadState((prevState) => prevState.toSpliced(index, 1, isSpreadPage(img))); + }; + img.src = url; + } + + setPageLoadStates((statePageLoadStates) => statePageLoadStates.toSpliced(index, 1, { loaded: true })); + }, + [actualPages, readingMode], + ); + + const onError = useCallback((pageIndex: number) => { + setPageLoadStates((statePageLoadStates) => + statePageLoadStates.toSpliced(pageIndex, 1, { loaded: false, error: true }), + ); + }, []); + // reset spread state useLayoutEffect(() => { setPagesToSpreadState(Array(totalPages).fill(false)); @@ -310,27 +335,8 @@ const BaseReaderViewer = forwardRef( pageLoadStates={pageLoadStates} retryFailedPagesKeyPrefix={retryFailedPagesKeyPrefix} imageRefs={imageRefs} - onLoad={(pagesIndex, isPrimary = true) => { - const page = actualPages[pagesIndex]; - const { index, url } = isPrimary ? page.primary : page.secondary!; - - if (readingMode === ReadingMode.DOUBLE_PAGE) { - const img = new Image(); - img.onload = () => { - setPagesToSpreadState((prevState) => prevState.toSpliced(index, 1, isSpreadPage(img))); - }; - img.src = url; - } - - setPageLoadStates((statePageLoadStates) => - statePageLoadStates.toSpliced(index, 1, { loaded: true }), - ); - }} - onError={(pageIndex) => { - setPageLoadStates((statePageLoadStates) => - statePageLoadStates.toSpliced(pageIndex, 1, { loaded: false, error: true }), - ); - }} + onLoad={onLoad} + onError={onError} /> ); diff --git a/src/modules/reader/components/viewer/pager/BasePager.tsx b/src/modules/reader/components/viewer/pager/BasePager.tsx index f1051737..137cabe6 100644 --- a/src/modules/reader/components/viewer/pager/BasePager.tsx +++ b/src/modules/reader/components/viewer/pager/BasePager.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { memo, ReactNode, useEffect, useMemo, useRef } from 'react'; +import { memo, ReactNode, useCallback, useEffect, useMemo, useRef } from 'react'; import Box, { BoxProps } from '@mui/material/Box'; import { ReaderService } from '@/modules/reader/services/ReaderService.ts'; import { getImageWidthStyling, getPageIndexesToLoad } from '@/modules/reader/utils/ReaderPager.utils.tsx'; @@ -37,7 +37,7 @@ const BaseBasePager = ({ pagesIndex: number, shouldLoad: boolean, shouldDisplay: boolean, - setRef: (element: HTMLElement | null) => void, + setRef: (pagesIndex: number, element: HTMLElement | null) => void, ) => ReactNode; slots?: { boxProps?: BoxProps }; }) => { @@ -50,6 +50,14 @@ const BaseBasePager = ({ previousCurrentPageIndex.current = currentPageIndex; }, [pagesIndexesToRender]); + const setRef = useCallback( + (pagesIndex: number, element: HTMLElement | null) => { + // eslint-disable-next-line no-param-reassign + imageRefs.current[pagesIndex] = element; + }, + [imageRefs], + ); + return ( { - // eslint-disable-next-line no-param-reassign - imageRefs.current[pagesIndex] = element; - }, + setRef, ), )} {createReaderPage( page, - () => onLoad?.(pagesIndex), - () => onError?.(primary.index), + pagesIndex, + true, + onLoad, + onError, shouldLoad, shouldDisplay && isPrimaryPage, currentPage.primary.index, @@ -82,8 +84,10 @@ const BaseReaderDoublePagedPager = ({ {hasSecondaryPage && createReaderPage( { ...page, primary: { ...page.secondary! } }, - () => onLoad?.(pagesIndex, false), - () => onError?.(secondary.index), + pagesIndex, + false, + onLoad, + onError, shouldLoad, shouldDisplay && isSecondaryPage, currentSecondaryPageIndex, diff --git a/src/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx b/src/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx index 3aaa7f93..151f6705 100644 --- a/src/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx +++ b/src/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx @@ -36,8 +36,10 @@ const BaseReaderHorizontalPager = ({ createPage={(page, pagesIndex, shouldLoad, _, setRef) => createReaderPage( page, - () => onLoad?.(pagesIndex), - () => onError?.(page.primary.index), + pagesIndex, + true, + onLoad, + onError, shouldLoad, true, currentPageIndex, diff --git a/src/modules/reader/components/viewer/pager/ReaderPagedPager.tsx b/src/modules/reader/components/viewer/pager/ReaderPagedPager.tsx index 995cc0dd..9480681b 100644 --- a/src/modules/reader/components/viewer/pager/ReaderPagedPager.tsx +++ b/src/modules/reader/components/viewer/pager/ReaderPagedPager.tsx @@ -26,8 +26,10 @@ const BaseReaderPagedPager = ({ createPage={(page, pagesIndex, shouldLoad, shouldDisplay) => createReaderPage( page, - () => onLoad?.(pagesIndex), - () => onError?.(page.primary.index), + pagesIndex, + true, + onLoad, + onError, shouldLoad, shouldDisplay && currentPageIndex === page.primary.index, currentPageIndex, diff --git a/src/modules/reader/components/viewer/pager/ReaderVerticalPager.tsx b/src/modules/reader/components/viewer/pager/ReaderVerticalPager.tsx index 8c200a7c..5f5f9608 100644 --- a/src/modules/reader/components/viewer/pager/ReaderVerticalPager.tsx +++ b/src/modules/reader/components/viewer/pager/ReaderVerticalPager.tsx @@ -33,8 +33,10 @@ const BaseReaderVerticalPager = ({ createPage={(page, pagesIndex, shouldLoad, _, setRef) => createReaderPage( page, - () => onLoad?.(pagesIndex), - () => onError?.(page.primary.index), + pagesIndex, + true, + onLoad, + onError, shouldLoad, true, currentPageIndex, diff --git a/src/modules/reader/utils/ReaderPager.utils.tsx b/src/modules/reader/utils/ReaderPager.utils.tsx index a6adf15e..3fc2c049 100644 --- a/src/modules/reader/utils/ReaderPager.utils.tsx +++ b/src/modules/reader/utils/ReaderPager.utils.tsx @@ -7,7 +7,7 @@ */ import { Direction, Theme } from '@mui/material/styles'; -import { ReactNode } from 'react'; +import { ComponentProps, ReactNode } from 'react'; import { IReaderSettings, PageInViewportType, @@ -227,7 +227,16 @@ export const createPageData = (url: string, index: number): ReaderStatePages['pa export const createPagesData = (pageUrls: string[]): ReaderStatePages['pages'] => pageUrls.map(createPageData); -const getPageDownloadPriority = (currentPageIndex: number, pageIndex: number, totalPages: number): number => { +const getPageDownloadPriority = ( + currentPageIndex: number, + pageIndex: number, + totalPages: number, + shouldLoad: boolean, +): number => { + if (!shouldLoad) { + return Number.MAX_SAFE_INTEGER; + } + const distanceToCurrentPage = Math.abs(pageIndex - currentPageIndex); const priorityBasedOnDistance = totalPages - distanceToCurrentPage; @@ -241,8 +250,10 @@ const getPageDownloadPriority = (currentPageIndex: number, pageIndex: number, to export const createReaderPage = ( { primary: { index, alt, url } }: ReaderStatePages['pages'][number], - onLoad: () => void, - onError: (() => void) | undefined, + pagesIndex: number, + isPrimaryPage: boolean, + onLoad: ComponentProps['onLoad'], + onError: ComponentProps['onError'], shouldLoad: boolean, display: boolean, currentPageIndex: number, @@ -251,15 +262,18 @@ export const createReaderPage = ( position?: 'left' | 'right', isDoublePage?: boolean, marginTop?: number, - setRef?: (ref: HTMLElement | null) => void, + setRef?: (pagesIndex: number, ref: HTMLElement | null) => void, ): ReactNode => (