Skip to content

Commit

Permalink
Merge pull request #81 from FYP-2024-IQMA/SCRUM-143-Create-frontend-f…
Browse files Browse the repository at this point in the history
…or-Settings-Page

Scrum-143 Create Frontend for Settings page
  • Loading branch information
germainetan authored Oct 10, 2024
2 parents c297c20 + a182c98 commit f436053
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 42 deletions.
2 changes: 2 additions & 0 deletions frontend/iQMA-Skills-Builder/app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export default function AppTabs() {
tabBarIcon: ({color, size}) => (
<Ionicons name="person" size={size} color={color} />
),
headerTintColor: '#fff'
}}
/>
<Tab.Screen
Expand All @@ -78,6 +79,7 @@ export default function AppTabs() {
tabBarIcon: ({color, size}) => (
<Ionicons name="settings" size={size} color={color} />
),
headerTintColor: '#fff'
}}
/>
</Tab.Navigator>
Expand Down
4 changes: 3 additions & 1 deletion frontend/iQMA-Skills-Builder/app/screens/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as unitEndpoints from '@/helpers/unitEndpoints';
import * as lessonEndpoints from '@/helpers/lessonEndpoints';
import * as resultEndpoints from '@/helpers/resultEndpoints';
import { LoadingIndicator } from '@/components/LoadingIndicator';
import { SafeAreaView } from 'react-native-safe-area-context';

function calculateTotalProgress(i: number, totalUnits: number, getLessonIds: any[]) {
const uniqueAlphabets = new Set(getLessonIds);
Expand Down Expand Up @@ -396,6 +397,7 @@ const HomeScreen: React.FC = () => {
}

return (
<SafeAreaView>
<ScrollView contentContainerStyle={styles.container}>
{/* Top Stats */}
<TopStats circularProgress={sectionCircularProgress} />
Expand All @@ -417,14 +419,14 @@ const HomeScreen: React.FC = () => {
<Text>No sections available</Text>
)}
</ScrollView>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
container: {
padding: 20,
backgroundColor: '#F5F5F5',
marginTop: 10,
},
lineSeparator: {
height: 1,
Expand Down
142 changes: 102 additions & 40 deletions frontend/iQMA-Skills-Builder/app/screens/Settings.tsx
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;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/iQMA-Skills-Builder/components/CustomButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const styles = StyleSheet.create({
// paddingBottom: 20,
},
button: {
width: screenWidth * 0.8,
width: screenWidth * 0.9,
marginVertical: 10,
padding: 15,
borderRadius: 10,
Expand Down
74 changes: 74 additions & 0 deletions frontend/iQMA-Skills-Builder/components/CustomSwitch.tsx
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;

0 comments on commit f436053

Please sign in to comment.