On Deck + Misc Fixes and Changes (#1215)
* Added playwright and started writing e2e tests. * To make things easy, disabled other browsers while I get confortable. Added a login flow (assumes my dev env) * More tests on login page * Lots more testing code, trying to figure out auth code. * Ensure we don't track DBs inside config * Added a new date property for when chapters are added to a series which helps with OnDeck calculations. Changed a lot of heavy api calls to use IEnumerable to stream repsonse to UI. * Fixed OnDeck with a new field for when last chapter was added on Series. This is a streamlined way to query. Updated Reading List with NormalizedTitle, CoverImage, CoverImageLocked. * Implemented the ability to read a random item in the reading list and for the reading list to be intact for order. * Tweaked the style for webtoon to not span the whole width, but use max width * When we update a cover image just send an event so we don't need to have logic for when updates occur * Fixed a bad name for entity type on cover updates * Aligned the edit collection tag modal to align with new tab design * Rewrote code for picking the first file for metadata to ensure it always picks the correct file, esp if the first chapter of a series starts with a float (1.1) * Refactored setting LastChapterAdded to ensure we do it on the Series. * Updated Chapter updating in scan loop to avoid nested for loop and an additional loop. * Fixed a bug where locked person fields wouldn't persist between scans. * Updated Contributing to reflect how to view the swagger api
This commit is contained in:
parent
912dfa8a80
commit
3bbb02f574
64 changed files with 3397 additions and 343 deletions
|
|
@ -19,5 +19,6 @@ export interface ReadingList {
|
|||
title: string;
|
||||
summary: string;
|
||||
promoted: boolean;
|
||||
coverImageLocked: boolean;
|
||||
items: Array<ReadingListItem>;
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ export interface SeriesMetadata {
|
|||
tagsLocked: boolean;
|
||||
writersLocked: boolean;
|
||||
coverArtistsLocked: boolean;
|
||||
publishersLocked: boolean;
|
||||
publisherLocked: boolean;
|
||||
charactersLocked: boolean;
|
||||
pencillersLocked: boolean;
|
||||
inkersLocked: boolean;
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ export class ActionService implements OnDestroy {
|
|||
}
|
||||
|
||||
editReadingList(readingList: ReadingList, callback?: ReadingListActionCallback) {
|
||||
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'md' });
|
||||
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'lg' });
|
||||
readingListModalRef.componentInstance.readingList = readingList;
|
||||
readingListModalRef.closed.pipe(take(1)).subscribe((list) => {
|
||||
if (callback && list !== undefined) {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ export class ImageService implements OnDestroy {
|
|||
return this.baseUrl + 'image/collection-cover?collectionTagId=' + collectionTagId;
|
||||
}
|
||||
|
||||
getReadingListCoverImage(readingListId: number) {
|
||||
return this.baseUrl + 'image/readinglist-cover?readingListId=' + readingListId;
|
||||
}
|
||||
|
||||
getChapterCoverImage(chapterId: number) {
|
||||
return this.baseUrl + 'image/chapter-cover?chapterId=' + chapterId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,9 +133,6 @@ export class SeriesService {
|
|||
getRecentlyUpdatedSeries() {
|
||||
return this.httpClient.post<SeriesGroup[]>(this.baseUrl + 'series/recently-updated-series', {});
|
||||
}
|
||||
getRecentlyAddedChapters() {
|
||||
return this.httpClient.post<RecentlyAddedItem[]>(this.baseUrl + 'series/recently-added-chapters', {});
|
||||
}
|
||||
|
||||
getOnDeck(libraryId: number = 0, pageNum?: number, itemsPerPage?: number, filter?: SeriesFilter) {
|
||||
const data = this.createSeriesFilter(filter);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ export class UploadService {
|
|||
return this.httpClient.post<number>(this.baseUrl + 'upload/collection', {id: tagId, url: this._cleanBase64Url(url)});
|
||||
}
|
||||
|
||||
updateReadingListCoverImage(readingListId: number, url: string) {
|
||||
return this.httpClient.post<number>(this.baseUrl + 'upload/reading-list', {id: readingListId, url: this._cleanBase64Url(url)});
|
||||
}
|
||||
|
||||
updateChapterCoverImage(chapterId: number, url: string) {
|
||||
return this.httpClient.post<number>(this.baseUrl + 'upload/chapter', {id: chapterId, url: this._cleanBase64Url(url)});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
<span class="d-none d-sm-block"> {{readingDirection === ReadingDirection.LeftToRight ? 'Previous' : 'Next'}}</span>
|
||||
</button>
|
||||
<button *ngIf="!this.adhocPageHistory.isEmpty()" class="btn btn-outline-secondary btn-icon col-2 col-xs-1" (click)="goBack()" title="Go Back"><i class="fa fa-reply" aria-hidden="true"></i><span class="d-none d-sm-block"> Go Back</span></button>
|
||||
<button class="btn btn-secondary col-2 col-xs-1" (click)="toggleDrawer()"><i class="fa fa-bars" aria-hidden="true"></i><span class="d-none d-sm-block">Settings {{drawerOpen}}</span></button>
|
||||
<button class="btn btn-secondary col-2 col-xs-1" (click)="toggleDrawer()"><i class="fa fa-bars" aria-hidden="true"></i><span class="d-none d-sm-block">Settings</span></button>
|
||||
<div class="book-title col-2 d-none d-sm-block">
|
||||
<ng-container *ngIf="isLoading; else showTitle">
|
||||
<div class="spinner-border spinner-border-sm text-primary" style="border-radius: 50%;" role="status">
|
||||
|
|
|
|||
|
|
@ -5,16 +5,15 @@
|
|||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
This tag is currently {{tag?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
|
||||
Promotion means that the tag can be seen server-wide, not just for admin users. All series that have this tag will still have user-access restrictions placed on them.
|
||||
</p>
|
||||
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs nav-pills">
|
||||
<div class="modal-body {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? '' : 'd-flex'}}">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="{{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'horizontal' : 'vertical'}}" style="min-width: 135px;">
|
||||
<li [ngbNavItem]="tabs[0]">
|
||||
<a ngbNavLink>{{tabs[0]}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<p>
|
||||
This tag is currently {{tag?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
|
||||
Promotion means that the tag can be seen server-wide, not just for admin users. All series that have this tag will still have user-access restrictions placed on them.
|
||||
</p>
|
||||
<form [formGroup]="collectionTagForm">
|
||||
<div class="mb-3">
|
||||
<label for="summary" class="form-label">Summary</label>
|
||||
|
|
@ -62,7 +61,7 @@
|
|||
</ul>
|
||||
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-3"></div>
|
||||
<div [ngbNavOutlet]="nav" class="mt-3 ms-2"></div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
|||
import { ToastrService } from 'ngx-toastr';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { ConfirmService } from 'src/app/shared/confirm.service';
|
||||
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
|
||||
import { SelectionModel } from 'src/app/typeahead/typeahead.component';
|
||||
import { CollectionTag } from 'src/app/_models/collection-tag';
|
||||
import { Pagination } from 'src/app/_models/pagination';
|
||||
|
|
@ -14,6 +15,7 @@ import { LibraryService } from 'src/app/_services/library.service';
|
|||
import { SeriesService } from 'src/app/_services/series.service';
|
||||
import { UploadService } from 'src/app/_services/upload.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-collection-tags',
|
||||
templateUrl: './edit-collection-tags.component.html',
|
||||
|
|
@ -39,11 +41,15 @@ export class EditCollectionTagsComponent implements OnInit {
|
|||
return this.selections != null && this.selections.hasSomeSelected();
|
||||
}
|
||||
|
||||
get Breakpoint() {
|
||||
return Breakpoint;
|
||||
}
|
||||
|
||||
constructor(public modal: NgbActiveModal, private seriesService: SeriesService,
|
||||
private collectionService: CollectionTagService, private toastr: ToastrService,
|
||||
private confirmSerivce: ConfirmService, private libraryService: LibraryService,
|
||||
private imageService: ImageService, private uploadService: UploadService) { }
|
||||
private imageService: ImageService, private uploadService: UploadService,
|
||||
public utilityService: UtilityService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.pagination == undefined) {
|
||||
|
|
|
|||
|
|
@ -192,8 +192,8 @@
|
|||
<div class="mb-3">
|
||||
<label for="publisher" class="form-label">Publisher</label>
|
||||
<app-typeahead (selectedData)="updatePerson($event, PersonRole.Publisher)" [settings]="getPersonsSettings(PersonRole.Publisher)"
|
||||
[(locked)]="metadata.publishersLocked" (onUnlock)="metadata.publishersLocked = false"
|
||||
(newItemAdded)="metadata.publishersLocked = true" (selectedData)="metadata.publishersLocked = true">
|
||||
[(locked)]="metadata.publisherLocked" (onUnlock)="metadata.publisherLocked = false"
|
||||
(newItemAdded)="metadata.publisherLocked = true" (selectedData)="metadata.publisherLocked = true">
|
||||
<ng-template #badgeItem let-item let-position="idx">
|
||||
{{item.name}}
|
||||
</ng-template>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
</ng-template>
|
||||
</app-carousel-reel>
|
||||
|
||||
<!-- TODO: Refactor this so we can use series actions here -->
|
||||
<app-carousel-reel [items]="recentlyUpdatedSeries" title="Recently Updated Series" (sectionClick)="handleSectionClick($event)">
|
||||
<ng-template #carouselItem let-item let-position="idx">
|
||||
<app-card-item [entity]="item" [title]="item.seriesName" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"
|
||||
|
|
@ -27,11 +26,4 @@
|
|||
<ng-template #carouselItem let-item let-position="idx">
|
||||
<app-series-card [data]="item" [libraryId]="item.libraryId" (dataChanged)="loadRecentlyAddedSeries()"></app-series-card>
|
||||
</ng-template>
|
||||
</app-carousel-reel>
|
||||
|
||||
<!-- <app-carousel-reel [items]="recentlyAddedChapters" title="Recently Added" (sectionClick)="handleSectionClick($event)">
|
||||
<ng-template #carouselItem let-item let-position="idx">
|
||||
<app-card-item [entity]="item" [title]="item.title" [subtitle]="item.seriesName" [imageUrl]="imageService.getRecentlyAddedItem(item)"
|
||||
[supressArchiveWarning]="true" (clicked)="handleRecentlyAddedChapterClick(item)"></app-card-item>
|
||||
</ng-template>
|
||||
</app-carousel-reel> -->
|
||||
</app-carousel-reel>
|
||||
|
|
@ -29,7 +29,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||
isAdmin = false;
|
||||
|
||||
recentlyUpdatedSeries: SeriesGroup[] = [];
|
||||
recentlyAddedChapters: RecentlyAddedItem[] = [];
|
||||
inProgress: Series[] = [];
|
||||
recentlyAddedSeries: Series[] = [];
|
||||
|
||||
|
|
@ -57,7 +56,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||
this.inProgress = this.inProgress.filter(item => item.id != seriesRemovedEvent.seriesId);
|
||||
this.recentlyAddedSeries = this.recentlyAddedSeries.filter(item => item.id != seriesRemovedEvent.seriesId);
|
||||
this.recentlyUpdatedSeries = this.recentlyUpdatedSeries.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
|
||||
this.recentlyAddedChapters = this.recentlyAddedChapters.filter(item => item.seriesId != seriesRemovedEvent.seriesId);
|
||||
} else if (res.event === EVENTS.ScanSeries) {
|
||||
// We don't have events for when series are updated, but we do get events when a scan update occurs. Refresh recentlyAdded at that time.
|
||||
this.loadRecentlyAdded$.next();
|
||||
|
|
@ -125,10 +123,6 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
|||
this.seriesService.getRecentlyUpdatedSeries().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
|
||||
this.recentlyUpdatedSeries = updatedSeries;
|
||||
});
|
||||
|
||||
this.seriesService.getRecentlyAddedChapters().pipe(takeUntil(this.onDestroy)).subscribe(updatedSeries => {
|
||||
this.recentlyAddedChapters = updatedSeries;
|
||||
});
|
||||
}
|
||||
|
||||
handleRecentlyAddedChapterClick(item: RecentlyAddedItem) {
|
||||
|
|
|
|||
|
|
@ -27,13 +27,10 @@
|
|||
|
||||
|
||||
img, .full-width {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// .img-container {
|
||||
// overflow: auto;
|
||||
// }
|
||||
|
||||
|
||||
@keyframes move-up-down {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,41 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Edit {{readingList.title}} Reading List</h4>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
This list is currently {{readingList?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
|
||||
Promotion means that the list can be seen server-wide, not just for admin users. All series that are within this list will still have user-access restrictions placed on them.
|
||||
</p>
|
||||
<form [formGroup]="reviewGroup">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">Name</label>
|
||||
<input id="title" class="form-control" formControlName="title" type="text">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="summary" class="form-label">Summary</label>
|
||||
<textarea id="summary" class="form-control" formControlName="summary" rows="3"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-body {{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? '' : 'd-flex'}}">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-pills" orientation="{{utilityService.getActiveBreakpoint() === Breakpoint.Mobile ? 'horizontal' : 'vertical'}}" style="min-width: 135px;">
|
||||
<li [ngbNavItem]="tabs[0]">
|
||||
<a ngbNavLink>{{tabs[0].title}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<p>
|
||||
This list is currently {{readingList?.promoted ? 'promoted' : 'not promoted'}} (<i class="fa fa-angle-double-up" aria-hidden="true"></i>).
|
||||
Promotion means that the list can be seen server-wide, not just for admin users. All series that are within this list will still have user-access restrictions placed on them.
|
||||
</p>
|
||||
<form [formGroup]="reviewGroup">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">Name</label>
|
||||
<input id="title" class="form-control" formControlName="title" type="text">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="summary" class="form-label">Summary</label>
|
||||
<textarea id="summary" class="form-control" formControlName="summary" rows="3"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="tabs[1]">
|
||||
<a ngbNavLink>{{tabs[1].title}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<p class="alert alert-primary" role="alert">
|
||||
Upload and choose a new cover image. Press Save to upload and override the cover.
|
||||
</p>
|
||||
<app-cover-image-chooser [(imageUrls)]="imageUrls" (imageSelected)="updateSelectedIndex($event)" (selectedBase64Url)="updateSelectedImage($event)" [showReset]="readingList.coverImageLocked" (resetClicked)="handleReset()"></app-cover-image-chooser>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="ms-2 mt-3"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" (click)="close()">Close</button>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { Breakpoint, UtilityService } from 'src/app/shared/_services/utility.service';
|
||||
import { ReadingList } from 'src/app/_models/reading-list';
|
||||
import { ImageService } from 'src/app/_services/image.service';
|
||||
import { ReadingListService } from 'src/app/_services/reading-list.service';
|
||||
import { UploadService } from 'src/app/_services/upload.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-reading-list-modal',
|
||||
|
|
@ -14,13 +20,33 @@ export class EditReadingListModalComponent implements OnInit {
|
|||
@Input() readingList!: ReadingList;
|
||||
reviewGroup!: FormGroup;
|
||||
|
||||
constructor(private ngModal: NgbActiveModal, private readingListService: ReadingListService) { }
|
||||
coverImageIndex: number = 0;
|
||||
/**
|
||||
* Url of the selected cover
|
||||
*/
|
||||
selectedCover: string = '';
|
||||
coverImageLocked: boolean = false;
|
||||
|
||||
imageUrls: Array<string> = [];
|
||||
|
||||
tabs = [{title: 'General', disabled: false}, {title: 'Cover', disabled: false}];
|
||||
active = this.tabs[0];
|
||||
|
||||
get Breakpoint() {
|
||||
return Breakpoint;
|
||||
}
|
||||
|
||||
constructor(private ngModal: NgbActiveModal, private readingListService: ReadingListService,
|
||||
public utilityService: UtilityService, private uploadService: UploadService, private toastr: ToastrService,
|
||||
private imageService: ImageService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.reviewGroup = new FormGroup({
|
||||
title: new FormControl(this.readingList.title, [Validators.required]),
|
||||
summary: new FormControl(this.readingList.summary, [])
|
||||
});
|
||||
|
||||
this.imageUrls.push(this.imageService.randomize(this.imageService.getReadingListCoverImage(this.readingList.id)));
|
||||
}
|
||||
|
||||
close() {
|
||||
|
|
@ -29,12 +55,22 @@ export class EditReadingListModalComponent implements OnInit {
|
|||
|
||||
save() {
|
||||
if (this.reviewGroup.value.title.trim() === '') return;
|
||||
const model = {...this.reviewGroup.value, readingListId: this.readingList.id, promoted: this.readingList.promoted};
|
||||
|
||||
this.readingListService.update(model).subscribe(() => {
|
||||
|
||||
const model = {...this.reviewGroup.value, readingListId: this.readingList.id, promoted: this.readingList.promoted, coverImageLocked: this.coverImageLocked};
|
||||
|
||||
const apis = [this.readingListService.update(model)];
|
||||
|
||||
if (this.selectedCover !== '') {
|
||||
apis.push(this.uploadService.updateReadingListCoverImage(this.readingList.id, this.selectedCover))
|
||||
}
|
||||
|
||||
forkJoin(apis).subscribe(results => {
|
||||
this.readingList.title = model.title;
|
||||
this.readingList.summary = model.summary;
|
||||
this.readingList.coverImageLocked = this.coverImageLocked;
|
||||
this.ngModal.close(this.readingList);
|
||||
this.toastr.success('Reading List updated');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -49,4 +85,16 @@ export class EditReadingListModalComponent implements OnInit {
|
|||
});
|
||||
}
|
||||
|
||||
updateSelectedIndex(index: number) {
|
||||
this.coverImageIndex = index;
|
||||
}
|
||||
|
||||
updateSelectedImage(url: string) {
|
||||
this.selectedCover = url;
|
||||
}
|
||||
|
||||
handleReset() {
|
||||
this.coverImageLocked = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,42 +3,48 @@
|
|||
<span *ngIf="actions.length > 0">
|
||||
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="readingList.title"></app-card-actionables>
|
||||
</span>
|
||||
{{readingList.title}} <span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>
|
||||
<span class="badge bg-primary rounded-pill" attr.aria-label="{{items.length}} total items">{{items.length}}</span>
|
||||
{{readingList?.title}} <span *ngIf="readingList?.promoted">(<i class="fa fa-angle-double-up" aria-hidden="true"></i>)</span>
|
||||
</h2>
|
||||
<h6 subtitle>{{items.length}} Items</h6>
|
||||
</app-side-nav-companion-bar>
|
||||
<div class="container-fluid mt-2" *ngIf="readingList">
|
||||
<div class="mb-3">
|
||||
<!-- Action row-->
|
||||
<div class="row g-0">
|
||||
<div class="col-auto me-2">
|
||||
<button class="btn btn-primary" title="Read" (click)="read()">
|
||||
<span>
|
||||
<i class="fa fa-book-open" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> Read</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-secondary" (click)="removeRead()" [disabled]="readingList?.promoted && !this.isAdmin">
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-2 col-xs-4 col-sm-6 d-none d-sm-block">
|
||||
<app-image maxWidth="300px" [imageUrl]="readingListImage"></app-image>
|
||||
</div>
|
||||
<div class="col-md-10 col-xs-8 col-sm-6 mt-2">
|
||||
<div class="row g-0 mb-3">
|
||||
<div class="col-auto me-2">
|
||||
<!-- Action row-->
|
||||
<button class="btn btn-primary" title="Read" (click)="read()">
|
||||
<span>
|
||||
<i class="fa fa-check"></i>
|
||||
<i class="fa fa-book-open" aria-hidden="true"></i>
|
||||
<span class="read-btn--text"> Read</span> <!-- IDEA: We can provide them the ability to read/continue like we do with a series -->
|
||||
</span>
|
||||
<span class="read-btn--text"> Remove Read</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto ms-2 mt-2" *ngIf="!(readingList?.promoted && !this.isAdmin)">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="accessibilit-mode" [value]="accessibilityMode" (change)="accessibilityMode = !accessibilityMode">
|
||||
<label class="form-check-label" for="accessibilit-mode">Order Numbers</label>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button class="btn btn-secondary" (click)="removeRead()" [disabled]="readingList?.promoted && !this.isAdmin">
|
||||
<span>
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
<span class="read-btn--text"> Remove Read</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-auto ms-2 mt-2" *ngIf="!(readingList?.promoted && !this.isAdmin)">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" id="accessibilit-mode" [value]="accessibilityMode" (change)="accessibilityMode = !accessibilityMode">
|
||||
<label class="form-check-label" for="accessibilit-mode">Order Numbers</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Summary row-->
|
||||
<div class="row g-0 mt-2">
|
||||
<app-read-more [text]="readingListSummary" [maxLength]="250"></app-read-more>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Summary row-->
|
||||
<div class="row g-0 mt-2">
|
||||
<app-read-more [text]="readingListSummary" [maxLength]="250"></app-read-more>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div *ngIf="items.length === 0">
|
||||
No chapters added
|
||||
|
|
@ -63,6 +69,8 @@
|
|||
<span *ngIf="item.promoted">
|
||||
<i class="fa fa-angle-double-up" aria-hidden="true"></i>
|
||||
</span>
|
||||
<br/>
|
||||
<a href="javascript:void(0);" (click)="readChapter(item)">Read</a>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { ReadingListService } from 'src/app/_services/reading-list.service';
|
|||
import { IndexUpdateEvent, ItemRemoveEvent } from '../dragable-ordered-list/dragable-ordered-list.component';
|
||||
import { LibraryService } from '../../_services/library.service';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { ReaderService } from 'src/app/_services/reader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-reading-list-detail',
|
||||
|
|
@ -38,6 +39,8 @@ export class ReadingListDetailComponent implements OnInit {
|
|||
|
||||
libraryTypes: {[key: number]: LibraryType} = {};
|
||||
|
||||
readingListImage: string = '';
|
||||
|
||||
get MangaFormat(): typeof MangaFormat {
|
||||
return MangaFormat;
|
||||
}
|
||||
|
|
@ -45,7 +48,7 @@ export class ReadingListDetailComponent implements OnInit {
|
|||
constructor(private route: ActivatedRoute, private router: Router, private readingListService: ReadingListService,
|
||||
private actionService: ActionService, private actionFactoryService: ActionFactoryService, public utilityService: UtilityService,
|
||||
public imageService: ImageService, private accountService: AccountService, private toastr: ToastrService,
|
||||
private confirmService: ConfirmService, private libraryService: LibraryService) {}
|
||||
private confirmService: ConfirmService, private libraryService: LibraryService, private readerService: ReaderService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
const listId = this.route.snapshot.paramMap.get('id');
|
||||
|
|
@ -57,6 +60,8 @@ export class ReadingListDetailComponent implements OnInit {
|
|||
|
||||
this.listId = parseInt(listId, 10);
|
||||
|
||||
this.readingListImage = this.imageService.randomize(this.imageService.getReadingListCoverImage(this.listId));
|
||||
|
||||
this.libraryService.getLibraries().subscribe(libs => {
|
||||
|
||||
});
|
||||
|
|
@ -107,6 +112,15 @@ export class ReadingListDetailComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
readChapter(item: ReadingListItem) {
|
||||
let reader = 'manga';
|
||||
if (item.seriesFormat === MangaFormat.EPUB) {
|
||||
reader = 'book;'
|
||||
}
|
||||
const params = this.readerService.getQueryParamsObject(false, true, this.readingList.id);
|
||||
this.router.navigate(['library', item.libraryId, 'series', item.seriesId, 'book', item.chapterId], {queryParams: params});
|
||||
}
|
||||
|
||||
handleReadingListActionCallback(action: Action, readingList: ReadingList) {
|
||||
switch(action) {
|
||||
case Action.Delete:
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { EditReadingListModalComponent } from './_modals/edit-reading-list-modal
|
|||
import { PipeModule } from '../pipe/pipe.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { SidenavModule } from '../sidenav/sidenav.module';
|
||||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
|
||||
|
||||
|
|
@ -31,7 +32,8 @@ import { SidenavModule } from '../sidenav/sidenav.module';
|
|||
CardsModule,
|
||||
PipeModule,
|
||||
SharedModule,
|
||||
SidenavModule
|
||||
SidenavModule,
|
||||
NgbNavModule
|
||||
],
|
||||
exports: [
|
||||
AddToListModalComponent,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@
|
|||
(pageChange)="onPageChange($event)"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx">
|
||||
<app-card-item [title]="item.title" [entity]="item" [actions]="getActions(item)" [supressLibraryLink]="true" [imageUrl]="imageService.placeholderImage" (clicked)="handleClick(item)"></app-card-item>
|
||||
<app-card-item [title]="item.title" [entity]="item" [actions]="getActions(item)" [supressLibraryLink]="true" [imageUrl]="imageService.getReadingListCoverImage(item.id)" (clicked)="handleClick(item)"></app-card-item>
|
||||
</ng-template>
|
||||
</app-card-detail-layout>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue