Color & storage fixes. Readme update
All checks were successful
Build Flutter Web and Docker Image for Local Registry / Build React Native Web App (push) Successful in 10m32s

This commit is contained in:
whysman 2025-02-21 21:56:54 -05:00
parent 4abd732fe8
commit d4d8d34d1f
5 changed files with 98 additions and 51 deletions

View File

@ -13,3 +13,11 @@
```bash
npm run web
```
## Contributing
Currently we're not looking for contributors.
## License
This work is licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/)

View File

@ -15,7 +15,7 @@ const Nav = ({ toggleProfile }: { toggleProfile: () => void; }) => {
return (
<View style={{ backgroundColor: theme.colors.background }}>
<Appbar.Header style={{ backgroundColor: theme.colors.primary }}>
<Appbar.Header style={{ backgroundColor: theme.colors.inversePrimary }}>
<View>
<Menu visible={menuVisible} onDismiss={() => setMenuVisible(false)} anchor={menuAnchor}>
<Menu.Item onPress={() => { setMenuVisible(false); setAboutVisible(true);}} title="About Us"/>
@ -25,12 +25,12 @@ const Nav = ({ toggleProfile }: { toggleProfile: () => void; }) => {
setMenuAnchor({ x: event.nativeEvent.pageX, y: event.nativeEvent.pageY + 40 });
setMenuVisible(true);
}}
iconColor={theme.colors.inversePrimary} />
iconColor={theme.colors.primary} />
</View>
<View style={styles.logoContainer}>
<Image source={require("../assets/images/pogdark_logo.png")} style={styles.logo} />
</View>
<Appbar.Action icon="pencil" onPress={toggleProfile} iconColor={ theme.colors.inversePrimary } />
<Appbar.Action icon="pencil" onPress={toggleProfile} iconColor={ theme.colors.primary } />
</Appbar.Header>
<Portal>
<Dialog visible={aboutVisible} onDismiss={() => setAboutVisible(false)} style={{ backgroundColor: theme.colors.background }}>

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import { Platform } from "react-native";
import { Button, TextInput, Dialog, Portal, Avatar, useTheme } from "react-native-paper";
import { Asset } from 'expo-asset';
@ -12,11 +12,24 @@ interface ProfileScreenProps {
setName: (name: string) => void;
image: string;
setImage: (image: string) => void;
setChanged: (dataChanged: boolean) => void;
onClose: () => void;
}
const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, image, setImage, onClose }) => {
const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, image, setImage, setChanged, onClose }) => {
const { colors } = useTheme();
const isNameEmpty = !name.trim();
// Track the initial values when the component first mounts
const [initialName, setInitialName] = useState(name);
const [initialImage, setInitialImage] = useState(image);
useEffect(() => {
if (visible) {
setInitialName(name); // Store initial name when the profile opens
setInitialImage(image); // Store initial image when the profile opens
}
}, [visible]); // Reset when the dialog is opened
useEffect(() => {
const loadDefaultImage = async () => {
@ -45,23 +58,43 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
};
const loadImage = async () => {
if (!image) {
if (!image || image === "") {
console.log("Loading ", image);
await loadDefaultImage();
}
};
loadImage().then(r => null);
loadImage().then(() => null);
}, [image]);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({ base64: true });
if (!result.canceled && result.assets.length > 0) {
if (result.assets[0].base64 !== image) { // Only update if the image actually changes
setImage(result.assets[0].base64 || image);
console.log("Picking Image");
}
}
};
const handleSave = () => {
// Check if the name or image has changed
const hasChanged = name !== initialName || image !== initialImage;
if (hasChanged) {
setChanged(true);
}
onClose(); // Close the profile screen
};
return (
<Portal>
<Dialog visible={visible} onDismiss={onClose} style={{ backgroundColor: colors.background }}>
<Dialog
visible={visible}
onDismiss={() => {
if (!isNameEmpty) { // Prevent closing if name is empty
onClose();
}
}}
style={{ backgroundColor: colors.background }}>
<Dialog.Title style={{ color: colors.onBackground, textAlign: 'center' }}>Edit Your Profile</Dialog.Title>
<Dialog.Content>
<Avatar.Image
@ -81,7 +114,12 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
label="Your Pet's Name"
mode="outlined"
value={name}
onChangeText={setName}
onChangeText={(newName) => {
if (newName !== name) { // Only trigger change if it's different
setName(newName);
console.log("Name change");
}
}}
style={{ marginBottom: 15, backgroundColor: colors.surface }}
placeholderTextColor={colors.onSurface}
theme={{ colors: { text: colors.onSurface } }}
@ -89,38 +127,20 @@ const ProfileScreen: React.FC<ProfileScreenProps> = ({ visible, name, setName, i
</Dialog.Content>
<Dialog.Actions>
<Button
onPress={onClose}
onPress={handleSave}
mode="contained"
style={{ backgroundColor: colors.secondary }}
labelStyle={{ color: colors.onPrimary }}>Save</Button>
disabled={isNameEmpty} // Disable if name is empty
style={{
backgroundColor: isNameEmpty ? colors.tertiary : colors.secondary, // Dim the button
opacity: isNameEmpty ? 0.5 : 1, // Visually dim the button
}}
labelStyle={{ color: colors.onPrimary }}
>
Save
</Button>
</Dialog.Actions>
</Dialog>
</Portal>
/*
<Portal>
<Dialog visible={visible} onDismiss={onClose} style={{ backgroundColor: colors.background }}>
<Dialog.Title>Edit Your Profile</Dialog.Title>
<Dialog.Content>
<Avatar.Image
size={100}
source={image ? { uri: `data:image/png;base64,${image}` } : require("../assets/images/default_profile_image.png")}
style={{ alignSelf: 'center', marginBottom: 15 }}
/>
<Button onPress={pickImage} mode="contained" style={{ backgroundColor: colors.primary, marginBottom: 10 }}>Change Profile Picture</Button>
<TextInput
label="Your Pet's Name"
mode="outlined"
value={name}
onChangeText={setName}
style={{ marginBottom: 15, backgroundColor: colors.surface, color: colors.primary }}
/>
</Dialog.Content>
<Dialog.Actions>
<Button onPress={onClose} mode="contained" style={{ backgroundColor: colors.secondary }}>Save</Button>
</Dialog.Actions>
</Dialog>
</Portal>
*/
);
};

View File

@ -188,7 +188,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
<View style={styles.listRow}>
<View style={styles.listColumn}>
<List.Section>
<List.Subheader style={[styles.listSubheader, { color: theme.colors.onSurface }]}>On the Way</List.Subheader>
<List.Subheader style={[styles.listSubheader, { color: theme.colors.primary }]}>On the Way</List.Subheader>
{messages.filter(msg => msg.Status === "On the Way")
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
.map(item => (
@ -207,7 +207,7 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
</View>
<View style={styles.listColumn}>
<List.Section>
<List.Subheader style={[styles.listSubheader, { color: theme.colors.onSurface }]}>Arrived</List.Subheader>
<List.Subheader style={[styles.listSubheader, { color: theme.colors.primary }]}>Arrived</List.Subheader>
{messages.filter(msg => msg.Status === "Arrived")
.sort((a, b) => new Date(a.Timestamp).getTime() - new Date(b.Timestamp).getTime())
.map(item => (
@ -234,9 +234,9 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
onPress={() => handleStatusPress("On the Way")}
style={[
styles.actionButton,
{ backgroundColor: currentStatus === "On the Way" ? pulseColorOnTheWay : theme.colors.primary }
{ backgroundColor: currentStatus === "On the Way" ? pulseColorOnTheWay : theme.colors.inversePrimary }
]}
labelStyle={{ color: theme.colors.onPrimary }}>
labelStyle={{ color: currentStatus === "On the Way" ? theme.colors.inversePrimary : theme.colors.primary }}>
{getButtonLabel("On the Way")}
</Button>
</Animated.View>
@ -246,9 +246,9 @@ const StatusPage: React.FC<StatusProps> = ({ id, name, image, currentStatus, set
onPress={() => handleStatusPress("Arrived")}
style={[
styles.actionButton,
{ backgroundColor: currentStatus === "Arrived" ? pulseColorArrived : theme.colors.primary }
{ backgroundColor: currentStatus === "Arrived" ? pulseColorArrived : theme.colors.inversePrimary }
]}
labelStyle={{ color: theme.colors.onPrimary }}>
labelStyle={{ color: currentStatus === "Arrived" ? theme.colors.inversePrimary : theme.colors.primary }}>
{getButtonLabel("Arrived")}
</Button>
</Animated.View>

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import {View, StyleSheet } from "react-native";
import {View, StyleSheet, Text } from "react-native";
import { useTheme } from "react-native-paper";
import { v4 as uuidv4 } from "uuid";
import AsyncStorage from "@react-native-async-storage/async-storage";
@ -10,10 +10,12 @@ import Nav from "@/app/Nav";
const Index = () => {
const { colors } = useTheme();
const [isProfileActive, setProfileActive] = useState(false);
const [userId, setUserId] = useState(uuidv4());
const [userId, setUserId] = useState("");
const [userName, setUserName] = useState("");
const [userImage, setUserImage] = useState("");
const [userStatus, setUserStatus] = useState("");
const [userDataChanged, setUserDataChanged] = useState(false);
const [isLoading, setIsLoading] = useState(true); // New loading state
useEffect(() => {
const loadUserData = async () => {
@ -21,6 +23,7 @@ const Index = () => {
const storedUserId = await AsyncStorage.getItem("userId");
const storedUserName = await AsyncStorage.getItem("userName");
const storedUserImage = await AsyncStorage.getItem("userImage");
if (storedUserId) {
setUserId(storedUserId || uuidv4());
setUserName(storedUserName || "");
@ -32,26 +35,41 @@ const Index = () => {
setUserImage("");
setProfileActive(true);
}
console.log("Loading data ", userId);
} catch (error) {
console.error("Error loading user data:", error);
} finally {
setIsLoading(false); // Mark loading as complete
}
};
loadUserData();
}, []);
useEffect(() => {
if (!userDataChanged) return;
const saveUserData = async () => {
try {
console.log("Saving data ", userId);
await AsyncStorage.setItem("userId", userId);
await AsyncStorage.setItem("userName", userName);
await AsyncStorage.setItem("userImage", userImage);
setUserDataChanged(false);
} catch (error) {
console.error("Error saving user data:", error);
}
};
saveUserData();
}, [userId, userName, userImage]);
}, [userDataChanged]);
if (isLoading) {
console.log("Still loading");
return (
<View style={[styles.container, { backgroundColor: colors.background, justifyContent: 'center', alignItems: 'center' }]}>
<Text>Loading...</Text>
</View>
);
}
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
@ -73,6 +91,7 @@ const Index = () => {
setName={setUserName}
image={userImage}
setImage={setUserImage}
setChanged={setUserDataChanged}
onClose={() => setProfileActive(false)}
/>
</View>