From 2f8c284c8b09298fb56182e8d7d7438a49180abf Mon Sep 17 00:00:00 2001
From: schroda <50052685+schroda@users.noreply.github.com>
Date: Tue, 19 Dec 2023 15:17:00 +0100
Subject: [PATCH] Add continue read button to library (#505)
---
src/components/MangaCard.tsx | 126 ++++++++++++------
.../context/LibraryOptionsContext.tsx | 1 +
.../library/LibraryOptionsPanel.tsx | 16 ++-
.../manga/ContinueReadingButton.tsx | 46 +++++++
src/i18n/locale/en.json | 10 +-
src/typings.ts | 1 +
6 files changed, 152 insertions(+), 48 deletions(-)
create mode 100644 src/components/manga/ContinueReadingButton.tsx
diff --git a/src/components/MangaCard.tsx b/src/components/MangaCard.tsx
index be6b7ad3..c0c15964 100644
--- a/src/components/MangaCard.tsx
+++ b/src/components/MangaCard.tsx
@@ -10,12 +10,13 @@ import Card from '@mui/material/Card';
import CardActionArea from '@mui/material/CardActionArea';
import Typography from '@mui/material/Typography';
import { Link } from 'react-router-dom';
-import { Avatar, Box, CardContent, styled, Tooltip } from '@mui/material';
+import { Avatar, Box, CardContent, Stack, styled, Tooltip } from '@mui/material';
import { useTranslation } from 'react-i18next';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { GridLayout, useLibraryOptionsContext } from '@/components/context/LibraryOptionsContext';
import { SpinnerImage } from '@/components/util/SpinnerImage';
import { TPartialManga } from '@/typings.ts';
+import { ContinueReadingButton } from '@/components/manga/ContinueReadingButton.tsx';
const BottomGradient = styled('div')({
position: 'absolute',
@@ -44,11 +45,6 @@ const MangaTitle = styled(Typography)({
});
const GridMangaTitle = styled(MangaTitle)({
- width: '100%',
- position: 'absolute',
- bottom: 0,
- margin: '0.5em 0',
- padding: '0 0.5em',
fontSize: '1.05rem',
});
@@ -75,17 +71,29 @@ export const MangaCard = (props: IProps) => {
const { t } = useTranslation();
const {
- manga: { id, title, thumbnailUrl: tmpThumbnailUrl, downloadCount, unreadCount: unread, inLibrary },
+ manga: {
+ id,
+ title,
+ thumbnailUrl: tmpThumbnailUrl,
+ downloadCount,
+ unreadCount: unread,
+ inLibrary,
+ lastReadChapter,
+ chapters,
+ },
gridLayout,
inLibraryIndicator,
} = props;
const thumbnailUrl = tmpThumbnailUrl ?? 'nonExistingMangaUrl';
const {
- options: { showUnreadBadge, showDownloadBadge },
+ options: { showContinueReadingButton, showUnreadBadge, showDownloadBadge },
} = useLibraryOptionsContext();
const mangaLinkTo = `/manga/${id}/`;
+ const nextChapterIndexToRead = (lastReadChapter?.sourceOrder ?? 0) + 1;
+ const isLatestChapterRead = chapters?.totalCount === lastReadChapter?.sourceOrder;
+
if (gridLayout !== GridLayout.List) {
return (
@@ -155,22 +163,42 @@ export const MangaCard = (props: IProps) => {
placeItems: 'center',
}}
/>
- {gridLayout !== GridLayout.Comfortable && (
- <>
-
-
-
-
- {title}
-
-
- >
- )}
+ <>
+
+
+
+ {gridLayout !== GridLayout.Comfortable && (
+
+
+ {title}
+
+
+ )}
+
+
+ >
{gridLayout === GridLayout.Comfortable && (
@@ -178,6 +206,10 @@ export const MangaCard = (props: IProps) => {
{
{title}
-
- {inLibraryIndicator && inLibrary && (
-
- {t('manga.button.in_library')}
-
- )}
- {showUnreadBadge && unread! > 0 && (
- {unread}
- )}
- {showDownloadBadge && downloadCount! > 0 && (
-
- {downloadCount}
-
- )}
-
+
+
+ {inLibraryIndicator && inLibrary && (
+
+ {t('manga.button.in_library')}
+
+ )}
+ {showUnreadBadge && unread! > 0 && (
+ {unread}
+ )}
+ {showDownloadBadge && downloadCount! > 0 && (
+
+ {downloadCount}
+
+ )}
+
+
+
diff --git a/src/components/context/LibraryOptionsContext.tsx b/src/components/context/LibraryOptionsContext.tsx
index 183853be..db2a2108 100644
--- a/src/components/context/LibraryOptionsContext.tsx
+++ b/src/components/context/LibraryOptionsContext.tsx
@@ -21,6 +21,7 @@ export enum GridLayout {
}
export const DefaultLibraryOptions: LibraryOptions = {
+ showContinueReadingButton: false,
showDownloadBadge: false,
showUnreadBadge: false,
gridLayout: GridLayout.Compact,
diff --git a/src/components/library/LibraryOptionsPanel.tsx b/src/components/library/LibraryOptionsPanel.tsx
index 9de1fd9d..d89f2145 100644
--- a/src/components/library/LibraryOptionsPanel.tsx
+++ b/src/components/library/LibraryOptionsPanel.tsx
@@ -82,7 +82,8 @@ export const LibraryOptionsPanel: React.FC = ({ open, onClose }) => {
));
}
if (key === 'display') {
- const { gridLayout, showDownloadBadge, showUnreadBadge, showTabSize } = options;
+ const { gridLayout, showContinueReadingButton, showDownloadBadge, showUnreadBadge, showTabSize } =
+ options;
return (
<>
{t('global.grid_layout.title')}
@@ -110,12 +111,12 @@ export const LibraryOptionsPanel: React.FC = ({ open, onClose }) => {
{t('library.option.display.badge.title')}
handleFilterChange('showUnreadBadge', !showUnreadBadge)}
/>
handleFilterChange('showDownloadBadge', !showDownloadBadge)}
/>
@@ -125,6 +126,15 @@ export const LibraryOptionsPanel: React.FC = ({ open, onClose }) => {
checked={showTabSize}
onChange={() => handleFilterChange('showTabSize', !showTabSize)}
/>
+
+ {t('global.label.other')}
+
+ handleFilterChange('showContinueReadingButton', !showContinueReadingButton)
+ }
+ />
>
);
}
diff --git a/src/components/manga/ContinueReadingButton.tsx b/src/components/manga/ContinueReadingButton.tsx
new file mode 100644
index 00000000..ff831dd2
--- /dev/null
+++ b/src/components/manga/ContinueReadingButton.tsx
@@ -0,0 +1,46 @@
+/*
+ * 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 { useTranslation } from 'react-i18next';
+import { Button, Tooltip } from '@mui/material';
+import PlayArrowIcon from '@mui/icons-material/PlayArrow';
+
+export const ContinueReadingButton = ({
+ showContinueReadingButton,
+ isLatestChapterRead,
+ nextChapterIndexToRead,
+ mangaLinkTo,
+}: {
+ showContinueReadingButton: boolean;
+ isLatestChapterRead: boolean;
+ nextChapterIndexToRead: number;
+ mangaLinkTo: string;
+}) => {
+ const { t } = useTranslation();
+
+ const isFirstChapter = nextChapterIndexToRead === 1;
+
+ if (!showContinueReadingButton || isLatestChapterRead) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index 1d7ccb47..956d8a39 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -141,8 +141,8 @@
"queue": {
"error": {
"label": {
- "failed_to_remove": "Could not remove the download from the queue.",
- "failed_delete_all": "Could not remove all downloads from the queue"
+ "failed_delete_all": "Could not remove all downloads from the queue",
+ "failed_to_remove": "Could not remove the download from the queue."
}
},
"label": {
@@ -319,6 +319,7 @@
"loading": "Loading…",
"never": "Never",
"none": "None",
+ "other": "Other",
"password": "Password",
"sort": "Sort",
"unknown": "Unknown",
@@ -379,6 +380,11 @@
},
"title": "Badges"
},
+ "other": {
+ "label": {
+ "show_continue_reading_button": "Show continue reading button"
+ }
+ },
"tab": {
"label": {
"show_number_of_items": "Show number of items"
diff --git a/src/typings.ts b/src/typings.ts
index 4aab13c8..5a76c7e2 100644
--- a/src/typings.ts
+++ b/src/typings.ts
@@ -340,6 +340,7 @@ enum GridLayout {
export interface LibraryOptions {
// display options
+ showContinueReadingButton: boolean;
showDownloadBadge: boolean;
showUnreadBadge: boolean;
gridLayout: GridLayout;