import AsyncStorage from "@react-native-async-storage/async-storage"; import { useRouter } from "expo-router"; import React, { useEffect, useState } from "react"; import { Alert, ImageBackground, KeyboardAvoidingView, Platform, ScrollView, Text, TextInput, TouchableOpacity, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { styles } from "./styles"; const motdBgImage = require("../assets/images/motd.png"); // Define a map for Minecraft color codes to React Native colors const MINECRAFT_COLORS: { [key: string]: string } = { "0": "#000000", // Black "1": "#0000AA", // Dark Blue "2": "#00AA00", // Dark Green "3": "#00AAAA", // Dark Aqua "4": "#AA0000", // Dark Red "5": "#AA00AA", // Dark Purple "6": "#FFAA00", // Gold "7": "#AAAAAA", // Gray "8": "#555555", // Dark Gray "9": "#5555FF", // Blue a: "#55FF55", // Green b: "#55FFFF", // Aqua c: "#FF5555", // Red d: "#FF55FF", // Light Purple e: "#FFFF55", // Yellow f: "#FFFFFF" // White }; export default function MotdCreator() { const router = useRouter(); const [motdText, setMotdText] = useState(""); const [savedMotds, setSavedMotds] = useState([]); const [previewMotdComponents, setPreviewMotdComponents] = useState< React.ReactNode[] >([]); // Define a unique key for AsyncStorage const STORAGE_KEY = "@minecraft_motd_list"; // Persistence Logic useEffect(() => { loadMotds(); }, []); useEffect(() => { saveMotds(); }, [savedMotds]); useEffect(() => { generateMotdPreview(); }, [motdText]); // Async function to load MOTDs from AsyncStorage const loadMotds = async () => { try { const jsonValue = await AsyncStorage.getItem(STORAGE_KEY); if (jsonValue != null) { const parsedMotds = JSON.parse(jsonValue); if (Array.isArray(parsedMotds)) { setSavedMotds(parsedMotds); } else { console.warn( "Loaded data is not an array, initializing empty MOTD list." ); setSavedMotds([]); } } } catch (e) { console.error("Failed to load MOTDs:", e); Alert.alert("Error", "Failed to load your MOTD list."); } }; // Async function to save MOTDs to AsyncStorage const saveMotds = async () => { try { const jsonValue = JSON.stringify(savedMotds); await AsyncStorage.setItem(STORAGE_KEY, jsonValue); } catch (e) { console.error("Failed to save MOTDs:", e); Alert.alert("Error", "Failed to save your MOTD list."); } }; // Function to apply Minecraft color codes const applyCode = (code: string) => { setMotdText((prevText) => prevText + "§" + code); }; // Function to generate a preview of the MOTD with styled Text components const generateMotdPreview = () => { const parts: React.ReactNode[] = []; let currentText = ""; let currentColor: string | undefined = undefined; let isBold = false; let isItalic = false; let isUnderlined = false; let isStrikethrough = false; let isObfuscated = false; const regex = /(§[0-9a-fk-or])|([^§]+)/g; let match; while ((match = regex.exec(motdText)) !== null) { const code = match[1]; const textContent = match[2]; if (currentText.length > 0) { const style: any = { color: currentColor || MINECRAFT_COLORS.f }; if (isBold) style.fontWeight = "bold"; if (isItalic) style.fontStyle = "italic"; if (isUnderlined) style.textDecorationLine = "underline"; if (isStrikethrough) style.textDecorationLine = style.textDecorationLine ? style.textDecorationLine + " line-through" : "line-through"; parts.push( {currentText} ); currentText = ""; // Reset current text } if (code) { const codeChar = code.charAt(1); // Apply color if (MINECRAFT_COLORS[codeChar]) { currentColor = MINECRAFT_COLORS[codeChar]; } // Apply formatting switch (codeChar) { case "l": // Bold isBold = true; break; case "m": // Strikethrough isStrikethrough = true; break; case "n": // Underline isUnderlined = true; break; case "o": // Italic isItalic = true; break; case "k": // Obfuscated isObfuscated = true; // Mark as obfuscated, but don't change text break; case "r": // Reset currentColor = undefined; isBold = false; isItalic = false; isUnderlined = false; isStrikethrough = false; isObfuscated = false; break; } } else if (textContent) { currentText += textContent; } } // Add any remaining text after the last code or if no codes were found if (currentText.length > 0) { const style: any = { color: currentColor || MINECRAFT_COLORS.f }; if (isBold) style.fontWeight = "bold"; if (isItalic) style.fontStyle = "italic"; if (isUnderlined) style.textDecorationLine = "underline"; if (isStrikethrough) style.textDecorationLine = style.textDecorationLine ? style.textDecorationLine + " line-through" : "line-through"; parts.push( {currentText} ); } setPreviewMotdComponents(parts); }; const saveMotd = () => { if (motdText.trim().length > 0) { setSavedMotds((prevMotds) => [...prevMotds, motdText.trim()]); setMotdText(""); // Clear input after saving } else { Alert.alert("Empty MOTD", "Please enter some text to save."); } }; const deleteMotd = (index: number) => { const motdToDelete = savedMotds[index]; Alert.alert( "Delete MOTD", `Are you sure you want to delete "${motdToDelete}"?`, [ { text: "Cancel", onPress: () => console.log("Delete Cancelled"), style: "cancel" }, { text: "Delete", onPress: () => { const updatedMotds = savedMotds.filter( (_, i) => i !== index ); setSavedMotds(updatedMotds); console.log("MOTD deleted:", motdToDelete); }, style: "destructive" } ], { cancelable: true } ); }; return ( {/* Custom Back Button */} router.back()} style={styles.backButton} > ← Go Back MOTD Creator {/* MOTD Input */} {/* Color Codes */} Color Codes: {Object.entries(MINECRAFT_COLORS).map( ([codeChar, colorHex]) => ( applyCode(codeChar)} > §{codeChar} ) )} {/* Formatting Codes */} Formatting Codes: {[ { code: "k", name: "Obfuscated" }, { code: "l", name: "Bold" }, { code: "m", name: "Strikethrough" }, { code: "n", name: "Underline" }, { code: "o", name: "Italic" }, { code: "r", name: "Reset" } ].map((format) => ( applyCode(format.code)} > §{format.code} {format.name} ))} {/* MOTD Preview */} MOTD Preview: {previewMotdComponents} {/* Save MOTD Button */} Save MOTD {/* Saved MOTDs */} Saved MOTDs: {savedMotds.length === 0 ? ( No MOTDs saved yet. ) : ( {savedMotds.map((motd, index) => ( {motd} deleteMotd(index)} style={styles.deleteButton} > Delete ))} )} ); }