Change Detection: On Push aka UI Smoothness (#1369)
* Updated Series Info Cards to use OnPush and hooked in progress events when we do a mark as read/unread on entities. These events update progress bars but also will now trigger a re-calculation on Read Time Left. * Removed Library Card Component * Refactored manga reader title and subtitle calculation to the backend. * Coverted card actionables to onPush * Series Card on push cleanup * Updated edit collection tags for on push * Update cover image chooser for on push * Cleaned up carsouel reel * Updated cover image to allow for uploading gif and webp files * Bulk add to collection on push * Updated bulk operation to use on push. Updated bulk operation to have mark as unread and read buttons explicitly. Updated so add to collection is visible and delete. Fixed a bug where manage library component wasn't invoking the trackBy function * Updating entity title for on push * Removed file info component * Updated Mange Library for on push * Entity info cards on push * List item on push * Updated icon and title for on push and fixed some missing change detection on series detail * Restricted the typeahead interface to simplify the design * Edit Series Relation now shows a value in the dropdown for Parent relationships and disables the field. * Updated edit series relation to focus on new typeahead when adding a new relationship * Added some documentation and when Scanning a library, don't allow the user to enqueue the same job multiple times. * Applied the No-enqueue if already enqueued logic to other tasks * Library detail on push * Updated events widget to onpush * Card detail drawer on push. Card detail cover chooser now will show all chapter's covers for selection in cover chooser. * Chapter metadata detail on push * Removed Card Detail modal * All collections on push * Removed some comments * Updated bulk selection to use an observable rather than function calls so new on push strategy works * collection detail now uses on push and scroller is placed on correct element * Updated library recommended to on push. Ensure that when mark as read occurs, the appropriate streams are refreshed. * Updated library detail to on push * Update metadata fiter to onpush. Bugs found and reported to Project * person badge on push * Read more on push * Updated tag badge to on push * User login on push * When initing side nav, don't call an authenticated api until we are sure a user is logged in * Updated splash container to on push * Dashboard on push * Side nav slight refactor around some api calls * Cleaned up series card on push to use same cdRef naming convention * Updated Static Files to use caching * Added width and height to logo image * shortcuts modal on push * reading lists on push * Reading list detail on push * draggable ordered list on push * Refactored reading-list-detail to use a new item which drastically reduces renders on operations * series format on push * circular loader on push * Badge Expander on push * update notification modal on push * drawer on push * Edit Series Modal on push * reset password on push * review series modal on push * series metadata detail on push * theme manager on push * confirm reset password on push * register on push * confirm migration email on push * confirm email on push * add email to account migration on push * user preferences on push. Made global settings default open * edit series relation on push * Fixed an edge case bug for next chapter where if the current volume had a single chapter of 1 and the next volume had a chapter number of 0, it would say there are no more chapters. * Updated infinite scroller with on push support * Moved some animations over to typeahead, not integrated yet. * Manga reader is now on push * Reader settings on push * refactored how we close the book * Updated table of contents for on push * Updated book reader for on push. Fixed a bug where table of contents wasn't showing current page anchor due to a scroll calulation bug * Small code tweak * Icon and title on push * nav header on push * grouped typeahead on push * typeahead on push and added a new trackby identity function to allow even faster rendering of big lists * pdf reader on push * code cleanup
This commit is contained in:
parent
f5be0fac58
commit
4e49aa47ce
126 changed files with 1658 additions and 1674 deletions
|
|
@ -84,7 +84,7 @@
|
|||
tabindex="-1" [ngStyle]="{height: PageHeightForPagination}"></div>
|
||||
</ng-container>
|
||||
|
||||
<div class="book-container" [ngClass]="{'immersive' : immersiveMode}"> <!-- {{ColumnLayout}}-->
|
||||
<div class="book-container" [ngClass]="{'immersive' : immersiveMode}">
|
||||
|
||||
<div #readingHtml class="book-content {{ColumnLayout}}" [ngStyle]="{'max-height': ColumnHeight, 'column-width': ColumnWidth}"
|
||||
[ngClass]="{'immersive': immersiveMode && actionBarVisible}"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AfterViewInit, Component, ElementRef, HostListener, Inject, OnDestroy, OnInit, Renderer2, RendererStyleFlags2, ViewChild } from '@angular/core';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostListener, Inject, OnDestroy, OnInit, Renderer2, RendererStyleFlags2, ViewChild } from '@angular/core';
|
||||
import {DOCUMENT, Location} from '@angular/common';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
|
@ -54,6 +54,7 @@ const elementLevelStyles = ['line-height', 'font-family'];
|
|||
selector: 'app-book-reader',
|
||||
templateUrl: './book-reader.component.html',
|
||||
styleUrls: ['./book-reader.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
animations: [
|
||||
trigger('isLoading', [
|
||||
state('false', style({opacity: 1})),
|
||||
|
|
@ -110,8 +111,9 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
/**
|
||||
* A stack of the chapter ids we come across during continuous reading mode. When we traverse a boundary, we use this to avoid extra API calls.
|
||||
* @see Stack
|
||||
* TODO: See if continuousChaptersStack can be moved into reader service so we can reduce code duplication between readers (and also use ChapterInfo with it instead)
|
||||
*/
|
||||
continuousChaptersStack: Stack<number> = new Stack(); // TODO: See if continuousChaptersStack can be moved into reader service so we can reduce code duplication between readers (and also use ChapterInfo with it instead)
|
||||
continuousChaptersStack: Stack<number> = new Stack();
|
||||
|
||||
/**
|
||||
* Belongs to the drawer component
|
||||
|
|
@ -383,10 +385,11 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
private renderer: Renderer2, private navService: NavService, private toastr: ToastrService,
|
||||
private domSanitizer: DomSanitizer, private bookService: BookService, private memberService: MemberService,
|
||||
private scrollService: ScrollService, private utilityService: UtilityService, private libraryService: LibraryService,
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService) {
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService, private readonly cdRef: ChangeDetectorRef) {
|
||||
this.navService.hideNavBar();
|
||||
this.themeService.clearThemes();
|
||||
this.navService.hideSideNav();
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -411,7 +414,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
// Highlight the current chapter we are on
|
||||
if (Object.keys(this.pageAnchors).length !== 0) {
|
||||
// get the height of the document so we can capture markers that are halfway on the document viewport
|
||||
const verticalOffset = this.scrollService.scrollPosition + (this.document.body.offsetHeight / 2);
|
||||
const verticalOffset = this.reader.nativeElement?.scrollTop || (this.scrollService.scrollPosition + (this.document.body.offsetHeight / 2));
|
||||
|
||||
const alreadyReached = Object.values(this.pageAnchors).filter((i: number) => i <= verticalOffset);
|
||||
if (alreadyReached.length > 0) {
|
||||
|
|
@ -419,6 +422,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
} else {
|
||||
this.currentPageAnchor = '';
|
||||
}
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
// Find the element that is on screen to bookmark against
|
||||
|
|
@ -439,7 +444,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (!this.incognitoMode) {
|
||||
this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, tempPageNum, this.lastSeenScrollPartPath).pipe(take(1)).subscribe(() => {/* No operation */});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
|
@ -481,6 +485,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.readingListMode = true;
|
||||
this.readingListId = parseInt(readingListId, 10);
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
||||
this.memberService.hasReadingProgress(this.libraryId).pipe(take(1)).subscribe(hasProgress => {
|
||||
|
|
@ -504,18 +509,20 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.nextChapterDisabled = false;
|
||||
this.prevChapterDisabled = false;
|
||||
this.nextChapterPrefetched = false;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
||||
|
||||
this.bookService.getBookInfo(this.chapterId).subscribe(info => {
|
||||
this.bookTitle = info.bookTitle;
|
||||
|
||||
if (this.readingListMode && info.seriesFormat !== MangaFormat.EPUB) {
|
||||
// Redirect to the manga reader.
|
||||
const params = this.readerService.getQueryParamsObject(this.incognitoMode, this.readingListMode, this.readingListId);
|
||||
this.router.navigate(this.readerService.getNavigationArray(info.libraryId, info.seriesId, this.chapterId, info.seriesFormat), {queryParams: params});
|
||||
return;
|
||||
}
|
||||
|
||||
this.bookTitle = info.bookTitle;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
forkJoin({
|
||||
chapter: this.seriesService.getChapter(this.chapterId),
|
||||
|
|
@ -527,23 +534,21 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.maxPages = results.chapter.pages;
|
||||
this.chapters = results.chapters;
|
||||
this.pageNum = results.progress.pageNum;
|
||||
this.cdRef.markForCheck();
|
||||
if (results.progress.bookScrollId) this.lastSeenScrollPartPath = results.progress.bookScrollId;
|
||||
|
||||
|
||||
|
||||
this.continuousChaptersStack.push(this.chapterId);
|
||||
|
||||
this.libraryService.getLibraryType(this.libraryId).pipe(take(1)).subscribe(type => {
|
||||
this.libraryType = type;
|
||||
});
|
||||
|
||||
// We need to think about if the user modified this and this function call is a continuous reader one
|
||||
//this.updateLayoutMode(this.user.preferences.bookReaderLayoutMode || BookPageLayoutMode.Default);
|
||||
this.updateImagesWithHeight();
|
||||
|
||||
|
||||
if (this.pageNum >= this.maxPages) {
|
||||
this.pageNum = this.maxPages - 1;
|
||||
this.cdRef.markForCheck();
|
||||
this.saveProgress();
|
||||
}
|
||||
|
||||
|
|
@ -552,6 +557,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (chapterId === CHAPTER_ID_DOESNT_EXIST || chapterId === this.chapterId) {
|
||||
this.nextChapterDisabled = true;
|
||||
this.nextChapterPrefetched = true;
|
||||
this.cdRef.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.setPageNum(this.pageNum);
|
||||
|
|
@ -561,6 +567,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (chapterId === CHAPTER_ID_DOESNT_EXIST || chapterId === this.chapterId) {
|
||||
this.prevChapterDisabled = true;
|
||||
this.prevChapterPrefetched = true; // If there is no prev chapter, then mark it as prefetched
|
||||
this.cdRef.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.setPageNum(this.pageNum);
|
||||
|
|
@ -577,20 +584,11 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event: any){
|
||||
// Update the window Height
|
||||
this.updateWidthAndHeightCalcs();
|
||||
|
||||
const resumeElement = this.getFirstVisibleElementXPath();
|
||||
if (this.layoutMode !== BookPageLayoutMode.Default && resumeElement !== null && resumeElement !== undefined) {
|
||||
this.scrollTo(resumeElement); // This works pretty well, but not perfect
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('window:orientationchange', ['$event'])
|
||||
onOrientationChange() {
|
||||
onResize(){
|
||||
// Update the window Height
|
||||
this.updateWidthAndHeightCalcs();
|
||||
|
||||
const resumeElement = this.getFirstVisibleElementXPath();
|
||||
if (this.layoutMode !== BookPageLayoutMode.Default && resumeElement !== null && resumeElement !== undefined) {
|
||||
this.scrollTo(resumeElement); // This works pretty well, but not perfect
|
||||
|
|
@ -616,6 +614,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
closeReader() {
|
||||
this.readerService.closeReader(this.readingListMode, this.readingListId);
|
||||
}
|
||||
|
||||
sortElements(a: Element, b: Element) {
|
||||
const aTop = a.getBoundingClientRect().top;
|
||||
const bTop = b.getBoundingClientRect().top;
|
||||
|
|
@ -646,6 +648,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.prevPageDisabled) { return; }
|
||||
|
||||
this.isLoading = true;
|
||||
this.cdRef.markForCheck();
|
||||
this.continuousChaptersStack.pop();
|
||||
const prevChapter = this.continuousChaptersStack.peek();
|
||||
if (prevChapter != this.chapterId) {
|
||||
|
|
@ -657,6 +660,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
if (this.prevChapterPrefetched && this.prevChapterId === CHAPTER_ID_DOESNT_EXIST) {
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -677,8 +682,9 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
// Load chapter Id onto route but don't reload
|
||||
const newRoute = this.readerService.getNextChapterUrl(this.router.url, this.chapterId, this.incognitoMode, this.readingListMode, this.readingListId);
|
||||
window.history.replaceState({}, '', newRoute);
|
||||
this.init();
|
||||
this.toastr.info(direction + ' ' + this.utilityService.formatChapterName(this.libraryType).toLowerCase() + ' loaded', '', {timeOut: 3000});
|
||||
this.cdRef.markForCheck();
|
||||
this.init();
|
||||
} else {
|
||||
// This will only happen if no actual chapter can be found
|
||||
this.toastr.warning('Could not find ' + direction.toLowerCase() + ' ' + this.utilityService.formatChapterName(this.libraryType).toLowerCase());
|
||||
|
|
@ -688,6 +694,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
} else {
|
||||
this.nextPageDisabled = true;
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -696,15 +703,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.loadPage('id("' + event.part + '")');
|
||||
}
|
||||
|
||||
closeReader() {
|
||||
if (this.readingListMode) {
|
||||
this.router.navigateByUrl('lists/' + this.readingListId);
|
||||
} else {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a click handler for any anchors that have 'kavita-page'. If 'kavita-page' present, changes page to kavita-page and optionally passes a part value
|
||||
* from 'kavita-part', which will cause the reader to scroll to the marker.
|
||||
|
|
@ -775,14 +773,15 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
loadPage(part?: string | undefined, scrollTop?: number | undefined) {
|
||||
this.isLoading = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.bookService.getBookPage(this.chapterId, this.pageNum).pipe(take(1)).subscribe(content => {
|
||||
this.page = this.domSanitizer.bypassSecurityTrustHtml(content); // PERF: Potential optimization to prefetch next/prev page and store in localStorage
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
setTimeout(() => {
|
||||
this.addLinkClickHandlers();
|
||||
this.updateReaderStyles(this.pageStyles);
|
||||
this.updateReaderStyles(this.pageStyles);
|
||||
|
||||
const imgs = this.readingSectionElemRef.nativeElement.querySelectorAll('img');
|
||||
if (imgs === null || imgs.length === 0) {
|
||||
|
|
@ -805,7 +804,6 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
* Applies a max-height inline css property on each image in the page if the layout mode is column-based, else it removes the property
|
||||
*/
|
||||
updateImagesWithHeight() {
|
||||
|
||||
const images = this.readingSectionElemRef?.nativeElement.querySelectorAll('img') || [];
|
||||
|
||||
if (this.layoutMode !== BookPageLayoutMode.Default) {
|
||||
|
|
@ -822,6 +820,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
setupPage(part?: string | undefined, scrollTop?: number | undefined) {
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// Virtual Paging stuff
|
||||
this.updateWidthAndHeightCalcs();
|
||||
|
|
@ -853,6 +852,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
// we need to click the document before arrow keys will scroll down.
|
||||
this.reader.nativeElement.focus();
|
||||
this.saveProgress();
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -868,21 +869,24 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
setPageNum(pageNum: number) {
|
||||
this.pageNum = Math.max(Math.min(pageNum, this.maxPages), 0);
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
if (this.pageNum >= this.maxPages - 10) {
|
||||
// Tell server to cache the next chapter
|
||||
if (!this.nextChapterPrefetched && this.nextChapterId !== CHAPTER_ID_DOESNT_EXIST) { // && !this.nextChapterDisabled
|
||||
if (!this.nextChapterPrefetched && this.nextChapterId !== CHAPTER_ID_DOESNT_EXIST) {
|
||||
this.readerService.getChapterInfo(this.nextChapterId).pipe(take(1), catchError(err => {
|
||||
this.nextChapterDisabled = true;
|
||||
this.cdRef.markForCheck();
|
||||
return of(null);
|
||||
})).subscribe(res => {
|
||||
this.nextChapterPrefetched = true;
|
||||
});
|
||||
}
|
||||
} else if (this.pageNum <= 10) {
|
||||
if (!this.prevChapterPrefetched && this.prevChapterId !== CHAPTER_ID_DOESNT_EXIST) { // && !this.prevChapterDisabled
|
||||
if (!this.prevChapterPrefetched && this.prevChapterId !== CHAPTER_ID_DOESNT_EXIST) {
|
||||
this.readerService.getChapterInfo(this.prevChapterId).pipe(take(1), catchError(err => {
|
||||
this.prevChapterDisabled = true;
|
||||
this.cdRef.markForCheck();
|
||||
return of(null);
|
||||
})).subscribe(res => {
|
||||
this.prevChapterPrefetched = true;
|
||||
|
|
@ -1105,6 +1109,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
// Recalculate if bottom action bar is needed
|
||||
this.scrollbarNeeded = this.readingHtml.nativeElement.clientHeight > this.reader.nativeElement.clientHeight;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
toggleDrawer() {
|
||||
|
|
@ -1113,6 +1118,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.immersiveMode) {
|
||||
this.actionBarVisible = false;
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
scrollTo(partSelector: string) {
|
||||
|
|
@ -1133,7 +1139,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.layoutMode === BookPageLayoutMode.Default) {
|
||||
const fromTopOffset = element.getBoundingClientRect().top + window.pageYOffset + TOP_OFFSET;
|
||||
// We need to use a delay as webkit browsers (aka apple devices) don't always have the document rendered by this point
|
||||
setTimeout(() => this.scrollService.scrollTo(fromTopOffset, this.reader.nativeElement), 10);
|
||||
setTimeout(() => this.scrollService.scrollTo(fromTopOffset, this.reader.nativeElement), 10); // BUG: This is broken
|
||||
} else {
|
||||
setTimeout(() => (element as Element).scrollIntoView({'block': 'start', 'inline': 'start'}));
|
||||
}
|
||||
|
|
@ -1184,11 +1190,13 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.isFullscreen) {
|
||||
this.readerService.exitFullscreen(() => {
|
||||
this.isFullscreen = false;
|
||||
this.cdRef.markForCheck();
|
||||
this.renderer.removeStyle(this.reader.nativeElement, 'background');
|
||||
});
|
||||
} else {
|
||||
this.readerService.enterFullscreen(this.reader.nativeElement, () => {
|
||||
this.isFullscreen = true;
|
||||
this.cdRef.markForCheck();
|
||||
// HACK: This is a bug with how browsers change the background color for fullscreen mode
|
||||
this.renderer.setStyle(this.reader.nativeElement, 'background', this.themeService.getCssVariable('--bs-body-color'));
|
||||
if (!this.darkMode) {
|
||||
|
|
@ -1200,6 +1208,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
updateLayoutMode(mode: BookPageLayoutMode) {
|
||||
this.layoutMode = mode;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// Remove any max-heights from column layout
|
||||
this.updateImagesWithHeight();
|
||||
|
|
@ -1209,7 +1218,10 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
setTimeout(() => this.updateLayoutMode(this.layoutMode), 10);
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {this.scrollbarNeeded = this.readingHtml.nativeElement.clientHeight > this.reader.nativeElement.clientHeight;});
|
||||
setTimeout(() => {
|
||||
this.scrollbarNeeded = this.readingHtml.nativeElement.clientHeight > this.reader.nativeElement.clientHeight;
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
// When I switch layout, I might need to resume the progress point.
|
||||
if (mode === BookPageLayoutMode.Default) {
|
||||
|
|
@ -1220,6 +1232,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
updateReadingDirection(readingDirection: ReadingDirection) {
|
||||
this.readingDirection = readingDirection;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
updateImmersiveMode(immersiveMode: boolean) {
|
||||
|
|
@ -1227,13 +1240,12 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
if (this.immersiveMode && !this.drawerOpen) {
|
||||
this.actionBarVisible = false;
|
||||
}
|
||||
|
||||
this.updateReadingSectionHeight();
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
updateReadingSectionHeight() {
|
||||
setTimeout(() => {
|
||||
//console.log('setting height on ', this.readingSectionElemRef)
|
||||
if (this.immersiveMode) {
|
||||
this.renderer.setStyle(this.readingSectionElemRef, 'height', 'calc(var(--vh, 1vh) * 100)', RendererStyleFlags2.Important);
|
||||
} else {
|
||||
|
|
@ -1263,6 +1275,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
setupPageAnchors() {
|
||||
this.pageAnchors = {};
|
||||
this.currentPageAnchor = '';
|
||||
this.cdRef.markForCheck();
|
||||
const ids = this.chapters.map(item => item.children).flat().filter(item => item.page === this.pageNum).map(item => item.part).filter(item => item.length > 0);
|
||||
if (ids.length > 0) {
|
||||
const elems = this.getPageMarkers(ids);
|
||||
|
|
@ -1275,6 +1288,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
// Settings Handlers
|
||||
showPaginationOverlay(clickToPaginate: boolean) {
|
||||
this.clickToPaginate = clickToPaginate;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.clearTimeout(this.clickToPaginateVisualOverlayTimeout2);
|
||||
if (!clickToPaginate) { return; }
|
||||
|
|
@ -1293,6 +1307,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
showClickToPaginateVisualOverlay() {
|
||||
this.clickToPaginateVisualOverlay = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
if (this.clickToPaginateVisualOverlay && this.clickToPaginateVisualOverlayTimeout !== undefined) {
|
||||
clearTimeout(this.clickToPaginateVisualOverlayTimeout);
|
||||
|
|
@ -1300,6 +1315,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
this.clickToPaginateVisualOverlayTimeout = setTimeout(() => {
|
||||
this.clickToPaginateVisualOverlay = false;
|
||||
this.cdRef.markForCheck();
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
|
@ -1338,8 +1354,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
Math.abs(this.mousePosition.y - event.screenY) <= mouseOffset
|
||||
) {
|
||||
this.actionBarVisible = !this.actionBarVisible;
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mouseDown($event: MouseEvent) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DOCUMENT } from '@angular/common';
|
||||
import { Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { Subject, take, takeUntil } from 'rxjs';
|
||||
import { BookPageLayoutMode } from 'src/app/_models/book-page-layout-mode';
|
||||
|
|
@ -60,7 +60,8 @@ const mobileBreakpointMarginOverride = 700;
|
|||
@Component({
|
||||
selector: 'app-reader-settings',
|
||||
templateUrl: './reader-settings.component.html',
|
||||
styleUrls: ['./reader-settings.component.scss']
|
||||
styleUrls: ['./reader-settings.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
|
|
@ -131,12 +132,14 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
|||
|
||||
|
||||
constructor(private bookService: BookService, private accountService: AccountService,
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService) {}
|
||||
@Inject(DOCUMENT) private document: Document, private themeService: ThemeService,
|
||||
private readonly cdRef: ChangeDetectorRef) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
this.fontFamilies = this.bookService.getFontFamilies();
|
||||
this.fontOptions = this.fontFamilies.map(f => f.title);
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
if (user) {
|
||||
|
|
@ -211,6 +214,7 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
|||
|
||||
|
||||
this.setTheme(this.user.preferences.bookReaderThemeName || this.themeService.defaultBookTheme);
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
// Emit first time so book reader gets the setting
|
||||
this.readingDirection.emit(this.readingDirectionModel);
|
||||
|
|
@ -241,6 +245,7 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
this.settingsForm.get('bookReaderFontFamily')?.setValue(this.user.preferences.bookReaderFontFamily);
|
||||
this.cdRef.markForCheck();
|
||||
this.styleUpdate.emit(this.pageStyles);
|
||||
}
|
||||
|
||||
|
|
@ -264,12 +269,12 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
|||
'margin-right': margin || this.pageStyles['margin-right'] || defaultMargin,
|
||||
'line-height': lineHeight || this.pageStyles['line-height'] || '100%'
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
setTheme(themeName: string) {
|
||||
const theme = this.themes.find(t => t.name === themeName);
|
||||
this.activeTheme = theme;
|
||||
this.cdRef.markForCheck();
|
||||
this.colorThemeUpdate.emit(theme);
|
||||
}
|
||||
|
||||
|
|
@ -280,11 +285,13 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy {
|
|||
this.readingDirectionModel = ReadingDirection.LeftToRight;
|
||||
}
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
this.readingDirection.emit(this.readingDirectionModel);
|
||||
}
|
||||
|
||||
toggleFullscreen() {
|
||||
this.isFullscreen = !this.isFullscreen;
|
||||
this.cdRef.markForCheck();
|
||||
this.fullscreen.emit();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<div class="table-of-contents">
|
||||
<!-- <h3>Table of Contents</h3> -->
|
||||
<div *ngIf="chapters.length === 0">
|
||||
<em>This book does not have Table of Contents set in the metadata or a toc file</em>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { BookChapterItem } from '../_models/book-chapter-item';
|
||||
|
||||
@Component({
|
||||
selector: 'app-table-of-contents',
|
||||
templateUrl: './table-of-contents.component.html',
|
||||
styleUrls: ['./table-of-contents.component.scss']
|
||||
styleUrls: ['./table-of-contents.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.Default
|
||||
})
|
||||
export class TableOfContentsComponent implements OnInit, OnDestroy {
|
||||
|
||||
|
|
@ -16,11 +17,8 @@ export class TableOfContentsComponent implements OnInit, OnDestroy {
|
|||
|
||||
@Output() loadChapter: EventEmitter<{pageNum: number, part: string}> = new EventEmitter();
|
||||
|
||||
|
||||
|
||||
private onDestroy: Subject<void> = new Subject();
|
||||
|
||||
|
||||
pageAnchors: {[n: string]: number } = {};
|
||||
|
||||
constructor() {}
|
||||
|
|
@ -44,5 +42,4 @@ export class TableOfContentsComponent implements OnInit, OnDestroy {
|
|||
loadChapterPage(pageNum: number, part: string) {
|
||||
this.loadChapter.emit({pageNum, part});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue