From 45f46a05d01dc8361860eb166d0ac9f868cd70da Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 30 Dec 2024 16:51:39 +0100 Subject: [PATCH] Optionally show preview or "reading mode" and "tap zone overlay" Shows a preview when opening the reader or when the values change --- public/locales/en.json | 10 +++ src/modules/metadata/Metadata.constants.ts | 2 + .../behaviour/ReaderBehaviourSettings.tsx | 24 ++++++ .../reader/components/viewer/ReaderViewer.tsx | 18 +++- .../constants/ReaderSettings.constants.tsx | 4 + src/modules/reader/screens/Reader.tsx | 83 +++++++++++++++++-- src/modules/reader/types/Reader.types.ts | 2 + 7 files changed, 135 insertions(+), 8 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index 334c2832f1..5420cc123e 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -922,6 +922,16 @@ "title": "Scale type", "width": "Fit width" }, + "preview": { + "reading_mode": { + "description": "Briefly show current mode when reader is opened or mode got changed", + "title": "Show reading mode" + }, + "tap_zones": { + "description": "Briefly show tap zone layout preview when reader is opened or layout got changed", + "title": "Show tap zones overlay" + } + }, "progress_bar": { "position": "Progress bar position", "size": "Progress bar size", diff --git a/src/modules/metadata/Metadata.constants.ts b/src/modules/metadata/Metadata.constants.ts index af1128c884..601524eaa6 100644 --- a/src/modules/metadata/Metadata.constants.ts +++ b/src/modules/metadata/Metadata.constants.ts @@ -71,6 +71,8 @@ const APP_METADATA_OBJECT: Record = { imagePreLoadAmount: undefined, shouldUseAutoWebtoonMode: undefined, autoScroll: undefined, + shouldShowReadingModePreview: undefined, + shouldShowTapZoneLayoutPreview: undefined, }; export const VALID_APP_METADATA_KEYS = Object.keys(APP_METADATA_OBJECT); diff --git a/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx b/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx index da9ee12422..3abf315ef2 100644 --- a/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx +++ b/src/modules/reader/components/settings/behaviour/ReaderBehaviourSettings.tsx @@ -49,6 +49,30 @@ export const ReaderBehaviourSettings = ({ onChange={(_, checked) => updateSetting('shouldOffsetDoubleSpreads', checked)} /> )} + + {t('reader.settings.preview.reading_mode.title')} + + {t('reader.settings.preview.reading_mode.description')} + + + } + checked={settings.shouldShowReadingModePreview} + onChange={(_, checked) => updateSetting('shouldShowReadingModePreview', checked)} + /> + + {t('reader.settings.preview.tap_zones.title')} + + {t('reader.settings.preview.tap_zones.description')} + + + } + checked={settings.shouldShowTapZoneLayoutPreview} + onChange={(_, checked) => updateSetting('shouldShowTapZoneLayoutPreview', checked)} + /> diff --git a/src/modules/reader/components/viewer/ReaderViewer.tsx b/src/modules/reader/components/viewer/ReaderViewer.tsx index 47bdc1ae93..fe3c44e448 100644 --- a/src/modules/reader/components/viewer/ReaderViewer.tsx +++ b/src/modules/reader/components/viewer/ReaderViewer.tsx @@ -53,6 +53,8 @@ import { useReaderHideOverlayOnUserScroll, useReaderHorizontalModeInvertXYScrolling, } from '@/modules/reader/utils/Reader.utils.ts'; +import { TReaderTapZoneContext } from '@/modules/reader/types/TapZoneLayout.types.ts'; +import { useReaderTapZoneContext } from '@/modules/reader/contexts/ReaderTapZoneContext.tsx'; const READING_MODE_TO_IN_VIEWPORT_TYPE: Record = { [ReadingMode.SINGLE_PAGE]: PageInViewportType.X, @@ -84,6 +86,8 @@ const BaseReaderViewer = forwardRef( isVisible: isOverlayVisible, setIsVisible: setIsOverlayVisible, updateCurrentPageIndex, + showPreview, + setShowPreview, }: Pick< ReaderStatePages, | 'currentPageIndex' @@ -100,7 +104,8 @@ const BaseReaderViewer = forwardRef( > & Pick & Pick & - Pick & { + Pick & + TReaderTapZoneContext & { updateCurrentPageIndex: ReturnType; }, @@ -202,7 +207,13 @@ const BaseReaderViewer = forwardRef( ); useReaderHideCursorOnInactivity(scrollElementRef); useReaderHorizontalModeInvertXYScrolling(readingMode, readingDirection, scrollElementRef); - useReaderHideOverlayOnUserScroll(isOverlayVisible, setIsOverlayVisible, scrollElementRef); + useReaderHideOverlayOnUserScroll( + isOverlayVisible, + setIsOverlayVisible, + showPreview, + setShowPreview, + scrollElementRef, + ); useReaderAutoScroll(isOverlayVisible, automaticScrolling); return ( @@ -249,6 +260,7 @@ export const ReaderViewer = withPropsFrom( useReaderScrollbarContext, useReaderOverlayContext, () => ({ updateCurrentPageIndex: ReaderControls.useUpdateCurrentPageIndex() }), + useReaderTapZoneContext, ], [ 'currentPageIndex', @@ -270,5 +282,7 @@ export const ReaderViewer = withPropsFrom( 'isVisible', 'setIsVisible', 'updateCurrentPageIndex', + 'showPreview', + 'setShowPreview', ], ); diff --git a/src/modules/reader/constants/ReaderSettings.constants.tsx b/src/modules/reader/constants/ReaderSettings.constants.tsx index 59544c2dfb..ff366fcd8d 100644 --- a/src/modules/reader/constants/ReaderSettings.constants.tsx +++ b/src/modules/reader/constants/ReaderSettings.constants.tsx @@ -57,6 +57,8 @@ const GLOBAL_READER_SETTING_OBJECT: Record = { diff --git a/src/modules/reader/screens/Reader.tsx b/src/modules/reader/screens/Reader.tsx index 71d50bd08f..3e1141bcca 100644 --- a/src/modules/reader/screens/Reader.tsx +++ b/src/modules/reader/screens/Reader.tsx @@ -26,7 +26,7 @@ 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 } from '@/Base.types.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'; @@ -34,11 +34,15 @@ 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 } from '@/modules/reader/constants/ReaderSettings.constants.tsx'; +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 { ReaderHotkeys } from '@/modules/reader/components/ReaderHotkeys.tsx'; import { IReaderSettings, + IReaderSettingsWithDefaultFlag, ReaderResumeMode, ReaderStateChapters, ReaderTransitionPageMode, @@ -56,6 +60,9 @@ 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'; const BaseReader = ({ setTitle, @@ -67,6 +74,11 @@ const BaseReader = ({ setManga, shouldSkipDupChapters, backgroundColor, + readingMode, + tapZoneLayout, + tapZoneInvertMode, + shouldShowReadingModePreview, + shouldShowTapZoneLayoutPreview, setSettings, initialChapter, currentChapter, @@ -82,11 +94,16 @@ const BaseReader = ({ setPageLoadStates, setTransitionPageMode, cancelAutoScroll, + setShowPreview, }: Pick & Pick & Pick & Pick & - Pick & + Pick< + IReaderSettings, + 'shouldSkipDupChapters' | 'backgroundColor' | 'shouldShowReadingModePreview' | 'shouldShowTapZoneLayoutPreview' + > & + Pick & Pick & Pick< ReaderStatePages, @@ -98,7 +115,8 @@ const BaseReader = ({ | 'setPageUrls' | 'setPageLoadStates' | 'setTransitionPageMode' - > & { + > & + Pick & { firstPageUrl?: string; cancelAutoScroll: TReaderAutoScrollContext['cancel']; }) => { @@ -257,9 +275,38 @@ const BaseReader = ({ profile, ); - setSettings(getReaderSettingsFor(mangaFromResponse, profileSettings)); + const finalSettings = getReaderSettingsFor(mangaFromResponse, profileSettings); + setSettings(finalSettings); }, [mangaResponse.data?.manga, defaultSettings]); + // show setting previews on change or when open reader + const previousReadingMode = useRef(); + const previousTapZoneLayout = useRef(); + const previousTapZoneInvertMode = useRef(); + useEffect(() => { + const mangaFromResponse = mangaResponse.data?.manga; + if (!mangaFromResponse || defaultSettingsResponse.loading || defaultSettingsResponse.error) { + return; + } + + const didReadingModeChange = JSON.stringify(readingMode) !== JSON.stringify(previousReadingMode.current); + const showReadingModePreview = shouldShowReadingModePreview && didReadingModeChange; + if (showReadingModePreview) { + previousReadingMode.current = readingMode; + makeToast(t(READING_MODE_VALUE_TO_DISPLAY_DATA[readingMode.value].title as TranslationKey)); + } + + const didTapZoneLayoutChange = + JSON.stringify(tapZoneLayout.value) !== JSON.stringify(previousTapZoneLayout.current) || + JSON.stringify(tapZoneInvertMode.value) !== JSON.stringify(previousTapZoneInvertMode.current); + const showTapZoneLayoutPreview = shouldShowTapZoneLayoutPreview && didTapZoneLayoutChange; + if (showTapZoneLayoutPreview) { + previousTapZoneLayout.current = tapZoneLayout; + previousTapZoneInvertMode.current = tapZoneInvertMode; + setShowPreview(true); + } + }, [readingMode, tapZoneInvertMode, shouldShowReadingModePreview, shouldShowTapZoneLayoutPreview]); + // set chapters state useEffect(() => { const newMangaChapters = chaptersResponse.data?.chapters.nodes; @@ -412,12 +459,30 @@ export const Reader = withPropsFrom( useReaderStateMangaContext, useReaderStateChaptersContext, useReaderStateSettingsContext, - ReaderService.useSettingsWithoutDefaultFlag, + () => { + const { + shouldSkipDupChapters, + backgroundColor, + shouldShowReadingModePreview, + shouldShowTapZoneLayoutPreview, + } = ReaderService.useSettingsWithoutDefaultFlag(); + return { + shouldSkipDupChapters, + backgroundColor, + shouldShowReadingModePreview, + shouldShowTapZoneLayoutPreview, + }; + }, + () => { + const { readingMode, tapZoneLayout, tapZoneInvertMode } = ReaderService.useSettings(); + return { readingMode, tapZoneLayout, tapZoneInvertMode }; + }, userReaderStatePagesContext, () => ({ firstPageUrl: userReaderStatePagesContext().pages[0].primary.url, }), () => ({ cancelAutoScroll: useReaderAutoScrollContext().cancel }), + useReaderTapZoneContext, ], [ 'setTitle', @@ -429,6 +494,11 @@ export const Reader = withPropsFrom( 'setManga', 'shouldSkipDupChapters', 'backgroundColor', + 'readingMode', + 'tapZoneLayout', + 'tapZoneInvertMode', + 'shouldShowReadingModePreview', + 'shouldShowTapZoneLayoutPreview', 'setSettings', 'initialChapter', 'currentChapter', @@ -444,5 +514,6 @@ export const Reader = withPropsFrom( 'setPageLoadStates', 'setTransitionPageMode', 'cancelAutoScroll', + 'setShowPreview', ], ); diff --git a/src/modules/reader/types/Reader.types.ts b/src/modules/reader/types/Reader.types.ts index d8f9424fa5..e2fc6b801c 100644 --- a/src/modules/reader/types/Reader.types.ts +++ b/src/modules/reader/types/Reader.types.ts @@ -132,6 +132,8 @@ export interface IReaderSettingsGlobal { value: number; smooth: boolean; }; + shouldShowReadingModePreview: boolean; + shouldShowTapZoneLayoutPreview: boolean; } export interface IReaderSettingsManga {