Round 3 of Bugfixing (#3318)

This commit is contained in:
Joe Milazzo 2024-10-28 18:13:48 -05:00 committed by GitHub
parent 727fbd353b
commit abdf15b895
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 482 additions and 489 deletions

View file

@ -198,7 +198,7 @@
<ng-container [ngTemplateOutlet]="lock" [ngTemplateOutletContext]="{ item: metadata, field: 'publicationStatusLocked' }"></ng-container>
<select class="form-select" id="publication-status" formControlName="publicationStatus">
@for (opt of publicationStatuses; track opt.value) {
<option [value]="opt.value">{{opt.title | titlecase}}</option>
<option [value]="opt.value">{{opt.value | publicationStatus}}</option>
}
</select>
</div>

View file

@ -515,7 +515,7 @@ export class EditSeriesModalComponent implements OnInit {
};
personSettings.addTransformFn = ((title: string) => {
return {id: 0, name: title, description: '', coverImageLocked: false };
return {id: 0, name: title, description: '', coverImageLocked: false, primaryColor: '', secondaryColor: '' };
});
return personSettings;
@ -551,6 +551,7 @@ export class EditSeriesModalComponent implements OnInit {
// We only need to call updateSeries if we changed name, sort name, or localized name or reset a cover image
const nameFieldsDirty = this.editSeriesForm.get('name')?.dirty || this.editSeriesForm.get('sortName')?.dirty || this.editSeriesForm.get('localizedName')?.dirty;
const nameFieldLockChanged = this.series.nameLocked !== this.initSeries.nameLocked || this.series.sortNameLocked !== this.initSeries.sortNameLocked || this.series.localizedNameLocked !== this.initSeries.localizedNameLocked;
if (nameFieldsDirty || nameFieldLockChanged || this.coverImageReset) {
model.nameLocked = this.series.nameLocked;
model.sortNameLocked = this.series.sortNameLocked;

View file

@ -46,12 +46,12 @@
<div class="card-overlay"></div>
<div class="chapter overlay-information">
<div class="overlay-information--centered">
<span class="card-title library mx-auto" style="width: auto;" (click)="read($event)">
<!-- Card Image -->
<div>
<i class="fa-solid fa-book" aria-hidden="true"></i>
</div>
</span>
<span class="card-title library mx-auto" style="width: auto;" (click)="read($event)">
<!-- Card Image -->
<div>
<i class="fa-solid fa-book" aria-hidden="true"></i>
</div>
</span>
</div>
</div>
</div>
@ -85,10 +85,10 @@
</a>
</span>
<span class="card-actions">
@if (actions && actions.length > 0) {
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="chapter.titleName"></app-card-actionables>
}
</span>
@if (actions && actions.length > 0) {
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="chapter.titleName"></app-card-actionables>
}
</span>
</div>
</div>

View file

@ -1,32 +1,31 @@
<ng-container *transloco="let t; read: 'cover-image-chooser'">
<div class="container-fluid" style="padding-left: 0px; padding-right: 0px">
<div class="container-fluid" style="padding-left: 0; padding-right: 0">
<form [formGroup]="form">
<ngx-file-drop (onFileDrop)="dropped($event)"
(onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)" [accept]="acceptableExtensions" [directory]="false"
dropZoneClassName="file-upload" contentClassName="file-upload-zone">
<ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector">
<div class="row g-0 mt-3 pb-3" *ngIf="mode === 'all'">
<div class="mx-auto">
<div class="row g-0 mb-3">
<i class="fa fa-file-upload mx-auto" style="font-size: 24px; width: 20px;" aria-hidden="true"></i>
</div>
@if (mode === 'all') {
<div class="row g-0 mt-3 pb-3">
<div class="mx-auto">
<div class="row g-0 mb-3">
<i class="fa fa-file-upload mx-auto" style="font-size: 24px; width: 20px;" aria-hidden="true"></i>
</div>
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-evenly">
<a class="pe-0" href="javascript:void(0)" (click)="changeMode('url')">
<span class="phone-hidden">{{t('enter-an-url-pre-title', {url: ''})}}</span>{{t('url')}}
</a>
<span class="ps-1 pe-1"></span>
<span class="pe-0" href="javascript:void(0)">{{t('drag-n-drop')}}</span>
<span class="ps-1 pe-1"></span>
<a class="pe-0" href="javascript:void(0)" (click)="openFileSelector()">{{t('upload')}}<span class="phone-hidden"> {{t('upload-continued')}}</span></a>
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-evenly">
<a class="pe-0" href="javascript:void(0)" (click)="changeMode('url')">
<span class="phone-hidden">{{t('enter-an-url-pre-title', {url: ''})}}</span>{{t('url')}}
</a>
<span class="ps-1 pe-1"></span>
<span class="pe-0" href="javascript:void(0)">{{t('drag-n-drop')}}</span>
<span class="ps-1 pe-1"></span>
<a class="pe-0" href="javascript:void(0)" (click)="openFileSelector()">{{t('upload')}}<span class="phone-hidden"> {{t('upload-continued')}}</span></a>
</div>
</div>
</div>
</div>
</div>
<ng-container *ngIf="mode === 'url'">
} @else if (mode === 'url') {
<div class="row g-0 mt-3 pb-3 ms-md-2 me-md-2">
<div class="input-group col-auto me-md-2" style="width: 83%">
<label class="input-group-text" for="load-image">{{t('url-label')}}</label>
@ -42,9 +41,7 @@
<span class="phone-hidden">{{t('back')}}</span>
</button>
</div>
</ng-container>
}
</ng-template>
</ngx-file-drop>
@ -54,28 +51,32 @@
</form>
<div class="row g-0 chooser" style="padding-top: 10px">
<div class="clickable col-auto"
*ngIf="showReset" tabindex="0" (click)="reset()"
[ngClass]="{'selected': !showApplyButton && selectedIndex === -1}">
<app-image class="card-img-top" [title]="t('reset-cover-tooltip')" height="232.91px" width="160px" [imageUrl]="imageService.resetCoverImage"></app-image>
<ng-container *ngIf="showApplyButton">
<br>
<button style="width: 100%;" class="btn btn-secondary" (click)="resetImage()">{{t('reset')}}</button>
</ng-container>
@if (showReset) {
<div class="clickable col-auto" tabindex="0" (click)="reset()"
[ngClass]="{'selected': !showApplyButton && selectedIndex === -1}">
<app-image class="card-img-top" [title]="t('reset-cover-tooltip')" height="232.91px" width="160px" [imageUrl]="imageService.resetCoverImage"></app-image>
@if (showApplyButton) {
<br>
<button style="width: 100%;" class="btn btn-secondary" (click)="resetImage()">{{t('reset')}}</button>
}
</div>
}
@for (url of imageUrls; track url; let idx = $index) {
<div class="clickable col-auto" tabindex="0" [attr.aria-label]="t('image-num', {num: idx + 1})" (click)="selectImage(idx)"
[ngClass]="{'selected': !showApplyButton && selectedIndex === idx}">
<app-image class="card-img-top" height="232.91px" width="160px" [imageUrl]="url" [processEvents]="idx > 0"></app-image>
@if (showApplyButton) {
<br>
<button class="btn btn-primary" style="width: 100%;"
(click)="applyImage(idx)">
{{appliedIndex === idx ? t('applied') : t('apply')}}
</button>
}
</div>
}
</div>
<div class="clickable col-auto"
*ngFor="let url of imageUrls; let idx = index;" tabindex="0" [attr.aria-label]="t('image-num', {num: idx + 1})" (click)="selectImage(idx)"
[ngClass]="{'selected': !showApplyButton && selectedIndex === idx}">
<app-image class="card-img-top" height="232.91px" width="160px" [imageUrl]="url" [processEvents]="idx > 0"></app-image>
<ng-container *ngIf="showApplyButton">
<br>
<button class="btn btn-primary" style="width: 100%;"
(click)="applyImage(idx)">
{{appliedIndex === idx ? t('applied') : t('apply')}}
</button>
</ng-container>
</div>
</div>
</div>

View file

@ -17,7 +17,7 @@ import { ToastrService } from 'ngx-toastr';
import { ImageService } from 'src/app/_services/image.service';
import { KEY_CODES } from 'src/app/shared/_services/utility.service';
import { UploadService } from 'src/app/_services/upload.service';
import {CommonModule, DOCUMENT} from '@angular/common';
import {DOCUMENT, NgClass} from '@angular/common';
import {ImageComponent} from "../../shared/image/image.component";
import {translate, TranslocoModule} from "@jsverse/transloco";
@ -27,9 +27,9 @@ import {translate, TranslocoModule} from "@jsverse/transloco";
imports: [
ReactiveFormsModule,
NgxFileDropModule,
CommonModule,
ImageComponent,
TranslocoModule
TranslocoModule,
NgClass
],
templateUrl: './cover-image-chooser.component.html',
styleUrls: ['./cover-image-chooser.component.scss'],

View file

@ -1,87 +1,94 @@
<ng-container *transloco="let t; read: 'entity-title'">
@switch (libraryType) {
@case (LibraryType.Comic) {
@if (titleName !== '' && prioritizeTitleName) {
@if (isChapter && includeChapter) {
{{t('issue-num') + ' ' + number + ' - ' }}
}
{{renderText | defaultValue}}
<!-- @switch (libraryType) {-->
<!-- @case (LibraryType.Comic) {-->
<!-- @if (titleName !== '' && prioritizeTitleName) {-->
<!-- @if (isChapter && includeChapter) {-->
<!-- {{t('issue-num') + ' ' + number + ' - ' }}-->
<!-- }-->
{{titleName}}
} @else {
@if (includeVolume && volumeTitle !== '') {
{{number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
}
{{number !== LooseLeafOrSpecial ? (isChapter ? t('issue-num') + number : volumeTitle) : t('special')}}
}
}
<!-- {{titleName}}-->
<!-- } @else {-->
<!-- @if (includeVolume && volumeTitle !== '') {-->
<!-- {{number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}-->
<!-- }-->
<!-- {{number !== LooseLeafOrSpecial ? (isChapter ? t('issue-num') + number : volumeTitle) : t('special')}}-->
<!-- }-->
<!-- }-->
@case (LibraryType.ComicVine) {
@if (titleName !== '' && prioritizeTitleName) {
@if (isChapter && includeChapter) {
{{t('issue-num') + ' ' + number + ' - ' }}
}
<!-- @case (LibraryType.ComicVine) {-->
<!-- @if (titleName !== '' && prioritizeTitleName) {-->
<!-- @if (isChapter && includeChapter) {-->
<!-- {{t('issue-num') + ' ' + number + ' - ' }}-->
<!-- }-->
{{titleName}}
} @else {
@if (includeVolume && volumeTitle !== '') {
{{number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}
}
{{number !== LooseLeafOrSpecial ? (isChapter ? t('issue-num') + number : volumeTitle) : t('special')}}
}
}
<!-- {{titleName}}-->
<!-- } @else {-->
<!-- @if (includeVolume && volumeTitle !== '') {-->
<!-- {{number !== LooseLeafOrSpecial ? (isChapter && includeVolume ? volumeTitle : '') : ''}}-->
<!-- }-->
<!-- @if (number !== LooseLeafOrSpecial) {-->
<!-- {{isChapter ? t('issue-num') + number : volumeTitle}}-->
<!-- } @else {-->
<!-- {{t('special')}}-->
<!-- }-->
<!-- }-->
<!-- }-->
@case (LibraryType.Manga) {
@if (titleName !== '' && prioritizeTitleName) {
@if (isChapter && includeChapter) {
@if (number === LooseLeafOrSpecial) {
{{t('chapter') + ' - ' }}
} @else {
{{t('chapter') + ' ' + number + ' - ' }}
}
<!-- @case (LibraryType.Manga) {-->
<!-- @if (titleName !== '' && prioritizeTitleName) {-->
<!-- @if (isChapter && includeChapter) {-->
<!-- @if (number === LooseLeafOrSpecial) {-->
<!-- {{t('chapter') + ' - ' }}-->
<!-- } @else {-->
<!-- {{t('chapter') + ' ' + number + ' - ' }}-->
<!-- }-->
}
{{titleName}}
} @else {
@if (includeVolume && volumeTitle !== '') {
@if (number !== LooseLeafOrSpecial && isChapter && includeVolume) {
{{volumeTitle}}
}
}
<!-- }-->
<!-- {{titleName}}-->
<!-- } @else {-->
<!-- @if (includeVolume && volumeTitle !== '') {-->
<!-- @if (number !== LooseLeafOrSpecial && isChapter && includeVolume) {-->
<!-- {{volumeTitle}}-->
<!-- }-->
<!-- }-->
@if (number !== LooseLeafOrSpecial) {
@if (isChapter) {
{{t('chapter') + ' ' + number}}
} @else {
{{volumeTitle}}
}
} @else {
{{t('special')}}
}
}
}
<!-- @if (number !== LooseLeafOrSpecial) {-->
<!-- @if (isChapter) {-->
<!-- {{t('chapter') + ' ' + number}}-->
<!-- } @else {-->
<!-- {{volumeTitle}}-->
<!-- }-->
<!-- } @else if (fallbackToVolume && isChapter && volumeTitle) {-->
<!-- {{t('vol-num', {num: volumeTitle})}}-->
<!-- } @else {-->
<!-- {{t('special')}}-->
<!-- }-->
<!-- }-->
<!-- }-->
@case (LibraryType.Book) {
@if (titleName !== '' && prioritizeTitleName) {
{{titleName}}
} @else if (number === LooseLeafOrSpecial) {
{{null | defaultValue}}
} @else {
{{t('book-num', {num: volumeTitle})}}
}
}
<!-- @case (LibraryType.Book) {-->
<!-- @if (titleName !== '' && prioritizeTitleName) {-->
<!-- {{titleName}}-->
<!-- } @else if (number === LooseLeafOrSpecial) {-->
<!-- {{null | defaultValue}}-->
<!-- } @else {-->
<!-- {{t('book-num', {num: volumeTitle})}}-->
<!-- }-->
<!-- }-->
@case (LibraryType.LightNovel) {
@if (titleName !== '' && prioritizeTitleName) {
{{titleName}}
} @else if (number === LooseLeafOrSpecial) {
{{null | defaultValue}}
} @else {
{{t('book-num', {num: (isChapter ? number : volumeTitle)})}}
}
}
<!-- @case (LibraryType.LightNovel) {-->
<!-- @if (titleName !== '' && prioritizeTitleName) {-->
<!-- {{titleName}}-->
<!-- } @else if (number === LooseLeafOrSpecial) {-->
<!-- {{null | defaultValue}}-->
<!-- } @else {-->
<!-- {{t('book-num', {num: (isChapter ? number : volumeTitle)})}}-->
<!-- }-->
<!-- }-->
@case (LibraryType.Images) {
{{number !== LooseLeafOrSpecial ? (isChapter ? (t('chapter') + ' ') + number : volumeTitle) : t('special')}}
}
}
<!-- @case (LibraryType.Images) {-->
<!-- {{number !== LooseLeafOrSpecial ? (isChapter ? (t('chapter') + ' ') + number : volumeTitle) : t('special')}}-->
<!-- }-->
<!-- }-->
</ng-container>

View file

@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, Input, OnInit} from '@angular/core';
import { UtilityService } from 'src/app/shared/_services/utility.service';
import { Chapter, LooseLeafOrDefaultNumber } from 'src/app/_models/chapter';
import { LibraryType } from 'src/app/_models/library/library';
import { Volume } from 'src/app/_models/volume';
import {TranslocoModule} from "@jsverse/transloco";
import {translate, TranslocoModule} from "@jsverse/transloco";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
/**
@ -22,6 +22,9 @@ import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
})
export class EntityTitleComponent implements OnInit {
private readonly utilityService = inject(UtilityService);
private readonly cdRef = inject(ChangeDetectorRef);
protected readonly LooseLeafOrSpecial = LooseLeafOrDefaultNumber + "";
protected readonly LibraryType = LibraryType;
@ -42,16 +45,18 @@ export class EntityTitleComponent implements OnInit {
* When a titleName (aka a title) is available on the entity, show it over Volume X Chapter Y
*/
@Input() prioritizeTitleName: boolean = true;
/**
* When there is no meaningful title to display and the chapter is just a single volume, show the volume number
*/
@Input() fallbackToVolume: boolean = true;
isChapter = false;
titleName: string = '';
volumeTitle: string = '';
number: string = '';
renderText: string = '';
constructor(private utilityService: UtilityService, private readonly cdRef: ChangeDetectorRef) {}
ngOnInit(): void {
this.isChapter = this.utilityService.isChapter(this.entity);
@ -60,7 +65,6 @@ export class EntityTitleComponent implements OnInit {
this.volumeTitle = c.volumeTitle || '';
this.titleName = c.titleName || '';
this.number = c.range;
} else {
const v = this.utilityService.asVolume(this.entity);
this.volumeTitle = v.name || '';
@ -70,6 +74,125 @@ export class EntityTitleComponent implements OnInit {
}
this.number = v.name;
}
this.calculateRenderText();
this.cdRef.markForCheck();
}
private calculateRenderText() {
switch (this.libraryType) {
case LibraryType.Manga:
this.renderText = this.calculateMangaRenderText();
break;
case LibraryType.Comic:
this.renderText = this.calculateComicRenderText();
break;
case LibraryType.Book:
this.renderText = this.calculateBookRenderText();
break;
case LibraryType.Images:
this.renderText = this.calculateImageRenderText();
break;
case LibraryType.LightNovel:
this.renderText = this.calculateLightNovelRenderText();
break;
case LibraryType.ComicVine:
this.renderText = this.calculateComicRenderText();
break;
}
this.cdRef.markForCheck();
}
private calculateBookRenderText() {
let renderText = '';
if (this.titleName !== '' && this.prioritizeTitleName) {
renderText = this.titleName;
} else if (this.number === this.LooseLeafOrSpecial) {
renderText = '';
} else {
renderText = translate('entity-title.book-num', {num: this.volumeTitle});
}
return renderText;
}
private calculateLightNovelRenderText() {
let renderText = '';
if (this.titleName !== '' && this.prioritizeTitleName) {
renderText = this.titleName;
} else if (this.number === this.LooseLeafOrSpecial) {
renderText = '';
} else {
const bookNum = this.isChapter ? this.number : this.volumeTitle;
renderText = translate('entity-title.book-num', {num: bookNum});
}
return renderText;
}
private calculateMangaRenderText() {
let renderText = '';
if (this.titleName !== '' && this.prioritizeTitleName) {
if (this.isChapter && this.includeChapter) {
if (this.number === this.LooseLeafOrSpecial) {
renderText = translate('entity-title.chapter') + ' - ';
} else {
renderText = translate('entity-title.chapter') + ' ' + this.number + ' - ';
}
}
renderText += this.titleName;
} else {
if (this.includeVolume && this.volumeTitle !== '') {
if (this.number !== this.LooseLeafOrSpecial && this.isChapter && this.includeVolume) {
renderText = this.volumeTitle;
}
}
if (this.number !== this.LooseLeafOrSpecial) {
if (this.isChapter) {
renderText = translate('entity-title.chapter') + ' ' + this.number;
} else {
renderText = this.volumeTitle;
}
} else if (this.fallbackToVolume && this.isChapter && this.volumeTitle) {
renderText = translate('entity-title.vol-num', {num: this.volumeTitle});
} else if (this.fallbackToVolume && this.isChapter) { // this.volumeTitle === '' (this is a single volume on volume detail page)
renderText = translate('entity-title.single-volume');
} else {
renderText = translate('entity-title.special');
}
}
return renderText;
}
private calculateImageRenderText() {
let renderText = '';
if (this.number !== this.LooseLeafOrSpecial) {
if (this.isChapter) {
renderText = translate('entity-title.chapter') + ' ' + this.number;
} else {
renderText = this.volumeTitle;
}
} else {
renderText = translate('entity-title.special');
}
return renderText;
}
private calculateComicRenderText() {
let renderText = '';
if (this.titleName !== '' && this.prioritizeTitleName) {
if (this.isChapter && this.includeChapter) {
renderText = translate('entity-title.issue-num') + ' ' + this.number + ' - ';
}
renderText += this.titleName;
}
return renderText;
}
}