Move reader "auto-scroll state" to "reader store"

This commit is contained in:
schroda
2025-08-31 22:39:30 +02:00
parent e68cb65874
commit dabe50754f
13 changed files with 206 additions and 117 deletions

View File

@@ -10,9 +10,7 @@ import { MutableRefObject } from 'react';
import { TapZoneInvertMode, TapZoneLayouts } from '@/features/reader/tap-zones/TapZoneLayout.types.ts'; import { TapZoneInvertMode, TapZoneLayouts } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
import { TChapterReader } from '@/features/chapter/Chapter.types.ts'; import { TChapterReader } from '@/features/chapter/Chapter.types.ts';
import { ReaderService } from '@/features/reader/services/ReaderService.ts'; import { ReaderService } from '@/features/reader/services/ReaderService.ts';
import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts';
import { ScrollOffset } from '@/base/Base.types.ts';
export enum ProgressBarType { export enum ProgressBarType {
HIDDEN, HIDDEN,
@@ -374,11 +372,4 @@ export type TReaderStateSettingsContext = {
setSettings: (settings: IReaderSettingsWithDefaultFlag) => void; setSettings: (settings: IReaderSettingsWithDefaultFlag) => void;
}; };
export type TReaderAutoScrollContext = ReturnType<typeof useAutomaticScrolling> & {
isActive: boolean;
scrollRef?: MutableRefObject<HTMLElement | null> | (() => void);
setScrollRef: (scrollRef?: MutableRefObject<HTMLElement | null>) => void;
setDirection: (direction: ScrollOffset) => void;
};
export type ReaderPageSpreadState = { url: string; isSpread: boolean }; export type ReaderPageSpreadState = { url: string; isSpread: boolean };

View File

@@ -14,8 +14,12 @@ import {
createReaderOverlayStoreSlice, createReaderOverlayStoreSlice,
ReaderOverlayStoreSlice, ReaderOverlayStoreSlice,
} from '@/features/reader/overlay/ReaderOverlayStore.ts'; } from '@/features/reader/overlay/ReaderOverlayStore.ts';
import {
createReaderAutoScrollStoreSlice,
ReaderAutoScrollStoreSlice,
} from '@/features/reader/auto-scroll/ReaderAutoScrollStore.ts';
interface ReaderStore extends ReaderOverlayStoreSlice { interface ReaderStore extends ReaderOverlayStoreSlice, ReaderAutoScrollStoreSlice {
reset: () => void; reset: () => void;
manga: TMangaReader | undefined; manga: TMangaReader | undefined;
setManga: (manga: TMangaReader | undefined) => void; setManga: (manga: TMangaReader | undefined) => void;
@@ -43,6 +47,7 @@ export const useReaderStore = create<ReaderStore>()(
draft.manga = DEFAULT_STATE.manga; draft.manga = DEFAULT_STATE.manga;
draft.scrollbar = { ...get().scrollbar, ...DEFAULT_STATE.scrollbar }; draft.scrollbar = { ...get().scrollbar, ...DEFAULT_STATE.scrollbar };
get().overlay.reset(); get().overlay.reset();
get().autoScroll.reset();
}), }),
setManga: (manga) => setManga: (manga) =>
set((draft) => { set((draft) => {
@@ -60,6 +65,7 @@ export const useReaderStore = create<ReaderStore>()(
}), }),
}, },
...createReaderOverlayStoreSlice(set, get, store), ...createReaderOverlayStoreSlice(set, get, store),
...createReaderAutoScrollStoreSlice(set, get, store),
})), })),
); );
export const useReaderStoreShallow = <T>(selector: (state: ReaderStore) => T): T => export const useReaderStoreShallow = <T>(selector: (state: ReaderStore) => T): T =>

View File

@@ -6,14 +6,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
import { createContext, memo, ReactNode, useCallback, useContext, useMemo, useState } from 'react'; import { memo, useCallback, useEffect } from 'react';
import { Direction, useTheme } from '@mui/material/styles'; import { Direction, useTheme } from '@mui/material/styles';
import { import { IReaderSettings, ReaderScrollAmount, ReadingMode } from '@/features/reader/Reader.types.ts';
IReaderSettings,
ReaderScrollAmount,
ReadingMode,
TReaderAutoScrollContext,
} from '@/features/reader/Reader.types.ts';
import { ReaderControls } from '@/features/reader/services/ReaderControls.ts'; import { ReaderControls } from '@/features/reader/services/ReaderControls.ts';
import { ScrollOffset } from '@/base/Base.types.ts'; import { ScrollOffset } from '@/base/Base.types.ts';
import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts'; import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts';
@@ -22,36 +17,23 @@ import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
import { CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION } from '@/features/reader/settings/ReaderSettings.constants.tsx'; import { CONTINUOUS_READING_MODE_TO_SCROLL_DIRECTION } from '@/features/reader/settings/ReaderSettings.constants.tsx';
import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx';
import { ReaderService } from '@/features/reader/services/ReaderService.ts'; import { ReaderService } from '@/features/reader/services/ReaderService.ts';
import { getReaderStore, useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
export const ReaderAutoScrollContext = createContext<TReaderAutoScrollContext>({ const BaseReaderAutoScroll = ({
isActive: false,
isPaused: false,
setScrollRef: () => {},
start: () => {},
cancel: () => {},
toggleActive: () => {},
pause: () => {},
resume: () => {},
setDirection: () => {},
});
export const useReaderAutoScrollContext = () => useContext(ReaderAutoScrollContext);
const BaseReaderAutoScrollContextProvider = ({
children,
openPage, openPage,
readingMode, readingMode,
autoScroll, autoScroll,
themeDirection, themeDirection,
combinedDirection, combinedDirection,
}: Pick<IReaderSettings, 'readingMode' | 'autoScroll'> & { }: Pick<IReaderSettings, 'readingMode' | 'autoScroll'> & {
children: ReactNode;
openPage: ReturnType<typeof ReaderControls.useOpenPage>; openPage: ReturnType<typeof ReaderControls.useOpenPage>;
themeDirection: Direction; themeDirection: Direction;
combinedDirection: Direction; combinedDirection: Direction;
}) => { }) => {
const [scrollRef, setScrollRef] = useState<TReaderAutoScrollContext['scrollRef']>(); const { scrollRef, direction } = useReaderStoreShallow((state) => ({
const [direction, setDirection] = useState<ScrollOffset>(ScrollOffset.FORWARD); scrollRef: state.autoScroll.scrollRef,
direction: state.autoScroll.direction,
}));
const isScrollingInvertedBasedOnReadingDirection = const isScrollingInvertedBasedOnReadingDirection =
readingMode === ReadingMode.CONTINUOUS_HORIZONTAL && themeDirection !== combinedDirection; readingMode === ReadingMode.CONTINUOUS_HORIZONTAL && themeDirection !== combinedDirection;
@@ -77,21 +59,23 @@ const BaseReaderAutoScrollContextProvider = ({
autoScroll.smooth, autoScroll.smooth,
); );
const value = useMemo( useEffect(() => {
() => ({ const autoScrollStore = getReaderStore().autoScroll;
scrollRef,
setScrollRef,
setDirection,
...automaticScrolling,
}),
[scrollRef, automaticScrolling],
);
return <ReaderAutoScrollContext.Provider value={value}>{children}</ReaderAutoScrollContext.Provider>; autoScrollStore.setIsActive(automaticScrolling.isActive);
autoScrollStore.setIsPaused(automaticScrolling.isPaused);
autoScrollStore.setStart(automaticScrolling.start);
autoScrollStore.setCancel(automaticScrolling.cancel);
autoScrollStore.setToggleActive(automaticScrolling.toggleActive);
autoScrollStore.setPause(automaticScrolling.pause);
autoScrollStore.setResume(automaticScrolling.resume);
}, [automaticScrolling]);
return null;
}; };
export const ReaderAutoScrollContextProvider = withPropsFrom( export const ReaderAutoScroll = withPropsFrom(
memo(BaseReaderAutoScrollContextProvider), memo(BaseReaderAutoScroll),
[ [
ReaderService.useSettingsWithoutDefaultFlag, ReaderService.useSettingsWithoutDefaultFlag,
() => ({ openPage: ReaderControls.useOpenPage() }), () => ({ openPage: ReaderControls.useOpenPage() }),

View File

@@ -0,0 +1,119 @@
/*
* 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 { createRef, MutableRefObject } from 'react';
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
import { ScrollOffset } from '@/base/Base.types.ts';
import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
import { noOp } from '@/lib/HelperFunctions.ts';
export interface ReaderAutoScrollStoreSlice {
autoScroll: ReturnType<typeof useAutomaticScrolling> & {
setIsActive: (active: boolean) => void;
setIsPaused: (paused: boolean) => void;
scrollRef?: MutableRefObject<HTMLElement | null>;
setScrollRef: (scrollElement: HTMLElement | null) => void;
setDirection: (direction: ScrollOffset) => void;
setStart: (start: () => void) => void;
setCancel: (cancel: () => void) => void;
setToggleActive: (toggleActive: () => void) => void;
setPause: (pause: () => void) => void;
setResume: (resume: () => void) => void;
invert: boolean;
setInvert: (invert: boolean) => void;
direction: ScrollOffset;
reset: () => void;
};
}
const DEFAULT_STATE = {
isActive: false,
isPaused: false,
start: noOp,
cancel: noOp,
toggleActive: noOp,
pause: noOp,
resume: noOp,
invert: false,
direction: ScrollOffset.FORWARD,
scrollRef: undefined,
} satisfies Omit<
ReaderAutoScrollStoreSlice['autoScroll'],
| 'setIsActive'
| 'setIsPaused'
| 'setStart'
| 'setCancel'
| 'setToggleActive'
| 'setPause'
| 'setResume'
| 'setInvert'
| 'setDirection'
| 'setScrollRef'
| 'reset'
>;
export const createReaderAutoScrollStoreSlice = <T extends ReaderAutoScrollStoreSlice>(
...[set, get]: Parameters<ImmerStateCreator<T>>
): ReaderAutoScrollStoreSlice =>
({
autoScroll: {
...DEFAULT_STATE,
reset: () =>
set((draft) => {
draft.autoScroll = { ...get().autoScroll, ...DEFAULT_STATE };
}),
setIsActive: (active) =>
set((draft) => {
draft.autoScroll.isActive = active;
}),
setIsPaused: (paused) =>
set((draft) => {
draft.autoScroll.isPaused = paused;
}),
setStart: (start) =>
set((draft) => {
draft.autoScroll.start = start;
}),
setCancel: (cancel) =>
set((draft) => {
draft.autoScroll.cancel = cancel;
}),
setToggleActive: (toggleActive) =>
set((draft) => {
draft.autoScroll.toggleActive = toggleActive;
}),
setPause: (pause) =>
set((draft) => {
draft.autoScroll.pause = pause;
}),
setResume: (resume) =>
set((draft) => {
draft.autoScroll.resume = resume;
}),
setInvert: (invert) =>
set((draft) => {
draft.autoScroll.invert = invert;
}),
setDirection: (direction) =>
set((draft) => {
draft.autoScroll.direction = direction;
}),
setScrollRef: (scrollElement) =>
set((draft) => {
if (!scrollElement) {
draft.autoScroll.scrollRef = undefined;
return;
}
const ref = createRef() as MutableRefObject<HTMLElement | null>;
ref.current = scrollElement;
// @ts-expect-error - TS2322: Type MutableRefObject<HTMLElement | null> is not assignable to type WritableDraft<MutableRefObject<HTMLElement | null>>
draft.autoScroll.scrollRef = ref;
}),
},
}) satisfies ReaderAutoScrollStoreSlice;

View File

@@ -7,20 +7,21 @@
*/ */
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
import { IReaderSettings } from '@/features/reader/Reader.types.ts'; import { IReaderSettings } from '@/features/reader/Reader.types.ts';
export const useReaderAutoScroll = ( export const useReaderAutoScroll = (
isOverlayVisible: boolean, isOverlayVisible: boolean,
automaticScrolling: ReturnType<typeof useAutomaticScrolling>, isAutoScrollPaused: boolean,
pauseAutoScroll: () => void,
resumeAutoScroll: () => void,
isStaticNav: IReaderSettings['isStaticNav'], isStaticNav: IReaderSettings['isStaticNav'],
): void => { ): void => {
useEffect(() => { useEffect(() => {
if (isOverlayVisible && !isStaticNav) { if (isOverlayVisible && !isStaticNav) {
automaticScrolling.pause(); pauseAutoScroll();
return; return;
} }
automaticScrolling.resume(); resumeAutoScroll();
}, [isOverlayVisible, automaticScrolling.isPaused, isStaticNav]); }, [isOverlayVisible, isAutoScrollPaused, isStaticNav]);
}; };

View File

@@ -14,10 +14,10 @@ import Stack from '@mui/material/Stack';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment'; import InputAdornment from '@mui/material/InputAdornment';
import { useRef } from 'react'; import { useRef } from 'react';
import { useReaderAutoScrollContext } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx';
import { IReaderSettings } from '@/features/reader/Reader.types.ts'; import { IReaderSettings } from '@/features/reader/Reader.types.ts';
import { AUTO_SCROLL_SPEED } from '@/features/reader/settings/ReaderSettings.constants.tsx'; import { AUTO_SCROLL_SPEED } from '@/features/reader/settings/ReaderSettings.constants.tsx';
import { coerceIn } from '@/lib/HelperFunctions.ts'; import { coerceIn } from '@/lib/HelperFunctions.ts';
import { useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
export const ReaderNavBarDesktopAutoScroll = ({ export const ReaderNavBarDesktopAutoScroll = ({
autoScroll, autoScroll,
@@ -26,7 +26,10 @@ export const ReaderNavBarDesktopAutoScroll = ({
setAutoScroll: (newAutoScroll: IReaderSettings['autoScroll'], commit: boolean) => void; setAutoScroll: (newAutoScroll: IReaderSettings['autoScroll'], commit: boolean) => void;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { isActive, toggleActive } = useReaderAutoScrollContext(); const { isActive, toggleActive } = useReaderStoreShallow((state) => ({
isActive: state.autoScroll.isActive,
toggleActive: state.autoScroll.toggleActive,
}));
const updateTimeout = useRef<NodeJS.Timeout>(undefined); const updateTimeout = useRef<NodeJS.Timeout>(undefined);

View File

@@ -8,16 +8,13 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { ReaderStateContextProvider } from '@/features/reader/contexts/state/ReaderStateContextProvider.tsx'; import { ReaderStateContextProvider } from '@/features/reader/contexts/state/ReaderStateContextProvider.tsx';
import { ReaderAutoScrollContextProvider } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx';
import { ReaderProgressBarContextProvider } from '@/features/reader/overlay/progress-bar/ReaderProgressBarContext.tsx'; import { ReaderProgressBarContextProvider } from '@/features/reader/overlay/progress-bar/ReaderProgressBarContext.tsx';
import { ReaderTapZoneContextProvider } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx'; import { ReaderTapZoneContextProvider } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx';
export const ReaderContextProvider = ({ children }: { children?: ReactNode }) => ( export const ReaderContextProvider = ({ children }: { children?: ReactNode }) => (
<ReaderStateContextProvider> <ReaderStateContextProvider>
<ReaderTapZoneContextProvider> <ReaderTapZoneContextProvider>
<ReaderProgressBarContextProvider> <ReaderProgressBarContextProvider>{children}</ReaderProgressBarContextProvider>
<ReaderAutoScrollContextProvider>{children}</ReaderAutoScrollContextProvider>
</ReaderProgressBarContextProvider>
</ReaderTapZoneContextProvider> </ReaderTapZoneContextProvider>
</ReaderStateContextProvider> </ReaderStateContextProvider>
); );

View File

@@ -12,7 +12,6 @@ import {
ReaderStateChapters, ReaderStateChapters,
ReaderStatePages, ReaderStatePages,
ReaderTransitionPageMode, ReaderTransitionPageMode,
TReaderAutoScrollContext,
TReaderStateSettingsContext, TReaderStateSettingsContext,
} from '@/features/reader/Reader.types.ts'; } from '@/features/reader/Reader.types.ts';
import { DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG } from '@/features/reader/settings/ReaderSettingsMetadata.ts'; import { DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG } from '@/features/reader/settings/ReaderSettingsMetadata.ts';
@@ -29,7 +28,6 @@ export const useReaderResetStates = (
setPageLoadStates: ReaderStatePages['setPageLoadStates'], setPageLoadStates: ReaderStatePages['setPageLoadStates'],
setTransitionPageMode: ReaderStatePages['setTransitionPageMode'], setTransitionPageMode: ReaderStatePages['setTransitionPageMode'],
setSettings: TReaderStateSettingsContext['setSettings'], setSettings: TReaderStateSettingsContext['setSettings'],
cancelAutoScroll: TReaderAutoScrollContext['cancel'],
) => { ) => {
useEffect( useEffect(
() => () => { () => () => {
@@ -45,8 +43,6 @@ export const useReaderResetStates = (
setTransitionPageMode(ReaderTransitionPageMode.NONE); setTransitionPageMode(ReaderTransitionPageMode.NONE);
setSettings(DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG); setSettings(DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG);
cancelAutoScroll();
}, },
[], [],
); );

View File

@@ -24,7 +24,6 @@ import { HotkeyScope } from '@/features/hotkeys/Hotkeys.types.ts';
import { ReaderControls } from '@/features/reader/services/ReaderControls.ts'; import { ReaderControls } from '@/features/reader/services/ReaderControls.ts';
import { ScrollOffset } from '@/base/Base.types.ts'; import { ScrollOffset } from '@/base/Base.types.ts';
import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts'; import { getOptionForDirection } from '@/features/theme/services/ThemeCreator.ts';
import { useReaderAutoScrollContext } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx';
import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx'; import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx';
import { getReaderStore } from '@/features/reader/ReaderStore.ts'; import { getReaderStore } from '@/features/reader/ReaderStore.ts';
@@ -74,7 +73,6 @@ export const ReaderHotkeys = ({
autoScroll, autoScroll,
scrollAmount, scrollAmount,
} = ReaderService.useSettings(); } = ReaderService.useSettings();
const automaticScrolling = useReaderAutoScrollContext();
const { setShowPreview } = useReaderTapZoneContext(); const { setShowPreview } = useReaderTapZoneContext();
const exitReader = ReaderService.useExit(); const exitReader = ReaderService.useExit();
@@ -86,6 +84,8 @@ export const ReaderHotkeys = ({
useHotkeys( useHotkeys(
hotkeys[ReaderHotkey.SCROLL_BACKWARD], hotkeys[ReaderHotkey.SCROLL_BACKWARD],
() => { () => {
const automaticScrolling = getReaderStore().autoScroll;
if (automaticScrolling.isActive) { if (automaticScrolling.isActive) {
automaticScrolling.setDirection(ScrollOffset.BACKWARD); automaticScrolling.setDirection(ScrollOffset.BACKWARD);
return; return;
@@ -108,18 +108,13 @@ export const ReaderHotkeys = ({
); );
}, },
{ preventDefault: true }, { preventDefault: true },
[ [readingMode.value, readingDirection.value, themeDirection, openChapter, scrollAmount],
readingMode.value,
readingDirection.value,
themeDirection,
openChapter,
scrollAmount,
automaticScrolling.isActive,
],
); );
useHotkeys( useHotkeys(
hotkeys[ReaderHotkey.SCROLL_FORWARD], hotkeys[ReaderHotkey.SCROLL_FORWARD],
() => { () => {
const automaticScrolling = getReaderStore().autoScroll;
if (automaticScrolling.isActive) { if (automaticScrolling.isActive) {
automaticScrolling.setDirection(ScrollOffset.FORWARD); automaticScrolling.setDirection(ScrollOffset.FORWARD);
return; return;
@@ -142,14 +137,7 @@ export const ReaderHotkeys = ({
); );
}, },
{ preventDefault: true }, { preventDefault: true },
[ [readingMode.value, readingDirection.value, themeDirection, openChapter, scrollAmount],
readingMode.value,
readingDirection.value,
themeDirection,
openChapter,
scrollAmount,
automaticScrolling.isActive,
],
); );
useHotkeys( useHotkeys(
hotkeys[ReaderHotkey.PREVIOUS_CHAPTER], hotkeys[ReaderHotkey.PREVIOUS_CHAPTER],
@@ -213,9 +201,9 @@ export const ReaderHotkeys = ({
}, },
[readingDirection.value, readingDirection.isDefault], [readingDirection.value, readingDirection.isDefault],
); );
useHotkeys(hotkeys[ReaderHotkey.TOGGLE_AUTO_SCROLL], automaticScrolling.toggleActive, { preventDefault: true }, [ useHotkeys(hotkeys[ReaderHotkey.TOGGLE_AUTO_SCROLL], () => getReaderStore().autoScroll.toggleActive(), {
automaticScrolling.toggleActive, preventDefault: true,
]); });
useHotkeys( useHotkeys(
hotkeys[ReaderHotkey.AUTO_SCROLL_SPEED_DECREASE], hotkeys[ReaderHotkey.AUTO_SCROLL_SPEED_DECREASE],
() => () =>

View File

@@ -22,14 +22,13 @@ const DEFAULT_STATE = {
export const createReaderOverlayStoreSlice = <T extends ReaderOverlayStoreSlice>( export const createReaderOverlayStoreSlice = <T extends ReaderOverlayStoreSlice>(
...[set, get]: Parameters<ImmerStateCreator<T>> ...[set, get]: Parameters<ImmerStateCreator<T>>
): ReaderOverlayStoreSlice => ): ReaderOverlayStoreSlice => ({
({ overlay: {
overlay: { isVisible: DEFAULT_STATE.isVisible,
isVisible: DEFAULT_STATE.isVisible, setIsVisible: (visible) =>
setIsVisible: (visible) => set((draft) => {
set((draft) => { draft.overlay.isVisible = visible;
draft.overlay.isVisible = visible; }),
}), reset: () => set(() => ({ overlay: { ...get().overlay, ...DEFAULT_STATE } })),
reset: () => set(() => ({ overlay: { ...get().overlay, ...DEFAULT_STATE } })), },
}, });
}) as T;

View File

@@ -13,21 +13,22 @@ import { ReaderSettingReadingMode } from '@/features/reader/settings/layout/comp
import { ReaderSettingReadingDirection } from '@/features/reader/settings/layout/components/ReaderSettingReadingDirection.tsx'; import { ReaderSettingReadingDirection } from '@/features/reader/settings/layout/components/ReaderSettingReadingDirection.tsx';
import { ReaderService } from '@/features/reader/services/ReaderService.ts'; import { ReaderService } from '@/features/reader/services/ReaderService.ts';
import { DefaultSettingFootnote } from '@/features/reader/settings/components/DefaultSettingFootnote.tsx'; import { DefaultSettingFootnote } from '@/features/reader/settings/components/DefaultSettingFootnote.tsx';
import { IReaderSettingsWithDefaultFlag, TReaderAutoScrollContext } from '@/features/reader/Reader.types.ts'; import { IReaderSettingsWithDefaultFlag } from '@/features/reader/Reader.types.ts';
import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx';
import { ReaderSettingAutoScroll } from '@/features/reader/auto-scroll/settings/ReaderSettingAutoScroll.tsx'; import { ReaderSettingAutoScroll } from '@/features/reader/auto-scroll/settings/ReaderSettingAutoScroll.tsx';
import { CheckboxInput } from '@/base/components/inputs/CheckboxInput.tsx'; import { CheckboxInput } from '@/base/components/inputs/CheckboxInput.tsx';
import { useReaderAutoScrollContext } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx'; import { useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
const BaseReaderBottomBarMobileQuickSettings = ({ const BaseReaderBottomBarMobileQuickSettings = ({
readingMode, readingMode,
readingDirection, readingDirection,
autoScroll, autoScroll,
isActive, }: Pick<IReaderSettingsWithDefaultFlag, 'readingMode' | 'readingDirection' | 'autoScroll'>) => {
toggleActive,
}: Pick<IReaderSettingsWithDefaultFlag, 'readingMode' | 'readingDirection' | 'autoScroll'> &
Pick<TReaderAutoScrollContext, 'isActive' | 'toggleActive'>) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { isActive, toggleActive } = useReaderStoreShallow((state) => ({
isActive: state.autoScroll.isActive,
toggleActive: state.autoScroll.toggleActive,
}));
return ( return (
<Stack sx={{ gap: 2 }}> <Stack sx={{ gap: 2 }}>
@@ -59,6 +60,6 @@ const BaseReaderBottomBarMobileQuickSettings = ({
export const ReaderBottomBarMobileQuickSettings = withPropsFrom( export const ReaderBottomBarMobileQuickSettings = withPropsFrom(
memo(BaseReaderBottomBarMobileQuickSettings), memo(BaseReaderBottomBarMobileQuickSettings),
[ReaderService.useSettings, useReaderAutoScrollContext], [ReaderService.useSettings],
['readingMode', 'readingDirection', 'autoScroll', 'isActive', 'toggleActive'], ['readingMode', 'readingDirection', 'autoScroll'],
); );

View File

@@ -33,14 +33,12 @@ import {
IReaderSettingsWithDefaultFlag, IReaderSettingsWithDefaultFlag,
ReaderStateChapters, ReaderStateChapters,
ReaderStatePages, ReaderStatePages,
TReaderAutoScrollContext,
TReaderStateSettingsContext, TReaderStateSettingsContext,
} from '@/features/reader/Reader.types.ts'; } from '@/features/reader/Reader.types.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts'; import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types.ts';
import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx';
import { useReaderStateChaptersContext } from '@/features/reader/contexts/state/ReaderStateChaptersContext.tsx'; import { useReaderStateChaptersContext } from '@/features/reader/contexts/state/ReaderStateChaptersContext.tsx';
import { useReaderAutoScrollContext } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx';
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts'; import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx'; import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx';
import { useReaderResetStates } from '@/features/reader/hooks/useReaderResetStates.ts'; import { useReaderResetStates } from '@/features/reader/hooks/useReaderResetStates.ts';
@@ -51,6 +49,7 @@ import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
import { useChapterListOptions } from '@/features/chapter/utils/ChapterList.util.tsx'; import { useChapterListOptions } from '@/features/chapter/utils/ChapterList.util.tsx';
import { FALLBACK_MANGA } from '@/features/manga/Manga.constants.ts'; import { FALLBACK_MANGA } from '@/features/manga/Manga.constants.ts';
import { useReaderStore, useReaderStoreShallow } from '@/features/reader/ReaderStore.ts'; import { useReaderStore, useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
import { ReaderAutoScroll } from '@/features/reader/auto-scroll/ReaderAutoScroll.tsx';
const BaseReader = ({ const BaseReader = ({
setOverride, setOverride,
@@ -76,7 +75,6 @@ const BaseReader = ({
setPageUrls, setPageUrls,
setPageLoadStates, setPageLoadStates,
setTransitionPageMode, setTransitionPageMode,
cancelAutoScroll,
setShowPreview, setShowPreview,
}: Pick<NavbarContextType, 'setOverride' | 'readerNavBarWidth'> & }: Pick<NavbarContextType, 'setOverride' | 'readerNavBarWidth'> &
Pick<TReaderStateSettingsContext, 'setSettings'> & Pick<TReaderStateSettingsContext, 'setSettings'> &
@@ -107,9 +105,7 @@ const BaseReader = ({
| 'setPageLoadStates' | 'setPageLoadStates'
| 'setTransitionPageMode' | 'setTransitionPageMode'
> & > &
Pick<TReaderTapZoneContext, 'setShowPreview'> & { Pick<TReaderTapZoneContext, 'setShowPreview'>) => {
cancelAutoScroll: TReaderAutoScrollContext['cancel'];
}) => {
const { t } = useTranslation(); const { t } = useTranslation();
const manga = useReaderStoreShallow((state) => state.manga); const manga = useReaderStoreShallow((state) => state.manga);
const overlay = useReaderStoreShallow((state) => state.overlay); const overlay = useReaderStoreShallow((state) => state.overlay);
@@ -163,7 +159,6 @@ const BaseReader = ({
setPageLoadStates, setPageLoadStates,
setTransitionPageMode, setTransitionPageMode,
setSettings, setSettings,
cancelAutoScroll,
); );
useReaderSetSettingsState( useReaderSetSettingsState(
mangaResponse, mangaResponse,
@@ -288,6 +283,7 @@ const BaseReader = ({
<ReaderViewer ref={scrollElementRef} /> <ReaderViewer ref={scrollElementRef} />
<TapZoneLayout /> <TapZoneLayout />
<ReaderRGBAFilter /> <ReaderRGBAFilter />
<ReaderAutoScroll />
</Box> </Box>
); );
}; };
@@ -319,7 +315,6 @@ export const Reader = withPropsFrom(
return { readingMode, tapZoneLayout, tapZoneInvertMode }; return { readingMode, tapZoneLayout, tapZoneInvertMode };
}, },
userReaderStatePagesContext, userReaderStatePagesContext,
() => ({ cancelAutoScroll: useReaderAutoScrollContext().cancel }),
useReaderTapZoneContext, useReaderTapZoneContext,
], ],
[ [
@@ -346,7 +341,6 @@ export const Reader = withPropsFrom(
'setPageUrls', 'setPageUrls',
'setPageLoadStates', 'setPageLoadStates',
'setTransitionPageMode', 'setTransitionPageMode',
'cancelAutoScroll',
'setShowPreview', 'setShowPreview',
], ],
); );

View File

@@ -43,7 +43,6 @@ import {
import { useMouseDragScroll } from '@/base/hooks/useMouseDragScroll.tsx'; import { useMouseDragScroll } from '@/base/hooks/useMouseDragScroll.tsx';
import { applyStyles } from '@/base/utils/ApplyStyles.ts'; import { applyStyles } from '@/base/utils/ApplyStyles.ts';
import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx'; import { withPropsFrom } from '@/base/hoc/withPropsFrom.tsx';
import { useReaderAutoScrollContext } from '@/features/reader/auto-scroll/ReaderAutoScrollContext.tsx';
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts'; import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx'; import { useReaderTapZoneContext } from '@/features/reader/tap-zones/ReaderTapZoneContext.tsx';
import { useReaderAutoScroll } from '@/features/reader/auto-scroll/hooks/useReaderAutoScroll.ts'; import { useReaderAutoScroll } from '@/features/reader/auto-scroll/hooks/useReaderAutoScroll.ts';
@@ -65,7 +64,7 @@ import { NavbarContextType } from '@/features/navigation-bar/NavigationBar.types
import { useReaderPreserveScrollPosition } from '@/features/reader/viewer/hooks/useReaderPreserveScrollPosition.ts'; import { useReaderPreserveScrollPosition } from '@/features/reader/viewer/hooks/useReaderPreserveScrollPosition.ts';
import { ChapterIdInfo } from '@/features/chapter/Chapter.types.ts'; import { ChapterIdInfo } from '@/features/chapter/Chapter.types.ts';
import { getReaderStore, useReaderStore } from '@/features/reader/ReaderStore.ts'; import { getReaderStore, useReaderStore, useReaderStoreShallow } from '@/features/reader/ReaderStore.ts';
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,
@@ -169,8 +168,13 @@ const BaseReaderViewer = forwardRef(
const isContinuousReadingModeActive = isContinuousReadingMode(readingMode); const isContinuousReadingModeActive = isContinuousReadingMode(readingMode);
const isDragging = useMouseDragScroll(scrollElementRef); const isDragging = useMouseDragScroll(scrollElementRef);
const automaticScrolling = useReaderAutoScrollContext(); const automaticScrolling = useReaderStoreShallow((state) => ({
useEffect(() => automaticScrolling.setScrollRef(scrollElementRef), []); isPaused: state.autoScroll.isPaused,
pause: state.autoScroll.pause,
resume: state.autoScroll.resume,
setScrollRef: state.autoScroll.setScrollRef,
}));
useEffect(() => automaticScrolling.setScrollRef(scrollElementRef.current), []);
const scrollbarXSize = MediaQuery.useGetScrollbarSize('width', scrollElementRef.current); const scrollbarXSize = MediaQuery.useGetScrollbarSize('width', scrollElementRef.current);
const scrollbarYSize = MediaQuery.useGetScrollbarSize('height', scrollElementRef.current); const scrollbarYSize = MediaQuery.useGetScrollbarSize('height', scrollElementRef.current);
@@ -271,7 +275,13 @@ const BaseReaderViewer = forwardRef(
useReaderHideCursorOnInactivity(scrollElementRef); useReaderHideCursorOnInactivity(scrollElementRef);
useReaderHorizontalModeInvertXYScrolling(readingMode, readingDirection, scrollElementRef); useReaderHorizontalModeInvertXYScrolling(readingMode, readingDirection, scrollElementRef);
useReaderHideOverlayOnUserScroll(isOverlayVisible, showPreview, setShowPreview, scrollElementRef); useReaderHideOverlayOnUserScroll(isOverlayVisible, showPreview, setShowPreview, scrollElementRef);
useReaderAutoScroll(isOverlayVisible, automaticScrolling, isStaticNav); useReaderAutoScroll(
isOverlayVisible,
automaticScrolling.isPaused,
automaticScrolling.pause,
automaticScrolling.resume,
isStaticNav,
);
useReaderPreserveScrollPosition( useReaderPreserveScrollPosition(
scrollElementRef, scrollElementRef,
currentChapter?.id, currentChapter?.id,