Improve "MobileReaderProgressBar" progress bar click/drag handling

Convert clicks on the progress bar in such a way, that there is a "padding" around the page "dots".
Thus, e.g. even if the click was actually for page 1, if it is inside page 2 padding, it will behave like it was a click for page 2
This commit is contained in:
schroda
2024-12-28 04:05:29 +01:00
parent bc14b68507
commit 3185449816
5 changed files with 22 additions and 5 deletions

View File

@@ -47,6 +47,7 @@ const BaseReaderProgressBar = ({
setIsDragging, setIsDragging,
openPage, openPage,
direction, direction,
fullSegmentClicks,
}: ReaderProgressBarProps & }: ReaderProgressBarProps &
Pick<TReaderProgressBarContext, 'isDragging' | 'setIsDragging'> & Pick<TReaderProgressBarContext, 'isDragging' | 'setIsDragging'> &
Pick<ComponentProps<typeof ReaderProgressBarSlotWrapper>, 'createProgressBarSlot'> & { Pick<ComponentProps<typeof ReaderProgressBarSlotWrapper>, 'createProgressBarSlot'> & {
@@ -69,6 +70,7 @@ const BaseReaderProgressBar = ({
}; };
openPage: ReturnType<typeof ReaderControls.useOpenPage>; openPage: ReturnType<typeof ReaderControls.useOpenPage>;
direction: ReturnType<typeof ReaderService.useGetThemeDirection>; direction: ReturnType<typeof ReaderService.useGetThemeDirection>;
fullSegmentClicks: boolean;
}) => { }) => {
const progressBarRef = useRef<HTMLDivElement | null>(null); const progressBarRef = useRef<HTMLDivElement | null>(null);
const draggingDetectionTimeout = useRef<NodeJS.Timeout>(); const draggingDetectionTimeout = useRef<NodeJS.Timeout>();
@@ -107,6 +109,7 @@ const BaseReaderProgressBar = ({
pages, pages,
progressBarPosition, progressBarPosition,
getOptionForDirection, getOptionForDirection,
fullSegmentClicks,
); );
const handleMouseDown = (e: React.MouseEvent | React.TouchEvent) => { const handleMouseDown = (e: React.MouseEvent | React.TouchEvent) => {
@@ -123,6 +126,7 @@ const BaseReaderProgressBar = ({
progressBarRef.current.getBoundingClientRect(), progressBarRef.current.getBoundingClientRect(),
pages, pages,
isHorizontalPosition, isHorizontalPosition,
fullSegmentClicks,
getOptionForDirection, getOptionForDirection,
), ),
), ),

View File

@@ -145,6 +145,7 @@ const BaseMobileReaderProgressBar = ({
{getOptionForDirection(<SkipPreviousIcon />, <SkipNextIcon />, direction)} {getOptionForDirection(<SkipPreviousIcon />, <SkipNextIcon />, direction)}
</IconButton> </IconButton>
<ReaderProgressBar <ReaderProgressBar
fullSegmentClicks={false}
createProgressBarSlot={useCallback( createProgressBarSlot={useCallback(
(page, pagesIndex, _2, _3, _4, _5, isTrailingPage, totalPages) => ( (page, pagesIndex, _2, _3, _4, _5, isTrailingPage, totalPages) => (
<ReaderProgressBarSlotMobile <ReaderProgressBarSlotMobile

View File

@@ -55,6 +55,7 @@ const BaseStandardReaderProgressBar = ({
return ( return (
<ReaderProgressBarDirectionWrapper> <ReaderProgressBarDirectionWrapper>
<ReaderProgressBar <ReaderProgressBar
fullSegmentClicks
createProgressBarSlot={useCallback( createProgressBarSlot={useCallback(
( (
page, page,

View File

@@ -543,6 +543,7 @@ export class ReaderControls {
pages: ReaderProgressBarProps['pages'], pages: ReaderProgressBarProps['pages'],
progressBarPosition: ProgressBarPosition, progressBarPosition: ProgressBarPosition,
getOptionForDirectionFn: typeof getOptionForDirection, getOptionForDirectionFn: typeof getOptionForDirection,
fullSegmentClicks: boolean,
): void { ): void {
useEffect(() => { useEffect(() => {
if (!isDragging) { if (!isDragging) {
@@ -562,6 +563,7 @@ export class ReaderControls {
progressBarRef.current.getBoundingClientRect(), progressBarRef.current.getBoundingClientRect(),
pages, pages,
isHorizontal, isHorizontal,
fullSegmentClicks,
getOptionForDirectionFn, getOptionForDirectionFn,
), ),
); );

View File

@@ -48,17 +48,26 @@ export const getPageForMousePos = (
elementRect: DOMRect, elementRect: DOMRect,
pages: ReaderProgressBarProps['pages'], pages: ReaderProgressBarProps['pages'],
isHorizontalPosition: boolean, isHorizontalPosition: boolean,
fullSegmentClicks: boolean,
getOptionForDirection: typeof getOptionForDirectionImpl, getOptionForDirection: typeof getOptionForDirectionImpl,
): ReaderProgressBarProps['pages'][number] => { ): ReaderProgressBarProps['pages'][number] => {
const pos = isHorizontalPosition ? coordinates.clientX : coordinates.clientY; const pos = isHorizontalPosition ? coordinates.clientX : coordinates.clientY;
const rectPos = isHorizontalPosition ? elementRect.left : elementRect.top; const rectPos = isHorizontalPosition ? elementRect.left : elementRect.top;
const rectSize = isHorizontalPosition ? elementRect.width : elementRect.height; const rectSize = isHorizontalPosition ? elementRect.width : elementRect.height;
const mouseXPosRelativeToProgressBar = pos - rectPos; const mousePosRelativeToProgressBar = pos - rectPos;
const pageForMouseXPos = Math.ceil((mouseXPosRelativeToProgressBar / rectSize) * pages.length);
const minPage = Math.max(1, pageForMouseXPos); const totalPages = pages.length - Number(!fullSegmentClicks);
const maxPage = Math.min(minPage, pages.length);
const newPageIndex = getOptionForDirection(maxPage - 1, pages.length - maxPage); const segmentWidth = rectSize / totalPages;
const clickedSegmentIndex = Math.floor(mousePosRelativeToProgressBar / segmentWidth);
const segmentMiddlePoint = (clickedSegmentIndex + (fullSegmentClicks ? 1 : 0.5)) * segmentWidth;
const actualClickedSegmentIndex =
mousePosRelativeToProgressBar <= segmentMiddlePoint ? clickedSegmentIndex : clickedSegmentIndex + 1;
const minPageIndex = Math.max(0, actualClickedSegmentIndex);
const maxPageIndex = Math.min(minPageIndex, pages.length - 1);
const newPageIndex = getOptionForDirection(maxPageIndex, pages.length - 1 - maxPageIndex);
return pages[newPageIndex]; return pages[newPageIndex];
}; };