feat: add prepation time to timers
parent
2e44837381
commit
5de377f0c3
|
|
@ -21,22 +21,26 @@ const t = i18n.scoped('dashboard');
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const navigation = useNavigation<NavigationProp>();
|
const navigation = useNavigation<NavigationProp>();
|
||||||
const { timerState, isLoading, updateReps, updateWorkTime, updateRestTime } = useTimerContext();
|
const { timerState, isLoading, updateReps, updateWorkTime, updateRestTime, updatePreparationTime } = useTimerContext();
|
||||||
|
|
||||||
const [showWorkTimePicker, setShowWorkTimePicker] = useState<boolean>(false);
|
const [showWorkTimePicker, setShowWorkTimePicker] = useState<boolean>(false);
|
||||||
|
const [showPreparationTimePicker, setShowPreparationTimePicker] = useState<boolean>(false);
|
||||||
const [showRestTimePicker, setShowRestTimePicker] = useState<boolean>(false);
|
const [showRestTimePicker, setShowRestTimePicker] = useState<boolean>(false);
|
||||||
|
|
||||||
// Local variables for UI changes
|
// Local variables for UI changes
|
||||||
|
const [localPreparationTime, setLocalPreparationTime] = useState<number>(timerState.preparationTime);
|
||||||
const [localReps, setLocalReps] = useState<number>(timerState.reps);
|
const [localReps, setLocalReps] = useState<number>(timerState.reps);
|
||||||
const [localWorkTime, setLocalWorkTime] = useState<number>(timerState.workTime);
|
const [localWorkTime, setLocalWorkTime] = useState<number>(timerState.workTime);
|
||||||
const [localRestTime, setLocalRestTime] = useState<number>(timerState.restTime);
|
const [localRestTime, setLocalRestTime] = useState<number>(timerState.restTime);
|
||||||
|
|
||||||
// Update local states when store data is loaded
|
// Update local states when store data is loaded
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
console.log('timerState', timerState);
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
setLocalReps(timerState.reps);
|
setLocalReps(timerState.reps);
|
||||||
setLocalWorkTime(timerState.workTime);
|
setLocalWorkTime(timerState.workTime);
|
||||||
setLocalRestTime(timerState.restTime);
|
setLocalRestTime(timerState.restTime);
|
||||||
|
setLocalPreparationTime(timerState.preparationTime);
|
||||||
}
|
}
|
||||||
}, [isLoading, timerState]);
|
}, [isLoading, timerState]);
|
||||||
|
|
||||||
|
|
@ -64,13 +68,35 @@ export default function Dashboard() {
|
||||||
<VerticalSpacer heightUnits={8} />
|
<VerticalSpacer heightUnits={8} />
|
||||||
|
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<Card backgroundColor="black">
|
<Card backgroundColor="grey" onPress={() => setShowPreparationTimePicker(true)}>
|
||||||
<CardTextContainer>
|
<CardTextContainer>
|
||||||
<CustomText>{t('repetition')}</CustomText>
|
<BlackCustomText>{t('preparation')}</BlackCustomText>
|
||||||
<NumberSelector reps={localReps} setReps={handleRepsChange} />
|
<BlackCustomText>{formatTime(localPreparationTime)}</BlackCustomText>
|
||||||
</CardTextContainer>
|
</CardTextContainer>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<TimerPickerModal
|
||||||
|
hideHours
|
||||||
|
visible={showPreparationTimePicker}
|
||||||
|
setIsVisible={setShowPreparationTimePicker}
|
||||||
|
onConfirm={(pickedDuration: any) => {
|
||||||
|
const newPreparationTime = pickedDuration.minutes * 60 + pickedDuration.seconds;
|
||||||
|
setLocalPreparationTime(newPreparationTime);
|
||||||
|
updatePreparationTime(newPreparationTime);
|
||||||
|
setShowPreparationTimePicker(false);
|
||||||
|
}}
|
||||||
|
modalTitle={t('setPreparationTime')}
|
||||||
|
onCancel={() => setShowPreparationTimePicker(false)}
|
||||||
|
closeOnOverlayPress
|
||||||
|
styles={{
|
||||||
|
theme: "dark",
|
||||||
|
}}
|
||||||
|
initialValue={{ minutes: Math.floor(timerState.preparationTime / 60), seconds: timerState.preparationTime % 60 }}
|
||||||
|
modalProps={{
|
||||||
|
overlayOpacity: 0.2,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
<Card backgroundColor="red" onPress={() => setShowWorkTimePicker(true)}>
|
<Card backgroundColor="red" onPress={() => setShowWorkTimePicker(true)}>
|
||||||
<CardTextContainer>
|
<CardTextContainer>
|
||||||
<CustomText>{t('fight')}</CustomText>
|
<CustomText>{t('fight')}</CustomText>
|
||||||
|
|
@ -128,6 +154,13 @@ export default function Dashboard() {
|
||||||
overlayOpacity: 0.2,
|
overlayOpacity: 0.2,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Card backgroundColor="black">
|
||||||
|
<CardTextContainer>
|
||||||
|
<CustomText>{t('repetition')}</CustomText>
|
||||||
|
<NumberSelector reps={localReps} setReps={handleRepsChange} />
|
||||||
|
</CardTextContainer>
|
||||||
|
</Card>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
|
|
||||||
<VerticalSpacer heightUnits={5} />
|
<VerticalSpacer heightUnits={5} />
|
||||||
|
|
@ -179,3 +212,7 @@ const CustomText = styled(Text)(({ theme }) => ({
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
color: theme.colors.fixed.white
|
color: theme.colors.fixed.white
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const BlackCustomText = styled(CustomText)(({ theme }) => ({
|
||||||
|
color: theme.colors.fixed.black
|
||||||
|
}))
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export default function Timer() {
|
||||||
const [isWorkPhase, setIsWorkPhase] = useState<boolean>(true);
|
const [isWorkPhase, setIsWorkPhase] = useState<boolean>(true);
|
||||||
const [isRunning, setIsRunning] = useState<boolean>(false);
|
const [isRunning, setIsRunning] = useState<boolean>(false);
|
||||||
const [isFinish, setIsFinish] = useState<boolean>(false);
|
const [isFinish, setIsFinish] = useState<boolean>(false);
|
||||||
|
const [isPreparationPhase, setIsPreparationPhase] = useState<boolean>(false);
|
||||||
const [soundEnabled, setSoundEnabled] = useState<boolean>(true);
|
const [soundEnabled, setSoundEnabled] = useState<boolean>(true);
|
||||||
const { playSound } = useAudio(
|
const { playSound } = useAudio(
|
||||||
require("../assets/audios/boxingBell.mp3"),
|
require("../assets/audios/boxingBell.mp3"),
|
||||||
|
|
@ -75,13 +76,25 @@ export default function Timer() {
|
||||||
timerId = BackgroundTimer.setInterval(() => {
|
timerId = BackgroundTimer.setInterval(() => {
|
||||||
const newTime = timeLeft - 1;
|
const newTime = timeLeft - 1;
|
||||||
setTimeLeft(newTime);
|
setTimeLeft(newTime);
|
||||||
|
|
||||||
|
let phaseText = "Repos";
|
||||||
|
if (isPreparationPhase) {
|
||||||
|
phaseText = "Préparation";
|
||||||
|
} else if (isWorkPhase) {
|
||||||
|
phaseText = "Travail";
|
||||||
|
}
|
||||||
|
|
||||||
updateNotification(
|
updateNotification(
|
||||||
"Timer en cours",
|
"Timer en cours",
|
||||||
`Phase: ${isWorkPhase ? "Travail" : "Repos"}, Temps restant: ${newTime}s`,
|
`Phase: ${phaseText}, Temps restant: ${newTime}s`,
|
||||||
);
|
);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else if (isRunning && timeLeft === 0) {
|
} else if (isRunning && timeLeft === 0) {
|
||||||
nextRep();
|
if (isPreparationPhase) {
|
||||||
|
startFirstRep();
|
||||||
|
} else {
|
||||||
|
nextRep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -89,23 +102,43 @@ export default function Timer() {
|
||||||
BackgroundTimer.clearInterval(timerId);
|
BackgroundTimer.clearInterval(timerId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [isRunning, timeLeft]);
|
}, [isRunning, timeLeft, isPreparationPhase]);
|
||||||
|
|
||||||
const handleStart = () => {
|
const handleStart = () => {
|
||||||
|
// Démarrer avec la phase de préparation si elle est configurée
|
||||||
|
if (timerState.preparationTime > 0) {
|
||||||
|
setIsPreparationPhase(true);
|
||||||
|
setCurrentRep(0);
|
||||||
|
setTimeLeft(timerState.preparationTime);
|
||||||
|
} else {
|
||||||
|
setIsPreparationPhase(false);
|
||||||
|
setCurrentRep(1);
|
||||||
|
setIsWorkPhase(true);
|
||||||
|
setTimeLeft(timerState.workTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRunning(true);
|
||||||
|
setIsFinish(false);
|
||||||
|
|
||||||
|
const phaseText = timerState.preparationTime > 0 ? "Préparation" : "Travail";
|
||||||
|
updateNotification(
|
||||||
|
"Timer en cours",
|
||||||
|
`Phase: ${phaseText}, Temps restant: ${timeLeft}s`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startFirstRep = () => {
|
||||||
|
playSound();
|
||||||
|
setIsPreparationPhase(false);
|
||||||
setCurrentRep(1);
|
setCurrentRep(1);
|
||||||
setIsWorkPhase(true);
|
setIsWorkPhase(true);
|
||||||
setTimeLeft(timerState.workTime);
|
setTimeLeft(timerState.workTime);
|
||||||
setIsRunning(true);
|
|
||||||
setIsFinish(false);
|
|
||||||
updateNotification(
|
|
||||||
"Timer en cours",
|
|
||||||
`Phase: ${isWorkPhase ? "Travail" : "Repos"}, Temps restant: ${timeLeft}s`,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setCurrentRep(0);
|
setCurrentRep(0);
|
||||||
setIsWorkPhase(true);
|
setIsWorkPhase(true);
|
||||||
|
setIsPreparationPhase(false);
|
||||||
setTimeLeft(timerState.workTime);
|
setTimeLeft(timerState.workTime);
|
||||||
setIsRunning(false);
|
setIsRunning(false);
|
||||||
setIsFinish(false);
|
setIsFinish(false);
|
||||||
|
|
@ -155,6 +188,7 @@ export default function Timer() {
|
||||||
|
|
||||||
const renderBgColor: () => TimerBgColor = () => {
|
const renderBgColor: () => TimerBgColor = () => {
|
||||||
if (isFinish) return "black";
|
if (isFinish) return "black";
|
||||||
|
if (isPreparationPhase) return "grey";
|
||||||
if (isWorkPhase) return "red";
|
if (isWorkPhase) return "red";
|
||||||
|
|
||||||
return "green";
|
return "green";
|
||||||
|
|
@ -167,6 +201,7 @@ export default function Timer() {
|
||||||
{!isFinish && (
|
{!isFinish && (
|
||||||
<TimerContent
|
<TimerContent
|
||||||
isWorkPhase={isWorkPhase}
|
isWorkPhase={isWorkPhase}
|
||||||
|
isPreparationPhase={isPreparationPhase}
|
||||||
timeLeft={timeLeft}
|
timeLeft={timeLeft}
|
||||||
reps={timerState.reps}
|
reps={timerState.reps}
|
||||||
bgColor={renderBgColor()}
|
bgColor={renderBgColor()}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,13 @@ export const en = {
|
||||||
repetition: 'Reps',
|
repetition: 'Reps',
|
||||||
fight: 'Fight time',
|
fight: 'Fight time',
|
||||||
rest: 'Rest',
|
rest: 'Rest',
|
||||||
|
preparation: 'Preparation',
|
||||||
totalTime: 'Total time',
|
totalTime: 'Total time',
|
||||||
begin: 'Start',
|
begin: 'Start',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
setWorkTime: 'Set fight time',
|
setWorkTime: 'Set fight time',
|
||||||
setRestTime: 'Set rest time',
|
setRestTime: 'Set rest time',
|
||||||
|
setPreparationTime: 'Set preparation time',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ export const fr = {
|
||||||
back: 'Retour',
|
back: 'Retour',
|
||||||
dashboard: {
|
dashboard: {
|
||||||
repetition: 'Reps.',
|
repetition: 'Reps.',
|
||||||
|
preparation: 'Préparation',
|
||||||
fight: 'Temps du combat',
|
fight: 'Temps du combat',
|
||||||
rest: 'Repos',
|
rest: 'Repos',
|
||||||
totalTime: 'Temps total',
|
totalTime: 'Temps total',
|
||||||
|
|
@ -10,6 +11,7 @@ export const fr = {
|
||||||
settings: 'Paramètres',
|
settings: 'Paramètres',
|
||||||
setWorkTime: 'Définir le temps de combat',
|
setWorkTime: 'Définir le temps de combat',
|
||||||
setRestTime: 'Définir le temps de repos',
|
setRestTime: 'Définir le temps de repos',
|
||||||
|
setPreparationTime: 'Définir le temps de préparation',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
title: 'Paramètres',
|
title: 'Paramètres',
|
||||||
|
|
@ -21,6 +23,8 @@ export const fr = {
|
||||||
timer: {
|
timer: {
|
||||||
timerContent: {
|
timerContent: {
|
||||||
fight: 'Combat',
|
fight: 'Combat',
|
||||||
|
preparation: 'Préparation',
|
||||||
|
preparationDescription: 'Commencez à vous préparer',
|
||||||
rest: 'Repos',
|
rest: 'Repos',
|
||||||
stop: 'Arrêter',
|
stop: 'Arrêter',
|
||||||
start: 'Commencer',
|
start: 'Commencer',
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ interface TimerContextType {
|
||||||
updateReps: (reps: number) => Promise<void>;
|
updateReps: (reps: number) => Promise<void>;
|
||||||
updateWorkTime: (workTime: number) => Promise<void>;
|
updateWorkTime: (workTime: number) => Promise<void>;
|
||||||
updateRestTime: (restTime: number) => Promise<void>;
|
updateRestTime: (restTime: number) => Promise<void>;
|
||||||
|
updatePreparationTime: (preparationTime: number) => Promise<void>;
|
||||||
updateState: (state: Partial<TimerState>) => Promise<void>;
|
updateState: (state: Partial<TimerState>) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16,12 +17,14 @@ const defaultContextValue: TimerContextType = {
|
||||||
timerState: {
|
timerState: {
|
||||||
reps: 1,
|
reps: 1,
|
||||||
workTime: 0,
|
workTime: 0,
|
||||||
restTime: 0
|
restTime: 0,
|
||||||
|
preparationTime: 3
|
||||||
},
|
},
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
updateReps: async () => {},
|
updateReps: async () => {},
|
||||||
updateWorkTime: async () => {},
|
updateWorkTime: async () => {},
|
||||||
updateRestTime: async () => {},
|
updateRestTime: async () => {},
|
||||||
|
updatePreparationTime: async () => {},
|
||||||
updateState: async () => {}
|
updateState: async () => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,7 +44,8 @@ export const TimerProvider: React.FC<TimerProviderProps> = ({ children }) => {
|
||||||
const [timerState, setTimerState] = useState<TimerState>({
|
const [timerState, setTimerState] = useState<TimerState>({
|
||||||
reps: 1,
|
reps: 1,
|
||||||
workTime: 0,
|
workTime: 0,
|
||||||
restTime: 0
|
restTime: 0,
|
||||||
|
preparationTime: 3
|
||||||
});
|
});
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
|
@ -71,6 +75,14 @@ export const TimerProvider: React.FC<TimerProviderProps> = ({ children }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updatePreparationTime = async (preparationTime: number) => {
|
||||||
|
try {
|
||||||
|
await timerStore.savePreparationTime(preparationTime);
|
||||||
|
setTimerState(prev => ({ ...prev, preparationTime }));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error updating preparation time:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Update work time
|
// Update work time
|
||||||
const updateWorkTime = async (workTime: number) => {
|
const updateWorkTime = async (workTime: number) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -108,6 +120,7 @@ export const TimerProvider: React.FC<TimerProviderProps> = ({ children }) => {
|
||||||
updateReps,
|
updateReps,
|
||||||
updateWorkTime,
|
updateWorkTime,
|
||||||
updateRestTime,
|
updateRestTime,
|
||||||
|
updatePreparationTime,
|
||||||
updateState
|
updateState
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
const TIMER_KEYS = {
|
const TIMER_KEYS = {
|
||||||
REPS: 'timer_reps',
|
REPS: 'timer_reps',
|
||||||
WORK_TIME: 'timer_work_time',
|
WORK_TIME: 'timer_work_time',
|
||||||
REST_TIME: 'timer_rest_time'
|
REST_TIME: 'timer_rest_time',
|
||||||
|
PREPARATION_TIME: 'timer_preparation_time'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store interface
|
// Store interface
|
||||||
|
|
@ -12,13 +13,15 @@ export interface TimerState {
|
||||||
reps: number;
|
reps: number;
|
||||||
workTime: number;
|
workTime: number;
|
||||||
restTime: number;
|
restTime: number;
|
||||||
|
preparationTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default values
|
// Default values
|
||||||
const DEFAULT_STATE: TimerState = {
|
const DEFAULT_STATE: TimerState = {
|
||||||
reps: 1,
|
reps: 1,
|
||||||
workTime: 0,
|
workTime: 0,
|
||||||
restTime: 0
|
restTime: 0,
|
||||||
|
preparationTime: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store management class
|
// Store management class
|
||||||
|
|
@ -32,6 +35,14 @@ class TimerStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async savePreparationTime(preparationTime: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
await AsyncStorage.setItem(TIMER_KEYS.PREPARATION_TIME, preparationTime.toString());
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving preparation time:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method to save work time
|
// Method to save work time
|
||||||
async saveWorkTime(workTime: number): Promise<void> {
|
async saveWorkTime(workTime: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
@ -56,7 +67,8 @@ class TimerStore {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.saveReps(state.reps),
|
this.saveReps(state.reps),
|
||||||
this.saveWorkTime(state.workTime),
|
this.saveWorkTime(state.workTime),
|
||||||
this.saveRestTime(state.restTime)
|
this.saveRestTime(state.restTime),
|
||||||
|
this.savePreparationTime(state.preparationTime)
|
||||||
]);
|
]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving state:', error);
|
console.error('Error saving state:', error);
|
||||||
|
|
@ -74,6 +86,16 @@ class TimerStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getPreparationTime(): Promise<number> {
|
||||||
|
try {
|
||||||
|
const value = await AsyncStorage.getItem(TIMER_KEYS.PREPARATION_TIME);
|
||||||
|
return value !== null ? parseInt(value, 10) : DEFAULT_STATE.preparationTime;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error retrieving preparation time:', error);
|
||||||
|
return DEFAULT_STATE.preparationTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Method to retrieve work time
|
// Method to retrieve work time
|
||||||
async getWorkTime(): Promise<number> {
|
async getWorkTime(): Promise<number> {
|
||||||
try {
|
try {
|
||||||
|
|
@ -99,16 +121,18 @@ class TimerStore {
|
||||||
// Method to retrieve complete state
|
// Method to retrieve complete state
|
||||||
async getState(): Promise<TimerState> {
|
async getState(): Promise<TimerState> {
|
||||||
try {
|
try {
|
||||||
const [reps, workTime, restTime] = await Promise.all([
|
const [reps, workTime, restTime, preparationTime] = await Promise.all([
|
||||||
this.getReps(),
|
this.getReps(),
|
||||||
this.getWorkTime(),
|
this.getWorkTime(),
|
||||||
this.getRestTime()
|
this.getRestTime(),
|
||||||
|
this.getPreparationTime()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
reps,
|
reps,
|
||||||
workTime,
|
workTime,
|
||||||
restTime
|
restTime,
|
||||||
|
preparationTime
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error retrieving state:', error);
|
console.error('Error retrieving state:', error);
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ describe('TimerStore', () => {
|
||||||
const state: TimerState = {
|
const state: TimerState = {
|
||||||
reps: 3,
|
reps: 3,
|
||||||
workTime: 40,
|
workTime: 40,
|
||||||
restTime: 20
|
restTime: 20,
|
||||||
|
preparationTime: 3
|
||||||
};
|
};
|
||||||
|
|
||||||
await timerStore.saveState(state);
|
await timerStore.saveState(state);
|
||||||
|
|
@ -233,7 +234,8 @@ describe('TimerStore', () => {
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
reps: 3,
|
reps: 3,
|
||||||
workTime: 40,
|
workTime: 40,
|
||||||
restTime: 20
|
restTime: 20,
|
||||||
|
preparationTime: 3
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_reps');
|
expect(mockedAsyncStorage.getItem).toHaveBeenCalledWith('timer_reps');
|
||||||
|
|
@ -250,7 +252,8 @@ describe('TimerStore', () => {
|
||||||
expect(result).toEqual({
|
expect(result).toEqual({
|
||||||
reps: 1,
|
reps: 1,
|
||||||
workTime: 0,
|
workTime: 0,
|
||||||
restTime: 0
|
restTime: 0,
|
||||||
|
preparationTime: 3
|
||||||
}); // Default values
|
}); // Default values
|
||||||
|
|
||||||
expect(consoleSpy).toHaveBeenCalledWith(
|
expect(consoleSpy).toHaveBeenCalledWith(
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export type TimerBgColor = 'red' | 'green' | 'black';
|
export type TimerBgColor = 'red' | 'green' | 'black' | 'grey';
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { i18n } from '@/app/i18n/i18n';
|
||||||
|
|
||||||
interface TimerContentProps {
|
interface TimerContentProps {
|
||||||
isWorkPhase: boolean;
|
isWorkPhase: boolean;
|
||||||
|
isPreparationPhase?: boolean;
|
||||||
timeLeft: number;
|
timeLeft: number;
|
||||||
reps: number;
|
reps: number;
|
||||||
currentRep: number;
|
currentRep: number;
|
||||||
|
|
@ -26,6 +27,7 @@ const t = i18n.scoped('timer.timerContent');
|
||||||
|
|
||||||
export default function TimerContent({
|
export default function TimerContent({
|
||||||
isWorkPhase,
|
isWorkPhase,
|
||||||
|
isPreparationPhase = false,
|
||||||
timeLeft,
|
timeLeft,
|
||||||
reps,
|
reps,
|
||||||
currentRep,
|
currentRep,
|
||||||
|
|
@ -44,24 +46,40 @@ export default function TimerContent({
|
||||||
handleReset();
|
handleReset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getTitle = () => {
|
||||||
|
if (isPreparationPhase) return t('preparation');
|
||||||
|
if (isWorkPhase) return t('fight');
|
||||||
|
return t('rest');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handler for disabled buttons during preparation phase
|
||||||
|
const handleNoop = () => {
|
||||||
|
// Ne fait rien si on est en phase de préparation
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title>{isWorkPhase ? t('fight') : t('rest')}</Title>
|
<Title isPreparationPhase={isPreparationPhase}>{getTitle()}</Title>
|
||||||
|
|
||||||
<VerticalSpacer heightUnits={8} />
|
<VerticalSpacer heightUnits={8} />
|
||||||
|
|
||||||
<Time>
|
<Time isPreparationPhase={isPreparationPhase}>
|
||||||
{formatTime(timeLeft)}
|
{formatTime(timeLeft)}
|
||||||
</Time>
|
</Time>
|
||||||
|
|
||||||
<VerticalSpacer heightUnits={8} />
|
<VerticalSpacer heightUnits={8} />
|
||||||
|
|
||||||
<Reps>{currentRep} / {reps}</Reps>
|
{!isPreparationPhase && <Reps>{currentRep} / {reps}</Reps>}
|
||||||
|
{isPreparationPhase && <Reps isPreparationPhase={true}>{t('preparationDescription')}</Reps>}
|
||||||
|
|
||||||
<VerticalSpacer heightUnits={8} />
|
<VerticalSpacer heightUnits={8} />
|
||||||
|
|
||||||
<ButtonContainer bgColor={bgColor}>
|
<ButtonContainer bgColor={bgColor}>
|
||||||
<Button label={t('prev')} onPress={previousRep} />
|
<Button
|
||||||
|
label={t('prev')}
|
||||||
|
onPress={isPreparationPhase ? handleNoop : previousRep}
|
||||||
|
status={isPreparationPhase ? 'disabled' : 'ready'}
|
||||||
|
/>
|
||||||
|
|
||||||
<ElasticSpacer />
|
<ElasticSpacer />
|
||||||
|
|
||||||
|
|
@ -73,7 +91,11 @@ export default function TimerContent({
|
||||||
|
|
||||||
<ElasticSpacer />
|
<ElasticSpacer />
|
||||||
|
|
||||||
<Button label={t('next')} onPress={nextRep} />
|
<Button
|
||||||
|
label={t('next')}
|
||||||
|
onPress={isPreparationPhase ? nextRep : nextRep}
|
||||||
|
status="ready"
|
||||||
|
/>
|
||||||
</ButtonContainer>
|
</ButtonContainer>
|
||||||
|
|
||||||
<VerticalSpacer heightUnits={4} />
|
<VerticalSpacer heightUnits={4} />
|
||||||
|
|
@ -89,20 +111,20 @@ const ButtonContainer = styled(View)<{ bgColor: TimerBgColor }>(({ theme, bgColo
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Title = styled(Text)(({ theme }) => ({
|
const Title = styled(Text)<{ isPreparationPhase?: boolean }>(({ theme, isPreparationPhase = false }) => ({
|
||||||
fontSize: 50,
|
fontSize: 50,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
color: theme.colors.fixed.white
|
color: isPreparationPhase ? theme.colors.fixed.black : theme.colors.fixed.white
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Time = styled(Text)(({ theme }) => ({
|
const Time = styled(Text)<{ isPreparationPhase?: boolean }>(({ theme, isPreparationPhase = false }) => ({
|
||||||
fontSize: 100,
|
fontSize: 100,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
color: theme.colors.fixed.white
|
color: isPreparationPhase ? theme.colors.fixed.black : theme.colors.fixed.white
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const Reps = styled(Text)(({ theme }) => ({
|
const Reps = styled(Text)<{ isPreparationPhase?: boolean }>(({ theme, isPreparationPhase = false }) => ({
|
||||||
fontSize: 30,
|
fontSize: 30,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
color: theme.colors.fixed.white
|
color: isPreparationPhase ? theme.colors.fixed.black : theme.colors.fixed.white
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue