Kavita/UI/Web/src/app/manga-reader/manga-reader.component.html
Joseph Milazzo ba77954d5c
Metadata Editing from the UI! (#1135)
* Added the skeleton code for layout, hooked up Age Rating, Publication Status, and Tags

* Tweaked message of Scan service to Finished scan of to better indicate the total scan time

* Hooked in foundation for person typeaheads

* Fixed people not populating typeaheads on load

* For manga/comics, when parsing, set the SeriesSort from ComicInfo if it exists.

* Implemented the ability to override and create new genre tags. Code is ready to flush out the rest.

* Ability to update metadata from the UI is hooked up. Next is locking.

* Updated typeahead to allow for non-multiple usage. Implemented ability to update Language tag in Series Metadata.

* Fixed a bug in GetContinuePoint for a case where we have Volumes, Loose Leaf chapters and no read progress.

* Added ETag headers on Images to allow for better caching (bookmarks and images in manga reader)

* Built out UI code to show locked indication to user

* Implemented Series locking and refactored a lot of styles in typeahead to make the lock setting work, plus misc cleanup.

* Added locked properties to dtos. Updated typeahead loading indicator to not interfere with close button if present

* Hooked up locking flags in UI

* Integrated regular field locking/unlocking

* Removed some old code

* Prevent input group from wrapping

* Implemented some basic layout for metadata on volume/chapter card modal. Refactored out all metadata from Chapter object in terms of UI and put into a separate call to ensure speedy delivery and simplicity of code.

* Refactored code to hide covers section if not an admin

* Implemented ability to modify a chapter/volume cover from the detail modal

* Removed a few variables and change cover image modal

* Added bookmark to single chapter view

* Put a temp fix in for a ngb v12 z-index bug (reported). Bumped ngb to 12.0 stable and fixed some small rendering bugs

* loading buttons ftw

* Lots of cleanup, looks like the story is finished

* Changed action name from Info to Details

* Style tweaks

* Fixed an issue where Summary would assume it's locked due to a subscription firing on setting the model

* Fixed some misc bugs

* Code smells

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
2022-03-04 13:04:15 -08:00

154 lines
No EOL
10 KiB
HTML

<div class="reader" #reader [ngStyle]="{overflow: (isFullscreen ? 'auto' : 'visible')}">
<div class="fixed-top overlay" *ngIf="menuOpen" [@slideFromTop]="menuOpen">
<div style="display: flex; margin-top: 5px;">
<button class="btn btn-icon" style="height: 100%" title="Back" (click)="closeReader()">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
<span class="visually-hidden">Back</span>
</button>
<div>
<div style="font-weight: bold;">{{title}} <span class="clickable" *ngIf="incognitoMode" (click)="turnOffIncognito()" role="button" aria-label="Incognito mode is on. Toggle to turn off.">(<i class="fa fa-glasses" aria-hidden="true"></i><span class="visually-hidden">Incognito Mode:</span>)</span></div>
<div class="subtitle">
{{subtitle}}
</div>
</div>
<div style="margin-left: auto; padding-right: 3%;">
<button class="btn btn-icon btn-small" role="checkbox" [attr.aria-checked]="pageBookmarked" title="{{pageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}" (click)="bookmarkPage()"><i class="{{pageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i><span class="visually-hidden">{{pageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}</span></button>
</div>
</div>
</div>
<ng-container *ngIf="isLoading">
<div class="spinner-border text-secondary loading" role="status">
<span class="invisible">Loading...</span>
</div>
</ng-container>
<div (click)="toggleMenu()" class="reading-area">
<!-- TODO: Change this logic to only render for split pages and use image for all else-->
<canvas style="display: none;" #content class="{{getFittingOptionClass()}} {{readerMode === READER_MODE.MANGA_LR || readerMode === READER_MODE.MANGA_UD ? '' : 'd-none'}} {{showClickOverlay ? 'blur' : ''}}"
ondragstart="return false;" onselectstart="return false;">
</canvas>
<div *ngIf="isCoverImage && shouldRenderAsFitSplit()">
<img [src]="canvasImage.src" class="{{getFittingOptionClass()}} {{readerMode === READER_MODE.MANGA_LR || readerMode === READER_MODE.MANGA_UD ? '' : 'd-none'}} {{showClickOverlay ? 'blur' : ''}}">
</div>
<div class="webtoon-images" *ngIf="readerMode === READER_MODE.WEBTOON && !isLoading && !inSetup">
<app-infinite-scroller [pageNum]="pageNum"
[bufferPages]="5"
[goToPage]="goToPageEvent"
(pageNumberChange)="handleWebtoonPageChange($event)"
[totalPages]="maxPages"
[urlProvider]="getPageUrl"
(loadNextChapter)="loadNextChapter()"
(loadPrevChapter)="loadPrevChapter()"
[bookmarkPage]="showBookmarkEffectEvent"
[fullscreenToggled]="fullscreenEvent"></app-infinite-scroller>
</div>
<ng-container *ngIf="readerMode === READER_MODE.MANGA_LR || readerMode === READER_MODE.MANGA_UD">
<div class="pagination-area {{readerMode === READER_MODE.MANGA_LR ? 'right' : 'bottom'}} {{clickOverlayClass('right')}}" (click)="handlePageChange($event, 'right')">
<div *ngIf="showClickOverlay">
<i class="fa fa-angle-{{readingDirection === ReadingDirection.LeftToRight ? 'double-' : ''}}{{readerMode === READER_MODE.MANGA_LR ? 'right' : 'down'}}"
title="Next Page" aria-hidden="true"></i>
</div>
</div>
<div class="pagination-area {{readerMode === READER_MODE.MANGA_LR ? 'left' : 'top'}} {{clickOverlayClass('left')}}" (click)="handlePageChange($event, 'left')">
<div *ngIf="showClickOverlay">
<i class="fa fa-angle-{{readingDirection === ReadingDirection.RightToLeft ? 'double-' : ''}}{{readerMode === READER_MODE.MANGA_LR ? 'left' : 'up'}}"
title="Previous Page" aria-hidden="true"></i>
</div>
</div>
</ng-container>
</div>
<div class="fixed-bottom overlay" *ngIf="menuOpen" [@slideFromBottom]="menuOpen">
<div class="mb-3" *ngIf="pageOptions != undefined && pageOptions.ceil != undefined">
<span class="visually-hidden" id="slider-info"></span>
<div class="row g-0">
<button class="btn btn-small btn-icon col-1" [disabled]="prevChapterDisabled" (click)="loadPrevChapter();resetMenuCloseTimer();" title="Prev Chapter/Volume"><i class="fa fa-fast-backward" aria-hidden="true"></i></button>
<button class="btn btn-small btn-icon col-1" [disabled]="prevPageDisabled || pageNum === 0" (click)="goToPage(0);resetMenuCloseTimer();" title="First Page"><i class="fa fa-step-backward" aria-hidden="true"></i></button>
<div class="col custom-slider" *ngIf="pageOptions.ceil > 0; else noSlider">
<ngx-slider [options]="pageOptions" [value]="pageNum" aria-describedby="slider-info" [manualRefresh]="refreshSlider" (userChangeEnd)="sliderPageUpdate($event);startMenuCloseTimer()" (userChange)="sliderDragUpdate($event)" (userChangeStart)="cancelMenuCloseTimer();"></ngx-slider>
</div>
<ng-template #noSlider>
<div class="col custom-slider">
<ngx-slider [options]="pageOptions" [value]="pageNum" aria-describedby="slider-info" (userChangeEnd)="startMenuCloseTimer()" (userChangeStart)="cancelMenuCloseTimer();"></ngx-slider>
</div>
</ng-template>
<button class="btn btn-small btn-icon col-2" [disabled]="nextPageDisabled || pageNum >= maxPages - 1" (click)="goToPage(this.maxPages);resetMenuCloseTimer();" title="Last Page"><i class="fa fa-step-forward" aria-hidden="true"></i></button>
<button class="btn btn-small btn-icon col-1" [disabled]="nextChapterDisabled" (click)="loadNextChapter();resetMenuCloseTimer();" title="Next Chapter/Volume"><i class="fa fa-fast-forward" aria-hidden="true"></i></button>
</div>
</div>
<div class="row pt-4 ms-2 me-2">
<div class="col">
<button class="btn btn-icon" (click)="setReadingDirection();resetMenuCloseTimer();" [disabled]="readerMode === READER_MODE.WEBTOON || readerMode === READER_MODE.MANGA_UD" aria-describedby="reading-direction" title="Reading Direction: {{readingDirection === ReadingDirection.LeftToRight ? 'Left to Right' : 'Right to Left'}}">
<i class="fa fa-angle-double-{{readingDirection === ReadingDirection.LeftToRight ? 'right' : 'left'}}" aria-hidden="true"></i>
<span id="reading-direction" class="visually-hidden">{{readingDirection === ReadingDirection.LeftToRight ? 'Left to Right' : 'Right to Left'}}</span>
</button>
</div>
<div class="col">
<button class="btn btn-icon" title="Reading Mode" (click)="toggleReaderMode();resetMenuCloseTimer();">
<i class="fa {{readerModeIcon}}" aria-hidden="true"></i>
<span class="visually-hidden">Reading Mode</span>
</button>
</div>
<div class="col">
<button class="btn btn-icon" title="{{this.isFullscreen ? 'Collapse' : 'Fullscreen'}}" (click)="toggleFullscreen();resetMenuCloseTimer();">
<i class="fa {{this.isFullscreen ? 'fa-compress-alt' : 'fa-expand-alt'}}" aria-hidden="true"></i>
<span class="visually-hidden">{{this.isFullscreen ? 'Collapse' : 'Fullscreen'}}</span>
</button>
</div>
<div class="col">
<button class="btn btn-icon" title="Settings" (click)="settingsOpen = !settingsOpen;resetMenuCloseTimer();">
<i class="fa fa-sliders-h" aria-hidden="true"></i>
<span class="visually-hidden">Settings</span>
</button>
</div>
</div>
<div class="bottom-menu" *ngIf="settingsOpen && generalSettingsForm">
<form [formGroup]="generalSettingsForm">
<div class="row">
<div class="col-6">
<label for="page-splitting" class="form-label">Image Splitting</label>&nbsp;
<div class="split fa fa-image">
<div class="{{splitIconClass}}"></div>
</div>
</div>
<div class="col-6">
<div class="mb-3">
<select class="form-control" id="page-splitting" formControlName="pageSplitOption">
<option *ngFor="let opt of pageSplitOptions" [value]="opt.value">{{opt.text}}</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<label for="page-fitting" class="form-label">Image Scaling</label>&nbsp;<i class="fa {{getFittingIcon()}}" aria-hidden="true"></i>
</div>
<div class="col-6">
<select class="form-control" id="page-fitting" formControlName="fittingOption">
<option value="full-height">Height</option>
<option value="full-width">Width</option>
<option value="original">Original</option>
</select>
</div>
</div>
<div class="row mt-2 mb-2">
<div class="col-6">
<label for="autoCloseMenu" class="form-check-label">Auto Close Menu</label>
</div>
<div class="col-6">
<div class="form-check">
<input id="autoCloseMenu" type="checkbox" aria-label="Admin" class="form-check-input" formControlName="autoCloseMenu">
</div>
</div>
</div>
</form>
</div>
</div>
</div>