diff --git a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx index 60534b6c..727287ea 100644 --- a/apps/readest-app/src/app/reader/components/FoliateViewer.tsx +++ b/apps/readest-app/src/app/reader/components/FoliateViewer.tsx @@ -114,18 +114,6 @@ const FoliateViewer: React.FC<{ const detail = (event as CustomEvent).detail; if (detail.reason !== 'scroll' && detail.reason !== 'page') return; - if (detail.reason === 'scroll') { - const renderer = viewRef.current?.renderer; - const viewSettings = getViewSettings(bookKey)!; - if (renderer && viewSettings.continuousScroll) { - if (renderer.start <= 0) { - viewRef.current?.prev(1); - // sometimes viewSize has subpixel value that the end never reaches - } else if (renderer.end + 1 >= renderer.viewSize) { - viewRef.current?.next(1); - } - } - } const parallelViews = getParallels(bookKey); if (parallelViews && parallelViews.size > 0) { parallelViews.forEach((key) => { @@ -140,7 +128,7 @@ const FoliateViewer: React.FC<{ }; const { handlePageFlip } = usePageFlip(bookKey, viewRef, containerRef); - useTouchEvent(bookKey, viewRef); + const { onTouchStart, onTouchMove, onTouchEnd } = useTouchEvent(bookKey, viewRef); useClickEvent(bookKey, handlePageFlip); useFoliateEvents(viewRef.current, { @@ -226,6 +214,9 @@ const FoliateViewer: React.FC<{
handlePageFlip(event)} + onTouchStart={onTouchStart} + onTouchMove={onTouchMove} + onTouchEnd={onTouchEnd} ref={containerRef} /> diff --git a/apps/readest-app/src/app/reader/hooks/useIframeEvents.ts b/apps/readest-app/src/app/reader/hooks/useIframeEvents.ts index 29606161..2a0c3b73 100644 --- a/apps/readest-app/src/app/reader/hooks/useIframeEvents.ts +++ b/apps/readest-app/src/app/reader/hooks/useIframeEvents.ts @@ -29,25 +29,25 @@ export const useTouchEvent = ( viewRef: React.MutableRefObject, ) => { const { hoveredBookKey, setHoveredBookKey, getViewSettings } = useReaderStore(); - const viewSettings = getViewSettings(bookKey)!; let touchStart: IframeTouch | null = null; let touchEnd: IframeTouch | null = null; - const onTouchStart = (e: IframeTouchEvent) => { + const onTouchStart = (e: IframeTouchEvent | React.TouchEvent) => { touchEnd = null; const touch = e.targetTouches[0]; if (!touch) return; touchStart = touch; }; - const onTouchMove = (e: IframeTouchEvent) => { + const onTouchMove = (e: IframeTouchEvent | React.TouchEvent) => { if (!touchStart) return; const touch = e.targetTouches[0]; if (touch) { touchEnd = touch; } if (hoveredBookKey && touchEnd) { + const viewSettings = getViewSettings(bookKey)!; const deltaY = touchEnd.screenY - touchStart.screenY; const deltaX = touchEnd.screenX - touchStart.screenX; if (!viewSettings!.scrolled && !viewSettings!.vertical) { @@ -60,7 +60,7 @@ export const useTouchEvent = ( } }; - const onTouchEnd = (e: IframeTouchEvent) => { + const onTouchEnd = (e: IframeTouchEvent | React.TouchEvent) => { if (!touchStart) return; const touch = e.targetTouches[0]; @@ -70,6 +70,7 @@ export const useTouchEvent = ( const windowWidth = window.innerWidth; if (touchEnd) { + const viewSettings = getViewSettings(bookKey)!; const deltaY = touchEnd.screenY - touchStart.screenY; const deltaX = touchEnd.screenX - touchStart.screenX; // also check for deltaX to prevent swipe page turn from triggering the toggle @@ -87,6 +88,34 @@ export const useTouchEvent = ( setHoveredBookKey(null); } } + const renderer = viewRef.current?.renderer; + if (renderer && viewSettings.scrolled && viewSettings.continuousScroll) { + const SCROLL_THRESHOLD = 30; + const doScroll = () => { + // may have overscroll where the start is greater than 0 + if (renderer.start <= deltaY && deltaY > SCROLL_THRESHOLD) { + setTimeout(() => { + viewRef.current?.prev(renderer.start + 1); + }, 100); + // sometimes viewSize has subpixel value that the end never reaches + } else if ( + Math.ceil(renderer.end) - deltaY >= renderer.viewSize && + deltaY < -SCROLL_THRESHOLD + ) { + setTimeout(() => { + viewRef.current?.next(renderer.viewSize - Math.floor(renderer.end) + 1); + }, 100); + } + }; + if (renderer.size >= renderer.viewSize) { + doScroll(); + } else { + const handleRelocate = () => { + doScroll(); + }; + renderer.addEventListener('relocate', handleRelocate, { once: true }); + } + } } touchStart = null; @@ -112,4 +141,10 @@ export const useTouchEvent = ( }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [hoveredBookKey, viewRef.current]); + + return { + onTouchStart, + onTouchMove, + onTouchEnd, + }; }; diff --git a/apps/readest-app/src/types/view.ts b/apps/readest-app/src/types/view.ts index fce1767a..92621ebf 100644 --- a/apps/readest-app/src/types/view.ts +++ b/apps/readest-app/src/types/view.ts @@ -48,7 +48,11 @@ export interface FoliateView extends HTMLElement { goTo?: (params: { index: number; anchor: number }) => void; setStyles?: (css: string) => void; getContents: () => { doc: Document; index?: number }[]; - addEventListener: (type: string, listener: EventListener) => void; + addEventListener: ( + type: string, + listener: EventListener, + option?: AddEventListenerOptions, + ) => void; removeEventListener: (type: string, listener: EventListener) => void; }; }