From 7f649296b9f0da6e2f3c66952ee094132cf55dc7 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sat, 18 Jan 2025 22:41:54 +0100 Subject: [PATCH] Extract logic from "Reader" into hooks --- .../reader/hooks/useReaderResetStates.ts | 60 +++++ .../reader/hooks/useReaderSetChaptersState.ts | 56 ++++ .../reader/hooks/useReaderSetPagesState.ts | 65 +++++ .../reader/hooks/useReaderSetSettingsState.ts | 62 +++++ .../useReaderShowSettingPreviewOnChange.ts | 77 ++++++ src/modules/reader/screens/Reader.tsx | 247 ++++-------------- 6 files changed, 376 insertions(+), 191 deletions(-) create mode 100644 src/modules/reader/hooks/useReaderResetStates.ts create mode 100644 src/modules/reader/hooks/useReaderSetChaptersState.ts create mode 100644 src/modules/reader/hooks/useReaderSetPagesState.ts create mode 100644 src/modules/reader/hooks/useReaderSetSettingsState.ts create mode 100644 src/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts diff --git a/src/modules/reader/hooks/useReaderResetStates.ts b/src/modules/reader/hooks/useReaderResetStates.ts new file mode 100644 index 00000000..46fa6c32 --- /dev/null +++ b/src/modules/reader/hooks/useReaderResetStates.ts @@ -0,0 +1,60 @@ +/* + * 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 { useEffect } from 'react'; +import { createPageData } from '@/modules/reader/utils/ReaderPager.utils.tsx'; +import { + ReaderStateChapters, + ReaderTransitionPageMode, + TReaderAutoScrollContext, + TReaderStateMangaContext, + TReaderStateSettingsContext, +} from '@/modules/reader/types/Reader.types.ts'; +import { DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG } from '@/modules/reader/services/ReaderSettingsMetadata.ts'; +import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts'; +import { TReaderOverlayContext } from '@/modules/reader/types/ReaderOverlay.types.ts'; + +export const useReaderResetStates = ( + setManga: TReaderStateMangaContext['setManga'], + setReaderStateChapters: ReaderStateChapters['setReaderStateChapters'], + setCurrentPageIndex: ReaderStatePages['setCurrentPageIndex'], + setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'], + setTotalPages: ReaderStatePages['setTotalPages'], + setPages: ReaderStatePages['setPages'], + setPageUrls: ReaderStatePages['setPageUrls'], + setPageLoadStates: ReaderStatePages['setPageLoadStates'], + setTransitionPageMode: ReaderStatePages['setTransitionPageMode'], + setIsOverlayVisible: TReaderOverlayContext['setIsVisible'], + setSettings: TReaderStateSettingsContext['setSettings'], + cancelAutoScroll: TReaderAutoScrollContext['cancel'], +) => { + useEffect( + () => () => { + setManga(undefined); + setReaderStateChapters({ + mangaChapters: [], + chapters: [], + }); + + setCurrentPageIndex(0); + setPageToScrollToIndex(null); + setTotalPages(0); + setPages([createPageData('', 0)]); + setPageUrls([]); + setPageLoadStates([{ url: '', loaded: false }]); + setTransitionPageMode(ReaderTransitionPageMode.NONE); + + setIsOverlayVisible(false); + + setSettings(DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG); + + cancelAutoScroll(); + }, + [], + ); +}; diff --git a/src/modules/reader/hooks/useReaderSetChaptersState.ts b/src/modules/reader/hooks/useReaderSetChaptersState.ts new file mode 100644 index 00000000..fe9862d3 --- /dev/null +++ b/src/modules/reader/hooks/useReaderSetChaptersState.ts @@ -0,0 +1,56 @@ +/* + * 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 { useEffect } from 'react'; +import { Chapters } from '@/modules/chapter/services/Chapters.ts'; +import { DirectionOffset } from '@/Base.types.ts'; +import { requestManager } from '@/lib/requests/RequestManager.ts'; +import { GetChaptersReaderQuery } from '@/lib/graphql/generated/graphql.ts'; +import { IReaderSettings, ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts'; + +export const useReaderSetChaptersState = ( + chaptersResponse: ReturnType>, + chapterSourceOrder: number, + initialChapter: ReaderStateChapters['initialChapter'], + setReaderStateChapters: ReaderStateChapters['setReaderStateChapters'], + shouldSkipDupChapters: IReaderSettings['shouldSkipDupChapters'], +) => { + useEffect(() => { + const newMangaChapters = chaptersResponse.data?.chapters.nodes; + const newCurrentChapter = newMangaChapters + ? (newMangaChapters[newMangaChapters.length - chapterSourceOrder] ?? null) + : undefined; + const newInitialChapter = initialChapter ?? newCurrentChapter; + + setReaderStateChapters({ + mangaChapters: newMangaChapters ?? [], + chapters: + newInitialChapter && newMangaChapters + ? Chapters.removeDuplicates(newInitialChapter, newMangaChapters) + : [], + initialChapter: newInitialChapter, + currentChapter: newCurrentChapter, + nextChapter: + newMangaChapters && + newCurrentChapter && + Chapters.getNextChapter(newCurrentChapter, newMangaChapters, { + offset: DirectionOffset.NEXT, + skipDupe: shouldSkipDupChapters, + skipDupeChapter: newInitialChapter, + }), + previousChapter: + newMangaChapters && + newCurrentChapter && + Chapters.getNextChapter(newCurrentChapter, newMangaChapters, { + offset: DirectionOffset.PREVIOUS, + skipDupe: shouldSkipDupChapters, + skipDupeChapter: newInitialChapter, + }), + }); + }, [chaptersResponse.data?.chapters.nodes, chapterSourceOrder, shouldSkipDupChapters]); +}; diff --git a/src/modules/reader/hooks/useReaderSetPagesState.ts b/src/modules/reader/hooks/useReaderSetPagesState.ts new file mode 100644 index 00000000..991f13ed --- /dev/null +++ b/src/modules/reader/hooks/useReaderSetPagesState.ts @@ -0,0 +1,65 @@ +/* + * 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 { useEffect } from 'react'; +import { getInitialReaderPageIndex } from '@/modules/reader/utils/Reader.utils.ts'; +import { createPageData, createPagesData } from '@/modules/reader/utils/ReaderPager.utils.tsx'; +import { + ReaderResumeMode, + ReaderStateChapters, + ReaderTransitionPageMode, +} from '@/modules/reader/types/Reader.types.ts'; +import { requestManager } from '@/lib/requests/RequestManager.ts'; +import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts'; + +export const useReaderSetPagesState = ( + pagesResponse: ReturnType[1], + resumeMode: ReaderResumeMode, + currentChapter: ReaderStateChapters['currentChapter'], + setArePagesFetched: (fetched: boolean) => void, + setTotalPages: ReaderStatePages['setTotalPages'], + setPages: ReaderStatePages['setPages'], + setPageUrls: ReaderStatePages['setPageUrls'], + setPageLoadStates: ReaderStatePages['setPageLoadStates'], + setCurrentPageIndex: ReaderStatePages['setCurrentPageIndex'], + setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'], + setTransitionPageMode: ReaderStatePages['setTransitionPageMode'], +) => { + useEffect(() => { + const pagesPayload = pagesResponse.data?.fetchChapterPages; + if (pagesPayload) { + const { pages: newPages } = pagesPayload; + + const initialReaderPageIndex = getInitialReaderPageIndex( + resumeMode, + currentChapter?.lastPageRead ?? 0, + newPages.length - 1, + ); + + const newPageData = createPagesData(newPages); + + setArePagesFetched(true); + setTotalPages(pagesPayload.chapter.pageCount); + setPages(newPageData); + setPageUrls(newPages); + setPageLoadStates(newPageData.map(({ primary: { url } }) => ({ url, loaded: false }))); + setCurrentPageIndex(initialReaderPageIndex); + setPageToScrollToIndex(initialReaderPageIndex); + } else { + setArePagesFetched(false); + setCurrentPageIndex(0); + setPageToScrollToIndex(null); + setTotalPages(0); + setPages([createPageData('', 0)]); + setPageUrls([]); + setPageLoadStates([{ url: '', loaded: false }]); + } + + setTransitionPageMode(ReaderTransitionPageMode.NONE); + }, [pagesResponse.data?.fetchChapterPages?.pages]); +}; diff --git a/src/modules/reader/hooks/useReaderSetSettingsState.ts b/src/modules/reader/hooks/useReaderSetSettingsState.ts new file mode 100644 index 00000000..d17d8502 --- /dev/null +++ b/src/modules/reader/hooks/useReaderSetSettingsState.ts @@ -0,0 +1,62 @@ +/* + * 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 { useEffect } from 'react'; +import { + getReaderSettings, + getReaderSettingsFor, + useDefaultReaderSettings, +} from '@/modules/reader/services/ReaderSettingsMetadata.ts'; +import { isAutoWebtoonMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; +import { ReadingMode, TReaderStateSettingsContext } from '@/modules/reader/types/Reader.types.ts'; +import { GetMangaReaderQuery } from '@/lib/graphql/generated/graphql.ts'; +import { requestManager } from '@/lib/requests/RequestManager.ts'; + +export const useReaderSetSettingsState = ( + mangaResponse: ReturnType>, + defaultSettingsResponse: ReturnType['request'], + defaultSettings: ReturnType['settings'], + defaultSettingsMetadata: ReturnType['metadata'], + setSettings: TReaderStateSettingsContext['setSettings'], + setAreSettingsSet: (areSet: boolean) => void, +) => { + useEffect(() => { + const mangaFromResponse = mangaResponse.data?.manga; + if (!mangaFromResponse || defaultSettingsResponse.loading || defaultSettingsResponse.error) { + return; + } + + const settingsWithDefaultProfileFallback = getReaderSettingsFor(mangaFromResponse, defaultSettings); + + const shouldUseWebtoonMode = isAutoWebtoonMode( + mangaFromResponse, + settingsWithDefaultProfileFallback.shouldUseAutoWebtoonMode, + settingsWithDefaultProfileFallback.readingMode, + ); + + const defaultSettingsWithAutoReadingMode = { + ...defaultSettings, + readingMode: shouldUseWebtoonMode ? ReadingMode.WEBTOON : defaultSettings.readingMode, + }; + + const profile = shouldUseWebtoonMode + ? ReadingMode.WEBTOON + : settingsWithDefaultProfileFallback.readingMode.value; + const profileSettings = getReaderSettings( + 'global', + { meta: defaultSettingsMetadata! }, + defaultSettingsWithAutoReadingMode, + undefined, + profile, + ); + + const finalSettings = getReaderSettingsFor(mangaFromResponse, profileSettings); + setSettings(finalSettings); + setAreSettingsSet(true); + }, [mangaResponse.data?.manga, defaultSettings]); +}; diff --git a/src/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts b/src/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts new file mode 100644 index 00000000..adb806e1 --- /dev/null +++ b/src/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts @@ -0,0 +1,77 @@ +/* + * 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 { useEffect, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { IReaderSettings, IReaderSettingsWithDefaultFlag } from '@/modules/reader/types/Reader.types.ts'; +import { makeToast } from '@/modules/core/utils/Toast.ts'; +import { READING_MODE_VALUE_TO_DISPLAY_DATA } from '@/modules/reader/constants/ReaderSettings.constants.tsx'; +import { TranslationKey } from '@/Base.types.ts'; +import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts'; + +const HIDE_PREVIEW_TIMEOUT = 5000; + +export const useReaderShowSettingPreviewOnChange = ( + isLoading: boolean, + error: any, + areSettingsSet: boolean, + readingMode: IReaderSettingsWithDefaultFlag['readingMode'], + tapZoneLayout: IReaderSettingsWithDefaultFlag['tapZoneLayout'], + tapZoneInvertMode: IReaderSettingsWithDefaultFlag['tapZoneInvertMode'], + shouldShowReadingModePreview: IReaderSettings['shouldShowReadingModePreview'], + shouldShowTapZoneLayoutPreview: IReaderSettings['shouldShowTapZoneLayoutPreview'], + setShowPreview: TReaderTapZoneContext['setShowPreview'], +) => { + const { t } = useTranslation(); + + // show setting previews on change or when open reader + const previousReadingMode = useRef(); + const previousTapZoneLayout = useRef(); + const previousTapZoneInvertMode = useRef(); + const isInitialPreview = useRef(true); + + useEffect(() => { + if (isLoading || error || !areSettingsSet) { + return; + } + + const didReadingModeChange = JSON.stringify(readingMode) !== JSON.stringify(previousReadingMode.current); + const showReadingModePreview = shouldShowReadingModePreview && didReadingModeChange; + if (showReadingModePreview) { + makeToast(t(READING_MODE_VALUE_TO_DISPLAY_DATA[readingMode.value].title as TranslationKey), { + autoHideDuration: HIDE_PREVIEW_TIMEOUT, + }); + } + previousReadingMode.current = readingMode; + + const didTapZoneLayoutChange = + JSON.stringify(tapZoneLayout) !== JSON.stringify(previousTapZoneLayout.current) || + JSON.stringify(tapZoneInvertMode) !== JSON.stringify(previousTapZoneInvertMode.current); + const showTapZoneLayoutPreview = shouldShowTapZoneLayoutPreview && didTapZoneLayoutChange; + if (showTapZoneLayoutPreview) { + setShowPreview(true); + if (isInitialPreview.current) { + setTimeout(() => setShowPreview(false), HIDE_PREVIEW_TIMEOUT); + } + } + previousTapZoneLayout.current = tapZoneLayout; + previousTapZoneInvertMode.current = tapZoneInvertMode; + + isInitialPreview.current = false; + }, [ + isLoading, + error, + areSettingsSet, + readingMode.value, + readingMode.isDefault, + tapZoneLayout.value, + tapZoneLayout.isDefault, + tapZoneInvertMode.value, + tapZoneInvertMode.isDefault, + ]); +}; diff --git a/src/modules/reader/screens/Reader.tsx b/src/modules/reader/screens/Reader.tsx index 93e749d7..68ab4f6f 100644 --- a/src/modules/reader/screens/Reader.tsx +++ b/src/modules/reader/screens/Reader.tsx @@ -10,12 +10,7 @@ import Box from '@mui/material/Box'; import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; -import { - DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG, - getReaderSettings, - getReaderSettingsFor, - useDefaultReaderSettings, -} from '@/modules/reader/services/ReaderSettingsMetadata.ts'; +import { useDefaultReaderSettings } from '@/modules/reader/services/ReaderSettingsMetadata.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { ReaderOverlay } from '@/modules/reader/components/overlay/ReaderOverlay.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; @@ -26,8 +21,6 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx'; import { GET_CHAPTERS_READER } from '@/lib/graphql/queries/ChapterQuery.ts'; -import { Chapters } from '@/modules/chapter/services/Chapters.ts'; -import { DirectionOffset, TranslationKey } from '@/Base.types.ts'; import { TapZoneLayout } from '@/modules/reader/components/TapZoneLayout.tsx'; import { useReaderOverlayContext } from '@/modules/reader/contexts/ReaderOverlayContext.tsx'; import { ReaderRGBAFilter } from '@/modules/reader/components/ReaderRGBAFilter.tsx'; @@ -35,35 +28,31 @@ import { useReaderStateSettingsContext } from '@/modules/reader/contexts/state/R import { useReaderStateMangaContext } from '@/modules/reader/contexts/state/ReaderStateMangaContext.tsx'; import { ReaderViewer } from '@/modules/reader/components/viewer/ReaderViewer.tsx'; import { ReaderService } from '@/modules/reader/services/ReaderService.ts'; -import { - READER_BACKGROUND_TO_COLOR, - READING_MODE_VALUE_TO_DISPLAY_DATA, -} from '@/modules/reader/constants/ReaderSettings.constants.tsx'; -import { createPageData, createPagesData } from '@/modules/reader/utils/ReaderPager.utils.tsx'; +import { READER_BACKGROUND_TO_COLOR } from '@/modules/reader/constants/ReaderSettings.constants.tsx'; import { ReaderHotkeys } from '@/modules/reader/components/ReaderHotkeys.tsx'; import { IReaderSettings, IReaderSettingsWithDefaultFlag, ReaderResumeMode, ReaderStateChapters, - ReaderTransitionPageMode, - ReadingMode, TReaderAutoScrollContext, TReaderStateMangaContext, TReaderStateSettingsContext, } from '@/modules/reader/types/Reader.types.ts'; -import { getInitialReaderPageIndex } from '@/modules/reader/utils/Reader.utils.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts'; import { TReaderOverlayContext } from '@/modules/reader/types/ReaderOverlay.types.ts'; import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts'; import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx'; import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx'; -import { isAutoWebtoonMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; import { useReaderAutoScrollContext } from '@/modules/reader/contexts/ReaderAutoScrollContext.tsx'; -import { makeToast } from '@/modules/core/utils/Toast.ts'; import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts'; import { useReaderTapZoneContext } from '@/modules/reader/contexts/ReaderTapZoneContext.tsx'; +import { useReaderResetStates } from '@/modules/reader/hooks/useReaderResetStates.ts'; +import { useReaderSetPagesState } from '@/modules/reader/hooks/useReaderSetPagesState.ts'; +import { useReaderSetSettingsState } from '@/modules/reader/hooks/useReaderSetSettingsState.ts'; +import { useReaderShowSettingPreviewOnChange } from '@/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts'; +import { useReaderSetChaptersState } from '@/modules/reader/hooks/useReaderSetChaptersState.ts'; const BaseReader = ({ setTitle, @@ -194,183 +183,59 @@ const BaseReader = ({ setManga(mangaResponse.data?.manga); }, [mangaResponse.data?.manga]); - // reset states - useEffect( - () => () => { - setManga(undefined); - setReaderStateChapters({ - mangaChapters: [], - chapters: [], - }); - - setCurrentPageIndex(0); - setPageToScrollToIndex(null); - setTotalPages(0); - setPages([createPageData('', 0)]); - setPageUrls([]); - setPageLoadStates([{ url: '', loaded: false }]); - setTransitionPageMode(ReaderTransitionPageMode.NONE); - - setIsOverlayVisible(false); - - setSettings(DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG); - - cancelAutoScroll(); - }, - [], + useReaderResetStates( + setManga, + setReaderStateChapters, + setCurrentPageIndex, + setPageToScrollToIndex, + setTotalPages, + setPages, + setPageUrls, + setPageLoadStates, + setTransitionPageMode, + setIsOverlayVisible, + setSettings, + cancelAutoScroll, ); - - // set pages state - useEffect(() => { - const pagesPayload = pagesResponse.data?.fetchChapterPages; - if (pagesPayload) { - const { pages: newPages } = pagesPayload; - - const initialReaderPageIndex = getInitialReaderPageIndex( - resumeMode, - currentChapter?.lastPageRead ?? 0, - newPages.length - 1, - ); - - const newPageData = createPagesData(newPages); - - setArePagesFetched(true); - setTotalPages(pagesPayload.chapter.pageCount); - setPages(newPageData); - setPageUrls(newPages); - setPageLoadStates(newPageData.map(({ primary: { url } }) => ({ url, loaded: false }))); - setCurrentPageIndex(initialReaderPageIndex); - setPageToScrollToIndex(initialReaderPageIndex); - } else { - setArePagesFetched(false); - setCurrentPageIndex(0); - setPageToScrollToIndex(null); - setTotalPages(0); - setPages([createPageData('', 0)]); - setPageUrls([]); - setPageLoadStates([{ url: '', loaded: false }]); - } - - setTransitionPageMode(ReaderTransitionPageMode.NONE); - }, [pagesResponse.data?.fetchChapterPages?.pages]); - - // set settings state - useEffect(() => { - const mangaFromResponse = mangaResponse.data?.manga; - if (!mangaFromResponse || defaultSettingsResponse.loading || defaultSettingsResponse.error) { - return; - } - - const settingsWithDefaultProfileFallback = getReaderSettingsFor(mangaFromResponse, defaultSettings); - - const shouldUseWebtoonMode = isAutoWebtoonMode( - mangaFromResponse, - settingsWithDefaultProfileFallback.shouldUseAutoWebtoonMode, - settingsWithDefaultProfileFallback.readingMode, - ); - - const defaultSettingsWithAutoReadingMode = { - ...defaultSettings, - readingMode: shouldUseWebtoonMode ? ReadingMode.WEBTOON : defaultSettings.readingMode, - }; - - const profile = shouldUseWebtoonMode - ? ReadingMode.WEBTOON - : settingsWithDefaultProfileFallback.readingMode.value; - const profileSettings = getReaderSettings( - 'global', - { meta: defaultSettingsMetadata! }, - defaultSettingsWithAutoReadingMode, - undefined, - profile, - ); - - const finalSettings = getReaderSettingsFor(mangaFromResponse, profileSettings); - setSettings(finalSettings); - setAreSettingsSet(true); - }, [mangaResponse.data?.manga, defaultSettings]); - - // show setting previews on change or when open reader - const previousReadingMode = useRef(); - const previousTapZoneLayout = useRef(); - const previousTapZoneInvertMode = useRef(); - const isInitialPreview = useRef(true); - useEffect(() => { - if (isLoading || error || !areSettingsSet) { - return; - } - - const HIDE_PREVIEW_TIMEOUT = 5000; - - const didReadingModeChange = JSON.stringify(readingMode) !== JSON.stringify(previousReadingMode.current); - const showReadingModePreview = shouldShowReadingModePreview && didReadingModeChange; - if (showReadingModePreview) { - makeToast(t(READING_MODE_VALUE_TO_DISPLAY_DATA[readingMode.value].title as TranslationKey), { - autoHideDuration: HIDE_PREVIEW_TIMEOUT, - }); - } - previousReadingMode.current = readingMode; - - const didTapZoneLayoutChange = - JSON.stringify(tapZoneLayout) !== JSON.stringify(previousTapZoneLayout.current) || - JSON.stringify(tapZoneInvertMode) !== JSON.stringify(previousTapZoneInvertMode.current); - const showTapZoneLayoutPreview = shouldShowTapZoneLayoutPreview && didTapZoneLayoutChange; - if (showTapZoneLayoutPreview) { - setShowPreview(true); - if (isInitialPreview.current) { - setTimeout(() => setShowPreview(false), HIDE_PREVIEW_TIMEOUT); - } - } - previousTapZoneLayout.current = tapZoneLayout; - previousTapZoneInvertMode.current = tapZoneInvertMode; - - isInitialPreview.current = false; - }, [ + useReaderSetPagesState( + pagesResponse, + resumeMode, + currentChapter, + setArePagesFetched, + setTotalPages, + setPages, + setPageUrls, + setPageLoadStates, + setCurrentPageIndex, + setPageToScrollToIndex, + setTransitionPageMode, + ); + useReaderSetSettingsState( + mangaResponse, + defaultSettingsResponse, + defaultSettings, + defaultSettingsMetadata, + setSettings, + setAreSettingsSet, + ); + useReaderShowSettingPreviewOnChange( isLoading, error, areSettingsSet, - readingMode.value, - readingMode.isDefault, - tapZoneLayout.value, - tapZoneLayout.isDefault, - tapZoneInvertMode.value, - tapZoneInvertMode.isDefault, - ]); - - // set chapters state - useEffect(() => { - const newMangaChapters = chaptersResponse.data?.chapters.nodes; - const newCurrentChapter = newMangaChapters - ? (newMangaChapters[newMangaChapters.length - chapterSourceOrder] ?? null) - : undefined; - const newInitialChapter = initialChapter ?? newCurrentChapter; - - setReaderStateChapters({ - mangaChapters: newMangaChapters ?? [], - chapters: - newInitialChapter && newMangaChapters - ? Chapters.removeDuplicates(newInitialChapter, newMangaChapters) - : [], - initialChapter: newInitialChapter, - currentChapter: newCurrentChapter, - nextChapter: - newMangaChapters && - newCurrentChapter && - Chapters.getNextChapter(newCurrentChapter, newMangaChapters, { - offset: DirectionOffset.NEXT, - skipDupe: shouldSkipDupChapters, - skipDupeChapter: newInitialChapter, - }), - previousChapter: - newMangaChapters && - newCurrentChapter && - Chapters.getNextChapter(newCurrentChapter, newMangaChapters, { - offset: DirectionOffset.PREVIOUS, - skipDupe: shouldSkipDupChapters, - skipDupeChapter: newInitialChapter, - }), - }); - }, [chaptersResponse.data?.chapters.nodes, chapterSourceOrder, shouldSkipDupChapters]); + readingMode, + tapZoneLayout, + tapZoneInvertMode, + shouldShowReadingModePreview, + shouldShowTapZoneLayoutPreview, + setShowPreview, + ); + useReaderSetChaptersState( + chaptersResponse, + chapterSourceOrder, + initialChapter, + setReaderStateChapters, + shouldSkipDupChapters, + ); useLayoutEffect(() => { setOverride({