Angular 16 (#2007)
* Removed adv, which isn't needed. * Updated zone * Updated to angular 16 * Updated to angular 16 (partially) * Updated to angular 16 * Package update for Angular 16 (and other dependencies) is complete. * Replaced all takeUntil(this.onDestroy) with new takeUntilDestroyed() * Updated all inputs that have ! to be required and deleted all unit tests. * Corrected how takeUntilDestroyed() is supposed to be implemented.
This commit is contained in:
parent
9bc8361381
commit
9c06cccd35
87 changed files with 3964 additions and 20426 deletions
|
|
@ -1,4 +1,17 @@
|
|||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { filter, map, Observable, of, Subject, takeUntil, takeWhile, tap } from 'rxjs';
|
||||
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
||||
import { ReaderService } from 'src/app/_services/reader.service';
|
||||
|
|
@ -7,6 +20,7 @@ import { FITTING_OPTION, PAGING_DIRECTION, SPLIT_PAGE_PART } from '../../_models
|
|||
import { ReaderSetting } from '../../_models/reader-setting';
|
||||
import { ImageRenderer } from '../../_models/renderer';
|
||||
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
const ValidSplits = [PageSplitOption.SplitLeftToRight, PageSplitOption.SplitRightToLeft];
|
||||
|
||||
|
|
@ -16,18 +30,18 @@ const ValidSplits = [PageSplitOption.SplitLeftToRight, PageSplitOption.SplitRigh
|
|||
styleUrls: ['./canvas-renderer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy, ImageRenderer {
|
||||
export class CanvasRendererComponent implements OnInit, AfterViewInit, ImageRenderer {
|
||||
|
||||
@Input() readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input() image$!: Observable<HTMLImageElement | null>;
|
||||
@Input() bookmark$!: Observable<number>;
|
||||
@Input() showClickOverlay$!: Observable<boolean>;
|
||||
@Input() imageFit$!: Observable<FITTING_OPTION>;
|
||||
@Input({required: true}) readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input({required: true}) image$!: Observable<HTMLImageElement | null>;
|
||||
@Input({required: true}) bookmark$!: Observable<number>;
|
||||
@Input({required: true}) showClickOverlay$!: Observable<boolean>;
|
||||
@Input() imageFit$!: Observable<FITTING_OPTION>;
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
@ViewChild('content') canvas: ElementRef | undefined;
|
||||
private ctx!: CanvasRenderingContext2D;
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
currentImageSplitPart: SPLIT_PAGE_PART = SPLIT_PAGE_PART.NO_SPLIT;
|
||||
pagingDirection: PAGING_DIRECTION = PAGING_DIRECTION.FORWARD;
|
||||
|
|
@ -47,13 +61,13 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
*/
|
||||
imageFitClass$!: Observable<string>;
|
||||
renderWithCanvas: boolean = false;
|
||||
|
||||
|
||||
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, private mangaReaderService: ManagaReaderService, private readerService: ReaderService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.readerSettings$.pipe(takeUntil(this.onDestroy), tap((value: ReaderSetting) => {
|
||||
this.readerSettings$.pipe(takeUntilDestroyed(this.destroyRef), tap((value: ReaderSetting) => {
|
||||
this.fit = value.fitting;
|
||||
this.pageSplit = value.pageSplit;
|
||||
this.layoutMode = value.layoutMode;
|
||||
|
|
@ -65,19 +79,19 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
})).subscribe(() => {});
|
||||
|
||||
this.darkenss$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.imageFitClass$ = this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map((values: ReaderSetting) => values.fitting),
|
||||
map(fit => {
|
||||
if (fit === FITTING_OPTION.WIDTH) return fit; // || this.layoutMode === LayoutMode.Single (so that we can check the wide stuff)
|
||||
if (this.canvasImage === null) return fit;
|
||||
|
||||
// Would this ever execute given that we perform splitting only in this renderer?
|
||||
// Would this ever execute given that we perform splitting only in this renderer?
|
||||
if (
|
||||
this.mangaReaderService.isWidePage(this.readerService.imageUrlToPageNum(this.canvasImage.src)) &&
|
||||
this.mangaReaderService.shouldRenderAsFitSplit(this.pageSplit)
|
||||
|
|
@ -92,7 +106,7 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
|
||||
|
||||
this.bookmark$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(_ => {
|
||||
if (this.currentImageSplitPart === SPLIT_PAGE_PART.NO_SPLIT) return;
|
||||
if (!this.canvas) return;
|
||||
|
|
@ -103,8 +117,8 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
).subscribe(() => {});
|
||||
|
||||
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
takeUntil(this.onDestroy)
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -114,10 +128,6 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.currentImageSplitPart = SPLIT_PAGE_PART.NO_SPLIT;
|
||||
|
|
@ -126,7 +136,7 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
updateSplitPage() {
|
||||
if (this.canvasImage == null) return;
|
||||
const needsSplitting = this.mangaReaderService.isWidePage(this.readerService.imageUrlToPageNum(this.canvasImage.src));
|
||||
|
||||
|
||||
if (!needsSplitting || this.mangaReaderService.isNoSplit(this.pageSplit)) {
|
||||
this.currentImageSplitPart = SPLIT_PAGE_PART.NO_SPLIT;
|
||||
return needsSplitting;
|
||||
|
|
@ -171,8 +181,8 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
|
||||
/**
|
||||
* This renderer does not render when splitting is not needed
|
||||
* @param img
|
||||
* @returns
|
||||
* @param img
|
||||
* @returns
|
||||
*/
|
||||
renderPage(img: Array<HTMLImageElement | null>) {
|
||||
this.renderWithCanvas = false;
|
||||
|
|
@ -184,7 +194,7 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
if (this.layoutMode !== LayoutMode.Single || !ValidSplits.includes(this.pageSplit)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const needsSplitting = this.updateSplitPage();
|
||||
if (!needsSplitting) return;
|
||||
|
||||
|
|
@ -236,8 +246,6 @@ export class CanvasRendererComponent implements OnInit, AfterViewInit, OnDestroy
|
|||
setCanvasSize() {
|
||||
if (this.canvasImage == null) return;
|
||||
if (!this.ctx || !this.canvas) { return; }
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const isSafari = [
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<ng-container *ngIf="isValid()">
|
||||
<div class="image-container {{imageFitClass$ | async}} {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkenss$ | async) ?? '' | safeStyle"
|
||||
<div class="image-container {{imageFitClass$ | async}} {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
|
||||
[ngClass]="{'center-double': (shouldRenderDouble$ | async)}">
|
||||
<ng-container *ngIf="currentImage">
|
||||
<img alt=" "
|
||||
#image [src]="currentImage.src"
|
||||
id="image-1"
|
||||
<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}}">
|
||||
<img alt=" " [src]="currentImage2.src"
|
||||
id="image-2"
|
||||
class="image-2 {{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}">
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
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';
|
||||
|
|
@ -9,6 +20,7 @@ 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';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
/**
|
||||
* Renders 2 pages except on last page, and before a wide image
|
||||
|
|
@ -19,22 +31,23 @@ import { ManagaReaderService } from '../../_series/managa-reader.service';
|
|||
styleUrls: ['./double-no-cover-renderer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
||||
|
||||
@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;
|
||||
export class DoubleNoCoverRendererComponent implements OnInit {
|
||||
|
||||
@Input({required: true}) readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input({required: true}) image$!: Observable<HTMLImageElement | null>;
|
||||
@Input({required: true}) bookmark$!: Observable<number>;
|
||||
@Input({required: true}) showClickOverlay$!: Observable<boolean>;
|
||||
@Input({required: true}) pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
@Input({required: true}) getPage!: (pageNum: number) => HTMLImageElement;
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.Logs;
|
||||
imageFitClass$!: Observable<string>;
|
||||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
layoutClass$!: Observable<string>;
|
||||
darkenss$: Observable<string> = of('brightness(100%)');
|
||||
darkness$: Observable<string> = of('brightness(100%)');
|
||||
emulateBookClass$: Observable<string> = of('');
|
||||
layoutMode: LayoutMode = LayoutMode.Single;
|
||||
pageSplit: PageSplitOption = PageSplitOption.FitSplit;
|
||||
|
|
@ -47,60 +60,58 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
*/
|
||||
currentImage = new Image();
|
||||
/**
|
||||
* Used solely for LayoutMode.Double rendering.
|
||||
* 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
|
||||
* 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;}
|
||||
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
get FITTING_OPTION() {return FITTING_OPTION;}
|
||||
get LayoutMode() {return LayoutMode;}
|
||||
|
||||
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
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(values => values.readerMode),
|
||||
map(mode => mode === ReaderMode.LeftRight || mode === ReaderMode.UpDown ? '' : 'd-none'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.darkenss$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
this.darkness$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.emulateBookClass$ = this.readerSettings$.pipe(
|
||||
map(data => data.emulateBook),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(pageInfo => {
|
||||
this.pageNum = pageInfo.pageNum;
|
||||
this.maxPages = pageInfo.maxPages;
|
||||
|
|
@ -114,20 +125,20 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
).subscribe(() => {});
|
||||
|
||||
this.shouldRenderDouble$ = this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map((_) => this.shouldRenderDouble()),
|
||||
filter(_ => this.isValid()),
|
||||
);
|
||||
|
||||
this.imageFitClass$ = this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(values => values.fitting),
|
||||
filter(_ => this.isValid()),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
this.layoutClass$ = combineLatest([this.shouldRenderDouble$, this.readerSettings$]).pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
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';
|
||||
|
|
@ -139,7 +150,7 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
|
||||
|
||||
this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(values => {
|
||||
this.layoutMode = values.layoutMode;
|
||||
this.pageSplit = values.pageSplit;
|
||||
|
|
@ -148,7 +159,7 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
).subscribe(() => {});
|
||||
|
||||
this.bookmark$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(_ => {
|
||||
const elements = [];
|
||||
const image1 = this.document.querySelector('#image-1');
|
||||
|
|
@ -156,18 +167,13 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
|
||||
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;
|
||||
|
||||
|
|
@ -202,11 +208,11 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
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);
|
||||
|
|
@ -297,7 +303,7 @@ export class DoubleNoCoverRendererComponent implements OnInit, OnDestroy {
|
|||
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<ng-container *ngIf="isValid()">
|
||||
<div class="image-container {{imageFitClass$ | async}} {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkenss$ | async) ?? '' | safeStyle"
|
||||
<div class="image-container {{imageFitClass$ | async}} {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
|
||||
[ngClass]="{'center-double': (shouldRenderDouble$ | async)}">
|
||||
<ng-container *ngIf="currentImage">
|
||||
<img alt=" "
|
||||
#image [src]="currentImage.src"
|
||||
id="image-1"
|
||||
<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}}">
|
||||
<img alt=" " [src]="currentImage2.src"
|
||||
id="image-2"
|
||||
class="image-2 {{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}">
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
Inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { Observable, of, Subject, map, takeUntil, tap, shareReplay, filter, combineLatest } from 'rxjs';
|
||||
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
||||
import { ReaderMode } from 'src/app/_models/preferences/reader-mode';
|
||||
|
|
@ -9,6 +20,7 @@ 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';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
/**
|
||||
* Renders 2 pages except on first page, last page, and before a wide image
|
||||
|
|
@ -19,22 +31,23 @@ import { ManagaReaderService } from '../../_series/managa-reader.service';
|
|||
styleUrls: ['./double-renderer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer {
|
||||
export class DoubleRendererComponent implements OnInit, ImageRenderer {
|
||||
|
||||
@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;
|
||||
@Input({required: true}) readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input({required: true}) image$!: Observable<HTMLImageElement | null>;
|
||||
@Input({required: true}) bookmark$!: Observable<number>;
|
||||
@Input({required: true}) showClickOverlay$!: Observable<boolean>;
|
||||
@Input({required: true}) pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
@Input({required: true}) getPage!: (pageNum: number) => HTMLImageElement;
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.None;
|
||||
imageFitClass$!: Observable<string>;
|
||||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
layoutClass$!: Observable<string>;
|
||||
darkenss$: Observable<string> = of('brightness(100%)');
|
||||
darkness$: Observable<string> = of('brightness(100%)');
|
||||
emulateBookClass$: Observable<string> = of('');
|
||||
layoutMode: LayoutMode = LayoutMode.Single;
|
||||
pageSplit: PageSplitOption = PageSplitOption.FitSplit;
|
||||
|
|
@ -47,60 +60,58 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
*/
|
||||
currentImage = new Image();
|
||||
/**
|
||||
* Used solely for LayoutMode.Double rendering.
|
||||
* 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
|
||||
* 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;}
|
||||
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
get FITTING_OPTION() {return FITTING_OPTION;}
|
||||
get LayoutMode() {return LayoutMode;}
|
||||
|
||||
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
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(values => values.readerMode),
|
||||
map(mode => mode === ReaderMode.LeftRight || mode === ReaderMode.UpDown ? '' : 'd-none'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.darkenss$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
this.darkness$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.emulateBookClass$ = this.readerSettings$.pipe(
|
||||
map(data => data.emulateBook),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(pageInfo => {
|
||||
this.pageNum = pageInfo.pageNum;
|
||||
this.maxPages = pageInfo.maxPages;
|
||||
|
|
@ -114,20 +125,20 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
).subscribe(() => {});
|
||||
|
||||
this.shouldRenderDouble$ = this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map((_) => this.shouldRenderDouble()),
|
||||
filter(_ => this.isValid()),
|
||||
);
|
||||
|
||||
this.imageFitClass$ = this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(values => values.fitting),
|
||||
filter(_ => this.isValid()),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
this.layoutClass$ = combineLatest([this.shouldRenderDouble$, this.readerSettings$]).pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
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';
|
||||
|
|
@ -140,7 +151,7 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
|
||||
|
||||
this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(values => {
|
||||
this.layoutMode = values.layoutMode;
|
||||
this.pageSplit = values.pageSplit;
|
||||
|
|
@ -149,7 +160,7 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
).subscribe(() => {});
|
||||
|
||||
this.bookmark$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(_ => {
|
||||
const elements = [];
|
||||
const image1 = this.document.querySelector('#image-1');
|
||||
|
|
@ -157,17 +168,13 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
|
||||
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;
|
||||
|
|
@ -203,11 +210,11 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
isValid() {
|
||||
return this.layoutMode === LayoutMode.Double;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
|
@ -291,7 +298,7 @@ export class DoubleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
<ng-container *ngIf="isValid()">
|
||||
<div class="image-container {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkenss$ | async) ?? '' | safeStyle"
|
||||
<div class="image-container {{layoutClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkness$ | async) ?? '' | safeStyle"
|
||||
[ngClass]="{'center-double': (shouldRenderDouble$ | async), 'reverse': (shouldRenderDouble$ | async)}">
|
||||
<ng-container *ngIf="leftImage">
|
||||
<img alt=" "
|
||||
#image [src]="leftImage.src"
|
||||
id="image-1"
|
||||
<img alt=" "
|
||||
#image [src]="leftImage.src"
|
||||
id="image-1"
|
||||
class="{{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}"
|
||||
>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="shouldRenderDouble$ | async">
|
||||
<img alt=" " [src]="rightImage.src"
|
||||
id="image-2"
|
||||
<img alt=" " [src]="rightImage.src"
|
||||
id="image-2"
|
||||
class="image-2 {{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}"> <!--reverse-->
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
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';
|
||||
|
|
@ -9,10 +20,11 @@ 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';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
/**
|
||||
* This is aimed at manga. Double page renderer but where if we have page = 10, you will see
|
||||
* page 11 page 10.
|
||||
* page 11 page 10.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-double-reverse-renderer',
|
||||
|
|
@ -20,16 +32,17 @@ import { ManagaReaderService } from '../../_series/managa-reader.service';
|
|||
styleUrls: ['./double-reverse-renderer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageRenderer {
|
||||
export class DoubleReverseRendererComponent implements OnInit, ImageRenderer {
|
||||
|
||||
|
||||
@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;
|
||||
@Input({required: true}) readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input({required: true}) image$!: Observable<HTMLImageElement | null>;
|
||||
@Input({required: true}) bookmark$!: Observable<number>;
|
||||
@Input({required: true}) showClickOverlay$!: Observable<boolean>;
|
||||
@Input({required: true}) pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
@Input({required: true}) getPage!: (pageNum: number) => HTMLImageElement;
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
debugMode: DEBUG_MODES = DEBUG_MODES.None;
|
||||
|
||||
|
|
@ -37,7 +50,7 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
layoutClass$!: Observable<string>;
|
||||
darkenss$: Observable<string> = of('brightness(100%)');
|
||||
darkness$: Observable<string> = of('brightness(100%)');
|
||||
emulateBookClass$: Observable<string> = of('');
|
||||
layoutMode: LayoutMode = LayoutMode.Single;
|
||||
pageSplit: PageSplitOption = PageSplitOption.FitSplit;
|
||||
|
|
@ -57,52 +70,50 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
|
||||
/**
|
||||
* 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
|
||||
* 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;}
|
||||
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
get FITTING_OPTION() {return FITTING_OPTION;}
|
||||
get LayoutMode() {return LayoutMode;}
|
||||
|
||||
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
@Inject(DOCUMENT) private document: Document, public readerService: ReaderService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.readerModeClass$ = this.readerSettings$.pipe(
|
||||
filter(_ => this.isValid()),
|
||||
map(values => values.readerMode),
|
||||
map(values => values.readerMode),
|
||||
map(mode => mode === ReaderMode.LeftRight || mode === ReaderMode.UpDown ? '' : 'd-none'),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.darkenss$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
this.darkness$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.emulateBookClass$ = this.readerSettings$.pipe(
|
||||
map(data => data.emulateBook),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(pageInfo => {
|
||||
this.pageNum = pageInfo.pageNum;
|
||||
this.maxPages = pageInfo.maxPages;
|
||||
|
|
@ -114,21 +125,21 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
).subscribe(() => {});
|
||||
|
||||
this.shouldRenderDouble$ = this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(() => this.shouldRenderDouble()),
|
||||
filter(() => this.isValid()),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
this.imageFitClass$ = this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
map(values => values.fitting),
|
||||
filter(_ => this.isValid()),
|
||||
shareReplay()
|
||||
);
|
||||
|
||||
this.layoutClass$ = combineLatest([this.shouldRenderDouble$, this.readerSettings$]).pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
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';
|
||||
|
|
@ -141,7 +152,7 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
|
||||
|
||||
this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(values => {
|
||||
this.layoutMode = values.layoutMode;
|
||||
this.pageSplit = values.pageSplit;
|
||||
|
|
@ -150,7 +161,7 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
).subscribe(() => {});
|
||||
|
||||
this.bookmark$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(_ => {
|
||||
const elements = [];
|
||||
const image1 = this.document.querySelector('#image-1');
|
||||
|
|
@ -165,11 +176,6 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
).subscribe(() => {});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
shouldRenderDouble() {
|
||||
if (!this.isValid()) return false;
|
||||
|
||||
|
|
@ -204,7 +210,7 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
isValid() {
|
||||
return this.layoutMode === LayoutMode.DoubleReversed;
|
||||
}
|
||||
|
||||
|
||||
renderPage(img: Array<HTMLImageElement | null>): void {
|
||||
if (img === null || img.length === 0 || img[0] === null) return;
|
||||
if (!this.isValid()) return;
|
||||
|
|
@ -305,7 +311,7 @@ export class DoubleReverseRendererComponent implements OnInit, OnDestroy, ImageR
|
|||
if (!(this.debugMode & DEBUG_MODES.Logs)) return;
|
||||
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,20 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, OnInit, Output, Renderer2, SimpleChanges } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
Inject,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
Renderer2,
|
||||
SimpleChanges
|
||||
} from '@angular/core';
|
||||
import { BehaviorSubject, fromEvent, ReplaySubject, Subject } from 'rxjs';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
import { ScrollService } from 'src/app/_services/scroll.service';
|
||||
|
|
@ -7,6 +22,7 @@ import { ReaderService } from '../../../_services/reader.service';
|
|||
import { PAGING_DIRECTION } from '../../_models/reader-enums';
|
||||
import { WebtoonImage } from '../../_models/webtoon-image';
|
||||
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
/**
|
||||
* How much additional space should pass, past the original bottom of the document height before we trigger the next chapter load
|
||||
|
|
@ -58,7 +74,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
/**
|
||||
* Method to generate the src for Image loading
|
||||
*/
|
||||
@Input() urlProvider!: (page: number) => string;
|
||||
@Input({required: true}) urlProvider!: (page: number) => string;
|
||||
@Output() pageNumberChange: EventEmitter<number> = new EventEmitter<number>();
|
||||
@Output() loadNextChapter: EventEmitter<void> = new EventEmitter<void>();
|
||||
@Output() loadPrevChapter: EventEmitter<void> = new EventEmitter<void>();
|
||||
|
|
@ -66,6 +82,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
@Input() goToPage: BehaviorSubject<number> | undefined;
|
||||
@Input() bookmarkPage: ReplaySubject<number> = new ReplaySubject<number>();
|
||||
@Input() fullscreenToggled: ReplaySubject<boolean> = new ReplaySubject<boolean>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
readerElemRef!: ElementRef<HTMLDivElement>;
|
||||
|
||||
|
|
@ -110,7 +127,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
/**
|
||||
* If the user has scrolled all the way to the bottom. This is used solely for continuous reading
|
||||
*/
|
||||
atBottom: boolean = false;
|
||||
atBottom: boolean = false;
|
||||
/**
|
||||
* If the user has scrolled all the way to the top. This is used solely for continuous reading
|
||||
*/
|
||||
|
|
@ -149,10 +166,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
return this.webtoonImageWidth > (innerWidth || document.body.clientWidth);
|
||||
}
|
||||
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
constructor(private readerService: ReaderService, private renderer: Renderer2,
|
||||
constructor(private readerService: ReaderService, private renderer: Renderer2,
|
||||
@Inject(DOCUMENT) private document: Document, private scrollService: ScrollService,
|
||||
private readonly cdRef: ChangeDetectorRef, private mangaReaderService: ManagaReaderService) {
|
||||
// This will always exist at this point in time since this is used within manga reader
|
||||
|
|
@ -172,18 +186,16 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
ngOnDestroy(): void {
|
||||
this.intersectionObserver.disconnect();
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for binding the scroll handler to the correct event. On non-fullscreen, body is correct. However, on fullscreen, we must use the reader as that is what
|
||||
* Responsible for binding the scroll handler to the correct event. On non-fullscreen, body is correct. However, on fullscreen, we must use the reader as that is what
|
||||
* gets promoted to fullscreen.
|
||||
*/
|
||||
initScrollHandler() {
|
||||
console.log('Setting up Scroll handler on ', this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body);
|
||||
fromEvent(this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body, 'scroll')
|
||||
.pipe(debounceTime(20), takeUntil(this.onDestroy))
|
||||
.pipe(debounceTime(20), takeUntilDestroyed(this.destroyRef))
|
||||
.subscribe((event) => this.handleScrollEvent(event));
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +205,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.recalculateImageWidth();
|
||||
|
||||
if (this.goToPage) {
|
||||
this.goToPage.pipe(takeUntil(this.onDestroy)).subscribe(page => {
|
||||
this.goToPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
|
||||
const isSamePage = this.pageNum === page;
|
||||
if (isSamePage) { return; }
|
||||
this.debugLog('[GoToPage] jump has occured from ' + this.pageNum + ' to ' + page);
|
||||
|
|
@ -209,11 +221,11 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
if (this.bookmarkPage) {
|
||||
this.bookmarkPage.pipe(takeUntil(this.onDestroy)).subscribe(page => {
|
||||
this.bookmarkPage.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(page => {
|
||||
const image = document.querySelector('img[id^="page-' + page + '"]');
|
||||
if (image) {
|
||||
this.renderer.addClass(image, 'bookmark-effect');
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
this.renderer.removeClass(image, 'bookmark-effect');
|
||||
}, 1000);
|
||||
|
|
@ -222,7 +234,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
if (this.fullscreenToggled) {
|
||||
this.fullscreenToggled.pipe(takeUntil(this.onDestroy)).subscribe(isFullscreen => {
|
||||
this.fullscreenToggled.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(isFullscreen => {
|
||||
this.debugLog('[FullScreen] Fullscreen mode: ', isFullscreen);
|
||||
this.isFullscreenMode = isFullscreen;
|
||||
this.cdRef.markForCheck();
|
||||
|
|
@ -251,13 +263,13 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
return (offset
|
||||
|| document.body.scrollTop
|
||||
|| document.documentElement.scrollTop
|
||||
|| document.body.scrollTop
|
||||
|| document.documentElement.scrollTop
|
||||
|| 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* On scroll in document, calculate if the user/javascript has scrolled to the current image element (and it's visible), update that scrolling has ended completely,
|
||||
* On scroll in document, calculate if the user/javascript has scrolled to the current image element (and it's visible), update that scrolling has ended completely,
|
||||
* and calculate the direction the scrolling is occuring. This is not used for prefetching.
|
||||
* @param event Scroll Event
|
||||
*/
|
||||
|
|
@ -279,7 +291,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
if (!this.isScrolling) {
|
||||
// Use offset of the image against the scroll container to test if the most of the image is visible on the screen. We can use this
|
||||
// to mark the current page and separate the prefetching code.
|
||||
// to mark the current page and separate the prefetching code.
|
||||
const midlineImages = Array.from(document.querySelectorAll('img[id^="page-"]'))
|
||||
.filter(entry => this.shouldElementCountAsCurrentPage(entry));
|
||||
|
||||
|
|
@ -336,7 +348,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
document.body.scrollTop = this.previousScrollHeightMinusTop + (SPACER_SCROLL_INTO_PX / 2);
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
} else if (totalScroll >= totalHeight + SPACER_SCROLL_INTO_PX && this.atBottom) {
|
||||
} else if (totalScroll >= totalHeight + SPACER_SCROLL_INTO_PX && this.atBottom) {
|
||||
// This if statement will fire once we scroll into the spacer at all
|
||||
this.loadNextChapter.emit();
|
||||
this.cdRef.markForCheck();
|
||||
|
|
@ -345,12 +357,12 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
// < 5 because debug mode and FF (mobile) can report non 0, despite being at 0
|
||||
if (this.getScrollTop() < 5 && this.pageNum === 0 && !this.atTop) {
|
||||
this.atBottom = false;
|
||||
this.atTop = true;
|
||||
this.atTop = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// Scroll user back to original location
|
||||
this.previousScrollHeightMinusTop = document.body.scrollHeight - document.body.scrollTop;
|
||||
|
||||
|
||||
const reader = this.isFullscreenMode ? this.readerElemRef.nativeElement : this.document.body;
|
||||
requestAnimationFrame(() => this.scrollService.scrollTo((SPACER_SCROLL_INTO_PX / 2), reader));
|
||||
} else if (this.getScrollTop() < 5 && this.pageNum === 0 && this.atTop) {
|
||||
|
|
@ -362,7 +374,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @returns Height, Width
|
||||
*/
|
||||
getInnerDimensions() {
|
||||
|
|
@ -377,10 +389,10 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Is any part of the element visible in the scrollport. Does not take into account
|
||||
* style properites, just scroll port visibility.
|
||||
* @param elem
|
||||
* @returns
|
||||
* Is any part of the element visible in the scrollport. Does not take into account
|
||||
* style properites, just scroll port visibility.
|
||||
* @param elem
|
||||
* @returns
|
||||
*/
|
||||
isElementVisible(elem: Element) {
|
||||
if (elem === null || elem === undefined) { return false; }
|
||||
|
|
@ -391,8 +403,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
const [innerHeight, innerWidth] = this.getInnerDimensions();
|
||||
|
||||
return (rect.bottom >= 0 &&
|
||||
rect.right >= 0 &&
|
||||
return (rect.bottom >= 0 &&
|
||||
rect.right >= 0 &&
|
||||
rect.top <= (innerHeight || document.body.clientHeight) &&
|
||||
rect.left <= (innerWidth || document.body.clientWidth)
|
||||
);
|
||||
|
|
@ -400,7 +412,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
/**
|
||||
* Is any part of the element visible in the scrollport and is it above the midline trigger.
|
||||
* The midline trigger does not mean it is half of the screen. It may be top 25%.
|
||||
* The midline trigger does not mean it is half of the screen. It may be top 25%.
|
||||
* @param elem HTML Element
|
||||
* @returns If above midline
|
||||
*/
|
||||
|
|
@ -412,8 +424,8 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
const [innerHeight, innerWidth] = this.getInnerDimensions();
|
||||
|
||||
|
||||
if (rect.bottom >= 0 &&
|
||||
rect.right >= 0 &&
|
||||
if (rect.bottom >= 0 &&
|
||||
rect.right >= 0 &&
|
||||
rect.top <= (innerHeight || document.body.clientHeight) &&
|
||||
rect.left <= (innerWidth || document.body.clientWidth)
|
||||
) {
|
||||
|
|
@ -444,7 +456,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
/**
|
||||
* Callback for an image onLoad. At this point the image is already rendered in DOM (may not be visible)
|
||||
* This will be used to scroll to current page for intial load
|
||||
* @param event
|
||||
* @param event
|
||||
*/
|
||||
onImageLoad(event: any) {
|
||||
const imagePage = this.readerService.imageUrlToPageNum(event.target.src);
|
||||
|
|
@ -468,13 +480,13 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.debugLog('[Image Load] ! Loaded current page !', this.pageNum);
|
||||
this.currentPageElem = this.document.querySelector('img#page-' + this.pageNum);
|
||||
// There needs to be a bit of time before we scroll
|
||||
if (this.currentPageElem && !this.isElementVisible(this.currentPageElem)) {
|
||||
if (this.currentPageElem && !this.isElementVisible(this.currentPageElem)) {
|
||||
this.scrollToCurrentPage();
|
||||
} else {
|
||||
this.initFinished = true;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
|
||||
this.allImagesLoaded = true;
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
|
@ -530,7 +542,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.currentPageElem = document.querySelector('img#page-' + this.pageNum);
|
||||
if (!this.currentPageElem) { return; }
|
||||
this.debugLog('[GoToPage] Scrolling to page', this.pageNum);
|
||||
|
||||
|
||||
// Update prevScrollPosition, so the next scroll event properly calculates direction
|
||||
this.prevScrollPosition = this.currentPageElem.getBoundingClientRect().top;
|
||||
this.isScrolling = true;
|
||||
|
|
@ -553,7 +565,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
|
||||
this.debugLog('\t[PREFETCH] Prefetching ', page);
|
||||
|
||||
|
||||
const data = this.webtoonImages.value.concat({src: this.urlProvider(page), page});
|
||||
|
||||
data.sort((a: WebtoonImage, b: WebtoonImage) => {
|
||||
|
|
@ -582,9 +594,9 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
/**
|
||||
* Finds the ranges of indecies to load from backend. totalPages - 1 is due to backend will automatically return last page for any page number
|
||||
* above totalPages. Webtoon reader might ask for that which results in duplicate last pages.
|
||||
* @param pageNum
|
||||
* @returns
|
||||
* above totalPages. Webtoon reader might ask for that which results in duplicate last pages.
|
||||
* @param pageNum
|
||||
* @returns
|
||||
*/
|
||||
calculatePrefetchIndecies(pageNum: number = -1) {
|
||||
if (pageNum == -1) {
|
||||
|
|
@ -646,7 +658,7 @@ export class InfiniteScrollerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
if (this.debugLogFilter.filter(str => message.replace('\t', '').startsWith(str)).length > 0) return;
|
||||
if (extraData !== undefined) {
|
||||
console.log(message, extraData);
|
||||
console.log(message, extraData);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Inject, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
inject,
|
||||
Inject,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
SimpleChanges,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { BehaviorSubject, debounceTime, distinctUntilChanged, forkJoin, fromEvent, map, merge, Observable, ReplaySubject, Subject, take, takeUntil, tap } from 'rxjs';
|
||||
|
|
@ -33,6 +47,7 @@ import { SingleRendererComponent } from '../single-renderer/single-renderer.comp
|
|||
import { ChapterInfo } from '../../_models/chapter-info';
|
||||
import { DoubleNoCoverRendererComponent } from '../double-renderer-no-cover/double-no-cover-renderer.component';
|
||||
import { SwipeEvent } from 'src/app/ng-swipe/ag-swipe.core';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
|
||||
const PREFETCH_PAGES = 10;
|
||||
|
|
@ -53,7 +68,7 @@ enum ChapterInfoPosition {
|
|||
enum KeyDirection {
|
||||
Right = 0,
|
||||
Left = 1,
|
||||
Up = 2,
|
||||
Up = 2,
|
||||
Down = 3
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +113,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
@ViewChild(DoubleRendererComponent, { static: false }) doubleRenderer!: DoubleRendererComponent;
|
||||
@ViewChild(DoubleReverseRendererComponent, { static: false }) doubleReverseRenderer!: DoubleReverseRendererComponent;
|
||||
@ViewChild(DoubleNoCoverRendererComponent, { static: false }) doubleNoCoverRenderer!: DoubleNoCoverRendererComponent;
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
libraryId!: number;
|
||||
seriesId!: number;
|
||||
|
|
@ -155,7 +170,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
isLoading = true;
|
||||
hasBookmarkRights: boolean = false; // TODO: This can be an observable
|
||||
|
||||
|
||||
|
||||
getPageFn!: (pageNum: number) => HTMLImageElement;
|
||||
|
||||
|
|
@ -165,9 +180,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
* @remarks Used for rendering to screen.
|
||||
*/
|
||||
canvasImage = new Image();
|
||||
|
||||
|
||||
/**
|
||||
* Dictates if we use render with canvas or with image.
|
||||
* Dictates if we use render with canvas or with image.
|
||||
* @remarks This is only for Splitting.
|
||||
*/
|
||||
//renderWithCanvas: boolean = false;
|
||||
|
|
@ -314,7 +329,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
prevIsVerticalScrollLeft = true;
|
||||
|
||||
/**
|
||||
* Has the user scrolled to the far right side. This is used for swipe to next page and must ensure user is at end of scroll then on next swipe, will move pages.
|
||||
* Has the user scrolled to the far right side. This is used for swipe to next page and must ensure user is at end of scroll then on next swipe, will move pages.
|
||||
*/
|
||||
hasHitRightScroll = false;
|
||||
/**
|
||||
|
|
@ -345,7 +360,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
private pageNumSubject: Subject<{pageNum: number, maxPages: number}> = new ReplaySubject();
|
||||
pageNum$: Observable<{pageNum: number, maxPages: number}> = this.pageNumSubject.asObservable();
|
||||
|
||||
|
||||
|
||||
bookmarkPageHandler = this.bookmarkPage.bind(this);
|
||||
|
||||
|
|
@ -354,8 +369,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return this.readerService.getPageUrl(chapterId, pageNum);
|
||||
}
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
get PageNumber() {
|
||||
return Math.max(Math.min(this.pageNum, this.maxPages - 1), 0);
|
||||
}
|
||||
|
|
@ -373,7 +386,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.FittingOption !== FITTING_OPTION.HEIGHT) {
|
||||
return this.mangaReaderService.getPageDimensions(this.pageNum)?.height + 'px';
|
||||
}
|
||||
|
||||
|
||||
return this.readingArea?.nativeElement?.clientHeight + 'px';
|
||||
}
|
||||
|
||||
|
|
@ -428,8 +441,8 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService,
|
||||
public readerService: ReaderService, private formBuilder: FormBuilder, private navService: NavService,
|
||||
private toastr: ToastrService, private memberService: MemberService,
|
||||
public utilityService: UtilityService, @Inject(DOCUMENT) private document: Document,
|
||||
private modalService: NgbModal, private readonly cdRef: ChangeDetectorRef,
|
||||
public utilityService: UtilityService, @Inject(DOCUMENT) private document: Document,
|
||||
private modalService: NgbModal, private readonly cdRef: ChangeDetectorRef,
|
||||
public mangaReaderService: ManagaReaderService) {
|
||||
this.navService.hideNavBar();
|
||||
this.navService.hideSideNav();
|
||||
|
|
@ -494,18 +507,18 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
// We need a mergeMap when page changes
|
||||
this.readerSettings$ = merge(this.generalSettingsForm.valueChanges, this.pagingDirection$, this.readerMode$).pipe(
|
||||
map(_ => this.createReaderSettingsUpdate()),
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
);
|
||||
|
||||
this.updateForm();
|
||||
|
||||
|
||||
this.pagingDirection$.pipe(
|
||||
distinctUntilChanged(),
|
||||
tap(dir => {
|
||||
this.pagingDirection = dir;
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntil(this.onDestroy)
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {});
|
||||
|
||||
this.readerMode$.pipe(
|
||||
|
|
@ -513,12 +526,12 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
tap(mode => {
|
||||
this.readerMode = mode;
|
||||
this.cdRef.markForCheck();
|
||||
}),
|
||||
takeUntil(this.onDestroy)
|
||||
}),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
).subscribe(() => {});
|
||||
|
||||
|
||||
this.generalSettingsForm.get('layoutMode')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(val => {
|
||||
|
||||
this.generalSettingsForm.get('layoutMode')?.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(val => {
|
||||
|
||||
const changeOccurred = parseInt(val, 10) !== this.layoutMode;
|
||||
this.layoutMode = parseInt(val, 10);
|
||||
|
|
@ -544,7 +557,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
this.generalSettingsForm.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe((changes: SimpleChanges) => {
|
||||
this.generalSettingsForm.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((changes: SimpleChanges) => {
|
||||
this.autoCloseMenu = this.generalSettingsForm.get('autoCloseMenu')?.value;
|
||||
this.pageSplitOption = parseInt(this.generalSettingsForm.get('pageSplitOption')?.value, 10);
|
||||
|
||||
|
|
@ -570,7 +583,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
fromEvent(this.readingArea.nativeElement, 'scroll').pipe(debounceTime(20), takeUntil(this.onDestroy)).subscribe(evt => {
|
||||
fromEvent(this.readingArea.nativeElement, 'scroll').pipe(debounceTime(20), takeUntilDestroyed(this.destroyRef)).subscribe(evt => {
|
||||
if (this.readerMode === ReaderMode.Webtoon) return;
|
||||
if (this.readerMode === ReaderMode.LeftRight && this.FittingOption === FITTING_OPTION.HEIGHT) {
|
||||
this.rightPaginationOffset = (this.readingArea.nativeElement.scrollLeft) * -1;
|
||||
|
|
@ -581,12 +594,12 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
fromEvent(this.readingArea.nativeElement, 'click').pipe(debounceTime(200), takeUntil(this.onDestroy)).subscribe((event: MouseEvent | any) => {
|
||||
fromEvent(this.readingArea.nativeElement, 'click').pipe(debounceTime(200), takeUntilDestroyed(this.destroyRef)).subscribe((event: MouseEvent | any) => {
|
||||
if (event.detail > 1) return;
|
||||
this.toggleMenu();
|
||||
});
|
||||
|
||||
fromEvent(this.readingArea.nativeElement, 'scroll').pipe(debounceTime(200), takeUntil(this.onDestroy)).subscribe((event: MouseEvent | any) => {
|
||||
fromEvent(this.readingArea.nativeElement, 'scroll').pipe(debounceTime(200), takeUntilDestroyed(this.destroyRef)).subscribe((event: MouseEvent | any) => {
|
||||
this.prevScrollLeft = this.readingArea?.nativeElement?.scrollLeft || 0;
|
||||
this.prevScrollTop = this.readingArea?.nativeElement?.scrollTop || 0;
|
||||
this.hasScrolledX = true;
|
||||
|
|
@ -598,8 +611,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.readerService.resetOverrideStyles();
|
||||
this.navService.showNavBar();
|
||||
this.navService.showSideNav();
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
this.showBookmarkEffectEvent.complete();
|
||||
if (this.goToPageEvent !== undefined) this.goToPageEvent.complete();
|
||||
}
|
||||
|
|
@ -607,7 +618,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
@HostListener('window:orientationchange', ['$event'])
|
||||
onResize() {
|
||||
onResize() {
|
||||
this.disableDoubleRendererIfScreenTooSmall();
|
||||
}
|
||||
|
||||
|
|
@ -692,7 +703,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return;
|
||||
};
|
||||
if (this.layoutMode === LayoutMode.Single || this.readerMode === ReaderMode.Webtoon) return;
|
||||
|
||||
|
||||
this.generalSettingsForm.get('layoutMode')?.setValue(LayoutMode.Single);
|
||||
this.generalSettingsForm.get('layoutMode')?.disable();
|
||||
this.toastr.info('Layout mode switched to Single due to insufficient space to render double layout');
|
||||
|
|
@ -704,13 +715,13 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
* @param pageNum Page Number to load
|
||||
* @param forceNew Forces to fetch a new image
|
||||
* @param chapterId ChapterId to fetch page from. Defaults to current chapterId. Not used when in bookmark mode
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
getPage(pageNum: number, chapterId: number = this.chapterId, forceNew: boolean = false) {
|
||||
|
||||
let img = undefined;
|
||||
if (this.bookmarkMode) img = this.cachedImages.find(img => this.readerService.imageUrlToPageNum(img.src) === pageNum);
|
||||
else img = this.cachedImages.find(img => this.readerService.imageUrlToPageNum(img.src) === pageNum
|
||||
else img = this.cachedImages.find(img => this.readerService.imageUrlToPageNum(img.src) === pageNum
|
||||
&& (this.readerService.imageUrlToChapterId(img.src) == chapterId || this.readerService.imageUrlToChapterId(img.src) === -1)
|
||||
);
|
||||
if (!img || forceNew) {
|
||||
|
|
@ -721,7 +732,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return img;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
isHorizontalScrollLeft() {
|
||||
const scrollLeft = this.readingArea?.nativeElement?.scrollLeft || 0;
|
||||
|
|
@ -736,11 +747,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
const scrollTop = this.readingArea?.nativeElement?.scrollTop || 0;
|
||||
return scrollTop < this.ReadingAreaHeight;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is there any room to scroll in the direction we are giving? If so, return false. Otherwise return true.
|
||||
* @param direction
|
||||
* @returns
|
||||
* @param direction
|
||||
* @returns
|
||||
*/
|
||||
checkIfPaginationAllowed(direction: KeyDirection) {
|
||||
if (this.readingArea === undefined || this.readingArea.nativeElement === undefined) return true;
|
||||
|
|
@ -782,7 +793,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
init() {
|
||||
this.nextChapterId = CHAPTER_ID_NOT_FETCHED;
|
||||
|
|
@ -887,7 +898,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
} else {
|
||||
// Fetch the first page of next chapter
|
||||
this.getPage(0, this.nextChapterId);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
this.readerService.getPrevChapter(this.seriesId, this.volumeId, this.chapterId, this.readingListId).pipe(take(1)).subscribe(chapterId => {
|
||||
|
|
@ -976,11 +987,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.hasHitBottomTopScroll = false;
|
||||
this.hasHitZeroTopScroll = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This executes BEFORE fromEvent('scroll')
|
||||
* @param event
|
||||
* @returns
|
||||
* @param event
|
||||
* @returns
|
||||
*/
|
||||
onSwipeMove(_: SwipeEvent) {
|
||||
this.prevScrollLeft = this.readingArea?.nativeElement?.scrollLeft || 0;
|
||||
|
|
@ -989,7 +1000,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
triggerSwipePagination(direction: KeyDirection) {
|
||||
if (!this.generalSettingsForm.get('swipeToPaginate')?.value) return;
|
||||
|
||||
|
||||
switch(direction) {
|
||||
case KeyDirection.Down:
|
||||
this.nextPage();
|
||||
|
|
@ -1004,7 +1015,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.readingDirection === ReadingDirection.LeftToRight ? this.prevPage() : this.nextPage();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
onSwipeEnd(event: SwipeEvent) {
|
||||
|
|
@ -1117,17 +1128,17 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
this.isLoading = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
||||
this.pagingDirectionSubject.next(PAGING_DIRECTION.FORWARD);
|
||||
|
||||
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.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.FORWARD),
|
||||
this.doubleNoCoverRenderer.getPageAmount(PAGING_DIRECTION.FORWARD)
|
||||
);
|
||||
const notInSplit = this.canvasRenderer.shouldMovePrev();
|
||||
|
||||
if ((this.pageNum + pageAmount >= this.maxPages && notInSplit)) {
|
||||
if ((this.pageNum + pageAmount >= this.maxPages && notInSplit)) {
|
||||
// Move to next volume/chapter automatically
|
||||
this.loadNextChapter();
|
||||
return;
|
||||
|
|
@ -1142,7 +1153,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
this.resetSwipeModifiers();
|
||||
|
||||
this.isLoading = true;
|
||||
|
|
@ -1151,8 +1162,8 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.pagingDirectionSubject.next(PAGING_DIRECTION.BACKWARDS);
|
||||
|
||||
|
||||
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
this.singleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
const pageAmount = Math.max(this.canvasRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
this.singleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
this.doubleRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
this.doubleNoCoverRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS),
|
||||
this.doubleReverseRenderer.getPageAmount(PAGING_DIRECTION.BACKWARDS)
|
||||
|
|
@ -1165,7 +1176,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.loadPrevChapter();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.setPageNum(this.pageNum - pageAmount);
|
||||
this.loadPage();
|
||||
}
|
||||
|
|
@ -1179,13 +1190,13 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.canvasImage.addEventListener('load', () => {
|
||||
this.currentImage.next(this.canvasImage);
|
||||
}, false);
|
||||
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
|
||||
loadNextChapter() {
|
||||
if (this.nextPageDisabled || this.nextChapterDisabled || this.bookmarkMode) {
|
||||
if (this.nextPageDisabled || this.nextChapterDisabled || this.bookmarkMode) {
|
||||
this.toastr.info('No Next Chapter');
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
|
|
@ -1203,11 +1214,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
loadPrevChapter() {
|
||||
if (this.prevPageDisabled || this.prevChapterDisabled || this.bookmarkMode) {
|
||||
if (this.prevPageDisabled || this.prevChapterDisabled || this.bookmarkMode) {
|
||||
this.toastr.info('No Previous Chapter');
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
return;
|
||||
return;
|
||||
}
|
||||
this.continuousChaptersStack.pop();
|
||||
const prevChapter = this.continuousChaptersStack.peek();
|
||||
|
|
@ -1254,12 +1265,12 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderPage() {
|
||||
const page = [this.canvasImage];
|
||||
|
||||
this.canvasRenderer?.renderPage(page);
|
||||
this.canvasRenderer?.renderPage(page);
|
||||
this.singleRenderer?.renderPage(page);
|
||||
this.doubleRenderer?.renderPage(page);
|
||||
this.doubleNoCoverRenderer?.renderPage(page);
|
||||
|
|
@ -1331,7 +1342,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
*/
|
||||
loadPage() {
|
||||
if (this.readerMode === ReaderMode.Webtoon) return;
|
||||
|
||||
|
||||
this.isLoading = true;
|
||||
this.setCanvasImage();
|
||||
this.cdRef.markForCheck();
|
||||
|
|
@ -1339,7 +1350,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.renderPage();
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
||||
this.prefetch();
|
||||
}
|
||||
|
||||
|
|
@ -1423,12 +1434,12 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
/**
|
||||
* Loads the first 5 images (throwaway cache) from the given chapterId
|
||||
* @param chapterId
|
||||
* @param chapterId
|
||||
* @param direction Used to indicate if the chapter is behind or ahead of curent chapter
|
||||
*/
|
||||
prefetchStartOfChapter(chapterId: number, direction: PAGING_DIRECTION) {
|
||||
let pages = [];
|
||||
|
||||
|
||||
if (direction === PAGING_DIRECTION.BACKWARDS) {
|
||||
if (this.continuousChapterInfos[ChapterInfoPosition.Previous] === undefined) return;
|
||||
const n = this.continuousChapterInfos[ChapterInfoPosition.Previous]!.pages;
|
||||
|
|
@ -1436,7 +1447,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
} else {
|
||||
pages = [0, 1, 2, 3, 4];
|
||||
}
|
||||
|
||||
|
||||
let images = [];
|
||||
pages.forEach((_, i: number) => {
|
||||
let img = new Image();
|
||||
|
|
@ -1564,7 +1575,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.bookmarkMode) return;
|
||||
|
||||
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(), this.doubleNoCoverRenderer.getBookmarkPageCount()) > 1;
|
||||
|
||||
if (this.CurrentPageBookmarked) {
|
||||
|
|
@ -1640,5 +1651,5 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<ng-container *ngIf="isValid() && !this.mangaReaderService.shouldSplit(this.currentImage, this.pageSplit)">
|
||||
<div class="image-container {{imageFitClass$ | async}} {{emulateBookClass$ | async}}"
|
||||
[style.filter]="(darkenss$ | async) ?? '' | safeStyle" [style.height]="(imageContainerHeight$ | async) ?? '' | safeStyle">
|
||||
[style.filter]="(darkness$ | async) ?? '' | safeStyle" [style.height]="(imageContainerHeight$ | async) ?? '' | safeStyle">
|
||||
<ng-container *ngIf="currentImage">
|
||||
<img alt=" "
|
||||
#image [src]="currentImage.src"
|
||||
id="image-1"
|
||||
<img alt=" "
|
||||
#image [src]="currentImage.src"
|
||||
id="image-1"
|
||||
class="{{imageFitClass$ | async}} {{readerModeClass$ | async}} {{showClickOverlayClass$ | async}}"
|
||||
>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component, DestroyRef,
|
||||
EventEmitter,
|
||||
inject,
|
||||
Inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { combineLatest, filter, map, Observable, of, shareReplay, Subject, takeUntil, tap } from 'rxjs';
|
||||
import { PageSplitOption } from 'src/app/_models/preferences/page-split-option';
|
||||
import { ReaderMode } from 'src/app/_models/preferences/reader-mode';
|
||||
|
|
@ -9,6 +20,7 @@ import { FITTING_OPTION, PAGING_DIRECTION } from '../../_models/reader-enums';
|
|||
import { ReaderSetting } from '../../_models/reader-setting';
|
||||
import { ImageRenderer } from '../../_models/renderer';
|
||||
import { ManagaReaderService } from '../../_series/managa-reader.service';
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
|
||||
@Component({
|
||||
selector: 'app-single-renderer',
|
||||
|
|
@ -16,21 +28,22 @@ import { ManagaReaderService } from '../../_series/managa-reader.service';
|
|||
styleUrls: ['./single-renderer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer {
|
||||
export class SingleRendererComponent implements OnInit, ImageRenderer {
|
||||
|
||||
@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({required: true}) readerSettings$!: Observable<ReaderSetting>;
|
||||
@Input({required: true}) image$!: Observable<HTMLImageElement | null>;
|
||||
@Input({required: true}) bookmark$!: Observable<number>;
|
||||
@Input({required: true}) showClickOverlay$!: Observable<boolean>;
|
||||
@Input({required: true}) pageNum$!: Observable<{pageNum: number, maxPages: number}>;
|
||||
|
||||
@Output() imageHeight: EventEmitter<number> = new EventEmitter<number>();
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
imageFitClass$!: Observable<string>;
|
||||
imageContainerHeight$!: Observable<string>;
|
||||
showClickOverlayClass$!: Observable<string>;
|
||||
readerModeClass$!: Observable<string>;
|
||||
darkenss$: Observable<string> = of('brightness(100%)');
|
||||
darkness$: Observable<string> = of('brightness(100%)');
|
||||
emulateBookClass$!: Observable<string>;
|
||||
currentImage!: HTMLImageElement;
|
||||
layoutMode: LayoutMode = LayoutMode.Single;
|
||||
|
|
@ -39,31 +52,29 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
pageNum: number = 0;
|
||||
maxPages: number = 1;
|
||||
|
||||
private readonly onDestroy = new Subject<void>();
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
get LayoutMode() {return LayoutMode;}
|
||||
|
||||
get ReaderMode() {return ReaderMode;}
|
||||
get LayoutMode() {return LayoutMode;}
|
||||
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
constructor(private readonly cdRef: ChangeDetectorRef, public mangaReaderService: ManagaReaderService,
|
||||
@Inject(DOCUMENT) private document: Document) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.readerModeClass$ = this.readerSettings$.pipe(
|
||||
map(values => values.readerMode),
|
||||
map(values => values.readerMode),
|
||||
map(mode => mode === ReaderMode.LeftRight || mode === ReaderMode.UpDown ? '' : 'd-none'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.emulateBookClass$ = this.readerSettings$.pipe(
|
||||
map(data => data.emulateBook),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
map(enabled => enabled ? 'book-shadow' : ''),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.imageContainerHeight$ = this.readerSettings$.pipe(
|
||||
map(values => values.fitting),
|
||||
map(values => values.fitting),
|
||||
map(mode => {
|
||||
if ( mode !== FITTING_OPTION.HEIGHT) return '';
|
||||
|
||||
|
|
@ -76,31 +87,31 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
return 'calc(100vh)'
|
||||
}),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.pageNum$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(pageInfo => {
|
||||
this.pageNum = pageInfo.pageNum;
|
||||
this.maxPages = pageInfo.maxPages;
|
||||
}),
|
||||
).subscribe(() => {});
|
||||
|
||||
this.darkenss$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
this.darkness$ = this.readerSettings$.pipe(
|
||||
map(values => 'brightness(' + values.darkness + '%)'),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy)
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.showClickOverlayClass$ = this.showClickOverlay$.pipe(
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
takeUntil(this.onDestroy),
|
||||
map(showOverlay => showOverlay ? 'blur' : ''),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
filter(_ => this.isValid()),
|
||||
);
|
||||
|
||||
this.readerSettings$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(values => {
|
||||
this.layoutMode = values.layoutMode;
|
||||
this.pageSplit = values.pageSplit;
|
||||
|
|
@ -109,7 +120,7 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
).subscribe(() => {});
|
||||
|
||||
this.bookmark$.pipe(
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(_ => {
|
||||
const elements = [];
|
||||
const image1 = this.document.querySelector('#image-1');
|
||||
|
|
@ -134,7 +145,7 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
}),
|
||||
shareReplay(),
|
||||
filter(_ => this.isValid()),
|
||||
takeUntil(this.onDestroy),
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -142,15 +153,10 @@ export class SingleRendererComponent implements OnInit, OnDestroy, ImageRenderer
|
|||
return this.layoutMode === LayoutMode.Single;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.onDestroy.next();
|
||||
this.onDestroy.complete();
|
||||
}
|
||||
|
||||
renderPage(img: Array<HTMLImageElement | null>): void {
|
||||
if (img === null || img.length === 0 || img[0] === null) return;
|
||||
if (!this.isValid()) return;
|
||||
|
||||
|
||||
this.currentImage = img[0];
|
||||
this.cdRef.markForCheck();
|
||||
this.imageHeight.emit(this.currentImage.height);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue