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)
|
||||
|
||||
const checkPWA = () => {
|
||||
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)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const checkPWA = () => {
|
||||
// android/general || ios
|
||||
return window.matchMedia('(display-mode: standalone)').matches || window.navigator.standalone === true
|
||||
}
|
||||
setIsPWA(checkPWA())
|
||||
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…
Reference in New Issue