/** * Hook pour gérer les gestes tactiles (touch gestures) * T0504: Create Playlist Mobile Responsive */ import { useRef, useCallback, useState } from 'react'; export interface SwipeDirection { direction: 'left' | 'right' | 'up' | 'down' | null; distance: number; } export interface TouchGestureHandlers { onSwipeLeft?: () => void; onSwipeRight?: () => void; onSwipeUp?: () => void; onSwipeDown?: () => void; onLongPress?: () => void; onTap?: () => void; swipeThreshold?: number; longPressDelay?: number; } export function useTouchGestures(handlers: TouchGestureHandlers = {}) { const { onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onLongPress, onTap, swipeThreshold = 50, longPressDelay = 500, } = handlers; const touchStartRef = useRef<{ x: number; y: number; time: number } | null>( null, ); const longPressTimerRef = useRef(null); const [isLongPressing, setIsLongPressing] = useState(false); const handleTouchStart = useCallback( (e: React.TouchEvent) => { const touch = e.touches[0]; touchStartRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now(), }; // Démarrer le timer pour le long press if (onLongPress) { longPressTimerRef.current = setTimeout(() => { setIsLongPressing(true); onLongPress(); }, longPressDelay); } }, [onLongPress, longPressDelay], ); const handleTouchMove = useCallback((_e: React.TouchEvent) => { // Annuler le long press si l'utilisateur bouge if (longPressTimerRef.current) { clearTimeout(longPressTimerRef.current); longPressTimerRef.current = null; } setIsLongPressing(false); }, []); const handleTouchEnd = useCallback( (e: React.TouchEvent) => { // Annuler le long press timer if (longPressTimerRef.current) { clearTimeout(longPressTimerRef.current); longPressTimerRef.current = null; } if (!touchStartRef.current) return; const touch = e.changedTouches[0]; const deltaX = touch.clientX - touchStartRef.current.x; const deltaY = touch.clientY - touchStartRef.current.y; const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); const time = Date.now() - touchStartRef.current.time; // Si c'était un long press, ne pas traiter comme un swipe if (isLongPressing) { setIsLongPressing(false); touchStartRef.current = null; return; } // Si la distance est trop petite, considérer comme un tap if (distance < swipeThreshold) { if (onTap && time < 300) { onTap(); } touchStartRef.current = null; return; } // Déterminer la direction du swipe const absX = Math.abs(deltaX); const absY = Math.abs(deltaY); if (absX > absY) { // Swipe horizontal if (deltaX > 0 && onSwipeRight) { onSwipeRight(); } else if (deltaX < 0 && onSwipeLeft) { onSwipeLeft(); } } else { // Swipe vertical if (deltaY > 0 && onSwipeDown) { onSwipeDown(); } else if (deltaY < 0 && onSwipeUp) { onSwipeUp(); } } touchStartRef.current = null; setIsLongPressing(false); }, [ swipeThreshold, onSwipeLeft, onSwipeRight, onSwipeUp, onSwipeDown, onTap, isLongPressing, ], ); const handleTouchCancel = useCallback(() => { if (longPressTimerRef.current) { clearTimeout(longPressTimerRef.current); longPressTimerRef.current = null; } touchStartRef.current = null; setIsLongPressing(false); }, []); return { touchHandlers: { onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchCancel, }, isLongPressing, }; }