import 'dart:async'; import 'package:flutter/material.dart'; import 'package:traccar_client/bridge/location_bridge.dart'; import 'package:traccar_client/preferences.dart'; import 'package:traccar_client/settings_screen.dart'; import 'package:traccar_client/status_screen.dart'; class MainScreen extends StatefulWidget { const MainScreen({super.key}); @override State createState() => _MainScreenState(); } class _MainScreenState extends State { StreamSubscription>? _locationSubscription; bool _isTracking = false; String _lastLat = '--'; String _lastLon = '--'; String _lastSpeed = '--'; String _lastTime = '--'; @override void initState() { super.initState(); _initLocationStream(); } @override void dispose() { _locationSubscription?.cancel(); super.dispose(); } Future _initLocationStream() async { final status = await LocationBridge.getStatus(); if (mounted) { setState(() { _isTracking = status?['isTracking'] == true; final lat = status?['lastLatitude']; final lon = status?['lastLongitude']; if (lat != null && lat != 0.0) { _lastLat = lat.toStringAsFixed(4); } if (lon != null && lon != 0.0) { _lastLon = lon.toStringAsFixed(4); } final speed = status?['lastSpeed']; if (speed != null) { _lastSpeed = '${(speed * 3.6).toStringAsFixed(0)} km/h'; } final timestamp = status?['lastTimestamp']; if (timestamp != null) { _lastTime = _formatTime( DateTime.fromMillisecondsSinceEpoch(timestamp), ); } }); } _locationSubscription = LocationBridge.locationUpdates.listen((location) { if (mounted) { setState(() { _lastLat = location['latitude']?.toStringAsFixed(4) ?? '--'; _lastLon = location['longitude']?.toStringAsFixed(4) ?? '--'; _lastSpeed = location['speed'] != null ? '${(location['speed'] * 3.6).toStringAsFixed(0)} km/h' : '--'; _lastTime = location['timestamp'] != null ? _formatTime( DateTime.fromMillisecondsSinceEpoch(location['timestamp']), ) : '--'; }); } }); } String _formatTime(DateTime dt) { return '${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}'; } Future _toggleTracking() async { final previousState = _isTracking; final newState = !_isTracking; setState(() { _isTracking = newState; }); bool success; if (newState) { success = await LocationBridge.startTracking(config: { 'serverUrl': Preferences.serverUrl, 'deviceId': Preferences.deviceId, 'password': Preferences.password, 'accuracy': Preferences.accuracy, 'distanceFilter': Preferences.distanceFilter, 'interval': Preferences.interval, 'heartbeat': Preferences.heartbeat, 'offlineBuffer': Preferences.offlineBuffer, 'stopDetection': Preferences.stopDetection, }); } else { success = await LocationBridge.stopTracking(); } if (!success && mounted) { setState(() { _isTracking = previousState; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(previousState ? 'Failed to stop tracking' : 'Failed to start tracking'), ), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Traccar Client'), centerTitle: true), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildStatusCard(), const SizedBox(height: 24), _buildTrackingToggle(), const Spacer(), _buildActionButtons(), ], ), ), ); } Widget _buildStatusCard() { return Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Last Location', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 16), _buildInfoRow('Lat', _lastLat), _buildInfoRow('Lon', _lastLon), _buildInfoRow('Speed', _lastSpeed), _buildInfoRow('Time', _lastTime), ], ), ), ); } Widget _buildInfoRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(label), Text(value, style: const TextStyle(fontWeight: FontWeight.bold)), ], ), ); } Widget _buildTrackingToggle() { return SwitchListTile( title: Text(_isTracking ? 'Tracking: ON' : 'Tracking: OFF'), subtitle: Text( _isTracking ? 'Location updates active' : 'Tap to start tracking', ), value: _isTracking, onChanged: (_) => _toggleTracking(), activeTrackColor: Colors.green, ); } Widget _buildActionButtons() { return Column( children: [ if (_isTracking) Padding( padding: const EdgeInsets.only(bottom: 16), child: SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: () async { final success = await LocationBridge.reportLocation(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( success ? 'Location sent to server' : 'Failed - check logs', ), duration: Duration(seconds: 2), ), ); } }, icon: const Icon(Icons.send), label: const Text('Send Location'), ), ), ), Row( children: [ Expanded( child: ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (_) => const SettingsScreen()), ); }, icon: const Icon(Icons.settings), label: const Text('Settings'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton.icon( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (_) => const StatusScreen()), ); }, icon: const Icon(Icons.history), label: const Text('Status/Logs'), ), ), ], ), ], ); } }