Recently Added Chapter Feedback (#1020)

* Added an alt implementation which shows Recently Added chapters. No extra grouping is performed if multiple chapters per volume.

* Started working on a grouping implementation for series.

* Disabled the code for bookmarks cleanup as there is some critical issue in there.

* Implemented a Series Group activity stream which shows recently updated series and providers a count badge showing how many new chapters/volumes were added in that series.

* Removed the bookmark disabling code

* Cleaned up code

* One more code cleanup
This commit is contained in:
Joseph Milazzo 2022-02-02 07:18:09 -08:00 committed by GitHub
parent 0ce0ee39e0
commit 730624d364
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 261 additions and 153 deletions

View file

@ -9,5 +9,5 @@ export interface RecentlyAddedItem {
libraryType: LibraryType;
volumeId: number;
chapterId: number;
id: number; // This is UI only
id: number; // This is UI only, sent from backend but has no relation to any entity
}

View file

@ -0,0 +1,14 @@
import { LibraryType } from "./library";
export interface SeriesGroup {
seriesId: number;
seriesName: string;
created: string;
title: string;
libraryId: number;
libraryType: LibraryType;
volumeId: number;
chapterId: number;
id: number; // This is UI only, sent from backend but has no relation to any entity
count: number;
}

View file

@ -9,6 +9,7 @@ import { PaginatedResult } from '../_models/pagination';
import { RecentlyAddedItem } from '../_models/recently-added-item';
import { Series } from '../_models/series';
import { SeriesFilter } from '../_models/series-filter';
import { SeriesGroup } from '../_models/series-group';
import { SeriesMetadata } from '../_models/series-metadata';
import { Volume } from '../_models/volume';
import { ImageService } from './image.service';
@ -123,13 +124,11 @@ export class SeriesService {
);
}
getRecentlyUpdatedSeries() {
return this.httpClient.post<SeriesGroup[]>(this.baseUrl + 'series/recently-updated-series', {});
}
getRecentlyAddedChapters() {
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {}).pipe(
map(items => {
items.forEach((item, i) => item.id = i);
return items;
})
);
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {});
}
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
@ -144,9 +143,6 @@ export class SeriesService {
}));
}
// getContinueReading(libraryId: number = 0) {
// return this.httpClient.get<InProgressChapter[]>(this.baseUrl + 'series/continue-reading?libraryId=' + libraryId);
// }
refreshMetadata(series: Series) {
return this.httpClient.post(this.baseUrl + 'series/refresh-metadata', {libraryId: series.libraryId, seriesId: series.id});

View file

@ -22,6 +22,10 @@
<div class="bulk-mode {{bulkSelectionService.hasSelections() ? 'always-show' : ''}}" (click)="handleSelection($event)" *ngIf="allowSelection">
<input type="checkbox" attr.aria-labelledby="{{title}}_{{entity?.id}}" [ngModel]="selected" [ngModelOptions]="{standalone: true}">
</div>
<div class="count" *ngIf="count > 1">
<span class="badge badge-primary">{{count}}</span>
</div>
</div>
<div class="card-body" *ngIf="title.length > 0 || actions.length > 0">

View file

@ -118,6 +118,12 @@ $image-width: 160px;
}
z-index: 10;
.count {
top: 5px;
right: 10px;
position: absolute;
}
}
.card-actions {

View file

@ -68,6 +68,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
* This will supress the cannot read archive warning when total pages is 0
*/
@Input() supressArchiveWarning: boolean = false;
/**
* The number of updates/items within the card. If less than 2, will not be shown.
*/
@Input() count: number = 0;
/**
* Event emitted when item is clicked
*/

View file

@ -11,6 +11,20 @@
</ng-template>
</app-carousel-reel>
<app-carousel-reel [items]="recentlyUpdatedSeries" title="Recently Updated Series">
<ng-template #carouselItem let-item let-position="idx">
<app-card-item [entity]="item" [title]="item.seriesName" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"
[supressArchiveWarning]="true" (clicked)="handleRecentlyAddedChapterClick(item)" [count]="item.count"></app-card-item>
</ng-template>
</app-carousel-reel>
<!-- <app-carousel-reel [items]="recentlyAdded" title="Recently Added Series" (sectionClick)="handleSectionClick($event)">
<ng-template #carouselItem let-item let-position="idx">
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAdded()"></app-series-card>
</ng-template>
</app-carousel-reel> -->
<app-carousel-reel [items]="recentlyAddedChapters" title="Recently Added">
<ng-template #carouselItem let-item let-position="idx">
<app-card-item [entity]="item" [title]="item.title" [subtitle]="item.seriesName" [imageUrl]="imageService.getRecentlyAddedItem(item)"
@ -18,12 +32,6 @@
</ng-template>
</app-carousel-reel>
<app-carousel-reel [items]="recentlyAdded" title="Recently Added Series" (sectionClick)="handleSectionClick($event)">
<ng-template #carouselItem let-item let-position="idx">
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAdded()"></app-series-card>
</ng-template>
</app-carousel-reel>
<app-carousel-reel [items]="libraries" title="Libraries" (sectionClick)="handleSectionClick($event)">
<ng-template #carouselItem let-item let-position="idx">
<app-library-card [data]="item"></app-library-card>

View file

@ -8,6 +8,7 @@ import { SeriesRemovedEvent } from '../_models/events/series-removed-event';
import { Library } from '../_models/library';
import { RecentlyAddedItem } from '../_models/recently-added-item';
import { Series } from '../_models/series';
import { SeriesGroup } from '../_models/series-group';
import { User } from '../_models/user';
import { AccountService } from '../_services/account.service';
import { ImageService } from '../_services/image.service';
@ -28,6 +29,7 @@ export class LibraryComponent implements OnInit, OnDestroy {
isAdmin = false;
recentlyAdded: Series[] = [];
recentlyUpdatedSeries: SeriesGroup[] = [];
recentlyAddedChapters: RecentlyAddedItem[] = [];
inProgress: Series[] = [];
@ -45,10 +47,14 @@ export class LibraryComponent implements OnInit, OnDestroy {
this.seriesService.getSeries(seriesAddedEvent.seriesId).subscribe(series => {
this.recentlyAdded.unshift(series);
});
this.loadRecentlyAddedChapters();
} else if (res.event === EVENTS.SeriesRemoved) {
const seriesRemovedEvent = res.payload as SeriesRemovedEvent;
this.recentlyAdded = this.recentlyAdded.filter(item => item.id != seriesRemovedEvent.seriesId);
this.inProgress = this.inProgress.filter(item => item.id != seriesRemovedEvent.seriesId);
this.recentlyUpdatedSeries = this.recentlyUpdatedSeries.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
this.recentlyAddedChapters = this.recentlyAddedChapters.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
}
});
}
@ -105,6 +111,10 @@ export class LibraryComponent implements OnInit, OnDestroy {
}
loadRecentlyAddedChapters() {
this.seriesService.getRecentlyUpdatedSeries().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
this.recentlyUpdatedSeries = updatedSeries;
});
this.seriesService.getRecentlyAddedChapters().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
this.recentlyAddedChapters = updatedSeries;
});