Readable Bookmarks (#1228)
* Moved bookmarks to it's own page on side nav and integrated actions. * Implemented the ability to read bookmarks in the manga reader. * Removed old bookmark components that aren't needed any longer. * Removed recently added component as we use all-series instead now * Removed bookmark tab from card detail * Fixed scroll to top not working and being missing * When opening the side nav on mobile with metadata filter already open, collapse the filter. * When on mobile viewports, when clicking an item from side nav, collapse it afterwards * Converted most of series detail to use the card detail layout, except storyline which has custom logic * Fixed unit test
This commit is contained in:
parent
62715a9977
commit
9d6843614d
48 changed files with 648 additions and 634 deletions
|
|
@ -21,7 +21,7 @@
|
|||
<!-- {{this.pageNum}} -->
|
||||
<!-- {{readerService.imageUrlToPageNum(canvasImage.src)}}<ng-container *ngIf="ShouldRenderDoublePage && (this.pageNum + 1 <= maxPages - 1 && this.pageNum > 0)"> - {{PageNumber + 1}}</ng-container> -->
|
||||
|
||||
<button class="btn btn-icon btn-small" role="checkbox" [attr.aria-checked]="isCurrentPageBookmarked" title="{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}" (click)="bookmarkPage()"><i class="{{isCurrentPageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i><span class="visually-hidden">{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}</span></button>
|
||||
<button *ngIf="!bookmarkMode" class="btn btn-icon btn-small" role="checkbox" [attr.aria-checked]="isCurrentPageBookmarked" title="{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}" (click)="bookmarkPage()"><i class="{{isCurrentPageBookmarked ? 'fa' : 'far'}} fa-bookmark" aria-hidden="true"></i><span class="visually-hidden">{{isCurrentPageBookmarked ? 'Unbookmark Page' : 'Bookmark Page'}}</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
class="{{getFittingOptionClass()}} {{readerMode === ReaderMode.LeftRight || readerMode === ReaderMode.UpDown ? '' : 'd-none'}} {{showClickOverlay ? 'blur' : ''}}">
|
||||
|
||||
<ng-container *ngIf="ShouldRenderDoublePage && (this.pageNum + 1 <= maxPages - 1 && this.pageNum > 0)">
|
||||
<img [src]="readerService.getPageUrl(this.chapterId, PageNumber + 1)" id="image-2" class="image-2 {{getFittingOptionClass()}} {{readerMode === ReaderMode.LeftRight || readerMode === ReaderMode.UpDown ? '' : 'd-none'}} {{showClickOverlay ? 'blur' : ''}} {{ShouldRenderReverseDouble ? 'reverse' : ''}}">
|
||||
<img [src]="getPageUrl(PageNumber + 1)" id="image-2" class="image-2 {{getFittingOptionClass()}} {{readerMode === ReaderMode.LeftRight || readerMode === ReaderMode.UpDown ? '' : 'd-none'}} {{showClickOverlay ? 'blur' : ''}} {{ShouldRenderReverseDouble ? 'reverse' : ''}}">
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { LibraryType } from '../_models/library';
|
|||
import { ShorcutsModalComponent } from '../reader-shared/_modals/shorcuts-modal/shorcuts-modal.component';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { LayoutMode } from './_models/layout-mode';
|
||||
import { SeriesService } from '../_services/series.service';
|
||||
|
||||
const PREFETCH_PAGES = 8;
|
||||
|
||||
|
|
@ -79,6 +80,10 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
* If this is true, no progress will be saved.
|
||||
*/
|
||||
incognitoMode: boolean = false;
|
||||
/**
|
||||
* If this is true, we are reading a bookmark. ChapterId will be 0. There is no continuous reading. Progress is not saved. Bookmark control is removed.
|
||||
*/
|
||||
bookmarkMode: boolean = false;
|
||||
|
||||
/**
|
||||
* If this is true, chapters will be fetched in the order of a reading list, rather than natural series order.
|
||||
|
|
@ -257,7 +262,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
private readonly onDestroy = new Subject<void>();
|
||||
|
||||
|
||||
getPageUrl = (pageNum: number) => this.readerService.getPageUrl(this.chapterId, pageNum);
|
||||
//getPageUrl = (pageNum: number) => this.readerService.getPageUrl(this.chapterId, pageNum);
|
||||
|
||||
get PageNumber() {
|
||||
return Math.max(Math.min(this.pageNum, this.maxPages - 1), 0);
|
||||
|
|
@ -326,7 +331,8 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
private formBuilder: FormBuilder, private navService: NavService,
|
||||
private toastr: ToastrService, private memberService: MemberService,
|
||||
public utilityService: UtilityService, private renderer: Renderer2,
|
||||
@Inject(DOCUMENT) private document: Document, private modalService: NgbModal) {
|
||||
@Inject(DOCUMENT) private document: Document, private modalService: NgbModal,
|
||||
private seriesService: SeriesService) {
|
||||
this.navService.hideNavBar();
|
||||
this.navService.hideSideNav();
|
||||
}
|
||||
|
|
@ -347,6 +353,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.seriesId = parseInt(seriesId, 10);
|
||||
this.chapterId = parseInt(chapterId, 10);
|
||||
this.incognitoMode = this.route.snapshot.queryParamMap.get('incognitoMode') === 'true';
|
||||
this.bookmarkMode = this.route.snapshot.queryParamMap.get('bookmarkMode') === 'true';
|
||||
|
||||
const readingListId = this.route.snapshot.queryParamMap.get('readingListId');
|
||||
if (readingListId != null) {
|
||||
|
|
@ -506,12 +513,42 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.goToPageEvent.complete();
|
||||
}
|
||||
|
||||
if (this.bookmarkMode) {
|
||||
this.readerService.getBookmarkInfo(this.seriesId).subscribe(bookmarkInfo => {
|
||||
this.setPageNum(0);
|
||||
this.title = bookmarkInfo.seriesName + ' Bookmarks';
|
||||
this.libraryType = bookmarkInfo.libraryType;
|
||||
this.maxPages = bookmarkInfo.pages;
|
||||
|
||||
// Due to change detection rules in Angular, we need to re-create the options object to apply the change
|
||||
const newOptions: Options = Object.assign({}, this.pageOptions);
|
||||
newOptions.ceil = this.maxPages - 1; // We -1 so that the slider UI shows us hitting the end, since visually we +1 everything.
|
||||
this.pageOptions = newOptions;
|
||||
this.inSetup = false;
|
||||
this.prevChapterDisabled = true;
|
||||
this.nextChapterDisabled = true;
|
||||
|
||||
const images = [];
|
||||
for (let i = 0; i < PREFETCH_PAGES + 2; i++) {
|
||||
images.push(new Image());
|
||||
}
|
||||
|
||||
this.cachedImages = new CircularArray<HTMLImageElement>(images, 0);
|
||||
|
||||
this.render();
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
forkJoin({
|
||||
progress: this.readerService.getProgress(this.chapterId),
|
||||
chapterInfo: this.readerService.getChapterInfo(this.chapterId),
|
||||
bookmarks: this.readerService.getBookmarks(this.chapterId),
|
||||
}).pipe(take(1)).subscribe(results => {
|
||||
|
||||
|
||||
if (this.readingListMode && results.chapterInfo.seriesFormat === MangaFormat.EPUB) {
|
||||
// Redirect to the book reader.
|
||||
const params = this.readerService.getQueryParamsObject(this.incognitoMode, this.readingListMode, this.readingListId);
|
||||
|
|
@ -1049,7 +1086,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
if (offsetIndex < this.maxPages - 1) {
|
||||
item.src = this.readerService.getPageUrl(this.chapterId, offsetIndex);
|
||||
// if (this.bookmarkMode) item.src = this.readerService.getBookmarkPageUrl(this.seriesId, offsetIndex);
|
||||
// else item.src = this.readerService.getPageUrl(this.chapterId, offsetIndex);
|
||||
item.src = this.getPageUrl(offsetIndex);
|
||||
index += 1;
|
||||
}
|
||||
}, this.cachedImages.size() - 3);
|
||||
|
|
@ -1057,6 +1096,11 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
//console.log('cachedImages: ', this.cachedImages.arr.map(img => this.readerService.imageUrlToPageNum(img.src) + ': ' + img.complete));
|
||||
}
|
||||
|
||||
getPageUrl(pageNum: number) {
|
||||
if (this.bookmarkMode) return this.readerService.getBookmarkPageUrl(this.seriesId, this.user.apiKey, pageNum);
|
||||
return this.readerService.getPageUrl(this.chapterId, pageNum);
|
||||
}
|
||||
|
||||
loadPage() {
|
||||
if (!this.canvas || !this.ctx) { return; }
|
||||
|
||||
|
|
@ -1067,10 +1111,13 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
|
||||
if (this.readerService.imageUrlToPageNum(this.canvasImage.src) !== this.pageNum || this.canvasImage.src === '' || !this.canvasImage.complete) {
|
||||
if (this.layoutMode === LayoutMode.Single) {
|
||||
this.canvasImage.src = this.readerService.getPageUrl(this.chapterId, this.pageNum);
|
||||
//this.canvasImage.src = this.readerService.getPageUrl(this.chapterId, this.pageNum);
|
||||
this.canvasImage.src = this.getPageUrl(this.pageNum);
|
||||
} else {
|
||||
this.canvasImage.src = this.readerService.getPageUrl(this.chapterId, this.pageNum);
|
||||
this.canvasImage2.src = this.readerService.getPageUrl(this.chapterId, this.pageNum + 1); // TODO: I need to handle last page correctly
|
||||
// this.canvasImage.src = this.readerService.getPageUrl(this.chapterId, this.pageNum);
|
||||
// this.canvasImage2.src = this.readerService.getPageUrl(this.chapterId, this.pageNum + 1); // TODO: I need to handle last page correctly
|
||||
this.canvasImage.src = this.getPageUrl(this.pageNum);
|
||||
this.canvasImage2.src = this.getPageUrl(this.pageNum + 1); // TODO: I need to handle last page correctly
|
||||
}
|
||||
this.canvasImage.onload = () => this.renderPage();
|
||||
|
||||
|
|
@ -1143,7 +1190,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
tempPageNum = this.pageNum + 1;
|
||||
}
|
||||
|
||||
if (!this.incognitoMode) {
|
||||
if (!this.incognitoMode || !this.bookmarkMode) {
|
||||
this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, tempPageNum).pipe(take(1)).subscribe(() => {/* No operation */});
|
||||
}
|
||||
}
|
||||
|
|
@ -1297,7 +1344,9 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
const newRoute = this.readerService.getNextChapterUrl(this.router.url, this.chapterId, this.incognitoMode, this.readingListMode, this.readingListId);
|
||||
window.history.replaceState({}, '', newRoute);
|
||||
this.toastr.info('Incognito mode is off. Progress will now start being tracked.');
|
||||
this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, this.pageNum).pipe(take(1)).subscribe(() => {/* No operation */});
|
||||
if (!this.bookmarkMode) {
|
||||
this.readerService.saveProgress(this.seriesId, this.volumeId, this.chapterId, this.pageNum).pipe(take(1)).subscribe(() => {/* No operation */});
|
||||
}
|
||||
}
|
||||
|
||||
getWindowDimensions() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue