import { useState, useEffect } from 'react'; import { View, Text, TextInput, Switch, Pressable, ScrollView, Alert, ActivityIndicator } from 'react-native'; import { router } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { AppSettings, getSettings, saveSettings, resetSettings, validateServerUrl, } from '../lib/settings-storage'; export default function SettingsScreen() { const [settings, setSettings] = useState(null); const [serverUrl, setServerUrl] = useState(''); const [useSpeaker, setUseSpeaker] = useState(false); const [keepScreenOn, setKeepScreenOn] = useState(true); const [theme, setTheme] = useState<'dark' | 'light' | 'auto'>('dark'); const [urlError, setUrlError] = useState(null); const [isSaving, setIsSaving] = useState(false); const [isTesting, setIsTesting] = useState(false); const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); useEffect(() => { loadSettings(); }, []); async function loadSettings() { const loaded = await getSettings(); setSettings(loaded); setServerUrl(loaded.serverUrl); setUseSpeaker(loaded.useSpeaker); setKeepScreenOn(loaded.keepScreenOn); setTheme(loaded.theme); } function validateUrl(url: string) { const validation = validateServerUrl(url); setUrlError(validation.valid ? null : validation.error || null); return validation.valid; } async function handleSaveSettings() { if (!validateUrl(serverUrl)) { return; } setIsSaving(true); try { const newSettings: AppSettings = { serverUrl, useSpeaker, keepScreenOn, theme, }; await saveSettings(newSettings); setSettings(newSettings); Alert.alert('Success', 'Settings saved successfully'); } catch (error) { Alert.alert('Error', 'Failed to save settings'); console.error('Save settings error:', error); } finally { setIsSaving(false); } } async function handleResetSettings() { 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 () => { const defaults = await resetSettings(); setServerUrl(defaults.serverUrl); setUseSpeaker(defaults.useSpeaker); setKeepScreenOn(defaults.keepScreenOn); setTheme(defaults.theme); setSettings(defaults); Alert.alert('Success', 'Settings reset to defaults'); }, }, ] ); } async function handleTestConnection() { if (!validateUrl(serverUrl)) { 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 (!settings) { return ( ); } return ( {/* Header */} Settings router.back()} className="px-4 py-2 rounded-lg bg-zinc-800 active:bg-zinc-700" > Done {/* Server Configuration */} Server Configuration WebSocket URL { setServerUrl(text); validateUrl(text); setTestResult(null); }} placeholder="wss://your-server.com/ws" placeholderTextColor="#71717a" autoCapitalize="none" autoCorrect={false} keyboardType="url" /> {urlError && ( {urlError} )} {testResult && ( {testResult.message} )} {isTesting ? ( <> Testing... ) : ( Test Connection )} {/* Audio Settings */} Audio Settings Use Speaker Use phone speaker instead of earpiece Keep Screen On Prevent screen from sleeping during use {/* App Information */} App Information App Version 1.0.0 Audio Format PCM 16kHz Mono Current Server {settings.serverUrl.replace('wss://', '').replace('ws://', '')} {/* Actions */} {isSaving ? ( ) : ( Save Settings )} Reset to Defaults {/* Bottom spacing */} ); }