Compare commits
2 Commits
5a4206a81e
...
c9c959ce76
| Author | SHA1 | Date | |
|---|---|---|---|
| c9c959ce76 | |||
| 45389364ff |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -9,5 +9,8 @@
|
|||||||
// "**/node_modules": true,
|
// "**/node_modules": true,
|
||||||
"**/.angular": true
|
"**/.angular": true
|
||||||
},
|
},
|
||||||
"editor.formatOnSave": true
|
"editor.formatOnSave": true,
|
||||||
|
"cSpell.words": [
|
||||||
|
"Manhwa"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Directive, ElementRef } from "@angular/core";
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: "[appLazyLoad]",
|
||||||
|
standalone: true,
|
||||||
|
})
|
||||||
|
export class LazyLoadDirective {
|
||||||
|
constructor({ nativeElement }: ElementRef) {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
console.log(entries);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rootMargin: "1000px",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
observer.observe(nativeElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<h3>{{ currentChapterInfo?.number }}. {{ currentChapterInfo?.name || "Нет названия" }}</h3>
|
<h3>{{ currentChapterInfo?.number }}. {{ currentChapterInfo?.name || "Нет названия" }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
@if (pages.length > 0 && cachedPages[currentPageIndex]) {
|
@if (pages.length > 0 && cachedPages.get(currentPageIndex)) {
|
||||||
<div [class]="imageContainerClass">
|
<div [class]="imageContainerClass">
|
||||||
@if (!isManhwa$.value) {
|
@if (!isManhwa$.value) {
|
||||||
<app-scale-image [imageSrc]="imageUrl"></app-scale-image>
|
<app-scale-image [imageSrc]="imageUrl"></app-scale-image>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
<div appLazyLoad></div>
|
||||||
<div class="flex items-center justify-center space-x-4 my-10">
|
<div class="flex items-center justify-center space-x-4 my-10">
|
||||||
<button (click)="prevPage()" class="p-3 text-white bg-slate-600 w-[100px] rounded-lg">
|
<button (click)="prevPage()" class="p-3 text-white bg-slate-600 w-[100px] rounded-lg">
|
||||||
←
|
←
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { Chapter, Page } from "../../services/parsers/rulib/rulib.chapter.dto";
|
|||||||
import { IRulibChapter } from "../../services/parsers/rulib/rulib.chapters.dto";
|
import { IRulibChapter } from "../../services/parsers/rulib/rulib.chapters.dto";
|
||||||
import { SearchService } from "../../services/search.service";
|
import { SearchService } from "../../services/search.service";
|
||||||
import { ScaleImageComponent } from "../scale-image/scale-image.component";
|
import { ScaleImageComponent } from "../scale-image/scale-image.component";
|
||||||
|
import { LazyLoadDirective } from "./lazyscroll.directive";
|
||||||
import { CachedPage, CachedPages } from "./reader.dto";
|
import { CachedPage, CachedPages } from "./reader.dto";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -22,13 +23,13 @@ import { CachedPage, CachedPages } from "./reader.dto";
|
|||||||
templateUrl: "./reader.component.html",
|
templateUrl: "./reader.component.html",
|
||||||
styleUrls: ["./reader.component.less"],
|
styleUrls: ["./reader.component.less"],
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, ScaleImageComponent, RouterLink],
|
imports: [CommonModule, ScaleImageComponent, RouterLink, LazyLoadDirective],
|
||||||
})
|
})
|
||||||
export class ReaderComponent implements AfterViewInit, OnDestroy {
|
export class ReaderComponent implements AfterViewInit, OnDestroy {
|
||||||
//FIXME: Scrolling to top when manhwa
|
//FIXME: Scrolling to top when manhwa
|
||||||
pages: Page[] = [];
|
pages: Page[] = [];
|
||||||
currentPageIndex = 0;
|
currentPageIndex = 0;
|
||||||
cachedPages: CachedPages = {};
|
cachedPages: CachedPages = new Map<number, CachedPage>();
|
||||||
imageUrl: string = "";
|
imageUrl: string = "";
|
||||||
isManhwa = false;
|
isManhwa = false;
|
||||||
currentChapterInfo: Chapter | null = null;
|
currentChapterInfo: Chapter | null = null;
|
||||||
@@ -53,7 +54,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get manhwaPages() {
|
get manhwaPages() {
|
||||||
return Object.values(this.cachedPages) as CachedPage[];
|
return this.cachedPages.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
@@ -79,11 +80,11 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
this.router.navigate(["/"]);
|
this.router.navigate(["/"]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.isManhwa$.pipe(takeUntil(this.destroy$)).subscribe((isManhwa) => {
|
// this.isManhwa$.pipe(takeUntil(this.destroy$)).subscribe((isManhwa) => {
|
||||||
this.isManhwa = isManhwa;
|
// this.isManhwa = isManhwa;
|
||||||
if (isManhwa) this.initManhwaScroll();
|
// if (isManhwa) this.initManhwaScroll();
|
||||||
else this.noManhwaScroll();
|
// else this.noManhwaScroll();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleScrollManhwa(event: Event) {
|
private handleScrollManhwa(event: Event) {
|
||||||
@@ -154,7 +155,6 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
this.cachePage(index); // Кэшируем текущую и соседние страницы
|
this.cachePage(index); // Кэшируем текущую и соседние страницы
|
||||||
if (!this.isManhwa$.value) this.unloadCachedPages(index); // Сгружаем ненужные страницы из кэша
|
if (!this.isManhwa$.value) this.unloadCachedPages(index); // Сгружаем ненужные страницы из кэша
|
||||||
if (!this.isManhwa$.value) {
|
if (!this.isManhwa$.value) {
|
||||||
console.log("scroll");
|
|
||||||
const container = document.querySelector("app-reader");
|
const container = document.querySelector("app-reader");
|
||||||
if (container) {
|
if (container) {
|
||||||
container.scrollTo({
|
container.scrollTo({
|
||||||
@@ -163,7 +163,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!this.cachedPages[index]?.imageData) {
|
if (!this.cachedPages.get(index)?.imageData) {
|
||||||
// Если страница не закэширована, загружаем её
|
// Если страница не закэширована, загружаем её
|
||||||
this.fetchAndCachePage(index)
|
this.fetchAndCachePage(index)
|
||||||
.pipe(takeUntil(this.destroy$))
|
.pipe(takeUntil(this.destroy$))
|
||||||
@@ -181,7 +181,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
const nextChapterIndex = Math.min(thisChapterIndex + 1, this.chaptersInfo.length - 1);
|
const nextChapterIndex = Math.min(thisChapterIndex + 1, this.chaptersInfo.length - 1);
|
||||||
const nextChapter = this.chaptersInfo[nextChapterIndex];
|
const nextChapter = this.chaptersInfo[nextChapterIndex];
|
||||||
if (nextChapter !== this.chaptersInfo[thisChapterIndex]) {
|
if (nextChapter !== this.chaptersInfo[thisChapterIndex]) {
|
||||||
this.cachedPages = [];
|
this.cachedPages.clear();
|
||||||
this.router.navigate(["/", "reader"], {
|
this.router.navigate(["/", "reader"], {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
@@ -197,7 +197,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
const prevChapterIndex = Math.max(thisChapterIndex - 1, 0);
|
const prevChapterIndex = Math.max(thisChapterIndex - 1, 0);
|
||||||
const prevChapter = this.chaptersInfo[prevChapterIndex];
|
const prevChapter = this.chaptersInfo[prevChapterIndex];
|
||||||
if (prevChapter !== this.chaptersInfo[thisChapterIndex]) {
|
if (prevChapter !== this.chaptersInfo[thisChapterIndex]) {
|
||||||
this.cachedPages = [];
|
this.cachedPages.clear();
|
||||||
this.router.navigate(["/", "reader"], {
|
this.router.navigate(["/", "reader"], {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
@@ -229,7 +229,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private isPageCached(index: number): boolean {
|
private isPageCached(index: number): boolean {
|
||||||
return !!this.cachedPages[index]?.imageData;
|
return !!this.cachedPages.get(index)?.imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Загрузка и сохранение изображения в кэш
|
// Загрузка и сохранение изображения в кэш
|
||||||
@@ -239,15 +239,12 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
.pipe(
|
.pipe(
|
||||||
map((imageData) => {
|
map((imageData) => {
|
||||||
const url = this.getImageUrl(imageData);
|
const url = this.getImageUrl(imageData);
|
||||||
this.cachedPages = {
|
this.cachedPages.set(index, {
|
||||||
...this.cachedPages,
|
|
||||||
[index]: {
|
|
||||||
...this.pages[index],
|
...this.pages[index],
|
||||||
imageData,
|
imageData,
|
||||||
imageUrl: url,
|
imageUrl: url,
|
||||||
isManhwa: +this.pages[index].ratio < 0.5,
|
isManhwa: +this.pages[index].ratio < 0.5,
|
||||||
},
|
});
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -257,7 +254,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
for (const key in this.cachedPages) {
|
for (const key in this.cachedPages) {
|
||||||
const pageIndex = +key;
|
const pageIndex = +key;
|
||||||
if (index - pageIndex > 2) {
|
if (index - pageIndex > 2) {
|
||||||
delete this.cachedPages[pageIndex];
|
this.cachedPages.delete(pageIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,7 +270,7 @@ export class ReaderComponent implements AfterViewInit, OnDestroy {
|
|||||||
|
|
||||||
// Обновляем изображение на странице
|
// Обновляем изображение на странице
|
||||||
private updateImage() {
|
private updateImage() {
|
||||||
const currentPage = this.cachedPages[this.currentPageIndex];
|
const currentPage = this.cachedPages.get(this.currentPageIndex);
|
||||||
if (currentPage && currentPage.imageData && !this.isManhwa$.value) {
|
if (currentPage && currentPage.imageData && !this.isManhwa$.value) {
|
||||||
const blob = new Blob([currentPage.imageData], { type: "image/jpeg" });
|
const blob = new Blob([currentPage.imageData], { type: "image/jpeg" });
|
||||||
const urlCreator = window.URL || window.webkitURL;
|
const urlCreator = window.URL || window.webkitURL;
|
||||||
|
|||||||
@@ -7,6 +7,4 @@ export interface CachedPage extends Page {
|
|||||||
isManhwa: boolean;
|
isManhwa: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CachedPages {
|
export type CachedPages = Map<number, CachedPage>;
|
||||||
[key: number]: CachedPage;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user