From 48b57c4a74319c8897d9570f3ce41c77284a56f3 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Mon, 17 Nov 2025 02:11:05 +0100 Subject: [PATCH] Simplify reader visible page detection --- .../reader/services/ReaderControls.ts | 16 +----------- .../reader/viewer/pager/ReaderPager.utils.tsx | 26 ++++++++++++++----- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/features/reader/services/ReaderControls.ts b/src/features/reader/services/ReaderControls.ts index 6b14ba8f..892bee16 100644 --- a/src/features/reader/services/ReaderControls.ts +++ b/src/features/reader/services/ReaderControls.ts @@ -494,22 +494,8 @@ export class ReaderControls { type: PageInViewportType, readingDirection: ReadingDirection, ) { - const themeDirectionForReadingDirection = READING_DIRECTION_TO_THEME_DIRECTION[readingDirection]; - const firstVisibleImageIndex = imageRefs.current.findIndex( - (image) => - image && - isPageInViewport( - image, - type, - // the pages aren't always properly scrolled to the top which results in the leading page to still be slightly - // visible (e.g. 0.0123px) breaking the "first visible image" detection - { - bottom: 1, - left: getOptionForDirection(0, 1, themeDirectionForReadingDirection), - right: getOptionForDirection(1, 0, themeDirectionForReadingDirection), - }, - ), + (image) => image && isPageInViewport(image, type, { truncateValues: true }), ); const lastPage = imageRefs.current?.[imageRefs.current.length - 1]; const isEndReached = lastPage && isEndOfPageInViewport(lastPage, type, readingDirection); diff --git a/src/features/reader/viewer/pager/ReaderPager.utils.tsx b/src/features/reader/viewer/pager/ReaderPager.utils.tsx index 6bc91553..e4f16bd1 100644 --- a/src/features/reader/viewer/pager/ReaderPager.utils.tsx +++ b/src/features/reader/viewer/pager/ReaderPager.utils.tsx @@ -333,13 +333,21 @@ type InViewportThresholds = { left?: number; right?: number; }; -const getIsPageInViewportInfo = ( - element: HTMLElement, +type InViewportOptions = { + /** + * The pages aren't always properly scrolled to the start/end (e.g., via scrollIntoView) which results in a side to be slightly + * visible (e.g. 0.0123px) breaking the visibility detection + */ + truncateValues?: boolean; /** * Thresholds are not considered for the detection of an image filling the whole viewport. * They are only used for detecting if a specific side of an image is inside the viewport */ - argThresholds?: InViewportThresholds, + thresholds?: InViewportThresholds; +}; +const getIsPageInViewportInfo = ( + element: HTMLElement, + { truncateValues, thresholds: argThresholds }: InViewportOptions = { truncateValues: false, thresholds: {} }, ): { isLeftInViewport: boolean; isRightInViewport: boolean; @@ -348,7 +356,13 @@ const getIsPageInViewportInfo = ( isBottomInViewport: boolean; isFillingHeightViewportCompletely: boolean; } => { - const { top, bottom, left, right } = element.getBoundingClientRect(); + const { top: topRaw, bottom: bottomRaw, left: leftRaw, right: rightRaw } = element.getBoundingClientRect(); + + const maybeTruncateValue = (value: number): number => (truncateValues ? Math.trunc(value) : value); + const top = maybeTruncateValue(topRaw); + const bottom = maybeTruncateValue(bottomRaw); + const left = maybeTruncateValue(leftRaw); + const right = maybeTruncateValue(rightRaw); const thresholds = { top: 0, @@ -379,7 +393,7 @@ const getIsPageInViewportInfo = ( export const isPageInViewport = ( element: HTMLElement, type: PageInViewportType, - thresholds?: InViewportThresholds, + options?: InViewportOptions, ): boolean => { const { isLeftInViewport, @@ -388,7 +402,7 @@ export const isPageInViewport = ( isTopInViewport, isBottomInViewport, isFillingHeightViewportCompletely, - } = getIsPageInViewportInfo(element, thresholds); + } = getIsPageInViewportInfo(element, options); const isInViewportX = isLeftInViewport || isRightInViewport || isFillingWidthViewportCompletely; const isInViewportY = isTopInViewport || isBottomInViewport || isFillingHeightViewportCompletely;