tracpulse/lib/settings_screen.dart
2026-04-30 15:39:19 +07:00

184 lines
5.7 KiB
Dart

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<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
late TextEditingController _serverUrlController;
late TextEditingController _deviceIdController;
late TextEditingController _distanceFilterController;
late TextEditingController _intervalController;
late TextEditingController _heartbeatController;
late int _accuracy;
late bool _offlineBuffer;
late bool _stopDetection;
@override
void initState() {
super.initState();
_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<void> _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(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)',
_distanceFilterController,
0,
1000,
),
_buildNumberField(
'Update Interval (s)',
_intervalController,
30,
3600,
),
_buildNumberField('Heartbeat (s)', _heartbeatController, 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<int>(
// 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,
TextEditingController controller,
int min,
int max,
) {
return TextField(
controller: controller,
decoration: InputDecoration(labelText: label),
keyboardType: TextInputType.number,
);
}
}