Want to Read List (#1392)

* Implemented a Want To Read list of series for all users, as a way to keep track of what you want to read.

When canceling a bulk action, like Add to Reading list, the selected cards wont de-select.

* Hooked up Remove from Want to Read

* When making bulk selection, allow the user to click on anywhere on the card

* Added no series messaging

* Code cleanup
This commit is contained in:
Joseph Milazzo 2022-07-28 17:18:35 -05:00 committed by GitHub
parent 495c986000
commit f130440bd0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 2209 additions and 48 deletions

View file

@ -69,6 +69,14 @@ export enum Action {
* Open the reader for entity
*/
Read = 14,
/**
* Add to user's Want to Read List
*/
AddToWantToReadList = 15,
/**
* Remove from user's Want to Read List
*/
RemoveFromWantToReadList = 16,
}
export interface ActionItem<T> {
@ -276,6 +284,12 @@ export class ActionFactoryService {
title: 'Add to Reading List',
callback: this.dummyCallback,
requiresAdmin: false
},
{
action: Action.AddToWantToReadList,
title: 'Add to Want To Read',
callback: this.dummyCallback,
requiresAdmin: false
}
];

View file

@ -13,6 +13,7 @@ import { ReadingList } from '../_models/reading-list';
import { Series } from '../_models/series';
import { Volume } from '../_models/volume';
import { LibraryService } from './library.service';
import { MemberService } from './member.service';
import { ReaderService } from './reader.service';
import { SeriesService } from './series.service';
@ -33,13 +34,12 @@ export type BooleanActionCallback = (result: boolean) => void;
export class ActionService implements OnDestroy {
private readonly onDestroy = new Subject<void>();
private bookmarkModalRef: NgbModalRef | null = null;
private readingListModalRef: NgbModalRef | null = null;
private collectionModalRef: NgbModalRef | null = null;
constructor(private libraryService: LibraryService, private seriesService: SeriesService,
private readerService: ReaderService, private toastr: ToastrService, private modalService: NgbModal,
private confirmService: ConfirmService) { }
private confirmService: ConfirmService, private memberService: MemberService) { }
ngOnDestroy() {
this.onDestroy.next();
@ -342,7 +342,7 @@ export class ActionService implements OnDestroy {
});
}
addMultipleToReadingList(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: VoidActionCallback) {
addMultipleToReadingList(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: BooleanActionCallback) {
if (this.readingListModalRef != null) { return; }
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
this.readingListModalRef.componentInstance.seriesId = seriesId;
@ -355,18 +355,36 @@ export class ActionService implements OnDestroy {
this.readingListModalRef.closed.pipe(take(1)).subscribe(() => {
this.readingListModalRef = null;
if (callback) {
callback();
callback(true);
}
});
this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => {
this.readingListModalRef = null;
if (callback) {
callback();
callback(false);
}
});
}
addMultipleSeriesToReadingList(series: Array<Series>, callback?: VoidActionCallback) {
addMultipleSeriesToWantToReadList(seriesIds: Array<number>, callback?: VoidActionCallback) {
this.memberService.addSeriesToWantToRead(seriesIds).subscribe(() => {
this.toastr.success('Series added to Want to Read list');
if (callback) {
callback();
}
});
}
removeMultipleSeriesFromWantToReadList(seriesIds: Array<number>, callback?: VoidActionCallback) {
this.memberService.removeSeriesToWantToRead(seriesIds).subscribe(() => {
this.toastr.success('Series removed from Want to Read list');
if (callback) {
callback();
}
});
}
addMultipleSeriesToReadingList(series: Array<Series>, callback?: BooleanActionCallback) {
if (this.readingListModalRef != null) { return; }
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
this.readingListModalRef.componentInstance.seriesIds = series.map(v => v.id);
@ -377,13 +395,13 @@ export class ActionService implements OnDestroy {
this.readingListModalRef.closed.pipe(take(1)).subscribe(() => {
this.readingListModalRef = null;
if (callback) {
callback();
callback(true);
}
});
this.readingListModalRef.dismissed.pipe(take(1)).subscribe(() => {
this.readingListModalRef = null;
if (callback) {
callback();
callback(false);
}
});
}
@ -394,7 +412,7 @@ export class ActionService implements OnDestroy {
* @param callback
* @returns
*/
addMultipleSeriesToCollectionTag(series: Array<Series>, callback?: VoidActionCallback) {
addMultipleSeriesToCollectionTag(series: Array<Series>, callback?: BooleanActionCallback) {
if (this.collectionModalRef != null) { return; }
this.collectionModalRef = this.modalService.open(BulkAddToCollectionComponent, { scrollable: true, size: 'md', windowClass: 'collection' });
this.collectionModalRef.componentInstance.seriesIds = series.map(v => v.id);
@ -403,13 +421,13 @@ export class ActionService implements OnDestroy {
this.collectionModalRef.closed.pipe(take(1)).subscribe(() => {
this.collectionModalRef = null;
if (callback) {
callback();
callback(true);
}
});
this.collectionModalRef.dismissed.pipe(take(1)).subscribe(() => {
this.collectionModalRef = null;
if (callback) {
callback();
callback(false);
}
});
}

View file

@ -36,8 +36,16 @@ export class MemberService {
return this.httpClient.get<boolean>(this.baseUrl + 'users/has-reading-progress?libraryId=' + librayId);
}
getPendingInvites() {
return this.httpClient.get<Array<Member>>(this.baseUrl + 'users/pending');
}
addSeriesToWantToRead(seriesIds: Array<number>) {
return this.httpClient.post<Array<Member>>(this.baseUrl + 'want-to-read/add-series', {seriesIds});
}
removeSeriesToWantToRead(seriesIds: Array<number>) {
return this.httpClient.post<Array<Member>>(this.baseUrl + 'want-to-read/remove-series', {seriesIds});
}
}

View file

@ -1,6 +1,6 @@
import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { UtilityService } from '../shared/_services/utility.service';
@ -124,6 +124,18 @@ export class SeriesService {
return this.httpClient.post<SeriesGroup[]>(this.baseUrl + 'series/recently-updated-series', {});
}
getWantToRead(pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter): Observable<PaginatedResult<Series[]>> {
const data = this.createSeriesFilter(filter);
let params = new HttpParams();
params = this.utilityService.addPaginationIfExists(params, pageNum, itemsPerPage);
return this.httpClient.post<Series[]>(this.baseUrl + 'want-to-read/', data, {observe: 'response', params}).pipe(
map(response => {
return this.utilityService.createPaginatedResult(response, new PaginatedResult<Series[]>());
}));
}
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
const data = this.createSeriesFilter(filter);

View file

@ -41,13 +41,23 @@ export class AllSeriesComponent implements OnInit, OnDestroy {
switch (action) {
case Action.AddToReadingList:
this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => {
this.actionService.addMultipleSeriesToReadingList(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
});
break;
case Action.AddToWantToReadList:
this.actionService.addMultipleSeriesToWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
});
break;
case Action.RemoveFromWantToReadList:
this.actionService.removeMultipleSeriesFromWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
});
break;
case Action.AddToCollection:
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => {
this.bulkSelectionService.deselectAll();
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
});
break;
case Action.MarkAsRead:

View file

@ -45,6 +45,10 @@ const routes: Routes = [
path: 'libraries',
loadChildren: () => import('../app/dashboard/dashboard.module').then(m => m.DashboardModule)
},
{
path: 'want-to-read',
loadChildren: () => import('../app/want-to-read/want-to-read.module').then(m => m.WantToReadModule)
},
{
path: 'library',
runGuardsAndResolvers: 'always',

View file

@ -2,7 +2,7 @@
<h2 title>
Bookmarks
</h2>
<h6 subtitle>{{series?.length}} Series</h6>
<h6 subtitle>{{series.length}} Series</h6>
</app-side-nav-companion-bar>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<app-card-detail-layout

View file

@ -141,7 +141,7 @@ export class BulkSelectionService {
getActions(callback: (action: Action, data: any) => void) {
// checks if series is present. If so, returns only series actions
// else returns volume/chapter items
const allowedActions = [Action.AddToReadingList, Action.MarkAsRead, Action.MarkAsUnread, Action.AddToCollection, Action.Delete];
const allowedActions = [Action.AddToReadingList, Action.MarkAsRead, Action.MarkAsUnread, Action.AddToCollection, Action.Delete, Action.AddToWantToReadList, Action.RemoveFromWantToReadList];
if (Object.keys(this.selectedCards).filter(item => item === 'series').length > 0) {
return this.actionFactory.getSeriesActions(callback).filter(item => allowedActions.includes(item.action));
}

View file

@ -16,6 +16,9 @@
<div class="viewport-container">
<div class="content-container">
<div class="card-container mt-2 mb-2">
<p *ngIf="items.length === 0 && !isLoading">
<ng-container [ngTemplateOutlet]="noDataTemplate"></ng-container>
</p>
<virtual-scroller #scroll [items]="items" [bufferAmount]="1" [parentScroll]="parentScroll">
<div class="grid row g-0" #container>
<div class="card col-auto mt-2 mb-2" *ngFor="let item of scroll.viewPortItems; trackBy:trackByIdentity; index as i" id="jumpbar-index--{{i}}" [attr.jumpbar-index]="i">
@ -23,10 +26,6 @@
</div>
</div>
</virtual-scroller>
<p *ngIf="items.length === 0 && !isLoading">
<ng-container [ngTemplateOutlet]="noDataTemplate"></ng-container>
</p>
</div>
</div>
@ -42,7 +41,9 @@
</virtual-scroller>
<div class="mx-auto" *ngIf="items.length === 0 && !isLoading" style="width: 200px;">
<p><ng-container [ngTemplateOutlet]="noDataTemplate"></ng-container></p>
<p>
<ng-container [ngTemplateOutlet]="noDataTemplate"></ng-container>
</p>
</div>
</ng-template>

View file

@ -117,6 +117,7 @@ export class CardDetailLayoutComponent implements OnInit, OnDestroy, OnChanges,
// }
// this.hasResumedJumpKey = true;
// });
console.log(this.noDataTemplate);
}
ngOnChanges(): void {

View file

@ -19,7 +19,7 @@
<div class="not-read-badge" *ngIf="read === 0 && total > 0"></div>
<div class="bulk-mode {{bulkSelectionService.hasSelections() ? 'always-show' : ''}}" (click)="handleSelection($event)" *ngIf="allowSelection">
<input type="checkbox" class="form-check-input" attr.aria-labelledby="{{title}}_{{entity?.id}}" [ngModel]="selected" [ngModelOptions]="{standalone: true}">
<input type="checkbox" class="form-check-input" attr.aria-labelledby="{{title}}_{{entity.id}}" [ngModel]="selected" [ngModelOptions]="{standalone: true}">
</div>
<div class="count" *ngIf="count > 1">
@ -35,7 +35,7 @@
<div class="card-body" *ngIf="title.length > 0 || actions.length > 0">
<div>
<span class="card-title" placement="top" id="{{title}}_{{entity?.id}}" [ngbTooltip]="tooltipTitle" (click)="handleClick($event)" tabindex="0">
<span class="card-title" placement="top" id="{{title}}_{{entity.id}}" [ngbTooltip]="tooltipTitle" (click)="handleClick($event)" tabindex="0">
<span *ngIf="isPromoted()">
<i class="fa fa-angle-double-up" aria-hidden="true"></i>
<span class="visually-hidden">(promoted)</span>

View file

@ -258,6 +258,10 @@ export class CardItemComponent implements OnInit, OnDestroy {
handleClick(event?: any) {
if (this.bulkSelectionService.hasSelections()) {
this.handleSelection();
return;
}
this.clicked.emit(this.title);
}

View file

@ -97,6 +97,9 @@ export class SeriesCardComponent implements OnInit, OnChanges, OnDestroy {
case(Action.AddToReadingList):
this.actionService.addSeriesToReadingList(series);
break;
case Action.AddToWantToReadList:
this.actionService.addMultipleSeriesToWantToReadList([series.id]);
break;
case(Action.AddToCollection):
this.actionService.addMultipleSeriesToCollectionTag([series]);
break;

View file

@ -37,10 +37,4 @@
></app-series-card>
</ng-template>
</app-card-detail-layout>
<div class="mx-auto" *ngIf="isLoading" style="width: 200px;">
<div class="spinner-border text-secondary loading" role="status">
<span class="invisible">Loading...</span>
</div>
</div>
</div>

View file

@ -63,14 +63,26 @@ export class CollectionDetailComponent implements OnInit, OnDestroy, AfterConten
switch (action) {
case Action.AddToReadingList:
this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => {
this.actionService.addMultipleSeriesToReadingList(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.AddToWantToReadList:
this.actionService.addMultipleSeriesToWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.RemoveFromWantToReadList:
this.actionService.removeMultipleSeriesFromWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.AddToCollection:
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => {
this.bulkSelectionService.deselectAll();
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;

View file

@ -3,7 +3,7 @@
<app-card-actionables [actions]="actions" (actionHandler)="performAction($event)"></app-card-actionables>
{{libraryName}}
</h2>
<h6 subtitle class="subtitle-with-actionables" *ngIf="active.fragment === ''">{{pagination?.totalItems}} Series</h6>
<h6 subtitle class="subtitle-with-actionables" *ngIf="active.fragment === ''">{{pagination.totalItems}} Series</h6>
<div main>
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-pills" style="flex-wrap: nowrap;">
<li *ngFor="let tab of tabs" [ngbNavItem]="tab">

View file

@ -57,14 +57,26 @@ export class LibraryDetailComponent implements OnInit, OnDestroy {
switch (action) {
case Action.AddToReadingList:
this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => {
this.actionService.addMultipleSeriesToReadingList(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.AddToWantToReadList:
this.actionService.addMultipleSeriesToWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.RemoveFromWantToReadList:
this.actionService.removeMultipleSeriesFromWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
case Action.AddToCollection:
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => {
this.bulkSelectionService.deselectAll();
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, (success) => {
if (success) this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;

View file

@ -180,9 +180,9 @@ export class SeriesDetailComponent implements OnInit, OnDestroy, AfterContentChe
switch (action) {
case Action.AddToReadingList:
this.actionService.addMultipleToReadingList(seriesId, selectedVolumeIds, chapters, () => {
this.actionService.addMultipleToReadingList(seriesId, selectedVolumeIds, chapters, (success) => {
this.actionInProgress = false;
this.bulkSelectionService.deselectAll();
if (success) this.bulkSelectionService.deselectAll();
this.changeDetectionRef.markForCheck();
});
break;
@ -379,6 +379,12 @@ export class SeriesDetailComponent implements OnInit, OnDestroy, AfterContentChe
this.changeDetectionRef.markForCheck();
});
break;
case Action.AddToWantToReadList:
this.actionService.addMultipleSeriesToWantToReadList([series.id], () => {
this.actionInProgress = false;
this.changeDetectionRef.markForCheck();
});
break;
case (Action.Download):
if (this.downloadInProgress) return;
this.downloadSeries();

View file

@ -1,5 +1,5 @@
<ng-container>
<div class="side-nav" [ngClass]="{'closed' : (navService?.sideNavCollapsed$ | async), 'hidden' :!(navService?.sideNavVisibility$ | async)}" *ngIf="accountService.currentUser$ | async as user">
<div class="side-nav" [ngClass]="{'closed' : (navService.sideNavCollapsed$ | async), 'hidden' :!(navService.sideNavVisibility$ | async)}" *ngIf="accountService.currentUser$ | async as user">
<!-- <app-side-nav-item icon="fa-user-circle align-self-center phone-hidden" [title]="user.username | sentenceCase" link="/preferences/">
<ng-container actions>
Todo: This will be customize dashboard/side nav controls
@ -8,6 +8,7 @@
</app-side-nav-item> -->
<app-side-nav-item icon="fa-home" title="Home" link="/libraries/"></app-side-nav-item>
<app-side-nav-item icon="fa-star" title="Want To Read" link="/want-to-read/"></app-side-nav-item>
<app-side-nav-item icon="fa-list" title="Collections" link="/collections/"></app-side-nav-item>
<app-side-nav-item icon="fa-list-ol" title="Reading Lists" link="/lists/"></app-side-nav-item>
<app-side-nav-item icon="fa-bookmark" title="Bookmarks" link="/bookmarks/"></app-side-nav-item>
@ -26,5 +27,5 @@
</ng-container>
</app-side-nav-item>
</div>
<div class="side-nav-overlay" (click)="toggleNavBar()" [ngClass]="{'closed' : (navService?.sideNavCollapsed$ | async)}"></div>
<div class="side-nav-overlay" (click)="toggleNavBar()" [ngClass]="{'closed' : (navService.sideNavCollapsed$ | async)}"></div>
</ng-container>

View file

@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '../_guards/auth.guard';
import { WantToReadComponent } from './want-to-read/want-to-read.component';
const routes: Routes = [
{path: '**', component: WantToReadComponent, pathMatch: 'full'},
{
runGuardsAndResolvers: 'always',
canActivate: [AuthGuard],
children: [
{path: '', component: WantToReadComponent, pathMatch: 'full'},
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes), ],
exports: [RouterModule]
})
export class WantToReadRoutingModule { }

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { WantToReadComponent } from './want-to-read/want-to-read.component';
import { CardsModule } from '../cards/cards.module';
import { SidenavModule } from '../sidenav/sidenav.module';
import { WantToReadRoutingModule } from './want-to-read-routing.module';
@NgModule({
declarations: [
WantToReadComponent
],
imports: [
CommonModule,
CardsModule,
SidenavModule,
WantToReadRoutingModule
]
})
export class WantToReadModule { }

View file

@ -0,0 +1,33 @@
<div #companionBar>
<app-side-nav-companion-bar [hasFilter]="true" (filterOpen)="filterOpen.emit($event)" [filterActive]="filterActive">
<ng-container title>
<h2>
Want To Read
</h2>
</ng-container>
</app-side-nav-companion-bar>
</div>
<div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid pt-2" #scrollingBlock>
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<app-card-detail-layout
[isLoading]="isLoading"
[items]="series"
[pagination]="seriesPagination"
[filterSettings]="filterSettings"
[filterOpen]="filterOpen"
[parentScroll]="scrollingBlock"
[jumpBarKeys]="jumpbarKeys"
(applyFilter)="updateFilter($event)">
<ng-template #cardItem let-item let-position="idx">
<app-series-card [data]="item" [libraryId]="item.libraryId" (reload)="loadPage()"
(selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true"
></app-series-card>
</ng-template>
<ng-template #noData>
No Series match your filter or exist in your list.
</ng-template>
</app-card-detail-layout>
</div>

View file

@ -0,0 +1,146 @@
import { DOCUMENT } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject, take, pipe, debounceTime, takeUntil } from 'rxjs';
import { BulkSelectionService } from 'src/app/cards/bulk-selection.service';
import { FilterSettings } from 'src/app/metadata-filter/filter-settings';
import { FilterUtilitiesService } from 'src/app/shared/_services/filter-utilities.service';
import { UtilityService, KEY_CODES } from 'src/app/shared/_services/utility.service';
import { JumpKey } from 'src/app/_models/jumpbar/jump-key';
import { Pagination } from 'src/app/_models/pagination';
import { Series } from 'src/app/_models/series';
import { SeriesFilter, FilterEvent } from 'src/app/_models/series-filter';
import { Action } from 'src/app/_services/action-factory.service';
import { ActionService } from 'src/app/_services/action.service';
import { ImageService } from 'src/app/_services/image.service';
import { MessageHubService, EVENTS } from 'src/app/_services/message-hub.service';
import { ScrollService } from 'src/app/_services/scroll.service';
import { SeriesService } from 'src/app/_services/series.service';
@Component({
selector: 'app-want-to-read',
templateUrl: './want-to-read.component.html',
styleUrls: ['./want-to-read.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class WantToReadComponent implements OnInit, OnDestroy {
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
isLoading: boolean = true;
series: Array<Series> = [];
seriesPagination!: Pagination;
filter: SeriesFilter | undefined = undefined;
filterSettings: FilterSettings = new FilterSettings();
filterActiveCheck!: SeriesFilter;
filterActive: boolean = false;
jumpbarKeys: Array<JumpKey> = [];
filterOpen: EventEmitter<boolean> = new EventEmitter();
private onDestory: Subject<void> = new Subject<void>();
bulkActionCallback = (action: Action, data: any) => {
const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series');
const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + ''));
switch (action) {
case Action.RemoveFromWantToReadList:
this.actionService.removeMultipleSeriesFromWantToReadList(selectedSeries.map(s => s.id), () => {
this.bulkSelectionService.deselectAll();
this.cdRef.markForCheck();
});
break;
}
}
collectionTag: any;
tagImage: any;
get ScrollingBlockHeight() {
if (this.scrollingBlock === undefined) return 'calc(var(--vh)*100)';
const navbar = this.document.querySelector('.navbar') as HTMLElement;
if (navbar === null) return 'calc(var(--vh)*100)';
const companionHeight = this.companionBar!.nativeElement.offsetHeight;
const navbarHeight = navbar.offsetHeight;
const totalHeight = companionHeight + navbarHeight + 21; //21px to account for padding
return 'calc(var(--vh)*100 - ' + totalHeight + 'px)';
}
constructor(public imageService: ImageService, private router: Router, private route: ActivatedRoute,
private seriesService: SeriesService, private titleService: Title,
public bulkSelectionService: BulkSelectionService, private actionService: ActionService, private messageHub: MessageHubService,
private filterUtilityService: FilterUtilitiesService, private utilityService: UtilityService, @Inject(DOCUMENT) private document: Document,
private readonly cdRef: ChangeDetectorRef, private scrollService: ScrollService) {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.titleService.setTitle('Want To Read');
this.seriesPagination = this.filterUtilityService.pagination(this.route.snapshot);
[this.filterSettings.presets, this.filterSettings.openByDefault] = this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot);
this.filterActiveCheck = this.seriesService.createSeriesFilter();
this.cdRef.markForCheck();
}
ngOnInit(): void {
this.messageHub.messages$.pipe(takeUntil(this.onDestory), debounceTime(2000)).subscribe(event => {
if (event.event === EVENTS.SeriesRemoved) {
this.loadPage();
}
});
}
ngAfterContentChecked(): void {
this.scrollService.setScrollContainer(this.scrollingBlock);
}
ngOnDestroy() {
this.onDestory.next();
this.onDestory.complete();
}
@HostListener('document:keydown.shift', ['$event'])
handleKeypress(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = true;
}
}
@HostListener('document:keyup.shift', ['$event'])
handleKeyUp(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = false;
}
}
loadPage() {
this.filterActive = !this.utilityService.deepEqual(this.filter, this.filterActiveCheck);
this.isLoading = true;
this.cdRef.markForCheck();
this.seriesService.getWantToRead(undefined, undefined, this.filter).pipe(take(1)).subscribe(paginatedList => {
this.series = paginatedList.result;
this.seriesPagination = paginatedList.pagination;
this.jumpbarKeys = this.utilityService.getJumpKeys(this.series, (series: Series) => series.name);
this.isLoading = false;
window.scrollTo(0, 0);
this.cdRef.markForCheck();
});
}
updateFilter(data: FilterEvent) {
this.filter = data.filter;
if (!data.isFirst) this.filterUtilityService.updateUrlFromFilter(this.seriesPagination, this.filter);
this.loadPage();
}
}