Library Recomendations (#1236)
* Updated cover regex for finding cover images in archives to ignore back_cover or back-cover * Fixed an issue where Tags wouldn't save due to not pulling them from the DB. * Refactored All series to it's own lazy loaded module * Modularized Dashboard and library detail. Had to change main dashboard page to be libraries. Subject to change. * Refactored login component into registration module * Series Detail module created * Refactored nav stuff into it's own module, not lazy loaded, but self contained. * Refactored theme component into a dev only module so we don't incur load for temp testing modules * Finished off modularization code. Only missing thing is to re-introduce some dashboard functionality for library view. * Implemented a basic recommendation page for library detail
This commit is contained in:
parent
743a3ba935
commit
f237aa7ab7
77 changed files with 1077 additions and 501 deletions
|
|
@ -1,20 +1,180 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplaySubject, Subject } from 'rxjs';
|
||||
import { debounceTime, take, takeUntil } from 'rxjs/operators';
|
||||
import { FilterQueryParam } from '../shared/_services/filter-utilities.service';
|
||||
import { SeriesAddedEvent } from '../_models/events/series-added-event';
|
||||
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 { SortField } from '../_models/series-filter';
|
||||
import { SeriesGroup } from '../_models/series-group';
|
||||
import { User } from '../_models/user';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
import { ImageService } from '../_services/image.service';
|
||||
import { LibraryService } from '../_services/library.service';
|
||||
import { MessageHubService, EVENTS } from '../_services/message-hub.service';
|
||||
import { SeriesService } from '../_services/series.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.scss']
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* By default, 0, but if non-zero, will limit all API calls to library id
|
||||
*/
|
||||
@Input() libraryId: number = 0;
|
||||
|
||||
constructor(public route: ActivatedRoute, private titleService: Title) {
|
||||
this.titleService.setTitle('Kavita - Dashboard');
|
||||
user: User | undefined;
|
||||
libraries: Library[] = [];
|
||||
isLoading = false;
|
||||
isAdmin = false;
|
||||
|
||||
recentlyUpdatedSeries: SeriesGroup[] = [];
|
||||
inProgress: Series[] = [];
|
||||
recentlyAddedSeries: Series[] = [];
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
/**
|
||||
* We use this Replay subject to slow the amount of times we reload the UI
|
||||
*/
|
||||
private loadRecentlyAdded$: ReplaySubject<void> = new ReplaySubject<void>();
|
||||
|
||||
constructor(public accountService: AccountService, private libraryService: LibraryService,
|
||||
private seriesService: SeriesService, private router: Router,
|
||||
private titleService: Title, public imageService: ImageService,
|
||||
private messageHub: MessageHubService) {
|
||||
this.messageHub.messages$.pipe(takeUntil(this.onDestroy)).subscribe(res => {
|
||||
if (res.event === EVENTS.SeriesAdded) {
|
||||
const seriesAddedEvent = res.payload as SeriesAddedEvent;
|
||||
|
||||
this.seriesService.getSeries(seriesAddedEvent.seriesId).subscribe(series => {
|
||||
this.recentlyAddedSeries.unshift(series);
|
||||
});
|
||||
} else if (res.event === EVENTS.SeriesRemoved) {
|
||||
const seriesRemovedEvent = res.payload as SeriesRemovedEvent;
|
||||
|
||||
this.inProgress = this.inProgress.filter(item => item.id != seriesRemovedEvent.seriesId);
|
||||
this.recentlyAddedSeries = this.recentlyAddedSeries.filter(item => item.id != seriesRemovedEvent.seriesId);
|
||||
this.recentlyUpdatedSeries = this.recentlyUpdatedSeries.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
|
||||
} else if (res.event === EVENTS.ScanSeries) {
|
||||
// We don't have events for when series are updated, but we do get events when a scan update occurs. Refresh recentlyAdded at that time.
|
||||
this.loadRecentlyAdded$.next();
|
||||
}
|
||||
});
|
||||
|
||||
this.loadRecentlyAdded$.pipe(debounceTime(1000), takeUntil(this.onDestroy)).subscribe(() => this.loadRecentlyAdded());
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.titleService.setTitle('Kavita - Dashboard');
|
||||
this.isLoading = true;
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
this.user = user;
|
||||
if (this.user) {
|
||||
this.isAdmin = this.accountService.hasAdminRole(this.user);
|
||||
this.libraryService.getLibrariesForMember().pipe(take(1)).subscribe(libraries => {
|
||||
this.libraries = libraries;
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.reloadSeries();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
reloadSeries() {
|
||||
this.loadOnDeck();
|
||||
this.loadRecentlyAdded();
|
||||
this.loadRecentlyAddedSeries();
|
||||
}
|
||||
|
||||
reloadInProgress(series: Series | boolean) {
|
||||
if (series === true || series === false) {
|
||||
if (!series) {return;}
|
||||
}
|
||||
// If the update to Series doesn't affect the requirement to be in this stream, then ignore update request
|
||||
const seriesObj = (series as Series);
|
||||
if (seriesObj.pagesRead !== seriesObj.pages && seriesObj.pagesRead !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadOnDeck();
|
||||
}
|
||||
|
||||
loadOnDeck() {
|
||||
let api = this.seriesService.getOnDeck();
|
||||
if (this.libraryId > 0) {
|
||||
api = this.seriesService.getOnDeck(this.libraryId);
|
||||
}
|
||||
api.pipe(takeUntil(this.onDestroy)).subscribe((updatedSeries) => {
|
||||
this.inProgress = updatedSeries.result;
|
||||
});
|
||||
}
|
||||
|
||||
loadRecentlyAddedSeries() {
|
||||
let api = this.seriesService.getRecentlyAdded();
|
||||
if (this.libraryId > 0) {
|
||||
api = this.seriesService.getRecentlyAdded(this.libraryId);
|
||||
}
|
||||
api.pipe(takeUntil(this.onDestroy)).subscribe((updatedSeries) => {
|
||||
this.recentlyAddedSeries = updatedSeries.result;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
loadRecentlyAdded() {
|
||||
let api = this.seriesService.getRecentlyUpdatedSeries();
|
||||
if (this.libraryId > 0) {
|
||||
api = this.seriesService.getRecentlyUpdatedSeries();
|
||||
}
|
||||
api.pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
|
||||
this.recentlyUpdatedSeries = updatedSeries.filter(group => {
|
||||
if (this.libraryId === 0) return true;
|
||||
return group.libraryId === this.libraryId;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleRecentlyAddedChapterClick(item: RecentlyAddedItem) {
|
||||
this.router.navigate(['library', item.libraryId, 'series', item.seriesId]);
|
||||
}
|
||||
|
||||
handleSectionClick(sectionTitle: string) {
|
||||
if (sectionTitle.toLowerCase() === 'recently updated series') {
|
||||
const params: any = {};
|
||||
params[FilterQueryParam.SortBy] = SortField.LastChapterAdded + ',false'; // sort by last chapter added, desc
|
||||
params[FilterQueryParam.Page] = 1;
|
||||
this.router.navigate(['all-series'], {queryParams: params});
|
||||
} else if (sectionTitle.toLowerCase() === 'on deck') {
|
||||
const params: any = {};
|
||||
params[FilterQueryParam.ReadStatus] = 'true,false,false';
|
||||
params[FilterQueryParam.SortBy] = SortField.LastChapterAdded + ',false'; // sort by last chapter added, desc
|
||||
params[FilterQueryParam.Page] = 1;
|
||||
this.router.navigate(['all-series'], {queryParams: params});
|
||||
}else if (sectionTitle.toLowerCase() === 'newly added series') {
|
||||
const params: any = {};
|
||||
params[FilterQueryParam.SortBy] = SortField.Created + ',false'; // sort by created, desc
|
||||
params[FilterQueryParam.Page] = 1;
|
||||
this.router.navigate(['all-series'], {queryParams: params});
|
||||
}
|
||||
}
|
||||
|
||||
removeFromArray(arr: Array<any>, element: any) {
|
||||
const index = arr.indexOf(element);
|
||||
if (index >= 0) {
|
||||
arr.splice(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue