Bulk Operations (#596)
* Implemented the ability to perform multi-selections on cards. Basic selection code is done, CSS needed and exposing actions. * Implemented a bulk selection bar. Added logic to the card on when to force show checkboxes. * Fixed some bad parsing groups and cases for Comic Chapters. * Hooked up some bulk actions on series detail page. Not hooked up to backend yet. * Fixes #593. URI Enocde library names as sometimes they can have & in them. * Implemented the ability to mark volume/chapters as read/unread. * Hooked up mark as unread with specials as well. * Add to reading list hooked up for Series Detail * Implemented ability to add multiple series to a reading list. * Implemented bulk selection for series cards * Added comments to the new code in ReaderService.cs * Implemented proper styling on bulk operation bar and integrated for collections. * Fixed an issue with shift clicking * Cleaned up css of bulk operations bar * Code cleanup
This commit is contained in:
parent
52c4285168
commit
f5229fd0e6
38 changed files with 1129 additions and 172 deletions
|
|
@ -20,6 +20,7 @@ export type SeriesActionCallback = (series: Series) => void;
|
|||
export type VolumeActionCallback = (volume: Volume) => void;
|
||||
export type ChapterActionCallback = (chapter: Chapter) => void;
|
||||
export type ReadingListActionCallback = (readingList: ReadingList) => void;
|
||||
export type VoidActionCallback = () => void;
|
||||
|
||||
/**
|
||||
* Responsible for executing actions
|
||||
|
|
@ -203,6 +204,85 @@ export class ActionService implements OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all chapters and the volumes as Read. All volumes and chapters must belong to a series
|
||||
* @param seriesId Series Id
|
||||
* @param volumes Volumes, should have id, chapters and pagesRead populated
|
||||
* @param chapters? Chapters, should have id
|
||||
* @param callback Optional callback to perform actions after API completes
|
||||
*/
|
||||
markMultipleAsRead(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: VoidActionCallback) {
|
||||
this.readerService.markMultipleRead(seriesId, volumes.map(v => v.id), chapters?.map(c => c.id)).pipe(take(1)).subscribe(() => {
|
||||
volumes.forEach(volume => {
|
||||
volume.pagesRead = volume.pages;
|
||||
volume.chapters?.forEach(c => c.pagesRead = c.pages);
|
||||
});
|
||||
chapters?.forEach(c => c.pagesRead = c.pages);
|
||||
this.toastr.success('Marked as Read');
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all chapters and the volumes as Unread. All volumes must belong to a series
|
||||
* @param seriesId Series Id
|
||||
* @param volumes Volumes, should have id, chapters and pagesRead populated
|
||||
* @param callback Optional callback to perform actions after API completes
|
||||
*/
|
||||
markMultipleAsUnread(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: VoidActionCallback) {
|
||||
this.readerService.markMultipleUnread(seriesId, volumes.map(v => v.id), chapters?.map(c => c.id)).pipe(take(1)).subscribe(() => {
|
||||
volumes.forEach(volume => {
|
||||
volume.pagesRead = volume.pages;
|
||||
volume.chapters?.forEach(c => c.pagesRead = c.pages);
|
||||
});
|
||||
chapters?.forEach(c => c.pagesRead = c.pages);
|
||||
this.toastr.success('Marked as Read');
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all series as Read.
|
||||
* @param series Series, should have id, pagesRead populated
|
||||
* @param callback Optional callback to perform actions after API completes
|
||||
*/
|
||||
markMultipleSeriesAsRead(series: Array<Series>, callback?: VoidActionCallback) {
|
||||
this.readerService.markMultipleSeriesRead(series.map(v => v.id)).pipe(take(1)).subscribe(() => {
|
||||
series.forEach(s => {
|
||||
s.pagesRead = s.pages;
|
||||
});
|
||||
this.toastr.success('Marked as Read');
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all series as Unread.
|
||||
* @param series Series, should have id, pagesRead populated
|
||||
* @param callback Optional callback to perform actions after API completes
|
||||
*/
|
||||
markMultipleSeriesAsUnread(series: Array<Series>, callback?: VoidActionCallback) {
|
||||
this.readerService.markMultipleSeriesUnread(series.map(v => v.id)).pipe(take(1)).subscribe(() => {
|
||||
series.forEach(s => {
|
||||
s.pagesRead = s.pages;
|
||||
});
|
||||
this.toastr.success('Marked as Unread');
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
openBookmarkModal(series: Series, callback?: SeriesActionCallback) {
|
||||
if (this.bookmarkModalRef != null) { return; }
|
||||
|
|
@ -222,6 +302,52 @@ export class ActionService implements OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
addMultipleToReadingList(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: VoidActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesId = seriesId;
|
||||
this.readingListModalRef.componentInstance.volumeIds = volumes.map(v => v.id);
|
||||
this.readingListModalRef.componentInstance.chapterIds = chapters?.map(c => c.id);
|
||||
this.readingListModalRef.componentInstance.title = 'Multiple Selections';
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Multiple;
|
||||
|
||||
|
||||
this.readingListModalRef.closed.pipe(take(1)).subscribe(() => {
|
||||
this.readingListModalRef = null;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => {
|
||||
this.readingListModalRef = null;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addMultipleSeriesToReadingList(series: Array<Series>, callback?: VoidActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesIds = series.map(v => v.id);
|
||||
this.readingListModalRef.componentInstance.title = 'Multiple Selections';
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Multiple_Series;
|
||||
|
||||
|
||||
this.readingListModalRef.closed.pipe(take(1)).subscribe(() => {
|
||||
this.readingListModalRef = null;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => {
|
||||
this.readingListModalRef = null;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addSeriesToReadingList(series: Series, callback?: SeriesActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export class LibraryService {
|
|||
listDirectories(rootPath: string) {
|
||||
let query = '';
|
||||
if (rootPath !== undefined && rootPath.length > 0) {
|
||||
query = '?path=' + rootPath;
|
||||
query = '?path=' + encodeURIComponent(rootPath);
|
||||
}
|
||||
|
||||
return this.httpClient.get<string[]>(this.baseUrl + 'library/list' + query);
|
||||
|
|
|
|||
|
|
@ -68,9 +68,26 @@ export class ReaderService {
|
|||
return this.httpClient.post(this.baseUrl + 'reader/mark-volume-read', {seriesId, volumeId});
|
||||
}
|
||||
|
||||
markMultipleRead(seriesId: number, volumeIds: Array<number>, chapterIds?: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-read', {seriesId, volumeIds, chapterIds});
|
||||
}
|
||||
|
||||
markMultipleUnread(seriesId: number, volumeIds: Array<number>, chapterIds?: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-unread', {seriesId, volumeIds, chapterIds});
|
||||
}
|
||||
|
||||
markMultipleSeriesRead(seriesIds: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-series-read', {seriesIds});
|
||||
}
|
||||
|
||||
markMultipleSeriesUnread(seriesIds: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'reader/mark-multiple-series-unread', {seriesIds});
|
||||
}
|
||||
|
||||
markVolumeUnread(seriesId: number, volumeId: number) {
|
||||
return this.httpClient.post(this.baseUrl + 'reader/mark-volume-unread', {seriesId, volumeId});
|
||||
}
|
||||
|
||||
|
||||
getNextChapter(seriesId: number, volumeId: number, currentChapterId: number, readingListId: number = -1) {
|
||||
if (readingListId > 0) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,14 @@ export class ReadingListService {
|
|||
return this.httpClient.post(this.baseUrl + 'readinglist/update', model, { responseType: 'text' as 'json' });
|
||||
}
|
||||
|
||||
updateByMultiple(readingListId: number, seriesId: number, volumeIds: Array<number>, chapterIds?: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'readinglist/update-by-multiple', {readingListId, seriesId, volumeIds, chapterIds});
|
||||
}
|
||||
|
||||
updateByMultipleSeries(readingListId: number, seriesIds: Array<number>) {
|
||||
return this.httpClient.post(this.baseUrl + 'readinglist/update-by-multiple-series', {readingListId, seriesIds});
|
||||
}
|
||||
|
||||
updateBySeries(readingListId: number, seriesId: number) {
|
||||
return this.httpClient.post(this.baseUrl + 'readinglist/update-by-series', {readingListId, seriesId}, { responseType: 'text' as 'json' });
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue