Foundational Rework (#2745)
This commit is contained in:
parent
42cd6e9b3a
commit
4fa21fe1ca
92 changed files with 13330 additions and 650 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import { MangaFile } from './manga-file';
|
||||
import { AgeRating } from './metadata/age-rating';
|
||||
|
||||
export const LooseLeafOrSpecialNumber = 0;
|
||||
export const LooseLeafOrDefaultNumber = -100000;
|
||||
export const SpecialVolumeNumber = 100000;
|
||||
|
||||
/**
|
||||
* Chapter table object. This does not have metadata on it, use ChapterMetadata which is the same Chapter but with those fields.
|
||||
|
|
@ -9,7 +10,12 @@ export const LooseLeafOrSpecialNumber = 0;
|
|||
export interface Chapter {
|
||||
id: number;
|
||||
range: string;
|
||||
/**
|
||||
* @deprecated Use minNumber/maxNumber
|
||||
*/
|
||||
number: string;
|
||||
minNumber: number;
|
||||
maxNumber: number;
|
||||
files: Array<MangaFile>;
|
||||
/**
|
||||
* This is used in the UI, it is not updated or sent to Backend
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {TranslocoService} from "@ngneat/transloco";
|
|||
})
|
||||
export class DefaultDatePipe implements PipeTransform {
|
||||
|
||||
// TODO: Figure out how to translate Never
|
||||
constructor(private translocoService: TranslocoService) {
|
||||
}
|
||||
transform(value: any, replacementString = 'default-date-pipe.never'): string {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,15 @@
|
|||
<td>
|
||||
<ng-container [ngSwitch]="item.scrobbleEventType">
|
||||
<ng-container *ngSwitchCase="ScrobbleEventType.ChapterRead">
|
||||
{{t('volume-and-chapter-num', {v: item.volumeNumber, n: item.chapterNumber})}}
|
||||
@if(item.volumeNumber === SpecialVolumeNumber) {
|
||||
{{t('chapter-num', {num: item.volumeNumber})}}
|
||||
} @else if (item.chapterNumber === LooseLeafOrDefaultNumber) {
|
||||
{{t('volume-num', {num: item.volumeNumber})}}
|
||||
} @else if (item.chapterNumber === LooseLeafOrDefaultNumber && item.volumeNumber === SpecialVolumeNumber) {
|
||||
|
||||
} @else {
|
||||
{{t('volume-and-chapter-num', {v: item.volumeNumber, n: item.chapterNumber})}}
|
||||
}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="ScrobbleEventType.ScoreUpdated">
|
||||
{{t('rating', {r: item.rating})}}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
|
|||
import {TranslocoLocaleModule} from "@ngneat/transloco-locale";
|
||||
import {UtcToLocalTimePipe} from "../../_pipes/utc-to-local-time.pipe";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import {LooseLeafOrDefaultNumber, SpecialVolumeNumber} from "../../_models/chapter";
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-scrobble-history',
|
||||
|
|
@ -101,4 +102,6 @@ export class UserScrobbleHistoryComponent implements OnInit {
|
|||
}
|
||||
|
||||
|
||||
protected readonly SpecialVolumeNumber = SpecialVolumeNumber;
|
||||
protected readonly LooseLeafOrDefaultNumber = LooseLeafOrDefaultNumber;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export class ManageLogsComponent implements OnInit, OnDestroy {
|
|||
this.hubConnection.on('SendLogAsObject', resp => {
|
||||
const payload = resp.arguments[0] as LogMessage;
|
||||
const logMessage = {timestamp: payload.timestamp, level: payload.level, message: payload.message, exception: payload.exception};
|
||||
// TODO: It might be better to just have a queue to show this
|
||||
// NOTE: It might be better to just have a queue to show this
|
||||
const values = this.logsSource.getValue();
|
||||
values.push(logMessage);
|
||||
this.logsSource.next(values);
|
||||
|
|
@ -60,7 +60,7 @@ export class ManageLogsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// unsubscrbe from signalr connection
|
||||
// unsubscribe from signalr connection
|
||||
if (this.hubConnection) {
|
||||
this.hubConnection.stop().catch(err => console.error(err));
|
||||
console.log('Stoping log connection');
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ export class EditSeriesModalComponent implements OnInit {
|
|||
});
|
||||
this.seriesVolumes.forEach(vol => {
|
||||
vol.volumeFiles = vol.chapters?.sort(this.utilityService.sortChapters).map((c: Chapter) => c.files.map((f: any) => {
|
||||
// TODO: Identify how to fix this hack
|
||||
f.chapter = c.number;
|
||||
return f;
|
||||
})).flat();
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@
|
|||
<span>
|
||||
<app-card-actionables (actionHandler)="performAction($event, chapter)" [actions]="chapterActions"
|
||||
[labelBy]="utilityService.formatChapterName(libraryType, true, true) + formatChapterNumber(chapter)"></app-card-actionables>
|
||||
<ng-container *ngIf="chapter.number !== '0'; else specialHeader">
|
||||
<ng-container *ngIf="chapter.minNumber !== LooseLeafOrSpecialNumber; else specialHeader">
|
||||
{{utilityService.formatChapterName(libraryType, true, false) }} {{formatChapterNumber(chapter)}}
|
||||
</ng-container>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { ToastrService } from 'ngx-toastr';
|
|||
import { Observable, of, map, shareReplay } from 'rxjs';
|
||||
import { DownloadService } from 'src/app/shared/_services/download.service';
|
||||
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
|
||||
import { Chapter } from 'src/app/_models/chapter';
|
||||
import {Chapter, LooseLeafOrDefaultNumber} from 'src/app/_models/chapter';
|
||||
import { ChapterMetadata } from 'src/app/_models/metadata/chapter-metadata';
|
||||
import { Device } from 'src/app/_models/device/device';
|
||||
import { LibraryType } from 'src/app/_models/library/library';
|
||||
|
|
@ -74,6 +74,7 @@ export class CardDetailDrawerComponent implements OnInit {
|
|||
protected readonly Breakpoint = Breakpoint;
|
||||
protected readonly LibraryType = LibraryType;
|
||||
protected readonly TabID = TabID;
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrDefaultNumber;
|
||||
|
||||
@Input() parentName = '';
|
||||
@Input() seriesId: number = 0;
|
||||
|
|
@ -182,10 +183,10 @@ export class CardDetailDrawerComponent implements OnInit {
|
|||
}
|
||||
|
||||
formatChapterNumber(chapter: Chapter) {
|
||||
if (chapter.number === '0') {
|
||||
if (chapter.minNumber === LooseLeafOrDefaultNumber) {
|
||||
return '1';
|
||||
}
|
||||
return chapter.number;
|
||||
return chapter.minNumber + '';
|
||||
}
|
||||
|
||||
performAction(action: ActionItem<any>, chapter: Chapter) {
|
||||
|
|
@ -281,5 +282,4 @@ export class CardDetailDrawerComponent implements OnInit {
|
|||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ export class CardItemComponent implements OnInit {
|
|||
if (volumeTitle === '' || volumeTitle === null || volumeTitle === undefined) {
|
||||
this.tooltipTitle = (this.title).trim();
|
||||
} else {
|
||||
this.tooltipTitle = (this.utilityService.asChapter(this.entity).volumeTitle + ' ' + this.title).trim();
|
||||
this.tooltipTitle = (volumeTitle + ' ' + this.title).trim();
|
||||
}
|
||||
} else {
|
||||
this.tooltipTitle = chapterTitle;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
<ng-template #fullComicTitle>
|
||||
{{seriesName.length > 0 ? seriesName + ' - ' : ''}}
|
||||
<ng-container *ngIf="includeVolume && volumeTitle !== ''">
|
||||
{{Number !== LooseLeafOrSpecialNumber ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
|
||||
{{Number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
|
||||
</ng-container>
|
||||
{{Number !== LooseLeafOrSpecialNumber ? (isChapter ? t('issue-num') + Number : volumeTitle) : t('special')}}
|
||||
{{Number !== LooseLeafOrSpecial ? (isChapter ? t('issue-num') + Number : volumeTitle) : t('special')}}
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="LibraryType.Manga">
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
<ng-template #fullMangaTitle>
|
||||
{{seriesName.length > 0 ? seriesName + ' - ' : ''}}
|
||||
<ng-container *ngIf="includeVolume && volumeTitle !== ''">
|
||||
{{Number !== LooseLeafOrSpecialNumber ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
|
||||
{{Number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
|
||||
</ng-container>
|
||||
{{Number !== LooseLeafOrSpecialNumber ? (isChapter ? (t('chapter') + ' ') + Number : volumeTitle) : t('special')}}
|
||||
{{Number !== LooseLeafOrSpecial ? (isChapter ? (t('chapter') + ' ') + Number : volumeTitle) : t('special')}}
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="LibraryType.Book">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
|
||||
import { UtilityService } from 'src/app/shared/_services/utility.service';
|
||||
import { Chapter, LooseLeafOrSpecialNumber } from 'src/app/_models/chapter';
|
||||
import { Chapter, LooseLeafOrDefaultNumber } from 'src/app/_models/chapter';
|
||||
import { LibraryType } from 'src/app/_models/library/library';
|
||||
import { Volume } from 'src/app/_models/volume';
|
||||
import {CommonModule, NgSwitch} from "@angular/common";
|
||||
import {TranslocoModule} from "@ngneat/transloco";
|
||||
|
||||
/**
|
||||
* This is primarily used for list item
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-entity-title',
|
||||
standalone: true,
|
||||
|
|
@ -20,7 +23,9 @@ import {TranslocoModule} from "@ngneat/transloco";
|
|||
})
|
||||
export class EntityTitleComponent implements OnInit {
|
||||
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrSpecialNumber;
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrDefaultNumber;
|
||||
protected readonly LooseLeafOrSpecial = LooseLeafOrDefaultNumber + "";
|
||||
protected readonly LibraryType = LibraryType;
|
||||
|
||||
/**
|
||||
* Library type for which the entity belongs
|
||||
|
|
@ -42,19 +47,18 @@ export class EntityTitleComponent implements OnInit {
|
|||
volumeTitle: string = '';
|
||||
|
||||
get Number() {
|
||||
if (this.utilityService.isVolume(this.entity)) return (this.entity as Volume).minNumber;
|
||||
return (this.entity as Chapter).number;
|
||||
if (this.isChapter) return (this.entity as Chapter).range;
|
||||
return (this.entity as Volume).name;
|
||||
}
|
||||
|
||||
get LibraryType() {
|
||||
return LibraryType;
|
||||
}
|
||||
|
||||
constructor(private utilityService: UtilityService, private readonly cdRef: ChangeDetectorRef) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isChapter = this.utilityService.isChapter(this.entity);
|
||||
|
||||
|
||||
|
||||
if (this.isChapter) {
|
||||
const c = (this.entity as Chapter);
|
||||
this.volumeTitle = c.volumeTitle || '';
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@
|
|||
<ng-container *ngIf="nextExpectedChapter">
|
||||
<ng-container [ngSwitch]="tabId">
|
||||
<ng-container *ngSwitchCase="TabID.Volumes">
|
||||
<app-next-expected-card *ngIf="nextExpectedChapter.volumeNumber > 0 && nextExpectedChapter.chapterNumber === LooseLeafOrSpecialNumber"
|
||||
<app-next-expected-card *ngIf="nextExpectedChapter.volumeNumber !== SpecialVolumeNumber && nextExpectedChapter.chapterNumber === LooseLeafOrSpecialNumber"
|
||||
class="col-auto mt-2 mb-2" [entity]="nextExpectedChapter"
|
||||
[imageUrl]="imageService.getSeriesCoverImage(series.id)"></app-next-expected-card>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ import {
|
|||
import {TagBadgeCursor} from 'src/app/shared/tag-badge/tag-badge.component';
|
||||
import {DownloadEvent, DownloadService} from 'src/app/shared/_services/download.service';
|
||||
import {KEY_CODES, UtilityService} from 'src/app/shared/_services/utility.service';
|
||||
import {Chapter} from 'src/app/_models/chapter';
|
||||
import {Chapter, SpecialVolumeNumber} from 'src/app/_models/chapter';
|
||||
import {Device} from 'src/app/_models/device/device';
|
||||
import {ScanSeriesEvent} from 'src/app/_models/events/scan-series-event';
|
||||
import {SeriesRemovedEvent} from 'src/app/_models/events/series-removed-event';
|
||||
|
|
@ -67,7 +67,7 @@ import {RelationKind} from 'src/app/_models/series-detail/relation-kind';
|
|||
import {SeriesMetadata} from 'src/app/_models/metadata/series-metadata';
|
||||
import {User} from 'src/app/_models/user';
|
||||
import {Volume} from 'src/app/_models/volume';
|
||||
import {LooseLeafOrSpecialNumber} from 'src/app/_models/chapter';
|
||||
import {LooseLeafOrDefaultNumber} from 'src/app/_models/chapter';
|
||||
import {AccountService} from 'src/app/_services/account.service';
|
||||
import {Action, ActionFactoryService, ActionItem} from 'src/app/_services/action-factory.service';
|
||||
import {ActionService} from 'src/app/_services/action.service';
|
||||
|
|
@ -184,7 +184,8 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
protected readonly PageLayoutMode = PageLayoutMode;
|
||||
protected readonly TabID = TabID;
|
||||
protected readonly TagBadgeCursor = TagBadgeCursor;
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrSpecialNumber;
|
||||
protected readonly LooseLeafOrSpecialNumber = LooseLeafOrDefaultNumber;
|
||||
protected readonly SpecialVolumeNumber = SpecialVolumeNumber;
|
||||
|
||||
@ViewChild('scrollingBlock') scrollingBlock: ElementRef<HTMLDivElement> | undefined;
|
||||
@ViewChild('companionBar') companionBar: ElementRef<HTMLDivElement> | undefined;
|
||||
|
|
@ -241,7 +242,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
/**
|
||||
* Track by function for Chapter to tell when to refresh card data
|
||||
*/
|
||||
trackByChapterIdentity = (index: number, item: Chapter) => `${item.title}_${item.number}_${item.volumeId}_${item.pagesRead}`;
|
||||
trackByChapterIdentity = (index: number, item: Chapter) => `${item.title}_${item.minNumber}_${item.maxNumber}_${item.volumeId}_${item.pagesRead}`;
|
||||
trackByRelatedSeriesIdentify = (index: number, item: RelatedSeriesPair) => `${item.series.name}_${item.series.libraryId}_${item.series.pagesRead}_${item.relation}`;
|
||||
trackBySeriesIdentify = (index: number, item: Series) => `${item.name}_${item.libraryId}_${item.pagesRead}`;
|
||||
trackByStoryLineIdentity = (index: number, item: StoryLineItem) => {
|
||||
|
|
@ -371,13 +372,13 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
|
||||
// This is a lone chapter
|
||||
if (vol.length === 0) {
|
||||
return 'Ch ' + this.currentlyReadingChapter.number;
|
||||
return 'Ch ' + this.currentlyReadingChapter.minNumber; // TODO: Refactor this to use DisplayTitle (or Range) and Localize it
|
||||
}
|
||||
|
||||
if (this.currentlyReadingChapter.number === "0") {
|
||||
if (this.currentlyReadingChapter.minNumber === LooseLeafOrDefaultNumber) {
|
||||
return 'Vol ' + vol[0].minNumber;
|
||||
}
|
||||
return 'Vol ' + vol[0].minNumber + ' Ch ' + this.currentlyReadingChapter.number;
|
||||
return 'Vol ' + vol[0].minNumber + ' Ch ' + this.currentlyReadingChapter.minNumber;
|
||||
}
|
||||
|
||||
return this.currentlyReadingChapter.title;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ export class DownloadService {
|
|||
case 'volume':
|
||||
return (downloadEntity as Volume).minNumber + '';
|
||||
case 'chapter':
|
||||
return (downloadEntity as Chapter).number;
|
||||
return (downloadEntity as Chapter).minNumber + '';
|
||||
case 'bookmark':
|
||||
return '';
|
||||
case 'logs':
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export class UtilityService {
|
|||
|
||||
|
||||
sortChapters = (a: Chapter, b: Chapter) => {
|
||||
return parseFloat(a.number) - parseFloat(b.number);
|
||||
return a.minNumber - b.minNumber;
|
||||
}
|
||||
|
||||
mangaFormatToText(format: MangaFormat): string {
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ export interface ReadHistoryEvent {
|
|||
libraryId: number;
|
||||
readDate: string;
|
||||
chapterId: number;
|
||||
chapterNumber: string;
|
||||
}
|
||||
chapterNumber: number;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue