Introduce "useAppAction" hook

This commit is contained in:
schroda
2025-05-03 13:24:55 +02:00
parent 3ab70c4802
commit aacdbaaeef
26 changed files with 230 additions and 430 deletions

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useEffect, useRef, useState } from 'react';
import List from '@mui/material/List';
import ListItemText from '@mui/material/ListItemText';
import { fromEvent } from 'file-selector';
@@ -37,7 +37,6 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
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<ServerSettings, 'backupPath' | 'backupTime' | 'backupInterval' | 'backupTTL'>;
@@ -61,15 +60,8 @@ let backupRestoreId: string | undefined;
export function Backup() {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('settings.backup.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
useAppTitle(t('settings.backup.title'));
const {
data: settingsData,

View File

@@ -7,7 +7,6 @@
*/
import { Trans, useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
@@ -27,7 +26,6 @@ import { makeToast } from '@/modules/core/utils/Toast.ts';
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<GqlServerSettings, 'maxSourcesInParallel' | 'localSourcePath' | 'extensionRepos'>;
@@ -40,12 +38,8 @@ const extractBrowseSettings = (settings: GqlServerSettings): ExtensionsSettings
export const BrowseSettings = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('global.label.browse'));
useLayoutEffect(() => {
setAction(null);
}, [t]);
useAppTitle(t('global.label.browse'));
const { data, loading, error, refetch } = requestManager.useGetServerSettings({
notifyOnNetworkStatusChange: true,

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { ComponentProps, useLayoutEffect, useMemo, useState } from 'react';
import { ComponentProps, useMemo, useState } from 'react';
import { useTheme } from '@mui/material/styles';
import Fab from '@mui/material/Fab';
import AddIcon from '@mui/icons-material/Add';
@@ -32,7 +32,6 @@ import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts'
import { CategorySettingsCard } from '@/modules/category/components/CategorySettingsCard.tsx';
import { CategoryIdInfo } from '@/modules/category/Category.types.ts';
import { getErrorMessage, noOp } from '@/lib/HelperFunctions.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { makeToast } from '@/modules/core/utils/Toast.ts';
import { DndSortableItem } from '@/lib/dnd-kit/DndSortableItem.tsx';
import { DndKitUtil } from '@/lib/dnd-kit/DndKitUtil.ts';
@@ -41,17 +40,9 @@ import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
export function CategorySettings() {
const { t } = useTranslation();
useAppTitle(t('category.dialog.title.edit_category_other'));
const { setAction } = useNavBarContext();
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const { data, loading, error, refetch } = requestManager.useGetCategories<
GetCategoriesSettingsQuery,
GetCategoriesSettingsQueryVariables

View File

@@ -11,7 +11,6 @@ import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import MenuItem from '@mui/material/MenuItem';
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import {
updateMetadataServerSettings,
useMetadataServerSettings,
@@ -26,23 +25,13 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
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 { setAction } = useNavBarContext();
useAppTitle(t('settings.device.title.device'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const {
metadata,
settings: { devices },

View File

@@ -10,7 +10,7 @@ import PauseIcon from '@mui/icons-material/Pause';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import Box from '@mui/material/Box';
import IconButton from '@mui/material/IconButton';
import React, { useLayoutEffect, useMemo, useState } from 'react';
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import DeleteSweepIcon from '@mui/icons-material/DeleteSweep';
import { Virtuoso } from 'react-virtuoso';
@@ -26,12 +26,12 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
import { ChapterDownloadStatus } from '@/modules/chapter/services/Chapters.ts';
import { DownloaderState } from '@/lib/graphql/generated/graphql.ts';
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export const DownloadQueue: React.FC = () => {
const { t } = useTranslation();
@@ -52,8 +52,6 @@ export const DownloadQueue: React.FC = () => {
const status = downloaderData?.state ?? DownloaderState.Started;
const isQueueEmpty = !queue.length;
const { setAction } = useNavBarContext();
const dndItems = useMemo(() => queue.map((download) => download.chapter), [queue]);
const dndSensors = DndKitUtil.useSensorsForDevice();
const [dndActiveDownload, setDndActiveDownload] = useState<ChapterDownloadStatus | null>(null);
@@ -99,8 +97,7 @@ export const DownloadQueue: React.FC = () => {
categoryReorder(queue, oldIndex, newIndex);
};
useLayoutEffect(() => {
setAction(
useAppAction(
<>
<CustomTooltip title={t('download.queue.label.delete_all')}>
<IconButton onClick={clearQueue} color="inherit">
@@ -119,11 +116,6 @@ export const DownloadQueue: React.FC = () => {
</>,
);
return () => {
setAction(null);
};
}, [t, status, isQueueEmpty]);
// Virtuoso's resize observer can throw this error,
// which is caught by DnD and aborts dragging.
useWindowEvent('error', (e) => {

View File

@@ -7,7 +7,6 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
@@ -32,7 +31,6 @@ import { GET_CATEGORIES_SETTINGS } from '@/lib/graphql/queries/CategoryQuery.ts'
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<
@@ -56,18 +54,9 @@ const extractDownloadSettings = (settings: ServerSettings): DownloadSettingsType
export const DownloadSettings = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('download.title.download'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const categories = requestManager.useGetCategories<GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables>(
GET_CATEGORIES_SETTINGS,
);

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { fromEvent } from 'file-selector';
import IconButton from '@mui/material/IconButton';
import AddIcon from '@mui/icons-material/Add';
@@ -45,13 +45,13 @@ import {
import { EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP } from '@/modules/extension/Extensions.constants.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 { ExtensionOptions } from '@/modules/extension/components/ExtensionOptions';
import {
createUpdateMetadataServerSettings,
useMetadataServerSettings,
} from '@/modules/settings/services/ServerSettingsMetadata.ts';
import { MetadataBrowseSettings } from '@/modules/browse/Browse.types.ts';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
const LANGUAGE = 0;
const EXTENSIONS = 1;
@@ -115,7 +115,6 @@ const GroupHeader = ({
export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const navigate = useNavigate();
const { pathname, search, state } = useLocation<{ selectedExtensionPkg?: TExtension['pkgName'] }>();
const selectedExtensionPkg = state?.selectedExtensionPkg;
@@ -201,8 +200,7 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
fetchExtensions();
}, [refetchExtensions]);
useLayoutEffect(() => {
setAction(
useAppAction(
<>
<AppbarSearch />
<CustomTooltip title={t('extension.action.label.install_external')}>
@@ -236,13 +234,9 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
languages={allLangs}
/>
</>,
[t, shownLangs, allLangs],
);
return () => {
setAction(null);
};
}, [t, shownLangs, allLangs]);
useWindowEvent('drop', async (e) => {
e.preventDefault();
const files = await fromEvent(e);

View File

@@ -9,7 +9,7 @@
import Card from '@mui/material/Card';
import CardActionArea from '@mui/material/CardActionArea';
import Typography from '@mui/material/Typography';
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { StringParam, useQueryParam } from 'use-query-params';
import { useTranslation } from 'react-i18next';
@@ -30,11 +30,11 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/Em
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.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 { 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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean; error: any };
type SourceToLoadingStateMap = Map<string, SourceLoadingState>;
@@ -189,8 +189,6 @@ const SourceSearchPreview = React.memo(
export const SearchAll: React.FC = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const { pathname, state } = useLocation<{ mangaTitle?: string }>();
const isMigrateMode = pathname.startsWith('/migrate/source');
@@ -236,8 +234,9 @@ export const SearchAll: React.FC = () => {
[setSourceToLoadingStateMap],
);
useLayoutEffect(() => {
setAction(
useAppAction(
useMemo(
() => (
<>
<AppbarSearch isClosable={false} />
<LanguageSelect
@@ -245,14 +244,12 @@ export const SearchAll: React.FC = () => {
setSelectedLanguages={setShownLangs}
languages={sourceLanguages}
/>
</>,
</>
),
[shownLangs, setShownLangs, sourceLanguages],
),
);
return () => {
setAction(null);
};
}, [t, shownLangs, setShownLangs, sources]);
if (loading) {
return <LoadingPlaceholder />;
}

View File

@@ -7,7 +7,6 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
@@ -21,20 +20,14 @@ import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/Em
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
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 { setAction } = useNavBarContext();
useAppTitle(t('history.title'));
useLayoutEffect(() => {
setAction(null);
}, [t]);
const {
settings: { hideHistory },
request: { loading, error, refetch },

View File

@@ -43,8 +43,8 @@ import { useLibraryOptionsContext } from '@/modules/library/contexts/LibraryOpti
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
const TitleWithSizeTag = styled('span')({
display: 'flex',
@@ -167,7 +167,6 @@ export function Library() {
);
}, [isSelectModeActive, selectedMangas]);
const { setAction } = useNavBarContext();
useAppTitle(
<TitleWithSizeTag>
{t('library.title')}
@@ -176,8 +175,7 @@ export function Library() {
t('library.title'),
[t, showTabSize, librarySize],
);
useLayoutEffect(() => {
setAction(
useAppAction(
<>
{!isSelectModeActive && activeTab && (
<>
@@ -190,9 +188,7 @@ export function Library() {
isActive={isSelectModeActive}
areAllItemsSelected={areAllItemsSelected}
areNoItemsSelected={areNoItemsSelected}
onSelectAll={(selectAll) =>
handleSelectAll(selectAll, [...new Set(mangas.map((manga) => manga.id))])
}
onSelectAll={(selectAll) => handleSelectAll(selectAll, [...new Set(mangas.map((manga) => manga.id))])}
onModeChange={(checked) => {
setIsSelectModeActive(checked);
@@ -204,21 +200,8 @@ export function Library() {
}}
/>
</>,
[isSelectModeActive, areNoItemsSelected, areAllItemsSelected, activeTab],
);
return () => {
setAction(null);
};
}, [
t,
librarySize,
areCategoriesLoading,
isSelectModeActive,
areNoItemsSelected,
areAllItemsSelected,
mangas.length,
activeTab,
showTabSize,
]);
const handleTabChange = (newTab: number) => {
setTabSearchParam(newTab);

View File

@@ -7,7 +7,7 @@
*/
import { useTranslation } from 'react-i18next';
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import IconButton from '@mui/material/IconButton';
import SettingsIcon from '@mui/icons-material/Settings';
import PopupState, { bindMenu, bindTrigger } from 'material-ui-popup-state';
@@ -34,8 +34,8 @@ import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
import { LibraryDuplicatesWorkerInput, TMangaDuplicate, TMangaDuplicates } from '@/modules/library/Library.types.ts';
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export const LibraryDuplicates = () => {
const { t } = useTranslation();
@@ -46,10 +46,8 @@ export const LibraryDuplicates = () => {
false,
);
const { setAction } = useNavBarContext();
useAppTitle(t('library.settings.advanced.duplicates.label.title'));
useLayoutEffect(() => {
setAction(
useAppAction(
<>
<GridLayouts gridLayout={gridLayout} onChange={setGridLayout} />
<PopupState variant="popover" popupId="library-dupliactes-settings">
@@ -61,9 +59,7 @@ export const LibraryDuplicates = () => {
<Menu {...bindMenu(popupState)}>
<MenuItem>
<CheckboxInput
label={t(
'library.settings.advanced.duplicates.settings.label.check_description',
)}
label={t('library.settings.advanced.duplicates.settings.label.check_description')}
checked={checkAlternativeTitles}
onChange={(_, checked) => setCheckAlternativeTitles(checked)}
/>
@@ -75,11 +71,6 @@ export const LibraryDuplicates = () => {
</>,
);
return () => {
setAction(null);
};
}, [t, gridLayout, checkAlternativeTitles]);
const { data, loading, error, refetch } = requestManager.useGetMangas<
GetMangasDuplicatesQuery,
GetMangasDuplicatesQueryVariables

View File

@@ -7,7 +7,6 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
@@ -38,7 +37,6 @@ import { GET_MANGAS_BASE } from '@/lib/graphql/queries/MangaQuery.ts';
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<void> => {
@@ -65,16 +63,8 @@ const removeNonLibraryMangasFromCategories = async (): Promise<void> => {
export function LibrarySettings() {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('library.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const categories = requestManager.useGetCategories<GetCategoriesSettingsQuery, GetCategoriesSettingsQueryVariables>(
GET_CATEGORIES_SETTINGS,

View File

@@ -11,7 +11,7 @@ import CircularProgress from '@mui/material/CircularProgress';
import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
import React, { useEffect, useLayoutEffect, useRef } from 'react';
import React, { useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { isNetworkRequestInFlight } from '@apollo/client/core/networkStatus';
@@ -26,13 +26,12 @@ import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPl
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export const Manga: React.FC = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const { id } = useParams<{ id: string }>();
const autofetchedRef = useRef(false);
@@ -61,16 +60,7 @@ export const Manga: React.FC = () => {
}, [manga]);
useAppTitle(manga?.title ?? t('manga.title_one'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t, manga?.title]);
useLayoutEffect(() => {
setAction(
useAppAction(
<Stack
direction="row"
sx={{
@@ -101,11 +91,6 @@ export const Manga: React.FC = () => {
</Stack>,
);
return () => {
setAction(null);
};
}, [t, error, isValidating, refreshing, manga, refresh]);
if (error && !manga) {
return (
<EmptyViewAbsoluteCentered

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useEffect, useLayoutEffect, useState } from 'react';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { requestManager } from '@/lib/requests/RequestManager.ts';
@@ -22,12 +22,11 @@ import { SOURCE_BASE_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts';
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export const Migrate = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const { sourceId: paramSourceId } = useParams<{ sourceId: string }>();
@@ -70,13 +69,7 @@ export const Migrate = () => {
});
useAppTitle(name ?? sourceId ?? t('migrate.title'));
useLayoutEffect(() => {
setAction(<GridLayouts gridLayout={gridLayout} onChange={setGridLayout} />);
return () => {
setAction(null);
};
}, [t, name, sourceId, gridLayout]);
useAppAction(<GridLayouts gridLayout={gridLayout} onChange={setGridLayout} />);
useEffect(() => {
if (isSourceLoading || isKnownSource) {

View File

@@ -0,0 +1,20 @@
/*
* 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 { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { NavbarContextType } from '@/modules/navigation-bar/NavigationBar.types.ts';
export const useAppAction = (action: NavbarContextType['action'], dependencies: any[] = []) => {
const { setAction } = useNavBarContext();
useEffect(() => {
setAction(action);
return () => setAction(null);
}, dependencies);
};

View File

@@ -7,12 +7,11 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect, useState } from 'react';
import { useState } from 'react';
import { useDefaultReaderSettingsWithDefaultFlag } from '@/modules/reader/services/ReaderSettingsMetadata.ts';
import { LoadingPlaceholder } from '@/modules/core/components/feedback/LoadingPlaceholder.tsx';
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { IReaderSettings, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
import { ReaderService } from '@/modules/reader/services/ReaderService.ts';
import { ReaderSettingsTabs } from '@/modules/reader/components/settings/ReaderSettingsTabs.tsx';
@@ -22,16 +21,8 @@ import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
export const GlobalReaderSettings = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('reader.settings.title.reader'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const [activeTab, setActiveTab] = useState(0);

View File

@@ -6,7 +6,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
@@ -21,22 +20,13 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/feedback/EmptyViewAbsoluteCentered.tsx';
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 { setAction } = useNavBarContext();
useAppTitle(t('settings.about.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const { data, loading, error, refetch } = requestManager.useGetAbout({ notifyOnNetworkStatusChange: true });

View File

@@ -7,7 +7,6 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
@@ -35,7 +34,6 @@ import { makeToast } from '@/modules/core/utils/Toast.ts';
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 = () => {
@@ -44,15 +42,7 @@ export const Appearance = () => {
const { mode, setMode } = useColorScheme();
const actualThemeMode = (mode ?? themeMode) as ThemeMode;
const { setAction } = useNavBarContext();
useAppTitle(t('settings.appearance.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const {
settings,

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { Fragment, useLayoutEffect } from 'react';
import { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import List from '@mui/material/List';
import ListItemIcon from '@mui/material/ListItemIcon';
@@ -15,7 +15,6 @@ import ListAltIcon from '@mui/icons-material/ListAlt';
import Divider from '@mui/material/Divider';
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
import { ListItemLink } from '@/modules/core/components/lists/ListItemLink.tsx';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
import { NAVIGATION_BAR_ITEMS } from '@/modules/navigation-bar/NavigationBar.constants.ts';
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
import { NavigationBarUtil } from '@/modules/navigation-bar/NavigationBar.util.ts';
@@ -25,9 +24,10 @@ import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
export const More = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const isMobileWidth = MediaQuery.useIsMobileWidth();
useAppTitle(t('global.label.more'));
const {
settings: { hideHistory },
} = useMetadataServerSettings();
@@ -59,15 +59,6 @@ export const More = () => {
[NavBarItemMoreGroup.HIDDEN_ITEM]: hiddenItemsMoreGroup,
};
useAppTitle(t('global.label.more'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
return (
<List sx={{ p: 0 }}>
{Object.entries(finalHiddenNavBarItemsByGroup).map(([group, items], index, list) => (

View File

@@ -7,7 +7,7 @@
*/
import { useTranslation, Trans } from 'react-i18next';
import { useLayoutEffect, useMemo } from 'react';
import { useMemo } from 'react';
import Link from '@mui/material/Link';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
@@ -31,7 +31,6 @@ import { makeToast } from '@/modules/core/utils/Toast.ts';
import { MetadataUpdateSettings } from '@/modules/app-updates/AppUpdateChecker.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 ServerSettingsType = Pick<
@@ -95,16 +94,8 @@ const getLogFilesCleanupDisplayValue = (ttl: number): string => {
export const ServerSettings = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('settings.server.title.server'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const {
settings: { serverInformAvailableUpdate },

View File

@@ -6,7 +6,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useLayoutEffect } from 'react';
import AutoStoriesIcon from '@mui/icons-material/AutoStories';
import List from '@mui/material/List';
import BackupIcon from '@mui/icons-material/Backup';
@@ -29,21 +28,12 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
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 { setAction } = useNavBarContext();
useAppTitle(t('settings.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const [triggerClearServerCache, { loading: isClearingServerCache }] = requestManager.useClearServerCache();

View File

@@ -7,12 +7,10 @@
*/
import { useTranslation } from 'react-i18next';
import { useLayoutEffect } from 'react';
import List from '@mui/material/List';
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 { WebUIUpdateIntervalSetting } from '@/modules/settings/components/webUI/WebUIUpdateIntervalSetting.tsx';
import { TextSetting } from '@/modules/core/components/settings/text/TextSetting.tsx';
@@ -121,16 +119,8 @@ const extractWebUISettings = (settings: ServerSettings): WebUISettingsType => ({
export const WebUISettings = () => {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('settings.webui.title.webui'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const {
settings: { webUIInformAvailableUpdate },

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { createElement, useLayoutEffect } from 'react';
import { createElement } from 'react';
import { useParams } from 'react-router-dom';
import List from '@mui/material/List';
import { useTranslation } from 'react-i18next';
@@ -27,7 +27,6 @@ import { GET_SOURCE_SETTINGS } from '@/lib/graphql/queries/SourceQuery.ts';
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) {
@@ -49,16 +48,8 @@ function getPrefComponent(type: string) {
export function SourceConfigure() {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
useAppTitle(t('source.configuration.title'));
useLayoutEffect(() => {
setAction(null);
return () => {
setAction(null);
};
}, [t]);
const { sourceId } = useParams<{ sourceId: string }>();
const { data, loading, error, refetch } = requestManager.useGetSource<

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useParams, useNavigate, useLocation, useSearchParams } from 'react-router-dom';
import IconButton from '@mui/material/IconButton';
import SettingsIcon from '@mui/icons-material/Settings';
@@ -51,9 +51,10 @@ import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
import { GridLayout } from '@/modules/core/Core.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 { Sources } from '@/modules/source/services/Sources.ts';
import { useAppTitle } from '@/modules/navigation-bar/hooks/useAppTitle.ts';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.tsx';
const DEFAULT_SOURCE: SourceIdInfo = { id: '-1' };
@@ -205,7 +206,7 @@ const useSourceManga = (
export function SourceMangas() {
const { t } = useTranslation();
const { setAction, appBarHeight } = useNavBarContext();
const { appBarHeight } = useNavBarContext();
const { sourceId } = useParams<{ sourceId: string }>();
@@ -400,8 +401,7 @@ export function SourceMangas() {
}, [clearCache]);
useAppTitle(source?.displayName ?? t('source.title_one'));
useLayoutEffect(() => {
setAction(
useAppAction(
<>
<AppbarSearch />
<SourceGridLayout />
@@ -420,11 +420,6 @@ export function SourceMangas() {
</>,
);
return () => {
setAction(null);
};
}, [t, source]);
const EmptyViewComponent = mangas.length ? EmptyView : EmptyViewAbsoluteCentered;
return (

View File

@@ -6,7 +6,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { Fragment, useLayoutEffect, useMemo } from 'react';
import { Fragment, useMemo } from 'react';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import TravelExploreIcon from '@mui/icons-material/TravelExplore';
@@ -24,13 +24,12 @@ import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts'
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.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 { Sources as SourceService } from '@/modules/source/services/Sources.ts';
import { useMetadataServerSettings } from '@/modules/settings/services/ServerSettingsMetadata.ts';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export function Sources() {
const { t } = useTranslation();
const { setAction } = useNavBarContext();
const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownSourceLangs', sourceDefualtLangs());
const {
@@ -61,8 +60,7 @@ export function Sources() {
const navigate = useNavigate();
useLayoutEffect(() => {
setAction(
useAppAction(
<>
<CustomTooltip title={t('search.title.global_search')}>
<IconButton onClick={() => navigate(AppRoutes.sources.childRoutes.searchAll.path)} color="inherit">
@@ -75,13 +73,9 @@ export function Sources() {
languages={sourceLanguages}
/>
</>,
[t, shownLangs, sourceLanguages],
);
return () => {
setAction(null);
};
}, [t, shownLangs, sourceLanguages]);
if (isLoading) return <LoadingPlaceholder />;
if (error) {

View File

@@ -25,12 +25,12 @@ import { useNavBarContext } from '@/modules/navigation-bar/contexts/NavbarContex
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';
import { useAppAction } from '@/modules/navigation-bar/hooks/useAppAction.ts';
export const Updates: React.FC = () => {
const { t } = useTranslation();
const { appBarHeight } = useNavBarContext();
const { setAction } = useNavBarContext();
const {
data: chapterUpdateData,
loading: isLoading,
@@ -74,13 +74,7 @@ export const Updates: React.FC = () => {
const lastUpdateTimestamp = lastUpdateTimestampData?.lastUpdateTimestamp.timestamp;
useAppTitle(t('updates.title'));
useLayoutEffect(() => {
setAction(<UpdateChecker />);
return () => {
setAction(null);
};
}, [t, lastUpdateTimestamp]);
useAppAction(<UpdateChecker />);
const loadMore = useCallback(() => {
if (!hasNextPage) {