Performance Improvements (#2449)
This commit is contained in:
parent
419a827d42
commit
5ed1eebd26
34 changed files with 389 additions and 132 deletions
8
UI/Web/src/app/_models/search/bookmark-search-result.ts
Normal file
8
UI/Web/src/app/_models/search/bookmark-search-result.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export interface BookmarkSearchResult {
|
||||
libraryId: number;
|
||||
seriesId: number;
|
||||
volumeId: number;
|
||||
chapterId: number;
|
||||
seriesName: string;
|
||||
localizedSeriesName: string;
|
||||
}
|
|
@ -3,6 +3,7 @@ import { Library } from "../library/library";
|
|||
import { MangaFile } from "../manga-file";
|
||||
import { SearchResult } from "./search-result";
|
||||
import { Tag } from "../tag";
|
||||
import {BookmarkSearchResult} from "./bookmark-search-result";
|
||||
|
||||
export class SearchResultGroup {
|
||||
libraries: Array<Library> = [];
|
||||
|
@ -14,6 +15,7 @@ export class SearchResultGroup {
|
|||
tags: Array<Tag> = [];
|
||||
files: Array<MangaFile> = [];
|
||||
chapters: Array<Chapter> = [];
|
||||
bookmarks: Array<BookmarkSearchResult> = [];
|
||||
|
||||
reset() {
|
||||
this.libraries = [];
|
||||
|
@ -25,5 +27,6 @@ export class SearchResultGroup {
|
|||
this.tags = [];
|
||||
this.files = [];
|
||||
this.chapters = [];
|
||||
this.bookmarks = [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ export class ActionService implements OnDestroy {
|
|||
}
|
||||
|
||||
editLibrary(library: Partial<Library>, callback?: LibraryActionCallback) {
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, { size: 'xl' });
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, {size: 'xl', fullscreen: 'md'});
|
||||
modalRef.componentInstance.library = library;
|
||||
modalRef.closed.subscribe((closeResult: {success: boolean, library: Library, coverImageUpdate: boolean}) => {
|
||||
if (callback) callback(library)
|
||||
|
@ -362,7 +362,7 @@ export class ActionService implements OnDestroy {
|
|||
|
||||
addMultipleToReadingList(seriesId: number, volumes: Array<Volume>, chapters?: Array<Chapter>, callback?: BooleanActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md', fullscreen: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesId = seriesId;
|
||||
this.readingListModalRef.componentInstance.volumeIds = volumes.map(v => v.id);
|
||||
this.readingListModalRef.componentInstance.chapterIds = chapters?.map(c => c.id);
|
||||
|
@ -404,7 +404,7 @@ export class ActionService implements OnDestroy {
|
|||
|
||||
addMultipleSeriesToReadingList(series: Array<Series>, callback?: BooleanActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md', fullscreen: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesIds = series.map(v => v.id);
|
||||
this.readingListModalRef.componentInstance.title = 'Multiple Selections';
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Multiple_Series;
|
||||
|
@ -432,7 +432,7 @@ export class ActionService implements OnDestroy {
|
|||
*/
|
||||
addMultipleSeriesToCollectionTag(series: Array<Series>, callback?: BooleanActionCallback) {
|
||||
if (this.collectionModalRef != null) { return; }
|
||||
this.collectionModalRef = this.modalService.open(BulkAddToCollectionComponent, { scrollable: true, size: 'md', windowClass: 'collection' });
|
||||
this.collectionModalRef = this.modalService.open(BulkAddToCollectionComponent, { scrollable: true, size: 'md', windowClass: 'collection', fullscreen: 'md' });
|
||||
this.collectionModalRef.componentInstance.seriesIds = series.map(v => v.id);
|
||||
this.collectionModalRef.componentInstance.title = 'New Collection';
|
||||
|
||||
|
@ -452,7 +452,7 @@ export class ActionService implements OnDestroy {
|
|||
|
||||
addSeriesToReadingList(series: Series, callback?: SeriesActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md', fullscreen: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesId = series.id;
|
||||
this.readingListModalRef.componentInstance.title = series.name;
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Series;
|
||||
|
@ -474,7 +474,7 @@ export class ActionService implements OnDestroy {
|
|||
|
||||
addVolumeToReadingList(volume: Volume, seriesId: number, callback?: VolumeActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md', fullscreen: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesId = seriesId;
|
||||
this.readingListModalRef.componentInstance.volumeId = volume.id;
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Volume;
|
||||
|
@ -496,7 +496,7 @@ export class ActionService implements OnDestroy {
|
|||
|
||||
addChapterToReadingList(chapter: Chapter, seriesId: number, callback?: ChapterActionCallback) {
|
||||
if (this.readingListModalRef != null) { return; }
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md' });
|
||||
this.readingListModalRef = this.modalService.open(AddToListModalComponent, { scrollable: true, size: 'md', fullscreen: 'md' });
|
||||
this.readingListModalRef.componentInstance.seriesId = seriesId;
|
||||
this.readingListModalRef.componentInstance.chapterId = chapter.id;
|
||||
this.readingListModalRef.componentInstance.type = ADD_FLOW.Chapter;
|
||||
|
@ -517,7 +517,7 @@ export class ActionService implements OnDestroy {
|
|||
}
|
||||
|
||||
editReadingList(readingList: ReadingList, callback?: ReadingListActionCallback) {
|
||||
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'lg' });
|
||||
const readingListModalRef = this.modalService.open(EditReadingListModalComponent, { scrollable: true, size: 'lg', fullscreen: 'md' });
|
||||
readingListModalRef.componentInstance.readingList = readingList;
|
||||
readingListModalRef.closed.pipe(take(1)).subscribe((list) => {
|
||||
if (callback && list !== undefined) {
|
||||
|
|
|
@ -43,7 +43,7 @@ export class ReviewCardComponent implements OnInit {
|
|||
} else {
|
||||
component = ReviewCardModalComponent;
|
||||
}
|
||||
const ref = this.modalService.open(component, {size: "lg"});
|
||||
const ref = this.modalService.open(component, {size: 'lg', fullscreen: 'md'});
|
||||
ref.componentInstance.review = this.review;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ export class ManageLibraryComponent implements OnInit {
|
|||
}
|
||||
|
||||
editLibrary(library: Library) {
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, { size: 'xl' });
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, { size: 'xl', fullscreen: 'md' });
|
||||
modalRef.componentInstance.library = library;
|
||||
modalRef.closed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(refresh => {
|
||||
if (refresh) {
|
||||
|
@ -109,7 +109,7 @@ export class ManageLibraryComponent implements OnInit {
|
|||
}
|
||||
|
||||
addLibrary() {
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, { size: 'xl' });
|
||||
const modalRef = this.modalService.open(LibrarySettingsModalComponent, { size: 'xl', fullscreen: 'md' });
|
||||
modalRef.closed.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(refresh => {
|
||||
if (refresh) {
|
||||
this.getLibraries();
|
||||
|
|
|
@ -96,7 +96,7 @@ export class ManageMediaSettingsComponent implements OnInit {
|
|||
}
|
||||
|
||||
openDirectoryChooser(existingDirectory: string, formControl: string) {
|
||||
const modalRef = this.modalService.open(DirectoryPickerComponent, { scrollable: true, size: 'lg' });
|
||||
const modalRef = this.modalService.open(DirectoryPickerComponent, { scrollable: true, size: 'lg', fullscreen: 'md' });
|
||||
modalRef.componentInstance.startingFolder = existingDirectory || '';
|
||||
modalRef.componentInstance.helpUrl = '';
|
||||
modalRef.closed.subscribe((closeResult: DirectoryPickerResult) => {
|
||||
|
|
|
@ -5,7 +5,7 @@ import { AccountService } from './_services/account.service';
|
|||
import { LibraryService } from './_services/library.service';
|
||||
import { NavService } from './_services/nav.service';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import {NgbModal, NgbOffcanvas, NgbRatingConfig} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {NgbModal, NgbModalConfig, NgbOffcanvas, NgbRatingConfig} from '@ng-bootstrap/ng-bootstrap';
|
||||
import { DOCUMENT, NgClass, NgIf, AsyncPipe } from '@angular/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import {ThemeService} from "./_services/theme.service";
|
||||
|
@ -32,7 +32,9 @@ export class AppComponent implements OnInit {
|
|||
constructor(private accountService: AccountService,
|
||||
private libraryService: LibraryService,
|
||||
private router: Router, private ngbModal: NgbModal, ratingConfig: NgbRatingConfig,
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService) {
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService, private modalConfig: NgbModalConfig) {
|
||||
|
||||
modalConfig.fullscreen = 'md';
|
||||
|
||||
// Setup default rating config
|
||||
ratingConfig.max = 5;
|
||||
|
|
|
@ -13,10 +13,16 @@
|
|||
(refreshToC)="refreshPersonalToC()">
|
||||
</app-book-line-overlay>
|
||||
<app-drawer #commentDrawer="drawer" [(isOpen)]="drawerOpen" [options]="{topOffset: topOffset}">
|
||||
<h5 header>
|
||||
{{t('title')}}
|
||||
</h5>
|
||||
<div header>
|
||||
<h5 class="mb-0">{{t('title')}}</h5>
|
||||
<span style="font-size: 14px; color: var(--primary-color)" tabindex="0" role="button" (click)="closeReader()">{{t('close-reader')}}</span>
|
||||
</div>
|
||||
<div subheader>
|
||||
<!-- <div class="g-0 text-center" *ngIf="!isLoading">-->
|
||||
<!-- <span *ngIf="incognitoMode" (click)="turnOffIncognito()" role="button" [attr.aria-label]="t('incognito-mode-alt')">-->
|
||||
<!-- (<i class="fa fa-glasses" aria-hidden="true"></i><span class="visually-hidden">{{t('incognito-mode-label')}}</span>)</span>-->
|
||||
<!-- <span class="book-title-text ms-1" [ngbTooltip]="bookTitle">{{bookTitle}}</span>-->
|
||||
<!-- </div>-->
|
||||
<div class="pagination-cont">
|
||||
<ng-container *ngIf="layoutMode !== BookPageLayoutMode.Default">
|
||||
<div class="virt-pagination-cont">
|
||||
|
@ -148,7 +154,7 @@
|
|||
<ng-template #showTitle>
|
||||
<span *ngIf="incognitoMode" (click)="turnOffIncognito()" role="button" [attr.aria-label]="t('incognito-mode-alt')">
|
||||
(<i class="fa fa-glasses" aria-hidden="true"></i><span class="visually-hidden">{{t('incognito-mode-label')}}</span>)</span>
|
||||
<span class="book-title-text ms-1" [ngbTooltip]="bookTitle">{{bookTitle}}</span>
|
||||
<span class="book-title-text ms-1" [ngbTooltip]="bookTitle">{{bookTitle}}</span>
|
||||
</ng-template>
|
||||
</div>
|
||||
<button class="btn btn-secondary col-2 col-xs-1" (click)="closeReader()"><i class="fa fa-times-circle" aria-hidden="true"></i></button>
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
<ng-container *transloco="let t; read: 'manga-reader'">
|
||||
<div class="reader" #reader [ngStyle]="{overflow: (isFullscreen ? 'auto' : 'visible')}">
|
||||
@if(debugMode) {
|
||||
<div class="fixed-top overlay">
|
||||
@for(img of cachedImages; track img.src) {
|
||||
<ng-container *ngIf="this.readerService.imageUrlToPageNum(img.src) as imageNum">
|
||||
<span class="me-1" [ngClass]="{'current': imageNum === this.pageNum, 'loaded': img.complete}">{{this.readerService.imageUrlToPageNum(img.src)}}</span>
|
||||
</ng-container>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="fixed-top overlay" *ngIf="menuOpen" [@slideFromTop]="menuOpen">
|
||||
<div style="display: flex; margin-top: 5px;">
|
||||
<button class="btn btn-icon" style="height: 100%" [title]="t('back')" (click)="closeReader()">
|
||||
|
@ -191,34 +200,34 @@
|
|||
<ng-container [ngSwitch]="layoutMode">
|
||||
<ng-container *ngSwitchCase="LayoutMode.Single">
|
||||
<div class="split-double">
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fa fa-image fa-stack-1x"></i>
|
||||
</span>
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fa fa-image fa-stack-1x"></i>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="LayoutMode.Double">
|
||||
<div class="split-double">
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-1 fa-stack-1x"></i>
|
||||
</span>
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-1 fa-stack-1x"></i>
|
||||
</span>
|
||||
<span class="fa-stack fa right">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-2 fa-stack-1x"></i>
|
||||
</span>
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-2 fa-stack-1x"></i>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="LayoutMode.DoubleReversed">
|
||||
<div class="split-double">
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-2 fa-stack-1x"></i>
|
||||
</span>
|
||||
<span class="fa-stack fa-1x">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-2 fa-stack-1x"></i>
|
||||
</span>
|
||||
<span class="fa-stack fa right">
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-1 fa-stack-1x"></i>
|
||||
</span>
|
||||
<i class="fa-regular fa-square-full fa-stack-2x"></i>
|
||||
<i class="fab fa-1 fa-stack-1x"></i>
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
@ -258,7 +267,8 @@
|
|||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<label for="darkness" class="form-label range-label">{{t('brightness-label')}}</label><span class="ms-1 range-text">{{generalSettingsForm.get('darkness')?.value + '%'}}</span>
|
||||
<label for="darkness" class="form-label range-label">{{t('brightness-label')}}</label>
|
||||
<span class="ms-1 range-text">{{generalSettingsForm.get('darkness')?.value + '%'}}</span>
|
||||
<input type="range" class="form-range" id="darkness"
|
||||
min="10" max="100" step="1" formControlName="darkness">
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,13 @@ $pointer-offset: 5px;
|
|||
|
||||
@use '../../.././../manga-reader-common';
|
||||
|
||||
.current {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.loaded {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.reading-area {
|
||||
|
@ -52,7 +58,7 @@ $pointer-offset: 5px;
|
|||
.overlay .right .i {
|
||||
right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Splitting Icon
|
||||
.split {
|
||||
|
@ -76,7 +82,7 @@ $pointer-offset: 5px;
|
|||
background-color: rgba(255, 255, 255, 0.6);
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
|
||||
/* Control the right side */
|
||||
.right-side {
|
||||
height: 20px;
|
||||
|
@ -112,7 +118,7 @@ $pointer-offset: 5px;
|
|||
.custom-slider .ngx-slider .ngx-slider-selection {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-pointer {
|
||||
width: 8px;
|
||||
height: 16px;
|
||||
|
@ -122,23 +128,23 @@ $pointer-offset: 5px;
|
|||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-pointer:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-bubble {
|
||||
bottom: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-limit {
|
||||
font-weight: bold;
|
||||
color: white !important;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-tick {
|
||||
width: 1px;
|
||||
height: 10px;
|
||||
|
@ -147,7 +153,7 @@ $pointer-offset: 5px;
|
|||
background: #ffe4d1;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
|
||||
.custom-slider .ngx-slider .ngx-slider-tick.ngx-slider-selected {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
@ -179,7 +185,7 @@ $pointer-offset: 5px;
|
|||
max-height: calc(var(--vh)*100);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
.top {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
|
@ -188,7 +194,7 @@ $pointer-offset: 5px;
|
|||
background: $pagination-bg;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
.left {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
|
@ -198,7 +204,7 @@ $pointer-offset: 5px;
|
|||
max-height: calc(var(--vh)*100);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
.bottom {
|
||||
position: fixed; // I couldn't figure out how to do this with abs, so only the bottom bar will not be scrollable
|
||||
left: 0px;
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {DOCUMENT, NgStyle, NgIf, NgFor, NgSwitch, NgSwitchCase, PercentPipe} from '@angular/common';
|
||||
import {DOCUMENT, NgStyle, NgIf, NgFor, NgSwitch, NgSwitchCase, PercentPipe, NgClass} from '@angular/common';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
|
@ -124,7 +124,7 @@ enum KeyDirection {
|
|||
imports: [NgStyle, NgIf, LoadingComponent, SwipeDirective, CanvasRendererComponent, SingleRendererComponent,
|
||||
DoubleRendererComponent, DoubleReverseRendererComponent, DoubleNoCoverRendererComponent, InfiniteScrollerComponent,
|
||||
NgxSliderModule, ReactiveFormsModule, NgFor, NgSwitch, NgSwitchCase, FittingIconPipe, ReaderModeIconPipe,
|
||||
FullscreenIconPipe, TranslocoDirective, NgbProgressbar, PercentPipe]
|
||||
FullscreenIconPipe, TranslocoDirective, NgbProgressbar, PercentPipe, NgClass]
|
||||
})
|
||||
export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
|
@ -392,6 +392,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
*/
|
||||
hasHitBottomTopScroll: boolean = false;
|
||||
|
||||
/**
|
||||
* Show and log debug information
|
||||
*/
|
||||
debugMode: boolean = false;
|
||||
|
||||
// Renderer interaction
|
||||
readerSettings$!: Observable<ReaderSetting>;
|
||||
private currentImage: Subject<HTMLImageElement | null> = new ReplaySubject(1);
|
||||
|
@ -405,7 +410,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return this.readerService.getPageUrl(chapterId, pageNum);
|
||||
}
|
||||
|
||||
|
||||
get CurrentPageBookmarked() {
|
||||
return this.bookmarks.hasOwnProperty(this.pageNum);
|
||||
}
|
||||
|
@ -479,7 +483,6 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.getPageFn = this.getPage.bind(this);
|
||||
this.readerService.enableWakeLock(this.reader.nativeElement);
|
||||
|
||||
this.libraryId = parseInt(libraryId, 10);
|
||||
this.seriesId = parseInt(seriesId, 10);
|
||||
|
@ -864,6 +867,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.render();
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
this.readerService.enableWakeLock(this.reader.nativeElement);
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1342,6 +1348,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (cachedImagePageNum !== numOffset) {
|
||||
this.cachedImages[index] = new Image();
|
||||
this.cachedImages[index].src = this.getPageUrl(numOffset);
|
||||
this.cachedImages[index].onload = (evt) => {
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,16 @@
|
|||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="bookmarkTemplate !== undefined && groupedData.bookmarks.length > 0">
|
||||
<li class="list-group-item section-header"><h5>{{t('bookmarks')}}</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li *ngFor="let option of groupedData.bookmarks; let index = index;" (click)="handleResultlick(option)" tabindex="0"
|
||||
class="list-group-item" role="option">
|
||||
<ng-container [ngTemplateOutlet]="bookmarkTemplate" [ngTemplateOutletContext]="{ $implicit: option, idx: index }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="libraryTemplate !== undefined && groupedData.libraries.length > 0">
|
||||
<li class="list-group-item section-header"><h5 id="libraries-group">{{t('libraries')}}</h5></li>
|
||||
<ul class="list-group results" role="group" aria-describedby="libraries-group">
|
||||
|
|
|
@ -80,6 +80,7 @@ export class GroupedTypeaheadComponent implements OnInit {
|
|||
@ContentChild('readingListTemplate') readingListTemplate!: TemplateRef<any>;
|
||||
@ContentChild('fileTemplate') fileTemplate!: TemplateRef<any>;
|
||||
@ContentChild('chapterTemplate') chapterTemplate!: TemplateRef<any>;
|
||||
@ContentChild('bookmarkTemplate') bookmarkTemplate!: TemplateRef<any>;
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
|
||||
|
@ -96,7 +97,7 @@ export class GroupedTypeaheadComponent implements OnInit {
|
|||
get hasData() {
|
||||
return !(this.noResultsTemplate != undefined && !this.groupedData.persons.length && !this.groupedData.collections.length
|
||||
&& !this.groupedData.series.length && !this.groupedData.persons.length && !this.groupedData.tags.length && !this.groupedData.genres.length && !this.groupedData.libraries.length
|
||||
&& !this.groupedData.files.length && !this.groupedData.chapters.length);
|
||||
&& !this.groupedData.files.length && !this.groupedData.chapters.length && !this.groupedData.bookmarks.length);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,23 @@
|
|||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #bookmarkTemplate let-item>
|
||||
<div style="display: flex;padding: 5px;" (click)="clickBookmarkSearchResult(item)">
|
||||
<div style="width: 24px" class="me-1">
|
||||
<app-image class="me-3 search-result" width="24px" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"></app-image>
|
||||
</div>
|
||||
<div class="ms-1">
|
||||
<app-series-format [format]="item.format"></app-series-format>
|
||||
<ng-container *ngIf="searchTerm.toLowerCase().trim() as st">
|
||||
<span *ngIf="item.seriesName.toLowerCase().trim().indexOf(st) >= 0; else localizedName">{{item.seriesName}}</span>
|
||||
<ng-template #localizedName>
|
||||
<span [innerHTML]="item.localizedSeriesName"></span>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #collectionTemplate let-item>
|
||||
<div style="display: flex;padding: 5px;" (click)="clickCollectionSearchResult(item)">
|
||||
<div style="width: 24px" class="me-1">
|
||||
|
|
|
@ -39,6 +39,7 @@ import {FilterUtilitiesService} from "../../../shared/_services/filter-utilities
|
|||
import {FilterStatement} from "../../../_models/metadata/v2/filter-statement";
|
||||
import {FilterField} from "../../../_models/metadata/v2/filter-field";
|
||||
import {FilterComparison} from "../../../_models/metadata/v2/filter-comparison";
|
||||
import {BookmarkSearchResult} from "../../../_models/search/bookmark-search-result";
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-header',
|
||||
|
@ -197,6 +198,15 @@ export class NavHeaderComponent implements OnInit {
|
|||
this.router.navigate(['library', libraryId, 'series', seriesId]);
|
||||
}
|
||||
|
||||
clickBookmarkSearchResult(item: BookmarkSearchResult) {
|
||||
this.clearSearch();
|
||||
const libraryId = item.libraryId;
|
||||
const seriesId = item.seriesId;
|
||||
this.router.navigate(['library', libraryId, 'series', seriesId, 'manga', item.chapterId], {queryParams: {
|
||||
incognitoMode: false, bookmarkMode: true
|
||||
}});
|
||||
}
|
||||
|
||||
clickFileSearchResult(item: MangaFile) {
|
||||
this.clearSearch();
|
||||
this.searchService.getSeriesForMangaFile(item.id).subscribe(series => {
|
||||
|
|
|
@ -73,7 +73,7 @@ export class ReadingListsComponent implements OnInit {
|
|||
}
|
||||
|
||||
importCbl() {
|
||||
const ref = this.ngbModal.open(ImportCblModalComponent, {size: 'xl'});
|
||||
const ref = this.ngbModal.open(ImportCblModalComponent, {size: 'xl', fullscreen: 'md'});
|
||||
ref.closed.subscribe(result => this.loadPage());
|
||||
ref.dismissed.subscribe(_ => this.loadPage());
|
||||
}
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
alt=""
|
||||
aria-hidden="true"
|
||||
[lazyLoad]="imageUrl"
|
||||
[errorImage]="errorImage"
|
||||
(onStateChange)="myCallbackFunction($event)">
|
||||
|
|
|
@ -172,7 +172,7 @@ export class ImageComponent implements OnChanges {
|
|||
case 'loading-failed':
|
||||
// The image could not be loaded for some reason.
|
||||
// `event.data` is the error in this case
|
||||
image.src = this.errorImage;
|
||||
this.renderer.removeClass(image, 'fade-in');
|
||||
this.cdRef.markForCheck();
|
||||
break;
|
||||
case 'finally':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue