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:
Joe Milazzo 2023-08-15 16:33:39 -05:00 committed by GitHub
parent ef3e76e3e5
commit c84a3294e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 324 additions and 246 deletions

View file

@ -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>

View file

@ -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();
}
}