Use HOC for reader context usage
This commit is contained in:
4
src/UtilTypes.d.ts
vendored
4
src/UtilTypes.d.ts
vendored
@@ -33,3 +33,7 @@ type TupleUnion<U extends string | number | symbol, R extends any[] = []> = {
|
|||||||
type TransformRecordToWithDefaultFlag<T extends Record<string, any>> = {
|
type TransformRecordToWithDefaultFlag<T extends Record<string, any>> = {
|
||||||
[K in keyof T]: { value: T[K]; isDefault: boolean };
|
[K in keyof T]: { value: T[K]; isDefault: boolean };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type MergeObjectsArray<T extends object[]> = T extends [infer F, ...infer R]
|
||||||
|
? F & MergeObjects<R extends object[] ? R : []>
|
||||||
|
: {};
|
||||||
|
|||||||
32
src/modules/core/hoc/withPropsFrom.tsx
Normal file
32
src/modules/core/hoc/withPropsFrom.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 { ComponentType, forwardRef } from 'react';
|
||||||
|
|
||||||
|
type PropsSourceCreator<T> = () => T;
|
||||||
|
|
||||||
|
export const withPropsFrom = <
|
||||||
|
ComponentProps extends Record<string, any>,
|
||||||
|
SourceProps extends Record<string, any>[],
|
||||||
|
SourcePropKeys extends keyof (ComponentProps | MergeObjectsArray<SourceProps>),
|
||||||
|
>(
|
||||||
|
Component: ComponentType<ComponentProps>,
|
||||||
|
propsSources: { [K in keyof SourceProps]: PropsSourceCreator<SourceProps[K]> },
|
||||||
|
sourcePropKeys: SourcePropKeys[],
|
||||||
|
) =>
|
||||||
|
forwardRef<HTMLElement, Omit<ComponentProps, SourcePropKeys>>((props, ref) => {
|
||||||
|
const sourceProps = propsSources.reduce((acc, propsSource) => ({ ...acc, ...propsSource() }), {});
|
||||||
|
|
||||||
|
const selectedProps = Object.fromEntries(
|
||||||
|
Object.entries(sourceProps).filter(([key]) => sourcePropKeys.includes(key as SourcePropKeys)),
|
||||||
|
) as Pick<MergeObjectsArray<SourceProps>, SourcePropKeys>;
|
||||||
|
|
||||||
|
const combinedProps = { ...props, ...selectedProps } as unknown as ComponentProps;
|
||||||
|
|
||||||
|
return <Component {...combinedProps} ref={ref} />;
|
||||||
|
});
|
||||||
@@ -11,29 +11,46 @@ import Typography from '@mui/material/Typography';
|
|||||||
import Stack from '@mui/material/Stack';
|
import Stack from '@mui/material/Stack';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ProgressBarType, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
import {
|
||||||
|
IReaderSettings,
|
||||||
|
ProgressBarType,
|
||||||
|
ReadingDirection,
|
||||||
|
TReaderScrollbarContext,
|
||||||
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
||||||
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
import { reverseString } from '@/util/Strings.ts';
|
import { reverseString } from '@/util/Strings.ts';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { ReaderStatePages, TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderPageNumber = () => {
|
const BaseReaderPageNumber = ({
|
||||||
const { isDesktop } = ReaderService.useOverlayMode();
|
isDesktop,
|
||||||
const { scrollbarXSize } = useReaderScrollbarContext();
|
scrollbarXSize,
|
||||||
const { readerNavBarWidth } = useNavBarContext();
|
readerNavBarWidth,
|
||||||
const { isMaximized } = useReaderProgressBarContext();
|
isMaximized,
|
||||||
const { currentPageIndex, pages, totalPages } = userReaderStatePagesContext();
|
currentPageIndex,
|
||||||
const { progressBarType, shouldShowPageNumber, readingDirection } = ReaderService.useSettings();
|
pages,
|
||||||
|
totalPages,
|
||||||
|
progressBarType,
|
||||||
|
shouldShowPageNumber,
|
||||||
|
readingDirection,
|
||||||
|
}: Pick<TReaderScrollbarContext, 'scrollbarXSize'> &
|
||||||
|
Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop'> &
|
||||||
|
Pick<NavbarContextType, 'readerNavBarWidth'> &
|
||||||
|
Pick<TReaderProgressBarContext, 'isMaximized'> &
|
||||||
|
Pick<ReaderStatePages, 'currentPageIndex' | 'pages' | 'totalPages'> &
|
||||||
|
Pick<IReaderSettings, 'progressBarType' | 'shouldShowPageNumber' | 'readingDirection'>) => {
|
||||||
const pageName = useMemo(() => {
|
const pageName = useMemo(() => {
|
||||||
const currentPageName = getPage(currentPageIndex, pages).name;
|
const currentPageName = getPage(currentPageIndex, pages).name;
|
||||||
const SEPARATOR = '/';
|
const SEPARATOR = '/';
|
||||||
const tmpPageName = `${currentPageName}${SEPARATOR}${totalPages}`;
|
const tmpPageName = `${currentPageName}${SEPARATOR}${totalPages}`;
|
||||||
|
|
||||||
return readingDirection.value === ReadingDirection.LTR ? tmpPageName : reverseString(tmpPageName, SEPARATOR);
|
return readingDirection === ReadingDirection.LTR ? tmpPageName : reverseString(tmpPageName, SEPARATOR);
|
||||||
}, [currentPageIndex, pages, totalPages, readingDirection.value]);
|
}, [currentPageIndex, pages, totalPages, readingDirection]);
|
||||||
|
|
||||||
if (!shouldShowPageNumber) {
|
if (!shouldShowPageNumber) {
|
||||||
return null;
|
return null;
|
||||||
@@ -74,3 +91,27 @@ export const ReaderPageNumber = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderPageNumber = withPropsFrom(
|
||||||
|
BaseReaderPageNumber,
|
||||||
|
[
|
||||||
|
ReaderService.useOverlayMode,
|
||||||
|
useReaderScrollbarContext,
|
||||||
|
useNavBarContext,
|
||||||
|
useReaderProgressBarContext,
|
||||||
|
userReaderStatePagesContext,
|
||||||
|
ReaderService.useSettingsWithoutDefaultFlag,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'isDesktop',
|
||||||
|
'scrollbarXSize',
|
||||||
|
'readerNavBarWidth',
|
||||||
|
'isMaximized',
|
||||||
|
'currentPageIndex',
|
||||||
|
'pages',
|
||||||
|
'totalPages',
|
||||||
|
'progressBarType',
|
||||||
|
'shouldShowPageNumber',
|
||||||
|
'readingDirection',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -9,18 +9,19 @@
|
|||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
|
||||||
export const ReaderRGBAFilter = () => {
|
const BaseReaderRGBAFilter = ({
|
||||||
const { readerNavBarWidth } = useNavBarContext();
|
readerNavBarWidth,
|
||||||
const {
|
|
||||||
customFilter: {
|
customFilter: {
|
||||||
rgba: {
|
rgba: {
|
||||||
value: { red, green, blue, alpha },
|
value: { red, green, blue, alpha },
|
||||||
enabled,
|
enabled,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} = ReaderService.useSettings();
|
}: Pick<NavbarContextType, 'readerNavBarWidth'> & Pick<IReaderSettings, 'customFilter'>) => {
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -39,3 +40,9 @@ export const ReaderRGBAFilter = () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderRGBAFilter = withPropsFrom(
|
||||||
|
BaseReaderRGBAFilter,
|
||||||
|
[useNavBarContext, ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['readerNavBarWidth', 'customFilter'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -14,15 +14,23 @@ import { ReaderTapZoneService } from '@/modules/reader/services/ReaderTapZoneSer
|
|||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts';
|
||||||
|
|
||||||
const CANVAS_ID = 'reader-tap-zone-layout-canvas';
|
const CANVAS_ID = 'reader-tap-zone-layout-canvas';
|
||||||
|
|
||||||
export const TapZoneLayout = () => {
|
const BaseTapZoneLayout = ({
|
||||||
|
readerNavBarWidth,
|
||||||
|
showPreview,
|
||||||
|
tapZoneLayout,
|
||||||
|
tapZoneInvertMode,
|
||||||
|
readingDirection,
|
||||||
|
}: Pick<NavbarContextType, 'readerNavBarWidth'> &
|
||||||
|
Pick<TReaderTapZoneContext, 'showPreview'> &
|
||||||
|
Pick<IReaderSettings, 'tapZoneLayout' | 'tapZoneInvertMode' | 'readingDirection'>) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { readerNavBarWidth } = useNavBarContext();
|
|
||||||
const { showPreview } = useReaderTapZoneContext();
|
|
||||||
const { tapZoneLayout, readingDirection, tapZoneInvertMode } = ReaderService.useSettings();
|
|
||||||
|
|
||||||
const [width, setWidth] = useState(0);
|
const [width, setWidth] = useState(0);
|
||||||
const [height, setHeight] = useState(0);
|
const [height, setHeight] = useState(0);
|
||||||
@@ -35,10 +43,10 @@ export const TapZoneLayout = () => {
|
|||||||
}, [tapZoneLayoutElement]),
|
}, [tapZoneLayoutElement]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const canvas = ReaderTapZoneService.getOrCreateCanvas(tapZoneLayout.value, width, height, theme.typography.h3, {
|
const canvas = ReaderTapZoneService.getOrCreateCanvas(tapZoneLayout, width, height, theme.typography.h3, {
|
||||||
vertical: tapZoneInvertMode.value.vertical,
|
vertical: tapZoneInvertMode.vertical,
|
||||||
horizontal: tapZoneInvertMode.value.horizontal,
|
horizontal: tapZoneInvertMode.horizontal,
|
||||||
isRTL: readingDirection.value === ReadingDirection.RTL,
|
isRTL: readingDirection === ReadingDirection.RTL,
|
||||||
});
|
});
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -62,3 +70,9 @@ export const TapZoneLayout = () => {
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TapZoneLayout = withPropsFrom(
|
||||||
|
BaseTapZoneLayout,
|
||||||
|
[useNavBarContext, useReaderTapZoneContext, ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['readerNavBarWidth', 'showPreview', 'tapZoneLayout', 'tapZoneInvertMode', 'readingDirection'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ import { ReaderNavBarDesktop } from '@/modules/reader/components/overlay/navigat
|
|||||||
import { ReaderOverlayHeaderMobile } from '@/modules/reader/components/overlay/ReaderOverlayHeaderMobile.tsx';
|
import { ReaderOverlayHeaderMobile } from '@/modules/reader/components/overlay/ReaderOverlayHeaderMobile.tsx';
|
||||||
import { ReaderBottomBarMobile } from '@/modules/reader/components/overlay/navigation/mobile/ReaderBottomBarMobile.tsx';
|
import { ReaderBottomBarMobile } from '@/modules/reader/components/overlay/navigation/mobile/ReaderBottomBarMobile.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderOverlay = ({ isVisible }: BaseReaderOverlayProps & MobileHeaderProps) => {
|
const BaseReaderOverlay = ({
|
||||||
const { isDesktop, isMobile } = ReaderService.useOverlayMode();
|
isVisible,
|
||||||
|
isDesktop,
|
||||||
|
isMobile,
|
||||||
|
}: BaseReaderOverlayProps &
|
||||||
|
MobileHeaderProps &
|
||||||
|
Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop' | 'isMobile'>) => {
|
||||||
const [areSettingsOpen, setAreSettingsOpen] = useState(false);
|
const [areSettingsOpen, setAreSettingsOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -44,3 +49,9 @@ export const ReaderOverlay = ({ isVisible }: BaseReaderOverlayProps & MobileHead
|
|||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderOverlay = withPropsFrom(
|
||||||
|
BaseReaderOverlay,
|
||||||
|
[ReaderService.useOverlayMode],
|
||||||
|
['isDesktop', 'isMobile'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -28,21 +28,32 @@ import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapt
|
|||||||
import { useBackButton } from '@/modules/core/hooks/useBackButton.ts';
|
import { useBackButton } from '@/modules/core/hooks/useBackButton.ts';
|
||||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||||
import { MobileHeaderProps } from '@/modules/reader/types/ReaderOverlay.types.ts';
|
import { MobileHeaderProps } from '@/modules/reader/types/ReaderOverlay.types.ts';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
|
||||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
|
||||||
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
|
||||||
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder';
|
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder';
|
||||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||||
|
import {
|
||||||
|
ReaderStateChapters,
|
||||||
|
TReaderScrollbarContext,
|
||||||
|
TReaderStateMangaContext,
|
||||||
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
||||||
|
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
||||||
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
|
|
||||||
const DEFAULT_MANGA = { id: -1, title: '' };
|
const DEFAULT_MANGA = { id: -1, title: '' };
|
||||||
const DEFAULT_CHAPTER = { id: -1, name: '', realUrl: '', isBookmarked: false };
|
const DEFAULT_CHAPTER = { id: -1, name: '', realUrl: '', isBookmarked: false };
|
||||||
|
|
||||||
export const ReaderOverlayHeaderMobile = ({ isVisible }: MobileHeaderProps) => {
|
const BaseReaderOverlayHeaderMobile = ({
|
||||||
|
isVisible,
|
||||||
|
manga,
|
||||||
|
currentChapter,
|
||||||
|
scrollbarYSize,
|
||||||
|
}: MobileHeaderProps &
|
||||||
|
Pick<TReaderStateMangaContext, 'manga'> &
|
||||||
|
Pick<ReaderStateChapters, 'currentChapter'> &
|
||||||
|
Pick<TReaderScrollbarContext, 'scrollbarYSize'>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { manga } = useReaderStateMangaContext();
|
|
||||||
const { currentChapter } = useReaderStateChaptersContext();
|
|
||||||
const getOptionForDirection = useGetOptionForDirection();
|
const getOptionForDirection = useGetOptionForDirection();
|
||||||
const { scrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
const handleBack = useBackButton();
|
const handleBack = useBackButton();
|
||||||
const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' });
|
const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' });
|
||||||
|
|
||||||
@@ -128,3 +139,9 @@ export const ReaderOverlayHeaderMobile = ({ isVisible }: MobileHeaderProps) => {
|
|||||||
</Slide>
|
</Slide>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderOverlayHeaderMobile = withPropsFrom(
|
||||||
|
BaseReaderOverlayHeaderMobile,
|
||||||
|
[useReaderStateMangaContext, useReaderStateChaptersContext, useReaderScrollbarContext],
|
||||||
|
['manga', 'currentChapter', 'scrollbarYSize'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx';
|
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx';
|
||||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { ReaderStateChapters, TReaderStateMangaContext } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const useGetPreviousNavBarStaticValue = (isVisible: boolean, isStaticNav: boolean) => {
|
const useGetPreviousNavBarStaticValue = (isVisible: boolean, isStaticNav: boolean) => {
|
||||||
const wasNavBarStaticRef = useRef(isStaticNav);
|
const wasNavBarStaticRef = useRef(isStaticNav);
|
||||||
@@ -52,17 +56,35 @@ const useGetPreviousNavBarStaticValue = (isVisible: boolean, isStaticNav: boolea
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_MANGA: MangaIdInfo = { id: -1 };
|
const DEFAULT_MANGA: MangaIdInfo = { id: -1 };
|
||||||
export const ReaderNavBarDesktop = ({ isVisible, openSettings }: ReaderNavBarDesktopProps) => {
|
const BaseReaderNavBarDesktop = ({
|
||||||
|
isVisible,
|
||||||
|
openSettings,
|
||||||
|
setReaderNavBarWidth,
|
||||||
|
manga,
|
||||||
|
chapters,
|
||||||
|
currentChapter,
|
||||||
|
previousChapter,
|
||||||
|
nextChapter,
|
||||||
|
pages,
|
||||||
|
currentPageIndex,
|
||||||
|
pageLoadStates,
|
||||||
|
setPageLoadStates,
|
||||||
|
setRetryFailedPagesKeyPrefix,
|
||||||
|
exit,
|
||||||
|
}: ReaderNavBarDesktopProps &
|
||||||
|
Pick<NavbarContextType, 'setReaderNavBarWidth'> &
|
||||||
|
Pick<TReaderStateMangaContext, 'manga'> &
|
||||||
|
Pick<ReaderStateChapters, 'currentChapter' | 'previousChapter' | 'nextChapter' | 'chapters'> &
|
||||||
|
Pick<
|
||||||
|
ReaderStatePages,
|
||||||
|
'pages' | 'currentPageIndex' | 'pageLoadStates' | 'setPageLoadStates' | 'setRetryFailedPagesKeyPrefix'
|
||||||
|
> & {
|
||||||
|
exit: ReturnType<typeof ReaderService.useExit>;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { setReaderNavBarWidth } = useNavBarContext();
|
|
||||||
const { manga } = useReaderStateMangaContext();
|
|
||||||
const { chapters, currentChapter, nextChapter, previousChapter } = useReaderStateChaptersContext();
|
|
||||||
const { pages, currentPageIndex, pageLoadStates, setPageLoadStates, setRetryFailedPagesKeyPrefix } =
|
|
||||||
userReaderStatePagesContext();
|
|
||||||
|
|
||||||
const getOptionForDirection = useGetOptionForDirection();
|
const getOptionForDirection = useGetOptionForDirection();
|
||||||
|
|
||||||
const exit = ReaderService.useExit();
|
|
||||||
const updateReaderSettings = ReaderService.useCreateUpdateSetting(manga ?? DEFAULT_MANGA);
|
const updateReaderSettings = ReaderService.useCreateUpdateSetting(manga ?? DEFAULT_MANGA);
|
||||||
const settings = ReaderService.useSettings();
|
const settings = ReaderService.useSettings();
|
||||||
|
|
||||||
@@ -154,3 +176,28 @@ export const ReaderNavBarDesktop = ({ isVisible, openSettings }: ReaderNavBarDes
|
|||||||
</Drawer>
|
</Drawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderNavBarDesktop = withPropsFrom(
|
||||||
|
BaseReaderNavBarDesktop,
|
||||||
|
[
|
||||||
|
useNavBarContext,
|
||||||
|
useReaderStateMangaContext,
|
||||||
|
useReaderStateChaptersContext,
|
||||||
|
userReaderStatePagesContext,
|
||||||
|
() => ({ exit: ReaderService.useExit() }),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'setReaderNavBarWidth',
|
||||||
|
'manga',
|
||||||
|
'chapters',
|
||||||
|
'currentChapter',
|
||||||
|
'previousChapter',
|
||||||
|
'nextChapter',
|
||||||
|
'pages',
|
||||||
|
'currentPageIndex',
|
||||||
|
'pageLoadStates',
|
||||||
|
'setPageLoadStates',
|
||||||
|
'setRetryFailedPagesKeyPrefix',
|
||||||
|
'exit',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -23,16 +23,20 @@ import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts'
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts';
|
import { ReaderControls } from '@/modules/reader/services/ReaderControls.ts';
|
||||||
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderNavBarDesktopChapterNavigation = ({
|
const BaseReaderNavBarDesktopChapterNavigation = ({
|
||||||
currentChapter,
|
currentChapter,
|
||||||
previousChapter,
|
previousChapter,
|
||||||
nextChapter,
|
nextChapter,
|
||||||
chapters = [],
|
chapters = [],
|
||||||
}: Pick<ReaderStateChapters, 'chapters' | 'currentChapter' | 'previousChapter' | 'nextChapter'>) => {
|
readerThemeDirection,
|
||||||
|
openChapter,
|
||||||
|
}: Pick<ReaderStateChapters, 'chapters' | 'currentChapter' | 'previousChapter' | 'nextChapter'> & {
|
||||||
|
readerThemeDirection: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
||||||
|
openChapter: ReturnType<typeof ReaderControls.useOpenChapter>;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const readerThemeDirection = ReaderService.useGetThemeDirection();
|
|
||||||
const openChapter = ReaderControls.useOpenChapter();
|
|
||||||
|
|
||||||
const popupState = usePopupState({ variant: 'popover', popupId: 'reader-nav-bar-desktop-chapter-list' });
|
const popupState = usePopupState({ variant: 'popover', popupId: 'reader-nav-bar-desktop-chapter-list' });
|
||||||
|
|
||||||
@@ -111,3 +115,16 @@ export const ReaderNavBarDesktopChapterNavigation = ({
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderNavBarDesktopChapterNavigation = withPropsFrom(
|
||||||
|
BaseReaderNavBarDesktopChapterNavigation,
|
||||||
|
[
|
||||||
|
() => ({
|
||||||
|
readerThemeDirection: ReaderService.useGetThemeDirection(),
|
||||||
|
}),
|
||||||
|
() => ({
|
||||||
|
openChapter: ReaderControls.useOpenChapter(),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
['readerThemeDirection', 'openChapter'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -20,18 +20,23 @@ import { useGetOptionForDirection } from '@/modules/theme/services/ThemeCreator.
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReaderNavBarDesktopNextPreviousButton } from '@/modules/reader/components/overlay/navigation/desktop/ReaderNavBarDesktopNextPreviousButton.tsx';
|
import { ReaderNavBarDesktopNextPreviousButton } from '@/modules/reader/components/overlay/navigation/desktop/ReaderNavBarDesktopNextPreviousButton.tsx';
|
||||||
import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
import { READING_DIRECTION_TO_THEME_DIRECTION } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
||||||
|
import { IReaderSettings } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderNavBarDesktopPageNavigation = ({
|
const BaseReaderNavBarDesktopPageNavigation = ({
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
pages,
|
pages,
|
||||||
}: Pick<ReaderStatePages, 'currentPageIndex' | 'pages'>) => {
|
readingDirection,
|
||||||
|
openPage,
|
||||||
|
}: Pick<ReaderStatePages, 'currentPageIndex' | 'pages'> &
|
||||||
|
Pick<IReaderSettings, 'readingDirection'> & {
|
||||||
|
openPage: ReturnType<typeof ReaderControls.useOpenPage>;
|
||||||
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const openPage = ReaderControls.useOpenPage();
|
|
||||||
const { readingDirection } = ReaderService.useSettings();
|
|
||||||
const getOptionForDirection = useGetOptionForDirection();
|
const getOptionForDirection = useGetOptionForDirection();
|
||||||
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
||||||
|
|
||||||
const direction = READING_DIRECTION_TO_THEME_DIRECTION[readingDirection.value];
|
const direction = READING_DIRECTION_TO_THEME_DIRECTION[readingDirection];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack sx={{ flexDirection: 'row', gap: 1 }} dir="ltr">
|
<Stack sx={{ flexDirection: 'row', gap: 1 }} dir="ltr">
|
||||||
@@ -73,3 +78,9 @@ export const ReaderNavBarDesktopPageNavigation = ({
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderNavBarDesktopPageNavigation = withPropsFrom(
|
||||||
|
BaseReaderNavBarDesktopPageNavigation,
|
||||||
|
[() => ({ openPage: ReaderControls.useOpenPage() }), ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['readingDirection', 'openPage'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -25,11 +25,20 @@ import { ReaderChapterList } from '@/modules/reader/components/overlay/navigatio
|
|||||||
import { ReaderBottomBarMobileQuickSettings } from '@/modules/reader/components/overlay/navigation/mobile/ReaderBottomBarMobileQuickSettings.tsx';
|
import { ReaderBottomBarMobileQuickSettings } from '@/modules/reader/components/overlay/navigation/mobile/ReaderBottomBarMobileQuickSettings.tsx';
|
||||||
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
|
import { ReaderStateChapters, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderBottomBarMobile = ({ openSettings, isVisible }: ReaderBottomBarMobileProps) => {
|
const BaseReaderBottomBarMobile = ({
|
||||||
|
openSettings,
|
||||||
|
isVisible,
|
||||||
|
currentChapter,
|
||||||
|
chapters,
|
||||||
|
scrollbarXSize,
|
||||||
|
scrollbarYSize,
|
||||||
|
}: ReaderBottomBarMobileProps &
|
||||||
|
Pick<ReaderStateChapters, 'currentChapter' | 'chapters'> &
|
||||||
|
Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { currentChapter, chapters } = useReaderStateChaptersContext();
|
|
||||||
const { scrollbarXSize, scrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
|
|
||||||
const chapterListPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-chapter-list-dialog' });
|
const chapterListPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-chapter-list-dialog' });
|
||||||
const quickSettingsPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-quick-settings-dialog' });
|
const quickSettingsPopupState = usePopupState({ variant: 'dialog', popupId: 'reader-quick-settings-dialog' });
|
||||||
@@ -112,3 +121,9 @@ export const ReaderBottomBarMobile = ({ openSettings, isVisible }: ReaderBottomB
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderBottomBarMobile = withPropsFrom(
|
||||||
|
BaseReaderBottomBarMobile,
|
||||||
|
[useReaderStateChaptersContext, useReaderScrollbarContext],
|
||||||
|
['currentChapter', 'chapters', 'scrollbarXSize', 'scrollbarYSize'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -13,11 +13,16 @@ import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
|||||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
||||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||||
import { DefaultSettingFootnote } from '@/modules/reader/components/settings/DefaultSettingFootnote.tsx';
|
import { DefaultSettingFootnote } from '@/modules/reader/components/settings/DefaultSettingFootnote.tsx';
|
||||||
|
import { IReaderSettingsWithDefaultFlag, TReaderStateMangaContext } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const DEFAULT_MANGA: MangaIdInfo = { id: -1 };
|
const DEFAULT_MANGA: MangaIdInfo = { id: -1 };
|
||||||
export const ReaderBottomBarMobileQuickSettings = () => {
|
const BaseReaderBottomBarMobileQuickSettings = ({
|
||||||
const { manga } = useReaderStateMangaContext();
|
manga,
|
||||||
const { readingMode, readingDirection } = ReaderService.useSettings();
|
readingMode,
|
||||||
|
readingDirection,
|
||||||
|
}: Pick<TReaderStateMangaContext, 'manga'> &
|
||||||
|
Pick<IReaderSettingsWithDefaultFlag, 'readingMode' | 'readingDirection'>) => {
|
||||||
const deleteSetting = ReaderService.useCreateDeleteSetting(manga ?? DEFAULT_MANGA);
|
const deleteSetting = ReaderService.useCreateDeleteSetting(manga ?? DEFAULT_MANGA);
|
||||||
|
|
||||||
if (!manga) {
|
if (!manga) {
|
||||||
@@ -42,3 +47,9 @@ export const ReaderBottomBarMobileQuickSettings = () => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderBottomBarMobileQuickSettings = withPropsFrom(
|
||||||
|
BaseReaderBottomBarMobileQuickSettings,
|
||||||
|
[useReaderStateMangaContext, ReaderService.useSettings],
|
||||||
|
['manga', 'readingMode', 'readingDirection'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ import { ReactNode, useCallback, useMemo, useRef } from 'react';
|
|||||||
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
import ClickAwayListener from '@mui/material/ClickAwayListener';
|
||||||
import { TypographyProps } from '@mui/material/Typography';
|
import { TypographyProps } from '@mui/material/Typography';
|
||||||
import { StackProps } from '@mui/material/Stack';
|
import { StackProps } from '@mui/material/Stack';
|
||||||
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
import { ReaderProgressBarProps, TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
import { ReaderProgressBarProps } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
|
||||||
import { ReaderProgressBarPageNumber } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarPageNumber.tsx';
|
import { ReaderProgressBarPageNumber } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarPageNumber.tsx';
|
||||||
import { ReaderProgressBarContainer } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarContainer.tsx';
|
import { ReaderProgressBarContainer } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarContainer.tsx';
|
||||||
import { ReaderProgressBarRoot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarRoot.tsx';
|
import { ReaderProgressBarRoot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarRoot.tsx';
|
||||||
@@ -30,8 +29,10 @@ import { getOptionForDirection as getOptionForDirectionImpl } from '@/modules/th
|
|||||||
import { ReaderProgressBarSlotsActionArea } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlotsActionArea.tsx';
|
import { ReaderProgressBarSlotsActionArea } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlotsActionArea.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReaderControls } from '@/modules/reader/services/ReaderControls.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';
|
||||||
|
|
||||||
export const ReaderProgressBar = ({
|
const BaseReaderProgressBar = ({
|
||||||
totalPages,
|
totalPages,
|
||||||
pages,
|
pages,
|
||||||
pageLoadStates,
|
pageLoadStates,
|
||||||
@@ -40,7 +41,12 @@ export const ReaderProgressBar = ({
|
|||||||
slots,
|
slots,
|
||||||
createProgressBarSlot,
|
createProgressBarSlot,
|
||||||
progressBarPosition,
|
progressBarPosition,
|
||||||
}: ReaderProgressBarProps & {
|
isDragging,
|
||||||
|
setIsDragging,
|
||||||
|
openPage,
|
||||||
|
direction,
|
||||||
|
}: ReaderProgressBarProps &
|
||||||
|
Pick<TReaderProgressBarContext, 'isDragging' | 'setIsDragging'> & {
|
||||||
createProgressBarSlot: (
|
createProgressBarSlot: (
|
||||||
page: ReaderProgressBarProps['pages'][number],
|
page: ReaderProgressBarProps['pages'][number],
|
||||||
pageLoadStates: ReaderProgressBarProps['pageLoadStates'],
|
pageLoadStates: ReaderProgressBarProps['pageLoadStates'],
|
||||||
@@ -63,11 +69,9 @@ export const ReaderProgressBar = ({
|
|||||||
slots?: {
|
slots?: {
|
||||||
progressBarCurrentPage?: ReactNode;
|
progressBarCurrentPage?: ReactNode;
|
||||||
};
|
};
|
||||||
}) => {
|
openPage: ReturnType<typeof ReaderControls.useOpenPage>;
|
||||||
const { isDragging, setIsDragging } = useReaderProgressBarContext();
|
direction: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
||||||
const openPage = ReaderControls.useOpenPage();
|
}) => {
|
||||||
const direction = ReaderService.useGetThemeDirection();
|
|
||||||
|
|
||||||
const progressBarRef = useRef<HTMLDivElement | null>(null);
|
const progressBarRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const isHorizontalPosition = getProgressBarPositionInfo(progressBarPosition).isHorizontal;
|
const isHorizontalPosition = getProgressBarPositionInfo(progressBarPosition).isHorizontal;
|
||||||
@@ -212,3 +216,15 @@ export const ReaderProgressBar = ({
|
|||||||
</ReaderProgressBarContainer>
|
</ReaderProgressBarContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderProgressBar = withPropsFrom(
|
||||||
|
BaseReaderProgressBar,
|
||||||
|
[
|
||||||
|
useReaderProgressBarContext,
|
||||||
|
() => ({ openPage: ReaderControls.useOpenPage() }),
|
||||||
|
() => ({
|
||||||
|
direction: ReaderService.useGetThemeDirection(),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
['isDragging', 'setIsDragging', 'openPage', 'direction'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -16,9 +16,15 @@ import { ThemeMode } from '@/modules/theme/contexts/ThemeModeContext.tsx';
|
|||||||
import { createTheme } from '@/modules/theme/services/ThemeCreator.ts';
|
import { createTheme } from '@/modules/theme/services/ThemeCreator.ts';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { DIRECTION_TO_CACHE } from '@/modules/theme/ThemeDirectionCache.ts';
|
import { DIRECTION_TO_CACHE } from '@/modules/theme/ThemeDirectionCache.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderProgressBarDirectionWrapper = ({ children }: { children: ReactNode }) => {
|
const BaseReaderProgressBarDirectionWrapper = ({
|
||||||
const direction = ReaderService.useGetThemeDirection();
|
children,
|
||||||
|
direction,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
direction: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
||||||
|
}) => {
|
||||||
const [appTheme] = useLocalStorage<AppThemes>('appTheme', 'default');
|
const [appTheme] = useLocalStorage<AppThemes>('appTheme', 'default');
|
||||||
const [themeMode] = useLocalStorage<ThemeMode>('themeMode', ThemeMode.SYSTEM);
|
const [themeMode] = useLocalStorage<ThemeMode>('themeMode', ThemeMode.SYSTEM);
|
||||||
const [pureBlackMode] = useLocalStorage<boolean>('pureBlackMode', false);
|
const [pureBlackMode] = useLocalStorage<boolean>('pureBlackMode', false);
|
||||||
@@ -40,3 +46,9 @@ export const ReaderProgressBarDirectionWrapper = ({ children }: { children: Reac
|
|||||||
</CacheProvider>
|
</CacheProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderProgressBarDirectionWrapper = withPropsFrom(
|
||||||
|
BaseReaderProgressBarDirectionWrapper,
|
||||||
|
[() => ({ direction: ReaderService.useGetThemeDirection() })],
|
||||||
|
['direction'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -20,15 +20,22 @@ import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/R
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
import { getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
||||||
import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
|
import { getOptionForDirection } from '@/modules/theme/services/ThemeCreator.ts';
|
||||||
import { ProgressBarPosition, ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
import { ProgressBarPosition, ReaderResumeMode, ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
|
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
|
||||||
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
||||||
import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx';
|
import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { TReaderOverlayContext } from '@/modules/reader/types/ReaderOverlay.types.ts';
|
||||||
|
import { TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
|
||||||
export const MobileReaderProgressBar = () => {
|
const BaseMobileReaderProgressBar = ({
|
||||||
const { nextChapter, previousChapter } = useReaderStateChaptersContext();
|
previousChapter,
|
||||||
const { isVisible } = useReaderOverlayContext();
|
nextChapter,
|
||||||
const { setIsMaximized } = useReaderProgressBarContext();
|
isVisible,
|
||||||
|
setIsMaximized,
|
||||||
|
}: Pick<ReaderStateChapters, 'previousChapter' | 'nextChapter'> &
|
||||||
|
Pick<TReaderOverlayContext, 'isVisible'> &
|
||||||
|
Pick<TReaderProgressBarContext, 'setIsMaximized'>) => {
|
||||||
const pagesState = userReaderStatePagesContext();
|
const pagesState = userReaderStatePagesContext();
|
||||||
const { currentPageIndex, pages } = pagesState;
|
const { currentPageIndex, pages } = pagesState;
|
||||||
|
|
||||||
@@ -177,3 +184,9 @@ export const MobileReaderProgressBar = () => {
|
|||||||
</ReaderProgressBarDirectionWrapper>
|
</ReaderProgressBarDirectionWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MobileReaderProgressBar = withPropsFrom(
|
||||||
|
BaseMobileReaderProgressBar,
|
||||||
|
[useReaderStateChaptersContext, useReaderOverlayContext, useReaderProgressBarContext],
|
||||||
|
['previousChapter', 'nextChapter', 'isVisible', 'setIsMaximized'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -9,26 +9,40 @@
|
|||||||
import { alpha, darken, lighten, useTheme } from '@mui/material/styles';
|
import { alpha, darken, lighten, useTheme } from '@mui/material/styles';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { ReaderProgressBar } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBar.tsx';
|
import { ReaderProgressBar } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBar.tsx';
|
||||||
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
|
||||||
import { ReaderProgressBarSlot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlot.tsx';
|
import { ReaderProgressBarSlot } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarSlot.tsx';
|
||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
|
||||||
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ProgressBarType } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ProgressBarType, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
import { getPage, getProgressBarPositionInfo } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
import { getPage, getProgressBarPositionInfo } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
||||||
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
|
import { ReaderProgressBarDirectionWrapper } from '@/modules/reader/components/overlay/progress-bar/ReaderProgressBarDirectionWrapper.tsx';
|
||||||
|
import { TReaderProgressBarContext } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
|
import { useReaderProgressBarContext } from '@/modules/reader/contexts/ReaderProgressBarContext.tsx';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
|
|
||||||
export const StandardReaderProgressBar = () => {
|
const BaseStandardReaderProgressBar = ({
|
||||||
|
readerNavBarWidth,
|
||||||
|
isMaximized,
|
||||||
|
setIsMaximized,
|
||||||
|
isDragging,
|
||||||
|
progressBarType,
|
||||||
|
progressBarSize,
|
||||||
|
progressBarPosition,
|
||||||
|
readerDirection,
|
||||||
|
scrollbarXSize,
|
||||||
|
scrollbarYSize,
|
||||||
|
}: Pick<NavbarContextType, 'readerNavBarWidth'> &
|
||||||
|
Pick<TReaderProgressBarContext, 'isMaximized' | 'setIsMaximized' | 'isDragging'> &
|
||||||
|
Pick<IReaderSettings, 'progressBarType' | 'progressBarSize' | 'progressBarPosition'> &
|
||||||
|
Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> & {
|
||||||
|
readerDirection: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
||||||
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const pagesState = userReaderStatePagesContext();
|
const pagesState = userReaderStatePagesContext();
|
||||||
const { currentPageIndex, pages } = pagesState;
|
const { currentPageIndex, pages } = pagesState;
|
||||||
const { readerNavBarWidth } = useNavBarContext();
|
|
||||||
const { isMaximized, setIsMaximized, isDragging } = useReaderProgressBarContext();
|
|
||||||
const { progressBarType, progressBarSize, progressBarPosition } = ReaderService.useSettings();
|
|
||||||
const readerDirection = ReaderService.useGetThemeDirection();
|
|
||||||
const { scrollbarXSize, scrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
|
|
||||||
const currentPagesIndex = getPage(currentPageIndex, pages).pagesIndex;
|
const currentPagesIndex = getPage(currentPageIndex, pages).pagesIndex;
|
||||||
|
|
||||||
@@ -255,3 +269,26 @@ export const StandardReaderProgressBar = () => {
|
|||||||
</ReaderProgressBarDirectionWrapper>
|
</ReaderProgressBarDirectionWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const StandardReaderProgressBar = withPropsFrom(
|
||||||
|
BaseStandardReaderProgressBar,
|
||||||
|
[
|
||||||
|
useNavBarContext,
|
||||||
|
useReaderProgressBarContext,
|
||||||
|
ReaderService.useSettingsWithoutDefaultFlag,
|
||||||
|
() => ({ readerDirection: ReaderService.useGetThemeDirection() }),
|
||||||
|
useReaderScrollbarContext,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'readerNavBarWidth',
|
||||||
|
'isMaximized',
|
||||||
|
'setIsMaximized',
|
||||||
|
'isDragging',
|
||||||
|
'progressBarType',
|
||||||
|
'progressBarSize',
|
||||||
|
'progressBarPosition',
|
||||||
|
'readerDirection',
|
||||||
|
'scrollbarXSize',
|
||||||
|
'scrollbarYSize',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -23,28 +23,30 @@ import { ReaderFilterSettings } from '@/modules/reader/components/settings/filte
|
|||||||
import { ReaderBehaviourSettings } from '@/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx';
|
import { ReaderBehaviourSettings } from '@/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx';
|
||||||
import { ReaderDefaultLayoutSettings } from '@/modules/reader/components/settings/layout/ReaderDefaultLayoutSettings.tsx';
|
import { ReaderDefaultLayoutSettings } from '@/modules/reader/components/settings/layout/ReaderDefaultLayoutSettings.tsx';
|
||||||
import { ReaderHotkeysSettings } from '@/modules/reader/components/settings/hotkeys/ReaderHotkeysSettings.tsx';
|
import { ReaderHotkeysSettings } from '@/modules/reader/components/settings/hotkeys/ReaderHotkeysSettings.tsx';
|
||||||
|
import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderSettingsTabs = ({
|
const BaseReaderSettingsTabs = ({
|
||||||
activeTab,
|
activeTab,
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
areDefaultSettings,
|
areDefaultSettings,
|
||||||
settings,
|
settings,
|
||||||
updateSetting,
|
updateSetting,
|
||||||
deleteSetting,
|
deleteSetting,
|
||||||
}: {
|
setShowPreview,
|
||||||
|
mode: overlayMode,
|
||||||
|
}: Pick<TReaderTapZoneContext, 'setShowPreview'> &
|
||||||
|
Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'mode'> & {
|
||||||
activeTab: number;
|
activeTab: number;
|
||||||
setActiveTab: (tab: number) => void;
|
setActiveTab: (tab: number) => void;
|
||||||
settings: IReaderSettingsWithDefaultFlag;
|
settings: IReaderSettingsWithDefaultFlag;
|
||||||
updateSetting: (...args: OmitFirst<Parameters<typeof ReaderService.updateSetting>>) => void;
|
updateSetting: (...args: OmitFirst<Parameters<typeof ReaderService.updateSetting>>) => void;
|
||||||
areDefaultSettings?: boolean;
|
areDefaultSettings?: boolean;
|
||||||
deleteSetting: (setting: keyof IReaderSettings) => void;
|
deleteSetting: (setting: keyof IReaderSettings) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { setShowPreview } = useReaderTapZoneContext();
|
|
||||||
const isTouchDevice = MediaQuery.useIsTouchDevice();
|
const isTouchDevice = MediaQuery.useIsTouchDevice();
|
||||||
|
|
||||||
const { mode: overlayMode } = ReaderService.useOverlayMode();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TabsMenu
|
<TabsMenu
|
||||||
@@ -177,3 +179,9 @@ export const ReaderSettingsTabs = ({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderSettingsTabs = withPropsFrom(
|
||||||
|
BaseReaderSettingsTabs,
|
||||||
|
[useReaderTapZoneContext, ReaderService.useOverlayMode],
|
||||||
|
['setShowPreview', 'mode'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import { ComponentProps, ForwardedRef, forwardRef } from 'react';
|
import { ComponentProps, ForwardedRef, forwardRef } from 'react';
|
||||||
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReaderCustomFilter } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ReaderCustomFilter, TReaderScrollbarContext } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import {
|
import {
|
||||||
getImageMarginStyling,
|
getImageMarginStyling,
|
||||||
getImagePlaceholderStyling,
|
getImagePlaceholderStyling,
|
||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
import { useReaderScrollbarContext } from '@/modules/reader/contexts/ReaderScrollbarContext.tsx';
|
||||||
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const getCustomFilterString = (customFilter: ReaderCustomFilter): string =>
|
const getCustomFilterString = (customFilter: ReaderCustomFilter): string =>
|
||||||
Object.keys(customFilter)
|
Object.keys(customFilter)
|
||||||
@@ -48,7 +49,7 @@ const getCustomFilterString = (customFilter: ReaderCustomFilter): string =>
|
|||||||
})
|
})
|
||||||
.join(' ');
|
.join(' ');
|
||||||
|
|
||||||
export const ReaderPage = forwardRef(
|
const BaseReaderPage = forwardRef(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
display,
|
display,
|
||||||
@@ -56,8 +57,20 @@ export const ReaderPage = forwardRef(
|
|||||||
position,
|
position,
|
||||||
marginTop,
|
marginTop,
|
||||||
shouldLoad,
|
shouldLoad,
|
||||||
|
readingMode,
|
||||||
|
customFilter,
|
||||||
|
pageScaleMode,
|
||||||
|
shouldStretchPage,
|
||||||
|
readerWidth,
|
||||||
|
scrollbarXSize,
|
||||||
|
scrollbarYSize,
|
||||||
...props
|
...props
|
||||||
}: Omit<ComponentProps<typeof SpinnerImage>, 'ref' | 'spinnerStyle' | 'imgStyle'> & {
|
}: Omit<ComponentProps<typeof SpinnerImage>, 'ref' | 'spinnerStyle' | 'imgStyle'> &
|
||||||
|
Pick<
|
||||||
|
IReaderSettings,
|
||||||
|
'readingMode' | 'customFilter' | 'pageScaleMode' | 'shouldStretchPage' | 'readerWidth'
|
||||||
|
> &
|
||||||
|
Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> & {
|
||||||
display: boolean;
|
display: boolean;
|
||||||
doublePage?: boolean;
|
doublePage?: boolean;
|
||||||
position?: 'left' | 'right';
|
position?: 'left' | 'right';
|
||||||
@@ -65,9 +78,6 @@ export const ReaderPage = forwardRef(
|
|||||||
},
|
},
|
||||||
ref: ForwardedRef<HTMLImageElement | null>,
|
ref: ForwardedRef<HTMLImageElement | null>,
|
||||||
) => {
|
) => {
|
||||||
const { readingMode, customFilter, pageScaleMode, shouldStretchPage, readerWidth } =
|
|
||||||
ReaderService.useSettings();
|
|
||||||
const { scrollbarXSize, scrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
const isTabletWidth = MediaQuery.useIsTabletWidth();
|
const isTabletWidth = MediaQuery.useIsTabletWidth();
|
||||||
|
|
||||||
if (!display && !shouldLoad) {
|
if (!display && !shouldLoad) {
|
||||||
@@ -83,10 +93,10 @@ export const ReaderPage = forwardRef(
|
|||||||
spinnerStyle={{
|
spinnerStyle={{
|
||||||
backgroundColor: 'background.paper',
|
backgroundColor: 'background.paper',
|
||||||
...getImagePlaceholderStyling(
|
...getImagePlaceholderStyling(
|
||||||
readingMode.value,
|
readingMode,
|
||||||
shouldStretchPage.value,
|
shouldStretchPage,
|
||||||
pageScaleMode.value,
|
pageScaleMode,
|
||||||
readerWidth.value,
|
readerWidth,
|
||||||
scrollbarXSize,
|
scrollbarXSize,
|
||||||
scrollbarYSize,
|
scrollbarYSize,
|
||||||
doublePage,
|
doublePage,
|
||||||
@@ -99,11 +109,11 @@ export const ReaderPage = forwardRef(
|
|||||||
}}
|
}}
|
||||||
imgStyle={{
|
imgStyle={{
|
||||||
...getImageWidthStyling(
|
...getImageWidthStyling(
|
||||||
readingMode.value,
|
readingMode,
|
||||||
shouldStretchPage.value,
|
shouldStretchPage,
|
||||||
pageScaleMode.value,
|
pageScaleMode,
|
||||||
doublePage,
|
doublePage,
|
||||||
readerWidth.value,
|
readerWidth,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
display: 'block',
|
display: 'block',
|
||||||
@@ -130,3 +140,17 @@ export const ReaderPage = forwardRef(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const ReaderPage = withPropsFrom(
|
||||||
|
BaseReaderPage,
|
||||||
|
[ReaderService.useSettingsWithoutDefaultFlag, useReaderScrollbarContext],
|
||||||
|
[
|
||||||
|
'readingMode',
|
||||||
|
'customFilter',
|
||||||
|
'pageScaleMode',
|
||||||
|
'shouldStretchPage',
|
||||||
|
'readerWidth',
|
||||||
|
'scrollbarXSize',
|
||||||
|
'scrollbarYSize',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ import { TChapterReader } from '@/modules/chapter/Chapter.types.ts';
|
|||||||
import {
|
import {
|
||||||
IReaderSettings,
|
IReaderSettings,
|
||||||
ReaderPageScaleMode,
|
ReaderPageScaleMode,
|
||||||
|
ReaderStateChapters,
|
||||||
ReaderTransitionPageMode,
|
ReaderTransitionPageMode,
|
||||||
ReadingMode,
|
ReadingMode,
|
||||||
|
TReaderScrollbarContext,
|
||||||
|
TReaderStateMangaContext,
|
||||||
} from '@/modules/reader/types/Reader.types.ts';
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { isTransitionPageVisible } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { isTransitionPageVisible } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { useBackButton } from '@/modules/core/hooks/useBackButton.ts';
|
import { useBackButton } from '@/modules/core/hooks/useBackButton.ts';
|
||||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
|
||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
import {
|
import {
|
||||||
isContinuousReadingMode,
|
isContinuousReadingMode,
|
||||||
@@ -31,6 +33,8 @@ import {
|
|||||||
} from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
} from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||||
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
|
||||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const ChapterInfo = ({
|
const ChapterInfo = ({
|
||||||
title,
|
title,
|
||||||
@@ -58,22 +62,29 @@ const ChapterInfo = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReaderTransitionPage = ({
|
const BaseReaderTransitionPage = ({
|
||||||
type,
|
type,
|
||||||
mode,
|
mode,
|
||||||
readingMode,
|
readingMode,
|
||||||
pageScaleMode,
|
pageScaleMode,
|
||||||
}: Pick<IReaderSettings, 'readingMode' | 'pageScaleMode'> & {
|
manga,
|
||||||
|
currentChapter,
|
||||||
|
previousChapter,
|
||||||
|
nextChapter,
|
||||||
|
scrollbarXSize,
|
||||||
|
scrollbarYSize,
|
||||||
|
readerNavBarWidth,
|
||||||
|
}: Pick<IReaderSettings, 'readingMode' | 'pageScaleMode'> &
|
||||||
|
Pick<TReaderStateMangaContext, 'manga'> &
|
||||||
|
Pick<ReaderStateChapters, 'currentChapter' | 'previousChapter' | 'nextChapter'> &
|
||||||
|
Pick<TReaderScrollbarContext, 'scrollbarXSize' | 'scrollbarYSize'> &
|
||||||
|
Pick<NavbarContextType, 'readerNavBarWidth'> & {
|
||||||
type: Exclude<ReaderTransitionPageMode, ReaderTransitionPageMode.NONE | ReaderTransitionPageMode.BOTH>;
|
type: Exclude<ReaderTransitionPageMode, ReaderTransitionPageMode.NONE | ReaderTransitionPageMode.BOTH>;
|
||||||
mode: ReaderTransitionPageMode;
|
mode: ReaderTransitionPageMode;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleBack = useBackButton();
|
const handleBack = useBackButton();
|
||||||
const { manga } = useReaderStateMangaContext();
|
|
||||||
const { currentChapter, nextChapter, previousChapter } = useReaderStateChaptersContext();
|
|
||||||
const { scrollbarXSize, scrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
const { readerNavBarWidth } = useNavBarContext();
|
|
||||||
|
|
||||||
const isPreviousType = type === ReaderTransitionPageMode.PREVIOUS;
|
const isPreviousType = type === ReaderTransitionPageMode.PREVIOUS;
|
||||||
const isNextType = type === ReaderTransitionPageMode.NEXT;
|
const isNextType = type === ReaderTransitionPageMode.NEXT;
|
||||||
@@ -191,3 +202,17 @@ export const ReaderTransitionPage = ({
|
|||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderTransitionPage = withPropsFrom(
|
||||||
|
BaseReaderTransitionPage,
|
||||||
|
[useReaderStateChaptersContext, useReaderScrollbarContext, useNavBarContext],
|
||||||
|
[
|
||||||
|
'manga',
|
||||||
|
'currentChapter',
|
||||||
|
'previousChapter',
|
||||||
|
'nextChapter',
|
||||||
|
'scrollbarXSize',
|
||||||
|
'scrollbarYSize',
|
||||||
|
'readerNavBarWidth',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -19,7 +19,13 @@ import {
|
|||||||
import Stack from '@mui/material/Stack';
|
import Stack from '@mui/material/Stack';
|
||||||
import { useTheme } from '@mui/material/styles';
|
import { useTheme } from '@mui/material/styles';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { PageInViewportType, ReadingDirection, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
import {
|
||||||
|
IReaderSettings,
|
||||||
|
PageInViewportType,
|
||||||
|
ReadingDirection,
|
||||||
|
ReadingMode,
|
||||||
|
TReaderScrollbarContext,
|
||||||
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { ReaderPagedPager } from '@/modules/reader/components/viewer/pager/ReaderPagedPager.tsx';
|
import { ReaderPagedPager } from '@/modules/reader/components/viewer/pager/ReaderPagedPager.tsx';
|
||||||
import { ReaderDoublePagedPager } from '@/modules/reader/components/viewer/pager/ReaderDoublePagedPager.tsx';
|
import { ReaderDoublePagedPager } from '@/modules/reader/components/viewer/pager/ReaderDoublePagedPager.tsx';
|
||||||
import { ReaderHorizontalPager } from '@/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx';
|
import { ReaderHorizontalPager } from '@/modules/reader/components/viewer/pager/ReaderHorizontalPager.tsx';
|
||||||
@@ -43,6 +49,9 @@ import { useMouseDragScroll } from '@/modules/core/hooks/useMouseDragScroll.tsx'
|
|||||||
import { DirectionOffset } from '@/Base.types.ts';
|
import { DirectionOffset } from '@/Base.types.ts';
|
||||||
import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx';
|
import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx';
|
||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
|
import { TReaderOverlayContext } from '@/modules/reader/types/ReaderOverlay.types.ts';
|
||||||
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const READING_MODE_TO_IN_VIEWPORT_TYPE: Record<ReadingMode, PageInViewportType> = {
|
const READING_MODE_TO_IN_VIEWPORT_TYPE: Record<ReadingMode, PageInViewportType> = {
|
||||||
[ReadingMode.SINGLE_PAGE]: PageInViewportType.X,
|
[ReadingMode.SINGLE_PAGE]: PageInViewportType.X,
|
||||||
@@ -52,8 +61,9 @@ const READING_MODE_TO_IN_VIEWPORT_TYPE: Record<ReadingMode, PageInViewportType>
|
|||||||
[ReadingMode.WEBTOON]: PageInViewportType.Y,
|
[ReadingMode.WEBTOON]: PageInViewportType.Y,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | null>) => {
|
const BaseReaderViewer = forwardRef(
|
||||||
const {
|
(
|
||||||
|
{
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
pageToScrollToIndex,
|
pageToScrollToIndex,
|
||||||
pages,
|
pages,
|
||||||
@@ -64,17 +74,41 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
setPageLoadStates,
|
setPageLoadStates,
|
||||||
transitionPageMode,
|
transitionPageMode,
|
||||||
retryFailedPagesKeyPrefix,
|
retryFailedPagesKeyPrefix,
|
||||||
} = userReaderStatePagesContext();
|
readingMode,
|
||||||
|
shouldOffsetDoubleSpreads,
|
||||||
|
readingDirection,
|
||||||
|
setScrollbarXSize,
|
||||||
|
setScrollbarYSize,
|
||||||
|
isVisible: isOverlayVisible,
|
||||||
|
setIsVisible: setIsOverlayVisible,
|
||||||
|
updateCurrentPageIndex,
|
||||||
|
}: Pick<
|
||||||
|
ReaderStatePages,
|
||||||
|
| 'currentPageIndex'
|
||||||
|
| 'pageToScrollToIndex'
|
||||||
|
| 'pages'
|
||||||
|
| 'setPages'
|
||||||
|
| 'totalPages'
|
||||||
|
| 'pageUrls'
|
||||||
|
| 'pageLoadStates'
|
||||||
|
| 'setPageLoadStates'
|
||||||
|
| 'transitionPageMode'
|
||||||
|
| 'retryFailedPagesKeyPrefix'
|
||||||
|
> &
|
||||||
|
Pick<IReaderSettings, 'readingMode' | 'shouldOffsetDoubleSpreads' | 'readingDirection'> &
|
||||||
|
Pick<TReaderScrollbarContext, 'setScrollbarXSize' | 'setScrollbarYSize'> &
|
||||||
|
Pick<TReaderOverlayContext, 'isVisible' | 'setIsVisible'> & {
|
||||||
|
updateCurrentPageIndex: ReturnType<typeof ReaderControls.useUpdateCurrentPageIndex>;
|
||||||
|
},
|
||||||
|
|
||||||
|
ref: ForwardedRef<HTMLDivElement | null>,
|
||||||
|
) => {
|
||||||
const { direction: themeDirection } = useTheme();
|
const { direction: themeDirection } = useTheme();
|
||||||
const { readingMode, shouldOffsetDoubleSpreads, readingDirection } = ReaderService.useSettings();
|
|
||||||
const { setScrollbarXSize, setScrollbarYSize } = useReaderScrollbarContext();
|
|
||||||
const { isVisible: isOverlayVisible, setIsVisible: setIsOverlayVisible } = useReaderOverlayContext();
|
|
||||||
const updateCurrentPageIndex = ReaderControls.useUpdateCurrentPageIndex();
|
|
||||||
|
|
||||||
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
||||||
useImperativeHandle(ref, () => scrollElementRef.current!);
|
useImperativeHandle(ref, () => scrollElementRef.current!);
|
||||||
|
|
||||||
const isContinuousReadingModeActive = isContinuousReadingMode(readingMode.value);
|
const isContinuousReadingModeActive = isContinuousReadingMode(readingMode);
|
||||||
const isDragging = useMouseDragScroll(isContinuousReadingModeActive ? scrollElementRef : undefined);
|
const isDragging = useMouseDragScroll(isContinuousReadingModeActive ? scrollElementRef : undefined);
|
||||||
|
|
||||||
const scrollbarXSize = MediaQuery.useGetScrollbarSize('width', scrollElementRef.current);
|
const scrollbarXSize = MediaQuery.useGetScrollbarSize('width', scrollElementRef.current);
|
||||||
@@ -86,7 +120,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
|
|
||||||
const handleClick = ReaderControls.useHandleClick(scrollElementRef.current);
|
const handleClick = ReaderControls.useHandleClick(scrollElementRef.current);
|
||||||
|
|
||||||
const [wasDoublePageMode, setWasDoublePageMode] = useState(readingMode.value === ReadingMode.DOUBLE_PAGE);
|
const [wasDoublePageMode, setWasDoublePageMode] = useState(readingMode === ReadingMode.DOUBLE_PAGE);
|
||||||
const [pagesToSpreadState, setPagesToSpreadState] = useState(Array(totalPages).fill(false));
|
const [pagesToSpreadState, setPagesToSpreadState] = useState(Array(totalPages).fill(false));
|
||||||
|
|
||||||
const imageRefs = useRef<(HTMLElement | null)[]>(pages.map(() => null));
|
const imageRefs = useRef<(HTMLElement | null)[]>(pages.map(() => null));
|
||||||
@@ -97,20 +131,20 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
return pages;
|
return pages;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readingMode.value === ReadingMode.DOUBLE_PAGE) {
|
if (readingMode === ReadingMode.DOUBLE_PAGE) {
|
||||||
return getDoublePageModePages(
|
return getDoublePageModePages(
|
||||||
pageUrls,
|
pageUrls,
|
||||||
pagesToSpreadState,
|
pagesToSpreadState,
|
||||||
shouldOffsetDoubleSpreads.value,
|
shouldOffsetDoubleSpreads,
|
||||||
readingDirection.value,
|
readingDirection,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
}, [pagesToSpreadState, readingMode.value, shouldOffsetDoubleSpreads.value, readingDirection.value]);
|
}, [pagesToSpreadState, readingMode, shouldOffsetDoubleSpreads, readingDirection]);
|
||||||
|
|
||||||
const Pager = useMemo(() => {
|
const Pager = useMemo(() => {
|
||||||
switch (readingMode.value) {
|
switch (readingMode) {
|
||||||
case ReadingMode.SINGLE_PAGE:
|
case ReadingMode.SINGLE_PAGE:
|
||||||
return ReaderPagedPager;
|
return ReaderPagedPager;
|
||||||
case ReadingMode.DOUBLE_PAGE:
|
case ReadingMode.DOUBLE_PAGE:
|
||||||
@@ -121,11 +155,11 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
case ReadingMode.CONTINUOUS_HORIZONTAL:
|
case ReadingMode.CONTINUOUS_HORIZONTAL:
|
||||||
return ReaderHorizontalPager;
|
return ReaderHorizontalPager;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unexpected "ReadingMode" (${readingMode.value})`);
|
throw new Error(`Unexpected "ReadingMode" (${readingMode})`);
|
||||||
}
|
}
|
||||||
}, [readingMode.value]);
|
}, [readingMode]);
|
||||||
|
|
||||||
const inViewportType = READING_MODE_TO_IN_VIEWPORT_TYPE[readingMode.value];
|
const inViewportType = READING_MODE_TO_IN_VIEWPORT_TYPE[readingMode];
|
||||||
|
|
||||||
// reset spread state
|
// reset spread state
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -134,7 +168,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
|
|
||||||
// optionally convert pages to normal or double page mode
|
// optionally convert pages to normal or double page mode
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const convertPagesToNormalPageMode = wasDoublePageMode && readingMode.value !== ReadingMode.DOUBLE_PAGE;
|
const convertPagesToNormalPageMode = wasDoublePageMode && readingMode !== ReadingMode.DOUBLE_PAGE;
|
||||||
if (convertPagesToNormalPageMode) {
|
if (convertPagesToNormalPageMode) {
|
||||||
setWasDoublePageMode(false);
|
setWasDoublePageMode(false);
|
||||||
setPages(createPagesData(pageUrls));
|
setPages(createPagesData(pageUrls));
|
||||||
@@ -142,15 +176,15 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const convertPagesToDoublePageMode = readingMode.value === ReadingMode.DOUBLE_PAGE;
|
const convertPagesToDoublePageMode = readingMode === ReadingMode.DOUBLE_PAGE;
|
||||||
if (convertPagesToDoublePageMode) {
|
if (convertPagesToDoublePageMode) {
|
||||||
if (!wasDoublePageMode) {
|
if (!wasDoublePageMode) {
|
||||||
updateCurrentPageIndex(getNextIndexFromPage(getPage(currentPageIndex, actualPages)));
|
updateCurrentPageIndex(getNextIndexFromPage(getPage(currentPageIndex, actualPages)));
|
||||||
}
|
}
|
||||||
setPages(actualPages);
|
setPages(actualPages);
|
||||||
setWasDoublePageMode(readingMode.value === ReadingMode.DOUBLE_PAGE);
|
setWasDoublePageMode(readingMode === ReadingMode.DOUBLE_PAGE);
|
||||||
}
|
}
|
||||||
}, [actualPages, readingMode.value]);
|
}, [actualPages, readingMode]);
|
||||||
|
|
||||||
// handle user page selection
|
// handle user page selection
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@@ -163,7 +197,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
|
|
||||||
imageRef?.scrollIntoView({
|
imageRef?.scrollIntoView({
|
||||||
block: 'start',
|
block: 'start',
|
||||||
inline: getScrollIntoViewInlineOption(directionOffset, themeDirection, readingDirection.value),
|
inline: getScrollIntoViewInlineOption(directionOffset, themeDirection, readingDirection),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +238,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
|
|
||||||
// invert x and y scrolling for the continuous horizontal reading mode
|
// invert x and y scrolling for the continuous horizontal reading mode
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (readingMode.value !== ReadingMode.CONTINUOUS_HORIZONTAL) {
|
if (readingMode !== ReadingMode.CONTINUOUS_HORIZONTAL) {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,13 +257,13 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
}
|
}
|
||||||
|
|
||||||
scrollElementRef.current?.scrollBy({
|
scrollElementRef.current?.scrollBy({
|
||||||
left: readingDirection.value === ReadingDirection.LTR ? e.deltaY : e.deltaY * -1,
|
left: readingDirection === ReadingDirection.LTR ? e.deltaY : e.deltaY * -1,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
scrollElementRef.current.addEventListener('wheel', handleScroll);
|
scrollElementRef.current.addEventListener('wheel', handleScroll);
|
||||||
return () => scrollElementRef.current?.removeEventListener('wheel', handleScroll);
|
return () => scrollElementRef.current?.removeEventListener('wheel', handleScroll);
|
||||||
}, [readingMode.value, readingDirection.value]);
|
}, [readingMode, readingDirection]);
|
||||||
|
|
||||||
// hide overlay on user triggered scroll
|
// hide overlay on user triggered scroll
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -254,7 +288,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
...applyStyles(isContinuousVerticalReadingMode(readingMode.value), { alignItems: 'center' }),
|
...applyStyles(isContinuousVerticalReadingMode(readingMode), { alignItems: 'center' }),
|
||||||
}}
|
}}
|
||||||
onClick={(e) => !isDragging && handleClick(e)}
|
onClick={(e) => !isDragging && handleClick(e)}
|
||||||
onScroll={() =>
|
onScroll={() =>
|
||||||
@@ -263,7 +297,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
totalPages - 1,
|
totalPages - 1,
|
||||||
updateCurrentPageIndex,
|
updateCurrentPageIndex,
|
||||||
inViewportType,
|
inViewportType,
|
||||||
readingDirection.value,
|
readingDirection,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -279,7 +313,7 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
const page = actualPages[pagesIndex];
|
const page = actualPages[pagesIndex];
|
||||||
const { index, url } = isPrimary ? page.primary : page.secondary!;
|
const { index, url } = isPrimary ? page.primary : page.secondary!;
|
||||||
|
|
||||||
if (readingMode.value === ReadingMode.DOUBLE_PAGE) {
|
if (readingMode === ReadingMode.DOUBLE_PAGE) {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
setPagesToSpreadState((prevState) => prevState.toSpliced(index, 1, isSpreadPage(img)));
|
setPagesToSpreadState((prevState) => prevState.toSpliced(index, 1, isSpreadPage(img)));
|
||||||
@@ -299,4 +333,36 @@ export const ReaderViewer = forwardRef((_, ref: ForwardedRef<HTMLDivElement | nu
|
|||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ReaderViewer = withPropsFrom(
|
||||||
|
BaseReaderViewer,
|
||||||
|
[
|
||||||
|
userReaderStatePagesContext,
|
||||||
|
ReaderService.useSettingsWithoutDefaultFlag,
|
||||||
|
useReaderScrollbarContext,
|
||||||
|
useReaderOverlayContext,
|
||||||
|
() => ({ updateCurrentPageIndex: ReaderControls.useUpdateCurrentPageIndex() }),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'currentPageIndex',
|
||||||
|
'pageToScrollToIndex',
|
||||||
|
'pages',
|
||||||
|
'setPages',
|
||||||
|
'totalPages',
|
||||||
|
'pageUrls',
|
||||||
|
'pageLoadStates',
|
||||||
|
'setPageLoadStates',
|
||||||
|
'transitionPageMode',
|
||||||
|
'retryFailedPagesKeyPrefix',
|
||||||
|
'readingMode',
|
||||||
|
'shouldOffsetDoubleSpreads',
|
||||||
|
'readingDirection',
|
||||||
|
'setScrollbarXSize',
|
||||||
|
'setScrollbarYSize',
|
||||||
|
'isVisible',
|
||||||
|
'setIsVisible',
|
||||||
|
'updateCurrentPageIndex',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -11,17 +11,27 @@ import Box, { BoxProps } from '@mui/material/Box';
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { getImageWidthStyling, getPageIndexesToLoad } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { getImageWidthStyling, getPageIndexesToLoad } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
import { ReaderPagerProps, ReaderTransitionPageMode } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ReaderPagerProps, ReaderTransitionPageMode } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { ReaderTransitionPage } from '@/modules/reader/components/viewer/ReaderTransitionPage.tsx';
|
import { ReaderTransitionPage } from '@/modules/reader/components/viewer/ReaderTransitionPage.tsx';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const BasePager = ({
|
const BaseBasePager = ({
|
||||||
currentPageIndex,
|
currentPageIndex,
|
||||||
pages,
|
pages,
|
||||||
transitionPageMode,
|
transitionPageMode,
|
||||||
imageRefs,
|
imageRefs,
|
||||||
createPage,
|
createPage,
|
||||||
slots,
|
slots,
|
||||||
}: Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix'> & {
|
readingMode,
|
||||||
|
pageScaleMode,
|
||||||
|
shouldStretchPage,
|
||||||
|
readerWidth,
|
||||||
|
imagePreLoadAmount,
|
||||||
|
}: Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix'> &
|
||||||
|
Pick<
|
||||||
|
IReaderSettings,
|
||||||
|
'readingMode' | 'pageScaleMode' | 'shouldStretchPage' | 'readerWidth' | 'imagePreLoadAmount'
|
||||||
|
> & {
|
||||||
createPage: (
|
createPage: (
|
||||||
page: ReaderStatePages['pages'][number],
|
page: ReaderStatePages['pages'][number],
|
||||||
pagesIndex: number,
|
pagesIndex: number,
|
||||||
@@ -30,10 +40,7 @@ export const BasePager = ({
|
|||||||
setRef: (element: HTMLElement | null) => void,
|
setRef: (element: HTMLElement | null) => void,
|
||||||
) => ReactNode;
|
) => ReactNode;
|
||||||
slots?: { boxProps?: BoxProps };
|
slots?: { boxProps?: BoxProps };
|
||||||
}) => {
|
}) => {
|
||||||
const { readingMode, pageScaleMode, shouldStretchPage, readerWidth, imagePreLoadAmount } =
|
|
||||||
ReaderService.useSettings();
|
|
||||||
|
|
||||||
const previousCurrentPageIndex = useRef(-1);
|
const previousCurrentPageIndex = useRef(-1);
|
||||||
const pagesIndexesToRender = useMemo(
|
const pagesIndexesToRender = useMemo(
|
||||||
() => getPageIndexesToLoad(currentPageIndex, pages, previousCurrentPageIndex.current, imagePreLoadAmount),
|
() => getPageIndexesToLoad(currentPageIndex, pages, previousCurrentPageIndex.current, imagePreLoadAmount),
|
||||||
@@ -48,20 +55,14 @@ export const BasePager = ({
|
|||||||
{...slots?.boxProps}
|
{...slots?.boxProps}
|
||||||
sx={[
|
sx={[
|
||||||
...(Array.isArray(slots?.boxProps?.sx) ? (slots?.boxProps?.sx ?? []) : [slots?.boxProps?.sx]),
|
...(Array.isArray(slots?.boxProps?.sx) ? (slots?.boxProps?.sx ?? []) : [slots?.boxProps?.sx]),
|
||||||
getImageWidthStyling(
|
getImageWidthStyling(readingMode, shouldStretchPage, pageScaleMode, false, readerWidth),
|
||||||
readingMode.value,
|
|
||||||
shouldStretchPage.value,
|
|
||||||
pageScaleMode.value,
|
|
||||||
false,
|
|
||||||
readerWidth.value,
|
|
||||||
),
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<ReaderTransitionPage
|
<ReaderTransitionPage
|
||||||
type={ReaderTransitionPageMode.PREVIOUS}
|
type={ReaderTransitionPageMode.PREVIOUS}
|
||||||
mode={transitionPageMode}
|
mode={transitionPageMode}
|
||||||
readingMode={readingMode.value}
|
readingMode={readingMode}
|
||||||
pageScaleMode={pageScaleMode.value}
|
pageScaleMode={pageScaleMode}
|
||||||
/>
|
/>
|
||||||
{pages.map((page, pagesIndex) =>
|
{pages.map((page, pagesIndex) =>
|
||||||
createPage(
|
createPage(
|
||||||
@@ -78,9 +79,15 @@ export const BasePager = ({
|
|||||||
<ReaderTransitionPage
|
<ReaderTransitionPage
|
||||||
type={ReaderTransitionPageMode.NEXT}
|
type={ReaderTransitionPageMode.NEXT}
|
||||||
mode={transitionPageMode}
|
mode={transitionPageMode}
|
||||||
readingMode={readingMode.value}
|
readingMode={readingMode}
|
||||||
pageScaleMode={pageScaleMode.value}
|
pageScaleMode={pageScaleMode}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const BasePager = withPropsFrom(
|
||||||
|
BaseBasePager,
|
||||||
|
[ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['readingMode', 'pageScaleMode', 'shouldStretchPage', 'readerWidth', 'imagePreLoadAmount'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ import { Direction, useTheme } from '@mui/material/styles';
|
|||||||
import { Fragment, useMemo } from 'react';
|
import { Fragment, useMemo } from 'react';
|
||||||
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { getNextIndexFromPage, getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
import { getNextIndexFromPage, getPage } from '@/modules/reader/utils/ReaderProgressBar.utils.tsx';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
const getPagePosition = (
|
const getPagePosition = (
|
||||||
pageType: 'first' | 'second',
|
pageType: 'first' | 'second',
|
||||||
@@ -37,20 +38,20 @@ const getPagePosition = (
|
|||||||
return isLtrReadingDirection ? 'right' : 'left';
|
return isLtrReadingDirection ? 'right' : 'left';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ReaderDoublePagedPager = ({
|
const BaseReaderDoublePagedPager = ({
|
||||||
onLoad,
|
onLoad,
|
||||||
onError,
|
onError,
|
||||||
pageLoadStates,
|
pageLoadStates,
|
||||||
retryFailedPagesKeyPrefix,
|
retryFailedPagesKeyPrefix,
|
||||||
|
readingDirection,
|
||||||
...props
|
...props
|
||||||
}: ReaderPagerProps) => {
|
}: ReaderPagerProps & Pick<IReaderSettings, 'readingDirection'>) => {
|
||||||
const { currentPageIndex, pages, totalPages } = props;
|
const { currentPageIndex, pages, totalPages } = props;
|
||||||
|
|
||||||
const { readingDirection } = ReaderService.useSettings();
|
|
||||||
const { direction: themeDirection } = useTheme();
|
const { direction: themeDirection } = useTheme();
|
||||||
|
|
||||||
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
||||||
const isLtrReadingDirection = readingDirection.value === ReadingDirection.LTR;
|
const isLtrReadingDirection = readingDirection === ReadingDirection.LTR;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePager
|
<BasePager
|
||||||
@@ -75,9 +76,7 @@ export const ReaderDoublePagedPager = ({
|
|||||||
currentPage.primary.index,
|
currentPage.primary.index,
|
||||||
totalPages,
|
totalPages,
|
||||||
pageLoadStates[primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
pageLoadStates[primary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
hasSecondaryPage
|
hasSecondaryPage ? getPagePosition('first', themeDirection, readingDirection) : undefined,
|
||||||
? getPagePosition('first', themeDirection, readingDirection.value)
|
|
||||||
: undefined,
|
|
||||||
hasSecondaryPage,
|
hasSecondaryPage,
|
||||||
)}
|
)}
|
||||||
{hasSecondaryPage &&
|
{hasSecondaryPage &&
|
||||||
@@ -90,7 +89,7 @@ export const ReaderDoublePagedPager = ({
|
|||||||
currentSecondaryPageIndex,
|
currentSecondaryPageIndex,
|
||||||
totalPages,
|
totalPages,
|
||||||
pageLoadStates[secondary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
pageLoadStates[secondary.index].error ? retryFailedPagesKeyPrefix : undefined,
|
||||||
getPagePosition('second', themeDirection, readingDirection.value),
|
getPagePosition('second', themeDirection, readingDirection),
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
@@ -115,3 +114,9 @@ export const ReaderDoublePagedPager = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderDoublePagedPager = withPropsFrom(
|
||||||
|
BaseReaderDoublePagedPager,
|
||||||
|
[ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['readingDirection'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -10,22 +10,24 @@ import { useTheme } from '@mui/material/styles';
|
|||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
||||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||||
import { ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, 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';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderHorizontalPager = ({
|
const BaseReaderHorizontalPager = ({
|
||||||
onLoad,
|
onLoad,
|
||||||
onError,
|
onError,
|
||||||
pageLoadStates,
|
pageLoadStates,
|
||||||
retryFailedPagesKeyPrefix,
|
retryFailedPagesKeyPrefix,
|
||||||
|
pageGap,
|
||||||
|
readingDirection,
|
||||||
...props
|
...props
|
||||||
}: ReaderPagerProps) => {
|
}: ReaderPagerProps & Pick<IReaderSettings, 'pageGap' | 'readingDirection'>) => {
|
||||||
const { currentPageIndex, totalPages } = props;
|
const { currentPageIndex, totalPages } = props;
|
||||||
|
|
||||||
const { pageGap, readingDirection } = ReaderService.useSettings();
|
|
||||||
const { direction: themeDirection } = useTheme();
|
const { direction: themeDirection } = useTheme();
|
||||||
|
|
||||||
const isLtrReadingDirection = readingDirection.value === ReadingDirection.LTR;
|
const isLtrReadingDirection = readingDirection === ReadingDirection.LTR;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePager
|
<BasePager
|
||||||
@@ -53,7 +55,7 @@ export const ReaderHorizontalPager = ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexWrap: 'nowrap',
|
flexWrap: 'nowrap',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
gap: `${pageGap.value}px`,
|
gap: `${pageGap}px`,
|
||||||
...applyStyles(themeDirection === 'ltr', {
|
...applyStyles(themeDirection === 'ltr', {
|
||||||
flexDirection: isLtrReadingDirection ? 'row' : 'row-reverse',
|
flexDirection: isLtrReadingDirection ? 'row' : 'row-reverse',
|
||||||
justifyContent: isLtrReadingDirection ? 'flex-start' : 'flex-end',
|
justifyContent: isLtrReadingDirection ? 'flex-start' : 'flex-end',
|
||||||
@@ -68,3 +70,9 @@ export const ReaderHorizontalPager = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderHorizontalPager = withPropsFrom(
|
||||||
|
BaseReaderHorizontalPager,
|
||||||
|
[ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['pageGap', 'readingDirection'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -7,22 +7,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
|
||||||
import { ReaderPagerProps, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
import { IReaderSettings, ReaderPagerProps, ReadingMode } 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';
|
||||||
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
|
||||||
export const ReaderVerticalPager = ({
|
const BaseReaderVerticalPager = ({
|
||||||
onLoad,
|
onLoad,
|
||||||
onError,
|
onError,
|
||||||
pageLoadStates,
|
pageLoadStates,
|
||||||
retryFailedPagesKeyPrefix,
|
retryFailedPagesKeyPrefix,
|
||||||
|
readingMode,
|
||||||
|
pageGap,
|
||||||
...props
|
...props
|
||||||
}: ReaderPagerProps) => {
|
}: ReaderPagerProps & Pick<IReaderSettings, 'pageGap' | 'readingMode'>) => {
|
||||||
const { currentPageIndex, totalPages } = props;
|
const { currentPageIndex, totalPages } = props;
|
||||||
|
|
||||||
const { readingMode, pageGap } = ReaderService.useSettings();
|
const isWebtoonMode = readingMode === ReadingMode.WEBTOON;
|
||||||
const isWebtoonMode = readingMode.value === ReadingMode.WEBTOON;
|
const actualPageGap = isWebtoonMode ? 0 : pageGap;
|
||||||
const actualPageGap = isWebtoonMode ? 0 : pageGap.value;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePager
|
<BasePager
|
||||||
@@ -46,3 +48,9 @@ export const ReaderVerticalPager = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReaderVerticalPager = withPropsFrom(
|
||||||
|
BaseReaderVerticalPager,
|
||||||
|
[ReaderService.useSettingsWithoutDefaultFlag],
|
||||||
|
['pageGap', 'readingMode'],
|
||||||
|
);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@@ -24,7 +24,6 @@ import { LoadingPlaceholder } from '@/modules/core/components/placeholder/Loadin
|
|||||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
||||||
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
|
||||||
import { GET_CHAPTERS_READER } from '@/lib/graphql/queries/ChapterQuery.ts';
|
import { GET_CHAPTERS_READER } from '@/lib/graphql/queries/ChapterQuery.ts';
|
||||||
import { Chapters } from '@/modules/chapter/services/Chapters.ts';
|
import { Chapters } from '@/modules/chapter/services/Chapters.ts';
|
||||||
import { DirectionOffset } from '@/Base.types.ts';
|
import { DirectionOffset } from '@/Base.types.ts';
|
||||||
@@ -38,38 +37,72 @@ import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
|
|||||||
import { READER_BACKGROUND_TO_COLOR } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
import { READER_BACKGROUND_TO_COLOR } from '@/modules/reader/constants/ReaderSettings.constants.tsx';
|
||||||
import { createPageData, createPagesData } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
import { createPageData, createPagesData } from '@/modules/reader/utils/ReaderPager.utils.tsx';
|
||||||
import { ReaderHotkeys } from '@/modules/reader/components/ReaderHotkeys.tsx';
|
import { ReaderHotkeys } from '@/modules/reader/components/ReaderHotkeys.tsx';
|
||||||
import { ReaderResumeMode, ReaderTransitionPageMode } from '@/modules/reader/types/Reader.types.ts';
|
import {
|
||||||
|
IReaderSettings,
|
||||||
|
ReaderResumeMode,
|
||||||
|
ReaderStateChapters,
|
||||||
|
ReaderTransitionPageMode,
|
||||||
|
TReaderStateMangaContext,
|
||||||
|
TReaderStateSettingsContext,
|
||||||
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { getInitialReaderPageIndex } from '@/modules/reader/utils/Reader.utils.ts';
|
import { getInitialReaderPageIndex } from '@/modules/reader/utils/Reader.utils.ts';
|
||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
|
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
|
||||||
|
import { TReaderOverlayContext } from '@/modules/reader/types/ReaderOverlay.types.ts';
|
||||||
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
|
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
||||||
|
|
||||||
export const Reader = () => {
|
const BaseReader = ({
|
||||||
const { t } = useTranslation();
|
setTitle,
|
||||||
const { setTitle, setOverride, readerNavBarWidth } = useNavBarContext();
|
setOverride,
|
||||||
const { isVisible: isOverlayVisible, setIsVisible: setIsOverlayVisible } = useReaderOverlayContext();
|
readerNavBarWidth,
|
||||||
const { manga, setManga } = useReaderStateMangaContext();
|
isVisible: isOverlayVisible,
|
||||||
const {
|
setIsVisible: setIsOverlayVisible,
|
||||||
settings: { shouldSkipDupChapters },
|
manga,
|
||||||
|
setManga,
|
||||||
|
shouldSkipDupChapters,
|
||||||
|
backgroundColor,
|
||||||
setSettings,
|
setSettings,
|
||||||
} = useReaderStateSettingsContext();
|
initialChapter,
|
||||||
const { initialChapter, currentChapter, chapters, setReaderStateChapters } = useReaderStateChaptersContext();
|
currentChapter,
|
||||||
const {
|
chapters,
|
||||||
|
setReaderStateChapters,
|
||||||
|
firstPageUrl,
|
||||||
|
totalPages,
|
||||||
setTotalPages,
|
setTotalPages,
|
||||||
setCurrentPageIndex,
|
setCurrentPageIndex,
|
||||||
setPageToScrollToIndex,
|
setPageToScrollToIndex,
|
||||||
pages,
|
|
||||||
setPages,
|
setPages,
|
||||||
setPageUrls,
|
setPageUrls,
|
||||||
setPageLoadStates,
|
setPageLoadStates,
|
||||||
setTransitionPageMode,
|
setTransitionPageMode,
|
||||||
} = userReaderStatePagesContext();
|
}: Pick<NavbarContextType, 'setTitle' | 'setOverride' | 'readerNavBarWidth'> &
|
||||||
|
Pick<TReaderOverlayContext, 'isVisible' | 'setIsVisible'> &
|
||||||
|
Pick<TReaderStateMangaContext, 'manga' | 'setManga'> &
|
||||||
|
Pick<TReaderStateSettingsContext, 'setSettings'> &
|
||||||
|
Pick<IReaderSettings, 'shouldSkipDupChapters' | 'backgroundColor'> &
|
||||||
|
Pick<ReaderStateChapters, 'initialChapter' | 'currentChapter' | 'chapters' | 'setReaderStateChapters'> &
|
||||||
|
Pick<
|
||||||
|
ReaderStatePages,
|
||||||
|
| 'totalPages'
|
||||||
|
| 'setTotalPages'
|
||||||
|
| 'setCurrentPageIndex'
|
||||||
|
| 'setPageToScrollToIndex'
|
||||||
|
| 'setPages'
|
||||||
|
| 'setPageUrls'
|
||||||
|
| 'setPageLoadStates'
|
||||||
|
| 'setTransitionPageMode'
|
||||||
|
> & {
|
||||||
|
firstPageUrl?: string;
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const { resumeMode } = useLocation<{
|
const { resumeMode } = useLocation<{
|
||||||
resumeMode: ReaderResumeMode;
|
resumeMode: ReaderResumeMode;
|
||||||
}>().state ?? { resumeMode: ReaderResumeMode.START };
|
}>().state ?? { resumeMode: ReaderResumeMode.START };
|
||||||
|
|
||||||
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { backgroundColor } = ReaderService.useSettings();
|
|
||||||
|
|
||||||
const { chapterIndex: paramChapterIndex, mangaId: paramMangaId } = useParams<{
|
const { chapterIndex: paramChapterIndex, mangaId: paramMangaId } = useParams<{
|
||||||
chapterIndex: string;
|
chapterIndex: string;
|
||||||
mangaId: string;
|
mangaId: string;
|
||||||
@@ -321,7 +354,7 @@ export const Reader = () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isPlaceholderPageState = pages.length === 1 && pages[0].primary.url === requestManager.getBaseUrl();
|
const isPlaceholderPageState = totalPages === 1 && firstPageUrl === requestManager.getBaseUrl();
|
||||||
if (isPlaceholderPageState) {
|
if (isPlaceholderPageState) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -350,3 +383,43 @@ export const Reader = () => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Reader = withPropsFrom(
|
||||||
|
memo(BaseReader),
|
||||||
|
[
|
||||||
|
useNavBarContext,
|
||||||
|
useReaderOverlayContext,
|
||||||
|
useReaderStateMangaContext,
|
||||||
|
useReaderStateChaptersContext,
|
||||||
|
useReaderStateSettingsContext,
|
||||||
|
ReaderService.useSettingsWithoutDefaultFlag,
|
||||||
|
userReaderStatePagesContext,
|
||||||
|
() => ({
|
||||||
|
firstPageUrl: userReaderStatePagesContext().pages[0].primary.url,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'setTitle',
|
||||||
|
'setOverride',
|
||||||
|
'readerNavBarWidth',
|
||||||
|
'isVisible',
|
||||||
|
'setIsVisible',
|
||||||
|
'manga',
|
||||||
|
'setManga',
|
||||||
|
'shouldSkipDupChapters',
|
||||||
|
'setSettings',
|
||||||
|
'initialChapter',
|
||||||
|
'currentChapter',
|
||||||
|
'chapters',
|
||||||
|
'setReaderStateChapters',
|
||||||
|
'firstPageUrl',
|
||||||
|
'totalPages',
|
||||||
|
'setTotalPages',
|
||||||
|
'setCurrentPageIndex',
|
||||||
|
'setPageToScrollToIndex',
|
||||||
|
'setPages',
|
||||||
|
'setPageUrls',
|
||||||
|
'setPageLoadStates',
|
||||||
|
'setTransitionPageMode',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|||||||
@@ -412,9 +412,9 @@ export class ReaderControls {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
clearTimeout(this.updateCurrentPageTimeout);
|
clearTimeout(ReaderControls.updateCurrentPageTimeout);
|
||||||
if (debounceChapterUpdate) {
|
if (debounceChapterUpdate) {
|
||||||
this.updateCurrentPageTimeout = setTimeout(handleCurrentPageIndexChange, 1000);
|
ReaderControls.updateCurrentPageTimeout = setTimeout(handleCurrentPageIndexChange, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,7 +480,7 @@ export class ReaderControls {
|
|||||||
break;
|
break;
|
||||||
case TapZoneRegionType.PREVIOUS:
|
case TapZoneRegionType.PREVIOUS:
|
||||||
if (isContinuousReadingModeActive) {
|
if (isContinuousReadingModeActive) {
|
||||||
this.scroll(
|
ReaderControls.scroll(
|
||||||
ScrollOffset.BACKWARD,
|
ScrollOffset.BACKWARD,
|
||||||
scrollDirection,
|
scrollDirection,
|
||||||
readingMode.value,
|
readingMode.value,
|
||||||
@@ -496,7 +496,7 @@ export class ReaderControls {
|
|||||||
break;
|
break;
|
||||||
case TapZoneRegionType.NEXT:
|
case TapZoneRegionType.NEXT:
|
||||||
if (isContinuousReadingModeActive) {
|
if (isContinuousReadingModeActive) {
|
||||||
this.scroll(
|
ReaderControls.scroll(
|
||||||
ScrollOffset.FORWARD,
|
ScrollOffset.FORWARD,
|
||||||
scrollDirection,
|
scrollDirection,
|
||||||
readingMode.value,
|
readingMode.value,
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ import {
|
|||||||
ReadingMode,
|
ReadingMode,
|
||||||
} from '@/modules/reader/types/Reader.types.ts';
|
} from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx';
|
||||||
import { updateReaderSettings } from '@/modules/reader/services/ReaderSettingsMetadata.ts';
|
import {
|
||||||
|
convertFromReaderSettingsWithDefaultFlag,
|
||||||
|
updateReaderSettings,
|
||||||
|
} from '@/modules/reader/services/ReaderSettingsMetadata.ts';
|
||||||
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
||||||
import { getMetadataKey } from '@/modules/metadata/services/MetadataReader.ts';
|
import { getMetadataKey } from '@/modules/metadata/services/MetadataReader.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
@@ -64,11 +67,11 @@ export class ReaderService {
|
|||||||
private static chapterUpdateQueues: Map<ChapterIdInfo['id'], Queue> = new Map();
|
private static chapterUpdateQueues: Map<ChapterIdInfo['id'], Queue> = new Map();
|
||||||
|
|
||||||
private static getOrCreateChapterUpdateQueue(id: ChapterIdInfo['id']): Queue {
|
private static getOrCreateChapterUpdateQueue(id: ChapterIdInfo['id']): Queue {
|
||||||
if (!this.chapterUpdateQueues.has(id)) {
|
if (!ReaderService.chapterUpdateQueues.has(id)) {
|
||||||
this.chapterUpdateQueues.set(id, new Queue(1));
|
ReaderService.chapterUpdateQueues.set(id, new Queue(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.chapterUpdateQueues.get(id)!;
|
return ReaderService.chapterUpdateQueues.get(id)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
static useNavigateToChapter(chapter?: TChapterReader, resumeMode?: ReaderResumeMode): () => void {
|
static useNavigateToChapter(chapter?: TChapterReader, resumeMode?: ReaderResumeMode): () => void {
|
||||||
@@ -95,7 +98,7 @@ export class ReaderService {
|
|||||||
): void {
|
): void {
|
||||||
const key = `${currentChapter.id}_${nextChapter?.id}_${pageIndex}_${downloadAheadLimit}`;
|
const key = `${currentChapter.id}_${nextChapter?.id}_${pageIndex}_${downloadAheadLimit}`;
|
||||||
|
|
||||||
this.downloadAheadQueue.enqueue(key, async () => {
|
ReaderService.downloadAheadQueue.enqueue(key, async () => {
|
||||||
const chapterIdsForDownloadAhead = getChapterIdsForDownloadAhead(
|
const chapterIdsForDownloadAhead = getChapterIdsForDownloadAhead(
|
||||||
currentChapter,
|
currentChapter,
|
||||||
nextChapter,
|
nextChapter,
|
||||||
@@ -119,7 +122,7 @@ export class ReaderService {
|
|||||||
static useUpdateChapter(): (patch: UpdateChapterPatchInput) => void {
|
static useUpdateChapter(): (patch: UpdateChapterPatchInput) => void {
|
||||||
const { manga } = useReaderStateMangaContext();
|
const { manga } = useReaderStateMangaContext();
|
||||||
const { initialChapter, currentChapter, mangaChapters } = useReaderStateChaptersContext();
|
const { initialChapter, currentChapter, mangaChapters } = useReaderStateChaptersContext();
|
||||||
const { shouldSkipDupChapters } = this.useSettings();
|
const { shouldSkipDupChapters } = ReaderService.useSettings();
|
||||||
const {
|
const {
|
||||||
settings: { deleteChaptersWhileReading, deleteChaptersWithBookmark, updateProgressAfterReading },
|
settings: { deleteChaptersWhileReading, deleteChaptersWithBookmark, updateProgressAfterReading },
|
||||||
} = useMetadataServerSettings();
|
} = useMetadataServerSettings();
|
||||||
@@ -193,7 +196,9 @@ export class ReaderService {
|
|||||||
.response.catch(defaultPromiseErrorHandler('ReaderService::useUpdateChapter'));
|
.response.catch(defaultPromiseErrorHandler('ReaderService::useUpdateChapter'));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getOrCreateChapterUpdateQueue(currentChapter.id).enqueue(`${currentChapter.id}`, () => update());
|
ReaderService.getOrCreateChapterUpdateQueue(currentChapter.id).enqueue(`${currentChapter.id}`, () =>
|
||||||
|
update(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
manga?.id,
|
manga?.id,
|
||||||
@@ -212,6 +217,10 @@ export class ReaderService {
|
|||||||
return useReaderStateSettingsContext().settings;
|
return useReaderStateSettingsContext().settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static useSettingsWithoutDefaultFlag(): IReaderSettings {
|
||||||
|
return convertFromReaderSettingsWithDefaultFlag(ReaderService.useSettings());
|
||||||
|
}
|
||||||
|
|
||||||
static useGetThemeDirection(): Direction {
|
static useGetThemeDirection(): Direction {
|
||||||
const { direction } = useTheme();
|
const { direction } = useTheme();
|
||||||
const { readingDirection } = ReaderService.useSettings();
|
const { readingDirection } = ReaderService.useSettings();
|
||||||
@@ -323,11 +332,11 @@ export class ReaderService {
|
|||||||
manga: MangaIdInfo,
|
manga: MangaIdInfo,
|
||||||
profile?: ReadingMode,
|
profile?: ReadingMode,
|
||||||
): (
|
): (
|
||||||
...args: OmitFirst<Parameters<typeof this.updateSetting<Setting>>>
|
...args: OmitFirst<Parameters<typeof ReaderService.updateSetting<Setting>>>
|
||||||
) => ReturnType<typeof this.updateSetting<Setting>> {
|
) => ReturnType<typeof ReaderService.updateSetting<Setting>> {
|
||||||
return useCallback(
|
return useCallback(
|
||||||
(setting, value, commit, isGlobal) =>
|
(setting, value, commit, isGlobal) =>
|
||||||
this.updateSetting<Setting>(manga, setting, value, commit, isGlobal, profile),
|
ReaderService.updateSetting<Setting>(manga, setting, value, commit, isGlobal, profile),
|
||||||
[manga, profile],
|
[manga, profile],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -336,17 +345,17 @@ export class ReaderService {
|
|||||||
manga: MangaIdInfo,
|
manga: MangaIdInfo,
|
||||||
profile?: ReadingMode,
|
profile?: ReadingMode,
|
||||||
): (
|
): (
|
||||||
...args: OmitFirst<Parameters<typeof this.deleteSetting<Setting>>>
|
...args: OmitFirst<Parameters<typeof ReaderService.deleteSetting<Setting>>>
|
||||||
) => ReturnType<typeof this.deleteSetting<Setting>> {
|
) => ReturnType<typeof ReaderService.deleteSetting<Setting>> {
|
||||||
return useCallback(
|
return useCallback(
|
||||||
(setting, isGlobal) => this.deleteSetting<Setting>(manga, setting, isGlobal, profile?.toString()),
|
(setting, isGlobal) => ReaderService.deleteSetting<Setting>(manga, setting, isGlobal, profile?.toString()),
|
||||||
[manga, profile],
|
[manga, profile],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static useOverlayMode(): { mode: ReaderOverlayMode; isDesktop: boolean; isMobile: boolean } {
|
static useOverlayMode(): { mode: ReaderOverlayMode; isDesktop: boolean; isMobile: boolean } {
|
||||||
const isTouchDevice = MediaQuery.useIsTouchDevice();
|
const isTouchDevice = MediaQuery.useIsTouchDevice();
|
||||||
const { overlayMode } = this.useSettings();
|
const { overlayMode } = ReaderService.useSettings();
|
||||||
|
|
||||||
const isAutoModeSelected = overlayMode === ReaderOverlayMode.AUTO;
|
const isAutoModeSelected = overlayMode === ReaderOverlayMode.AUTO;
|
||||||
const isDesktopModeSelected = overlayMode === ReaderOverlayMode.DESKTOP;
|
const isDesktopModeSelected = overlayMode === ReaderOverlayMode.DESKTOP;
|
||||||
@@ -364,7 +373,7 @@ export class ReaderService {
|
|||||||
|
|
||||||
static useExit(): () => void {
|
static useExit(): () => void {
|
||||||
const { manga } = useReaderStateMangaContext();
|
const { manga } = useReaderStateMangaContext();
|
||||||
const { exitMode } = this.useSettings();
|
const { exitMode } = ReaderService.useSettings();
|
||||||
const handleBack = useBackButton();
|
const handleBack = useBackButton();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user