Log levels, moved styles, cleaning up

This commit is contained in:
whysman 2025-03-02 15:32:39 -05:00
parent 3ced969c4f
commit 9e077667e9
12 changed files with 507 additions and 155 deletions

View File

@ -1,11 +1,7 @@
import {Appbar, Portal, Button, Dialog, Menu, Text, useTheme} from "react-native-paper"; import {Appbar, Portal, Button, Dialog, Menu, Text, useTheme} from "react-native-paper";
import {Image, StyleSheet, useColorScheme, View} from "react-native"; import {Image, useColorScheme, View} from "react-native";
import React, {useState} from "react"; import React, {useState} from "react";
import styles from "@/app/styles";
const styles = StyleSheet.create({
logoContainer: { flex: 1, alignItems: "center" },
logo: { width: 150, height: 75, resizeMode: "contain" },
});
const Nav = ({ toggleProfile }: { toggleProfile: () => void; }) => { const Nav = ({ toggleProfile }: { toggleProfile: () => void; }) => {
const theme = useTheme(); const theme = useTheme();
@ -28,11 +24,11 @@ const Nav = ({ toggleProfile }: { toggleProfile: () => void; }) => {
}} }}
iconColor={theme.colors.primary} /> iconColor={theme.colors.primary} />
</View> </View>
<View style={styles.logoContainer}> <View style={styles.logoContainer} >
<Image source={ <Image source={
colorScheme === 'dark' ? colorScheme === 'dark' ?
require("../assets/images/pogdark_logo_inverse.png") : require("../assets/images/pogdark_logo.png") require("../assets/images/pogdark_logo_inverse.png") : require("../assets/images/pogdark_logo.png")
} style={styles.logo} /> } style={styles.logo} resizeMode={"contain"} />
</View> </View>
<Appbar.Action icon="pencil" onPress={toggleProfile} iconColor={ theme.colors.primary } /> <Appbar.Action icon="pencil" onPress={toggleProfile} iconColor={ theme.colors.primary } />
</Appbar.Header> </Appbar.Header>

View File

@ -1,11 +1,13 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Platform, View, TouchableOpacity, StyleSheet } from "react-native"; import { Platform, View, TouchableOpacity } from "react-native";
import { Button, TextInput, Dialog, Portal, Avatar, useTheme, Text } from "react-native-paper"; import { Button, TextInput, Dialog, Portal, Avatar, useTheme, Text } from "react-native-paper";
import { Asset } from 'expo-asset'; import { Asset } from 'expo-asset';
import * as FileSystem from 'expo-file-system'; import * as FileSystem from 'expo-file-system';
import * as ImagePicker from "expo-image-picker"; import * as ImagePicker from "expo-image-picker";
import { themes } from '@/app/themes'; import themes from '@/app/themes';
import { featureFlags } from '@/featureFlags'; import styles from "@/app/styles";
import log from "@/util/log"
import featureFlags from '@/util/featureFlags';
interface ProfileScreenProps { interface ProfileScreenProps {
visible: boolean; visible: boolean;
@ -66,7 +68,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
const loadImage = async () => { const loadImage = async () => {
if (!image || image === "") { if (!image || image === "") {
console.log("Loading ", image); log.debug("Loading ", image);
await loadDefaultImage(); await loadDefaultImage();
} }
}; };
@ -78,7 +80,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
if (!result.canceled && result.assets.length > 0) { if (!result.canceled && result.assets.length > 0) {
if (result.assets[0].base64 !== image) { // Only update if the image actually changes if (result.assets[0].base64 !== image) { // Only update if the image actually changes
setImage(result.assets[0].base64 || image); setImage(result.assets[0].base64 || image);
console.log("Picking Image"); log.debug("Picking Image");
} }
} }
}; };
@ -124,7 +126,7 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
onChangeText={(newName) => { onChangeText={(newName) => {
if (newName !== name) { // Only trigger change if it's different if (newName !== name) { // Only trigger change if it's different
setName(newName); setName(newName);
console.log("Name change"); log.debug("Name change");
} }
}} }}
style={{ marginBottom: 15, fontFamily: "SpaceReg" }} style={{ marginBottom: 15, fontFamily: "SpaceReg" }}
@ -134,18 +136,18 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
/> />
{featureFlags.enableThemeSelection && ( {featureFlags.enableThemeSelection && (
<> <>
<Text style={{ color: theme.colors.primary, fontSize: 18, fontFamily: "SpaceReg", textAlign: 'center' }}>Choose Theme</Text> <Text style={{ color: theme.colors.primary, fontSize: 18, fontFamily: "SpaceReg", textAlign: 'center' }}>Choose Theme</Text>
<View style={styles.themeContainer}> <View style={styles.themeContainer}>
{themeColors.map((userTheme) => ( {themeColors.map((userTheme) => (
<TouchableOpacity <TouchableOpacity
key={userTheme} key={userTheme}
style={[styles.themeButton, { backgroundColor: themes[userTheme as keyof typeof themes]['light'].colors.primary }]} style={[styles.themeButton, { backgroundColor: themes[userTheme as keyof typeof themes]['light'].colors.primary }]}
onPress={() => {setTheme(userTheme); console.log("Changing Theme: ", userTheme)}} onPress={() => {setTheme(userTheme); log.debug("Changing Theme: ", userTheme)}}
> >
<View style={[styles.halfCircle, { backgroundColor: themes[userTheme as keyof typeof themes]['dark'].colors.primary }]} /> <View style={[styles.halfCircle, { backgroundColor: themes[userTheme as keyof typeof themes]['dark'].colors.primary }]} />
</TouchableOpacity> </TouchableOpacity>
))} ))}
</View> </View>
</> </>
)} )}
</Dialog.Content> </Dialog.Content>
@ -165,30 +167,4 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
); );
}; };
const styles = StyleSheet.create({
themeContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
marginTop: 10,
},
themeButton: {
width: 50,
height: 50,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'flex-start',
overflow: 'hidden',
borderWidth: 1,
borderColor: 'black',
},
halfCircle: {
width: '50%',
height: '100%',
position: 'absolute',
bottom: 0,
},
});
export default ProfileScreen; export default ProfileScreen;

View File

@ -1,9 +1,11 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import useWebSocket from "react-use-websocket"; import useWebSocket from "react-use-websocket";
import axios from "axios"; import axios from "axios";
import {Animated, Easing, ImageBackground, StyleSheet, useColorScheme, View} from "react-native"; import {Animated, Easing, ImageBackground, useColorScheme, View} from "react-native";
import { Avatar, List, Button, useTheme, } from "react-native-paper"; import { Avatar, List, Button, useTheme, } from "react-native-paper";
import { themes } from "@/app/themes"; import themes from "@/app/themes";
import styles from "@/app/styles";
import log from "@/util/log"
export const API_URL = process.env.EXPO_PUBLIC_API_URL; export const API_URL = process.env.EXPO_PUBLIC_API_URL;
export const WS_URL = process.env.EXPO_PUBLIC_WS_URL; export const WS_URL = process.env.EXPO_PUBLIC_WS_URL;
@ -17,55 +19,6 @@ interface Message {
Timestamp: string; Timestamp: string;
} }
const styles = StyleSheet.create({
container: { flex: 1, alignItems: "stretch" },
listContainer: { flex: 1, width: "100%", backgroundColor: 'transparent' },
listSubheader: {
fontFamily: "Medium",
fontSize: 18, // Larger text
textAlign: "center", // Center the text
fontWeight: "bold", // Make it more distinct
marginBottom: 10, // Add spacing below
zIndex: 0,
},
listWrapper: { flex: 1, padding: 5 },
listRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-start", // Aligns subheaders properly
paddingHorizontal: 10, // Adds some spacing
},
listColumn: { flex: 1, paddingHorizontal: 5, zIndex: 1},
buttonContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignSelf: "stretch",
paddingHorizontal: 10,
paddingBottom: 20,
},
actionButton: {
flex: 1,
marginHorizontal: 5,
},
card: {
marginVertical: 5,
elevation: 4, // Android shadow
shadowColor: "#000", // iOS shadow
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
borderRadius: 10,
},
imageBackground: {
position: "absolute", // Allows child elements to layer on top
width: "100%", // Ensure full coverage of the column
height: "100%", // Fully stretches to column height
resizeMode: "cover", // Ensures it fits well
opacity: 0.2, // Fades the image
zIndex: -1,
},
});
interface StatusProps { interface StatusProps {
id: string; id: string;
name: string; name: string;
@ -77,11 +30,11 @@ interface StatusProps {
} }
const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, setStatus, currentTheme, isProfileActive }) => { const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, setStatus, currentTheme, isProfileActive }) => {
//console.log("WebSocket URL: ", WS_URL); log.debug("WebSocket URL: ", WS_URL);
//console.log("API URL: ", API_URL); log.debug("API URL: ", API_URL);
const theme = useTheme(); const theme = useTheme();
const colorScheme = useColorScheme(); const colorScheme = useColorScheme();
console.log(themes[currentTheme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.primary); log.debug(themes[currentTheme as keyof typeof themes][colorScheme === 'dark' ? 'dark' : 'light'].colors.primary);
const [messages, setMessages] = useState<Message[]>([]); const [messages, setMessages] = useState<Message[]>([]);
const { lastMessage } = useWebSocket(WS_URL + "/ws", { const { lastMessage } = useWebSocket(WS_URL + "/ws", {
@ -118,7 +71,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
}; };
useEffect(() => { useEffect(() => {
//console.log("Updated status: ", currentStatus); log.debug("Updated status: ", currentStatus);
if (currentStatus === "On the Way") { if (currentStatus === "On the Way") {
startPulsing(pulseAnimOnTheWay); startPulsing(pulseAnimOnTheWay);
@ -147,7 +100,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
try { try {
if (currentStatus === status) { if (currentStatus === status) {
// If pressed again, send "none" status and clear currentStatus // If pressed again, send "none" status and clear currentStatus
console.log(`Removing status: ${status}`); log.debug(`Removing status: ${status}`);
const message: Message = { const message: Message = {
Id: id, Id: id,
Name: name, Name: name,
@ -162,7 +115,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
}, 0) }, 0)
} else { } else {
// Otherwise, send the new status // Otherwise, send the new status
console.log(`Setting status: ${status}`); log.debug(`Setting status: ${status}`);
const message: Message = { const message: Message = {
Id: id, Id: id,
Name: name, Name: name,
@ -178,7 +131,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
} }
} catch (error) { } catch (error) {
console.error(`Error sending status '${status}':`, error); log.error(`Error sending status '${status}':`, error);
} }
}; };
@ -193,21 +146,21 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
if (lastMessage?.data) { if (lastMessage?.data) {
try { try {
const newMessage: Message = JSON.parse(lastMessage.data); const newMessage: Message = JSON.parse(lastMessage.data);
console.log("Current Status", currentStatus); log.debug("Current Status", currentStatus);
setMessages((prev) => { setMessages((prev) => {
if (newMessage.Id === id && newMessage.Status !== currentStatus) { if (newMessage.Id === id && newMessage.Status !== currentStatus) {
console.log("Status different, change to: ", newMessage.Status); log.debug("Status different, change to: ", newMessage.Status);
setTimeout(() => { setTimeout(() => {
setStatus(newMessage.Status); setStatus(newMessage.Status);
}, 0); }, 0);
//return prev.filter((msg) => msg.Id !== newMessage.Id); //return prev.filter((msg) => msg.Id !== newMessage.Id);
}else{ }else{
console.log("Status equal, no change"); log.debug("Status equal, no change");
} }
return prev.filter((msg) => msg.Id !== newMessage.Id).concat(newMessage); return prev.filter((msg) => msg.Id !== newMessage.Id).concat(newMessage);
}); });
} catch (error) { } catch (error) {
console.error("Error parsing WebSocket message:", error); log.error("Error parsing WebSocket message:", error);
} }
} }
}, [lastMessage, setStatus, id]); }, [lastMessage, setStatus, id]);

View File

@ -5,8 +5,9 @@ import { useEffect } from 'react';
import 'react-native-reanimated'; import 'react-native-reanimated';
import { useColorScheme } from 'react-native'; import { useColorScheme } from 'react-native';
import { PaperProvider, Provider } from "react-native-paper"; import { PaperProvider, Provider } from "react-native-paper";
import { themes } from '@/app/themes'
import { UserProvider, useUser } from "@/context/UserContext"; import { UserProvider, useUser } from "@/context/UserContext";
import themes from '@/app/themes'
import log from "@/util/log"
// Prevent the splash screen from auto-hiding before asset loading is complete. // Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync(); SplashScreen.preventAutoHideAsync();
@ -21,9 +22,9 @@ export default function RootLayout() {
function InnerRootLayout() { function InnerRootLayout() {
const { currentTheme } = useUser(); // Access the currentTheme from UserContext const { currentTheme } = useUser(); // Access the currentTheme from UserContext
console.log(currentTheme); log.debug(currentTheme);
const colorScheme = useColorScheme(); const colorScheme = useColorScheme();
console.log(colorScheme); log.debug(colorScheme);
const [loaded] = useFonts({ const [loaded] = useFonts({
SpaceReg: require('../assets/fonts/SpaceMono-Regular.ttf'), SpaceReg: require('../assets/fonts/SpaceMono-Regular.ttf'),
SpaceBold: require('../assets/fonts/SpaceMono-Bold.ttf'), SpaceBold: require('../assets/fonts/SpaceMono-Bold.ttf'),

View File

@ -1,10 +1,12 @@
import React from 'react'; import React from 'react';
import {View, StyleSheet, Text } from "react-native"; import {View, Text } from "react-native";
import { useTheme } from "react-native-paper"; import { useTheme } from "react-native-paper";
import ProfileScreen from "@/app/ProfileScreen"; import ProfileScreen from "@/app/ProfileScreen";
import StatusPage from "@/app/StatusPage"; import StatusPage from "@/app/StatusPage";
import Nav from "@/app/Nav"; import Nav from "@/app/Nav";
import { useUser } from "@/context/UserContext"; import { useUser } from "@/context/UserContext";
import styles from "@/app/styles";
import log from "@/util/log"
const Index = () => { const Index = () => {
const theme = useTheme(); const theme = useTheme();
@ -26,16 +28,16 @@ const Index = () => {
} = useUser(); } = useUser();
if (isLoading) { if (isLoading) {
console.log("Still loading"); log.debug("Still loading");
return ( return (
<View style={[styles.container, { backgroundColor: theme.colors.background, justifyContent: 'center', alignItems: 'center' }]}> <View style={[styles.indexContainer, { backgroundColor: theme.colors.background, justifyContent: 'center', alignItems: 'center' }]}>
<Text>Loading...</Text> <Text>Loading...</Text>
</View> </View>
); );
} }
return ( return (
<View style={[styles.container, { backgroundColor: theme.colors.background }]}> <View style={[styles.indexContainer, { backgroundColor: theme.colors.background }]}>
<Nav <Nav
toggleProfile={() => setProfileActive(true)} toggleProfile={() => setProfileActive(true)}
/> />
@ -64,15 +66,4 @@ const Index = () => {
); );
}; };
const styles = StyleSheet.create({
container: { flex: 1, alignItems: "stretch" },
imageBackground: {
position: "absolute", // Allows child elements to layer on top
width: "100%", // Ensure full coverage of the column
height: "100%", // Fully stretches to column height
resizeMode: "cover", // Ensures it fits well
opacity: 0.3, // Fades the image
},
});
export default Index; export default Index;

89
app/styles.ts Normal file
View File

@ -0,0 +1,89 @@
import {StyleSheet} from "react-native";
const styles = StyleSheet.create({
//StatusPage
container: { flex: 1, alignItems: "stretch" },
listContainer: { flex: 1, width: "100%", backgroundColor: 'transparent' },
listSubheader: {
fontFamily: "Medium",
fontSize: 18, // Larger text
textAlign: "center", // Center the text
fontWeight: "bold", // Make it more distinct
marginBottom: 10, // Add spacing below
zIndex: 0,
},
listWrapper: { flex: 1, padding: 5 },
listRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-start", // Aligns subheaders properly
paddingHorizontal: 10, // Adds some spacing
},
listColumn: { flex: 1, paddingHorizontal: 5, zIndex: 1},
buttonContainer: {
flexDirection: "row",
justifyContent: "space-between",
alignSelf: "stretch",
paddingHorizontal: 10,
paddingBottom: 20,
},
actionButton: {
flex: 1,
marginHorizontal: 5,
},
card: {
marginVertical: 5,
elevation: 4, // Android shadow
shadowColor: "#000", // iOS shadow
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
borderRadius: 10,
},
imageBackground: {
position: "absolute", // Allows child elements to layer on top
width: "100%", // Ensure full coverage of the column
height: "100%", // Fully stretches to column height
resizeMode: "cover", // Ensures it fits well
opacity: 0.2, // Fades the image
zIndex: -1,
},
//profile screen
themeContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
alignSelf: 'center',
//alignItems: 'center',
marginTop: 10,
},
themeButton: {
width: 50,
height: 50,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'flex-start',
overflow: 'hidden',
borderWidth: 1,
borderColor: 'black',
},
halfCircle: {
width: '50%',
height: '100%',
position: 'absolute',
bottom: 0,
},
//Nav
logoContainer: { flex: 1, alignItems: "center" },
logo: { width: 150, height: 75 },
//index
indexImageBackground: {
position: "absolute", // Allows child elements to layer on top
width: "100%", // Ensure full coverage of the column
height: "100%", // Fully stretches to column height
resizeMode: "cover", // Ensures it fits well
opacity: 0.3, // Fades the image
},
indexContainer: { flex: 1, alignItems: "stretch" },
});
export default styles;

View File

@ -1,6 +1,6 @@
import { MD3LightTheme, MD3DarkTheme } from 'react-native-paper'; import { MD3LightTheme, MD3DarkTheme } from 'react-native-paper';
export const themes = { const themes = {
purple: { purple: {
light: MD3LightTheme, light: MD3LightTheme,
dark: MD3DarkTheme, dark: MD3DarkTheme,
@ -106,3 +106,345 @@ export const themes = {
}, },
} }
}; };
export const oldThemes = {
purple: {
light: MD3LightTheme,
dark: MD3DarkTheme,
},
red: {
light: {
...MD3LightTheme,
colors: {
...MD3LightTheme.colors,
primary: '#D32F2F',
onPrimary: '#FFFFFF',
primaryContainer: '#FFCDD2',
onPrimaryContainer: '#4A0D0D',
secondary: '#FF5252',
onSecondary: '#FFFFFF',
secondaryContainer: '#FFEBEE',
onSecondaryContainer: '#5D1E1E',
tertiary: '#C2185B',
onTertiary: '#FFFFFF',
tertiaryContainer: '#F8BBD0',
onTertiaryContainer: '#550027',
background: '#FFFFFF',
onBackground: '#121212',
surface: '#F5F5F5',
onSurface: '#1E1E1E',
error: '#B00020',
onError: '#FFFFFF',
outline: '#B71C1C',
inverseSurface: '#333333',
inverseOnSurface: '#FAFAFA',
inversePrimary: '#FFB4A9',
},
},
dark: {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
primary: '#FF5252',
onPrimary: '#FFFFFF',
primaryContainer: '#7F0000',
onPrimaryContainer: '#FFDAD4',
secondary: '#FF8A80',
onSecondary: '#1E0000',
secondaryContainer: '#4A0D0D',
onSecondaryContainer: '#FFEBEE',
tertiary: '#FF4081',
onTertiary: '#1E001E',
tertiaryContainer: '#7A001A',
onTertiaryContainer: '#FFD9E3',
background: '#121212',
onBackground: '#E1E1E1',
surface: '#1E1E1E',
onSurface: '#FFFFFF',
error: '#CF6679',
onError: '#FFFFFF',
outline: '#FF6F61',
inverseSurface: '#E1E1E1',
inverseOnSurface: '#1E1E1E',
inversePrimary: '#D32F2F',
},
},
},
blue: {
light: {
...MD3LightTheme,
colors: {
...MD3LightTheme.colors,
primary: '#1976D2',
onPrimary: '#FFFFFF',
primaryContainer: '#BBDEFB',
onPrimaryContainer: '#0D47A1',
secondary: '#64B5F6',
onSecondary: '#FFFFFF',
secondaryContainer: '#E3F2FD',
onSecondaryContainer: '#1565C0',
tertiary: '#0288D1',
onTertiary: '#FFFFFF',
tertiaryContainer: '#81D4FA',
onTertiaryContainer: '#01579B',
background: '#FFFFFF',
onBackground: '#121212',
surface: '#F5F5F5',
onSurface: '#1E1E1E',
error: '#B00020',
onError: '#FFFFFF',
outline: '#1565C0',
inverseSurface: '#333333',
inverseOnSurface: '#FAFAFA',
inversePrimary: '#90CAF9',
},
},
dark: {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
primary: '#64B5F6',
onPrimary: '#FFFFFF',
primaryContainer: '#0D47A1',
onPrimaryContainer: '#BBDEFB',
secondary: '#81D4FA',
onSecondary: '#1E1E1E',
secondaryContainer: '#1565C0',
onSecondaryContainer: '#E3F2FD',
tertiary: '#29B6F6',
onTertiary: '#1E1E1E',
tertiaryContainer: '#01579B',
onTertiaryContainer: '#81D4FA',
background: '#121212',
onBackground: '#E1E1E1',
surface: '#1E1E1E',
onSurface: '#FFFFFF',
error: '#CF6679',
onError: '#FFFFFF',
outline: '#64B5F6',
inverseSurface: '#E1E1E1',
inverseOnSurface: '#1E1E1E',
inversePrimary: '#1976D2',
},
},
},
yellow: {
light: {
...MD3LightTheme,
colors: {
...MD3LightTheme.colors,
primary: '#FBC02D',
onPrimary: '#000000',
primaryContainer: '#FFF9C4',
onPrimaryContainer: '#5F3700',
secondary: '#FFD54F',
onSecondary: '#000000',
secondaryContainer: '#FFF8E1',
onSecondaryContainer: '#775A00',
tertiary: '#FFB300',
onTertiary: '#FFFFFF',
tertiaryContainer: '#FFECB3',
onTertiaryContainer: '#603800',
background: '#FFFFFF',
onBackground: '#121212',
surface: '#F5F5F5',
onSurface: '#1E1E1E',
error: '#B00020',
onError: '#FFFFFF',
outline: '#FF8F00',
inverseSurface: '#333333',
inverseOnSurface: '#FAFAFA',
inversePrimary: '#FDD835',
},
},
dark: {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
primary: '#FFD54F',
onPrimary: '#000000',
primaryContainer: '#5F3700',
onPrimaryContainer: '#FFF9C4',
secondary: '#FFEB3B',
onSecondary: '#000000',
secondaryContainer: '#775A00',
onSecondaryContainer: '#FFF8E1',
tertiary: '#FFB300',
onTertiary: '#1E1E1E',
tertiaryContainer: '#603800',
onTertiaryContainer: '#FFECB3',
background: '#121212',
onBackground: '#E1E1E1',
surface: '#1E1E1E',
onSurface: '#FFFFFF',
error: '#CF6679',
onError: '#FFFFFF',
outline: '#FDD835',
inverseSurface: '#E1E1E1',
inverseOnSurface: '#1E1E1E',
inversePrimary: '#FBC02D',
},
},
},
green: {
light: {
...MD3LightTheme,
colors: {
...MD3LightTheme.colors,
primary: '#388E3C', // Material Green 700
onPrimary: '#FFFFFF',
primaryContainer: '#C8E6C9',
onPrimaryContainer: '#004D00',
secondary: '#66BB6A',
onSecondary: '#FFFFFF',
secondaryContainer: '#E8F5E9',
onSecondaryContainer: '#1B5E20',
tertiary: '#2E7D32',
onTertiary: '#FFFFFF',
tertiaryContainer: '#A5D6A7',
onTertiaryContainer: '#003300',
background: '#FFFFFF',
onBackground: '#121212',
surface: '#F5F5F5',
onSurface: '#1E1E1E',
error: '#B00020',
onError: '#FFFFFF',
outline: '#388E3C',
inverseSurface: '#333333',
inverseOnSurface: '#FAFAFA',
inversePrimary: '#A5D6A7', // Soft green
},
},
dark: {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
primary: '#66BB6A',
onPrimary: '#FFFFFF',
primaryContainer: '#004D00',
onPrimaryContainer: '#C8E6C9',
secondary: '#81C784',
onSecondary: '#1E1E1E',
secondaryContainer: '#1B5E20',
onSecondaryContainer: '#E8F5E9',
tertiary: '#43A047',
onTertiary: '#1E1E1E',
tertiaryContainer: '#003300',
onTertiaryContainer: '#A5D6A7',
background: '#121212',
onBackground: '#E1E1E1',
surface: '#1E1E1E',
onSurface: '#FFFFFF',
error: '#CF6679',
onError: '#FFFFFF',
outline: '#A5D6A7',
inverseSurface: '#E1E1E1',
inverseOnSurface: '#1E1E1E',
inversePrimary: '#388E3C', // Same as light theme primary
}
}
},
orange: {
light: {
...MD3LightTheme,
colors: {
...MD3LightTheme.colors,
primary: '#F57C00', // Material Orange 700
onPrimary: '#FFFFFF',
primaryContainer: '#FFCC80',
onPrimaryContainer: '#7A3300',
secondary: '#FFA726',
onSecondary: '#FFFFFF',
secondaryContainer: '#FFE0B2',
onSecondaryContainer: '#8E4700',
tertiary: '#EF6C00', // Deep orange
onTertiary: '#FFFFFF',
tertiaryContainer: '#FFD180',
onTertiaryContainer: '#622600',
background: '#FFFFFF',
onBackground: '#121212',
surface: '#F5F5F5',
onSurface: '#1E1E1E',
error: '#B00020',
onError: '#FFFFFF',
outline: '#F57C00',
inverseSurface: '#333333',
inverseOnSurface: '#FAFAFA',
inversePrimary: '#FFAB40', // Soft orange
},
},
dark: {
...MD3DarkTheme,
colors: {
...MD3DarkTheme.colors,
primary: '#FFA726',
onPrimary: '#FFFFFF',
primaryContainer: '#b38800',
onPrimaryContainer: '#FFCC80',
secondary: '#FFB74D',
onSecondary: '#1E1E1E',
secondaryContainer: '#5a4406',
onSecondaryContainer: '#FFE0B2',
tertiary: '#FB8C00',
onTertiary: '#1E1E1E',
tertiaryContainer: '#623400',
onTertiaryContainer: '#FFD180',
background: '#121212',
onBackground: '#E1E1E1',
surface: '#1E1E1E',
onSurface: '#FFFFFF',
error: '#CF6679',
onError: '#FFFFFF',
outline: '#FFAB40',
inverseSurface: '#E1E1E1',
inverseOnSurface: '#1E1E1E',
inversePrimary: '#F57C00', // Same as light theme primary
},
}
}
};
export const themePreviews = {
purple: {
light: '#6200EA', // Default Purple Light
dark: '#BB86FC', // Default Purple Dark
},
red: {
light: '#D32F2F',
dark: '#FF5252',
},
blue: {
light: '#1976D2',
dark: '#64B5F6',
},
yellow: {
light: '#FBC02D',
dark: '#FFD54F',
},
green: {
light: '#388E3C',
dark: '#66BB6A',
},
orange: {
light: '#F57C00',
dark: '#FFA726',
},
};
export default themes;

View File

@ -3,6 +3,7 @@ import AsyncStorage from "@react-native-async-storage/async-storage";
import { AppState } from "react-native"; import { AppState } from "react-native";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
import axios from "axios"; import axios from "axios";
import log from "@/util/log"
export const API_URL = process.env.EXPO_PUBLIC_API_URL; export const API_URL = process.env.EXPO_PUBLIC_API_URL;
@ -41,6 +42,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [appState, setAppState] = useState(AppState.currentState); const [appState, setAppState] = useState(AppState.currentState);
const [currentTheme, setTheme] = useState(""); const [currentTheme, setTheme] = useState("");
const [isDarkMode, setDarkMode] = useState(false);
useEffect(() => { useEffect(() => {
const loadUserData = async () => { const loadUserData = async () => {
@ -49,7 +51,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const storedUserName = await AsyncStorage.getItem("userName"); const storedUserName = await AsyncStorage.getItem("userName");
const storedUserImage = await AsyncStorage.getItem("userImage"); const storedUserImage = await AsyncStorage.getItem("userImage");
const storedUserTheme = await AsyncStorage.getItem("theme"); const storedUserTheme = await AsyncStorage.getItem("theme");
console.log("Stored theme: ", storedUserTheme); log.debug("Stored theme: ", storedUserTheme);
if (storedUserId) { if (storedUserId) {
setUserId(storedUserId); setUserId(storedUserId);
setUserName(storedUserName || ""); setUserName(storedUserName || "");
@ -64,7 +66,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
setProfileActive(true); setProfileActive(true);
} }
} catch (error) { } catch (error) {
console.error("Error loading user data:", error); log.error("Error loading user data:", error);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
} }
@ -82,10 +84,10 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
await AsyncStorage.setItem("userName", userName); await AsyncStorage.setItem("userName", userName);
await AsyncStorage.setItem("userImage", userImage); await AsyncStorage.setItem("userImage", userImage);
await AsyncStorage.setItem("theme", currentTheme); await AsyncStorage.setItem("theme", currentTheme);
console.log("Current theme: ", currentTheme); log.debug("Current theme: ", currentTheme);
setUserDataChanged(false); setUserDataChanged(false);
} catch (error) { } catch (error) {
console.error("Error saving user data:", error); log.error("Error saving user data:", error);
} }
}; };
@ -98,7 +100,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
if (!isLoading) { if (!isLoading) {
fetchCurrentStatus(); fetchCurrentStatus();
} else { } else {
console.log("Waiting for loading to complete before fetching status..."); log.debug("Waiting for loading to complete before fetching status...");
} }
} }
setAppState(AppState.currentState); setAppState(AppState.currentState);
@ -120,7 +122,7 @@ export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
}, 0); }, 0);
} }
} catch (error) { } catch (error) {
console.error("Error fetching status:", error); log.error("Error fetching status:", error);
} }
}; };

22
package-lock.json generated
View File

@ -30,8 +30,8 @@
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-native": "0.77.1", "react-native": "0.77.1",
"react-native-config": "~1.5.5",
"react-native-gesture-handler": "~2.20.2", "react-native-gesture-handler": "~2.20.2",
"react-native-logs": "~5.3.0",
"react-native-paper": "~5.13.1", "react-native-paper": "~5.13.1",
"react-native-reanimated": "~3.16.1", "react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "4.12.0", "react-native-safe-area-context": "4.12.0",
@ -12430,20 +12430,6 @@
} }
} }
}, },
"node_modules/react-native-config": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/react-native-config/-/react-native-config-1.5.5.tgz",
"integrity": "sha512-dGdLnBU0cd5xL5bF0ROTmHYbsstZnQKOEPfglvZi1vStvAjpld14X25K6mY3KGPTMWAzx6TbjKeq5dR+ILuMMA==",
"license": "MIT",
"peerDependencies": {
"react-native-windows": ">=0.61"
},
"peerDependenciesMeta": {
"react-native-windows": {
"optional": true
}
}
},
"node_modules/react-native-gesture-handler": { "node_modules/react-native-gesture-handler": {
"version": "2.20.2", "version": "2.20.2",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz",
@ -12484,6 +12470,12 @@
"react-native": ">=0.73.0" "react-native": ">=0.73.0"
} }
}, },
"node_modules/react-native-logs": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/react-native-logs/-/react-native-logs-5.3.0.tgz",
"integrity": "sha512-tq4S0JFy06ggu1D/udYeV80qPy5koURNNcKrVJmv0Hf3x44akysctaE4ARybD5Pv7MnFD8fP1VFhycSLjqXHQw==",
"license": "MIT"
},
"node_modules/react-native-paper": { "node_modules/react-native-paper": {
"version": "5.13.1", "version": "5.13.1",
"resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.13.1.tgz", "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.13.1.tgz",

View File

@ -34,6 +34,7 @@
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-native": "0.77.1", "react-native": "0.77.1",
"react-native-gesture-handler": "~2.20.2", "react-native-gesture-handler": "~2.20.2",
"react-native-logs": "~5.3.0",
"react-native-reanimated": "~3.16.1", "react-native-reanimated": "~3.16.1",
"react-native-safe-area-context": "4.12.0", "react-native-safe-area-context": "4.12.0",
"react-native-screens": "~4.4.0", "react-native-screens": "~4.4.0",

View File

@ -1,3 +1,5 @@
export const featureFlags = { const featureFlags = {
enableThemeSelection: true, // Toggle this to true or false to enable/disable the feature enableThemeSelection: true, // Toggle this to true or false to enable/disable the feature
}; };
export default featureFlags;

7
util/log.ts Normal file
View File

@ -0,0 +1,7 @@
import { logger } from "react-native-logs";
const log = logger.createLogger({
severity: "error"
});
export default log;