/* * Copyright (C) Contributors to the Suwayomi project * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { BoxProps } from '@mui/material/Box'; import { memo, ReactNode, useCallback, useMemo, useRef, ComponentProps } from 'react'; import ClickAwayListener from '@mui/material/ClickAwayListener'; import { TypographyProps } from '@mui/material/Typography'; import { StackProps } from '@mui/material/Stack'; import { ReaderProgressBarProps, TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts'; import { ReaderProgressBarPageNumber } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarPageNumber.tsx'; import { ReaderProgressBarContainer } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarContainer.tsx'; import { ReaderProgressBarRoot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarRoot.tsx'; import { ReaderProgressBarSlotsContainer } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlotsContainer.tsx'; import { ProgressBarHighlightReadPages } from '@/modules/reader/components/overlay/progress-bar/ProgressBarHighlightReadPages.tsx'; import { ReaderProgressBarCurrentPageSlot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarCurrentPageSlot.tsx'; import { getNextIndexFromPage, getPage, getPageForMousePos, getProgressBarPositionInfo, useHandleProgressDragging, } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx'; import { getOptionForDirection as getOptionForDirectionImpl } from '@/modules/theme/services/ThemeCreator.ts'; import { ReaderProgressBarSlotsActionArea } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlotsActionArea.tsx'; import { ReaderService } from '@/modules/reader/services/ReaderService.ts'; import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts'; import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx'; import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx'; import { ReaderProgressBarSlotWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlotWrapper.tsx'; const BaseReaderProgressBar = ({ totalPages, pages, pageLoadStates, currentPageIndex, slotProps, slots, createProgressBarSlot, progressBarPosition, isDragging, setIsDragging, openPage, direction, }: ReaderProgressBarProps & Pick & Pick, 'createProgressBarSlot'> & { slotProps?: { container?: StackProps; progressBarRoot?: StackProps; progressBarSlotsActionArea?: StackProps; progressBarSlotsContainer?: StackProps; progressBarSlot?: BoxProps; progressBarReadPages?: BoxProps; progressBarCurrentPageSlot?: BoxProps; progressBarPageTexts?: { base?: TypographyProps; current?: TypographyProps; total?: TypographyProps; }; }; slots?: { progressBarCurrentPage?: ReactNode; }; openPage: ReturnType; direction: ReturnType; }) => { const progressBarRef = useRef(null); const currentPagesIndex = useMemo(() => getPage(currentPageIndex, pages).pagesIndex, [currentPageIndex, pages]); const isHorizontalPosition = getProgressBarPositionInfo(progressBarPosition).isHorizontal; const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]); const getOptionForDirection = useCallback( (...args: Parameters>) => getOptionForDirectionImpl(args[0], args[1], direction), [direction], ); useHandleProgressDragging( openPage, progressBarRef, isDragging, currentPage, pages, progressBarPosition, getOptionForDirection, ); return ( openPage('previous', 'ltr', false)} > {currentPage.name} setIsDragging(false)}> setIsDragging(false)} onTouchStart={(event) => { if (!progressBarRef.current) { return; } openPage( getNextIndexFromPage( getPageForMousePos( event.touches[0], progressBarRef.current.getBoundingClientRect(), pages, isHorizontalPosition, getOptionForDirection, ), ), undefined, false, ); setIsDragging(true); }} onMouseUp={() => setIsDragging(false)} onMouseDown={(event) => { if (!progressBarRef.current) { return; } openPage( getNextIndexFromPage( getPageForMousePos( event, progressBarRef.current.getBoundingClientRect(), pages, isHorizontalPosition, getOptionForDirection, ), ), undefined, false, ); setIsDragging(true); }} > {pages.map((page, pagesIndex) => ( currentPagesIndex} totalPages={pages.length} primaryPageLoadState={pageLoadStates[page.primary.index].loaded} secondaryPageLoadState={ page.secondary ? pageLoadStates[page.secondary.index].loaded : undefined } createProgressBarSlot={createProgressBarSlot} /> ))} {slots?.progressBarCurrentPage} openPage('next', 'ltr', false)} > {totalPages} ); }; export const ReaderProgressBar = withPropsFrom( memo(BaseReaderProgressBar), [ useReaderProgressBarContext, () => ({ openPage: ReaderControls.useOpenPage() }), () => ({ direction: ReaderService.useGetThemeDirection(), }), ], ['isDragging', 'setIsDragging', 'openPage', 'direction'], );