Files
suwayomi-material-you-webui/src/modules/manga/components/cards/MangaCard.tsx
T

170 lines
6.3 KiB
TypeScript
Raw Normal View History

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
2021-01-26 23:32:12 +03:30
* 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/.
*/
2021-01-26 23:32:12 +03:30
2023-12-25 21:37:45 +01:00
import PopupState, { bindMenu } from 'material-ui-popup-state';
2024-04-07 21:30:47 +02:00
import { useMemo, useState } from 'react';
2024-04-05 02:03:00 +02:00
import { useLongPress } from 'use-long-press';
2024-10-26 17:25:04 +02:00
import { useLibraryOptionsContext } from '@/modules/library/contexts/LibraryOptionsContext.tsx';
2024-10-05 19:21:26 +02:00
import { MangaActionMenuItems, SingleModeProps } from '@/modules/manga/components/MangaActionMenuItems.tsx';
2024-10-05 16:09:34 +02:00
import { Menu } from '@/modules/core/components/menu/Menu.tsx';
2024-10-05 21:35:25 +02:00
import { MigrateDialog } from '@/modules/migration/components/MigrateDialog.tsx';
2024-10-05 19:21:26 +02:00
import { useManageMangaLibraryState } from '@/modules/manga/hooks/useManageMangaLibraryState.tsx';
import { MangaGridCard } from '@/modules/manga/components/cards/MangaGridCard.tsx';
import { MangaListCard } from '@/modules/manga/components/cards/MangaListCard.tsx';
2024-10-07 13:31:23 +02:00
import { MangaCardMode, MangaCardProps } from '@/modules/manga/Manga.types.ts';
2024-10-05 19:21:26 +02:00
import { ContinueReadingButton } from '@/modules/manga/components/ContinueReadingButton.tsx';
import { MangaBadges } from '@/modules/manga/components/MangaBadges.tsx';
2024-10-26 17:25:04 +02:00
import { GridLayout } from '@/modules/core/Core.types.ts';
2023-02-06 10:06:33 +01:00
2024-03-28 17:30:34 +01:00
const getMangaLinkTo = (
mode: MangaCardMode,
mangaId: number,
sourceId: string | undefined,
mangaTitle: string,
): string => {
2024-01-26 20:50:51 +01:00
switch (mode) {
case 'default':
case 'source':
2024-05-08 18:59:01 +02:00
case 'duplicate':
2024-01-26 20:50:51 +01:00
return `/manga/${mangaId}/`;
case 'migrate.search':
return `/migrate/source/${sourceId}/manga/${mangaId}/search?query=${mangaTitle}`;
case 'migrate.select':
return '';
default:
throw new Error(`getMangaLinkTo: unexpected MangaCardMode "${mode}"`);
}
};
export const MangaCard = (props: MangaCardProps) => {
const { manga, gridLayout, inLibraryIndicator, selected, handleSelection, mode = 'default' } = props;
const { id, firstUnreadChapter, downloadCount, unreadCount } = manga;
2023-02-06 10:06:33 +01:00
const {
2024-04-07 21:30:47 +02:00
options: { showContinueReadingButton },
2023-02-06 10:06:33 +01:00
} = useLibraryOptionsContext();
2021-10-31 21:02:45 +03:30
const { CategorySelectComponent, updateLibraryState, isInLibrary } = useManageMangaLibraryState(
manga,
mode === 'source',
);
2024-07-08 18:02:50 +02:00
const mangaLinkTo = getMangaLinkTo(mode, manga.id, manga.sourceId, manga.title);
2022-11-21 01:33:45 +01:00
const nextChapterIndexToRead = firstUnreadChapter?.sourceOrder;
2023-12-19 15:17:00 +01:00
2024-01-26 20:50:51 +01:00
const [isMigrateDialogOpen, setIsMigrateDialogOpen] = useState(false);
2024-04-07 15:21:25 +02:00
const handleClick = (event: React.MouseEvent | React.TouchEvent, openMenu?: () => void) => {
const isDefaultMode = mode === 'default';
const isSourceMode = mode === 'source';
2024-04-07 15:21:25 +02:00
const isMigrateSelectMode = mode === 'migrate.select';
const isSelectionMode = selected !== null;
const isLongPress = !!openMenu;
2024-04-07 15:21:25 +02:00
const shouldHandleClick =
isMigrateSelectMode || isSelectionMode || ((isDefaultMode || isSourceMode) && isLongPress);
2024-04-07 15:21:25 +02:00
if (!shouldHandleClick) {
2024-04-05 02:03:00 +02:00
return;
}
2024-04-07 15:21:25 +02:00
event.preventDefault();
if (isSourceMode) {
updateLibraryState();
return;
}
2024-04-07 15:21:25 +02:00
if (isSelectionMode) {
handleSelection?.(id, !selected, { selectRange: event.shiftKey });
return;
}
if (isDefaultMode) {
openMenu?.();
return;
}
if (isMigrateSelectMode) {
setIsMigrateDialogOpen(true);
}
2024-04-05 02:03:00 +02:00
};
2024-04-07 15:21:25 +02:00
const longPressBind = useLongPress((e, { context }) => {
2024-04-05 02:03:00 +02:00
e.shiftKey = true;
2024-04-07 15:21:25 +02:00
handleClick(e, context as () => {});
2024-04-05 02:03:00 +02:00
});
2024-04-07 21:30:47 +02:00
const MangaCardComponent = useMemo(
() => (gridLayout === GridLayout.List ? MangaListCard : MangaGridCard),
[gridLayout],
);
const continueReadingButton = useMemo(
() => (
<ContinueReadingButton
showContinueReadingButton={showContinueReadingButton && mode === 'default'}
2024-04-07 21:30:47 +02:00
nextChapterIndexToRead={nextChapterIndexToRead}
mangaLinkTo={mangaLinkTo}
/>
),
[showContinueReadingButton, nextChapterIndexToRead, mangaLinkTo],
2024-04-07 21:30:47 +02:00
);
const mangaBadges = useMemo(
() => (
<MangaBadges
inLibraryIndicator={inLibraryIndicator}
isInLibrary={isInLibrary}
unread={unreadCount}
downloadCount={downloadCount}
updateLibraryState={updateLibraryState}
mode={mode}
2024-04-07 21:30:47 +02:00
/>
),
[inLibraryIndicator, isInLibrary, unreadCount, downloadCount, updateLibraryState],
);
2024-01-26 20:50:51 +01:00
return (
<>
{isMigrateDialogOpen && (
<MigrateDialog mangaIdToMigrateTo={manga.id} onClose={() => setIsMigrateDialogOpen(false)} />
)}
2023-12-25 21:37:45 +01:00
<PopupState variant="popover" popupId="manga-card-action-menu">
{(popupState) => (
<>
2024-04-07 21:30:47 +02:00
<MangaCardComponent
{...props}
longPressBind={longPressBind}
popupState={popupState}
handleClick={handleClick}
mangaLinkTo={mangaLinkTo}
isInLibrary={isInLibrary}
inLibraryIndicator={inLibraryIndicator}
continueReadingButton={continueReadingButton}
mangaBadges={mangaBadges}
/>
2023-12-25 21:37:45 +01:00
{!!handleSelection && popupState.isOpen && (
2023-12-30 14:26:50 +01:00
<Menu {...bindMenu(popupState)}>
{(onClose, setHideMenu) => (
<MangaActionMenuItems
manga={manga as SingleModeProps['manga']}
handleSelection={handleSelection}
onClose={onClose}
setHideMenu={setHideMenu}
/>
)}
</Menu>
2023-12-25 21:37:45 +01:00
)}
{CategorySelectComponent}
2023-12-25 21:37:45 +01:00
</>
)}
</PopupState>
2024-01-26 20:50:51 +01:00
</>
2020-12-25 17:42:22 +01:00
);
2023-06-17 16:50:17 +02:00
};