import { useEffect, useState } from 'react'; import { useRoute, useNavigation } from '@react-navigation/native'; import { View } from '@/components/shared/Themed'; import styled from '@emotion/native'; import TimerContent from '@/components/useCases/timer/view/TimerContent'; import FinishContent from '@/components/useCases/timer/view/FinishContent'; import { TimerBgColor } from '@/components/useCases/timer/business/type'; import { Audio } from 'expo-av'; import { Sound } from 'expo-av/build/Audio'; import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake'; import { loadUserSettings } from '@/components/shared/business/AsyncStorage'; interface TimerProps { reps: number; restTime: number; workTime: number; } export default function Timer() { const navigation = useNavigation(); const route = useRoute(); const { reps, restTime, workTime } = route.params as TimerProps; const [currentRep, setCurrentRep] = useState(0); const [timeLeft, setTimeLeft] = useState(0); const [isWorkPhase, setIsWorkPhase] = useState(true); const [isRunning, setIsRunning] = useState(false); const [isFinish, setIsFinish] = useState(false); const [sound, setSound] = useState(); const [soundEnabled, setSoundEnabled] = useState(true); useEffect(() => { const init = async () => { try { const soundEnabledLocal = await loadUserSettings('soundEnabled'); setSoundEnabled(Boolean(Number(soundEnabledLocal))); if (soundEnabled) await configureAudio(); handleStart(); await activateKeepAwakeAsync(); } catch (error) { throw new Error('Erreur lors du chargement des paramètres utilisateur'); } }; init(); }, []); // when the user exits the screen, desactivate the keepAwake useEffect(() => { const unsubscribe = navigation.addListener('beforeRemove', (_) => { deactivateKeepAwake(); }); return unsubscribe; }, [navigation]); useEffect(() => { let timer: NodeJS.Timeout; if (isRunning && timeLeft > 0) { timer = setTimeout(() => { setTimeLeft(timeLeft - 1); }, 1000); } else if (isRunning && timeLeft === 0) { if (currentRep < reps) { if (isWorkPhase) { // If the work phase is over, move on to the rest phase playSound() setIsWorkPhase(false); setTimeLeft(restTime); } else { // If the rest phase is complete, move on to the next work phase playSound() setIsWorkPhase(true); setTimeLeft(workTime); setCurrentRep(currentRep + 1); } } else { // Done playSound(); setIsRunning(false); setIsFinish(true); } } return () => clearTimeout(timer); }, [isRunning, timeLeft, currentRep, isWorkPhase, reps, workTime, restTime]); const handleStart = () => { setCurrentRep(1); setIsWorkPhase(true); setTimeLeft(workTime); setIsRunning(true); setIsFinish(false); }; async function configureAudio() { await Audio.setAudioModeAsync({ allowsRecordingIOS: false, staysActiveInBackground: false, playsInSilentModeIOS: true, shouldDuckAndroid: true, playThroughEarpieceAndroid: false, }); } async function playSound() { if (!soundEnabled) return; const { sound } = await Audio.Sound.createAsync(require('../assets/audios/boxingBell.mp3')); setSound(sound); await sound.playAsync(); } useEffect(() => { return sound ? () => { sound.unloadAsync(); } : undefined; }, [sound]); const nextRep = () => { if (currentRep < reps) { if (isWorkPhase) { setIsWorkPhase(false); setTimeLeft(restTime); } else { setIsWorkPhase(true); setTimeLeft(workTime); setCurrentRep((prevRep) => prevRep + 1); } } else { setIsFinish(true); setIsRunning(false); } }; const previousRep = () => { if (isWorkPhase) { if (currentRep > 1) { setIsWorkPhase(false); setTimeLeft(restTime); setCurrentRep((prevRep) => prevRep - 1); } } else { setIsWorkPhase(true); setTimeLeft(workTime); } }; const handleContine = () => { setIsRunning(true); }; const handleStop = () => { setIsRunning(false); }; const renderBgColor: () => TimerBgColor = () => { if (isFinish) return 'black'; if (isWorkPhase) return 'red'; return 'green'; } return ( {isFinish && ( )} {!isFinish && ( )} ); } const Container = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColor }) => ({ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: theme.colors[bgColor] }));