import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:url_launcher/url_launcher.dart'; import 'bridge/location_bridge.dart'; import 'preferences.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { late TextEditingController _serverUrlController; late TextEditingController _deviceIdController; late TextEditingController _distanceFilterController; late TextEditingController _intervalController; late TextEditingController _heartbeatController; late int _accuracy; late bool _offlineBuffer; late bool _stopDetection; int _tapCount = 0; DateTime? _lastTapTime; Future _handleAppBarTap() async { const tripleTapInterval = Duration(milliseconds: 500); final now = DateTime.now(); if (_lastTapTime != null && now.difference(_lastTapTime!) > tripleTapInterval) { _tapCount = 0; } _tapCount++; _lastTapTime = now; if (_tapCount == 3) { _tapCount = 0; final uri = Uri.parse('https://fiatcode.dev'); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } } } @override void initState() { super.initState(); SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( statusBarColor: Color(0xFF0d0d0d), statusBarIconBrightness: Brightness.light, ), ); _serverUrlController = TextEditingController(text: Preferences.serverUrl); _deviceIdController = TextEditingController(text: Preferences.deviceId); _distanceFilterController = TextEditingController( text: Preferences.distanceFilter.toString(), ); _intervalController = TextEditingController( text: Preferences.interval.toString(), ); _heartbeatController = TextEditingController( text: Preferences.heartbeat.toString(), ); _accuracy = Preferences.accuracy; _offlineBuffer = Preferences.offlineBuffer; _stopDetection = Preferences.stopDetection; } @override void dispose() { _serverUrlController.dispose(); _deviceIdController.dispose(); _distanceFilterController.dispose(); _intervalController.dispose(); _heartbeatController.dispose(); super.dispose(); } Future _saveSettings() async { final distanceFilter = int.tryParse(_distanceFilterController.text) ?? 75; final interval = int.tryParse(_intervalController.text) ?? 300; final heartbeat = int.tryParse(_heartbeatController.text) ?? 60; await Preferences.setServerUrl(_serverUrlController.text); await Preferences.setDeviceId(_deviceIdController.text); await Preferences.setAccuracy(_accuracy); await Preferences.setDistanceFilter(distanceFilter); await Preferences.setInterval(interval); await Preferences.setHeartbeat(heartbeat); await Preferences.setOfflineBuffer(_offlineBuffer); await Preferences.setStopDetection(_stopDetection); await LocationBridge.updateConfig({ 'serverUrl': _serverUrlController.text, 'deviceId': _deviceIdController.text, 'accuracy': _accuracy, 'distanceFilter': distanceFilter, 'interval': interval, 'heartbeat': heartbeat, 'offlineBuffer': _offlineBuffer, 'stopDetection': _stopDetection, }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: const [ Icon(Icons.check_circle, color: Color(0xFF00e676), size: 18), SizedBox(width: 10), Text( 'Settings saved', style: TextStyle(fontFamily: 'monospace', letterSpacing: 1), ), ], ), backgroundColor: const Color(0xFF1a1a1a), behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), ), ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0d0d0d), appBar: AppBar( backgroundColor: const Color(0xFF161616), elevation: 0, leading: IconButton( icon: const Icon( Icons.arrow_back, color: Color(0xFF9e9e9e), size: 20, ), onPressed: () => Navigator.pop(context), ), title: GestureDetector( onTap: _handleAppBarTap, child: const Text( 'SETTINGS', style: TextStyle( fontFamily: 'monospace', fontSize: 14, fontWeight: FontWeight.w700, letterSpacing: 2, color: Color(0xFFe0e0e0), ), ), ), bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Container(height: 1, color: const Color(0xFF2a2a2a)), ), ), body: ListView( padding: const EdgeInsets.all(20), children: [ _buildSectionHeader('SERVER'), const SizedBox(height: 12), _buildTextField('Server URL', _serverUrlController), const SizedBox(height: 12), _buildTextField('Device ID', _deviceIdController), const SizedBox(height: 24), _buildSectionHeader('LOCATION'), const SizedBox(height: 12), _buildAccuracyDropdown(), const SizedBox(height: 12), _buildNumberField('Distance Filter (m)', _distanceFilterController), const SizedBox(height: 12), _buildNumberField('Update Interval (s)', _intervalController), const SizedBox(height: 12), _buildNumberField('Heartbeat (s)', _heartbeatController), const SizedBox(height: 24), _buildSectionHeader('ADVANCED'), const SizedBox(height: 8), _buildSwitch( 'Offline Buffering', 'Queue locations when network unavailable', _offlineBuffer, (v) => setState(() => _offlineBuffer = v), ), const SizedBox(height: 4), _buildSwitch( 'Stop Detection', 'Auto-stop tracking when stationary', _stopDetection, (v) => setState(() => _stopDetection = v), ), const SizedBox(height: 32), _buildSaveButton(), const SizedBox(height: 20), ], ), ); } Widget _buildSectionHeader(String title) { return Row( children: [ Container( width: 3, height: 14, decoration: BoxDecoration( color: const Color(0xFF00bcd4), borderRadius: BorderRadius.circular(1), ), ), const SizedBox(width: 8), Text( title, style: const TextStyle( fontFamily: 'monospace', fontSize: 11, fontWeight: FontWeight.w700, letterSpacing: 2, color: Color(0xFF00bcd4), ), ), ], ); } Widget _buildTextField(String label, TextEditingController controller) { return Container( decoration: BoxDecoration( color: const Color(0xFF161616), borderRadius: BorderRadius.circular(4), border: Border.all(color: const Color(0xFF2a2a2a), width: 1), ), child: TextField( controller: controller, style: const TextStyle( fontFamily: 'monospace', fontSize: 13, color: Color(0xFFe0e0e0), ), decoration: InputDecoration( labelText: label, labelStyle: const TextStyle( fontFamily: 'monospace', fontSize: 11, letterSpacing: 1, color: Color(0xFF616161), ), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric( horizontal: 14, vertical: 14, ), ), ), ); } Widget _buildAccuracyDropdown() { return Container( padding: const EdgeInsets.symmetric(horizontal: 14), decoration: BoxDecoration( color: const Color(0xFF161616), borderRadius: BorderRadius.circular(4), border: Border.all(color: const Color(0xFF2a2a2a), width: 1), ), child: DropdownButtonFormField( initialValue: _accuracy, dropdownColor: const Color(0xFF1a1a1a), style: const TextStyle( fontFamily: 'monospace', fontSize: 13, color: Color(0xFFe0e0e0), ), decoration: const InputDecoration( labelText: 'Accuracy', labelStyle: TextStyle( fontFamily: 'monospace', fontSize: 11, letterSpacing: 1, color: Color(0xFF616161), ), border: InputBorder.none, ), items: const [ DropdownMenuItem( value: 0, child: Text('High', style: TextStyle(fontFamily: 'monospace')), ), DropdownMenuItem( value: 1, child: Text( 'High Accuracy', style: TextStyle(fontFamily: 'monospace'), ), ), DropdownMenuItem( value: 2, child: Text('Balanced', style: TextStyle(fontFamily: 'monospace')), ), DropdownMenuItem( value: 3, child: Text('Low', style: TextStyle(fontFamily: 'monospace')), ), ], onChanged: (v) => setState(() => _accuracy = v!), ), ); } Widget _buildNumberField(String label, TextEditingController controller) { return Container( decoration: BoxDecoration( color: const Color(0xFF161616), borderRadius: BorderRadius.circular(4), border: Border.all(color: const Color(0xFF2a2a2a), width: 1), ), child: TextField( controller: controller, keyboardType: TextInputType.number, style: const TextStyle( fontFamily: 'monospace', fontSize: 13, color: Color(0xFFe0e0e0), ), decoration: InputDecoration( labelText: label, labelStyle: const TextStyle( fontFamily: 'monospace', fontSize: 11, letterSpacing: 1, color: Color(0xFF616161), ), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric( horizontal: 14, vertical: 14, ), ), ), ); } Widget _buildSwitch( String title, String subtitle, bool value, ValueChanged onChanged, ) { return Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: const Color(0xFF161616), borderRadius: BorderRadius.circular(4), border: Border.all(color: const Color(0xFF2a2a2a), width: 1), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontFamily: 'monospace', fontSize: 13, fontWeight: FontWeight.w600, color: Color(0xFFe0e0e0), ), ), const SizedBox(height: 2), Text( subtitle, style: const TextStyle( fontFamily: 'monospace', fontSize: 10, color: Color(0xFF616161), ), ), ], ), ), Switch( value: value, onChanged: onChanged, activeThumbColor: const Color(0xFF00e676), activeTrackColor: const Color(0xFF00e676).withValues(alpha: 0.3), ), ], ), ); } Widget _buildSaveButton() { return Material( color: const Color(0xFF00bcd4).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(4), child: InkWell( onTap: _saveSettings, borderRadius: BorderRadius.circular(4), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), border: Border.all( color: const Color(0xFF00bcd4).withValues(alpha: 0.4), width: 1, ), ), child: const Center( child: Text( 'SAVE SETTINGS', style: TextStyle( fontFamily: 'monospace', fontSize: 13, fontWeight: FontWeight.w700, letterSpacing: 2, color: Color(0xFF00bcd4), ), ), ), ), ), ); } }