Random Fixes (#3549)
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
ea81a2f432
commit
39726f8c4d
33 changed files with 425 additions and 107 deletions
|
@ -109,6 +109,7 @@ export class ReaderService {
|
|||
return this.httpClient.post<PageBookmark[]>(this.baseUrl + 'reader/all-bookmarks', filter);
|
||||
}
|
||||
|
||||
|
||||
getBookmarks(chapterId: number) {
|
||||
return this.httpClient.get<PageBookmark[]>(this.baseUrl + 'reader/chapter-bookmarks?chapterId=' + chapterId);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<ng-container *transloco="let t; read: 'related-tab'">
|
||||
<div style="padding-bottom: 1rem;">
|
||||
<div class="pb-2">
|
||||
@if (relations.length > 0) {
|
||||
<app-carousel-reel [items]="relations" [title]="t('relations-title')">
|
||||
<ng-template #carouselItem let-item>
|
||||
|
@ -30,5 +30,18 @@
|
|||
</ng-template>
|
||||
</app-carousel-reel>
|
||||
}
|
||||
|
||||
@if (bookmarks.length > 0) {
|
||||
<app-carousel-reel [items]="bookmarks" [title]="t('bookmarks-title')">
|
||||
<ng-template #carouselItem let-item>
|
||||
<app-card-item [entity]="item" [title]="t('bookmarks-title')" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"
|
||||
[suppressArchiveWarning]="true"
|
||||
[linkUrl]="'/library/' + libraryId + '/series/' + item.seriesId + '/manga/0?bookmarkMode=true'"
|
||||
(clicked)="viewBookmark(item)"
|
||||
[count]="bookmarks.length"
|
||||
[allowSelection]="false"></app-card-item>
|
||||
</ng-template>
|
||||
</app-carousel-reel>
|
||||
}
|
||||
</div>
|
||||
</ng-container>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ChangeDetectionStrategy, Component, inject, Input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, inject, Input, OnInit} from '@angular/core';
|
||||
import {ReadingList} from "../../_models/reading-list";
|
||||
import {CardItemComponent} from "../../cards/card-item/card-item.component";
|
||||
import {CarouselReelComponent} from "../../carousel/_components/carousel-reel/carousel-reel.component";
|
||||
|
@ -9,6 +9,7 @@ import {Router} from "@angular/router";
|
|||
import {SeriesCardComponent} from "../../cards/series-card/series-card.component";
|
||||
import {Series} from "../../_models/series";
|
||||
import {RelationKind} from "../../_models/series-detail/relation-kind";
|
||||
import {PageBookmark} from "../../_models/readers/page-bookmark";
|
||||
|
||||
export interface RelatedSeriesPair {
|
||||
series: Series;
|
||||
|
@ -28,7 +29,7 @@ export interface RelatedSeriesPair {
|
|||
styleUrl: './related-tab.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class RelatedTabComponent {
|
||||
export class RelatedTabComponent implements OnInit {
|
||||
|
||||
protected readonly imageService = inject(ImageService);
|
||||
protected readonly router = inject(Router);
|
||||
|
@ -36,6 +37,12 @@ export class RelatedTabComponent {
|
|||
@Input() readingLists: Array<ReadingList> = [];
|
||||
@Input() collections: Array<UserCollection> = [];
|
||||
@Input() relations: Array<RelatedSeriesPair> = [];
|
||||
@Input() bookmarks: Array<PageBookmark> = [];
|
||||
@Input() libraryId!: number;
|
||||
|
||||
ngOnInit() {
|
||||
console.log('bookmarks: ', this.bookmarks);
|
||||
}
|
||||
|
||||
openReadingList(readingList: ReadingList) {
|
||||
this.router.navigate(['lists', readingList.id]);
|
||||
|
@ -45,4 +52,8 @@ export class RelatedTabComponent {
|
|||
this.router.navigate(['collections', collection.id]);
|
||||
}
|
||||
|
||||
viewBookmark(bookmark: PageBookmark) {
|
||||
this.router.navigate(['library', this.libraryId, 'series', bookmark.seriesId, 'manga', 0], {queryParams: {incognitoMode: false, bookmarkMode: true}});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,18 @@
|
|||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FastFontSerif";
|
||||
src: url(../../../../assets/fonts/Fast_Font/Fast_Serif.woff2) format("woff2");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "FastFontSans";
|
||||
src: url(../../../../assets/fonts/Fast_Font/Fast_Sans.woff2) format("woff2");
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
:root {
|
||||
--br-actionbar-button-text-color: #6c757d;
|
||||
--accordion-body-bg-color: black;
|
||||
|
|
|
@ -103,7 +103,7 @@ export const BookWhiteTheme = `
|
|||
|
||||
|
||||
.book-content *:not(input), .book-content *:not(select), .book-content *:not(code), .book-content *:not(:link), .book-content *:not(.ngx-toastr) {
|
||||
color: black !important;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.book-content code {
|
||||
|
@ -125,7 +125,7 @@ export const BookWhiteTheme = `
|
|||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
border-radius: unset;
|
||||
color: #dcdcdc !important;
|
||||
color: #dcdcdc;
|
||||
}
|
||||
|
||||
.book-content :visited, .book-content :visited *, .book-content :visited *[class] {
|
||||
|
|
|
@ -28,7 +28,7 @@ export class BookService {
|
|||
getFontFamilies(): Array<FontFamily> {
|
||||
return [{title: 'default', family: 'default'}, {title: 'EBGaramond', family: 'EBGaramond'}, {title: 'Fira Sans', family: 'Fira_Sans'},
|
||||
{title: 'Lato', family: 'Lato'}, {title: 'Libre Baskerville', family: 'Libre_Baskerville'}, {title: 'Merriweather', family: 'Merriweather'},
|
||||
{title: 'Nanum Gothic', family: 'Nanum_Gothic'}, {title: 'RocknRoll One', family: 'RocknRoll_One'}, {title: 'Open Dyslexic', family: 'OpenDyslexic2'}];
|
||||
{title: 'Nanum Gothic', family: 'Nanum_Gothic'}, {title: 'Open Dyslexic', family: 'OpenDyslexic2'}, {title: 'RocknRoll One', family: 'RocknRoll_One'}, {title: 'Fast Font Serif (Bionic)', family: 'FastFontSerif'}, {title: 'Fast Font Sans (Bionic)', family: 'FastFontSans'}];
|
||||
}
|
||||
|
||||
getBookChapters(chapterId: number) {
|
||||
|
|
|
@ -7,27 +7,29 @@
|
|||
<h5 subtitle>{{t('series-count', {num: series.length | number})}}</h5>
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[isLoading]="loadingBookmarks"
|
||||
[items]="series"
|
||||
[filterSettings]="filterSettings"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
[refresh]="refresh"
|
||||
[jumpBarKeys]="jumpbarKeys"
|
||||
(applyFilter)="updateFilter($event)"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx">
|
||||
<app-card-item [entity]="item" [title]="item.name" [imageUrl]="imageService.getSeriesCoverImage(item.id)"
|
||||
[suppressArchiveWarning]="true" (clicked)="viewBookmarks(item)" [count]="seriesIds[item.id]" [allowSelection]="true"
|
||||
[actions]="actions"
|
||||
[selected]="bulkSelectionService.isCardSelected('bookmark', position)"
|
||||
(selection)="bulkSelectionService.handleCardSelection('bookmark', position, series.length, $event)"
|
||||
></app-card-item>
|
||||
</ng-template>
|
||||
@if (filter) {
|
||||
<app-card-detail-layout
|
||||
[isLoading]="loadingBookmarks"
|
||||
[items]="series"
|
||||
[filterSettings]="filterSettings"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
[refresh]="refresh"
|
||||
[jumpBarKeys]="jumpbarKeys"
|
||||
(applyFilter)="updateFilter($event)"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx">
|
||||
<app-card-item [entity]="item" [title]="item.name" [imageUrl]="imageService.getSeriesCoverImage(item.id)"
|
||||
[suppressArchiveWarning]="true" (clicked)="viewBookmarks(item)" [count]="seriesIds[item.id]" [allowSelection]="true"
|
||||
[actions]="actions"
|
||||
[selected]="bulkSelectionService.isCardSelected('bookmark', position)"
|
||||
(selection)="bulkSelectionService.handleCardSelection('bookmark', position, series.length, $event)"
|
||||
></app-card-item>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #noData>
|
||||
{{t('no-data')}} <a [href]="WikiLink.Bookmarks" rel="noopener noreferrer" target="_blank">{{t('no-data-2')}}<i class="fa fa-external-link-alt ms-1" aria-hidden="true"></i></a>
|
||||
</ng-template>
|
||||
</app-card-detail-layout>
|
||||
<ng-template #noData>
|
||||
{{t('no-data')}} <a [href]="WikiLink.Bookmarks" rel="noopener noreferrer" target="_blank">{{t('no-data-2')}}<i class="fa fa-external-link-alt ms-1" aria-hidden="true"></i></a>
|
||||
</ng-template>
|
||||
</app-card-detail-layout>
|
||||
}
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -15,7 +15,6 @@ import { FilterSettings } from 'src/app/metadata-filter/filter-settings';
|
|||
import { ConfirmService } from 'src/app/shared/confirm.service';
|
||||
import {DownloadService} from 'src/app/shared/_services/download.service';
|
||||
import { FilterUtilitiesService } from 'src/app/shared/_services/filter-utilities.service';
|
||||
import { KEY_CODES } from 'src/app/shared/_services/utility.service';
|
||||
import { JumpKey } from 'src/app/_models/jumpbar/jump-key';
|
||||
import { PageBookmark } from 'src/app/_models/readers/page-bookmark';
|
||||
import { Pagination } from 'src/app/_models/pagination';
|
||||
|
@ -103,13 +102,13 @@ export class BookmarksComponent implements OnInit {
|
|||
async handleAction(action: ActionItem<Series>, series: Series) {
|
||||
switch (action.action) {
|
||||
case(Action.Delete):
|
||||
this.clearBookmarks(series);
|
||||
await this.clearBookmarks(series);
|
||||
break;
|
||||
case(Action.DownloadBookmark):
|
||||
this.downloadBookmarks(series);
|
||||
break;
|
||||
case(Action.ViewSeries):
|
||||
this.router.navigate(['library', series.libraryId, 'series', series.id]);
|
||||
await this.router.navigate(['library', series.libraryId, 'series', series.id]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="progress-banner">
|
||||
@if (read > 0 && read < total && total > 0 && read !== total) {
|
||||
<p ngbTooltip="{{((read / total) * 100) | number:'1.0-1'}}% Read">
|
||||
<p ngbTooltip="{{((read / total) * 100) | number:'1.0-1'}}% Read" container="body">
|
||||
<ngb-progressbar type="primary" height="5px" [value]="read" [max]="total"></ngb-progressbar>
|
||||
</p>
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="progress-banner">
|
||||
@if (chapter.pagesRead > 0 && chapter.pagesRead < chapter.pages && chapter.pages > 0 && chapter.pagesRead !== chapter.pages) {
|
||||
<p ngbTooltip="{{((chapter.pagesRead / chapter.pages) * 100) | number:'1.0-1'}}% Read">
|
||||
<p ngbTooltip="{{((chapter.pagesRead / chapter.pages) * 100) | number:'1.0-1'}}% Read" container="body">
|
||||
<ngb-progressbar type="primary" height="5px" [value]="chapter.pagesRead" [max]="chapter.pages"></ngb-progressbar>
|
||||
</p>
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
@if (chapter.files.length > 1) {
|
||||
@if (chapter.files.length > 1 && chapter.files[0].format !== MangaFormat.IMAGE) {
|
||||
<div class="count">
|
||||
<span class="badge bg-primary">{{chapter.files.length}}</span>
|
||||
</div>
|
||||
|
|
|
@ -35,6 +35,7 @@ import {ReaderService} from "../../_services/reader.service";
|
|||
import {LibraryType} from "../../_models/library/library";
|
||||
import {Device} from "../../_models/device/device";
|
||||
import {ActionService} from "../../_services/action.service";
|
||||
import {MangaFormat} from "../../_models/manga-format";
|
||||
|
||||
@Component({
|
||||
selector: 'app-chapter-card',
|
||||
|
@ -49,8 +50,7 @@ import {ActionService} from "../../_services/action.service";
|
|||
EntityTitleComponent,
|
||||
CardActionablesComponent,
|
||||
RouterLink,
|
||||
TranslocoDirective,
|
||||
DefaultValuePipe
|
||||
TranslocoDirective
|
||||
],
|
||||
templateUrl: './chapter-card.component.html',
|
||||
styleUrl: './chapter-card.component.scss',
|
||||
|
@ -213,4 +213,5 @@ export class ChapterCardComponent implements OnInit {
|
|||
|
||||
|
||||
protected readonly LibraryType = LibraryType;
|
||||
protected readonly MangaFormat = MangaFormat;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="progress-banner">
|
||||
@if (series.pagesRead > 0 && series.pagesRead < series.pages && series.pages > 0 && series.pagesRead !== series.pages) {
|
||||
<p ngbTooltip="{{((series.pagesRead / series.pages) * 100) | number:'1.0-1'}}%">
|
||||
<p ngbTooltip="{{((series.pagesRead / series.pages) * 100) | number:'1.0-1'}}%" container="body">
|
||||
<ngb-progressbar type="primary" height="5px" [value]="series.pagesRead" [max]="series.pages"></ngb-progressbar>
|
||||
</p>
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<div class="progress-banner">
|
||||
@if (volume.pagesRead > 0 && volume.pagesRead < volume.pages && volume.pages > 0 && volume.pagesRead !== volume.pages) {
|
||||
<p ngbTooltip="{{((volume.pagesRead / volume.pages) * 100) | number:'1.0-1'}}% Read">
|
||||
<p ngbTooltip="{{((volume.pagesRead / volume.pages) * 100) | number:'1.0-1'}}% Read" container="body">
|
||||
<ngb-progressbar type="primary" height="5px" [value]="volume.pagesRead" [max]="volume.pages"></ngb-progressbar>
|
||||
</p>
|
||||
}
|
||||
|
|
|
@ -199,7 +199,9 @@
|
|||
<div class="{{SplitIconClass}}"></div>
|
||||
</div>
|
||||
<select class="form-control" id="page-splitting" formControlName="pageSplitOption">
|
||||
<option *ngFor="let opt of pageSplitOptionsTranslated" [value]="opt.value">{{opt.text}}</option>
|
||||
@for (opt of pageSplitOptionsTranslated; track opt.value) {
|
||||
<option [value]="opt.value">{{opt.text}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
@ -216,42 +218,45 @@
|
|||
<div class="row mb-2">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<label for="layout-mode" class="form-label">Layout Mode</label>
|
||||
<ng-container [ngSwitch]="layoutMode">
|
||||
<ng-container *ngSwitchCase="LayoutMode.Single">
|
||||
@switch (layoutMode) {
|
||||
@case (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">
|
||||
}
|
||||
@case (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">
|
||||
}
|
||||
@case (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>
|
||||
}
|
||||
}
|
||||
|
||||
<select class="form-control" id="layout-mode" formControlName="layoutMode">
|
||||
<option [value]="opt.value" *ngFor="let opt of layoutModesTranslated">{{opt.text}}</option>
|
||||
@for (opt of layoutModesTranslated; track opt.value) {
|
||||
<option [value]="opt.value">{{opt.text}}</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-12">
|
||||
|
|
|
@ -8,12 +8,11 @@ import {
|
|||
EventEmitter,
|
||||
HostListener,
|
||||
inject,
|
||||
Inject,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {AsyncPipe, DOCUMENT, NgClass, NgFor, NgStyle, NgSwitch, NgSwitchCase, PercentPipe} from '@angular/common';
|
||||
import {AsyncPipe, NgClass, NgStyle, PercentPipe} from '@angular/common';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
|
@ -33,7 +32,7 @@ import {
|
|||
import {ChangeContext, LabelType, NgxSliderModule, Options} from '@angular-slider/ngx-slider';
|
||||
import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||
import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms';
|
||||
import {NgbModal, NgbProgressbar} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
|
||||
import {ToastrService} from 'ngx-toastr';
|
||||
import {ShortcutsModalComponent} from 'src/app/reader-shared/_modals/shortcuts-modal/shortcuts-modal.component';
|
||||
import {Stack} from 'src/app/shared/data-structures/stack';
|
||||
|
@ -126,7 +125,7 @@ enum KeyDirection {
|
|||
standalone: true,
|
||||
imports: [NgStyle, LoadingComponent, SwipeDirective, CanvasRendererComponent, SingleRendererComponent,
|
||||
DoubleRendererComponent, DoubleReverseRendererComponent, DoubleNoCoverRendererComponent, InfiniteScrollerComponent,
|
||||
NgxSliderModule, ReactiveFormsModule, NgFor, NgSwitch, NgSwitchCase, FittingIconPipe, ReaderModeIconPipe,
|
||||
NgxSliderModule, ReactiveFormsModule, FittingIconPipe, ReaderModeIconPipe,
|
||||
FullscreenIconPipe, TranslocoDirective, PercentPipe, NgClass, AsyncPipe, DblClickDirective]
|
||||
})
|
||||
export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
@ -275,7 +274,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
step: 1,
|
||||
boundPointerLabels: true,
|
||||
showSelectionBar: true,
|
||||
translate: (value: number, label: LabelType) => {
|
||||
translate: (_: number, label: LabelType) => {
|
||||
if (label == LabelType.Floor) {
|
||||
return 1 + '';
|
||||
} else if (label === LabelType.Ceil) {
|
||||
|
@ -467,7 +466,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
|
||||
constructor(@Inject(DOCUMENT) private document: Document) {
|
||||
constructor() {
|
||||
this.navService.hideNavBar();
|
||||
this.navService.hideSideNav();
|
||||
this.cdRef.markForCheck();
|
||||
|
@ -784,6 +783,17 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
return pageNum;
|
||||
}
|
||||
|
||||
switchToWebtoonReaderIfPagesLikelyWebtoon() {
|
||||
if (this.readerMode === ReaderMode.Webtoon) return;
|
||||
|
||||
if (this.mangaReaderService.shouldBeWebtoonMode()) {
|
||||
this.readerMode = ReaderMode.Webtoon;
|
||||
this.toastr.info(translate('manga-reader.webtoon-override'));
|
||||
this.readerModeSubject.next(this.readerMode);
|
||||
this.cdRef.markForCheck();
|
||||
}
|
||||
}
|
||||
|
||||
disableDoubleRendererIfScreenTooSmall() {
|
||||
if (window.innerWidth > window.innerHeight) {
|
||||
this.generalSettingsForm.get('layoutMode')?.enable();
|
||||
|
@ -991,6 +1001,7 @@ export class MangaReaderComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||
this.inSetup = false;
|
||||
|
||||
this.disableDoubleRendererIfScreenTooSmall();
|
||||
this.switchToWebtoonReaderIfPagesLikelyWebtoon();
|
||||
|
||||
|
||||
// From bookmarks, create map of pages to make lookup time O(1)
|
||||
|
|
|
@ -6,6 +6,7 @@ import { ChapterInfo } from '../_models/chapter-info';
|
|||
import { DimensionMap } from '../_models/file-dimension';
|
||||
import { FITTING_OPTION } from '../_models/reader-enums';
|
||||
import { BookmarkInfo } from 'src/app/_models/manga-reader/bookmark-info';
|
||||
import {ReaderMode} from "../../_models/preferences/reader-mode";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -150,6 +151,35 @@ export class ManagaReaderService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the page dimensions are all "webtoon-like", then reader mode will be converted for the user
|
||||
*/
|
||||
shouldBeWebtoonMode() {
|
||||
const pages = Object.values(this.pageDimensions);
|
||||
|
||||
let webtoonScore = 0;
|
||||
pages.forEach(info => {
|
||||
const aspectRatio = info.height / info.width;
|
||||
let score = 0;
|
||||
|
||||
// Strong webtoon indicator: If aspect ratio is at least 2:1
|
||||
if (aspectRatio >= 2) {
|
||||
score += 1;
|
||||
}
|
||||
|
||||
// Boost score if width is small (≤ 800px, common in webtoons)
|
||||
if (info.width <= 800) {
|
||||
score += 0.5; // Adjust weight as needed
|
||||
}
|
||||
|
||||
webtoonScore += score;
|
||||
});
|
||||
|
||||
|
||||
// If at least 50% of the pages fit the webtoon criteria, switch to Webtoon mode.
|
||||
return webtoonScore / pages.length >= 0.5;
|
||||
}
|
||||
|
||||
|
||||
applyBookmarkEffect(elements: Array<Element | ElementRef>) {
|
||||
if (elements.length > 0) {
|
||||
|
@ -160,7 +190,4 @@ export class ManagaReaderService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -266,15 +266,19 @@
|
|||
</li>
|
||||
}
|
||||
|
||||
@if (hasRelations || readingLists.length > 0 || collections.length > 0) {
|
||||
@if (hasRelations || readingLists.length > 0 || collections.length > 0 || bookmarks.length > 0) {
|
||||
<li [ngbNavItem]="TabID.Related">
|
||||
<a ngbNavLink>
|
||||
{{t(TabID.Related)}}
|
||||
<span class="badge rounded-pill text-bg-secondary">{{relations.length + readingLists.length + collections.length}}</span>
|
||||
<span class="badge rounded-pill text-bg-secondary">{{relations.length + readingLists.length + collections.length + (bookmarks.length > 0 ? 1 : 0)}}</span>
|
||||
</a>
|
||||
<ng-template ngbNavContent>
|
||||
@defer (when activeTabId === TabID.Related; prefetch on idle) {
|
||||
<app-related-tab [readingLists]="readingLists" [collections]="collections" [relations]="relations"></app-related-tab>
|
||||
<app-related-tab [readingLists]="readingLists"
|
||||
[collections]="collections"
|
||||
[relations]="relations"
|
||||
[libraryId]="libraryId"
|
||||
[bookmarks]="bookmarks"></app-related-tab>
|
||||
}
|
||||
</ng-template>
|
||||
</li>
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
import {
|
||||
AsyncPipe,
|
||||
DOCUMENT,
|
||||
Location,
|
||||
NgClass,
|
||||
NgStyle,
|
||||
NgTemplateOutlet
|
||||
} from '@angular/common';
|
||||
import {AsyncPipe, DOCUMENT, Location, NgClass, NgStyle, NgTemplateOutlet} from '@angular/common';
|
||||
import {
|
||||
AfterContentChecked,
|
||||
ChangeDetectionStrategy,
|
||||
|
@ -121,7 +114,7 @@ import {UserCollection} from "../../../_models/collection-tag";
|
|||
import {CoverImageComponent} from "../../../_single-module/cover-image/cover-image.component";
|
||||
import {DefaultModalOptions} from "../../../_models/default-modal-options";
|
||||
import {LicenseService} from "../../../_services/license.service";
|
||||
|
||||
import {PageBookmark} from "../../../_models/readers/page-bookmark";
|
||||
|
||||
|
||||
enum TabID {
|
||||
|
@ -233,6 +226,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
|
||||
reviews: Array<UserReview> = [];
|
||||
plusReviews: Array<UserReview> = [];
|
||||
bookmarks: Array<PageBookmark> = [];
|
||||
ratings: Array<Rating> = [];
|
||||
libraryType: LibraryType = LibraryType.Manga;
|
||||
seriesMetadata: SeriesMetadata | null = null;
|
||||
|
@ -712,7 +706,24 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
|
|||
this.collectionTagService.allCollectionsForSeries(seriesId, false).subscribe(tags => {
|
||||
this.collections = tags;
|
||||
this.cdRef.markForCheck();
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
this.readerService.getBookmarksForSeries(seriesId).subscribe(bookmarks => {
|
||||
if (bookmarks.length > 0) {
|
||||
this.bookmarks = Object.values(
|
||||
bookmarks.reduce((acc, bookmark) => {
|
||||
if (!acc[bookmark.seriesId]) {
|
||||
acc[bookmark.seriesId] = bookmark; // Select the first one per seriesId
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<number, PageBookmark>)
|
||||
);
|
||||
} else {
|
||||
this.bookmarks = [];
|
||||
}
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
this.readerService.getTimeLeft(seriesId).subscribe((timeLeft) => {
|
||||
this.readingTimeLeft = timeLeft;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue