fix: Persistent storage for todo + font fix

Signed-off-by: SindreKjelsrud <sindre@kjelsrud.dev>
This commit is contained in:
Sid 2025-07-05 17:56:37 +02:00
parent 2764f555de
commit 43aa945fc9
Signed by: sidski
GPG key ID: D2BBDF3EDE6BA9A6
2 changed files with 143 additions and 84 deletions

View file

@ -221,6 +221,7 @@ export const styles = StyleSheet.create({
flex: 1, flex: 1,
fontSize: 18, fontSize: 18,
color: "#333", color: "#333",
fontFamily: "Minecraft",
}, },
removeTodoButton: { removeTodoButton: {
backgroundColor: "#FF6347", backgroundColor: "#FF6347",

View file

@ -1,14 +1,16 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useRouter } from "expo-router"; import { useRouter } from "expo-router";
import { useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
ImageBackground, Alert,
KeyboardAvoidingView, ImageBackground,
Platform, KeyboardAvoidingView,
ScrollView, Platform,
Text, ScrollView,
TextInput, Text,
TouchableOpacity, TextInput,
View TouchableOpacity,
View
} from "react-native"; } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context"; import { SafeAreaView } from "react-native-safe-area-context";
import { styles } from "./styles"; import { styles } from "./styles";
@ -16,86 +18,142 @@ import { styles } from "./styles";
const converterBgImage = require("../assets/images/todo.png"); const converterBgImage = require("../assets/images/todo.png");
export default function CoordinateConverter() { export default function CoordinateConverter() {
const router = useRouter(); const router = useRouter();
const [todos, setTodos] = useState<string[]>([]); const [todos, setTodos] = useState<string[]>([]);
const [newTodo, setNewTodo] = useState<string>(""); const [newTodo, setNewTodo] = useState<string>("");
const addTodo = () => { // Define a unique key for AsyncStorage
if (newTodo.trim().length > 0) { const STORAGE_KEY = "@my_todo_list";
setTodos([...todos, newTodo.trim()]);
setNewTodo("");
}
};
const removeTodo = (index: number) => { // --- Persistence Logic ---
const updatedTodos = todos.filter((_, i) => i !== index); useEffect(() => {
setTodos(updatedTodos); loadTodos();
}; }, []);
useEffect(() => {
saveTodos();
}, [todos]);
return ( // Async function to load todos from AsyncStorage
<View style={styles.converterScreenRoot}> const loadTodos = async () => {
<ImageBackground try {
source={converterBgImage} const jsonValue = await AsyncStorage.getItem(STORAGE_KEY);
style={styles.converterBackgroundImage} if (jsonValue != null) {
resizeMode="cover" const parsedTodos = JSON.parse(jsonValue);
> if (Array.isArray(parsedTodos)) {
<View style={styles.converterBackgroundOverlay} /> setTodos(parsedTodos);
</ImageBackground> } else {
console.warn("Loaded data is not an array, initializing empty todo list.");
setTodos([]);
}
}
} catch (e) {
console.error("Failed to load todos:", e);
Alert.alert("Error", "Failed to load your todo list.");
}
};
<SafeAreaView style={styles.converterContentWrapper}> // Async function to save todos to AsyncStorage
<KeyboardAvoidingView const saveTodos = async () => {
style={styles.converterContainer} try {
behavior={Platform.OS === "ios" ? "padding" : "height"} const jsonValue = JSON.stringify(todos);
> await AsyncStorage.setItem(STORAGE_KEY, jsonValue);
<ScrollView contentContainerStyle={styles.converterScrollContent}> } catch (e) {
{/* Custom Back Button */} console.error("Failed to save todos:", e);
<TouchableOpacity Alert.alert("Error", "Failed to save your todo list.");
onPress={() => router.back()} }
style={styles.backButton} };
const addTodo = () => {
if (newTodo.trim().length > 0) {
setTodos((prevTodos) => [...prevTodos, newTodo.trim()]);
setNewTodo("");
}
};
const removeTodo = (index: number) => {
const updatedTodos = todos.filter((_, i) => i !== index);
setTodos(updatedTodos);
};
return (
<View style={styles.converterScreenRoot}>
<ImageBackground
source={converterBgImage}
style={styles.converterBackgroundImage}
resizeMode="cover"
> >
<Text style={styles.backButtonText}> Go Back</Text> <View style={styles.converterBackgroundOverlay} />
</TouchableOpacity> </ImageBackground>
<Text style={styles.converterTitle}>Todo List</Text> <SafeAreaView style={styles.converterContentWrapper}>
<KeyboardAvoidingView
{/* Todo Input Section */} style={styles.converterContainer}
<View style={styles.todoInputContainer}> behavior={Platform.OS === "ios" ? "padding" : "height"}
<TextInput >
style={styles.todoInputField} <ScrollView
placeholder="Add a new todo..." contentContainerStyle={styles.converterScrollContent}
placeholderTextColor="#666"
value={newTodo}
onChangeText={setNewTodo}
onSubmitEditing={addTodo}
/>
<TouchableOpacity onPress={addTodo} style={styles.addTodoButton}>
<Text style={styles.addTodoButtonText}>Add</Text>
</TouchableOpacity>
</View>
{/* Todo List Display */}
<View style={styles.todoListContainer}>
{todos.length === 0 ? (
<Text style={styles.placeholderText}>
Your todo list is empty. Add some tasks!
</Text>
) : (
todos.map((todo, index) => (
<View key={index} style={styles.todoItem}>
<Text style={styles.todoText}>{todo}</Text>
<TouchableOpacity
onPress={() => removeTodo(index)}
style={styles.removeTodoButton}
> >
<Text style={styles.removeTodoButtonText}>X</Text> {/* Custom Back Button */}
</TouchableOpacity> <TouchableOpacity
</View> onPress={() => router.back()}
)) style={styles.backButton}
)} >
</View> <Text style={styles.backButtonText}>
</ScrollView> Go Back
</KeyboardAvoidingView> </Text>
</SafeAreaView> </TouchableOpacity>
</View>
); <Text style={styles.converterTitle}>Todo List</Text>
{/* Todo Input Section */}
<View style={styles.todoInputContainer}>
<TextInput
style={styles.todoInputField}
placeholder="Add a new todo..."
placeholderTextColor="#666"
value={newTodo}
onChangeText={setNewTodo}
onSubmitEditing={addTodo}
/>
<TouchableOpacity
onPress={addTodo}
style={styles.addTodoButton}
>
<Text style={styles.addTodoButtonText}>
Add
</Text>
</TouchableOpacity>
</View>
{/* Todo List Display */}
<View style={styles.todoListContainer}>
{todos.length === 0 ? (
<Text style={styles.placeholderText}>
Your todo list is empty. Add some tasks!
</Text>
) : (
todos.map((todo, index) => (
<View key={index} style={styles.todoItem}>
<Text style={styles.todoText}>
{todo}
</Text>
<TouchableOpacity
onPress={() => removeTodo(index)}
style={styles.removeTodoButton}
>
<Text
style={styles.removeTodoButtonText}
>
X
</Text>
</TouchableOpacity>
</View>
))
)}
</View>
</ScrollView>
</KeyboardAvoidingView>
</SafeAreaView>
</View>
);
} }