Add option to update tracking on manual mark as read
This commit is contained in:
@@ -1127,7 +1127,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
"update_progress_reading": "Update progress after reading"
|
"update_progress_manual": "Update progress after manually marking as read",
|
||||||
|
"update_progress_reading": "Update progress after reading",
|
||||||
|
"update_progress_reading_description": "Does not work when marking multiple manga as read at once"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"settings": "Tracking settings",
|
"settings": "Tracking settings",
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
ChapterAction,
|
ChapterAction,
|
||||||
ChapterBookmarkInfo,
|
ChapterBookmarkInfo,
|
||||||
ChapterDownloadInfo,
|
ChapterDownloadInfo,
|
||||||
|
ChapterIdInfo,
|
||||||
|
ChapterMangaInfo,
|
||||||
ChapterReadInfo,
|
ChapterReadInfo,
|
||||||
ChapterRealUrlInfo,
|
ChapterRealUrlInfo,
|
||||||
Chapters,
|
Chapters,
|
||||||
@@ -38,7 +40,12 @@ import { useMetadataServerSettings } from '@/lib/metadata/metadataServerSettings
|
|||||||
type BaseProps = { onClose: () => void };
|
type BaseProps = { onClose: () => void };
|
||||||
|
|
||||||
type SingleModeProps = {
|
type SingleModeProps = {
|
||||||
chapter: ChapterDownloadInfo & ChapterBookmarkInfo & ChapterReadInfo & ChapterRealUrlInfo;
|
chapter: ChapterIdInfo &
|
||||||
|
ChapterMangaInfo &
|
||||||
|
ChapterDownloadInfo &
|
||||||
|
ChapterBookmarkInfo &
|
||||||
|
ChapterReadInfo &
|
||||||
|
ChapterRealUrlInfo;
|
||||||
allChapters: TChapter[];
|
allChapters: TChapter[];
|
||||||
handleSelection?: SelectableCollectionReturnType<TChapter['id']>['handleSelection'];
|
handleSelection?: SelectableCollectionReturnType<TChapter['id']>['handleSelection'];
|
||||||
canBeDownloaded: boolean;
|
canBeDownloaded: boolean;
|
||||||
@@ -109,7 +116,7 @@ export const ChapterActionMenuItems = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getChapters = (): (ChapterDownloadInfo & ChapterBookmarkInfo & ChapterReadInfo)[] => {
|
const getChapters = (): SingleModeProps['chapter'][] => {
|
||||||
// select mode
|
// select mode
|
||||||
if (!chapter) {
|
if (!chapter) {
|
||||||
return ChaptersWithMeta.getChapters(chaptersWithMeta);
|
return ChaptersWithMeta.getChapters(chaptersWithMeta);
|
||||||
@@ -139,6 +146,7 @@ export const ChapterActionMenuItems = ({
|
|||||||
Chapters.performAction(actualAction, Chapters.getIds(chapters), {
|
Chapters.performAction(actualAction, Chapters.getIds(chapters), {
|
||||||
chapters,
|
chapters,
|
||||||
wasManuallyMarkedAsRead: true,
|
wasManuallyMarkedAsRead: true,
|
||||||
|
trackProgressMangaId: chapters[0]?.mangaId,
|
||||||
}).catch(defaultPromiseErrorHandler('ChapterActionMenuItems::performAction'));
|
}).catch(defaultPromiseErrorHandler('ChapterActionMenuItems::performAction'));
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import { t as translate } from 'i18next';
|
import { t as translate } from 'i18next';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import { DocumentNode } from '@apollo/client';
|
import { DocumentNode } from '@apollo/client';
|
||||||
import { ChapterOffset, TChapter, TranslationKey } from '@/typings.ts';
|
import { ChapterOffset, TChapter, TManga, TranslationKey } from '@/typings.ts';
|
||||||
import { makeToast } from '@/components/util/Toast.tsx';
|
import { makeToast } from '@/components/util/Toast.tsx';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
|
import { getMetadataServerSettings } from '@/lib/metadata/metadataServerSettings.ts';
|
||||||
@@ -78,6 +78,7 @@ export const actionToTranslationKey: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ChapterIdInfo = Pick<TChapter, 'id'>;
|
export type ChapterIdInfo = Pick<TChapter, 'id'>;
|
||||||
|
export type ChapterMangaInfo = Pick<TChapter, 'mangaId'>;
|
||||||
export type ChapterDownloadInfo = ChapterIdInfo & Pick<TChapter, 'isDownloaded'>;
|
export type ChapterDownloadInfo = ChapterIdInfo & Pick<TChapter, 'isDownloaded'>;
|
||||||
export type ChapterBookmarkInfo = ChapterIdInfo & Pick<TChapter, 'isBookmarked'>;
|
export type ChapterBookmarkInfo = ChapterIdInfo & Pick<TChapter, 'isBookmarked'>;
|
||||||
export type ChapterReadInfo = ChapterIdInfo & Pick<TChapter, 'isRead'>;
|
export type ChapterReadInfo = ChapterIdInfo & Pick<TChapter, 'isRead'>;
|
||||||
@@ -207,8 +208,10 @@ export class Chapters {
|
|||||||
static async markAsRead(
|
static async markAsRead(
|
||||||
chapters: (ChapterDownloadInfo & ChapterBookmarkInfo)[],
|
chapters: (ChapterDownloadInfo & ChapterBookmarkInfo)[],
|
||||||
wasManuallyMarkedAsRead: boolean = false,
|
wasManuallyMarkedAsRead: boolean = false,
|
||||||
|
trackProgressMangaId?: TManga['id'],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { deleteChaptersManuallyMarkedRead, deleteChaptersWithBookmark } = await getMetadataServerSettings();
|
const { deleteChaptersManuallyMarkedRead, deleteChaptersWithBookmark, updateProgressManualMarkRead } =
|
||||||
|
await getMetadataServerSettings();
|
||||||
const chapterIdsToDelete =
|
const chapterIdsToDelete =
|
||||||
deleteChaptersManuallyMarkedRead && wasManuallyMarkedAsRead
|
deleteChaptersManuallyMarkedRead && wasManuallyMarkedAsRead
|
||||||
? Chapters.getIds(Chapters.getDeletable(chapters, deleteChaptersWithBookmark))
|
? Chapters.getIds(Chapters.getDeletable(chapters, deleteChaptersWithBookmark))
|
||||||
@@ -221,6 +224,8 @@ export class Chapters {
|
|||||||
isRead: true,
|
isRead: true,
|
||||||
lastPageRead: 0,
|
lastPageRead: 0,
|
||||||
chapterIdsToDelete,
|
chapterIdsToDelete,
|
||||||
|
trackProgressMangaId:
|
||||||
|
updateProgressManualMarkRead && wasManuallyMarkedAsRead ? trackProgressMangaId : undefined,
|
||||||
}).response,
|
}).response,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -268,14 +273,17 @@ export class Chapters {
|
|||||||
chapterIds: number[],
|
chapterIds: number[],
|
||||||
{
|
{
|
||||||
wasManuallyMarkedAsRead,
|
wasManuallyMarkedAsRead,
|
||||||
|
trackProgressMangaId,
|
||||||
chapters,
|
chapters,
|
||||||
}: Action extends 'mark_as_read'
|
}: Action extends 'mark_as_read'
|
||||||
? {
|
? {
|
||||||
wasManuallyMarkedAsRead: boolean;
|
wasManuallyMarkedAsRead: boolean;
|
||||||
|
trackProgressMangaId?: TManga['id'];
|
||||||
chapters: (ChapterDownloadInfo & ChapterBookmarkInfo & ChapterReadInfo)[];
|
chapters: (ChapterDownloadInfo & ChapterBookmarkInfo & ChapterReadInfo)[];
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
wasManuallyMarkedAsRead?: never;
|
wasManuallyMarkedAsRead?: never;
|
||||||
|
trackProgressMangaId?: never;
|
||||||
chapters?: never;
|
chapters?: never;
|
||||||
},
|
},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -285,7 +293,7 @@ export class Chapters {
|
|||||||
case 'delete':
|
case 'delete':
|
||||||
return Chapters.delete(chapterIds);
|
return Chapters.delete(chapterIds);
|
||||||
case 'mark_as_read':
|
case 'mark_as_read':
|
||||||
return Chapters.markAsRead(chapters!, wasManuallyMarkedAsRead!);
|
return Chapters.markAsRead(chapters!, wasManuallyMarkedAsRead!, trackProgressMangaId);
|
||||||
case 'mark_as_unread':
|
case 'mark_as_unread':
|
||||||
return Chapters.markAsUnread(chapterIds);
|
return Chapters.markAsUnread(chapterIds);
|
||||||
case 'bookmark':
|
case 'bookmark':
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ export class Mangas {
|
|||||||
|
|
||||||
static async markAsRead(mangaIds: number[], wasManuallyMarkedAsRead: boolean = false): Promise<void> {
|
static async markAsRead(mangaIds: number[], wasManuallyMarkedAsRead: boolean = false): Promise<void> {
|
||||||
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: false });
|
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: false });
|
||||||
return Chapters.markAsRead(chapters, wasManuallyMarkedAsRead);
|
return Chapters.markAsRead(chapters, wasManuallyMarkedAsRead, mangaIds.length === 1 ? mangaIds[0] : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async markAsUnread(mangaIds: number[]): Promise<void> {
|
static async markAsUnread(mangaIds: number[]): Promise<void> {
|
||||||
|
|||||||
@@ -328,6 +328,7 @@ export const FULL_CHAPTER_FIELDS = gql`
|
|||||||
isRead
|
isRead
|
||||||
lastPageRead
|
lastPageRead
|
||||||
lastReadAt
|
lastReadAt
|
||||||
|
mangaId
|
||||||
manga {
|
manga {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -146,6 +146,7 @@ export const UPDATE_CHAPTER = gql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const UPDATE_CHAPTERS = gql`
|
export const UPDATE_CHAPTERS = gql`
|
||||||
|
${BASE_TRACK_RECORD_FIELDS}
|
||||||
mutation UPDATE_CHAPTERS(
|
mutation UPDATE_CHAPTERS(
|
||||||
$input: UpdateChaptersInput!
|
$input: UpdateChaptersInput!
|
||||||
$getBookmarked: Boolean!
|
$getBookmarked: Boolean!
|
||||||
@@ -153,6 +154,8 @@ export const UPDATE_CHAPTERS = gql`
|
|||||||
$getLastPageRead: Boolean!
|
$getLastPageRead: Boolean!
|
||||||
$chapterIdsToDelete: [Int!]!
|
$chapterIdsToDelete: [Int!]!
|
||||||
$deleteChapters: Boolean!
|
$deleteChapters: Boolean!
|
||||||
|
$mangaId: Int!
|
||||||
|
$trackProgress: Boolean!
|
||||||
) {
|
) {
|
||||||
updateChapters(input: $input) {
|
updateChapters(input: $input) {
|
||||||
clientMutationId
|
clientMutationId
|
||||||
@@ -192,5 +195,10 @@ export const UPDATE_CHAPTERS = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
trackProgress(input: { mangaId: $mangaId }) @include(if: $trackProgress) {
|
||||||
|
trackRecords {
|
||||||
|
...BASE_TRACK_RECORD_FIELDS
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ const GLOBAL_METADATA_KEYS: AppMetadataKeys[] = [
|
|||||||
|
|
||||||
// tracking
|
// tracking
|
||||||
'updateProgressAfterReading',
|
'updateProgressAfterReading',
|
||||||
|
'updateProgressManualMarkRead',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export const getDefaultSettings = (): MetadataServerSettings => ({
|
|||||||
|
|
||||||
// tracking
|
// tracking
|
||||||
updateProgressAfterReading: true,
|
updateProgressAfterReading: true,
|
||||||
|
updateProgressManualMarkRead: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const convertSettingsToMetadata = (
|
export const convertSettingsToMetadata = (
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ import {
|
|||||||
TRACKER_UPDATE_BIND,
|
TRACKER_UPDATE_BIND,
|
||||||
} from '@/lib/graphql/mutations/TrackerMutation.ts';
|
} from '@/lib/graphql/mutations/TrackerMutation.ts';
|
||||||
import { ControlledPromise } from '@/lib/ControlledPromise.ts';
|
import { ControlledPromise } from '@/lib/ControlledPromise.ts';
|
||||||
|
import { TManga } from '@/typings.ts';
|
||||||
|
|
||||||
enum GQLMethod {
|
enum GQLMethod {
|
||||||
QUERY = 'QUERY',
|
QUERY = 'QUERY',
|
||||||
@@ -1942,10 +1943,10 @@ export class RequestManager {
|
|||||||
|
|
||||||
public updateChapters(
|
public updateChapters(
|
||||||
ids: number[],
|
ids: number[],
|
||||||
patch: UpdateChapterPatchInput & { chapterIdsToDelete?: number[] },
|
patch: UpdateChapterPatchInput & { chapterIdsToDelete?: number[]; trackProgressMangaId?: TManga['id'] },
|
||||||
options?: MutationOptions<UpdateChaptersMutation, UpdateChaptersMutationVariables>,
|
options?: MutationOptions<UpdateChaptersMutation, UpdateChaptersMutationVariables>,
|
||||||
): AbortableApolloMutationResponse<UpdateChaptersMutation> {
|
): AbortableApolloMutationResponse<UpdateChaptersMutation> {
|
||||||
const { chapterIdsToDelete = [], ...updatePatch } = patch;
|
const { chapterIdsToDelete = [], trackProgressMangaId = -1, ...updatePatch } = patch;
|
||||||
|
|
||||||
return this.doRequest<UpdateChaptersMutation, UpdateChaptersMutationVariables>(
|
return this.doRequest<UpdateChaptersMutation, UpdateChaptersMutationVariables>(
|
||||||
GQLMethod.MUTATION,
|
GQLMethod.MUTATION,
|
||||||
@@ -1957,6 +1958,8 @@ export class RequestManager {
|
|||||||
getLastPageRead: patch.lastPageRead != null,
|
getLastPageRead: patch.lastPageRead != null,
|
||||||
chapterIdsToDelete,
|
chapterIdsToDelete,
|
||||||
deleteChapters: !!chapterIdsToDelete.length,
|
deleteChapters: !!chapterIdsToDelete.length,
|
||||||
|
mangaId: trackProgressMangaId,
|
||||||
|
trackProgress: trackProgressMangaId >= 0,
|
||||||
},
|
},
|
||||||
options,
|
options,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const TrackingSettings = () => {
|
|||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
settings: { updateProgressAfterReading },
|
settings: { updateProgressAfterReading, updateProgressManualMarkRead },
|
||||||
} = useMetadataServerSettings();
|
} = useMetadataServerSettings();
|
||||||
const updateTrackingSettings = createUpdateMetadataServerSettings<keyof MetadataTrackingSettings>(() =>
|
const updateTrackingSettings = createUpdateMetadataServerSettings<keyof MetadataTrackingSettings>(() =>
|
||||||
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
makeToast(t('global.error.label.failed_to_save_changes'), 'error'),
|
||||||
@@ -63,6 +63,17 @@ export const TrackingSettings = () => {
|
|||||||
onChange={(e) => updateTrackingSettings('updateProgressAfterReading', e.target.checked)}
|
onChange={(e) => updateTrackingSettings('updateProgressAfterReading', e.target.checked)}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText
|
||||||
|
primary={t('tracking.settings.label.update_progress_manual')}
|
||||||
|
secondary={t('tracking.setting.label.update_progress_reading_description')}
|
||||||
|
/>
|
||||||
|
<Switch
|
||||||
|
edge="end"
|
||||||
|
checked={updateProgressManualMarkRead}
|
||||||
|
onChange={(e) => updateTrackingSettings('updateProgressManualMarkRead', e.target.checked)}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
<List
|
<List
|
||||||
subheader={
|
subheader={
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ export type MetadataBrowseSettings = {
|
|||||||
|
|
||||||
export type MetadataTrackingSettings = {
|
export type MetadataTrackingSettings = {
|
||||||
updateProgressAfterReading: boolean;
|
updateProgressAfterReading: boolean;
|
||||||
|
updateProgressManualMarkRead: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MetadataServerSettings = MetadataDownloadSettings &
|
export type MetadataServerSettings = MetadataDownloadSettings &
|
||||||
|
|||||||
Reference in New Issue
Block a user