/* * 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 Typography from '@mui/material/Typography'; import Stack from '@mui/material/Stack'; import Button from '@mui/material/Button'; import { Link } from 'react-router-dom'; import { ComponentProps, memo, useMemo } from 'react'; import { alpha, useTheme } from '@mui/material/styles'; import { useLingui } from '@lingui/react/macro'; import { IReaderSettings, ReaderTransitionPageMode, ReadingMode } from '@/features/reader/Reader.types.ts'; import { isTransitionPageVisible } from '@/features/reader/viewer/pager/ReaderPager.utils.tsx'; import { useBackButton } from '@/base/hooks/useBackButton.ts'; import { applyStyles } from '@/base/utils/ApplyStyles.ts'; import { isContinuousReadingMode, isContinuousVerticalReadingMode, } from '@/features/reader/settings/ReaderSettings.utils.tsx'; import { useNavBarContext } from '@/features/navigation-bar/NavbarContext.tsx'; import { AppRoutes } from '@/base/AppRoute.constants.ts'; import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { getValueFromObject, noOp } from '@/lib/HelperFunctions.ts'; import { READER_BACKGROUND_TO_COLOR } from '@/features/reader/settings/ReaderSettings.constants.tsx'; import { ChapterType } from '@/lib/graphql/generated/graphql.ts'; import { ChapterIdInfo } from '@/features/chapter/Chapter.types.ts'; import { useReaderChaptersStore, useReaderPagesStore, useReaderScrollbarStore, useReaderSettingsStore, useReaderStore, } from '@/features/reader/stores/ReaderStore.ts'; const ChapterInfo = ({ title, name, scanlator, backgroundColor, }: { title: string; name?: ChapterType['name']; scanlator?: ChapterType['scanlator']; backgroundColor: IReaderSettings['backgroundColor']; }) => { const theme = useTheme(); const contrastText = theme.palette.getContrastText( getValueFromObject(theme.palette, READER_BACKGROUND_TO_COLOR[backgroundColor]), ); const disabledText = alpha(contrastText, 0.5); if (!name) { return null; } return ( {title} {name} {scanlator && ( {scanlator} )} ); }; const BaseReaderTransitionPage = ({ type, currentChapterName, currentChapterScanlator, previousChapterName, previousChapterScanlator, nextChapterName, nextChapterScanlator, readerNavBarWidth, handleBack, }: Pick & { // gets used in the "source props creators" of the "withPropsFrom" call // eslint-disable-next-line react/no-unused-prop-types chapterId: ChapterIdInfo['id']; currentChapterName?: ChapterType['name']; currentChapterScanlator?: ChapterType['scanlator']; previousChapterName?: ChapterType['name']; previousChapterScanlator?: ChapterType['scanlator']; nextChapterName?: ChapterType['name']; nextChapterScanlator?: ChapterType['scanlator']; type: Exclude; handleBack: () => void; }) => { const { t } = useLingui(); const manga = useReaderStore((state) => state.manga); const scrollbar = useReaderScrollbarStore((state) => state); const transitionPageMode = useReaderPagesStore((state) => state.transitionPageMode); const { readingMode, backgroundColor, shouldShowTransitionPage } = useReaderSettingsStore((state) => ({ readingMode: state.readingMode.value, backgroundColor: state.backgroundColor, shouldShowTransitionPage: state.shouldShowTransitionPage, })); const isPreviousType = type === ReaderTransitionPageMode.PREVIOUS; const isNextType = type === ReaderTransitionPageMode.NEXT; const isFirstChapter = !!currentChapterName && !previousChapterName; const isLastChapter = !!currentChapterName && !nextChapterName; const forceShowFirstChapterPreviousTransitionPage = isFirstChapter && type === ReaderTransitionPageMode.PREVIOUS; const forceShowLastChapterNextTransitionPage = isLastChapter && type === ReaderTransitionPageMode.NEXT; const forceShowTransitionPage = forceShowFirstChapterPreviousTransitionPage || forceShowLastChapterNextTransitionPage; if (!shouldShowTransitionPage && !forceShowTransitionPage) { return null; } if (!isTransitionPageVisible(type, transitionPageMode, readingMode)) { return null; } return ( // spacing = added padding left + right `calc(100vw - ${scrollbar.ySize}px - ${readerNavBarWidth}px - ${theme.spacing(2)})`, maxHeight: `calc(100vh - ${scrollbar.xSize}px)`, width: 'max-content', p: 1, }} > {isPreviousType && isFirstChapter && ( {t`There is no previous chapter`} )} {isPreviousType && !isFirstChapter && ( )} {!!currentChapterName && ( )} {isNextType && !isLastChapter && ( )} {isNextType && isLastChapter && {t`There is no next chapter`}} {((isPreviousType && isFirstChapter) || (isNextType && isLastChapter)) && ( )} ); }; export const ReaderTransitionPage = withPropsFrom( memo(BaseReaderTransitionPage) as typeof BaseReaderTransitionPage, [ ({ chapterId }: Pick, 'chapterId'>) => { const chapters = useReaderChaptersStore((state) => state.chapters); const currentChapterIndex = useMemo( () => chapters.findIndex((chapter) => chapter.id === chapterId), [chapterId, chapters], ); const currentChapter = chapters[currentChapterIndex]; // chapters are sorted from latest to oldest const previousChapter = useMemo(() => chapters[currentChapterIndex + 1], [currentChapterIndex, chapters]); const nextChapter = useMemo(() => chapters[currentChapterIndex - 1], [currentChapterIndex, chapters]); return { currentChapterName: currentChapter?.name, currentChapterScanlator: currentChapter?.scanlator, previousChapterName: previousChapter?.name, previousChapterScanlator: previousChapter?.name, nextChapterName: nextChapter?.name, nextChapterScanlator: nextChapter?.scanlator, }; }, useNavBarContext, ({ chapterId, type }: Pick, 'chapterId' | 'type'>) => { const handleBack = useBackButton(); const chapters = useReaderChaptersStore((state) => state.chapters); const currentChapterIndex = useMemo( () => chapters.findIndex((chapter) => chapter.id === chapterId), [chapterId, chapters], ); // chapters are sorted from latest to oldest const isLastChapter = currentChapterIndex === 0; const isFirstChapter = currentChapterIndex === chapters.length - 1; const handleBackFirstChapter = type === ReaderTransitionPageMode.PREVIOUS && isFirstChapter; const handleBackLastChapter = type === ReaderTransitionPageMode.NEXT && isLastChapter; const needsToHandleBack = handleBackFirstChapter || handleBackLastChapter; return { handleBack: needsToHandleBack ? handleBack : noOp, }; }, ], [ 'currentChapterName', 'currentChapterScanlator', 'previousChapterName', 'previousChapterScanlator', 'nextChapterName', 'nextChapterScanlator', 'readerNavBarWidth', 'handleBack', ], );