diff --git a/src/modules/backup/screens/Backup.tsx b/src/modules/backup/screens/Backup.tsx index 8ee6b68c..8fa6158b 100644 --- a/src/modules/backup/screens/Backup.tsx +++ b/src/modules/backup/screens/Backup.tsx @@ -38,6 +38,7 @@ import { ServerSettings } from '@/modules/settings/Settings.types.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type BackupSettingsType = Pick; @@ -60,13 +61,12 @@ let backupRestoreId: string | undefined; export function Backup() { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.backup.title')); useLayoutEffect(() => { - setTitle(t('settings.backup.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/browse/screens/Browse.tsx b/src/modules/browse/screens/Browse.tsx index 7d1b884f..139d2162 100644 --- a/src/modules/browse/screens/Browse.tsx +++ b/src/modules/browse/screens/Browse.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { useCallback, useLayoutEffect, useRef, useState } from 'react'; +import { useCallback, useRef, useState } from 'react'; import Tab from '@mui/material/Tab'; import { useTranslation } from 'react-i18next'; import { StringParam, useQueryParam } from 'use-query-params'; @@ -17,8 +17,8 @@ import { TabsWrapper } from '@/modules/core/components/tabs/TabsWrapper.tsx'; import { TabsMenu } from '@/modules/core/components/tabs/TabsMenu.tsx'; import { Migration } from '@/modules/migration/screens/Migration.tsx'; import { useResizeObserver } from '@/modules/core/hooks/useResizeObserver.tsx'; -import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { GROUPED_VIRTUOSO_Z_INDEX } from '@/modules/core/AppRoute.constants.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; enum Tabs { SOURCE = 'source', @@ -28,11 +28,7 @@ enum Tabs { export function Browse() { const { t } = useTranslation(); - const { setTitle } = useNavBarContext(); - - useLayoutEffect(() => { - setTitle(t('global.label.browse')); - }, [t]); + useAppTitle(t('global.label.browse')); const tabsMenuRef = useRef(null); const [tabsMenuHeight, setTabsMenuHeight] = useState(0); diff --git a/src/modules/browse/screens/BrowseSettings.tsx b/src/modules/browse/screens/BrowseSettings.tsx index 91c168c1..8ed1018d 100644 --- a/src/modules/browse/screens/BrowseSettings.tsx +++ b/src/modules/browse/screens/BrowseSettings.tsx @@ -28,6 +28,7 @@ import { MetadataBrowseSettings } from '@/modules/browse/Browse.types.ts'; import { ServerSettings as GqlServerSettings } from '@/modules/settings/Settings.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type ExtensionsSettings = Pick; @@ -39,10 +40,10 @@ const extractBrowseSettings = (settings: GqlServerSettings): ExtensionsSettings export const BrowseSettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('global.label.browse')); useLayoutEffect(() => { - setTitle(t('global.label.browse')); setAction(null); }, [t]); diff --git a/src/modules/category/screens/CategorySettings.tsx b/src/modules/category/screens/CategorySettings.tsx index 4e5b9790..31f5e414 100644 --- a/src/modules/category/screens/CategorySettings.tsx +++ b/src/modules/category/screens/CategorySettings.tsx @@ -37,17 +37,17 @@ import { makeToast } from '@/modules/core/utils/Toast.ts'; import { DndSortableItem } from '@/lib/dnd-kit/DndSortableItem.tsx'; import { DndKitUtil } from '@/lib/dnd-kit/DndKitUtil.ts'; import { DndOverlayItem } from '@/lib/dnd-kit/DndOverlayItem.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export function CategorySettings() { const { t } = useTranslation(); + useAppTitle(t('category.dialog.title.edit_category_other')); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); useLayoutEffect(() => { - setTitle(t('category.dialog.title.edit_category_other')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/device/screens/DeviceSetting.tsx b/src/modules/device/screens/DeviceSetting.tsx index f01b8e9b..61360df1 100644 --- a/src/modules/device/screens/DeviceSetting.tsx +++ b/src/modules/device/screens/DeviceSetting.tsx @@ -27,17 +27,18 @@ import { DEFAULT_DEVICE } from '@/modules/device/services/Device.ts'; import { MetadataServerSettingKeys, MetadataServerSettings } from '@/modules/settings/Settings.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const DeviceSetting = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + + useAppTitle(t('settings.device.title.device')); useLayoutEffect(() => { - setTitle(t('settings.device.title.device')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/downloads/screens/DownloadQueue.tsx b/src/modules/downloads/screens/DownloadQueue.tsx index 378af32c..73b777c8 100644 --- a/src/modules/downloads/screens/DownloadQueue.tsx +++ b/src/modules/downloads/screens/DownloadQueue.tsx @@ -31,10 +31,13 @@ import { DndSortableItem } from '@/lib/dnd-kit/DndSortableItem.tsx'; import { DndKitUtil } from '@/lib/dnd-kit/DndKitUtil.ts'; import { DndOverlayItem } from '@/lib/dnd-kit/DndOverlayItem.tsx'; import { DownloadQueueChapterCard } from '@/modules/downloads/components/DownloadQueueChapterCard.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const DownloadQueue: React.FC = () => { const { t } = useTranslation(); + useAppTitle(t('download.queue.title')); + const [reorderDownload, { reset: revertReorder }] = requestManager.useReorderChapterInDownloadQueue(); const { @@ -49,7 +52,7 @@ export const DownloadQueue: React.FC = () => { const status = downloaderData?.state ?? DownloaderState.Started; const isQueueEmpty = !queue.length; - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const dndItems = useMemo(() => queue.map((download) => download.chapter), [queue]); const dndSensors = DndKitUtil.useSensorsForDevice(); @@ -97,7 +100,6 @@ export const DownloadQueue: React.FC = () => { }; useLayoutEffect(() => { - setTitle(t('download.queue.title')); setAction( <> @@ -118,7 +120,6 @@ export const DownloadQueue: React.FC = () => { ); return () => { - setTitle(''); setAction(null); }; }, [t, status, isQueueEmpty]); diff --git a/src/modules/downloads/screens/DownloadSettings.tsx b/src/modules/downloads/screens/DownloadSettings.tsx index 39ce9800..cab87d3c 100644 --- a/src/modules/downloads/screens/DownloadSettings.tsx +++ b/src/modules/downloads/screens/DownloadSettings.tsx @@ -33,6 +33,7 @@ import { MetadataDownloadSettings } from '@/modules/downloads/Downloads.types.ts import { ServerSettings } from '@/modules/settings/Settings.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type DownloadSettingsType = Pick< ServerSettings, @@ -55,14 +56,14 @@ const extractDownloadSettings = (settings: ServerSettings): DownloadSettingsType export const DownloadSettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + + useAppTitle(t('download.title.download')); useLayoutEffect(() => { - setTitle(t('download.title.download')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/global-search/screens/SearchAll.tsx b/src/modules/global-search/screens/SearchAll.tsx index 3cfb770c..a23b18fc 100644 --- a/src/modules/global-search/screens/SearchAll.tsx +++ b/src/modules/global-search/screens/SearchAll.tsx @@ -34,6 +34,7 @@ import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContex import { Sources } from '@/modules/source/services/Sources.ts'; import { SourceDisplayNameInfo, SourceIdInfo } from '@/modules/source/Source.types.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean; error: any }; type SourceToLoadingStateMap = Map; @@ -188,12 +189,12 @@ const SourceSearchPreview = React.memo( export const SearchAll: React.FC = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const { pathname, state } = useLocation<{ mangaTitle?: string }>(); const isMigrateMode = pathname.startsWith('/migrate/source'); - const mangaTitle = state?.mangaTitle; + useAppTitle(t(isMigrateMode ? 'migrate.search.title' : 'search.title.global_search', { title: state?.mangaTitle })); const [query] = useQueryParam('query', StringParam); const searchString = useDebounce(query, TRIGGER_SEARCH_THRESHOLD); @@ -236,7 +237,6 @@ export const SearchAll: React.FC = () => { ); useLayoutEffect(() => { - setTitle(t(isMigrateMode ? 'migrate.search.title' : 'search.title.global_search', { title: mangaTitle })); setAction( <> @@ -249,7 +249,6 @@ export const SearchAll: React.FC = () => { ); return () => { - setTitle(''); setAction(null); }; }, [t, shownLangs, setShownLangs, sources]); diff --git a/src/modules/history/screens/History.tsx b/src/modules/history/screens/History.tsx index c3ba60fc..7d9bb79d 100644 --- a/src/modules/history/screens/History.tsx +++ b/src/modules/history/screens/History.tsx @@ -7,7 +7,7 @@ */ import Typography from '@mui/material/Typography'; -import React, { useCallback, useLayoutEffect, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx'; @@ -18,14 +18,15 @@ import { StyledGroupItemWrapper } from '@/modules/core/components/virtuoso/Style import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'; import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; -import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { ChapterHistoryCard } from '@/modules/history/components/ChapterHistoryCard.tsx'; import { Chapters } from '@/modules/chapter/services/Chapters.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const History: React.FC = () => { const { t } = useTranslation(); - const { setTitle } = useNavBarContext(); + useAppTitle(t('history.title')); + const { data: chapterHistoryData, loading: isLoading, @@ -54,14 +55,6 @@ export const History: React.FC = () => { useCallback((index) => readEntries[index].id, [readEntries]), ); - useLayoutEffect(() => { - setTitle(t('history.title')); - - return () => { - setTitle(''); - }; - }, [t]); - const loadMore = useCallback(() => { if (!hasNextPage) { return; diff --git a/src/modules/history/screens/HistorySettings.tsx b/src/modules/history/screens/HistorySettings.tsx index 3f2caaf8..6b02ba1c 100644 --- a/src/modules/history/screens/HistorySettings.tsx +++ b/src/modules/history/screens/HistorySettings.tsx @@ -23,13 +23,15 @@ import { makeToast } from '@/modules/core/utils/Toast.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { MetadataHistorySettings } from '@/modules/history/History.types.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const HistorySettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + + useAppTitle(t('history.title')); useLayoutEffect(() => { - setTitle(t('history.title')); setAction(null); }, [t]); diff --git a/src/modules/library/screens/Library.tsx b/src/modules/library/screens/Library.tsx index 355604a2..d679cf5f 100644 --- a/src/modules/library/screens/Library.tsx +++ b/src/modules/library/screens/Library.tsx @@ -44,6 +44,7 @@ import { useMetadataServerSettings } from '@/modules/settings/services/ServerSet import { getCategoryMetadata } from '@/modules/category/services/CategoryMetadata.ts'; import { GET_LIBRARY_MANGA_COUNT } from '@/lib/graphql/queries/MangaQuery.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; const TitleWithSizeTag = styled('span')({ display: 'flex', @@ -166,16 +167,16 @@ export function Library() { ); }, [isSelectModeActive, selectedMangas]); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle( + + {t('library.title')} + {showTabSize && } + , + t('library.title'), + [t, showTabSize, librarySize], + ); useLayoutEffect(() => { - const title = t('library.title'); - const navBarTitle = ( - - {title} - {showTabSize && } - - ); - setTitle(navBarTitle, title); setAction( <> {!isSelectModeActive && activeTab && ( @@ -205,7 +206,6 @@ export function Library() { , ); return () => { - setTitle(''); setAction(null); }; }, [ diff --git a/src/modules/library/screens/LibraryDuplicates.tsx b/src/modules/library/screens/LibraryDuplicates.tsx index 304d78ef..89ef0ca0 100644 --- a/src/modules/library/screens/LibraryDuplicates.tsx +++ b/src/modules/library/screens/LibraryDuplicates.tsx @@ -35,6 +35,7 @@ import { LibraryDuplicatesWorkerInput, TMangaDuplicate, TMangaDuplicates } from import { GridLayout } from '@/modules/core/Core.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const LibraryDuplicates = () => { const { t } = useTranslation(); @@ -45,9 +46,9 @@ export const LibraryDuplicates = () => { false, ); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('library.settings.advanced.duplicates.label.title')); useLayoutEffect(() => { - setTitle(t('library.settings.advanced.duplicates.label.title')); setAction( <> @@ -75,7 +76,6 @@ export const LibraryDuplicates = () => { ); return () => { - setTitle(''); setAction(null); }; }, [t, gridLayout, checkAlternativeTitles]); diff --git a/src/modules/library/screens/LibrarySettings.tsx b/src/modules/library/screens/LibrarySettings.tsx index 34c9f7e0..1b247a1a 100644 --- a/src/modules/library/screens/LibrarySettings.tsx +++ b/src/modules/library/screens/LibrarySettings.tsx @@ -39,6 +39,7 @@ import { MetadataLibrarySettings } from '@/modules/library/Library.types.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; const removeNonLibraryMangasFromCategories = async (): Promise => { try { @@ -64,14 +65,13 @@ const removeNonLibraryMangasFromCategories = async (): Promise => { export function LibrarySettings() { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('library.title')); useLayoutEffect(() => { - setTitle(t('library.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/manga/screens/Manga.tsx b/src/modules/manga/screens/Manga.tsx index 24ab9175..4d70cbf6 100644 --- a/src/modules/manga/screens/Manga.tsx +++ b/src/modules/manga/screens/Manga.tsx @@ -27,11 +27,12 @@ import { GetMangaScreenQuery } from '@/lib/graphql/generated/graphql.ts'; import { GET_MANGA_SCREEN } from '@/lib/graphql/queries/MangaQuery.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const Manga: React.FC = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const { id } = useParams<{ id: string }>(); const autofetchedRef = useRef(false); @@ -59,12 +60,11 @@ export const Manga: React.FC = () => { } }, [manga]); + useAppTitle(manga?.title ?? t('manga.title_one')); useLayoutEffect(() => { - setTitle(manga?.title ?? t('manga.title_one')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t, manga?.title]); diff --git a/src/modules/migration/screens/Migrate.tsx b/src/modules/migration/screens/Migrate.tsx index 9c6bd094..40d633e9 100644 --- a/src/modules/migration/screens/Migrate.tsx +++ b/src/modules/migration/screens/Migrate.tsx @@ -23,10 +23,11 @@ import { BaseMangaGrid } from '@/modules/manga/components/BaseMangaGrid.tsx'; import { GridLayout } from '@/modules/core/Core.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const Migrate = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const { sourceId: paramSourceId } = useParams<{ sourceId: string }>(); @@ -68,12 +69,11 @@ export const Migrate = () => { notifyOnNetworkStatusChange: true, }); + useAppTitle(name ?? sourceId ?? t('migrate.title')); useLayoutEffect(() => { - setTitle(name ?? sourceId ?? t('migrate.title')); setAction(); return () => { - setTitle(''); setAction(null); }; }, [t, name, sourceId, gridLayout]); diff --git a/src/modules/navigation-bar/hooks/useAppTitle.ts b/src/modules/navigation-bar/hooks/useAppTitle.ts new file mode 100644 index 00000000..fd71d9d3 --- /dev/null +++ b/src/modules/navigation-bar/hooks/useAppTitle.ts @@ -0,0 +1,37 @@ +/* + * 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 { useLayoutEffect } from 'react'; +import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts'; + +export function useAppTitle( + title: NavbarContextType['title'], + browserTitleOrDependencies: string, + dependencies?: any[], +): void; +export function useAppTitle(title: NavbarContextType['title'], browserTitleOrDependencies?: any[]): void; +export function useAppTitle( + title: NavbarContextType['title'], + browserTitleOrDependencies?: string | any[], + dependencies: any[] = [title, browserTitleOrDependencies], +): void { + const { setTitle } = useNavBarContext(); + + useLayoutEffect(() => { + if (typeof browserTitleOrDependencies === 'string') { + setTitle(title, browserTitleOrDependencies); + } else { + setTitle(title); + } + + return () => { + setTitle(''); + }; + }, dependencies); +} diff --git a/src/modules/reader/screens/GlobalReaderSettings.tsx b/src/modules/reader/screens/GlobalReaderSettings.tsx index 8fa8e25c..a5e547d9 100644 --- a/src/modules/reader/screens/GlobalReaderSettings.tsx +++ b/src/modules/reader/screens/GlobalReaderSettings.tsx @@ -18,17 +18,17 @@ import { ReaderService } from '@/modules/reader/services/ReaderService.ts'; import { ReaderSettingsTabs } from '@/modules/reader/components/settings/ReaderSettingsTabs.tsx'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { GLOBAL_READER_SETTINGS_MANGA } from '@/modules/manga/Manga.constants.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const GlobalReaderSettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('reader.settings.title.reader')); useLayoutEffect(() => { - setTitle(t('reader.settings.title.reader')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/reader/screens/Reader.tsx b/src/modules/reader/screens/Reader.tsx index 83eb00b7..61e9ba03 100644 --- a/src/modules/reader/screens/Reader.tsx +++ b/src/modules/reader/screens/Reader.tsx @@ -51,9 +51,9 @@ import { useReaderResetStates } from '@/modules/reader/hooks/useReaderResetState import { useReaderSetSettingsState } from '@/modules/reader/hooks/useReaderSetSettingsState.ts'; import { useReaderShowSettingPreviewOnChange } from '@/modules/reader/hooks/useReaderShowSettingPreviewOnChange.ts'; import { useReaderSetChaptersState } from '@/modules/reader/hooks/useReaderSetChaptersState.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; const BaseReader = ({ - setTitle, setOverride, readerNavBarWidth, isVisible: isOverlayVisible, @@ -81,7 +81,7 @@ const BaseReader = ({ setTransitionPageMode, cancelAutoScroll, setShowPreview, -}: Pick & +}: Pick & Pick & Pick & Pick & @@ -123,6 +123,12 @@ const BaseReader = ({ const mangaResponse = requestManager.useGetManga(GET_MANGA_READER, mangaId); const chaptersResponse = requestManager.useGetMangaChapters(GET_CHAPTERS_READER, mangaId); + useAppTitle( + !manga || !currentChapter + ? t('reader.title', { mangaId, chapterIndex: chapterSourceOrder }) + : `${manga.title}: ${currentChapter.name}`, + ); + const { metadata: defaultSettingsMetadata, settings: defaultSettings, @@ -137,15 +143,6 @@ const BaseReader = ({ defaultSettingsResponse.loading; const error = mangaResponse.error ?? chaptersResponse.error ?? defaultSettingsResponse.error; - useLayoutEffect(() => { - if (!manga || !currentChapter) { - setTitle(t('reader.title', { mangaId, chapterIndex: chapterSourceOrder })); - return; - } - - setTitle(`${manga.title}: ${currentChapter.name}`); - }, [t, mangaId, chapterSourceOrder, manga, currentChapter]); - useEffect(() => { setManga(mangaResponse.data?.manga); }, [mangaResponse.data?.manga]); @@ -319,7 +316,6 @@ export const Reader = withPropsFrom( useReaderTapZoneContext, ], [ - 'setTitle', 'setOverride', 'readerNavBarWidth', 'isVisible', diff --git a/src/modules/settings/screens/About.tsx b/src/modules/settings/screens/About.tsx index e95a1bef..be459e0f 100644 --- a/src/modules/settings/screens/About.tsx +++ b/src/modules/settings/screens/About.tsx @@ -23,17 +23,17 @@ import { VersionInfo } from '@/modules/app-updates/components/VersionInfo.tsx'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { epochToDate } from '@/util/DateHelper.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export function About() { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.about.title')); useLayoutEffect(() => { - setTitle(t('settings.about.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/settings/screens/Appearance.tsx b/src/modules/settings/screens/Appearance.tsx index 66dc095f..a085f32f 100644 --- a/src/modules/settings/screens/Appearance.tsx +++ b/src/modules/settings/screens/Appearance.tsx @@ -36,6 +36,7 @@ import { MetadataThemeSettings } from '@/modules/theme/AppTheme.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { AppStorage } from '@/lib/storage/AppStorage.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const Appearance = () => { const { t, i18n } = useTranslation(); @@ -43,13 +44,12 @@ export const Appearance = () => { const { mode, setMode } = useColorScheme(); const actualThemeMode = (mode ?? themeMode) as ThemeMode; - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.appearance.title')); useLayoutEffect(() => { - setTitle(t('settings.appearance.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/settings/screens/More.tsx b/src/modules/settings/screens/More.tsx index 432a0906..bb594d77 100644 --- a/src/modules/settings/screens/More.tsx +++ b/src/modules/settings/screens/More.tsx @@ -21,10 +21,11 @@ import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx'; import { NavigationBarUtil } from '@/modules/navigation-bar/NavigationBar.util.ts'; import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts'; import { NavbarItem, NavBarItemMoreGroup } from '@/modules/navigation-bar/NavigationBar.types.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const More = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const isMobileWidth = MediaQuery.useIsMobileWidth(); const { @@ -58,12 +59,11 @@ export const More = () => { [NavBarItemMoreGroup.HIDDEN_ITEM]: hiddenItemsMoreGroup, }; + useAppTitle(t('global.label.more')); useLayoutEffect(() => { - setTitle(t('global.label.more')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/settings/screens/ServerSettings.tsx b/src/modules/settings/screens/ServerSettings.tsx index fbcee6f2..cc597ec5 100644 --- a/src/modules/settings/screens/ServerSettings.tsx +++ b/src/modules/settings/screens/ServerSettings.tsx @@ -32,6 +32,7 @@ import { MetadataUpdateSettings } from '@/modules/app-updates/AppUpdateChecker.t import { ServerSettings as GqlServerSettings } from '@/modules/settings/Settings.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type ServerSettingsType = Pick< GqlServerSettings, @@ -94,14 +95,13 @@ const getLogFilesCleanupDisplayValue = (ttl: number): string => { export const ServerSettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.server.title.server')); useLayoutEffect(() => { - setTitle(t('settings.server.title.server')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/settings/screens/Settings.tsx b/src/modules/settings/screens/Settings.tsx index 374ab8bd..148d2c8f 100644 --- a/src/modules/settings/screens/Settings.tsx +++ b/src/modules/settings/screens/Settings.tsx @@ -30,17 +30,17 @@ import { makeToast } from '@/modules/core/utils/Toast.ts'; import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export function Settings() { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.title')); useLayoutEffect(() => { - setTitle(t('settings.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/settings/screens/WebUISettings.tsx b/src/modules/settings/screens/WebUISettings.tsx index 363bdf17..2cc95237 100644 --- a/src/modules/settings/screens/WebUISettings.tsx +++ b/src/modules/settings/screens/WebUISettings.tsx @@ -33,6 +33,7 @@ import { makeToast } from '@/modules/core/utils/Toast.ts'; import { MetadataUpdateSettings } from '@/modules/app-updates/AppUpdateChecker.types.ts'; import { ServerSettings } from '@/modules/settings/Settings.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; type WebUISettingsType = Pick< ServerSettings, @@ -120,14 +121,13 @@ const extractWebUISettings = (settings: ServerSettings): WebUISettingsType => ({ export const WebUISettings = () => { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('settings.webui.title.webui')); useLayoutEffect(() => { - setTitle(t('settings.webui.title.webui')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/source/screens/SourceConfigure.tsx b/src/modules/source/screens/SourceConfigure.tsx index 246b8e37..60a225bb 100644 --- a/src/modules/source/screens/SourceConfigure.tsx +++ b/src/modules/source/screens/SourceConfigure.tsx @@ -28,6 +28,7 @@ import { makeToast } from '@/modules/core/utils/Toast.ts'; import { PreferenceProps } from '@/modules/source/Source.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; function getPrefComponent(type: string) { switch (type) { @@ -48,14 +49,13 @@ function getPrefComponent(type: string) { export function SourceConfigure() { const { t } = useTranslation(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); + useAppTitle(t('source.configuration.title')); useLayoutEffect(() => { - setTitle(t('source.configuration.title')); setAction(null); return () => { - setTitle(''); setAction(null); }; }, [t]); diff --git a/src/modules/source/screens/SourceMangas.tsx b/src/modules/source/screens/SourceMangas.tsx index 64d2830d..ce802ce6 100644 --- a/src/modules/source/screens/SourceMangas.tsx +++ b/src/modules/source/screens/SourceMangas.tsx @@ -53,6 +53,7 @@ import { AppRoutes } from '@/modules/core/AppRoute.constants.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { Sources } from '@/modules/source/services/Sources.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; const DEFAULT_SOURCE: SourceIdInfo = { id: '-1' }; @@ -204,7 +205,7 @@ const useSourceManga = ( export function SourceMangas() { const { t } = useTranslation(); - const { setTitle, setAction, appBarHeight } = useNavBarContext(); + const { setAction, appBarHeight } = useNavBarContext(); const { sourceId } = useParams<{ sourceId: string }>(); @@ -398,8 +399,8 @@ export function SourceMangas() { requestManager.clearBrowseCacheFor(sourceId); }, [clearCache]); + useAppTitle(source?.displayName ?? t('source.title_one')); useLayoutEffect(() => { - setTitle(source?.displayName ?? t('source.title_one')); setAction( <> @@ -420,7 +421,6 @@ export function SourceMangas() { ); return () => { - setTitle(''); setAction(null); }; }, [t, source]); diff --git a/src/modules/tracker/screens/TrackingSettings.tsx b/src/modules/tracker/screens/TrackingSettings.tsx index ceef98de..c02c9ca3 100644 --- a/src/modules/tracker/screens/TrackingSettings.tsx +++ b/src/modules/tracker/screens/TrackingSettings.tsx @@ -7,13 +7,11 @@ */ import { useTranslation } from 'react-i18next'; -import { useLayoutEffect } from 'react'; import List from '@mui/material/List'; import ListSubheader from '@mui/material/ListSubheader'; import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import Switch from '@mui/material/Switch'; -import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx'; import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx'; @@ -28,14 +26,12 @@ import { GET_TRACKERS_SETTINGS } from '@/lib/graphql/queries/TrackerQuery.ts'; import { GetTrackersSettingsQuery } from '@/lib/graphql/generated/graphql.ts'; import { MetadataTrackingSettings } from '@/modules/tracker/Tracker.types.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const TrackingSettings = () => { const { t } = useTranslation(); - const { setTitle } = useNavBarContext(); - useLayoutEffect(() => { - setTitle(t('tracking.title')); - }, [t]); + useAppTitle(t('tracking.title')); const { settings: { updateProgressAfterReading, updateProgressManualMarkRead }, diff --git a/src/modules/updates/screens/Updates.tsx b/src/modules/updates/screens/Updates.tsx index ba4e28a0..fe188ec5 100644 --- a/src/modules/updates/screens/Updates.tsx +++ b/src/modules/updates/screens/Updates.tsx @@ -24,12 +24,13 @@ import { ChapterUpdateCard } from '@/modules/updates/components/ChapterUpdateCar import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx'; import { Chapters } from '@/modules/chapter/services/Chapters.ts'; import { GROUPED_VIRTUOSO_Z_INDEX } from '@/modules/core/AppRoute.constants.ts'; +import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts'; export const Updates: React.FC = () => { const { t } = useTranslation(); const { appBarHeight } = useNavBarContext(); - const { setTitle, setAction } = useNavBarContext(); + const { setAction } = useNavBarContext(); const { data: chapterUpdateData, loading: isLoading, @@ -72,12 +73,11 @@ export const Updates: React.FC = () => { }); const lastUpdateTimestamp = lastUpdateTimestampData?.lastUpdateTimestamp.timestamp; + useAppTitle(t('updates.title')); useLayoutEffect(() => { - setTitle(t('updates.title')); setAction(); return () => { - setTitle(''); setAction(null); }; }, [t, lastUpdateTimestamp]);