More Bugfixes (#2874)

This commit is contained in:
Joe Milazzo 2024-04-14 17:37:22 -05:00 committed by GitHub
parent f02e1f7d1f
commit 6d9a5d8f65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 303 additions and 108 deletions

View File

@ -176,6 +176,7 @@ public class SeriesController : BaseApiController
return Ok(await _unitOfWork.ChapterRepository.AddChapterModifiers(User.GetUserId(), chapter));
}
[Obsolete("All chapter entities will load this data by default. Will not be maintained as of v0.8.1")]
[HttpGet("chapter-metadata")]
public async Task<ActionResult<ChapterMetadataDto>> GetChapterMetadata(int chapterId)
{

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using API.DTOs.Metadata;
using API.Entities.Enums;
using API.Entities.Interfaces;
@ -120,4 +121,42 @@ public class ChapterDto : IHasReadTimeEstimate
/// </summary>
/// <remarks>This is guaranteed to be Valid</remarks>
public string ISBN { get; set; }
#region Metadata
public ICollection<PersonDto> Writers { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> CoverArtists { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Publishers { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Characters { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Pencillers { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Inkers { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Imprints { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Colorists { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Letterers { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Editors { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Translators { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Teams { get; set; } = new List<PersonDto>();
public ICollection<PersonDto> Locations { get; set; } = new List<PersonDto>();
public ICollection<GenreTagDto> Genres { get; set; } = new List<GenreTagDto>();
/// <summary>
/// Collection of all Tags from underlying chapters for a Series
/// </summary>
public ICollection<TagDto> Tags { get; set; } = new List<TagDto>();
public PublicationStatus PublicationStatus { get; set; }
/// <summary>
/// Language for the Chapter/Issue
/// </summary>
public string? Language { get; set; }
/// <summary>
/// Number in the TotalCount of issues
/// </summary>
public int Count { get; set; }
/// <summary>
/// Total number of issues for the series
/// </summary>
public int TotalCount { get; set; }
#endregion
}

View File

@ -51,7 +51,6 @@ public class AutoMapperProfiles : Profile
CreateMap<Volume, VolumeDto>()
.ForMember(dest => dest.Number, opt => opt.MapFrom(src => (int) src.MinNumber));
CreateMap<MangaFile, MangaFileDto>();
CreateMap<Chapter, ChapterDto>();
CreateMap<Series, SeriesDto>();
CreateMap<CollectionTag, CollectionTagDto>();
CreateMap<AppUserCollection, AppUserCollectionDto>()
@ -191,6 +190,48 @@ public class AutoMapperProfiles : Profile
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Location).OrderBy(p => p.NormalizedName)))
;
CreateMap<Chapter, ChapterDto>()
.ForMember(dest => dest.Writers,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Writer).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.CoverArtists,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.CoverArtist).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Colorists,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Colorist).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Inkers,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Inker).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Imprints,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Imprint).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Letterers,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Letterer).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Pencillers,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Penciller).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Publishers,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Publisher).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Translators,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Translator).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Characters,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Character).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Editors,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Editor).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Teams,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Team).OrderBy(p => p.NormalizedName)))
.ForMember(dest => dest.Locations,
opt =>
opt.MapFrom(src => src.People.Where(p => p.Role == PersonRole.Location).OrderBy(p => p.NormalizedName)))
;
CreateMap<AppUser, UserDto>()
.ForMember(dest => dest.AgeRestriction,
opt =>

View File

@ -191,7 +191,14 @@ public class CacheService : ICacheService
if (files.Count > 0 && files[0].Format == MangaFormat.Image)
{
_readingItemService.Extract(files[0].FilePath, extractPath, MangaFormat.Image, files.Count);
foreach (var file in files)
{
if (fileCount > 1)
{
extraPath = file.Id + string.Empty;
}
_readingItemService.Extract(file.FilePath, Path.Join(extractPath, extraPath), MangaFormat.Image, files.Count);
}
_directoryService.Flatten(extractDi.FullName);
}

View File

@ -1,5 +1,9 @@
import { MangaFile } from './manga-file';
import { AgeRating } from './metadata/age-rating';
import {PublicationStatus} from "./metadata/publication-status";
import {Genre} from "./metadata/genre";
import {Tag} from "./tag";
import {Person} from "./metadata/person";
export const LooseLeafOrDefaultNumber = -100000;
export const SpecialVolumeNumber = 100000;
@ -51,4 +55,28 @@ export interface Chapter {
isbn: string;
lastReadingProgress: string;
sortOrder: number;
// originally in ChapterMetadata but now inlined with Chapter data
year: string;
language: string;
publicationStatus: PublicationStatus;
count: number;
totalCount: number;
genres: Array<Genre>;
tags: Array<Tag>;
writers: Array<Person>;
coverArtists: Array<Person>;
publishers: Array<Person>;
characters: Array<Person>;
pencillers: Array<Person>;
inkers: Array<Person>;
imprints: Array<Person>;
colorists: Array<Person>;
letterers: Array<Person>;
editors: Array<Person>;
translators: Array<Person>;
teams: Array<Person>;
locations: Array<Person>;
}

View File

@ -1,42 +0,0 @@
import { Genre } from "./genre";
import { AgeRating } from "./age-rating";
import { PublicationStatus } from "./publication-status";
import { Person } from "./person";
import { Tag } from "../tag";
export interface ChapterMetadata {
id: number;
chapterId: number;
title: string;
year: string;
ageRating: AgeRating;
releaseDate: string;
language: string;
publicationStatus: PublicationStatus;
summary: string;
count: number;
totalCount: number;
wordCount: number;
genres: Array<Genre>;
tags: Array<Tag>;
writers: Array<Person>;
coverArtists: Array<Person>;
publishers: Array<Person>;
characters: Array<Person>;
pencillers: Array<Person>;
inkers: Array<Person>;
imprints: Array<Person>;
colorists: Array<Person>;
letterers: Array<Person>;
editors: Array<Person>;
translators: Array<Person>;
teams: Array<Person>;
locations: Array<Person>;
}

View File

@ -5,8 +5,6 @@ import { map } from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { UtilityService } from '../shared/_services/utility.service';
import { Chapter } from '../_models/chapter';
import { ChapterMetadata } from '../_models/metadata/chapter-metadata';
import { UserCollection } from '../_models/collection-tag';
import { PaginatedResult } from '../_models/pagination';
import { Series } from '../_models/series';
import { RelatedSeries } from '../_models/series-detail/related-series';
@ -75,10 +73,6 @@ export class SeriesService {
return this.httpClient.get<Chapter>(this.baseUrl + 'series/chapter?chapterId=' + chapterId);
}
getChapterMetadata(chapterId: number) {
return this.httpClient.get<ChapterMetadata>(this.baseUrl + 'series/chapter-metadata?chapterId=' + chapterId);
}
delete(seriesId: number) {
return this.httpClient.delete<string>(this.baseUrl + 'series/' + seriesId, TextResonse).pipe(map(s => s === "true"));
}

View File

@ -39,7 +39,7 @@
<li [ngbNavItem]="tabs[TabID.Metadata]">
<a ngbNavLink>{{t(tabs[TabID.Metadata].title)}}</a>
<ng-template ngbNavContent>
<app-chapter-metadata-detail [chapter]="chapterMetadata"></app-chapter-metadata-detail>
<app-chapter-metadata-detail [chapter]="chapter"></app-chapter-metadata-detail>
</ng-template>
</li>

View File

@ -21,7 +21,6 @@ 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, 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';
import { MangaFile } from 'src/app/_models/manga-file';
@ -48,7 +47,7 @@ import {BytesPipe} from "../../_pipes/bytes.pipe";
import {BadgeExpanderComponent} from "../../shared/badge-expander/badge-expander.component";
import {TagBadgeComponent} from "../../shared/tag-badge/tag-badge.component";
import {PersonBadgeComponent} from "../../shared/person-badge/person-badge.component";
import {translate, TranslocoDirective, TranslocoService} from "@ngneat/transloco";
import {translate, TranslocoDirective} from "@ngneat/transloco";
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
import {EditChapterProgressComponent} from "../edit-chapter-progress/edit-chapter-progress.component";
@ -113,9 +112,7 @@ export class CardDetailDrawerComponent implements OnInit {
];
active = this.tabs[0];
chapterMetadata: ChapterMetadata | undefined;
summary: string = '';
downloadInProgress: boolean = false;
@ -139,10 +136,6 @@ export class CardDetailDrawerComponent implements OnInit {
this.isChapter = this.utilityService.isChapter(this.data);
this.chapter = this.utilityService.isChapter(this.data) ? (this.data as Chapter) : (this.data as Volume).chapters[0];
this.seriesService.getChapterMetadata(this.chapter.id).subscribe(metadata => {
this.chapterMetadata = metadata;
this.cdRef.markForCheck();
});
if (this.isChapter) {
this.coverImageUrl = this.imageService.getChapterCoverImage(this.data.id);

View File

@ -171,8 +171,10 @@ export class CardDetailLayoutComponent implements OnInit, OnChanges {
hasCustomSort() {
if (this.filteringDisabled) return false;
return this.filter?.sortOptions?.sortField != SortField.SortName || !this.filter?.sortOptions.isAscending
|| this.filterSettings?.presetsV2?.sortOptions?.sortField != SortField.SortName || !this.filterSettings?.presetsV2?.sortOptions?.isAscending;
const hasCustomSort = this.filter?.sortOptions?.sortField != SortField.SortName || !this.filter?.sortOptions.isAscending;
const hasNonDefaultSortField = this.filterSettings?.presetsV2?.sortOptions?.sortField != SortField.SortName;
return hasCustomSort;
}
performAction(action: ActionItem<any>) {

View File

@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { ChapterMetadata } from 'src/app/_models/metadata/chapter-metadata';
import {CommonModule} from "@angular/common";
import {BadgeExpanderComponent} from "../../shared/badge-expander/badge-expander.component";
import {PersonBadgeComponent} from "../../shared/person-badge/person-badge.component";
import {TranslocoDirective} from "@ngneat/transloco";
import {Chapter} from "../../_models/chapter";
@Component({
selector: 'app-chapter-metadata-detail',
@ -14,5 +14,5 @@ import {TranslocoDirective} from "@ngneat/transloco";
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChapterMetadataDetailComponent {
@Input() chapter: ChapterMetadata | undefined;
@Input() chapter: Chapter | undefined;
}

View File

@ -1,13 +1,13 @@
<ng-container *transloco="let t; read: 'entity-info-cards'">
<div class="mt-3 mb-3">
<div class="row g-0" *ngIf="chapterMetadata ">
<div class="row g-0" *ngIf="chapter ">
<!-- Tags and Characters are used a lot of Hentai and Doujinshi type content, so showing in list item has value add on first glance -->
<app-metadata-detail [tags]="chapterMetadata.tags" [libraryId]="libraryId" [queryParam]="FilterField.Tags" heading="Tags">
<app-metadata-detail [tags]="chapter.tags" [libraryId]="libraryId" [queryParam]="FilterField.Tags" heading="Tags">
<ng-template #titleTemplate let-item>{{item.title}}</ng-template>
</app-metadata-detail>
<app-metadata-detail [tags]="chapterMetadata.characters" [libraryId]="libraryId" [queryParam]="FilterField.Characters" heading="Characters">
<app-metadata-detail [tags]="chapter.characters" [libraryId]="libraryId" [queryParam]="FilterField.Characters" heading="Characters">
<ng-template #titleTemplate let-item>{{item.name}}</ng-template>
</app-metadata-detail>
</div>

View File

@ -8,7 +8,6 @@ import {
} from '@angular/core';
import { UtilityService } from 'src/app/shared/_services/utility.service';
import { Chapter } from 'src/app/_models/chapter';
import { ChapterMetadata } from 'src/app/_models/metadata/chapter-metadata';
import { HourEstimateRange } from 'src/app/_models/series-detail/hour-estimate-range';
import { MangaFormat } from 'src/app/_models/manga-format';
import { AgeRating } from 'src/app/_models/metadata/age-rating';
@ -51,10 +50,6 @@ export class EntityInfoCardsComponent implements OnInit {
@Input({required: true}) entity!: Volume | Chapter;
@Input({required: true}) libraryId!: number;
/**
* This will pull extra information
*/
@Input() includeMetadata: boolean = false;
/**
* Hide more system based fields, like id or Date Added
@ -64,7 +59,6 @@ export class EntityInfoCardsComponent implements OnInit {
isChapter = false;
chapter!: Chapter;
chapterMetadata!: ChapterMetadata;
ageRating!: string;
totalPages: number = 0;
totalWordCount: number = 0;
@ -94,12 +88,6 @@ export class EntityInfoCardsComponent implements OnInit {
}, 0);
}
if (this.includeMetadata) {
this.seriesService.getChapterMetadata(this.chapter.id).subscribe(metadata => {
this.chapterMetadata = metadata;
this.cdRef.markForCheck();
});
}
this.totalPages = this.chapter.pages;
if (!this.isChapter) {

View File

@ -31,7 +31,7 @@
</div>
</ng-container>
<div class="ps-2 d-none d-md-inline-block" style="width: 100%">
<app-entity-info-cards [entity]="entity" [libraryId]="libraryId" [includeMetadata]="ShowExtended" [showExtendedProperties]="ShowExtended"></app-entity-info-cards>
<app-entity-info-cards [entity]="entity" [libraryId]="libraryId" [showExtendedProperties]="ShowExtended"></app-entity-info-cards>
</div>
</div>
</div>

View File

@ -30,6 +30,7 @@
<div infinite-scroll [infiniteScrollDistance]="1" [infiniteScrollThrottle]="50">
<ng-container *ngFor="let item of webtoonImages | async; let index = index;">
<img src="{{item.src}}" style="display: block"
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
class="mx-auto {{pageNum === item.page && showDebugOutline() ? 'active': ''}} {{areImagesWiderThanWindow ? 'full-width' : ''}}"
rel="nofollow" alt="image" (load)="onImageLoad($event)" id="page-{{item.page}}" [attr.page]="item.page" ondragstart="return false;" onselectstart="return false;">
</ng-container>

View File

@ -16,7 +16,7 @@ import {
Renderer2,
SimpleChanges, ViewChild
} from '@angular/core';
import { BehaviorSubject, fromEvent, ReplaySubject } from 'rxjs';
import {BehaviorSubject, filter, fromEvent, map, Observable, of, ReplaySubject} from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { ScrollService } from 'src/app/_services/scroll.service';
import { ReaderService } from '../../../_services/reader.service';
@ -27,6 +27,8 @@ import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {TranslocoDirective} from "@ngneat/transloco";
import {MangaReaderComponent} from "../manga-reader/manga-reader.component";
import {InfiniteScrollModule} from "ngx-infinite-scroll";
import {ReaderSetting} from "../../_models/reader-setting";
import {SafeStylePipe} from "../../../_pipes/safe-style.pipe";
/**
* How much additional space should pass, past the original bottom of the document height before we trigger the next chapter load
@ -61,7 +63,7 @@ const enum DEBUG_MODES {
styleUrls: ['./infinite-scroller.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [NgIf, NgFor, AsyncPipe, TranslocoDirective, InfiniteScrollModule]
imports: [NgIf, NgFor, AsyncPipe, TranslocoDirective, InfiniteScrollModule, SafeStylePipe]
})
export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit {
@ -70,6 +72,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy,
private readonly renderer = inject(Renderer2);
private readonly scrollService = inject(ScrollService);
private readonly cdRef = inject(ChangeDetectorRef);
private readonly destroyRef = inject(DestroyRef);
/**
* Current page number aka what's recorded on screen
@ -87,6 +90,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy,
* Method to generate the src for Image loading
*/
@Input({required: true}) urlProvider!: (page: number) => string;
@Input({required: true}) readerSettings$!: Observable<ReaderSetting>;
@Output() pageNumberChange: EventEmitter<number> = new EventEmitter<number>();
@Output() loadNextChapter: EventEmitter<void> = new EventEmitter<void>();
@Output() loadPrevChapter: EventEmitter<void> = new EventEmitter<void>();
@ -99,7 +103,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy,
bottomSpacerIntersectionObserver: IntersectionObserver = new IntersectionObserver((entries) => this.handleBottomIntersection(entries),
{ threshold: 1.0 });
private readonly destroyRef = inject(DestroyRef);
darkness$: Observable<string> = of('brightness(100%)');
readerElemRef!: ElementRef<HTMLDivElement>;
@ -223,6 +227,11 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy,
this.recalculateImageWidth();
this.darkness$ = this.readerSettings$.pipe(
map(values => 'brightness(' + values.darkness + '%)'),
takeUntilDestroyed(this.destroyRef)
);
if (this.goToPage) {
this.goToPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
const isSamePage = this.pageNum === page;

View File

@ -28,11 +28,13 @@
<i class="fa-regular fa-rectangle-list" aria-hidden="true"></i>
<span class="visually-hidden">{{t('shortcuts-menu-alt')}}</span>
</button>
<button *ngIf="!bookmarkMode && hasBookmarkRights" class="btn btn-icon" role="checkbox" [attr.aria-checked]="CurrentPageBookmarked"
title="{{t(CurrentPageBookmarked ? 'unbookmark-page-tooltip' : 'bookmark-page-tooltip')}}" (click)="bookmarkPage()">
<i class="{{CurrentPageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i>
<span class="visually-hidden">{{t(CurrentPageBookmarked ? 'unbookmark-page-tooltip' : 'bookmark-page-tooltip')}}</span>
</button>
@if (!bookmarkMode && hasBookmarkRights) {
<button class="btn btn-icon" role="checkbox" [attr.aria-checked]="CurrentPageBookmarked"
title="{{t(CurrentPageBookmarked ? 'unbookmark-page-tooltip' : 'bookmark-page-tooltip')}}" (click)="bookmarkPage()">
<i class="{{CurrentPageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i>
<span class="visually-hidden">{{t(CurrentPageBookmarked ? 'unbookmark-page-tooltip' : 'bookmark-page-tooltip')}}</span>
</button>
}
</div>
</div>
</div>
@ -118,7 +120,8 @@
(loadNextChapter)="loadNextChapter()"
(loadPrevChapter)="loadPrevChapter()"
[bookmarkPage]="showBookmarkEffectEvent"
[fullscreenToggled]="fullscreenEvent">
[fullscreenToggled]="fullscreenEvent"
[readerSettings$]="readerSettings$">
</app-infinite-scroller>
</div>
</ng-template>

View File

@ -2,12 +2,14 @@
<div class="d-flex flex-row g-0 mb-2 reading-list-item">
<div class="pe-2">
<app-image width="106px" maxHeight="125px" class="img-top me-3" [imageUrl]="imageService.getChapterCoverImage(item.chapterId)"></app-image>
<ng-container *ngIf="item.pagesRead === 0 && item.pagesTotal > 0">
@if (item.pagesRead === 0 && item.pagesTotal > 0) {
<div class="not-read-badge" ></div>
</ng-container>
<div class="progress-banner" *ngIf="item.pagesRead < item.pagesTotal && item.pagesTotal > 0 && item.pagesRead !== item.pagesTotal">
<p><ngb-progressbar type="primary" height="5px" [value]="item.pagesRead" [max]="item.pagesTotal"></ngb-progressbar></p>
</div>
}
@if (item.pagesRead < item.pagesTotal && item.pagesTotal > 0 && item.pagesRead !== item.pagesTotal) {
<div class="progress-banner">
<p><ngb-progressbar type="primary" height="5px" [value]="item.pagesRead" [max]="item.pagesTotal"></ngb-progressbar></p>
</div>
}
</div>
<div class="flex-grow-1">
@ -37,9 +39,11 @@
<!-- TODO: Let's add summary here-->
<div class="ps-1 mt-2" *ngIf="item.releaseDate !== '0001-01-01T00:00:00'">
Released: {{item.releaseDate | date:'longDate'}}
</div>
@if (item.releaseDate !== '0001-01-01T00:00:00') {
<div class="ps-1 mt-2">
Released: {{item.releaseDate | date:'longDate'}}
</div>
}
</div>
</div>

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import {ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output} from '@angular/core';
import { LibraryType } from 'src/app/_models/library/library';
import { MangaFormat } from 'src/app/_models/manga-format';
import { ReadingListItem } from 'src/app/_models/reading-list';
@ -6,7 +6,7 @@ import { ImageService } from 'src/app/_services/image.service';
import { MangaFormatIconPipe } from '../../../_pipes/manga-format-icon.pipe';
import { MangaFormatPipe } from '../../../_pipes/manga-format.pipe';
import { NgbProgressbar } from '@ng-bootstrap/ng-bootstrap';
import { NgIf, DatePipe } from '@angular/common';
import { DatePipe } from '@angular/common';
import { ImageComponent } from '../../../shared/image/image.component';
import {TranslocoDirective} from "@ngneat/transloco";
import {SeriesFormatComponent} from "../../../shared/series-format/series-format.component";
@ -17,10 +17,13 @@ import {SeriesFormatComponent} from "../../../shared/series-format/series-format
styleUrls: ['./reading-list-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ImageComponent, NgIf, NgbProgressbar, DatePipe, MangaFormatPipe, MangaFormatIconPipe, TranslocoDirective, SeriesFormatComponent]
imports: [ImageComponent, NgbProgressbar, DatePipe, MangaFormatPipe, MangaFormatIconPipe, TranslocoDirective, SeriesFormatComponent]
})
export class ReadingListItemComponent {
protected readonly imageService = inject(ImageService);
protected readonly MangaFormat = MangaFormat;
@Input({required: true}) item!: ReadingListItem;
@Input() position: number = 0;
@Input() libraryTypes: {[key: number]: LibraryType} = {};
@ -32,15 +35,7 @@ export class ReadingListItemComponent {
@Output() read: EventEmitter<ReadingListItem> = new EventEmitter();
@Output() remove: EventEmitter<ReadingListItem> = new EventEmitter();
get MangaFormat(): typeof MangaFormat {
return MangaFormat;
}
constructor(public imageService: ImageService) { }
readChapter(item: ReadingListItem) {
this.read.emit(item);
}
}

View File

@ -7,7 +7,7 @@
"name": "GPL-3.0",
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
},
"version": "0.8.0.3"
"version": "0.8.0.4"
},
"servers": [
{
@ -14716,6 +14716,138 @@
"type": "string",
"description": "ISBN-13 (usually) of the Chapter",
"nullable": true
},
"writers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"coverArtists": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"publishers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"characters": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"pencillers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"inkers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"imprints": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"colorists": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"letterers": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"editors": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"translators": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"teams": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"locations": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonDto"
},
"nullable": true
},
"genres": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenreTagDto"
},
"nullable": true
},
"tags": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TagDto"
},
"description": "Collection of all Tags from underlying chapters for a Series",
"nullable": true
},
"publicationStatus": {
"enum": [
0,
1,
2,
3,
4
],
"type": "integer",
"format": "int32"
},
"language": {
"type": "string",
"description": "Language for the Chapter/Issue",
"nullable": true
},
"count": {
"type": "integer",
"description": "Number in the TotalCount of issues",
"format": "int32"
},
"totalCount": {
"type": "integer",
"description": "Total number of issues for the series",
"format": "int32"
}
},
"additionalProperties": false,