61 lines
1.9 KiB
TypeScript
61 lines
1.9 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
import { View, Dimensions } from 'react-native';
|
|
|
|
const { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
|
|
export function useSharedVisibility(threshold: number, dwellTime: number) {
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
const [shouldPlay, setShouldPlay] = useState(false);
|
|
const ref = useRef<View>(null);
|
|
const timerRef = useRef<number | undefined>(undefined);
|
|
const visibilityCheckRef = useRef<number | undefined>(undefined);
|
|
const isMountedRef = useRef(true);
|
|
|
|
const checkVisibility = useCallback(() => {
|
|
if (!ref.current || !isMountedRef.current) return;
|
|
|
|
ref.current.measureInWindow((x, y, width, height) => {
|
|
if (!isMountedRef.current) return;
|
|
|
|
const isInViewport =
|
|
y + height * threshold >= 0 &&
|
|
y <= SCREEN_HEIGHT - height * threshold &&
|
|
x + width * threshold >= 0 &&
|
|
x <= SCREEN_WIDTH;
|
|
|
|
setIsVisible((prev) => {
|
|
if (prev === isInViewport) return prev;
|
|
|
|
if (isInViewport) {
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
timerRef.current = setTimeout(() => {
|
|
if (isMountedRef.current) {
|
|
setShouldPlay(true);
|
|
}
|
|
}, dwellTime);
|
|
} else {
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
setShouldPlay(false);
|
|
}
|
|
|
|
return isInViewport;
|
|
});
|
|
});
|
|
}, [threshold, dwellTime]);
|
|
|
|
useEffect(() => {
|
|
isMountedRef.current = true;
|
|
|
|
checkVisibility();
|
|
visibilityCheckRef.current = setInterval(checkVisibility, 1000);
|
|
|
|
return () => {
|
|
isMountedRef.current = false;
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
if (visibilityCheckRef.current) clearInterval(visibilityCheckRef.current);
|
|
};
|
|
}, [checkVisibility]);
|
|
|
|
return { ref, isVisible, shouldPlay };
|
|
}
|