Simplify selecting zustand store state
This commit is contained in:
@@ -31,10 +31,7 @@ const BaseReaderAutoScroll = ({
|
|||||||
themeDirection: Direction;
|
themeDirection: Direction;
|
||||||
combinedDirection: Direction;
|
combinedDirection: Direction;
|
||||||
}) => {
|
}) => {
|
||||||
const { scrollRef, direction } = useReaderAutoScrollStore((state) => ({
|
const { scrollRef, direction } = useReaderAutoScrollStore('scrollRef', 'direction');
|
||||||
scrollRef: state.scrollRef,
|
|
||||||
direction: state.direction,
|
|
||||||
}));
|
|
||||||
const { readingMode, autoScroll } = useReaderSettingsStore((state) => ({
|
const { readingMode, autoScroll } = useReaderSettingsStore((state) => ({
|
||||||
readingMode: state.readingMode.value,
|
readingMode: state.readingMode.value,
|
||||||
autoScroll: state.autoScroll,
|
autoScroll: state.autoScroll,
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import type { IReaderSettings } from '@/features/reader/Reader.types.ts';
|
|||||||
import { getReaderAutoScrollStore, useReaderAutoScrollStore } from '@/features/reader/stores/ReaderStore.ts';
|
import { getReaderAutoScrollStore, useReaderAutoScrollStore } from '@/features/reader/stores/ReaderStore.ts';
|
||||||
|
|
||||||
export const useReaderAutoScroll = (isOverlayVisible: boolean, isStaticNav: IReaderSettings['isStaticNav']): void => {
|
export const useReaderAutoScroll = (isOverlayVisible: boolean, isStaticNav: IReaderSettings['isStaticNav']): void => {
|
||||||
const { isPaused } = useReaderAutoScrollStore((state) => ({
|
const isPaused = useReaderAutoScrollStore('isPaused');
|
||||||
isPaused: state.isPaused,
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { pause, resume } = getReaderAutoScrollStore();
|
const { pause, resume } = getReaderAutoScrollStore();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const ReaderNavBarDesktopAutoScroll = ({
|
|||||||
setAutoScroll: (newAutoScroll: IReaderSettings['autoScroll'], commit: boolean) => void;
|
setAutoScroll: (newAutoScroll: IReaderSettings['autoScroll'], commit: boolean) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const isActive = useReaderAutoScrollStore((state) => state.isActive);
|
const isActive = useReaderAutoScrollStore('isActive');
|
||||||
|
|
||||||
const updateTimeout = useRef<NodeJS.Timeout>(undefined);
|
const updateTimeout = useRef<NodeJS.Timeout>(undefined);
|
||||||
|
|
||||||
|
|||||||
@@ -66,9 +66,7 @@ export const ReaderHotkeys = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const readerThemeDirection = ReaderService.useGetThemeDirection();
|
const readerThemeDirection = ReaderService.useGetThemeDirection();
|
||||||
const { enableScope, disableScope } = useHotkeysContext();
|
const { enableScope, disableScope } = useHotkeysContext();
|
||||||
const { hotkeys } = useReaderSettingsStore((state) => ({
|
const hotkeys = useReaderSettingsStore('hotkeys');
|
||||||
hotkeys: state.hotkeys,
|
|
||||||
}));
|
|
||||||
const exitReader = ReaderService.useExit();
|
const exitReader = ReaderService.useExit();
|
||||||
|
|
||||||
useHotkeys(hotkeys[ReaderHotkey.PREVIOUS_PAGE], () => ReaderControls.openPage('previous'));
|
useHotkeys(hotkeys[ReaderHotkey.PREVIOUS_PAGE], () => ReaderControls.openPage('previous'));
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const BaseReaderOverlay = ({
|
|||||||
isDesktop,
|
isDesktop,
|
||||||
isMobile,
|
isMobile,
|
||||||
}: Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop' | 'isMobile'>) => {
|
}: Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop' | 'isMobile'>) => {
|
||||||
const isVisible = useReaderOverlayStore((state) => state.isVisible);
|
const isVisible = useReaderOverlayStore('isVisible');
|
||||||
|
|
||||||
const [areSettingsOpen, setAreSettingsOpen] = useState(false);
|
const [areSettingsOpen, setAreSettingsOpen] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -30,17 +30,13 @@ const BaseReaderPageNumber = ({
|
|||||||
}: Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop'> &
|
}: Pick<ReturnType<typeof ReaderService.useOverlayMode>, 'isDesktop'> &
|
||||||
Pick<NavbarContextType, 'readerNavBarWidth'>) => {
|
Pick<NavbarContextType, 'readerNavBarWidth'>) => {
|
||||||
const scrollbar = useReaderScrollbarStore((state) => state);
|
const scrollbar = useReaderScrollbarStore((state) => state);
|
||||||
const { currentPageIndex, pages, totalPages } = useReaderPagesStore((state) => ({
|
const { currentPageIndex, pages, totalPages } = useReaderPagesStore('currentPageIndex', 'pages', 'totalPages');
|
||||||
currentPageIndex: state.currentPageIndex,
|
|
||||||
pages: state.pages,
|
|
||||||
totalPages: state.totalPages,
|
|
||||||
}));
|
|
||||||
const { readingDirection, shouldShowPageNumber, progressBarType } = useReaderSettingsStore((state) => ({
|
const { readingDirection, shouldShowPageNumber, progressBarType } = useReaderSettingsStore((state) => ({
|
||||||
readingDirection: state.readingDirection.value,
|
readingDirection: state.readingDirection.value,
|
||||||
shouldShowPageNumber: state.shouldShowPageNumber,
|
shouldShowPageNumber: state.shouldShowPageNumber,
|
||||||
progressBarType: state.progressBarType,
|
progressBarType: state.progressBarType,
|
||||||
}));
|
}));
|
||||||
const isMaximized = useReaderProgressBarStore((state) => state.isMaximized);
|
const isMaximized = useReaderProgressBarStore('isMaximized');
|
||||||
|
|
||||||
const pageName = useMemo(() => {
|
const pageName = useMemo(() => {
|
||||||
const currentPageName = getPage(currentPageIndex, pages).name;
|
const currentPageName = getPage(currentPageIndex, pages).name;
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ export const useReaderHideOverlayOnUserScroll = (
|
|||||||
isOverlayVisible: boolean,
|
isOverlayVisible: boolean,
|
||||||
scrollElementRef: MutableRefObject<HTMLDivElement | null>,
|
scrollElementRef: MutableRefObject<HTMLDivElement | null>,
|
||||||
) => {
|
) => {
|
||||||
const { showPreview } = useReaderTapZoneStore((state) => ({
|
const showPreview = useReaderTapZoneStore('showPreview');
|
||||||
showPreview: state.showPreview,
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ const DEFAULT_MANGA = { ...FALLBACK_MANGA, title: '' };
|
|||||||
const BaseReaderOverlayHeaderMobile = ({ isVisible, ref }: MobileHeaderProps & { ref?: Ref<HTMLDivElement> }) => {
|
const BaseReaderOverlayHeaderMobile = ({ isVisible, ref }: MobileHeaderProps & { ref?: Ref<HTMLDivElement> }) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' });
|
const popupState = usePopupState({ popupId: 'reader-overlay-more-menu', variant: 'popover' });
|
||||||
const currentChapter = useReaderChaptersStore((state) => state.currentChapter);
|
const currentChapter = useReaderChaptersStore('currentChapter');
|
||||||
|
|
||||||
const manga = useReaderStore((state) => state.manga);
|
const manga = useReaderStore('manga');
|
||||||
const scrollbar = useReaderScrollbarStore((state) => state);
|
const scrollbar = useReaderScrollbarStore((state) => state);
|
||||||
|
|
||||||
const { id: mangaId, title } = manga ?? DEFAULT_MANGA;
|
const { id: mangaId, title } = manga ?? DEFAULT_MANGA;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const ACTION_FALLBACK_MANGA = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ReaderLibraryButton = memo(() => {
|
export const ReaderLibraryButton = memo(() => {
|
||||||
const manga = useReaderStore((state) => state.manga);
|
const manga = useReaderStore('manga');
|
||||||
|
|
||||||
const { inLibrary } = manga ?? ACTION_FALLBACK_MANGA;
|
const { inLibrary } = manga ?? ACTION_FALLBACK_MANGA;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ const BaseReaderNavBarDesktop = ({
|
|||||||
setReaderNavBarWidth,
|
setReaderNavBarWidth,
|
||||||
}: ReaderNavBarDesktopProps & Pick<NavbarContextType, 'setReaderNavBarWidth'>) => {
|
}: ReaderNavBarDesktopProps & Pick<NavbarContextType, 'setReaderNavBarWidth'>) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const manga = useReaderStore((state) => state.manga);
|
const manga = useReaderStore('manga');
|
||||||
const {
|
const {
|
||||||
chapters,
|
chapters,
|
||||||
currentChapterId,
|
currentChapterId,
|
||||||
@@ -77,7 +77,7 @@ const BaseReaderNavBarDesktop = ({
|
|||||||
previousChapter: state.previousChapter,
|
previousChapter: state.previousChapter,
|
||||||
nextChapter: state.nextChapter,
|
nextChapter: state.nextChapter,
|
||||||
}));
|
}));
|
||||||
const isStaticNav = useReaderSettingsStore((state) => state.isStaticNav);
|
const isStaticNav = useReaderSettingsStore('isStaticNav');
|
||||||
|
|
||||||
const [navBarElement, setNavBarElement] = useState<HTMLDivElement | null>();
|
const [navBarElement, setNavBarElement] = useState<HTMLDivElement | null>();
|
||||||
useResizeObserver(
|
useResizeObserver(
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export const ReaderNavBarDesktopActions = memo(() => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const pageLoadStates = useReaderPagesStore((state) => state.pageLoadStates);
|
const pageLoadStates = useReaderPagesStore('pageLoadStates');
|
||||||
|
|
||||||
const pageRetryKeyPrefix = useRef<number>(0);
|
const pageRetryKeyPrefix = useRef<number>(0);
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ import { ReaderControls } from '@/features/reader/services/ReaderControls.ts';
|
|||||||
const BaseReaderNavBarDesktopPageNavigation = () => {
|
const BaseReaderNavBarDesktopPageNavigation = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const getOptionForDirection = useGetOptionForDirection();
|
const getOptionForDirection = useGetOptionForDirection();
|
||||||
const { currentPageIndex, pages } = useReaderPagesStore((state) => ({
|
const { currentPageIndex, pages } = useReaderPagesStore('currentPageIndex', 'pages');
|
||||||
currentPageIndex: state.currentPageIndex,
|
|
||||||
pages: state.pages,
|
|
||||||
}));
|
|
||||||
const readingDirection = useReaderSettingsStore((state) => state.readingDirection.value);
|
const readingDirection = useReaderSettingsStore((state) => state.readingDirection.value);
|
||||||
|
|
||||||
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
const currentPage = useMemo(() => getPage(currentPageIndex, pages), [currentPageIndex, pages]);
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ import { useReaderSettingsStore } from '@/features/reader/stores/ReaderStore.ts'
|
|||||||
const BaseReaderNavBarDesktopQuickSettings = ({ openSettings }: Pick<ReaderNavBarDesktopProps, 'openSettings'>) => {
|
const BaseReaderNavBarDesktopQuickSettings = ({ openSettings }: Pick<ReaderNavBarDesktopProps, 'openSettings'>) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const { readingMode, shouldOffsetDoubleSpreads, pageScaleMode, shouldStretchPage, readingDirection, autoScroll } =
|
const { readingMode, shouldOffsetDoubleSpreads, pageScaleMode, shouldStretchPage, readingDirection, autoScroll } =
|
||||||
useReaderSettingsStore((state) => ({
|
useReaderSettingsStore(
|
||||||
readingMode: state.readingMode,
|
'readingMode',
|
||||||
shouldOffsetDoubleSpreads: state.shouldOffsetDoubleSpreads,
|
'shouldOffsetDoubleSpreads',
|
||||||
pageScaleMode: state.pageScaleMode,
|
'pageScaleMode',
|
||||||
shouldStretchPage: state.shouldStretchPage,
|
'shouldStretchPage',
|
||||||
readingDirection: state.readingDirection,
|
'readingDirection',
|
||||||
autoScroll: state.autoScroll,
|
'autoScroll',
|
||||||
}));
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack sx={{ gap: 1 }}>
|
<Stack sx={{ gap: 1 }}>
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import {
|
|||||||
|
|
||||||
const BaseReaderBottomBarMobileQuickSettings = () => {
|
const BaseReaderBottomBarMobileQuickSettings = () => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const isActive = useReaderAutoScrollStore((state) => state.isActive);
|
const isActive = useReaderAutoScrollStore('isActive');
|
||||||
const { readingMode, readingDirection, autoScroll } = useReaderSettingsStore((state) => ({
|
const { readingMode, readingDirection, autoScroll } = useReaderSettingsStore(
|
||||||
readingMode: state.readingMode,
|
'readingMode',
|
||||||
readingDirection: state.readingDirection,
|
'readingDirection',
|
||||||
autoScroll: state.autoScroll,
|
'autoScroll',
|
||||||
}));
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack sx={{ gap: 2 }}>
|
<Stack sx={{ gap: 2 }}>
|
||||||
|
|||||||
@@ -68,14 +68,14 @@ const BaseReaderProgressBar = ({
|
|||||||
direction: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
direction: ReturnType<typeof ReaderService.useGetThemeDirection>;
|
||||||
fullSegmentClicks: boolean;
|
fullSegmentClicks: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const { pages, pageLoadStates, totalPages, currentPageIndex } = useReaderPagesStore((state) => ({
|
const { pages, pageLoadStates, totalPages, currentPageIndex } = useReaderPagesStore(
|
||||||
pages: state.pages,
|
'pages',
|
||||||
pageLoadStates: state.pageLoadStates,
|
'pageLoadStates',
|
||||||
totalPages: state.totalPages,
|
'totalPages',
|
||||||
currentPageIndex: state.currentPageIndex,
|
'currentPageIndex',
|
||||||
}));
|
);
|
||||||
const readingMode = useReaderSettingsStore((state) => state.readingMode.value);
|
const readingMode = useReaderSettingsStore((state) => state.readingMode.value);
|
||||||
const isDragging = useReaderProgressBarStore((state) => state.isDragging);
|
const isDragging = useReaderProgressBarStore('isDragging');
|
||||||
|
|
||||||
const progressBarRef = useRef<HTMLDivElement | null>(null);
|
const progressBarRef = useRef<HTMLDivElement | null>(null);
|
||||||
const draggingDetectionTimeout = useRef<NodeJS.Timeout>(undefined);
|
const draggingDetectionTimeout = useRef<NodeJS.Timeout>(undefined);
|
||||||
|
|||||||
@@ -37,18 +37,15 @@ const BaseStandardReaderProgressBar = ({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const scrollbar = useReaderScrollbarStore((state) => state);
|
const scrollbar = useReaderScrollbarStore((state) => state);
|
||||||
const totalPages = useReaderPagesStore((state) => state.totalPages);
|
const totalPages = useReaderPagesStore('totalPages');
|
||||||
const { progressBarType, progressBarSize, progressBarPosition, progressBarPositionAutoVertical } =
|
const { progressBarType, progressBarSize, progressBarPosition, progressBarPositionAutoVertical } =
|
||||||
useReaderSettingsStore((state) => ({
|
useReaderSettingsStore(
|
||||||
progressBarType: state.progressBarType,
|
'progressBarType',
|
||||||
progressBarSize: state.progressBarSize,
|
'progressBarSize',
|
||||||
progressBarPosition: state.progressBarPosition,
|
'progressBarPosition',
|
||||||
progressBarPositionAutoVertical: state.progressBarPositionAutoVertical,
|
'progressBarPositionAutoVertical',
|
||||||
}));
|
);
|
||||||
const { isMaximized, isDragging } = useReaderProgressBarStore((state) => ({
|
const { isMaximized, isDragging } = useReaderProgressBarStore('isMaximized', 'isDragging');
|
||||||
isMaximized: state.isMaximized,
|
|
||||||
isDragging: state.isDragging,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const [, setRefreshProgressBarPosition] = useState({});
|
const [, setRefreshProgressBarPosition] = useState({});
|
||||||
useResizeObserver(
|
useResizeObserver(
|
||||||
|
|||||||
@@ -59,20 +59,14 @@ const BaseMobileReaderProgressBar = ({
|
|||||||
bottomOffset?: number;
|
bottomOffset?: number;
|
||||||
}) => {
|
}) => {
|
||||||
const scrollbar = useReaderScrollbarStore((state) => state);
|
const scrollbar = useReaderScrollbarStore((state) => state);
|
||||||
const isVisible = useReaderOverlayStore((state) => state.isVisible);
|
const isVisible = useReaderOverlayStore('isVisible');
|
||||||
const { currentPageIndex, pages } = useReaderPagesStore((state) => ({
|
const { currentPageIndex, pages } = useReaderPagesStore('currentPageIndex', 'pages');
|
||||||
currentPageIndex: state.currentPageIndex,
|
const { previousChapter, nextChapter } = useReaderChaptersStore('previousChapter', 'nextChapter');
|
||||||
pages: state.pages,
|
const { progressBarPosition, progressBarPositionAutoVertical } = useReaderSettingsStore(
|
||||||
}));
|
'progressBarPosition',
|
||||||
const { previousChapter, nextChapter } = useReaderChaptersStore((state) => ({
|
'progressBarPositionAutoVertical',
|
||||||
previousChapter: state.previousChapter,
|
);
|
||||||
nextChapter: state.nextChapter,
|
const isDragging = useReaderProgressBarStore('isDragging');
|
||||||
}));
|
|
||||||
const { progressBarPosition, progressBarPositionAutoVertical } = useReaderSettingsStore((state) => ({
|
|
||||||
progressBarPosition: state.progressBarPosition,
|
|
||||||
progressBarPositionAutoVertical: state.progressBarPositionAutoVertical,
|
|
||||||
}));
|
|
||||||
const isDragging = useReaderProgressBarStore((state) => state.isDragging);
|
|
||||||
|
|
||||||
const [, setRefreshProgressBarPosition] = useState({});
|
const [, setRefreshProgressBarPosition] = useState({});
|
||||||
useResizeObserver(
|
useResizeObserver(
|
||||||
|
|||||||
@@ -49,14 +49,12 @@ const BaseReader = ({
|
|||||||
readerNavBarWidth,
|
readerNavBarWidth,
|
||||||
}: Pick<NavbarContextType, 'setOverride' | 'readerNavBarWidth'>) => {
|
}: Pick<NavbarContextType, 'setOverride' | 'readerNavBarWidth'>) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const manga = useReaderStore((state) => state.manga);
|
const manga = useReaderStore('manga');
|
||||||
const { mangaChapters, initialChapter, chapterForDuplicatesHandling, currentChapter } = useReaderChaptersStore(
|
const { mangaChapters, initialChapter, chapterForDuplicatesHandling, currentChapter } = useReaderChaptersStore(
|
||||||
(state) => ({
|
'mangaChapters',
|
||||||
mangaChapters: state.mangaChapters,
|
'initialChapter',
|
||||||
initialChapter: state.initialChapter,
|
'chapterForDuplicatesHandling',
|
||||||
chapterForDuplicatesHandling: state.chapterForDuplicatesHandling,
|
'currentChapter',
|
||||||
currentChapter: state.currentChapter,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
shouldSkipDupChapters,
|
shouldSkipDupChapters,
|
||||||
@@ -67,16 +65,16 @@ const BaseReader = ({
|
|||||||
tapZoneInvertMode,
|
tapZoneInvertMode,
|
||||||
shouldShowReadingModePreview,
|
shouldShowReadingModePreview,
|
||||||
shouldShowTapZoneLayoutPreview,
|
shouldShowTapZoneLayoutPreview,
|
||||||
} = useReaderSettingsStore((state) => ({
|
} = useReaderSettingsStore(
|
||||||
shouldSkipDupChapters: state.shouldSkipDupChapters,
|
'shouldSkipDupChapters',
|
||||||
shouldSkipFilteredChapters: state.shouldSkipFilteredChapters,
|
'shouldSkipFilteredChapters',
|
||||||
backgroundColor: state.backgroundColor,
|
'backgroundColor',
|
||||||
readingMode: state.readingMode,
|
'readingMode',
|
||||||
tapZoneLayout: state.tapZoneLayout,
|
'tapZoneLayout',
|
||||||
tapZoneInvertMode: state.tapZoneInvertMode,
|
'tapZoneInvertMode',
|
||||||
shouldShowReadingModePreview: state.shouldShowReadingModePreview,
|
'shouldShowReadingModePreview',
|
||||||
shouldShowTapZoneLayoutPreview: state.shouldShowTapZoneLayoutPreview,
|
'shouldShowTapZoneLayoutPreview',
|
||||||
}));
|
);
|
||||||
|
|
||||||
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
const scrollElementRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ export class ReaderService {
|
|||||||
|
|
||||||
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 = useReaderSettingsStore((state) => state.overlayMode);
|
const overlayMode = useReaderSettingsStore('overlayMode');
|
||||||
|
|
||||||
const isAutoModeSelected = overlayMode === ReaderOverlayMode.AUTO;
|
const isAutoModeSelected = overlayMode === ReaderOverlayMode.AUTO;
|
||||||
const isDesktopModeSelected = overlayMode === ReaderOverlayMode.DESKTOP;
|
const isDesktopModeSelected = overlayMode === ReaderOverlayMode.DESKTOP;
|
||||||
@@ -442,7 +442,7 @@ export class ReaderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static useExit(): () => void {
|
static useExit(): () => void {
|
||||||
const exitMode = useReaderSettingsStore((state) => state.exitMode);
|
const exitMode = useReaderSettingsStore('exitMode');
|
||||||
const handleBack = useBackButton();
|
const handleBack = useBackButton();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { devtools } from 'zustand/middleware';
|
import { devtools } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import { useShallow } from 'zustand/react/shallow';
|
|
||||||
import type { TMangaReader } from '@/features/manga/Manga.types.ts';
|
import type { TMangaReader } from '@/features/manga/Manga.types.ts';
|
||||||
import type { ReaderOverlayStoreSlice } from '@/features/reader/overlay/ReaderOverlayStore.ts';
|
import type { ReaderOverlayStoreSlice } from '@/features/reader/overlay/ReaderOverlayStore.ts';
|
||||||
import { createReaderOverlayStoreSlice } from '@/features/reader/overlay/ReaderOverlayStore.ts';
|
import { createReaderOverlayStoreSlice } from '@/features/reader/overlay/ReaderOverlayStore.ts';
|
||||||
@@ -156,37 +155,29 @@ const readerStore = create<ReaderStore>()(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
export const useReaderStore = <T>(selector: (state: ReaderStore) => T): T => readerStore(useShallow(selector));
|
export const useReaderStore = ZustandUtil.createStoreHook(readerStore);
|
||||||
export const getReaderStore = () => readerStore.getState();
|
export const getReaderStore = () => readerStore.getState();
|
||||||
|
|
||||||
export const useReaderScrollbarStore = <T>(selector: (state: ReaderStore['scrollbar']) => T): T =>
|
export const useReaderScrollbarStore = ZustandUtil.createStoreHook(readerStore, 'scrollbar');
|
||||||
readerStore(useShallow((state) => selector(state.scrollbar)));
|
|
||||||
export const getReaderScrollbarStore = () => readerStore.getState().scrollbar;
|
export const getReaderScrollbarStore = () => readerStore.getState().scrollbar;
|
||||||
|
|
||||||
export const useReaderSettingsStore = <T>(selector: (state: ReaderStore['settings']) => T): T =>
|
export const useReaderSettingsStore = ZustandUtil.createStoreHook(readerStore, 'settings');
|
||||||
readerStore(useShallow((state) => selector(state.settings)));
|
|
||||||
export const getReaderSettingsStore = () => readerStore.getState().settings;
|
export const getReaderSettingsStore = () => readerStore.getState().settings;
|
||||||
|
|
||||||
export const useReaderOverlayStore = <T>(selector: (state: ReaderOverlayStoreSlice['overlay']) => T): T =>
|
export const useReaderOverlayStore = ZustandUtil.createStoreHook(readerStore, 'overlay');
|
||||||
readerStore(useShallow((state) => selector(state.overlay)));
|
|
||||||
export const getReaderOverlayStore = () => readerStore.getState().overlay;
|
export const getReaderOverlayStore = () => readerStore.getState().overlay;
|
||||||
|
|
||||||
export const useReaderAutoScrollStore = <T>(selector: (state: ReaderAutoScrollStoreSlice['autoScroll']) => T): T =>
|
export const useReaderAutoScrollStore = ZustandUtil.createStoreHook(readerStore, 'autoScroll');
|
||||||
readerStore(useShallow((state) => selector(state.autoScroll)));
|
|
||||||
export const getReaderAutoScrollStore = () => readerStore.getState().autoScroll;
|
export const getReaderAutoScrollStore = () => readerStore.getState().autoScroll;
|
||||||
|
|
||||||
export const useReaderPagesStore = <T>(selector: (state: ReaderPagesStoreSlice['pages']) => T): T =>
|
export const useReaderPagesStore = ZustandUtil.createStoreHook(readerStore, 'pages');
|
||||||
readerStore(useShallow((state) => selector(state.pages)));
|
|
||||||
export const getReaderPagesStore = () => readerStore.getState().pages;
|
export const getReaderPagesStore = () => readerStore.getState().pages;
|
||||||
|
|
||||||
export const useReaderChaptersStore = <T>(selector: (state: ReaderChaptersStoreSlice['chapters']) => T): T =>
|
export const useReaderChaptersStore = ZustandUtil.createStoreHook(readerStore, 'chapters');
|
||||||
readerStore(useShallow((state) => selector(state.chapters)));
|
|
||||||
export const getReaderChaptersStore = () => readerStore.getState().chapters;
|
export const getReaderChaptersStore = () => readerStore.getState().chapters;
|
||||||
|
|
||||||
export const useReaderProgressBarStore = <T>(selector: (state: ReaderProgressBarStoreSlice['progressBar']) => T): T =>
|
export const useReaderProgressBarStore = ZustandUtil.createStoreHook(readerStore, 'progressBar');
|
||||||
readerStore(useShallow((state) => selector(state.progressBar)));
|
|
||||||
export const getReaderProgressBarStore = () => readerStore.getState().progressBar;
|
export const getReaderProgressBarStore = () => readerStore.getState().progressBar;
|
||||||
|
|
||||||
export const useReaderTapZoneStore = <T>(selector: (state: ReaderTapZoneStoreSlice['tapZone']) => T): T =>
|
export const useReaderTapZoneStore = ZustandUtil.createStoreHook(readerStore, 'tapZone');
|
||||||
readerStore(useShallow((state) => selector(state.tapZone)));
|
|
||||||
export const getReaderTapZoneStore = () => readerStore.getState().tapZone;
|
export const getReaderTapZoneStore = () => readerStore.getState().tapZone;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const BaseTapZoneLayout = ({ readerNavBarWidth }: Pick<NavbarContextType, 'reade
|
|||||||
tapZoneInvertMode: state.tapZoneInvertMode.value,
|
tapZoneInvertMode: state.tapZoneInvertMode.value,
|
||||||
readingDirection: state.readingDirection.value,
|
readingDirection: state.readingDirection.value,
|
||||||
}));
|
}));
|
||||||
const showPreview = useReaderTapZoneStore((state) => state.showPreview);
|
const showPreview = useReaderTapZoneStore('showPreview');
|
||||||
|
|
||||||
const [width, setWidth] = useState(0);
|
const [width, setWidth] = useState(0);
|
||||||
const [height, setHeight] = useState(0);
|
const [height, setHeight] = useState(0);
|
||||||
|
|||||||
@@ -68,24 +68,22 @@ const BaseReaderViewer = ({
|
|||||||
ref?: ForwardedRef<HTMLDivElement | null>;
|
ref?: ForwardedRef<HTMLDivElement | null>;
|
||||||
}) => {
|
}) => {
|
||||||
const { direction: themeDirection } = useTheme();
|
const { direction: themeDirection } = useTheme();
|
||||||
const isOverlayVisible = useReaderOverlayStore((state) => state.isVisible);
|
const isOverlayVisible = useReaderOverlayStore('isVisible');
|
||||||
const { currentPageIndex, pageToScrollToIndex, pages, totalPages, transitionPageMode, retryFailedPagesKeyPrefix } =
|
const { currentPageIndex, pageToScrollToIndex, pages, totalPages, transitionPageMode, retryFailedPagesKeyPrefix } =
|
||||||
useReaderPagesStore((state) => ({
|
useReaderPagesStore(
|
||||||
currentPageIndex: state.currentPageIndex,
|
'currentPageIndex',
|
||||||
pageToScrollToIndex: state.pageToScrollToIndex,
|
'pageToScrollToIndex',
|
||||||
pages: state.pages,
|
'pages',
|
||||||
totalPages: state.totalPages,
|
'totalPages',
|
||||||
transitionPageMode: state.transitionPageMode,
|
'transitionPageMode',
|
||||||
retryFailedPagesKeyPrefix: state.retryFailedPagesKeyPrefix,
|
'retryFailedPagesKeyPrefix',
|
||||||
}));
|
);
|
||||||
const { initialChapter, currentChapter, chapters, visibleChapters, isCurrentChapterReady } = useReaderChaptersStore(
|
const { initialChapter, currentChapter, chapters, visibleChapters, isCurrentChapterReady } = useReaderChaptersStore(
|
||||||
(state) => ({
|
'initialChapter',
|
||||||
initialChapter: state.initialChapter,
|
'currentChapter',
|
||||||
currentChapter: state.currentChapter,
|
'chapters',
|
||||||
chapters: state.chapters,
|
'visibleChapters',
|
||||||
visibleChapters: state.visibleChapters,
|
'isCurrentChapterReady',
|
||||||
isCurrentChapterReady: state.isCurrentChapterReady,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
readingMode,
|
readingMode,
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ const BaseReaderTransitionPage = ({
|
|||||||
handleBack: () => void;
|
handleBack: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const manga = useReaderStore((state) => state.manga);
|
const manga = useReaderStore('manga');
|
||||||
const scrollbar = useReaderScrollbarStore((state) => state);
|
const scrollbar = useReaderScrollbarStore((state) => state);
|
||||||
const transitionPageMode = useReaderPagesStore((state) => state.transitionPageMode);
|
const transitionPageMode = useReaderPagesStore('transitionPageMode');
|
||||||
const { readingMode, backgroundColor, shouldShowTransitionPage } = useReaderSettingsStore((state) => ({
|
const { readingMode, backgroundColor, shouldShowTransitionPage } = useReaderSettingsStore((state) => ({
|
||||||
readingMode: state.readingMode.value,
|
readingMode: state.readingMode.value,
|
||||||
backgroundColor: state.backgroundColor,
|
backgroundColor: state.backgroundColor,
|
||||||
@@ -226,7 +226,7 @@ export const ReaderTransitionPage = withPropsFrom(
|
|||||||
memo(BaseReaderTransitionPage) as typeof BaseReaderTransitionPage,
|
memo(BaseReaderTransitionPage) as typeof BaseReaderTransitionPage,
|
||||||
[
|
[
|
||||||
({ chapterId }: Pick<ComponentProps<typeof BaseReaderTransitionPage>, 'chapterId'>) => {
|
({ chapterId }: Pick<ComponentProps<typeof BaseReaderTransitionPage>, 'chapterId'>) => {
|
||||||
const chapters = useReaderChaptersStore((state) => state.chapters);
|
const chapters = useReaderChaptersStore('chapters');
|
||||||
|
|
||||||
const currentChapterIndex = useMemo(
|
const currentChapterIndex = useMemo(
|
||||||
() => chapters.findIndex((chapter) => chapter.id === chapterId),
|
() => chapters.findIndex((chapter) => chapter.id === chapterId),
|
||||||
@@ -249,7 +249,7 @@ export const ReaderTransitionPage = withPropsFrom(
|
|||||||
useNavBarContext,
|
useNavBarContext,
|
||||||
({ chapterId, type }: Pick<ComponentProps<typeof BaseReaderTransitionPage>, 'chapterId' | 'type'>) => {
|
({ chapterId, type }: Pick<ComponentProps<typeof BaseReaderTransitionPage>, 'chapterId' | 'type'>) => {
|
||||||
const handleBack = useBackButton();
|
const handleBack = useBackButton();
|
||||||
const chapters = useReaderChaptersStore((state) => state.chapters);
|
const chapters = useReaderChaptersStore('chapters');
|
||||||
|
|
||||||
const currentChapterIndex = useMemo(
|
const currentChapterIndex = useMemo(
|
||||||
() => chapters.findIndex((chapter) => chapter.id === chapterId),
|
() => chapters.findIndex((chapter) => chapter.id === chapterId),
|
||||||
|
|||||||
@@ -6,7 +6,64 @@
|
|||||||
* 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 { useShallow } from 'zustand/react/shallow';
|
||||||
|
|
||||||
|
type UseBoundStoreAny<S> = <T>(selector: (state: S) => T) => T;
|
||||||
|
|
||||||
|
type StoreHook<State> = {
|
||||||
|
<T>(selector: (state: State) => T): T;
|
||||||
|
<Key extends keyof State>(key: Key): State[Key];
|
||||||
|
<Key extends keyof State>(...keys: Key[]): Pick<State, Key>;
|
||||||
|
};
|
||||||
|
|
||||||
export class ZustandUtil {
|
export class ZustandUtil {
|
||||||
|
static createKeySelector<State, Key extends keyof State>(keys: Key[]): (state: State) => Pick<State, Key> {
|
||||||
|
return (state) => {
|
||||||
|
const result = {} as Pick<State, Key>;
|
||||||
|
|
||||||
|
for (const key of keys) {
|
||||||
|
result[key] = state[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static createStoreHook<FullState extends object, SliceKey extends keyof FullState>(
|
||||||
|
store: UseBoundStoreAny<FullState>,
|
||||||
|
sliceKey: SliceKey,
|
||||||
|
): StoreHook<FullState[SliceKey]>;
|
||||||
|
static createStoreHook<State>(store: UseBoundStoreAny<State>): StoreHook<State>;
|
||||||
|
static createStoreHook<State>(
|
||||||
|
store: UseBoundStoreAny<State>,
|
||||||
|
sliceKey?: keyof State,
|
||||||
|
): StoreHook<State[keyof State] | State> {
|
||||||
|
return ((...args: unknown[]) => {
|
||||||
|
let selector: (state: State) => unknown;
|
||||||
|
|
||||||
|
if (typeof args[0] === 'function') {
|
||||||
|
const fn = args[0] as (state: unknown) => unknown;
|
||||||
|
selector = sliceKey !== undefined ? (state: State) => fn(state[sliceKey]) : fn;
|
||||||
|
} else if (args.length === 1) {
|
||||||
|
const key = args[0];
|
||||||
|
selector =
|
||||||
|
sliceKey !== undefined
|
||||||
|
? (state: State) => (state[sliceKey] as Record<PropertyKey, unknown>)[key as PropertyKey]
|
||||||
|
: (state: State) => (state as Record<PropertyKey, unknown>)[key as PropertyKey];
|
||||||
|
} else {
|
||||||
|
const pickSelector = ZustandUtil.createKeySelector<Record<PropertyKey, unknown>, PropertyKey>(
|
||||||
|
args as PropertyKey[],
|
||||||
|
);
|
||||||
|
selector =
|
||||||
|
sliceKey !== undefined
|
||||||
|
? (state: State) => pickSelector(state[sliceKey] as Record<PropertyKey, unknown>)
|
||||||
|
: (pickSelector as (state: State) => unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
return store(useShallow(selector));
|
||||||
|
}) as StoreHook<State[keyof State] | State>;
|
||||||
|
}
|
||||||
|
|
||||||
static createActionName(...names: string[]) {
|
static createActionName(...names: string[]) {
|
||||||
const storeAndSlices = names.slice(0, -1);
|
const storeAndSlices = names.slice(0, -1);
|
||||||
const action = names.slice(-1)[0];
|
const action = names.slice(-1)[0];
|
||||||
|
|||||||
Reference in New Issue
Block a user