Move reader "auto-scroll state" to "reader store"
This commit is contained in:
@@ -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 };
|
||||||
|
|||||||
@@ -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 =>
|
||||||
|
|||||||
@@ -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() }),
|
||||||
119
src/features/reader/auto-scroll/ReaderAutoScrollStore.ts
Normal file
119
src/features/reader/auto-scroll/ReaderAutoScrollStore.ts
Normal 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;
|
||||||
@@ -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]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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();
|
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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],
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|||||||
@@ -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'],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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',
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user