-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from FYP-2024-IQMA/SCRUM-143-Create-frontend-f…
…or-Settings-Page Scrum-143 Create Frontend for Settings page
- Loading branch information
Showing
6 changed files
with
182 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,109 @@ | ||
import {Button, StyleSheet, Text, View} from 'react-native'; | ||
|
||
import React from 'react'; | ||
import {LogoutButton} from '@/components/LogoutButton'; | ||
import {router} from 'expo-router'; | ||
|
||
const testLesson = () => { | ||
router.push('SectionIntroduction'); | ||
}; | ||
|
||
const testQuiz = () => { | ||
router.push('VideoQuiz'); | ||
}; | ||
|
||
const testAsssessment = () => { | ||
router.push('Assessment'); | ||
}; | ||
|
||
const assessmentIntro = () => { | ||
router.push('AssessmentIntroduction'); | ||
}; | ||
|
||
const SettingPage: React.FC = () => ( | ||
<View style={styles.container}> | ||
<Text>Settings Screen</Text> | ||
<View style={{marginBottom: 10}}></View> | ||
<Button title="Test Lesson" onPress={testLesson}></Button> | ||
<View style={{marginBottom: 10}}></View> | ||
<Button title="Test Quiz" onPress={testQuiz}></Button> | ||
<View style={{marginBottom: 10}}></View> | ||
<Button title="Test Assessment" onPress={testAsssessment}></Button> | ||
<View style={{marginBottom: 10}}></View> | ||
<Button title="Test Assessment Intro" onPress={assessmentIntro}></Button> | ||
<View style={{marginBottom: 10}}></View> | ||
<LogoutButton></LogoutButton> | ||
</View> | ||
); | ||
import { StyleSheet, Text, View } from 'react-native'; | ||
import React, { useContext, useEffect, useState } from 'react'; | ||
import CustomSwitch from '@/components/CustomSwitch'; | ||
import { CustomButton } from '@/components/CustomButton'; | ||
import { AuthContext } from '@/context/AuthContext'; | ||
import AsyncStorage from '@react-native-async-storage/async-storage'; | ||
import { LoadingIndicator } from '@/components/LoadingIndicator'; | ||
|
||
export default function Settings() { | ||
const { logOut } = useContext(AuthContext); | ||
|
||
const [isSoundEffectsEnabled, setIsSoundEffectsEnabled] = useState(false); | ||
const [isNotificationsEnabled, setIsNotificationsEnabled] = useState(false); | ||
const [isLoading, setIsLoading] = useState(true); | ||
|
||
// Get Settings from AsyncStorage | ||
const getSettingsData = async () => { | ||
try { | ||
const soundEffects = await AsyncStorage.getItem('soundEffects'); | ||
const notifications = await AsyncStorage.getItem('notifications'); | ||
|
||
if (soundEffects !== null) { | ||
const parsedSoundEffects = JSON.parse(soundEffects); | ||
setIsSoundEffectsEnabled(parsedSoundEffects); | ||
} | ||
if (notifications !== null) { | ||
const parsedNotifications = JSON.parse(notifications); | ||
setIsNotificationsEnabled(parsedNotifications); | ||
} | ||
} catch (e) { | ||
console.error('Error reading AsyncStorage values:', e); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
getSettingsData(); | ||
}, []); | ||
|
||
// Auto save to AsyncStorage when user make changes | ||
const toggleSoundEffects = async (value: boolean) => { | ||
setIsSoundEffectsEnabled(value); | ||
try { | ||
await AsyncStorage.setItem('soundEffects', JSON.stringify(value)); | ||
console.log('Sound Effects setting saved!'); | ||
} catch (e) { | ||
console.error('Error saving sound effects setting:', e); | ||
} | ||
}; | ||
|
||
// Auto save to AsyncStorage when user make changes | ||
const toggleNotifications = async (value: boolean) => { | ||
setIsNotificationsEnabled(value); | ||
try { | ||
await AsyncStorage.setItem('notifications', JSON.stringify(value)); | ||
console.log('Notifications setting saved!'); | ||
} catch (e) { | ||
console.error('Error saving notifications setting:', e); | ||
} | ||
}; | ||
|
||
// If still loading, show the loading indicator | ||
if (isLoading) { | ||
return <LoadingIndicator />; | ||
} | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<Text style={styles.textHeading}>GENERAL</Text> | ||
<View style={styles.switchContainer}> | ||
<Text style={styles.label}>Sound Effects</Text> | ||
<CustomSwitch isEnabled={isSoundEffectsEnabled} onToggle={toggleSoundEffects} /> | ||
</View> | ||
|
||
<Text style={styles.textHeading}>NOTIFICATIONS</Text> | ||
<View style={styles.switchContainer}> | ||
<Text style={styles.label}>All Notifications</Text> | ||
<CustomSwitch isEnabled={isNotificationsEnabled} onToggle={toggleNotifications} /> | ||
</View> | ||
|
||
<CustomButton | ||
label="Log out" | ||
backgroundColor="white" | ||
onPressHandler={logOut} | ||
/> | ||
</View> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flex: 1, | ||
justifyContent: 'center', | ||
padding: 20, | ||
}, | ||
textHeading: { | ||
color: '#7654F2', | ||
fontWeight: 'bold', | ||
}, | ||
switchContainer: { | ||
flexDirection: 'row', | ||
justifyContent: 'space-between', | ||
alignItems: 'center', | ||
marginVertical: 10, | ||
}, | ||
label: { | ||
fontSize: 16, | ||
}, | ||
}); | ||
|
||
export default SettingPage; |
Binary file added
BIN
+46.9 KB
...tend/iQMA-Skills-Builder/assets/images/cbcddad7-609d-4691-a812-4ac8b50f01fa.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import React, { useState, useEffect, useRef } from 'react'; | ||
import { View, TouchableOpacity, Animated, StyleSheet } from 'react-native'; | ||
|
||
interface CustomSwitchProps { | ||
isEnabled: boolean; | ||
onToggle: (value: boolean) => void; | ||
} | ||
|
||
const CustomSwitch: React.FC<CustomSwitchProps> = ({ isEnabled, onToggle }) => { | ||
|
||
const animationValue = useRef(new Animated.Value(isEnabled ? 1 : 0)).current; | ||
|
||
// Update the animation when isEnabled changes | ||
useEffect(() => { | ||
Animated.timing(animationValue, { | ||
toValue: isEnabled ? 1 : 0, | ||
duration: 300, | ||
useNativeDriver: false, | ||
}).start(); | ||
}, [isEnabled]); | ||
|
||
const interpolateBackgroundColor = animationValue.interpolate({ | ||
inputRange: [0, 1], | ||
outputRange: ['#ddd', '#7654F2'], // Off state to On state colors | ||
}); | ||
|
||
const knobPosition = animationValue.interpolate({ | ||
inputRange: [0, 1], | ||
outputRange: [0, 20], // Left position for 'Off' and 'On' | ||
}); | ||
|
||
return ( | ||
<TouchableOpacity | ||
onPress={() => onToggle(!isEnabled)} | ||
style={styles.container} | ||
activeOpacity={0.8} // Prevent quick double-taps causing issues | ||
> | ||
<Animated.View | ||
style={[ | ||
styles.switchBackground, | ||
{ backgroundColor: interpolateBackgroundColor }, | ||
]} | ||
> | ||
<Animated.View | ||
style={[ | ||
styles.switchKnob, | ||
{ transform: [{ translateX: knobPosition }] }, | ||
]} | ||
/> | ||
</Animated.View> | ||
</TouchableOpacity> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
padding: 10, | ||
}, | ||
switchBackground: { | ||
width: 50, | ||
height: 30, | ||
borderRadius: 15, | ||
justifyContent: 'center', | ||
padding: 2, | ||
}, | ||
switchKnob: { | ||
width: 26, | ||
height: 26, | ||
borderRadius: 13, | ||
backgroundColor: '#fff', | ||
}, | ||
}); | ||
|
||
export default CustomSwitch; |