import 'package:flutter/material.dart'; import 'package:traccar_client/bridge/location_bridge.dart'; import 'package:traccar_client/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 int _accuracy; late int _distanceFilter; late int _interval; late int _heartbeat; late bool _offlineBuffer; late bool _stopDetection; @override void initState() { super.initState(); _serverUrlController = TextEditingController(text: Preferences.serverUrl); _deviceIdController = TextEditingController(text: Preferences.deviceId); _accuracy = Preferences.accuracy; _distanceFilter = Preferences.distanceFilter; _interval = Preferences.interval; _heartbeat = Preferences.heartbeat; _offlineBuffer = Preferences.offlineBuffer; _stopDetection = Preferences.stopDetection; } @override void dispose() { _serverUrlController.dispose(); _deviceIdController.dispose(); super.dispose(); } Future _saveSettings() async { 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(const SnackBar(content: Text('Settings saved'))); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Settings')), body: ListView( padding: const EdgeInsets.all(16), children: [ _buildSectionHeader('Server'), _buildTextField('Server URL', _serverUrlController), _buildTextField('Device ID', _deviceIdController), const SizedBox(height: 16), _buildSectionHeader('Location'), _buildAccuracyDropdown(), _buildNumberField('Distance Filter (m)', _distanceFilter, 0, 1000), _buildNumberField('Update Interval (s)', _interval, 30, 3600), _buildNumberField('Heartbeat (s)', _heartbeat, 60, 3600), const SizedBox(height: 16), _buildSectionHeader('Advanced'), SwitchListTile( title: const Text('Offline Buffering'), subtitle: const Text('Queue locations when offline'), value: _offlineBuffer, onChanged: (v) => setState(() => _offlineBuffer = v), ), SwitchListTile( title: const Text('Stop Detection'), subtitle: const Text('Auto-stop when stationary'), value: _stopDetection, onChanged: (v) => setState(() => _stopDetection = v), ), const SizedBox(height: 24), ElevatedButton( onPressed: _saveSettings, child: const Text('Save Settings'), ), ], ), ); } Widget _buildSectionHeader(String title) { return Padding( padding: const EdgeInsets.only(top: 16, bottom: 8), child: Text( title, style: Theme.of( context, ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold), ), ); } Widget _buildTextField( String label, TextEditingController controller, { bool obscure = false, }) { return TextField( controller: controller, decoration: InputDecoration(labelText: label), obscureText: obscure, ); } Widget _buildAccuracyDropdown() { return DropdownButtonFormField( // ignore: deprecated_member_use value: _accuracy, decoration: const InputDecoration(labelText: 'Accuracy'), items: const [ DropdownMenuItem(value: 0, child: Text('High')), DropdownMenuItem(value: 1, child: Text('High Accuracy')), DropdownMenuItem(value: 2, child: Text('Balanced')), DropdownMenuItem(value: 3, child: Text('Low')), ], onChanged: (v) => setState(() => _accuracy = v!), ); } Widget _buildNumberField(String label, int value, int min, int max) { return TextFormField( initialValue: value.toString(), decoration: InputDecoration(labelText: label), keyboardType: TextInputType.number, validator: (v) { final parsed = int.tryParse(v ?? ''); if (parsed == null || parsed < min || parsed > max) { return 'Must be between $min and $max'; } return null; }, onSaved: (v) { final parsed = int.tryParse(v ?? ''); if (parsed != null) { if (label.contains('Distance')) { _distanceFilter = parsed; } else if (label.contains('Interval')) { _interval = parsed; } else if (label.contains('Heartbeat')) { _heartbeat = parsed; } } }, ); } }