feat: add settings page

merge-requests/10/head
Torpenn 2024-10-13 23:18:08 +02:00
parent 397c14d590
commit 2a633cb3f4
8 changed files with 118 additions and 17 deletions

View File

@ -1,4 +1,4 @@
import { Link, Stack } from 'expo-router'; import { Stack } from 'expo-router';
import { StyleSheet } from 'react-native'; import { StyleSheet } from 'react-native';
import { Text, View } from '@/components/shared/Themed'; import { Text, View } from '@/components/shared/Themed';

View File

@ -1,4 +1,5 @@
export type RootStackParamList = { export type RootStackParamList = {
dashboard: undefined; Dashboard: undefined;
timer: { reps: number, restTime: number, workTime: number}; Timer: { reps: number, restTime: number, workTime: number};
Settings: undefined;
}; };

80
app/Settings.tsx Normal file
View File

@ -0,0 +1,80 @@
import React, { useEffect, useState } from 'react';
import { Text } from '@/components/shared/Themed';
import styled from '@emotion/native';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { RootStackParamList } from '@/app/RootStackParamList';
import { loadUserSettings, saveUserSettings } from '@/components/shared/business/AsyncStorage';
import { Switch } from 'react-native';
import { VerticalSpacer } from '@/components/shared/Spacers';
import Button from '@/components/shared/Button';
type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'Dashboard'>;
export default function Dashboard() {
const navigation = useNavigation<NavigationProp>();
const [soundEnabled, setSoundEnabled] = useState<boolean>(false);
useEffect(() => {
const init = async () => {
try {
const soundEnabledLocal = await loadUserSettings('soundEnabled');
console.log('soundEnabledLocal', soundEnabledLocal);
if (soundEnabledLocal === null) {
console.log('soundEnabledLocal is null');
setSoundEnabled(true);
} else {
console.log('soundEnabledLocal is present', );
setSoundEnabled(Boolean(Number(soundEnabledLocal)));
}
} catch (error) {
throw new Error('Erreur lors du chargement des paramètres utilisateur');
}
};
init();
}, []);
useEffect(() => {
saveUserSettings('soundEnabled', String(Number(soundEnabled)));
}, [soundEnabled]);
return (
<Container>
<Title>Preferences</Title>
<Button label="Retour" onPress={() => navigation.navigate('Dashboard')} />
<VerticalSpacer heightUnits={8} />
<Row>
<Text>Son activé ?</Text>
<Switch
onValueChange={() => setSoundEnabled(previousState => !previousState)}
value={soundEnabled}
/>
</Row>
</Container>
);
}
const Title = styled(Text)(({ theme }) => ({
textAlign: 'center',
fontSize: 40,
fontWeight: 'bold',
color: theme.colors.black
}));
const Row = styled.View({
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
})
const Container = styled.View({
padding: 20
})

View File

@ -1,6 +1,6 @@
import FontAwesome from '@expo/vector-icons/FontAwesome'; import FontAwesome from '@expo/vector-icons/FontAwesome';
import { ThemeProvider } from '@emotion/react'; import { ThemeProvider } from '@emotion/react';
import { theme } from '@/app/shared/theme'; import { theme } from '@/app/shared/theme/index';
import { useFonts } from 'expo-font'; import { useFonts } from 'expo-font';
import { Stack } from 'expo-router'; import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen'; import * as SplashScreen from 'expo-splash-screen';
@ -14,7 +14,7 @@ export {
export const unstable_settings = { export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present. // Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: 'dashboard', initialRouteName: 'Dashboard',
}; };
// Prevent the splash screen from auto-hiding before asset loading is complete. // Prevent the splash screen from auto-hiding before asset loading is complete.
@ -47,9 +47,10 @@ export default function RootLayout() {
function RootLayoutNav() { function RootLayoutNav() {
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Stack> <Stack initialRouteName="Dashboard">
<Stack.Screen name="dashboard" options={{ headerShown: false }} /> <Stack.Screen name="Dashboard" options={{ headerShown: false }} />
<Stack.Screen name="timer" options={{ headerShown: false }} /> <Stack.Screen name="Timer" options={{ headerShown: false }} />
<Stack.Screen name="Setting" options={{ headerShown: false }} />
</Stack> </Stack>
</ThemeProvider> </ThemeProvider>
); );

View File

@ -12,7 +12,7 @@ import { TimerPickerModal } from 'react-native-timer-picker';
import Button from '@/components/shared/Button'; import Button from '@/components/shared/Button';
import NumberSelector from '@/components/shared/NumberSelector'; import NumberSelector from '@/components/shared/NumberSelector';
type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'timer'>; type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'Timer'>;
export default function Dashboard() { export default function Dashboard() {
const navigation = useNavigation<NavigationProp>(); const navigation = useNavigation<NavigationProp>();
@ -97,7 +97,11 @@ export default function Dashboard() {
<VerticalSpacer heightUnits={5} /> <VerticalSpacer heightUnits={5} />
<Button label="Commencer" onPress={() => navigation.navigate('timer', { reps, restTime, workTime})} /> <Button label="Commencer" onPress={() => navigation.navigate('Timer', { reps, restTime, workTime})} />
<VerticalSpacer heightUnits={5} />
<Button label="Préférences" onPress={() => navigation.navigate('Settings')} />
</Container> </Container>
); );
} }

View File

@ -9,6 +9,7 @@ import { TimerBgColor } from '@/components/useCases/timer/business/type';
import { Audio } from 'expo-av'; import { Audio } from 'expo-av';
import { Sound } from 'expo-av/build/Audio'; import { Sound } from 'expo-av/build/Audio';
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake'; import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';
import { loadUserSettings } from '@/components/shared/business/AsyncStorage';
interface TimerProps { interface TimerProps {
reps: number; reps: number;
@ -27,11 +28,23 @@ export default function Timer() {
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 [sound, setSound] = useState<Sound>(); const [sound, setSound] = useState<Sound>();
const [soundEnabled, setSoundEnabled] = useState<boolean>(true);
useEffect(() => { useEffect(() => {
configureAudio(); const init = async () => {
try {
const soundEnabledLocal = await loadUserSettings('soundEnabled');
setSoundEnabled(Boolean(Number(soundEnabledLocal)));
if (soundEnabled) await configureAudio();
handleStart(); handleStart();
activateKeepAwakeAsync(); 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 // when the user exits the screen, desactivate the keepAwake
@ -94,6 +107,8 @@ export default function Timer() {
} }
async function playSound() { async function playSound() {
if (!soundEnabled) return;
const { sound } = await Audio.Sound.createAsync(require('../assets/audios/boxingBell.mp3')); const { sound } = await Audio.Sound.createAsync(require('../assets/audios/boxingBell.mp3'));
setSound(sound); setSound(sound);

View File

@ -11,7 +11,7 @@ type FinishContentProps = {
handleStart: () => void; handleStart: () => void;
}; };
type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'dashboard'>; type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'Dashboard'>;
export default function FinishContent({ export default function FinishContent({
handleStart handleStart
@ -29,7 +29,7 @@ export default function FinishContent({
<HorizontalSpacer widthUnits={3} /> <HorizontalSpacer widthUnits={3} />
<Button label="Retour" onPress={() => navigation.navigate('dashboard')} /> <Button label="Retour" onPress={() => navigation.navigate('Dashboard')} />
</Row> </Row>
</> </>
); );

View File

@ -19,7 +19,7 @@ interface TimerContentProps {
bgColor: TimerBgColor; bgColor: TimerBgColor;
} }
type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'dashboard'>; type NavigationProp = NativeStackNavigationProp<RootStackParamList, 'Dashboard'>;
export default function TimerContent({ export default function TimerContent({
isWorkPhase, isWorkPhase,
@ -58,7 +58,7 @@ export default function TimerContent({
<VerticalSpacer heightUnits={3} /> <VerticalSpacer heightUnits={3} />
<Button label="Retour" onPress={() => navigation.navigate('dashboard')} /> <Button label="Retour" onPress={() => navigation.navigate('Dashboard')} />
</ButtonContainer> </ButtonContainer>
</> </>
); );