Reading List Detail Overhaul + More Bugfixes and Polish (#3687)
Co-authored-by: Yongun Seong <yseong.p@gmail.com>
This commit is contained in:
parent
b2ee651fb8
commit
dad212bfb9
71 changed files with 5056 additions and 729 deletions
|
|
@ -28,12 +28,24 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
<div class="mb-3 ms-1">
|
||||
<h4 class="header">{{t('format-title')}}</h4>
|
||||
<div class="ms-3">
|
||||
<app-series-format [format]="format"></app-series-format> {{format | mangaFormat }}
|
||||
@if (ageRating) {
|
||||
<div class="mb-3 ms-1">
|
||||
<h4 class="header">{{t('age-rating-title')}}</h4>
|
||||
<div class="ms-3">
|
||||
<app-age-rating-image [rating]="ageRating" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (format) {
|
||||
<div class="mb-3 ms-1">
|
||||
<h4 class="header">{{t('format-title')}}</h4>
|
||||
<div class="ms-3">
|
||||
<app-series-format [format]="format"></app-series-format> {{format | mangaFormat }}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<div class="setting-section-break" aria-hidden="true"></div>
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import {MangaFormatPipe} from "../../_pipes/manga-format.pipe";
|
|||
import {LanguageNamePipe} from "../../_pipes/language-name.pipe";
|
||||
import {AsyncPipe} from "@angular/common";
|
||||
import {SafeUrlPipe} from "../../_pipes/safe-url.pipe";
|
||||
import {AgeRating} from "../../_models/metadata/age-rating";
|
||||
import {AgeRatingImageComponent} from "../age-rating-image/age-rating-image.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-details-tab',
|
||||
|
|
@ -34,7 +36,8 @@ import {SafeUrlPipe} from "../../_pipes/safe-url.pipe";
|
|||
MangaFormatPipe,
|
||||
LanguageNamePipe,
|
||||
AsyncPipe,
|
||||
SafeUrlPipe
|
||||
SafeUrlPipe,
|
||||
AgeRatingImageComponent
|
||||
],
|
||||
templateUrl: './details-tab.component.html',
|
||||
styleUrl: './details-tab.component.scss',
|
||||
|
|
@ -47,11 +50,13 @@ export class DetailsTabComponent {
|
|||
|
||||
protected readonly PersonRole = PersonRole;
|
||||
protected readonly FilterField = FilterField;
|
||||
protected readonly MangaFormat = MangaFormat;
|
||||
|
||||
@Input({required: true}) metadata!: IHasCast;
|
||||
@Input() readingTime: IHasReadingTime | undefined;
|
||||
@Input() ageRating: AgeRating | undefined;
|
||||
@Input() language: string | undefined;
|
||||
@Input() format: MangaFormat = MangaFormat.UNKNOWN;
|
||||
@Input() format: MangaFormat | undefined;
|
||||
@Input() releaseYear: number | undefined;
|
||||
@Input() genres: Array<Genre> = [];
|
||||
@Input() tags: Array<Tag> = [];
|
||||
|
|
@ -62,6 +67,4 @@ export class DetailsTabComponent {
|
|||
if (queryParamName === FilterField.None) return;
|
||||
this.filterUtilityService.applyFilter(['all-series'], queryParamName, FilterComparison.Equal, `${filter}`).subscribe();
|
||||
}
|
||||
|
||||
protected readonly MangaFormat = MangaFormat;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</div>
|
||||
<div class="ms-1">
|
||||
<div><span class="title">{{item.series.name}}</span> <span class="me-1 float-end">({{item.matchRating | translocoPercent}})</span></div>
|
||||
<div class="text-body-secondary">
|
||||
<div class="text-muted">
|
||||
@for(synm of item.series.synonyms; track synm; let last = $last) {
|
||||
{{synm}}
|
||||
@if (!last) {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ import {
|
|||
Output
|
||||
} from '@angular/core';
|
||||
import {ImageComponent} from "../../shared/image/image.component";
|
||||
import {SeriesFormatComponent} from "../../shared/series-format/series-format.component";
|
||||
import {ExternalSeriesMatch} from "../../_models/series-detail/external-series-match";
|
||||
import {PercentPipe} from "@angular/common";
|
||||
import {TranslocoPercentPipe} from "@jsverse/transloco-locale";
|
||||
import {ReadMoreComponent} from "../../shared/read-more/read-more.component";
|
||||
import {TranslocoDirective} from "@jsverse/transloco";
|
||||
|
|
@ -18,18 +16,18 @@ import {PlusMediaFormatPipe} from "../../_pipes/plus-media-format.pipe";
|
|||
import {LoadingComponent} from "../../shared/loading/loading.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-match-series-result-item',
|
||||
imports: [
|
||||
ImageComponent,
|
||||
TranslocoPercentPipe,
|
||||
ReadMoreComponent,
|
||||
TranslocoDirective,
|
||||
PlusMediaFormatPipe,
|
||||
LoadingComponent
|
||||
],
|
||||
templateUrl: './match-series-result-item.component.html',
|
||||
styleUrl: './match-series-result-item.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
selector: 'app-match-series-result-item',
|
||||
imports: [
|
||||
ImageComponent,
|
||||
TranslocoPercentPipe,
|
||||
ReadMoreComponent,
|
||||
TranslocoDirective,
|
||||
PlusMediaFormatPipe,
|
||||
LoadingComponent
|
||||
],
|
||||
templateUrl: './match-series-result-item.component.html',
|
||||
styleUrl: './match-series-result-item.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class MatchSeriesResultItemComponent {
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
[count]="pageInfo.totalElements"
|
||||
[offset]="pageInfo.pageNumber"
|
||||
[limit]="pageInfo.size"
|
||||
[sorts]="[{prop: 'lastModifiedUtc', dir: 'desc'}]"
|
||||
>
|
||||
|
||||
<ngx-datatable-column prop="lastModifiedUtc" [sortable]="true" [draggable]="false" [resizeable]="false">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {debounceTime, take} from "rxjs/operators";
|
|||
import {PaginatedResult} from "../../_models/pagination";
|
||||
import {SortEvent} from "../table/_directives/sortable-header.directive";
|
||||
import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
|
||||
import {TranslocoModule} from "@jsverse/transloco";
|
||||
import {translate, TranslocoModule} from "@jsverse/transloco";
|
||||
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
||||
import {TranslocoLocaleModule} from "@jsverse/transloco-locale";
|
||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||
|
|
@ -18,6 +18,7 @@ import {LooseLeafOrDefaultNumber, SpecialVolumeNumber} from "../../_models/chapt
|
|||
import {ColumnMode, NgxDatatableModule} from "@siemens/ngx-datatable";
|
||||
import {AsyncPipe} from "@angular/common";
|
||||
import {AccountService} from "../../_services/account.service";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
|
||||
export interface DataTablePage {
|
||||
pageNumber: number,
|
||||
|
|
@ -44,6 +45,7 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
private readonly scrobblingService = inject(ScrobblingService);
|
||||
private readonly cdRef = inject(ChangeDetectorRef);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly toastr = inject(ToastrService);
|
||||
protected readonly accountService = inject(AccountService);
|
||||
|
||||
|
||||
|
|
@ -60,6 +62,10 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
totalElements: 0,
|
||||
totalPages: 0
|
||||
}
|
||||
private currentSort: SortEvent<ScrobbleEvent> = {
|
||||
column: 'lastModifiedUtc',
|
||||
direction: 'desc'
|
||||
};
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
|
|
@ -73,26 +79,26 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
|
||||
this.formGroup.get('filter')?.valueChanges.pipe(debounceTime(200), takeUntilDestroyed(this.destroyRef)).subscribe(query => {
|
||||
this.loadPage();
|
||||
})
|
||||
});
|
||||
|
||||
this.loadPage(this.currentSort);
|
||||
}
|
||||
|
||||
onPageChange(pageInfo: any) {
|
||||
this.pageInfo.pageNumber = pageInfo.offset;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.loadPage();
|
||||
this.loadPage(this.currentSort);
|
||||
}
|
||||
|
||||
updateSort(data: any) {
|
||||
this.loadPage({column: data.column.prop, direction: data.newValue});
|
||||
this.currentSort = {
|
||||
column: data.column.prop,
|
||||
direction: data.newValue
|
||||
};
|
||||
}
|
||||
|
||||
loadPage(sortEvent?: SortEvent<ScrobbleEvent>) {
|
||||
if (sortEvent && this.pageInfo) {
|
||||
this.pageInfo.pageNumber = 1;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
const page = (this.pageInfo?.pageNumber || 0) + 1;
|
||||
const pageSize = this.pageInfo?.size || 0;
|
||||
const isDescending = sortEvent?.direction === 'desc';
|
||||
|
|
@ -102,7 +108,6 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
this.isLoading = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// BUG: Table should be sorted by lastModifiedUtc by default
|
||||
this.scrobblingService.getScrobbleEvents({query, field, isDescending}, page, pageSize)
|
||||
.pipe(take(1))
|
||||
.subscribe((result: PaginatedResult<ScrobbleEvent[]>) => {
|
||||
|
|
@ -122,13 +127,14 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
case 'isProcessed': return ScrobbleEventSortField.IsProcessed;
|
||||
case 'lastModifiedUtc': return ScrobbleEventSortField.LastModified;
|
||||
case 'seriesName': return ScrobbleEventSortField.Series;
|
||||
case 'scrobbleEventType': return ScrobbleEventSortField.ScrobbleEvent;
|
||||
}
|
||||
return ScrobbleEventSortField.None;
|
||||
}
|
||||
|
||||
generateScrobbleEvents() {
|
||||
this.scrobblingService.triggerScrobbleEventGeneration().subscribe(_ => {
|
||||
|
||||
this.toastr.info(translate('toasts.scrobble-gen-init'))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue