Kavita/UI/Web/src/app/sidenav/side-nav/side-nav.component.ts
Joseph Milazzo c1490d6e86
Word Count (#1286)
* Adding some code for Robbie

* See more on series detail metadata area is now at the bottom on the section

* Cleaned up subtitle headings to use a single class for offset with actionables

* Added some markup for the new design, waiting for Robbie to finish it off

* styling age-rating badge

* Started hooking up basic analyze file service and hooks in the UI. Basic code to implement the count is implemented and in benchmarks.

* Hooked up analyze ui to backend

* Refactored Series Detail metadata area to use a new icon/title design

* Cleaned up the new design

* Pushing for robbie to do css

* Massive performance improvement to scan series where we only need to scan folders reported that have series in them, rather than the whole library.

* Removed theme page as we no longer need it. Added WordCount to DTOs so the UI can show them. Added new pipe to format numbers in compact mode.

* Hooked up actual reading time based on user's words per hour

* Refactor some magic numbers to consts

* Hooked in progress reporting for series word count

* Hooked up analyze files

* Re-implemented time to read on comics

* Removed the word Last Read

* Show proper language name instead of iso tag on series detail page. Added some error handling on word count code.

* Reworked error handling

* Fixed some security vulnerabilities in npm.

* Handle a case where there are no text nodes and instead of returning an empty list, htmlagilitypack returns null.

* Tweaked the styles a bit on the icon-and-title

* Code cleanup

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
2022-05-25 14:53:39 -07:00

102 lines
No EOL
3.6 KiB
TypeScript

import { Component, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { Observable, Subject } from 'rxjs';
import { filter, map, take, takeUntil, takeWhile } from 'rxjs/operators';
import { EVENTS, MessageHubService } from 'src/app/_services/message-hub.service';
import { Breakpoint, UtilityService } from '../../shared/_services/utility.service';
import { Library } from '../../_models/library';
import { User } from '../../_models/user';
import { AccountService } from '../../_services/account.service';
import { Action, ActionFactoryService, ActionItem } from '../../_services/action-factory.service';
import { ActionService } from '../../_services/action.service';
import { LibraryService } from '../../_services/library.service';
import { NavService } from '../../_services/nav.service';
@Component({
selector: 'app-side-nav',
templateUrl: './side-nav.component.html',
styleUrls: ['./side-nav.component.scss']
})
export class SideNavComponent implements OnInit, OnDestroy {
user: User | undefined;
libraries: Library[] = [];
isAdmin = false;
actions: ActionItem<Library>[] = [];
filterQuery: string = '';
filterLibrary = (library: Library) => {
return library.name.toLowerCase().indexOf((this.filterQuery || '').toLowerCase()) >= 0;
}
private onDestroy: Subject<void> = new Subject();
constructor(public accountService: AccountService, private libraryService: LibraryService,
public utilityService: UtilityService, private messageHub: MessageHubService,
private actionFactoryService: ActionFactoryService, private actionService: ActionService, public navService: NavService, private router: Router) { }
ngOnInit(): void {
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: Library[]) => {
this.libraries = libraries;
});
this.actions = this.actionFactoryService.getLibraryActions(this.handleAction.bind(this));
});
this.messageHub.messages$.pipe(takeUntil(this.onDestroy), filter(event => event.event === EVENTS.LibraryModified)).subscribe(event => {
this.libraryService.getLibrariesForMember().pipe(take(1)).subscribe((libraries: Library[]) => {
this.libraries = libraries;
});
});
this.router.events
.pipe(filter(event => event instanceof NavigationEnd),
takeUntil(this.onDestroy),
map(evt => evt as NavigationEnd))
.subscribe((evt: NavigationEnd) => {
if (this.utilityService.getActiveBreakpoint() < Breakpoint.Tablet) {
// collapse side nav
this.navService.sideNavCollapsed$.pipe(take(1)).subscribe(collapsed => {
if (!collapsed) {
this.navService.toggleSideNav();
}
});
}
});
}
ngOnDestroy(): void {
this.onDestroy.next();
this.onDestroy.complete();
}
handleAction(action: Action, library: Library) {
switch (action) {
case(Action.ScanLibrary):
this.actionService.scanLibrary(library);
break;
case(Action.RefreshMetadata):
this.actionService.refreshMetadata(library);
break;
case (Action.AnalyzeFiles):
this.actionService.analyzeFiles(library);
break;
default:
break;
}
}
performAction(action: ActionItem<Library>, library: Library) {
if (typeof action.callback === 'function') {
action.callback(action.action, library);
}
}
}