Misc Bugfixes (#2216)
* Folder watching will now appropriately ignore changes that occur in blacklisted folders. * Fixed up recently updated from dashboard not opening a pre-sorted page. There were issues with how encoding and decoding was done plus missing code. * Fixed up all streams from Dashboard opening to correctly filtered pages. * All search linking now works. * Rating tooltip and stars are bigger on mobile. * A bit of cleanup * Added day breakdown to user stats page. * Removed Token checks before we write events to the history table for scrobbling. Refactored so series holds will prevent writing events for reviews, ratings, etc. * Fixed a potential bug where series name could be taken from a chapter that isn't the first ordered (very unlikely) for epubs. Fixed a bug where Volume 1.5 could be selected for series-level metadata over Volume 1. * Optimized the license check code so that users without any license entered would still take advantage of the cache layer. * Sped up an API that checks if the library allows scrobbling * Cleaned up the mobile CSS a bit for filters.
This commit is contained in:
parent
ef3e76e3e5
commit
c84a3294e9
30 changed files with 324 additions and 246 deletions
|
|
@ -79,7 +79,7 @@
|
|||
</ng-template>
|
||||
|
||||
<ng-template #tagTemplate let-item>
|
||||
<div style="display: flex;padding: 5px;" (click)="goTo('tags', item.id)">
|
||||
<div style="display: flex;padding: 5px;" (click)="goToOther(FilterField.Tags, item.id)">
|
||||
<div class="ms-1">
|
||||
<span>{{item.title}}</span>
|
||||
</div>
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
</ng-template>
|
||||
|
||||
<ng-template #genreTemplate let-item>
|
||||
<div style="display: flex;padding: 5px;" class="clickable" (click)="goTo('genres', item.id)">
|
||||
<div style="display: flex;padding: 5px;" class="clickable" (click)="goToOther(FilterField.Genres, item.id)">
|
||||
<div class="ms-1">
|
||||
<div [innerHTML]="item.title"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,40 +1,44 @@
|
|||
import { DOCUMENT, NgIf, NgOptimizedImage, AsyncPipe } from '@angular/common';
|
||||
import {AsyncPipe, DOCUMENT, NgIf, NgOptimizedImage} from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
Component,
|
||||
DestroyRef,
|
||||
ElementRef,
|
||||
inject,
|
||||
Inject,
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { NavigationEnd, Router, RouterLink, RouterLinkActive } from '@angular/router';
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs/operators';
|
||||
import { FilterQueryParam } from 'src/app/shared/_services/filter-utilities.service';
|
||||
import { Chapter } from 'src/app/_models/chapter';
|
||||
import { CollectionTag } from 'src/app/_models/collection-tag';
|
||||
import { Library } from 'src/app/_models/library';
|
||||
import { MangaFile } from 'src/app/_models/manga-file';
|
||||
import { PersonRole } from 'src/app/_models/metadata/person';
|
||||
import { ReadingList } from 'src/app/_models/reading-list';
|
||||
import { SearchResult } from 'src/app/_models/search/search-result';
|
||||
import { SearchResultGroup } from 'src/app/_models/search/search-result-group';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
import { ImageService } from 'src/app/_services/image.service';
|
||||
import { NavService } from 'src/app/_services/nav.service';
|
||||
import { ScrollService } from 'src/app/_services/scroll.service';
|
||||
import { SearchService } from 'src/app/_services/search.service';
|
||||
import {NavigationEnd, Router, RouterLink, RouterLinkActive} from '@angular/router';
|
||||
import {fromEvent} from 'rxjs';
|
||||
import {debounceTime, distinctUntilChanged, filter, tap} from 'rxjs/operators';
|
||||
import {Chapter} from 'src/app/_models/chapter';
|
||||
import {CollectionTag} from 'src/app/_models/collection-tag';
|
||||
import {Library} from 'src/app/_models/library';
|
||||
import {MangaFile} from 'src/app/_models/manga-file';
|
||||
import {PersonRole} from 'src/app/_models/metadata/person';
|
||||
import {ReadingList} from 'src/app/_models/reading-list';
|
||||
import {SearchResult} from 'src/app/_models/search/search-result';
|
||||
import {SearchResultGroup} from 'src/app/_models/search/search-result-group';
|
||||
import {AccountService} from 'src/app/_services/account.service';
|
||||
import {ImageService} from 'src/app/_services/image.service';
|
||||
import {NavService} from 'src/app/_services/nav.service';
|
||||
import {ScrollService} from 'src/app/_services/scroll.service';
|
||||
import {SearchService} from 'src/app/_services/search.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import { SentenceCasePipe } from '../../../pipe/sentence-case.pipe';
|
||||
import { PersonRolePipe } from '../../../pipe/person-role.pipe';
|
||||
import { NgbDropdown, NgbDropdownToggle, NgbDropdownMenu, NgbDropdownItem } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { EventsWidgetComponent } from '../events-widget/events-widget.component';
|
||||
import { SeriesFormatComponent } from '../../../shared/series-format/series-format.component';
|
||||
import { ImageComponent } from '../../../shared/image/image.component';
|
||||
import { GroupedTypeaheadComponent } from '../grouped-typeahead/grouped-typeahead.component';
|
||||
import {SentenceCasePipe} from '../../../pipe/sentence-case.pipe';
|
||||
import {PersonRolePipe} from '../../../pipe/person-role.pipe';
|
||||
import {NgbDropdown, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {EventsWidgetComponent} from '../events-widget/events-widget.component';
|
||||
import {SeriesFormatComponent} from '../../../shared/series-format/series-format.component';
|
||||
import {ImageComponent} from '../../../shared/image/image.component';
|
||||
import {GroupedTypeaheadComponent} from '../grouped-typeahead/grouped-typeahead.component';
|
||||
import {TranslocoDirective} from "@ngneat/transloco";
|
||||
import {FilterUtilitiesService} from "../../../shared/_services/filter-utilities.service";
|
||||
import {FilterStatement} from "../../../_models/metadata/v2/filter-statement";
|
||||
import {FilterField} from "../../../_models/metadata/v2/filter-field";
|
||||
import {FilterComparison} from "../../../_models/metadata/v2/filter-comparison";
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-header',
|
||||
|
|
@ -58,10 +62,12 @@ export class NavHeaderComponent implements OnInit {
|
|||
backToTopNeeded = false;
|
||||
searchFocused: boolean = false;
|
||||
scrollElem: HTMLElement;
|
||||
protected readonly FilterField = FilterField;
|
||||
|
||||
constructor(public accountService: AccountService, private router: Router, public navService: NavService,
|
||||
public imageService: ImageService, @Inject(DOCUMENT) private document: Document,
|
||||
private scrollService: ScrollService, private searchService: SearchService, private readonly cdRef: ChangeDetectorRef) {
|
||||
private scrollService: ScrollService, private searchService: SearchService, private readonly cdRef: ChangeDetectorRef,
|
||||
private filterUtilityService: FilterUtilitiesService) {
|
||||
this.scrollElem = this.document.body;
|
||||
}
|
||||
|
||||
|
|
@ -69,12 +75,11 @@ export class NavHeaderComponent implements OnInit {
|
|||
this.scrollService.scrollContainer$.pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef), tap((scrollContainer) => {
|
||||
if (scrollContainer === 'body' || scrollContainer === undefined) {
|
||||
this.scrollElem = this.document.body;
|
||||
fromEvent(this.document.body, 'scroll').pipe(debounceTime(20)).subscribe(() => this.checkBackToTopNeeded(this.document.body));
|
||||
} else {
|
||||
const elem = scrollContainer as ElementRef<HTMLDivElement>;
|
||||
this.scrollElem = elem.nativeElement;
|
||||
fromEvent(elem.nativeElement, 'scroll').pipe(debounceTime(20)).subscribe(() => this.checkBackToTopNeeded(elem.nativeElement));
|
||||
}
|
||||
fromEvent(this.scrollElem, 'scroll').pipe(debounceTime(20)).subscribe(() => this.checkBackToTopNeeded(this.scrollElem));
|
||||
})).subscribe();
|
||||
|
||||
// Sometimes the top event emitter can be slow, so let's also check when a navigation occurs and recalculate
|
||||
|
|
@ -125,49 +130,54 @@ export class NavHeaderComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
goTo(queryParamName: string, filter: any) {
|
||||
goTo(statement: FilterStatement) {
|
||||
let params: any = {};
|
||||
params[queryParamName] = filter;
|
||||
params[FilterQueryParam.Page] = 1;
|
||||
const filter = this.filterUtilityService.createSeriesV2Filter();
|
||||
filter.statements = [statement];
|
||||
params['page'] = 1;
|
||||
this.clearSearch();
|
||||
this.router.navigate(['all-series'], {queryParams: params});
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params);
|
||||
}
|
||||
|
||||
goToOther(field: FilterField, value: string) {
|
||||
this.goTo({field, comparison: FilterComparison.Equal, value});
|
||||
}
|
||||
|
||||
goToPerson(role: PersonRole, filter: any) {
|
||||
this.clearSearch();
|
||||
switch(role) {
|
||||
case PersonRole.Writer:
|
||||
this.goTo(FilterQueryParam.Writers, filter);
|
||||
this.goTo({field: FilterField.Writers, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Artist:
|
||||
this.goTo(FilterQueryParam.Artists, filter);
|
||||
this.goTo({field: FilterField.CoverArtist, comparison: FilterComparison.Equal, value: filter}); // TODO: What is this supposed to be?
|
||||
break;
|
||||
case PersonRole.Character:
|
||||
this.goTo(FilterQueryParam.Character, filter);
|
||||
this.goTo({field: FilterField.Characters, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Colorist:
|
||||
this.goTo(FilterQueryParam.Colorist, filter);
|
||||
this.goTo({field: FilterField.Colorist, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Editor:
|
||||
this.goTo(FilterQueryParam.Editor, filter);
|
||||
this.goTo({field: FilterField.Editor, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Inker:
|
||||
this.goTo(FilterQueryParam.Inker, filter);
|
||||
this.goTo({field: FilterField.Inker, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.CoverArtist:
|
||||
this.goTo(FilterQueryParam.CoverArtists, filter);
|
||||
this.goTo({field: FilterField.CoverArtist, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Letterer:
|
||||
this.goTo(FilterQueryParam.Letterer, filter);
|
||||
this.goTo({field: FilterField.Letterer, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Penciller:
|
||||
this.goTo(FilterQueryParam.Penciller, filter);
|
||||
this.goTo({field: FilterField.Penciller, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Publisher:
|
||||
this.goTo(FilterQueryParam.Publisher, filter);
|
||||
this.goTo({field: FilterField.Publisher, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
case PersonRole.Translator:
|
||||
this.goTo(FilterQueryParam.Translator, filter);
|
||||
this.goTo({field: FilterField.Translators, comparison: FilterComparison.Equal, value: filter});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -232,4 +242,6 @@ export class NavHeaderComponent implements OnInit {
|
|||
hideSideNav() {
|
||||
this.navService.toggleSideNav();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue