let AI comment everything because well... yeah...
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
// * Widget for GPS tracking during wildlife monitoring excursions
|
||||
// * Features:
|
||||
// * - Real-time location tracking
|
||||
// * - Track visualization on map
|
||||
// * - Distance calculation
|
||||
// * - Location accuracy monitoring
|
||||
// * - Track recording controls (start/pause/stop)
|
||||
// * - Track data persistence
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fforte/l10n/app_localizations.dart';
|
||||
@@ -11,27 +20,40 @@ import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
/// Widget for managing GPS tracking functionality
|
||||
/// Provides map visualization and tracking controls
|
||||
class Tracking extends StatefulWidget {
|
||||
/// Initial position for the tracking session
|
||||
final Position startPosition;
|
||||
/// Controller for storing the tracked path
|
||||
final TextEditingController weg;
|
||||
|
||||
const Tracking({super.key, required this.startPosition, required this.weg});
|
||||
|
||||
@override
|
||||
State<Tracking> createState() => _TrackingState();
|
||||
}
|
||||
|
||||
/// State class for the tracking widget
|
||||
class _TrackingState extends State<Tracking> {
|
||||
/// Service for managing tracking functionality
|
||||
final TrackingService _trackingService = TrackingService();
|
||||
/// Current GPS position
|
||||
Position? currentPosition;
|
||||
/// Controller for the map widget
|
||||
MapController mapController = MapController();
|
||||
/// Subscription for position updates
|
||||
StreamSubscription? _positionSubscription;
|
||||
/// Subscription for tracking statistics updates
|
||||
StreamSubscription? _statsSubscription;
|
||||
/// Current tracking statistics
|
||||
TrackingStats? _currentStats;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Load existing track if available
|
||||
if (widget.weg.text.isNotEmpty) {
|
||||
for (var element in widget.weg.text.split(";")) {
|
||||
List<String> posSplit = element.split(",");
|
||||
@@ -50,24 +72,27 @@ class _TrackingState extends State<Tracking> {
|
||||
|
||||
currentPosition = widget.startPosition;
|
||||
|
||||
// Initialisiere die Statistiken sofort
|
||||
// Initialize tracking statistics
|
||||
setState(() {
|
||||
_currentStats = _trackingService.currentStats;
|
||||
});
|
||||
_trackingService.requestStatsUpdate();
|
||||
|
||||
// Subscribe to position updates
|
||||
_positionSubscription = _trackingService.positionStream$.listen((position) {
|
||||
setState(() {
|
||||
currentPosition = position;
|
||||
});
|
||||
});
|
||||
|
||||
// Subscribe to statistics updates
|
||||
_statsSubscription = _trackingService.statsStream$.listen((stats) {
|
||||
setState(() {
|
||||
_currentStats = stats;
|
||||
});
|
||||
});
|
||||
|
||||
// Check location permissions
|
||||
GeolocatorService.alwaysPositionEnabled().then((value) {
|
||||
if (!value && mounted) {
|
||||
Navigator.of(context).pop();
|
||||
@@ -84,6 +109,9 @@ class _TrackingState extends State<Tracking> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Format distance for display
|
||||
/// @param meters Distance in meters
|
||||
/// @return Formatted distance string with appropriate unit
|
||||
String _formatDistance(double meters) {
|
||||
if (meters >= 1000) {
|
||||
return '${(meters / 1000).toStringAsFixed(2)} km';
|
||||
@@ -99,6 +127,7 @@ class _TrackingState extends State<Tracking> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(AppLocalizations.of(context)!.tracking),
|
||||
// Display tracking statistics if available
|
||||
if (_currentStats != null)
|
||||
DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.bodySmall!,
|
||||
@@ -125,6 +154,7 @@ class _TrackingState extends State<Tracking> {
|
||||
icon: Icon(Icons.arrow_back_rounded)
|
||||
),
|
||||
actions: [
|
||||
// Delete track button (only when not tracking)
|
||||
if (!_trackingService.isTracking)
|
||||
IconButton(
|
||||
onPressed: () async {
|
||||
@@ -140,6 +170,7 @@ class _TrackingState extends State<Tracking> {
|
||||
color: Theme.of(context).colorScheme.errorContainer,
|
||||
),
|
||||
),
|
||||
// Stop tracking button (only when tracking)
|
||||
if (_trackingService.isTracking)
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
@@ -149,6 +180,7 @@ class _TrackingState extends State<Tracking> {
|
||||
},
|
||||
child: Text(AppLocalizations.of(context)!.trackingStop),
|
||||
),
|
||||
// Start/Pause tracking button
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@@ -165,6 +197,7 @@ class _TrackingState extends State<Tracking> {
|
||||
),
|
||||
],
|
||||
),
|
||||
// Center on current location button
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
mapController.move(
|
||||
@@ -177,6 +210,7 @@ class _TrackingState extends State<Tracking> {
|
||||
},
|
||||
child: Icon(Icons.my_location),
|
||||
),
|
||||
// Map display
|
||||
body: FlutterMap(
|
||||
mapController: mapController,
|
||||
options: MapOptions(
|
||||
@@ -192,10 +226,12 @@ class _TrackingState extends State<Tracking> {
|
||||
initialZoom: 16.0,
|
||||
),
|
||||
children: [
|
||||
// Base map layer
|
||||
TileLayer(
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
userAgentPackageName: 'de.lupus.apps',
|
||||
),
|
||||
// Track path layer
|
||||
if (_trackingService.pathList.isNotEmpty)
|
||||
PolylineLayer(
|
||||
polylines: [
|
||||
@@ -206,6 +242,7 @@ class _TrackingState extends State<Tracking> {
|
||||
),
|
||||
],
|
||||
),
|
||||
// Current position accuracy circle
|
||||
if (currentPosition != null)
|
||||
CircleLayer(
|
||||
circles: [
|
||||
@@ -231,6 +268,7 @@ class _TrackingState extends State<Tracking> {
|
||||
),
|
||||
],
|
||||
),
|
||||
// Current location marker
|
||||
CurrentLocationLayer(),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user