test: togglable Android's native PTR
This commit is contained in:
		
							parent
							
								
									eea121e30c
								
							
						
					
					
						commit
						5a359feeed
					
				| @ -15,7 +15,7 @@ export default function Layout ({ | ||||
|   return ( | ||||
|     <> | ||||
|       {seo && <Seo sub={sub} item={item} user={user} />} | ||||
|       <PullToRefresh> | ||||
|       <PullToRefresh android> {/* android prop if true disables its native PTR */} | ||||
|         <Navigation sub={sub} /> | ||||
|         {contain | ||||
|           ? ( | ||||
|  | ||||
| @ -2,26 +2,34 @@ import { useRouter } from 'next/router' | ||||
| import { useState, useRef, useEffect, useCallback } from 'react' | ||||
| import styles from './pull-to-refresh.module.css' | ||||
| 
 | ||||
| export default function PullToRefresh ({ children }) { | ||||
| const PULL_THRESHOLD = 300 | ||||
| const REFRESH_TIMEOUT = 500 | ||||
| 
 | ||||
| export default function PullToRefresh ({ children, android }) { | ||||
|   const router = useRouter() | ||||
|   const [isRefreshing, setIsRefreshing] = useState(false) | ||||
|   const [pullDistance, setPullDistance] = useState(0) | ||||
|   const [isPWA, setIsPWA] = useState(false) | ||||
|   const [isAndroid, setIsAndroid] = useState(false) | ||||
|   const touchStartY = useRef(0) | ||||
|   const touchEndY = useRef(0) | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|   const checkPWA = () => { | ||||
|       // android/general || ios
 | ||||
|       return window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true | ||||
|     const androidPWA = window.matchMedia('(display-mode: standalone)').matches | ||||
|     const iosPWA = window.navigator.standalone === true | ||||
|     setIsAndroid(androidPWA) // we need to know if the user is on Android to enable toggling its native PTR
 | ||||
|     setIsPWA(androidPWA || iosPWA) | ||||
|   } | ||||
|     setIsPWA(checkPWA()) | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     checkPWA() | ||||
|   }, []) | ||||
| 
 | ||||
|   const handleTouchStart = useCallback((e) => { | ||||
|     if (!isPWA || window.scrollY > 0) return // don't handle if the user is not scrolling from the top of the page
 | ||||
|     // don't handle if the user is not scrolling from the top of the page, is not on a PWA or if we want Android's native PTR
 | ||||
|     if (!isPWA || (isAndroid && !android) || window.scrollY > 0) return | ||||
|     touchStartY.current = e.touches[0].clientY | ||||
|   }, [isPWA]) | ||||
|   }, [isPWA, isAndroid, android]) | ||||
| 
 | ||||
|   const handleTouchMove = useCallback((e) => { | ||||
|     if (touchStartY.current === 0) return | ||||
| @ -31,12 +39,12 @@ export default function PullToRefresh ({ children }) { | ||||
| 
 | ||||
|   const handleTouchEnd = useCallback(() => { | ||||
|     if (touchStartY.current === 0 || touchEndY.current === 0) return | ||||
|     if (touchEndY.current - touchStartY.current > 300) { // current threshold is 300, subject to change
 | ||||
|     if (touchEndY.current - touchStartY.current > PULL_THRESHOLD) { | ||||
|       setIsRefreshing(true) | ||||
|       router.push(router.asPath) | ||||
|       router.push(router.asPath) // reload the same path
 | ||||
|       setTimeout(() => { | ||||
|         setIsRefreshing(false) | ||||
|       }, 500) // simulate loading time
 | ||||
|       }, REFRESH_TIMEOUT) // simulate loading time
 | ||||
|     } | ||||
|     setPullDistance(0) // using this to reset the message behavior
 | ||||
|     touchStartY.current = 0 // avoid random refreshes by resetting touch
 | ||||
| @ -44,7 +52,8 @@ export default function PullToRefresh ({ children }) { | ||||
|   }, [router]) | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (!isPWA) return | ||||
|     // don't handle if the user is not on a PWA or if we want Android's native PTR
 | ||||
|     if (!isPWA || (isAndroid && !android)) return | ||||
|     document.addEventListener('touchstart', handleTouchStart) | ||||
|     document.addEventListener('touchmove', handleTouchMove) | ||||
|     document.addEventListener('touchend', handleTouchEnd) | ||||
| @ -53,17 +62,17 @@ export default function PullToRefresh ({ children }) { | ||||
|       document.removeEventListener('touchmove', handleTouchMove) | ||||
|       document.removeEventListener('touchend', handleTouchEnd) | ||||
|     } | ||||
|   }, [isPWA, handleTouchStart, handleTouchMove, handleTouchEnd]) | ||||
|   }, [isPWA, isAndroid, android, handleTouchStart, handleTouchMove, handleTouchEnd]) | ||||
| 
 | ||||
|   const getPullMessage = () => { | ||||
|     if (isRefreshing) return 'refreshing...' | ||||
|     if (pullDistance > 300) return 'release to refresh' | ||||
|     if (pullDistance > PULL_THRESHOLD) return 'release to refresh' | ||||
|     if (pullDistance > 0) return 'pull down to refresh' | ||||
|     return '' | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <div> | ||||
|     <div className={android ? styles.pullToRefreshContainer : ''}> {/* android prop if true disables its native PTR */} | ||||
|       <div | ||||
|         onTouchStart={handleTouchStart} | ||||
|         onTouchMove={handleTouchMove} | ||||
|  | ||||
| @ -1,3 +1,7 @@ | ||||
| .pullToRefreshContainer { | ||||
|     overscroll-behavior: contain; | ||||
| } | ||||
| 
 | ||||
| .pullMessage { | ||||
|     position: fixed; | ||||
|     left: 50%; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user