diff --git a/src/App.tsx b/src/App.tsx index 79e13028..4a94b481 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -26,13 +26,16 @@ const { Browse } = loadable(() => import('@/screens/Browse'), lazyLoadFallback); const { DownloadQueue } = loadable(() => import('@/screens/DownloadQueue'), lazyLoadFallback); const { Library } = loadable(() => import('@/modules/library/screens/Library.tsx'), lazyLoadFallback); const { Manga } = loadable(() => import('@/modules/manga/screens/Manga.tsx'), lazyLoadFallback); -const { Reader } = loadable(() => import('@/screens/Reader'), lazyLoadFallback); +const { Reader } = loadable(() => import('@/modules/reader/screens/Reader.tsx'), lazyLoadFallback); const { SearchAll } = loadable(() => import('@/screens/SearchAll'), lazyLoadFallback); const { Settings } = loadable(() => import('@/screens/Settings'), lazyLoadFallback); const { About } = loadable(() => import('@/screens/settings/About'), lazyLoadFallback); const { Backup } = loadable(() => import('@/screens/settings/Backup'), lazyLoadFallback); const { Categories } = loadable(() => import('@/screens/settings/Categories'), lazyLoadFallback); -const { DefaultReaderSettings } = loadable(() => import('@/screens/settings/DefaultReaderSettings'), lazyLoadFallback); +const { DefaultReaderSettings } = loadable( + () => import('@/modules/reader/screens/DefaultReaderSettings.tsx'), + lazyLoadFallback, +); const { SourceConfigure } = loadable(() => import('@/screens/SourceConfigure'), lazyLoadFallback); const { SourceMangas } = loadable(() => import('@/screens/SourceMangas'), lazyLoadFallback); const { Updates } = loadable(() => import('@/screens/Updates'), lazyLoadFallback); diff --git a/src/modules/manga/MangaCard.types.tsx b/src/modules/manga/MangaCard.types.tsx index ebda24bb..7ac2e027 100644 --- a/src/modules/manga/MangaCard.types.tsx +++ b/src/modules/manga/MangaCard.types.tsx @@ -14,7 +14,7 @@ import { useManageMangaLibraryState } from '@/modules/manga/hooks/useManageManga import { MangaThumbnailInfo } from '@/modules/manga/services/Mangas.ts'; import { ChapterType, MangaType } from '@/lib/graphql/generated/graphql.ts'; import { SingleModeProps } from '@/modules/manga/components/MangaActionMenuItems.tsx'; -import { IReaderSettings } from '@/typings'; +import { IReaderSettings } from '@/modules/reader/Reader.types'; export type MangaCardMode = 'default' | 'source' | 'migrate.search' | 'migrate.select' | 'duplicate'; diff --git a/src/modules/reader/Reader.constants.ts b/src/modules/reader/Reader.constants.ts new file mode 100644 index 00000000..3f3b400b --- /dev/null +++ b/src/modules/reader/Reader.constants.ts @@ -0,0 +1,21 @@ +/* + * 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 { IReaderSettings } from '@/modules/reader/Reader.types.ts'; + +export const DEFAULT_READER_SETTINGS: IReaderSettings = { + staticNav: false, + showPageNumber: true, + loadNextOnEnding: false, + skipDupChapters: true, + fitPageToWindow: true, + scalePage: false, + readerType: 'ContinuesVertical', + offsetFirstPage: false, + readerWidth: 50, +}; diff --git a/src/modules/reader/Reader.types.ts b/src/modules/reader/Reader.types.ts new file mode 100644 index 00000000..176332fe --- /dev/null +++ b/src/modules/reader/Reader.types.ts @@ -0,0 +1,55 @@ +/* + * 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 { GetChaptersReaderQuery, MangaReaderFieldsFragment } from '@/lib/graphql/generated/graphql.ts'; + +export type ReaderType = + | 'ContinuesVertical' + | 'Webtoon' + | 'SingleVertical' + | 'SingleRTL' + | 'SingleLTR' + | 'DoubleVertical' + | 'DoubleRTL' + | 'DoubleLTR' + | 'ContinuesHorizontalLTR' + | 'ContinuesHorizontalRTL'; + +export interface IReaderSettings { + staticNav: boolean; + showPageNumber: boolean; + loadNextOnEnding: boolean; + skipDupChapters: boolean; + fitPageToWindow: boolean; + scalePage: boolean; + readerType: ReaderType; + offsetFirstPage: boolean; + readerWidth: number; +} + +export type UndefinedReaderSettings = { + [setting in keyof IReaderSettings]: IReaderSettings[setting] | undefined; +}; + +export interface IReaderPage { + index: number; + src: string; +} + +export interface IReaderProps { + pages: Array; + pageCount: number; + setCurPage: React.Dispatch>; + curPage: number; + initialPage: number; + settings: IReaderSettings; + manga: MangaReaderFieldsFragment; + chapter: GetChaptersReaderQuery['chapters']['nodes'][number]; + nextChapter: () => void; + prevChapter: () => void; +} diff --git a/src/components/navbar/ReaderNavBar.tsx b/src/modules/reader/components/ReaderNavBar.tsx similarity index 98% rename from src/components/navbar/ReaderNavBar.tsx rename to src/modules/reader/components/ReaderNavBar.tsx index 9a80129c..d1bd2b34 100644 --- a/src/components/navbar/ReaderNavBar.tsx +++ b/src/modules/reader/components/ReaderNavBar.tsx @@ -27,8 +27,8 @@ import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import Collapse from '@mui/material/Collapse'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, IReaderSettings } from '@/typings'; -import { ReaderSettingsOptions } from '@/components/reader/ReaderSettingsOptions'; +import { AllowedMetadataValueTypes } from '@/typings.ts'; +import { ReaderSettingsOptions } from '@/modules/reader/components/ReaderSettingsOptions.tsx'; import { useBackButton } from '@/modules/core/hooks/useBackButton.ts'; import { Select } from '@/modules/core/components/inputs/Select.tsx'; import { useGetOptionForDirection } from '@/theme.tsx'; @@ -37,6 +37,7 @@ import { MangaChapterCountInfo, MangaIdInfo } from '@/modules/manga/services/Man import { useNavBarContext } from '@/components/context/NavbarContext.tsx'; import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; import { CustomIconButton } from '@/modules/core/components/buttons/CustomIconButton.tsx'; +import { IReaderSettings } from '@/modules/reader/Reader.types.ts'; import { DirectionOffset } from '@/Base.types.ts'; const Root = styled('div')({ diff --git a/src/components/reader/ReaderSettingsOptions.tsx b/src/modules/reader/components/ReaderSettingsOptions.tsx similarity index 96% rename from src/components/reader/ReaderSettingsOptions.tsx rename to src/modules/reader/components/ReaderSettingsOptions.tsx index 5d655ebb..54a92462 100644 --- a/src/components/reader/ReaderSettingsOptions.tsx +++ b/src/modules/reader/components/ReaderSettingsOptions.tsx @@ -12,10 +12,11 @@ import ListItemText from '@mui/material/ListItemText'; import Switch from '@mui/material/Switch'; import MenuItem from '@mui/material/MenuItem'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, IReaderSettings } from '@/typings'; +import { AllowedMetadataValueTypes } from '@/typings.ts'; import { NumberSetting } from '@/modules/core/components/settings/NumberSetting.tsx'; -import { isHorizontalReaderType } from '@/components/reader/Page.tsx'; +import { isHorizontalReaderType } from '@/modules/reader/components/page/Page.tsx'; import { Select } from '@/modules/core/components/inputs/Select.tsx'; +import { IReaderSettings } from '@/modules/reader/Reader.types.ts'; interface IProps extends IReaderSettings { setSettingValue: (key: keyof IReaderSettings, value: AllowedMetadataValueTypes, persist?: boolean) => void; diff --git a/src/components/reader/DoublePage.tsx b/src/modules/reader/components/page/DoublePage.tsx similarity index 95% rename from src/components/reader/DoublePage.tsx rename to src/modules/reader/components/page/DoublePage.tsx index ba105ba5..f0181ff5 100644 --- a/src/components/reader/DoublePage.tsx +++ b/src/modules/reader/components/page/DoublePage.tsx @@ -8,10 +8,10 @@ import { CSSProperties, forwardRef } from 'react'; import Box from '@mui/material/Box'; -import { IReaderSettings } from '@/typings'; import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx'; -import { imageStyle } from '@/components/reader/Page'; +import { imageStyle } from '@/modules/reader/components/page/Page.tsx'; import { getOptionForDirection } from '@/theme.tsx'; +import { IReaderSettings } from '@/modules/reader/Reader.types.ts'; interface IProps { index: number; diff --git a/src/components/reader/Page.tsx b/src/modules/reader/components/page/Page.tsx similarity index 97% rename from src/components/reader/Page.tsx rename to src/modules/reader/components/page/Page.tsx index 85f7678e..e33afd38 100644 --- a/src/components/reader/Page.tsx +++ b/src/modules/reader/components/page/Page.tsx @@ -10,9 +10,9 @@ import { CSSProperties, forwardRef } from 'react'; import Box from '@mui/material/Box'; import { useTheme } from '@mui/material/styles'; import useMediaQuery from '@mui/material/useMediaQuery'; -import { IReaderSettings, ReaderType } from '@/typings'; import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx'; import { MediaQuery } from '@/lib/ui/MediaQuery.tsx'; +import { IReaderSettings, ReaderType } from '@/modules/reader/Reader.types.ts'; export const isHorizontalReaderType = (readerType: ReaderType): boolean => ['ContinuesHorizontalLTR', 'ContinuesHorizontalRTL'].includes(readerType); diff --git a/src/components/reader/PageNumber.tsx b/src/modules/reader/components/page/PageNumber.tsx similarity index 93% rename from src/components/reader/PageNumber.tsx rename to src/modules/reader/components/page/PageNumber.tsx index de268f38..9cfaa686 100644 --- a/src/components/reader/PageNumber.tsx +++ b/src/modules/reader/components/page/PageNumber.tsx @@ -7,7 +7,8 @@ */ import Box from '@mui/material/Box'; -import { IReaderSettings } from '@/typings'; + +import { IReaderSettings } from '@/modules/reader/Reader.types.ts'; interface IProps { settings: IReaderSettings; diff --git a/src/components/reader/pager/DoublePagedPager.tsx b/src/modules/reader/components/pager/DoublePagedPager.tsx similarity index 98% rename from src/components/reader/pager/DoublePagedPager.tsx rename to src/modules/reader/components/pager/DoublePagedPager.tsx index 0b0c88c1..8d613cdb 100644 --- a/src/components/reader/pager/DoublePagedPager.tsx +++ b/src/modules/reader/components/pager/DoublePagedPager.tsx @@ -8,8 +8,8 @@ import { MouseEvent, useEffect, useRef, useState } from 'react'; import Box from '@mui/material/Box'; -import { IReaderProps } from '@/typings'; -import { Page } from '@/components/reader/Page'; +import { Page } from '@/modules/reader/components/page/Page.tsx'; +import { IReaderProps } from '@/modules/reader/Reader.types.ts'; const isSpreadPage = (image: HTMLImageElement): boolean => { const aspectRatio = image.height / image.width; diff --git a/src/components/reader/pager/HorizontalPager.tsx b/src/modules/reader/components/pager/HorizontalPager.tsx similarity index 98% rename from src/components/reader/pager/HorizontalPager.tsx rename to src/modules/reader/components/pager/HorizontalPager.tsx index 609fb2b6..0e149bed 100644 --- a/src/components/reader/pager/HorizontalPager.tsx +++ b/src/modules/reader/components/pager/HorizontalPager.tsx @@ -8,9 +8,9 @@ import { MouseEvent as ReactMouseEvent, WheelEvent as ReactWheelEvent, useCallback, useEffect, useRef } from 'react'; import Box from '@mui/material/Box'; -import { IReaderProps } from '@/typings'; -import { Page } from '@/components/reader/Page'; +import { Page } from '@/modules/reader/components/page/Page.tsx'; import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; +import { IReaderProps } from '@/modules/reader/Reader.types.ts'; const findCurrentPageIndex = (wrapper: HTMLDivElement): number => { for (let i = 0; i < wrapper.children.length; i++) { diff --git a/src/components/reader/pager/PagedPager.tsx b/src/modules/reader/components/pager/PagedPager.tsx similarity index 96% rename from src/components/reader/pager/PagedPager.tsx rename to src/modules/reader/components/pager/PagedPager.tsx index b5e5aee2..50e484a1 100644 --- a/src/components/reader/pager/PagedPager.tsx +++ b/src/modules/reader/components/pager/PagedPager.tsx @@ -8,8 +8,8 @@ import { MouseEvent, useEffect, useRef } from 'react'; import Box from '@mui/material/Box'; -import { IReaderProps } from '@/typings'; -import { Page } from '@/components/reader/Page'; +import { Page } from '@/modules/reader/components/page/Page.tsx'; +import { IReaderProps } from '@/modules/reader/Reader.types.ts'; export function PagedPager(props: IReaderProps) { const { pages, settings, setCurPage, initialPage, curPage, nextChapter, prevChapter } = props; diff --git a/src/components/reader/pager/VerticalPager.tsx b/src/modules/reader/components/pager/VerticalPager.tsx similarity index 98% rename from src/components/reader/pager/VerticalPager.tsx rename to src/modules/reader/components/pager/VerticalPager.tsx index 0d42cd55..a131e6e3 100644 --- a/src/components/reader/pager/VerticalPager.tsx +++ b/src/modules/reader/components/pager/VerticalPager.tsx @@ -8,9 +8,9 @@ import { useCallback, useEffect, useRef } from 'react'; import Box from '@mui/material/Box'; -import { IReaderProps } from '@/typings'; -import { Page } from '@/components/reader/Page'; +import { Page } from '@/modules/reader/components/page/Page.tsx'; import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; +import { IReaderProps } from '@/modules/reader/Reader.types.ts'; const findCurrentPageIndex = (wrapper: HTMLDivElement): number => { for (let i = 0; i < wrapper.children.length; i++) { diff --git a/src/screens/settings/DefaultReaderSettings.tsx b/src/modules/reader/screens/DefaultReaderSettings.tsx similarity index 88% rename from src/screens/settings/DefaultReaderSettings.tsx rename to src/modules/reader/screens/DefaultReaderSettings.tsx index 1a5f9290..c6f5aaa5 100644 --- a/src/screens/settings/DefaultReaderSettings.tsx +++ b/src/modules/reader/screens/DefaultReaderSettings.tsx @@ -8,19 +8,20 @@ import { useContext, useLayoutEffect } from 'react'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, IReaderSettings } from '@/typings'; +import { AllowedMetadataValueTypes } from '@/typings.ts'; import { convertToGqlMeta, requestUpdateServerMetadata } from '@/lib/metadata/metadata.ts'; import { checkAndHandleMissingStoredReaderSettings, - getDefaultSettings, useDefaultReaderSettings, -} from '@/lib/metadata/readerSettings.ts'; -import { ReaderSettingsOptions } from '@/components/reader/ReaderSettingsOptions'; +} from '@/modules/reader/services/ReaderSettingsMetadata.ts'; +import { ReaderSettingsOptions } from '@/modules/reader/components/ReaderSettingsOptions.tsx'; import { makeToast } from '@/lib/ui/Toast.ts'; -import { NavBarContext } from '@/components/context/NavbarContext'; +import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx'; +import { DEFAULT_READER_SETTINGS } from '@/modules/reader/Reader.constants.ts'; +import { IReaderSettings } from '@/modules/reader/Reader.types.ts'; export function DefaultReaderSettings() { const { t } = useTranslation(); @@ -67,7 +68,7 @@ export function DefaultReaderSettings() { checkAndHandleMissingStoredReaderSettings( { meta: convertToGqlMeta(metadata)! }, 'server', - getDefaultSettings(), + DEFAULT_READER_SETTINGS, ).catch(defaultPromiseErrorHandler('DefaultReaderSettings::checkAndHandleMissingStoredReaderSettings')); return ( diff --git a/src/screens/Reader.tsx b/src/modules/reader/screens/Reader.tsx similarity index 96% rename from src/screens/Reader.tsx rename to src/modules/reader/screens/Reader.tsx index e7e387eb..0f91a554 100644 --- a/src/screens/Reader.tsx +++ b/src/modules/reader/screens/Reader.tsx @@ -11,20 +11,20 @@ import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, u import { useLocation, useNavigate, useParams } from 'react-router-dom'; import Box from '@mui/material/Box'; import { useTranslation } from 'react-i18next'; -import { AllowedMetadataValueTypes, IReaderSettings, ReaderType } from '@/typings'; +import { AllowedMetadataValueTypes } from '@/typings.ts'; import { requestManager } from '@/lib/requests/requests/RequestManager.ts'; import { checkAndHandleMissingStoredReaderSettings, getReaderSettingsFor, useDefaultReaderSettings, -} from '@/lib/metadata/readerSettings.ts'; +} from '@/modules/reader/services/ReaderSettingsMetadata.ts'; import { requestUpdateMangaMetadata } from '@/lib/metadata/metadata.ts'; -import { HorizontalPager } from '@/components/reader/pager/HorizontalPager'; -import { PageNumber } from '@/components/reader/PageNumber'; -import { PagedPager } from '@/components/reader/pager/PagedPager'; -import { DoublePagedPager } from '@/components/reader/pager/DoublePagedPager'; -import { VerticalPager } from '@/components/reader/pager/VerticalPager'; -import { ReaderNavBar } from '@/components/navbar/ReaderNavBar'; +import { HorizontalPager } from '@/modules/reader/components/pager/HorizontalPager.tsx'; +import { PageNumber } from '@/modules/reader/components/page/PageNumber.tsx'; +import { PagedPager } from '@/modules/reader/components/pager/PagedPager.tsx'; +import { DoublePagedPager } from '@/modules/reader/components/pager/DoublePagedPager.tsx'; +import { VerticalPager } from '@/modules/reader/components/pager/VerticalPager.tsx'; +import { ReaderNavBar } from '@/modules/reader/components/ReaderNavBar.tsx'; import { makeToast } from '@/lib/ui/Toast.ts'; import { NavBarContext } from '@/components/context/NavbarContext.tsx'; import { useDebounce } from '@/modules/core/hooks/useDebounce.ts'; @@ -43,6 +43,7 @@ import { GET_MANGA_READER } from '@/lib/graphql/queries/MangaQuery.ts'; import { TMangaReader } from '@/modules/manga/services/Mangas.ts'; import { CHAPTER_READER_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts'; import { MediaQuery } from '@/lib/ui/MediaQuery.tsx'; +import { IReaderSettings, ReaderType } from '@/modules/reader/Reader.types.ts'; import { DirectionOffset } from '@/Base.types.ts'; type TChapter = GetChaptersReaderQuery['chapters']['nodes'][number]; diff --git a/src/lib/metadata/readerSettings.ts b/src/modules/reader/services/ReaderSettingsMetadata.ts similarity index 86% rename from src/lib/metadata/readerSettings.ts rename to src/modules/reader/services/ReaderSettingsMetadata.ts index a326885e..ce230194 100644 --- a/src/lib/metadata/readerSettings.ts +++ b/src/modules/reader/services/ReaderSettingsMetadata.ts @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Metadata, IReaderSettings, MetadataKeyValuePair, GqlMetaHolder } from '@/typings.ts'; +import { GqlMetaHolder, Metadata, MetadataKeyValuePair } from '@/typings.ts'; import { requestManager } from '@/lib/requests/requests/RequestManager.ts'; import { convertFromGqlMeta, @@ -16,26 +16,12 @@ import { } from '@/lib/metadata/metadata.ts'; import { MetaType } from '@/lib/graphql/generated/graphql.ts'; import { MangaIdInfo } from '@/modules/manga/services/Mangas.ts'; - -type UndefinedReaderSettings = { - [setting in keyof IReaderSettings]: IReaderSettings[setting] | undefined; -}; - -export const getDefaultSettings = (): IReaderSettings => ({ - staticNav: false, - showPageNumber: true, - loadNextOnEnding: false, - skipDupChapters: true, - fitPageToWindow: true, - scalePage: false, - readerType: 'ContinuesVertical', - offsetFirstPage: false, - readerWidth: 50, -}); +import { DEFAULT_READER_SETTINGS } from '@/modules/reader/Reader.constants.ts'; +import { IReaderSettings, UndefinedReaderSettings } from '@/modules/reader/Reader.types.ts'; const getReaderSettingsWithDefaultValueFallback = ( meta?: Metadata, - defaultSettings: DefaultSettings = getDefaultSettings() as DefaultSettings, + defaultSettings: DefaultSettings = DEFAULT_READER_SETTINGS as DefaultSettings, applyMetadataMigration: boolean = true, ): DefaultSettings => getMetadataFrom({ meta }, defaultSettings, applyMetadataMigration); diff --git a/src/typings.ts b/src/typings.ts index 66587ea7..b20488bf 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -9,11 +9,9 @@ import { OverridableComponent } from '@mui/material/OverridableComponent'; import { SvgIconTypeMap } from '@mui/material/SvgIcon'; import { - GetChaptersReaderQuery, GetServerSettingsQuery, GetSourceBrowseQuery, GetSourceSettingsQuery, - MangaReaderFieldsFragment, MetaType, SourcePreferenceChangeInput, } from '@/lib/graphql/generated/graphql.ts'; @@ -88,30 +86,6 @@ export interface INavbarOverride { value: any; } -export type ReaderType = - | 'ContinuesVertical' - | 'Webtoon' - | 'SingleVertical' - | 'SingleRTL' - | 'SingleLTR' - | 'DoubleVertical' - | 'DoubleRTL' - | 'DoubleLTR' - | 'ContinuesHorizontalLTR' - | 'ContinuesHorizontalRTL'; - -export interface IReaderSettings { - staticNav: boolean; - showPageNumber: boolean; - loadNextOnEnding: boolean; - skipDupChapters: boolean; - fitPageToWindow: boolean; - scalePage: boolean; - readerType: ReaderType; - offsetFirstPage: boolean; - readerWidth: number; -} - export type MetadataDownloadSettings = { deleteChaptersManuallyMarkedRead: boolean; deleteChaptersWhileReading: number; @@ -163,24 +137,6 @@ export interface ISearchSettings { ignoreFilters: boolean; } -export interface IReaderPage { - index: number; - src: string; -} - -export interface IReaderProps { - pages: Array; - pageCount: number; - setCurPage: React.Dispatch>; - curPage: number; - initialPage: number; - settings: IReaderSettings; - manga: MangaReaderFieldsFragment; - chapter: GetChaptersReaderQuery['chapters']['nodes'][number]; - nextChapter: () => void; - prevChapter: () => void; -} - export type SourcePreferences = GetSourceSettingsQuery['source']['preferences'][number]; export interface PreferenceProps {