Recently Added Chapters/Volumes (#1007)

* Working on adding recently added chapter/volumes to dashboard. Have some progress, need to tweak grouping logic.

* Tweaked the logic to work well for grouping. Now to incorporate information for UI to provide seamless integration

* Implemented UI part for Recently Added.
This commit is contained in:
Joseph Milazzo 2022-01-29 08:04:18 -08:00 committed by GitHub
parent 81562b7d41
commit 2d59580aef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 253 additions and 23 deletions

View file

@ -1,13 +0,0 @@
export interface InProgressChapter {
id: number;
range: string;
number: string;
pages: number;
volumeId: number;
pagesRead: number;
seriesId: number;
seriesName: string;
coverImage: string;
libraryId: number;
libraryName: string;
}

View file

@ -0,0 +1,13 @@
import { LibraryType } from "./library";
export interface RecentlyAddedItem {
seriesId: number;
seriesName: string;
created: string;
title: string;
libraryId: number;
libraryType: LibraryType;
volumeId: number;
chapterId: number;
id: number; // This is UI only
}

View file

@ -2,6 +2,7 @@ import { Injectable, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { RecentlyAddedItem } from '../_models/recently-added-item';
import { AccountService } from './account.service';
import { NavService } from './nav.service';
@ -41,6 +42,13 @@ export class ImageService implements OnDestroy {
this.onDestroy.complete();
}
getRecentlyAddedItem(item: RecentlyAddedItem) {
if (item.chapterId === 0) {
return this.getVolumeCoverImage(item.volumeId);
}
return this.getChapterCoverImage(item.chapterId);
}
getVolumeCoverImage(volumeId: number) {
return this.baseUrl + 'image/volume-cover?volumeId=' + volumeId;
}

View file

@ -5,10 +5,10 @@ import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { Chapter } from '../_models/chapter';
import { CollectionTag } from '../_models/collection-tag';
import { InProgressChapter } from '../_models/in-progress-chapter';
import { PaginatedResult } from '../_models/pagination';
import { RecentlyAddedItem } from '../_models/recently-added-item';
import { Series } from '../_models/series';
import { ReadStatus, SeriesFilter } from '../_models/series-filter';
import { SeriesFilter } from '../_models/series-filter';
import { SeriesMetadata } from '../_models/series-metadata';
import { Volume } from '../_models/volume';
import { ImageService } from './image.service';
@ -123,6 +123,15 @@ export class SeriesService {
);
}
getRecentlyAddedChapters() {
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {}).pipe(
map(items => {
items.forEach((item, i) => item.id = i);
return items;
})
);
}
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
const data = this.createSeriesFilter(filter);

View file

@ -38,6 +38,7 @@
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="title"></app-card-actionables>
</span>
</div>
<span class="card-title library" [ngbTooltip]="subtitle" placement="top" *ngIf="subtitle.length > 0">{{subtitle}}</span>
<a class="card-title library" [routerLink]="['/library', libraryId]" routerLinkActive="router-link-active" *ngIf="!supressLibraryLink && libraryName">{{libraryName | sentenceCase}}</a>
</div>
</div>

View file

@ -9,6 +9,7 @@ import { Chapter } from 'src/app/_models/chapter';
import { CollectionTag } from 'src/app/_models/collection-tag';
import { MangaFormat } from 'src/app/_models/manga-format';
import { PageBookmark } from 'src/app/_models/page-bookmark';
import { RecentlyAddedItem } from 'src/app/_models/recently-added-item';
import { Series } from 'src/app/_models/series';
import { Volume } from 'src/app/_models/volume';
import { Action, ActionItem } from 'src/app/_services/action-factory.service';
@ -31,6 +32,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
* Name of the card
*/
@Input() title = '';
/**
* Shows below the title. Defaults to not visible
*/
@Input() subtitle = '';
/**
* Any actions to perform on the card
*/
@ -50,7 +55,7 @@ export class CardItemComponent implements OnInit, OnDestroy {
/**
* This is the entity we are representing. It will be returned if an action is executed.
*/
@Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark;
@Input() entity!: Series | Volume | Chapter | CollectionTag | PageBookmark | RecentlyAddedItem;
/**
* If the entity is selected or not.
*/
@ -59,6 +64,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
* If the entity should show selection code
*/
@Input() allowSelection: boolean = false;
/**
* This will supress the cannot read archive warning when total pages is 0
*/
@Input() supressArchiveWarning: boolean = false;
/**
* Event emitted when item is clicked
*/
@ -72,10 +81,6 @@ export class CardItemComponent implements OnInit, OnDestroy {
*/
libraryName: string | undefined = undefined;
libraryId: number | undefined = undefined;
/**
* This will supress the cannot read archive warning when total pages is 0
*/
supressArchiveWarning: boolean = false;
/**
* Format of the entity (only applies to Series)
*/

View file

@ -11,7 +11,14 @@
</ng-template>
</app-carousel-reel>
<app-carousel-reel [items]="recentlyAdded" title="Recently Added" (sectionClick)="handleSectionClick($event)">
<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)"
[supressArchiveWarning]="true" (clicked)="handleRecentlyAddedChapterClick(item)"></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>

View file

@ -5,8 +5,8 @@ import { Subject } from 'rxjs';
import { take, takeUntil } from 'rxjs/operators';
import { SeriesAddedEvent } from '../_models/events/series-added-event';
import { SeriesRemovedEvent } from '../_models/events/series-removed-event';
import { InProgressChapter } from '../_models/in-progress-chapter';
import { Library } from '../_models/library';
import { RecentlyAddedItem } from '../_models/recently-added-item';
import { Series } from '../_models/series';
import { User } from '../_models/user';
import { AccountService } from '../_services/account.service';
@ -28,8 +28,8 @@ export class LibraryComponent implements OnInit, OnDestroy {
isAdmin = false;
recentlyAdded: Series[] = [];
recentlyAddedChapters: RecentlyAddedItem[] = [];
inProgress: Series[] = [];
continueReading: InProgressChapter[] = [];
private readonly onDestroy = new Subject<void>();
@ -76,6 +76,7 @@ export class LibraryComponent implements OnInit, OnDestroy {
reloadSeries() {
this.loadRecentlyAdded();
this.loadOnDeck();
this.loadRecentlyAddedChapters();
}
reloadInProgress(series: Series | boolean) {
@ -103,6 +104,16 @@ export class LibraryComponent implements OnInit, OnDestroy {
});
}
loadRecentlyAddedChapters() {
this.seriesService.getRecentlyAddedChapters().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
this.recentlyAddedChapters = updatedSeries;
});
}
handleRecentlyAddedChapterClick(item: RecentlyAddedItem) {
this.router.navigate(['library', item.libraryId, 'series', item.seriesId]);
}
handleSectionClick(sectionTitle: string) {
if (sectionTitle.toLowerCase() === 'collections') {
this.router.navigate(['collections']);