Feature/automatic chapter deletion more options (#484)
* Add missing translations keys * [Codegen] Update to latest server schema changes * [VersionMapping] Require server version "r1431" for preview * Rename "deleteChaptersAutoMarkedRead" metadata setting * Add more options to auto delete chapters while reading Makes it possible to delete the last to fifth to last read chapter instead of only being able to delete the last read chapter
This commit is contained in:
@@ -102,7 +102,7 @@ export const ChapterCard: React.FC<IProps> = (props: IProps) => {
|
||||
requestManager.updateChapter(chapter.id, {
|
||||
[key]: value,
|
||||
lastPageRead: key === 'isRead' ? 0 : undefined,
|
||||
deleteChapter: !!chapterIdsToDelete.length,
|
||||
chapterIdToDelete: chapterIdsToDelete[0],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 {
|
||||
SelectSetting,
|
||||
SelectSettingValue,
|
||||
SelectSettingValueDisplayInfo,
|
||||
} from '@/components/settings/SelectSetting.tsx';
|
||||
|
||||
const CHAPTERS_TO_DELETE = [0, 1, 2, 3, 4, 5] as const;
|
||||
const CHAPTERS_TO_DELETE_TO_TRANSLATION_KEY: {
|
||||
[flavor in (typeof CHAPTERS_TO_DELETE)[number]]: SelectSettingValueDisplayInfo;
|
||||
} = {
|
||||
0: {
|
||||
text: 'global.label.disabled',
|
||||
},
|
||||
1: {
|
||||
text: 'download.settings.delete_chapters.while_reading.option.label.first',
|
||||
},
|
||||
2: {
|
||||
text: 'download.settings.delete_chapters.while_reading.option.label.second',
|
||||
},
|
||||
3: {
|
||||
text: 'download.settings.delete_chapters.while_reading.option.label.third',
|
||||
},
|
||||
4: {
|
||||
text: 'download.settings.delete_chapters.while_reading.option.label.fourth',
|
||||
},
|
||||
5: {
|
||||
text: 'download.settings.delete_chapters.while_reading.option.label.fifth',
|
||||
},
|
||||
};
|
||||
const CHAPTERS_TO_DELETE_SELECT_VALUES: SelectSettingValue<(typeof CHAPTERS_TO_DELETE)[number]>[] =
|
||||
CHAPTERS_TO_DELETE.map((chapterToDelete) => [
|
||||
chapterToDelete,
|
||||
CHAPTERS_TO_DELETE_TO_TRANSLATION_KEY[chapterToDelete],
|
||||
]);
|
||||
|
||||
const getNormalizedChapterToDelete = (chapterToDelete?: number | boolean) => {
|
||||
if (!chapterToDelete) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isMigrationVersion0 = typeof chapterToDelete === 'boolean';
|
||||
if (isMigrationVersion0) {
|
||||
return Number(chapterToDelete);
|
||||
}
|
||||
|
||||
return chapterToDelete;
|
||||
};
|
||||
|
||||
export const DeleteChaptersWhileReadingSetting = ({
|
||||
chapterToDelete,
|
||||
handleChange,
|
||||
}: {
|
||||
chapterToDelete?: number;
|
||||
handleChange: (chapterToDelete: number) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const normalizedChapterToDelete = getNormalizedChapterToDelete(chapterToDelete);
|
||||
|
||||
return (
|
||||
<SelectSetting
|
||||
settingName={t('download.settings.delete_chapters.while_reading.label.title')}
|
||||
value={normalizedChapterToDelete}
|
||||
defaultValue={0}
|
||||
values={CHAPTERS_TO_DELETE_SELECT_VALUES}
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -157,6 +157,27 @@
|
||||
},
|
||||
"title": "Auto-download"
|
||||
},
|
||||
"delete_chapters": {
|
||||
"label": {
|
||||
"allow_deletion_of_bookmarked": "Allow deleting bookmarked chapters",
|
||||
"manually_marked_as_read": "Delete chapter after manually marking it as read"
|
||||
},
|
||||
"title": "Delete chapters",
|
||||
"while_reading": {
|
||||
"label": {
|
||||
"title": "Delete finished chapters while reading"
|
||||
},
|
||||
"option": {
|
||||
"label": {
|
||||
"fifth": "Fifth to last read chapter",
|
||||
"first": "Last read chapter",
|
||||
"fourth": "Fourth to last read chapter",
|
||||
"second": "Second to last read chapter",
|
||||
"third": "Third to last read chapter"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"download_ahead": {
|
||||
"label": {
|
||||
"description": "How many chapters should get downloaded when marking a chapter as read while reading.",
|
||||
@@ -286,6 +307,7 @@
|
||||
"label": {
|
||||
"browse": "Browse",
|
||||
"client": "Client",
|
||||
"disabled": "Disabled",
|
||||
"discord": "Discord",
|
||||
"display": "Display",
|
||||
"filter": "Filter",
|
||||
|
||||
@@ -416,7 +416,6 @@ export const WEBUI_UPDATE_INFO = gql`
|
||||
fragment WEBUI_UPDATE_INFO on WebUIUpdateInfo {
|
||||
channel
|
||||
tag
|
||||
updateAvailable
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ export type AboutServerPayloadFieldPolicy = {
|
||||
revision?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
version?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type AboutWebUIKeySpecifier = ('channel' | 'tag' | AboutWebUIKeySpecifier)[];
|
||||
export type AboutWebUIFieldPolicy = {
|
||||
channel?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
tag?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type BackupRestoreStatusKeySpecifier = ('mangaProgress' | 'state' | 'totalManga' | BackupRestoreStatusKeySpecifier)[];
|
||||
export type BackupRestoreStatusFieldPolicy = {
|
||||
mangaProgress?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
@@ -105,6 +110,13 @@ export type CheckForServerUpdatesPayloadFieldPolicy = {
|
||||
tag?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
url?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type ClearCachedImagesPayloadKeySpecifier = ('cachedPages' | 'cachedThumbnails' | 'clientMutationId' | 'downloadedThumbnails' | ClearCachedImagesPayloadKeySpecifier)[];
|
||||
export type ClearCachedImagesPayloadFieldPolicy = {
|
||||
cachedPages?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
cachedThumbnails?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
downloadedThumbnails?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type ClearDownloaderPayloadKeySpecifier = ('clientMutationId' | 'downloadStatus' | ClearDownloaderPayloadKeySpecifier)[];
|
||||
export type ClearDownloaderPayloadFieldPolicy = {
|
||||
clientMutationId?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
@@ -390,8 +402,9 @@ export type MultiSelectListPreferenceFieldPolicy = {
|
||||
title?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
visible?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type MutationKeySpecifier = ('clearDownloader' | 'createBackup' | 'createCategory' | 'deleteCategory' | 'deleteCategoryMeta' | 'deleteChapterMeta' | 'deleteDownloadedChapter' | 'deleteDownloadedChapters' | 'deleteGlobalMeta' | 'deleteMangaMeta' | 'dequeueChapterDownload' | 'dequeueChapterDownloads' | 'downloadAhead' | 'enqueueChapterDownload' | 'enqueueChapterDownloads' | 'fetchChapterPages' | 'fetchChapters' | 'fetchExtensions' | 'fetchManga' | 'fetchSourceManga' | 'installExternalExtension' | 'reorderChapterDownload' | 'resetSettings' | 'restoreBackup' | 'setCategoryMeta' | 'setChapterMeta' | 'setGlobalMeta' | 'setMangaMeta' | 'setSettings' | 'startDownloader' | 'stopDownloader' | 'updateCategories' | 'updateCategory' | 'updateCategoryManga' | 'updateCategoryOrder' | 'updateChapter' | 'updateChapters' | 'updateExtension' | 'updateExtensions' | 'updateLibraryManga' | 'updateManga' | 'updateMangaCategories' | 'updateMangas' | 'updateMangasCategories' | 'updateSourcePreference' | 'updateStop' | 'updateWebUI' | MutationKeySpecifier)[];
|
||||
export type MutationKeySpecifier = ('clearCachedImages' | 'clearDownloader' | 'createBackup' | 'createCategory' | 'deleteCategory' | 'deleteCategoryMeta' | 'deleteChapterMeta' | 'deleteDownloadedChapter' | 'deleteDownloadedChapters' | 'deleteGlobalMeta' | 'deleteMangaMeta' | 'dequeueChapterDownload' | 'dequeueChapterDownloads' | 'downloadAhead' | 'enqueueChapterDownload' | 'enqueueChapterDownloads' | 'fetchChapterPages' | 'fetchChapters' | 'fetchExtensions' | 'fetchManga' | 'fetchSourceManga' | 'installExternalExtension' | 'reorderChapterDownload' | 'resetSettings' | 'restoreBackup' | 'setCategoryMeta' | 'setChapterMeta' | 'setGlobalMeta' | 'setMangaMeta' | 'setSettings' | 'startDownloader' | 'stopDownloader' | 'updateCategories' | 'updateCategory' | 'updateCategoryManga' | 'updateCategoryOrder' | 'updateChapter' | 'updateChapters' | 'updateExtension' | 'updateExtensions' | 'updateLibraryManga' | 'updateManga' | 'updateMangaCategories' | 'updateMangas' | 'updateMangasCategories' | 'updateSourcePreference' | 'updateStop' | 'updateWebUI' | MutationKeySpecifier)[];
|
||||
export type MutationFieldPolicy = {
|
||||
clearCachedImages?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
clearDownloader?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
createBackup?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
createCategory?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
@@ -814,6 +827,12 @@ export type ValidateBackupSourceFieldPolicy = {
|
||||
id?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
name?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type WebUIUpdateCheckKeySpecifier = ('channel' | 'tag' | 'updateAvailable' | WebUIUpdateCheckKeySpecifier)[];
|
||||
export type WebUIUpdateCheckFieldPolicy = {
|
||||
channel?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
tag?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
updateAvailable?: FieldPolicy<any> | FieldReadFunction<any>
|
||||
};
|
||||
export type WebUIUpdateInfoKeySpecifier = ('channel' | 'tag' | 'updateAvailable' | WebUIUpdateInfoKeySpecifier)[];
|
||||
export type WebUIUpdateInfoFieldPolicy = {
|
||||
channel?: FieldPolicy<any> | FieldReadFunction<any>,
|
||||
@@ -836,6 +855,10 @@ export type StrictTypedTypePolicies = {
|
||||
keyFields?: false | AboutServerPayloadKeySpecifier | (() => undefined | AboutServerPayloadKeySpecifier),
|
||||
fields?: AboutServerPayloadFieldPolicy,
|
||||
},
|
||||
AboutWebUI?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | AboutWebUIKeySpecifier | (() => undefined | AboutWebUIKeySpecifier),
|
||||
fields?: AboutWebUIFieldPolicy,
|
||||
},
|
||||
BackupRestoreStatus?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | BackupRestoreStatusKeySpecifier | (() => undefined | BackupRestoreStatusKeySpecifier),
|
||||
fields?: BackupRestoreStatusFieldPolicy,
|
||||
@@ -884,6 +907,10 @@ export type StrictTypedTypePolicies = {
|
||||
keyFields?: false | CheckForServerUpdatesPayloadKeySpecifier | (() => undefined | CheckForServerUpdatesPayloadKeySpecifier),
|
||||
fields?: CheckForServerUpdatesPayloadFieldPolicy,
|
||||
},
|
||||
ClearCachedImagesPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | ClearCachedImagesPayloadKeySpecifier | (() => undefined | ClearCachedImagesPayloadKeySpecifier),
|
||||
fields?: ClearCachedImagesPayloadFieldPolicy,
|
||||
},
|
||||
ClearDownloaderPayload?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | ClearDownloaderPayloadKeySpecifier | (() => undefined | ClearDownloaderPayloadKeySpecifier),
|
||||
fields?: ClearDownloaderPayloadFieldPolicy,
|
||||
@@ -1248,6 +1275,10 @@ export type StrictTypedTypePolicies = {
|
||||
keyFields?: false | ValidateBackupSourceKeySpecifier | (() => undefined | ValidateBackupSourceKeySpecifier),
|
||||
fields?: ValidateBackupSourceFieldPolicy,
|
||||
},
|
||||
WebUIUpdateCheck?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | WebUIUpdateCheckKeySpecifier | (() => undefined | WebUIUpdateCheckKeySpecifier),
|
||||
fields?: WebUIUpdateCheckFieldPolicy,
|
||||
},
|
||||
WebUIUpdateInfo?: Omit<TypePolicy, "fields" | "keyFields"> & {
|
||||
keyFields?: false | WebUIUpdateInfoKeySpecifier | (() => undefined | WebUIUpdateInfoKeySpecifier),
|
||||
fields?: WebUIUpdateInfoFieldPolicy,
|
||||
|
||||
@@ -28,6 +28,12 @@ export type AboutServerPayload = {
|
||||
version: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type AboutWebUi = {
|
||||
__typename?: 'AboutWebUI';
|
||||
channel: Scalars['String']['output'];
|
||||
tag: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum BackupRestoreState {
|
||||
Failure = 'FAILURE',
|
||||
Idle = 'IDLE',
|
||||
@@ -244,6 +250,21 @@ export type CheckForServerUpdatesPayload = {
|
||||
url: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type ClearCachedImagesInput = {
|
||||
cachedPages?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
cachedThumbnails?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||
downloadedThumbnails?: InputMaybe<Scalars['Boolean']['input']>;
|
||||
};
|
||||
|
||||
export type ClearCachedImagesPayload = {
|
||||
__typename?: 'ClearCachedImagesPayload';
|
||||
cachedPages?: Maybe<Scalars['Boolean']['output']>;
|
||||
cachedThumbnails?: Maybe<Scalars['Boolean']['output']>;
|
||||
clientMutationId?: Maybe<Scalars['String']['output']>;
|
||||
downloadedThumbnails?: Maybe<Scalars['Boolean']['output']>;
|
||||
};
|
||||
|
||||
export type ClearDownloaderInput = {
|
||||
clientMutationId?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
@@ -907,6 +928,7 @@ export type MultiSelectListPreference = {
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
clearCachedImages: ClearCachedImagesPayload;
|
||||
clearDownloader: ClearDownloaderPayload;
|
||||
createBackup: CreateBackupPayload;
|
||||
createCategory: CreateCategoryPayload;
|
||||
@@ -957,6 +979,11 @@ export type Mutation = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationClearCachedImagesArgs = {
|
||||
input: ClearCachedImagesInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationClearDownloaderArgs = {
|
||||
input: ClearDownloaderInput;
|
||||
};
|
||||
@@ -1294,13 +1321,13 @@ export type Preference = CheckBoxPreference | EditTextPreference | ListPreferenc
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
aboutServer: AboutServerPayload;
|
||||
aboutWebUI: WebUiUpdateInfo;
|
||||
aboutWebUI: AboutWebUi;
|
||||
categories: CategoryNodeList;
|
||||
category: CategoryType;
|
||||
chapter: ChapterType;
|
||||
chapters: ChapterNodeList;
|
||||
checkForServerUpdates: Array<CheckForServerUpdatesPayload>;
|
||||
checkForWebUIUpdate: WebUiUpdateInfo;
|
||||
checkForWebUIUpdate: WebUiUpdateCheck;
|
||||
downloadStatus: DownloadStatus;
|
||||
extension: ExtensionType;
|
||||
extensions: ExtensionNodeList;
|
||||
@@ -2055,6 +2082,13 @@ export enum WebUiInterface {
|
||||
Electron = 'ELECTRON'
|
||||
}
|
||||
|
||||
export type WebUiUpdateCheck = {
|
||||
__typename?: 'WebUIUpdateCheck';
|
||||
channel: Scalars['String']['output'];
|
||||
tag: Scalars['String']['output'];
|
||||
updateAvailable: Scalars['Boolean']['output'];
|
||||
};
|
||||
|
||||
export type WebUiUpdateInfo = {
|
||||
__typename?: 'WebUIUpdateInfo';
|
||||
channel: Scalars['String']['output'];
|
||||
@@ -2109,9 +2143,9 @@ export type PartialUpdaterStatusFragment = { __typename?: 'UpdateStatus', isRunn
|
||||
|
||||
export type FullUpdaterStatusFragment = { __typename?: 'UpdateStatus', isRunning: boolean, completeJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', unreadCount: number, downloadCount: number, artist?: string | null, author?: string | null, chaptersLastFetchedAt?: any | null, description?: string | null, genre: Array<string>, id: number, inLibrary: boolean, inLibraryAt: any, initialized: boolean, lastFetchedAt?: any | null, realUrl?: string | null, status: MangaStatus, thumbnailUrl?: string | null, title: string, url: string, chapters: { __typename?: 'ChapterNodeList', totalCount: number }, meta: Array<{ __typename?: 'MangaMetaType', key: string, value: string }>, source?: { __typename?: 'SourceType', displayName: string, iconUrl: string, id: any, isConfigurable: boolean, isNsfw: boolean, lang: string, name: string, supportsLatest: boolean } | null }> } }, failedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, pendingJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, runningJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, skippedJobs: { __typename?: 'UpdateStatusType', mangas: { __typename?: 'MangaNodeList', totalCount: number, nodes: Array<{ __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null }> } }, updatingCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number, name: string, includeInUpdate: IncludeInUpdate }> } }, skippedCategories: { __typename?: 'UpdateStatusCategoryType', categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number, name: string, includeInUpdate: IncludeInUpdate }> } } };
|
||||
|
||||
export type WebuiUpdateInfoFragment = { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean };
|
||||
export type WebuiUpdateInfoFragment = { __typename?: 'WebUIUpdateInfo', channel: string, tag: string };
|
||||
|
||||
export type WebuiUpdateStatusFragment = { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } };
|
||||
export type WebuiUpdateStatusFragment = { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string } };
|
||||
|
||||
export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyHost: string, socksProxyPort: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadAheadLimit: number, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, basicAuthEnabled: boolean, basicAuthUsername: string, basicAuthPassword: string, debugLogsEnabled: boolean, gqlDebugLogsEnabled: boolean, systemTrayEnabled: boolean, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string };
|
||||
|
||||
@@ -2218,6 +2252,7 @@ export type UpdateChapterMutationVariables = Exact<{
|
||||
getRead: Scalars['Boolean']['input'];
|
||||
getLastPageRead: Scalars['Boolean']['input'];
|
||||
id: Scalars['Int']['input'];
|
||||
chapterIdToDelete: Scalars['Int']['input'];
|
||||
deleteChapter: Scalars['Boolean']['input'];
|
||||
mangaId: Scalars['Int']['input'];
|
||||
downloadAhead: Scalars['Boolean']['input'];
|
||||
@@ -2414,7 +2449,7 @@ export type UpdateWebuiMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateWebuiMutation = { __typename?: 'Mutation', updateWebUI: { __typename?: 'WebUIUpdatePayload', clientMutationId?: string | null, updateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } } };
|
||||
export type UpdateWebuiMutation = { __typename?: 'Mutation', updateWebUI: { __typename?: 'WebUIUpdatePayload', clientMutationId?: string | null, updateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string } } } };
|
||||
|
||||
export type ResetServerSettingsMutationVariables = Exact<{
|
||||
input: ResetSettingsInput;
|
||||
@@ -2604,7 +2639,7 @@ export type GetMangasQuery = { __typename?: 'Query', mangas: { __typename?: 'Man
|
||||
export type GetAboutQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetAboutQuery = { __typename?: 'Query', aboutServer: { __typename?: 'AboutServerPayload', buildTime: any, buildType: string, discord: string, github: string, name: string, revision: string, version: string }, aboutWebUI: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } };
|
||||
export type GetAboutQuery = { __typename?: 'Query', aboutServer: { __typename?: 'AboutServerPayload', buildTime: any, buildType: string, discord: string, github: string, name: string, revision: string, version: string }, aboutWebUI: { __typename?: 'AboutWebUI', channel: string, tag: string } };
|
||||
|
||||
export type CheckForServerUpdatesQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -2614,12 +2649,12 @@ export type CheckForServerUpdatesQuery = { __typename?: 'Query', checkForServerU
|
||||
export type CheckForWebuiUpdateQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CheckForWebuiUpdateQuery = { __typename?: 'Query', checkForWebUIUpdate: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } };
|
||||
export type CheckForWebuiUpdateQuery = { __typename?: 'Query', checkForWebUIUpdate: { __typename?: 'WebUIUpdateCheck', channel: string, tag: string, updateAvailable: boolean } };
|
||||
|
||||
export type GetWebuiUpdateStatusQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetWebuiUpdateStatusQuery = { __typename?: 'Query', getWebUIUpdateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } };
|
||||
export type GetWebuiUpdateStatusQuery = { __typename?: 'Query', getWebUIUpdateStatus: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string } } };
|
||||
|
||||
export type GetServerSettingsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
@@ -2656,7 +2691,7 @@ export type DownloadStatusSubscription = { __typename?: 'Subscription', download
|
||||
export type WebuiUpdateSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type WebuiUpdateSubscription = { __typename?: 'Subscription', webUIUpdateStatusChange: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string, updateAvailable: boolean } } };
|
||||
export type WebuiUpdateSubscription = { __typename?: 'Subscription', webUIUpdateStatusChange: { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string } } };
|
||||
|
||||
export type UpdaterSubscriptionVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ export const UPDATE_CHAPTER = gql`
|
||||
$getRead: Boolean!
|
||||
$getLastPageRead: Boolean!
|
||||
$id: Int!
|
||||
$chapterIdToDelete: Int!
|
||||
$deleteChapter: Boolean!
|
||||
$mangaId: Int!
|
||||
$downloadAhead: Boolean!
|
||||
@@ -109,7 +110,7 @@ export const UPDATE_CHAPTER = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteDownloadedChapter(input: { id: $id }) @include(if: $deleteChapter) {
|
||||
deleteDownloadedChapter(input: { id: $chapterIdToDelete }) @include(if: $deleteChapter) {
|
||||
clientMutationId
|
||||
chapters {
|
||||
id
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import gql from 'graphql-tag';
|
||||
import { WEBUI_UPDATE_INFO, WEBUI_UPDATE_STATUS } from '@/lib/graphql/Fragments';
|
||||
import { WEBUI_UPDATE_STATUS } from '@/lib/graphql/Fragments';
|
||||
|
||||
export const GET_ABOUT = gql`
|
||||
query GET_ABOUT {
|
||||
@@ -23,7 +23,6 @@ export const GET_ABOUT = gql`
|
||||
aboutWebUI {
|
||||
channel
|
||||
tag
|
||||
updateAvailable
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -39,10 +38,11 @@ export const CHECK_FOR_SERVER_UPDATES = gql`
|
||||
`;
|
||||
|
||||
export const CHECK_FOR_WEBUI_UPDATE = gql`
|
||||
${WEBUI_UPDATE_INFO}
|
||||
query CHECK_FOR_WEBUI_UPDATE {
|
||||
checkForWebUIUpdate {
|
||||
...WEBUI_UPDATE_INFO
|
||||
channel
|
||||
tag
|
||||
updateAvailable
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1498,10 +1498,13 @@ export class RequestManager {
|
||||
|
||||
public updateChapter(
|
||||
id: number,
|
||||
patch: UpdateChapterPatchInput & { deleteChapter?: boolean; downloadAheadMangaId?: number },
|
||||
patch: UpdateChapterPatchInput & {
|
||||
chapterIdToDelete?: number;
|
||||
downloadAheadMangaId?: number;
|
||||
},
|
||||
options?: MutationOptions<UpdateChapterMutation, UpdateChapterMutationVariables>,
|
||||
): AbortableApolloMutationResponse<UpdateChapterMutation> {
|
||||
const { deleteChapter, downloadAheadMangaId = -1, ...updatePatch } = patch;
|
||||
const { chapterIdToDelete = -1, downloadAheadMangaId = -1, ...updatePatch } = patch;
|
||||
|
||||
return this.doRequest<UpdateChapterMutation, UpdateChapterMutationVariables>(
|
||||
GQLMethod.MUTATION,
|
||||
@@ -1512,7 +1515,8 @@ export class RequestManager {
|
||||
getBookmarked: patch.isBookmarked != null,
|
||||
getRead: patch.isRead != null,
|
||||
getLastPageRead: patch.lastPageRead != null,
|
||||
deleteChapter: !!deleteChapter,
|
||||
chapterIdToDelete,
|
||||
deleteChapter: chapterIdToDelete >= 0,
|
||||
mangaId: downloadAheadMangaId,
|
||||
downloadAhead: downloadAheadMangaId !== -1,
|
||||
},
|
||||
|
||||
@@ -169,6 +169,8 @@ export function Reader() {
|
||||
const [pageToScrollTo, setPageToScrollTo] = useState<number | undefined>(undefined);
|
||||
const { setOverride, setTitle } = useContext(NavBarContext);
|
||||
const [retrievingNextChapter, setRetrievingNextChapter] = useState(false);
|
||||
const { data: mangaChaptersData } = requestManager.useGetMangaChapters(mangaId, { nextFetchPolicy: 'standby' });
|
||||
const mangaChapters = mangaChaptersData?.chapters.nodes;
|
||||
|
||||
const { settings: defaultSettings, loading: areDefaultSettingsLoading } = useDefaultReaderSettings();
|
||||
const [settings, setSettings] = useState(getReaderSettingsFor(manga, defaultSettings));
|
||||
@@ -176,11 +178,27 @@ export function Reader() {
|
||||
const { settings: metadataSettings } = useMetadataServerSettings();
|
||||
|
||||
const updateChapter = (patch: UpdateChapterPatchInput) => {
|
||||
const shouldDeleteChapter =
|
||||
!!patch.isRead &&
|
||||
metadataSettings.deleteChaptersAutoMarkedRead &&
|
||||
chapter.isDownloaded &&
|
||||
(!chapter.isBookmarked || metadataSettings.deleteChaptersWithBookmark);
|
||||
const isAutoDeletionEnabled = !!patch.isRead && !!metadataSettings.deleteChaptersWhileReading;
|
||||
|
||||
const getChapterIdToDelete = () => {
|
||||
if (!isAutoDeletionEnabled || !mangaChapters) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const chapterToDeleteSourceOrder = Number(chapterIndex) - (metadataSettings.deleteChaptersWhileReading - 1);
|
||||
const chapterToDelete = mangaChapters.find(
|
||||
(mangaChapter) => mangaChapter.sourceOrder === chapterToDeleteSourceOrder,
|
||||
);
|
||||
|
||||
const shouldDeleteChapter =
|
||||
chapterToDelete?.isDownloaded &&
|
||||
(!chapterToDelete?.isBookmarked || metadataSettings.deleteChaptersWithBookmark);
|
||||
if (!shouldDeleteChapter) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return chapterToDelete.id;
|
||||
};
|
||||
|
||||
const shouldDownloadAhead =
|
||||
chapter.manga.inLibrary && !chapter.isRead && !!patch.isRead && isDownloadAheadEnabled;
|
||||
@@ -188,7 +206,7 @@ export function Reader() {
|
||||
requestManager
|
||||
.updateChapter(chapter.id, {
|
||||
...patch,
|
||||
deleteChapter: shouldDeleteChapter,
|
||||
chapterIdToDelete: getChapterIdToDelete(),
|
||||
downloadAheadMangaId: shouldDownloadAhead ? chapter.manga.id : undefined,
|
||||
})
|
||||
.response.catch(() => {});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { DownloadAheadSetting } from '@/components/settings/downloads/DownloadAh
|
||||
import { useMetadataServerSettings } from '@/util/metadataServerSettings.ts';
|
||||
import { convertToGqlMeta, requestUpdateServerMetadata } from '@/util/metadata.ts';
|
||||
import { makeToast } from '@/components/util/Toast.tsx';
|
||||
import { DeleteChaptersWhileReadingSetting } from '@/components/settings/downloads/DeleteChaptersWhileReadingSetting.tsx';
|
||||
|
||||
type DownloadSettingsType = Pick<
|
||||
ServerSettings,
|
||||
@@ -97,12 +98,12 @@ export const DownloadSettings = () => {
|
||||
<List
|
||||
subheader={
|
||||
<ListSubheader component="div" id="download-settings-auto-download">
|
||||
Delete chapters
|
||||
{t('download.settings.delete_chapters.title')}
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItem>
|
||||
<ListItemText primary="Delete chapter after manually marking it as read" />
|
||||
<ListItemText primary={t('download.settings.delete_chapters.label.manually_marked_as_read')} />
|
||||
<ListItemSecondaryAction>
|
||||
<Switch
|
||||
edge="end"
|
||||
@@ -113,18 +114,14 @@ export const DownloadSettings = () => {
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<DeleteChaptersWhileReadingSetting
|
||||
chapterToDelete={metadataSettings.deleteChaptersWhileReading}
|
||||
handleChange={(chapterToDelete) =>
|
||||
updateMetadataSetting('deleteChaptersWhileReading', chapterToDelete)
|
||||
}
|
||||
/>
|
||||
<ListItem>
|
||||
<ListItemText primary="Delete finished chapters while reading" />
|
||||
<ListItemSecondaryAction>
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={metadataSettings.deleteChaptersAutoMarkedRead}
|
||||
onChange={(e) => updateMetadataSetting('deleteChaptersAutoMarkedRead', e.target.checked)}
|
||||
/>
|
||||
</ListItemSecondaryAction>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText primary="Allow deleting bookmarked chapters" />
|
||||
<ListItemText primary={t('download.settings.delete_chapters.label.allow_deletion_of_bookmarked')} />
|
||||
<ListItemSecondaryAction>
|
||||
<Switch
|
||||
edge="end"
|
||||
|
||||
@@ -230,7 +230,7 @@ export enum ChapterOffset {
|
||||
|
||||
export type MetadataServerSettings = {
|
||||
deleteChaptersManuallyMarkedRead: boolean;
|
||||
deleteChaptersAutoMarkedRead: boolean;
|
||||
deleteChaptersWhileReading: number;
|
||||
deleteChaptersWithBookmark: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -83,6 +83,9 @@ const migrations: IMetadataMigration[] = [
|
||||
{
|
||||
keys: [{ oldKey: 'loadNextonEnding', newKey: 'loadNextOnEnding' }],
|
||||
},
|
||||
{
|
||||
keys: [{ oldKey: 'deleteChaptersAutoMarkedRead', newKey: 'deleteChaptersWhileReading' }],
|
||||
},
|
||||
];
|
||||
|
||||
const getAppKeyPrefixForMigration = (migrationId: number): string => {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { convertFromGqlMeta, getMetadataFrom } from '@/util/metadata';
|
||||
|
||||
export const getDefaultSettings = (): MetadataServerSettings => ({
|
||||
deleteChaptersManuallyMarkedRead: false,
|
||||
deleteChaptersAutoMarkedRead: false,
|
||||
deleteChaptersWhileReading: 0,
|
||||
deleteChaptersWithBookmark: false,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"uiVersion": "PREVIEW",
|
||||
"serverVersion": "r1427"
|
||||
"serverVersion": "r1431"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user