import React, { useCallback, useState } from "react"; import { Alert, Keyboard, KeyboardAvoidingView, Platform, Pressable, ScrollView, Text, TextInput, TouchableWithoutFeedback, View, } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import { router } from "expo-router"; import { useConnection } from "../contexts/ConnectionContext"; import { useTheme } from "../contexts/ThemeContext"; import { StatusDot } from "../components/ui/StatusDot"; import { ServerConfig } from "../types"; import { sendWol, isValidMac } from "../services/wol"; import { wsClient } from "../services/websocket"; export default function SettingsScreen() { const { serverConfig, status, connect, disconnect, saveServerConfig } = useConnection(); const { colors } = useTheme(); const [host, setHost] = useState(serverConfig?.host ?? ""); const [localHost, setLocalHost] = useState(serverConfig?.localHost ?? ""); const [port, setPort] = useState( serverConfig?.port ? String(serverConfig.port) : "8765" ); const [macAddress, setMacAddress] = useState(serverConfig?.macAddress ?? ""); const [saved, setSaved] = useState(false); const [waking, setWaking] = useState(false); const handleSave = useCallback(async () => { const trimmedHost = host.trim(); const portNum = parseInt(port.trim(), 10); const trimmedLocal = localHost.trim(); if ((!trimmedHost && !trimmedLocal) || isNaN(portNum) || portNum < 1 || portNum > 65535) { return; } const trimmedMac = macAddress.trim(); const effectiveHost = trimmedHost || trimmedLocal; const config: ServerConfig = { host: effectiveHost, port: portNum, ...(trimmedLocal && trimmedHost ? { localHost: trimmedLocal } : {}), ...(trimmedMac ? { macAddress: trimmedMac } : {}), }; await saveServerConfig(config); setSaved(true); setTimeout(() => setSaved(false), 2000); }, [host, localHost, port, macAddress, saveServerConfig]); const handleConnect = useCallback(() => { if (status === "connected" || status === "connecting" || status === "reconnecting") { disconnect(); } else { connect(); } }, [status, connect, disconnect]); const handleWake = useCallback(async () => { const mac = macAddress.trim() || serverConfig?.macAddress; if (!mac || !isValidMac(mac)) { Alert.alert("Invalid MAC", "Enter a valid MAC address (e.g. 6a:8a:e7:b3:8e:5c)"); return; } setWaking(true); try { await sendWol(mac, host.trim() || serverConfig?.host); Alert.alert("WoL Sent", "Magic packet sent. The Mac should wake in a few seconds."); } catch (err) { Alert.alert("WoL Failed", err instanceof Error ? err.message : String(err)); } finally { setWaking(false); } }, [macAddress, host, serverConfig]); const isFormValid = (host.trim().length > 0 || localHost.trim().length > 0) && parseInt(port, 10) > 0; return ( {/* Header */} router.back()} hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }} style={{ width: 36, height: 36, alignItems: "center", justifyContent: "center", borderRadius: 18, backgroundColor: colors.bgTertiary, marginRight: 12, }} > {"\u2190"} Settings {/* Connection status card */} Connection Status {status === "connected" ? "Connected" : status === "connecting" ? "Connecting..." : status === "reconnecting" ? "Reconnecting..." : "Disconnected"} {serverConfig && ( {wsClient.currentUrl || `ws://${serverConfig.host}:${serverConfig.port}`} )} {/* Server config */} Server Configuration {/* Local Host (preferred when on same network) */} Local Address (optional) {/* Remote Host (fallback / external) */} Remote Address {/* Port */} Port {/* MAC Address for Wake-on-LAN */} MAC Address (Wake-on-LAN) {/* Save button */} {saved ? "Saved!" : "Save Configuration"} {/* Wake-on-LAN button */} {waking ? "Sending..." : "Wake Mac (WoL)"} {/* Connect/Disconnect button */} {status === "connected" ? "Disconnect" : status === "connecting" || status === "reconnecting" ? "Reconnecting..." : "Connect"} ); }