/* * 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 BookmarkIcon from '@mui/icons-material/Bookmark'; import BookmarkAdd from '@mui/icons-material/BookmarkAdd'; import BookmarkRemove from '@mui/icons-material/BookmarkRemove'; import CheckBoxOutlineBlank from '@mui/icons-material/CheckBoxOutlineBlank'; import Delete from '@mui/icons-material/Delete'; import Done from '@mui/icons-material/Done'; import DoneAll from '@mui/icons-material/DoneAll'; import Download from '@mui/icons-material/Download'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import RemoveDone from '@mui/icons-material/RemoveDone'; import { CardActionArea, Checkbox, ListItemIcon, ListItemText, Stack, Tooltip } from '@mui/material'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import IconButton from '@mui/material/IconButton'; import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import { useTheme } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; import React from 'react'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { getUploadDateString } from '@/util/date'; import { DownloadStateIndicator } from '@/components/molecules/DownloadStateIndicator'; import { DownloadType, UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts'; import { TChapter } from '@/typings.ts'; import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts'; interface IProps { chapter: TChapter; allChapters: TChapter[]; downloadChapter: DownloadType | undefined; showChapterNumber: boolean; onSelect: (selected: boolean) => void; selected: boolean | null; } export const ChapterCard: React.FC = (props: IProps) => { const { t } = useTranslation(); const theme = useTheme(); const { chapter, allChapters, downloadChapter: dc, showChapterNumber, onSelect, selected } = props; const isSelecting = selected !== null; const { settings: metadataServerSettings } = useMetadataServerSettings(); const [anchorEl, setAnchorEl] = React.useState(null); const handleMenuClick = (event: React.MouseEvent) => { // prevent parent tags from getting the event event.stopPropagation(); event.preventDefault(); setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; type UpdatePatchInput = UpdateChapterPatchInput & { markPrevRead?: boolean }; const sendChange = (key: Key, value: UpdatePatchInput[Key]) => { handleClose(); const shouldDeleteChapter = ({ isBookmarked, isDownloaded }: TChapter) => isDownloaded && (!isBookmarked || metadataServerSettings.deleteChaptersWithBookmark); const isMarkAsRead = (key === 'isRead' && value) || key === 'markPrevRead'; const shouldAutoDeleteChapters = isMarkAsRead && metadataServerSettings.deleteChaptersManuallyMarkedRead; const chaptersToDelete = key === 'isRead' ? [chapter] : allChapters; const chapterIdsToDelete = shouldAutoDeleteChapters ? chaptersToDelete.filter(shouldDeleteChapter).map(({ id: chapterId }) => chapterId) : []; if (key === 'markPrevRead') { const index = allChapters.findIndex(({ id: chapterId }) => chapterId === chapter.id); const isFirstChapter = index + 1 > allChapters.length - 1; if (isFirstChapter) { return; } requestManager.updateChapters( allChapters .slice(index + 1) .filter(({ isRead }) => !isRead) .map(({ id: chapterId }) => chapterId), { isRead: true, chapterIdsToDelete }, ); return; } requestManager.updateChapter(chapter.id, { [key]: value, lastPageRead: key === 'isRead' ? 0 : undefined, chapterIdToDelete: chapterIdsToDelete[0], }); }; const downloadChapter = () => { requestManager.addChapterToDownloadQueue(chapter.id); handleClose(); }; const deleteChapter = () => { requestManager.deleteDownloadedChapter(chapter.id); handleClose(); }; const handleSelect = () => { onSelect(true); handleClose(); }; const handleClick = (event: React.MouseEvent) => { if (isSelecting) { event.preventDefault(); event.stopPropagation(); onSelect(!selected); } }; const { isDownloaded } = chapter; const canBeDownloaded = !chapter.isDownloaded && dc === undefined; return (
  • {chapter.isBookmarked && ( )} {showChapterNumber ? `${t('chapter.title')} ${chapter.chapterNumber}` : chapter.name} {chapter.scanlator} {getUploadDateString(Number(chapter.uploadDate ?? 0))} {isDownloaded && ` • ${t('chapter.status.label.downloaded')}`} {dc && } {selected === null ? ( ) : ( )} {t('chapter.action.label.select')} {isDownloaded && ( {t('chapter.action.download.delete.label.action')} )} {canBeDownloaded && ( {t('chapter.action.download.add.label.action')} )} sendChange('isBookmarked', !chapter.isBookmarked)}> {chapter.isBookmarked && } {!chapter.isBookmarked && } {chapter.isBookmarked && t('chapter.action.bookmark.remove.label.action')} {!chapter.isBookmarked && t('chapter.action.bookmark.add.label.action')} sendChange('isRead', !chapter.isRead)}> {chapter.isRead && } {!chapter.isRead && } {chapter.isRead && t('chapter.action.mark_as_read.remove.label.action')} {!chapter.isRead && t('chapter.action.mark_as_read.add.label.action.current')} sendChange('markPrevRead', true)}> {t('chapter.action.mark_as_read.add.label.action.previous')}
  • ); };