Update chapter
This commit is contained in:
@@ -7,6 +7,10 @@
|
||||
*/
|
||||
|
||||
import { ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
||||
import { UpdateChapterPatchInput } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { TChapterReader } from '@/modules/chapter/Chapter.types.ts';
|
||||
import { ChapterIdInfo, Chapters } from '@/modules/chapter/services/Chapters.ts';
|
||||
import { CHAPTER_READER_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts';
|
||||
|
||||
export const getInitialReaderPageIndex = (
|
||||
resumeMode: ReaderResumeMode,
|
||||
@@ -23,3 +27,80 @@ export const getInitialReaderPageIndex = (
|
||||
|
||||
return Math.max(0, Math.min(lastPageIndex, lastReadPageIndex));
|
||||
};
|
||||
|
||||
export const getReaderChapterFromCache = (id: ChapterIdInfo['id']): TChapterReader | null =>
|
||||
Chapters.getFromCache<TChapterReader>(id, CHAPTER_READER_FIELDS, 'CHAPTER_READER_FIELDS')!;
|
||||
|
||||
export const getChapterIdsToDeleteForChapterUpdate = (
|
||||
chapter: TChapterReader,
|
||||
chapters: TChapterReader[],
|
||||
previousChapters: TChapterReader[],
|
||||
patch: UpdateChapterPatchInput,
|
||||
deleteChaptersWhileReading: number,
|
||||
deleteChaptersWithBookmark: boolean,
|
||||
shouldSkipDupChapters: boolean,
|
||||
): TChapterReader['id'][] => {
|
||||
const isAutoDeletionEnabled = !!patch.isRead && !!deleteChaptersWhileReading;
|
||||
if (!isAutoDeletionEnabled) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const chapterToDelete = [chapter, ...previousChapters][deleteChaptersWhileReading - 1];
|
||||
if (!chapterToDelete) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const chapterToDeleteUpToDateData = getReaderChapterFromCache(chapterToDelete.id);
|
||||
if (!chapterToDeleteUpToDateData) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const shouldDeleteChapter =
|
||||
chapterToDeleteUpToDateData.isRead &&
|
||||
Chapters.isDeletable(chapterToDeleteUpToDateData, deleteChaptersWithBookmark);
|
||||
if (!shouldDeleteChapter) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!shouldSkipDupChapters) {
|
||||
return Chapters.getIds([chapterToDelete]);
|
||||
}
|
||||
|
||||
return Chapters.getIds(Chapters.addDuplicates([chapterToDelete], chapters));
|
||||
};
|
||||
|
||||
export const getChapterIdsForDownloadAhead = (
|
||||
chapter: TChapterReader,
|
||||
nextChapter: TChapterReader | undefined,
|
||||
nextChapters: TChapterReader[],
|
||||
currentPageIndex: number,
|
||||
downloadAheadLimit: number,
|
||||
): TChapterReader['id'][] => {
|
||||
const chapterUpToDateData = getReaderChapterFromCache(chapter.id);
|
||||
if (!chapterUpToDateData || !nextChapter) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isDownloadAheadEnabled = !!downloadAheadLimit;
|
||||
const inDownloadRange = currentPageIndex / chapterUpToDateData.pageCount > 0.25;
|
||||
const shouldCheckDownloadAhead = isDownloadAheadEnabled && chapterUpToDateData.isDownloaded && inDownloadRange;
|
||||
if (!shouldCheckDownloadAhead) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const nextChapterUpToDateData = getReaderChapterFromCache(nextChapter.id);
|
||||
|
||||
if (!nextChapterUpToDateData?.isDownloaded) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const unreadNextChaptersUpToDateData = Chapters.getNonRead(nextChapters)
|
||||
.map((unreadNextChapter) => getReaderChapterFromCache(unreadNextChapter.id))
|
||||
.filter((unreadNextChapterUpToDateData) => !!unreadNextChapterUpToDateData);
|
||||
|
||||
return unreadNextChaptersUpToDateData
|
||||
.slice(-downloadAheadLimit)
|
||||
.filter((unreadNextChapter) => !unreadNextChapter.isDownloaded)
|
||||
.map((unreadUnDownloadedNextChapter) => unreadUnDownloadedNextChapter.id)
|
||||
.filter((id) => !Chapters.isDownloading(id));
|
||||
};
|
||||
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
IReaderSettings,
|
||||
PageInViewportType,
|
||||
ReaderPageScaleMode,
|
||||
ReadingDirection,
|
||||
ReaderTransitionPageMode,
|
||||
ReadingDirection,
|
||||
ReadingMode,
|
||||
} from '@/modules/reader/types/Reader.types.ts';
|
||||
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
|
||||
@@ -224,7 +224,16 @@ export const createReaderPage = (
|
||||
/>
|
||||
);
|
||||
|
||||
export const isPageInViewport = (element: HTMLElement, type: PageInViewportType): boolean => {
|
||||
const getIsPageInViewportInfo = (
|
||||
element: HTMLElement,
|
||||
): {
|
||||
isLeftInViewport: boolean;
|
||||
isRightInViewport: boolean;
|
||||
isFillingWidthViewportCompletely: boolean;
|
||||
isTopInViewport: boolean;
|
||||
isBottomInViewport: boolean;
|
||||
isFillingHeightViewportCompletely: boolean;
|
||||
} => {
|
||||
const { top, bottom, left, right } = element.getBoundingClientRect();
|
||||
|
||||
// for some reason using "scrollIntoView" to scroll a page into view does not always result in the page to be at top,
|
||||
@@ -239,6 +248,26 @@ export const isPageInViewport = (element: HTMLElement, type: PageInViewportType)
|
||||
const isBottomInViewport = bottom >= MIN_VISIBLE_PX && bottom <= window.innerHeight;
|
||||
const isFillingHeightViewportCompletely = top <= MIN_VISIBLE_PX && bottom >= window.innerHeight;
|
||||
|
||||
return {
|
||||
isLeftInViewport,
|
||||
isRightInViewport,
|
||||
isFillingWidthViewportCompletely,
|
||||
isTopInViewport,
|
||||
isBottomInViewport,
|
||||
isFillingHeightViewportCompletely,
|
||||
};
|
||||
};
|
||||
|
||||
export const isPageInViewport = (element: HTMLElement, type: PageInViewportType): boolean => {
|
||||
const {
|
||||
isLeftInViewport,
|
||||
isRightInViewport,
|
||||
isFillingWidthViewportCompletely,
|
||||
isTopInViewport,
|
||||
isBottomInViewport,
|
||||
isFillingHeightViewportCompletely,
|
||||
} = getIsPageInViewportInfo(element);
|
||||
|
||||
const isInViewportX = isLeftInViewport || isRightInViewport || isFillingWidthViewportCompletely;
|
||||
const isInViewportY = isTopInViewport || isBottomInViewport || isFillingHeightViewportCompletely;
|
||||
|
||||
@@ -252,6 +281,23 @@ export const isPageInViewport = (element: HTMLElement, type: PageInViewportType)
|
||||
}
|
||||
};
|
||||
|
||||
export const isEndOfPageInViewport = (
|
||||
element: HTMLElement,
|
||||
type: PageInViewportType,
|
||||
direction: ReadingDirection,
|
||||
): boolean => {
|
||||
const { isLeftInViewport, isRightInViewport, isBottomInViewport } = getIsPageInViewportInfo(element);
|
||||
|
||||
switch (type) {
|
||||
case PageInViewportType.X:
|
||||
return direction === ReadingDirection.LTR ? isRightInViewport : isLeftInViewport;
|
||||
case PageInViewportType.Y:
|
||||
return isBottomInViewport;
|
||||
default:
|
||||
throw new Error(`unexpected "type" (${type})`);
|
||||
}
|
||||
};
|
||||
|
||||
export const getDoublePageModePages = (
|
||||
pageUrls: ReaderStatePages['pageUrls'],
|
||||
pagesToSpreadState: boolean[],
|
||||
|
||||
@@ -23,6 +23,13 @@ export const getPage = (pageIndex: number, pages: ReaderProgressBarProps['pages'
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* for the double page mode the secondary page index has to be used to be able to correctly detect if the last page is visible
|
||||
*
|
||||
*/
|
||||
export const getNextIndexFromPage = (page: ReaderProgressBarProps['pages'][number]) =>
|
||||
page.secondary?.index ?? page.primary.index;
|
||||
|
||||
export const getNextPageIndex = (
|
||||
offset: 'previous' | 'next',
|
||||
pagesIndex: number,
|
||||
@@ -30,9 +37,9 @@ export const getNextPageIndex = (
|
||||
): number => {
|
||||
switch (offset) {
|
||||
case 'previous':
|
||||
return pages[Math.max(0, pagesIndex - 1)].primary.index;
|
||||
return getNextIndexFromPage(pages[Math.max(0, pagesIndex - 1)]);
|
||||
case 'next':
|
||||
return pages[Math.min(pages.length - 1, pagesIndex + 1)].primary.index;
|
||||
return getNextIndexFromPage(pages[Math.min(pages.length - 1, pagesIndex + 1)]);
|
||||
default:
|
||||
throw new Error(`Unexpected offset "${offset}"`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user