mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-08-11 09:13:42 -04:00
Fix pagination in Manga reader from last PR (#1736)
* Added a new Double (No Cover) rendering mode which always has first 2 pages together unless wide. * Removed layout mode for build
This commit is contained in:
parent
1ccfecde76
commit
38cc601cc2
@ -43,6 +43,6 @@ export const readingDirections = [{text: 'Left to Right', value: ReadingDirectio
|
|||||||
export const scalingOptions = [{text: 'Automatic', value: ScalingOption.Automatic}, {text: 'Fit to Height', value: ScalingOption.FitToHeight}, {text: 'Fit to Width', value: ScalingOption.FitToWidth}, {text: 'Original', value: ScalingOption.Original}];
|
export const scalingOptions = [{text: 'Automatic', value: ScalingOption.Automatic}, {text: 'Fit to Height', value: ScalingOption.FitToHeight}, {text: 'Fit to Width', value: ScalingOption.FitToWidth}, {text: 'Original', value: ScalingOption.Original}];
|
||||||
export const pageSplitOptions = [{text: 'Fit to Screen', value: PageSplitOption.FitSplit}, {text: 'Right to Left', value: PageSplitOption.SplitRightToLeft}, {text: 'Left to Right', value: PageSplitOption.SplitLeftToRight}, {text: 'No Split', value: PageSplitOption.NoSplit}];
|
export const pageSplitOptions = [{text: 'Fit to Screen', value: PageSplitOption.FitSplit}, {text: 'Right to Left', value: PageSplitOption.SplitRightToLeft}, {text: 'Left to Right', value: PageSplitOption.SplitLeftToRight}, {text: 'No Split', value: PageSplitOption.NoSplit}];
|
||||||
export const readingModes = [{text: 'Left to Right', value: ReaderMode.LeftRight}, {text: 'Up to Down', value: ReaderMode.UpDown}, {text: 'Webtoon', value: ReaderMode.Webtoon}];
|
export const readingModes = [{text: 'Left to Right', value: ReaderMode.LeftRight}, {text: 'Up to Down', value: ReaderMode.UpDown}, {text: 'Webtoon', value: ReaderMode.Webtoon}];
|
||||||
export const layoutModes = [{text: 'Single', value: LayoutMode.Single}, {text: 'Double', value: LayoutMode.Double}, {text: 'Double (Manga)', value: LayoutMode.DoubleReversed}];
|
export const layoutModes = [{text: 'Single', value: LayoutMode.Single}, {text: 'Double', value: LayoutMode.Double}, {text: 'Double (Manga)', value: LayoutMode.DoubleReversed}]; // , {text: 'Double (No Cover)', value: LayoutMode.DoubleNoCover}
|
||||||
export const bookLayoutModes = [{text: 'Scroll', value: BookPageLayoutMode.Default}, {text: '1 Column', value: BookPageLayoutMode.Column1}, {text: '2 Column', value: BookPageLayoutMode.Column2}];
|
export const bookLayoutModes = [{text: 'Scroll', value: BookPageLayoutMode.Default}, {text: '1 Column', value: BookPageLayoutMode.Column1}, {text: '2 Column', value: BookPageLayoutMode.Column2}];
|
||||||
export const pageLayoutModes = [{text: 'Cards', value: PageLayoutMode.Cards}, {text: 'List', value: PageLayoutMode.List}];
|
export const pageLayoutModes = [{text: 'Cards', value: PageLayoutMode.Cards}, {text: 'List', value: PageLayoutMode.List}];
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
<ng-container *ngIf="isValid()">
|
||||||
|
<div class="image-container {{imageFitClass$ | async}} {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||||
|
[style.filter]="(darkenss$ | async) ?? '' | safeStyle"
|
||||||
|
[ngClass]="{'center-double': (shouldRenderDouble$ | async)}">
|
||||||
|
<ng-container *ngIf="currentImage">
|
||||||
|
<img alt=" "
|
||||||
|
#image [src]="currentImage.src"
|
||||||
|
id="image-1"
|
||||||
|
class="{{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}"
|
||||||
|
>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="shouldRenderDouble$ | async">
|
||||||
|
<img alt=" " [src]="currentImage2.src"
|
||||||
|
id="image-2"
|
||||||
|
class="image-2 {{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}">
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
@ -0,0 +1,50 @@
|
|||||||
|
@use '../../../../manga-reader-common';
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
#image-1 {
|
||||||
|
&.double {
|
||||||
|
margin: 0 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container.full-height {
|
||||||
|
display: inline-block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
vertical-align: top;
|
||||||
|
max-width: fit-content;
|
||||||
|
|
||||||
|
&.double {
|
||||||
|
width: 50%;
|
||||||
|
|
||||||
|
&.cover {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-double {
|
||||||
|
display: flex;
|
||||||
|
overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fit-to-width-double-offset {
|
||||||
|
max-width: 100%; // max-width fixes center alignment issue
|
||||||
|
}
|
||||||
|
|
||||||
|
.original-double-offset {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fit-to-height-double-offset {
|
||||||
|
height: 100vh;
|
||||||
|
object-fit: scale-down;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,298 @@
|
|||||||
|
import { DOCUMENT } from '@angular/common';
|
||||||
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
|
import { Observable, of, Subject, map, takeUntil, tap, zip, shareReplay, filter, combineLatest } from 'rxjs';
|
||||||
|
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
||||||
|
import { ReaderMode } from 'src/app/_models/preferences/reader-mode';
|
||||||
|
import { ReaderService } from 'src/app/_services/reader.service';
|
||||||
|
import { LayoutMode } from '../../_models/layout-mode';
|
||||||
|
import { FITTING_OPTION, PAGING_DIRECTION } from '../../_models/reader-enums';
|
||||||
|
import { ReaderSetting } from '../../_models/reader-setting';
|
||||||
|
import { DEBUG_MODES, ImageRenderer } from '../../_models/renderer';
|
||||||
|
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders 2 pages except on last page, and before a wide image
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'app-double-no-cover-renderer',
|
||||||
|
templateUrl: './double-no-cover-renderer.component.html',
|
||||||
|
styleUrls: ['./double-no-cover-renderer.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DoubleNoCoverRendererComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() readerSettings$!: Observable<ReaderSetting>;
|
||||||
|
@Input() image$!: Observable<HTMLImageElement | null>;
|
||||||
|
@Input() bookmark$!: Observable<number>;
|
||||||
|
@Input() showClickOverlay$!: Observable<boolean>;
|
||||||
|
@Input() pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||||
|
@Input() getPage!: (pageNum: number) => HTMLImageElement;
|
||||||
|
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||||
|
|
||||||
|
debugMode: DEBUG_MODES = DEBUG_MODES.Logs;
|
||||||
|
imageFitClass$!: Observable<string>;
|
||||||
|
showClickOverlayClass$!: Observable<string>;
|
||||||
|
readerModeClass$!: Observable<string>;
|
||||||
|
layoutClass$!: Observable<string>;
|
||||||
|
darkenss$: Observable<string> = of('brightness(100%)');
|
||||||
|
emulateBookClass$: Observable<string> = of('');
|
||||||
|
layoutMode: LayoutMode = LayoutMode.Single;
|
||||||
|
pageSplit: PageSplitOption = PageSplitOption.FitSplit;
|
||||||
|
pageNum: number = 0;
|
||||||
|
maxPages: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to render a page on the canvas or in the image tag. This Image element is prefetched by the cachedImages buffer.
|
||||||
|
* @remarks Used for rendering to screen.
|
||||||
|
*/
|
||||||
|
currentImage = new Image();
|
||||||
|
/**
|
||||||
|
* Used solely for LayoutMode.Double rendering.
|
||||||
|
* @remarks Used for rendering to screen.
|
||||||
|
*/
|
||||||
|
currentImage2 = new Image();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if we should render a double page.
|
||||||
|
* The general gist is if we are on double layout mode, the current page (first page) is not a cover image or a wide image
|
||||||
|
* and the next page is not a wide image (as only non-wides should be shown next to each other).
|
||||||
|
* @remarks This will always fail if the window's width is greater than the height
|
||||||
|
*/
|
||||||
|
shouldRenderDouble$!: Observable<boolean>;
|
||||||
|
|
||||||
|
|
||||||
|
private readonly onDestroy = new Subject<void>();
|
||||||
|
|
||||||
|
get ReaderMode() {return ReaderMode;}
|
||||||
|
get FITTING_OPTION() {return FITTING_OPTION;}
|
||||||
|
get LayoutMode() {return LayoutMode;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||||
|
@Inject(DOCUMENT) private document: Document, public readerService: ReaderService) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.readerModeClass$ = this.readerSettings$.pipe(
|
||||||
|
map(values => values.readerMode),
|
||||||
|
map(mode => mode === ReaderMode.LeftRight || mode === ReaderMode.UpDown ? '' : 'd-none'),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
takeUntil(this.onDestroy)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.darkenss$ = this.readerSettings$.pipe(
|
||||||
|
map(values => 'brightness(' + values.darkness + '%)'),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
takeUntil(this.onDestroy)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.emulateBookClass$ = this.readerSettings$.pipe(
|
||||||
|
map(data => data.emulateBook),
|
||||||
|
map(enabled => enabled ? 'book-shadow' : ''),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
takeUntil(this.onDestroy)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||||
|
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
takeUntil(this.onDestroy)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.pageNum$.pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
tap(pageInfo => {
|
||||||
|
this.pageNum = pageInfo.pageNum;
|
||||||
|
this.maxPages = pageInfo.maxPages;
|
||||||
|
|
||||||
|
this.currentImage = this.getPage(this.pageNum);
|
||||||
|
this.currentImage2 = this.getPage(this.pageNum + 1);
|
||||||
|
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
}),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
).subscribe(() => {});
|
||||||
|
|
||||||
|
this.shouldRenderDouble$ = this.pageNum$.pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
map((_) => this.shouldRenderDouble()),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.imageFitClass$ = this.readerSettings$.pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
map(values => values.fitting),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
shareReplay()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.layoutClass$ = combineLatest([this.shouldRenderDouble$, this.readerSettings$]).pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
map((value) => {
|
||||||
|
if (value[0] && value[1].fitting === FITTING_OPTION.WIDTH) return 'fit-to-width-double-offset';
|
||||||
|
if (value[0] && value[1].fitting === FITTING_OPTION.HEIGHT) return 'fit-to-height-double-offset';
|
||||||
|
if (value[0] && value[1].fitting === FITTING_OPTION.ORIGINAL) return 'original-double-offset';
|
||||||
|
return '';
|
||||||
|
}),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
this.readerSettings$.pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
tap(values => {
|
||||||
|
this.layoutMode = values.layoutMode;
|
||||||
|
this.pageSplit = values.pageSplit;
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
})
|
||||||
|
).subscribe(() => {});
|
||||||
|
|
||||||
|
this.bookmark$.pipe(
|
||||||
|
takeUntil(this.onDestroy),
|
||||||
|
tap(_ => {
|
||||||
|
const elements = [];
|
||||||
|
const image1 = this.document.querySelector('#image-1');
|
||||||
|
if (image1 != null) elements.push(image1);
|
||||||
|
|
||||||
|
const image2 = this.document.querySelector('#image-2');
|
||||||
|
if (image2 != null) elements.push(image2);
|
||||||
|
|
||||||
|
this.mangaReaderService.applyBookmarkEffect(elements);
|
||||||
|
}),
|
||||||
|
filter(_ => this.isValid()),
|
||||||
|
).subscribe(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.onDestroy.next();
|
||||||
|
this.onDestroy.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldRenderDouble() {
|
||||||
|
if (!this.isValid()) return false;
|
||||||
|
|
||||||
|
// if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||||
|
// this.debugLog('Not rendering double as current page is cover image');
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum) ) {
|
||||||
|
this.debugLog('Not rendering double as current page is wide image');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||||
|
this.debugLog('Not rendering double as current page is last');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||||
|
this.debugLog('Not rendering double as current page is last');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum + 1) ) {
|
||||||
|
this.debugLog('Not rendering double as next page is wide image');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.layoutMode === LayoutMode.DoubleNoCover;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPage(img: Array<HTMLImageElement | null>): void {
|
||||||
|
if (img === null || img.length === 0 || img[0] === null) return;
|
||||||
|
if (!this.isValid()) return;
|
||||||
|
|
||||||
|
// First load, switching from double manga -> double, this is 0 and thus not rendering
|
||||||
|
if (!this.shouldRenderDouble() && (this.currentImage.height || img[0].height) > 0) {
|
||||||
|
this.imageHeight.emit(this.currentImage.height || img[0].height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
this.imageHeight.emit(Math.max(this.currentImage.height, this.currentImage2.height));
|
||||||
|
this.cdRef.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldMovePrev(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
shouldMoveNext(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
getPageAmount(direction: PAGING_DIRECTION): number {
|
||||||
|
if (!this.isValid()) return 0;
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case PAGING_DIRECTION.FORWARD:
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||||
|
this.debugLog('Moving forward 1 page as current page is wide');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum + 1)) {
|
||||||
|
this.debugLog('Moving forward 1 page as next page is wide');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||||
|
this.debugLog('Moving forward 2 page as on cover image');
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if (this.mangaReaderService.isSecondLastImage(this.pageNum, this.maxPages)) {
|
||||||
|
this.debugLog('Moving forward 1 page as 2 pages left');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (this.mangaReaderService.isLastImage(this.pageNum, this.maxPages)) {
|
||||||
|
this.debugLog('Moving forward 1 page as 1 page left');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
this.debugLog('Moving forward 2 pages');
|
||||||
|
return 2;
|
||||||
|
case PAGING_DIRECTION.BACKWARDS:
|
||||||
|
if (this.mangaReaderService.isCoverImage(this.pageNum)) {
|
||||||
|
this.debugLog('Moving back 1 page as on cover image');
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.adjustForDoubleReader(this.pageNum - 1) != this.pageNum - 1 && !this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||||
|
this.debugLog('Moving back 2 pages as previous pair should be in a pair');
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum)) {
|
||||||
|
this.debugLog('Moving back 1 page as current page is wide');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum - 1)) {
|
||||||
|
this.debugLog('Moving back 1 page as prev page is wide');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (this.mangaReaderService.isWidePage(this.pageNum - 2)) {
|
||||||
|
this.debugLog('Moving back 1 page as 2 pages back is wide');
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debugLog('Moving back 2 pages');
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reset(): void {}
|
||||||
|
|
||||||
|
getBookmarkPageCount(): number {
|
||||||
|
return this.shouldRenderDouble() ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog(message: string, extraData?: any) {
|
||||||
|
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||||
|
|
||||||
|
if (extraData !== undefined) {
|
||||||
|
console.log(message, extraData);
|
||||||
|
} else {
|
||||||
|
console.log(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
import { Observable, of, Subject, map, takeUntil, tap, zip, shareReplay, filter, combineLatest } from 'rxjs';
|
import { Observable, of, Subject, map, takeUntil, tap, shareReplay, filter, combineLatest } from 'rxjs';
|
||||||
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
||||||
import { ReaderMode } from 'src/app/_models/preferences/reader-mode';
|
import { ReaderMode } from 'src/app/_models/preferences/reader-mode';
|
||||||
import { ReaderService } from 'src/app/_services/reader.service';
|
import { ReaderService } from 'src/app/_services/reader.service';
|
||||||
@ -225,7 +225,7 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
getPageAmount(direction: PAGING_DIRECTION): number {
|
getPageAmount(direction: PAGING_DIRECTION): number {
|
||||||
if (this.layoutMode !== LayoutMode.Double) return 0;
|
if (!this.isValid()) return 0;
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case PAGING_DIRECTION.FORWARD:
|
case PAGING_DIRECTION.FORWARD:
|
||||||
@ -295,5 +295,4 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||||||
console.log(message);
|
console.log(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
title="Previous Page" aria-hidden="true"></i>
|
title="Previous Page" aria-hidden="true"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="{{readerMode === ReaderMode.LeftRight ? 'right' : 'bottom'}} {{clickOverlayClass('right')}}" (click)="handlePageChange($event, KeyDirection.Left)"
|
<div class="{{readerMode === ReaderMode.LeftRight ? 'right' : 'bottom'}} {{clickOverlayClass('right')}}" (click)="handlePageChange($event, KeyDirection.Right)"
|
||||||
[ngStyle]="{'height': (readerMode === ReaderMode.LeftRight ? ImageHeight: '25%'),
|
[ngStyle]="{'height': (readerMode === ReaderMode.LeftRight ? ImageHeight: '25%'),
|
||||||
'left': 'inherit',
|
'left': 'inherit',
|
||||||
'right': RightPaginationOffset + 'px'}">
|
'right': RightPaginationOffset + 'px'}">
|
||||||
@ -84,6 +84,14 @@
|
|||||||
[pageNum$]="pageNum$"
|
[pageNum$]="pageNum$"
|
||||||
[getPage]="getPageFn">
|
[getPage]="getPageFn">
|
||||||
</app-double-reverse-renderer>
|
</app-double-reverse-renderer>
|
||||||
|
|
||||||
|
<app-double-no-cover-renderer [image$]="currentImage$"
|
||||||
|
[readerSettings$]="readerSettings$"
|
||||||
|
[bookmark$]="showBookmarkEffect$"
|
||||||
|
[showClickOverlay$]="showClickOverlay$"
|
||||||
|
[pageNum$]="pageNum$"
|
||||||
|
[getPage]="getPageFn">
|
||||||
|
</app-double-no-cover-renderer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -32,6 +32,7 @@ import { DoubleReverseRendererComponent } from '../double-reverse-renderer/doubl
|
|||||||
import { SingleRendererComponent } from '../single-renderer/single-renderer.component';
|
import { SingleRendererComponent } from '../single-renderer/single-renderer.component';
|
||||||
import { ChapterInfo } from '../../_models/chapter-info';
|
import { ChapterInfo } from '../../_models/chapter-info';
|
||||||
import { SwipeEvent } from 'ng-swipe';
|
import { SwipeEvent } from 'ng-swipe';
|
||||||
|
import { DoubleNoCoverRendererComponent } from '../double-renderer-no-cover/double-no-cover-renderer.component';
|
||||||
|
|
||||||
|
|
||||||
const PREFETCH_PAGES = 10;
|
const PREFETCH_PAGES = 10;
|
||||||
@ -96,6 +97,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
@ViewChild(SingleRendererComponent, { static: false }) singleRenderer!: SingleRendererComponent;
|
@ViewChild(SingleRendererComponent, { static: false }) singleRenderer!: SingleRendererComponent;
|
||||||
@ViewChild(DoubleRendererComponent, { static: false }) doubleRenderer!: DoubleRendererComponent;
|
@ViewChild(DoubleRendererComponent, { static: false }) doubleRenderer!: DoubleRendererComponent;
|
||||||
@ViewChild(DoubleReverseRendererComponent, { static: false }) doubleReverseRenderer!: DoubleReverseRendererComponent;
|
@ViewChild(DoubleReverseRendererComponent, { static: false }) doubleReverseRenderer!: DoubleReverseRendererComponent;
|
||||||
|
@ViewChild(DoubleNoCoverRendererComponent, { static: false }) doubleNoCoverRenderer!: DoubleNoCoverRendererComponent;
|
||||||
|
|
||||||
|
|
||||||
libraryId!: number;
|
libraryId!: number;
|
||||||
@ -1128,7 +1130,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.FORWARD), this.singleRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.FORWARD), this.singleRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
||||||
this.doubleRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
this.doubleRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
||||||
this.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.FORWARD));
|
this.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
||||||
|
this.doubleNoCoverRenderer.getPageAmount(PAGING_DIRECTION.FORWARD)
|
||||||
|
);
|
||||||
const notInSplit = this.canvasRenderer.shouldMovePrev();
|
const notInSplit = this.canvasRenderer.shouldMovePrev();
|
||||||
|
|
||||||
if ((this.pageNum + pageAmount >= this.maxPages && notInSplit)) {
|
if ((this.pageNum + pageAmount >= this.maxPages && notInSplit)) {
|
||||||
@ -1155,7 +1159,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||||
this.singleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
this.singleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||||
this.doubleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
this.doubleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||||
this.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS));
|
this.doubleNoCoverRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||||
|
this.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS)
|
||||||
|
);
|
||||||
|
|
||||||
const notInSplit = this.canvasRenderer.shouldMovePrev();
|
const notInSplit = this.canvasRenderer.shouldMovePrev();
|
||||||
|
|
||||||
@ -1257,6 +1263,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.canvasRenderer?.renderPage(page);
|
this.canvasRenderer?.renderPage(page);
|
||||||
this.singleRenderer?.renderPage(page);
|
this.singleRenderer?.renderPage(page);
|
||||||
this.doubleRenderer?.renderPage(page);
|
this.doubleRenderer?.renderPage(page);
|
||||||
|
this.doubleNoCoverRenderer?.renderPage(page);
|
||||||
this.doubleReverseRenderer?.renderPage(page);
|
this.doubleReverseRenderer?.renderPage(page);
|
||||||
|
|
||||||
// Originally this was only for fit to height, but when swiping was introduced, it made more sense to do it always to reset to the same view
|
// Originally this was only for fit to height, but when swiping was introduced, it made more sense to do it always to reset to the same view
|
||||||
@ -1558,7 +1565,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
const pageNum = this.pageNum;
|
const pageNum = this.pageNum;
|
||||||
const isDouble = Math.max(this.canvasRenderer.getBookmarkPageCount(), this.singleRenderer.getBookmarkPageCount(),
|
const isDouble = Math.max(this.canvasRenderer.getBookmarkPageCount(), this.singleRenderer.getBookmarkPageCount(),
|
||||||
this.doubleRenderer.getBookmarkPageCount(), this.doubleReverseRenderer.getBookmarkPageCount()) > 1;
|
this.doubleRenderer.getBookmarkPageCount(), this.doubleReverseRenderer.getBookmarkPageCount(), this.doubleNoCoverRenderer.getBookmarkPageCount()) > 1;
|
||||||
|
|
||||||
if (this.CurrentPageBookmarked) {
|
if (this.CurrentPageBookmarked) {
|
||||||
let apis = [this.readerService.unbookmark(this.seriesId, this.volumeId, this.chapterId, pageNum)];
|
let apis = [this.readerService.unbookmark(this.seriesId, this.volumeId, this.chapterId, pageNum)];
|
||||||
|
@ -13,5 +13,10 @@ export enum LayoutMode {
|
|||||||
/**
|
/**
|
||||||
* Renders 2 pages side by side on the renderer. Cover images will not split and take up both panes. This version reverses the order and is used for Manga only
|
* Renders 2 pages side by side on the renderer. Cover images will not split and take up both panes. This version reverses the order and is used for Manga only
|
||||||
*/
|
*/
|
||||||
DoubleReversed = 3
|
DoubleReversed = 3,
|
||||||
|
/**
|
||||||
|
* Renders 2 pages side by side on the renderer. Cover images will split.
|
||||||
|
*/
|
||||||
|
DoubleNoCover = 4,
|
||||||
|
|
||||||
}
|
}
|
@ -14,6 +14,8 @@ export class LayoutModeIconPipe implements PipeTransform {
|
|||||||
return 'double';
|
return 'double';
|
||||||
case LayoutMode.DoubleReversed:
|
case LayoutMode.DoubleReversed:
|
||||||
return 'double-reversed';
|
return 'double-reversed';
|
||||||
|
case LayoutMode.DoubleNoCover:
|
||||||
|
return 'double'; // TODO: Validate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import { DoubleReverseRendererComponent } from './_components/double-reverse-ren
|
|||||||
import { MangaReaderComponent } from './_components/manga-reader/manga-reader.component';
|
import { MangaReaderComponent } from './_components/manga-reader/manga-reader.component';
|
||||||
import { FittingIconPipe } from './_pipes/fitting-icon.pipe';
|
import { FittingIconPipe } from './_pipes/fitting-icon.pipe';
|
||||||
import { SwipeModule } from 'ng-swipe';
|
import { SwipeModule } from 'ng-swipe';
|
||||||
|
import { DoubleNoCoverRendererComponent } from './_components/double-renderer-no-cover/double-no-cover-renderer.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -31,6 +32,7 @@ import { SwipeModule } from 'ng-swipe';
|
|||||||
DoubleRendererComponent,
|
DoubleRendererComponent,
|
||||||
DoubleReverseRendererComponent,
|
DoubleReverseRendererComponent,
|
||||||
FittingIconPipe,
|
FittingIconPipe,
|
||||||
|
DoubleNoCoverRendererComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user