Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding page loading with Double Page Mode. #480

Merged
merged 5 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 36 additions & 7 deletions src/components/reader/DoublePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,39 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { forwardRef } from 'react';
import { Box, styled } from '@mui/material';
import { CSSProperties, forwardRef, useRef } from 'react';
import { Box, SxProps, Theme } from '@mui/material';
import { IReaderSettings } from '@/typings';
import { SpinnerImage } from '@/components/util/SpinnerImage';

const Image = styled('img')({
const imgStyles: CSSProperties = {
display: 'block',
marginBottom: 0,
width: 'auto',
minHeight: '99vh',
height: 'auto',
maxHeight: '99vh',
objectFit: 'contain',
});
};

const spinnerStyle: SxProps<Theme> = {
...imgStyles,
width: 'calc((100vw - 300px) * 0.5)',
backgroundColor: '#525252',
};

interface IProps {
index: number;
image1src: string;
image2src: string;
onImageLoad?: () => void;
settings: IReaderSettings;
}

export const DoublePage = forwardRef((props: IProps, ref: any) => {
const { image1src, image2src, index, settings } = props;
const { image1src, image2src, index, onImageLoad, settings } = props;

const imgRef = useRef<HTMLImageElement>(null);

return (
<Box
Expand All @@ -42,8 +53,26 @@ export const DoublePage = forwardRef((props: IProps, ref: any) => {
overflowX: 'scroll',
}}
>
<Image src={image1src} alt={`Page #${index}`} />
<Image src={image2src} alt={`Page #${index + 1}`} />
<SpinnerImage
src={image1src}
onImageLoad={onImageLoad}
alt={`Page #${index}`}
imgRef={imgRef}
spinnerStyle={spinnerStyle}
imgStyle={imgStyles}
/>
<SpinnerImage
src={image2src}
onImageLoad={onImageLoad}
alt={`Page #${index + 1}`}
imgRef={imgRef}
spinnerStyle={{
...spinnerStyle,
width: 'calc((100vw - 300px - 5px) * 0.5)',
marginLeft: '5px',
}}
imgStyle={imgStyles}
/>
</Box>
);
});
98 changes: 38 additions & 60 deletions src/components/reader/pager/DoublePagedPager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { Box } from '@mui/material';
import { createRoot } from 'react-dom/client';
import { IReaderProps } from '@/typings';
import { Page } from '@/components/reader/Page';
import { DoublePage } from '@/components/reader/DoublePage';
Expand All @@ -35,56 +34,30 @@ export function DoublePagedPager(props: IReaderProps) {
const selfRef = useRef<HTMLDivElement>(null);
const pagesRef = useRef<HTMLImageElement[]>([]);

const pagesDisplayed = useRef<number>(0);
const pageLoaded = useRef<boolean[]>(Array(pages.length).fill(false));
const spreadPage = useRef<boolean[]>(Array(pages.length).fill(false));
const [pagesToSpreadState, setPagesToSpreadState] = useState(Array(pages.length).fill(false));
const [pagesLoadState, setPagesLoadState] = useState<boolean[]>(Array(pages.length).fill(false));

function setPagesToDisplay() {
pagesDisplayed.current = 0;
function getPagesToDisplay(): number {
let pagesToDisplay = 1; // has to be at least one so skipping forward while pages are still loading is possible
if (curPage < pages.length && pagesRef.current[curPage]) {
if (pageLoaded.current[curPage]) {
pagesDisplayed.current = 1;
if (spreadPage.current[curPage]) return;
if (pagesLoadState[curPage]) {
pagesToDisplay = 1;
if (pagesToSpreadState[curPage]) return pagesToDisplay;
}
}
if (curPage + 1 < pages.length && pagesRef.current[curPage + 1]) {
if (pageLoaded.current[curPage + 1]) {
if (isSinglePage(curPage, spreadPage.current, settings.offsetFirstPage)) return;
pagesDisplayed.current = 2;
if (pagesLoadState[curPage + 1]) {
if (isSinglePage(curPage, pagesToSpreadState, settings.offsetFirstPage)) return pagesToDisplay;
pagesToDisplay = 2;
}
}
}

function displayPages() {
const container = document.getElementById('display');
const root = createRoot(container!);

if (pagesDisplayed.current === 2) {
root.render(
<DoublePage
key={curPage}
index={curPage}
image1src={pages[curPage].src}
image2src={pages[curPage + 1].src}
settings={settings}
/>,
);
} else {
root.render(
<Page
key={curPage}
index={curPage}
src={pagesDisplayed.current === 1 ? pages[curPage].src : ''}
onImageLoad={() => {}}
settings={settings}
/>,
);
}
return pagesToDisplay;
}

function pagesToGoBack() {
// If previous page is single page, go only one page pack
if (isSinglePage(curPage - 2, spreadPage.current, settings.offsetFirstPage)) {
if (isSinglePage(curPage - 2, pagesToSpreadState, settings.offsetFirstPage)) {
return 1;
}

Expand All @@ -94,7 +67,7 @@ export function DoublePagedPager(props: IReaderProps) {

function nextPage() {
if (curPage < pages.length - 1) {
const nextCurPage = curPage + pagesDisplayed.current;
const nextCurPage = curPage + getPagesToDisplay();
setCurPage(nextCurPage >= pages.length ? pages.length - 1 : nextCurPage);
} else if (settings.loadNextOnEnding) {
nextChapter();
Expand Down Expand Up @@ -153,45 +126,32 @@ export function DoublePagedPager(props: IReaderProps) {

function handleImageLoad(index: number) {
return () => {
pageLoaded.current[index] = true;
setPagesLoadState((prevState) => prevState.toSpliced(index, 1, true));
const image = pagesRef.current[index];
spreadPage.current[index] = isSpreadPage(image);
setPagesToSpreadState((prevState) => prevState.toSpliced(index, 1, isSpreadPage(image)));
};
}

useEffect(() => {
const retryDisplay = setInterval(() => {
const isLastPage = curPage === pages.length - 1;
if (
(!isLastPage && pageLoaded.current[curPage] && pageLoaded.current[curPage + 1]) ||
pageLoaded.current[curPage]
) {
setPagesToDisplay();
displayPages();
clearInterval(retryDisplay);
}
}, 50);

document.addEventListener('keydown', keyboardControl);
selfRef.current?.addEventListener('click', clickControl);

return () => {
clearInterval(retryDisplay);
document.removeEventListener('keydown', keyboardControl);
selfRef.current?.removeEventListener('click', clickControl);
};
}, [selfRef, curPage, settings.readerType, prevChapter, nextChapter]);
}, [selfRef, curPage, settings.readerType, prevChapter, nextChapter, pagesLoadState, pagesToSpreadState]);

useEffect(() => {
setCurPage(initialPage);
}, [initialPage]);

useEffect(() => {
if (settings.offsetFirstPage) {
if (pagesDisplayed.current === 2) {
if (getPagesToDisplay() === 2) {
setCurPage(curPage + 1);
}
} else if (curPage > 0 && !isSinglePage(curPage - 1, spreadPage.current, settings.offsetFirstPage)) {
} else if (curPage > 0 && !isSinglePage(curPage - 1, pagesToSpreadState, settings.offsetFirstPage)) {
setCurPage(curPage - 1);
}
}, [settings.offsetFirstPage]);
Expand Down Expand Up @@ -222,7 +182,25 @@ export function DoublePagedPager(props: IReaderProps) {
height: 'auto',
overflowX: 'scroll',
}}
/>
>
{getPagesToDisplay() === 2 ? (
<DoublePage
key={curPage}
index={curPage}
image1src={pages[curPage].src}
image2src={pages[curPage + 1].src}
settings={settings}
/>
) : (
<Page
key={curPage}
index={curPage}
src={pages[curPage].src}
onImageLoad={() => {}}
settings={settings}
/>
)}
</Box>
</Box>
);
}
Loading