import { useState, useEffect } from 'react'; import { View, Text, ScrollView, TextInput, Switch, Pressable, Alert, ActivityIndicator } from 'react-native'; import { router } from 'expo-router'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSettings } from '@/hooks/use-settings'; export default function SettingsScreen() { const { settings, isLoading, updateSettings, resetSettings } = useSettings(); const insets = useSafeAreaInsets(); const [serverUrl, setServerUrl] = useState(settings.serverUrl); const [useSpeaker, setUseSpeaker] = useState(settings.useSpeaker); const [keepScreenOn, setKeepScreenOn] = useState(settings.keepScreenOn); const [theme, setTheme] = useState<'dark' | 'light' | 'auto'>(settings.theme); const [hasChanges, setHasChanges] = useState(false); const [isTesting, setIsTesting] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); // Update local state when settings load useEffect(() => { setServerUrl(settings.serverUrl); setUseSpeaker(settings.useSpeaker); setKeepScreenOn(settings.keepScreenOn); setTheme(settings.theme); }, [settings]); // Track changes useEffect(() => { const changed = serverUrl !== settings.serverUrl || useSpeaker !== settings.useSpeaker || keepScreenOn !== settings.keepScreenOn || theme !== settings.theme; setHasChanges(changed); }, [serverUrl, useSpeaker, keepScreenOn, theme, settings]); function validateServerUrl(url: string): boolean { try { const urlObj = new URL(url); return urlObj.protocol === 'ws:' || urlObj.protocol === 'wss:'; } catch { return false; } } async function handleSave() { // Validate server URL if (!validateServerUrl(serverUrl)) { Alert.alert( 'Invalid URL', 'Server URL must be a valid WebSocket URL (ws:// or wss://)', [{ text: 'OK' }] ); return; } try { await updateSettings({ serverUrl, useSpeaker, keepScreenOn, theme, }); Alert.alert( 'Settings Saved', 'Your settings have been saved successfully.', [ { text: 'OK', onPress: () => router.back(), }, ] ); } catch (error) { Alert.alert( 'Error', 'Failed to save settings. Please try again.', [{ text: 'OK' }] ); } } async function handleReset() { Alert.alert( 'Reset Settings', 'Are you sure you want to reset all settings to defaults?', [ { text: 'Cancel', style: 'cancel' }, { text: 'Reset', style: 'destructive', onPress: async () => { try { await resetSettings(); Alert.alert('Settings Reset', 'All settings have been reset to defaults.'); } catch (error) { Alert.alert('Error', 'Failed to reset settings. Please try again.'); } }, }, ] ); } function handleCancel() { if (hasChanges) { Alert.alert( 'Discard Changes', 'You have unsaved changes. Are you sure you want to go back?', [ { text: 'Stay', style: 'cancel' }, { text: 'Discard', style: 'destructive', onPress: () => router.back(), }, ] ); } else { router.back(); } } async function handleTestConnection() { if (!validateServerUrl(serverUrl)) { Alert.alert( 'Invalid URL', 'Server URL must be a valid WebSocket URL (ws:// or wss://)', [{ text: 'OK' }] ); return; } setIsTesting(true); setTestResult(null); try { const ws = new WebSocket(serverUrl); const timeout = setTimeout(() => { ws.close(); setTestResult({ success: false, message: 'Connection timeout - server did not respond', }); setIsTesting(false); }, 5000); ws.onopen = () => { clearTimeout(timeout); ws.close(); setTestResult({ success: true, message: 'Connection successful', }); setIsTesting(false); }; ws.onerror = () => { clearTimeout(timeout); setTestResult({ success: false, message: 'Connection failed - check URL and network', }); setIsTesting(false); }; } catch (error) { setTestResult({ success: false, message: 'Failed to create connection', }); setIsTesting(false); } } if (isLoading) { return ( Loading settings... ); } return ( {/* Header */} Settings Cancel {/* Server Configuration */} Server Configuration WebSocket URL { setServerUrl(text); setTestResult(null); }} autoCapitalize="none" autoCorrect={false} keyboardType="url" /> Must be a valid WebSocket URL (ws:// or wss://) {/* Test Connection Button */} {isTesting ? ( <> Testing... ) : ( Test Connection )} {/* Test Result */} {testResult && ( {testResult.message} )} {/* Audio Settings */} Audio Use Speaker Play audio through speaker instead of earpiece Keep Screen On Prevent screen from sleeping during voice sessions {/* Theme Settings */} Theme Theme selection (coming soon) {(['dark', 'light', 'auto'] as const).map((themeOption) => ( {theme === themeOption && ( )} {themeOption} ))} {/* Action Buttons */} Save Settings Reset to Defaults {/* App Info */} Voice Assistant Mobile Version 1.0.0 ); }