import 'dart:async'; import 'dart:math'; import 'package:fforte/l10n/app_localizations.dart'; import 'package:fforte/screens/addCam/services/geolocator_service.dart'; import 'package:fforte/screens/helper/add_entries_dialog_helper.dart'; import 'package:fforte/screens/helper/snack_bar_helper.dart'; import 'package:fforte/services/notification_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map_location_marker/flutter_map_location_marker.dart'; import 'package:geolocator/geolocator.dart'; import 'package:latlong2/latlong.dart'; class Tracking extends StatefulWidget { final Position startPosition; final TextEditingController weg; const Tracking({super.key, required this.startPosition, required this.weg}); @override State createState() => _TrackingState(); } class _TrackingState extends State { List pathList = []; StreamSubscription? positionStream; LocationMarkerPosition? locationMarkerPosition; bool positionStreamRunning = false; MapController mapController = MapController(); Random rand = Random(); @override void initState() { // debugging (i guess) // pathList.add( // LatLng(widget.startPosition.latitude, widget.startPosition.longitude), // ); if (widget.weg.text.isNotEmpty) { for (var element in widget.weg.text.split(";")) { List posSplit = element.split(","); try { posSplit[0] = posSplit[0].substring(0, 9); posSplit[1] = posSplit[1].substring(0, 9); } on RangeError { // ignore because the double is short enough then } pathList.add( LatLng(double.parse(posSplit.first), double.parse(posSplit[1])), ); } } locationMarkerPosition = LocationMarkerPosition( latitude: widget.startPosition.latitude, longitude: widget.startPosition.longitude, accuracy: widget.startPosition.accuracy, ); super.initState(); GeolocatorService.alwaysPositionEnabled().then((value) { if (!value && mounted) { Navigator.of(context).pop(); SnackBarHelper.showSnackBarMessage(context, "${AppLocalizations.of(context)!.locationForbidden} ${AppLocalizations.of(context)!.oder} ${AppLocalizations.of(context)!.locationDisabled}"); } }); } @override void dispose() { if (positionStream != null) positionStream!.cancel(); bool isFirst = true; if (pathList.isNotEmpty) { for (var pos in pathList) { if (!isFirst) { widget.weg.text += ";"; } else { isFirst = false; } widget.weg.text += "${pos.latitude},${pos.longitude}"; } } NotificationService().deleteNotification(); super.dispose(); } final LocationSettings streamLocationSettings = LocationSettings( accuracy: LocationAccuracy.high, distanceFilter: 10, ); void onTrackingStart() async { // notification handling for tracking in background notification await NotificationService().initNotification(); if (mounted) { NotificationService().showNotification( title: AppLocalizations.of(context)!.trackingRunningInBackground, ); } positionStream = Geolocator.getPositionStream( locationSettings: AndroidSettings( accuracy: LocationAccuracy.high, distanceFilter: 0, foregroundNotificationConfig: mounted ? ForegroundNotificationConfig( notificationTitle: AppLocalizations.of(context)!.trackingRunningInBackground, notificationText: "", ) : null, ), ).listen((Position? position) { if (position != null) { setState(() { pathList.add(LatLng(position.latitude, position.longitude)); // Random value for debugging // pathList.add(LatLng(rand.nextInt(5) + 40, position.longitude)); locationMarkerPosition = LocationMarkerPosition( latitude: position.latitude, longitude: position.longitude, accuracy: position.accuracy, ); }); } else { if (mounted) { SnackBarHelper.showSnackBarMessage( context, AppLocalizations.of(context)!.couldntDeterminePosition, ); } } }); positionStream!.onError((e) { NotificationService().deleteNotification(); NotificationService().showNotification(title: "ERROR: $e"); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(AppLocalizations.of(context)!.tracking), leading: IconButton(onPressed: () { Navigator.pop(context); }, icon: Icon(Icons.arrow_back_rounded)), actions: [ if (!positionStreamRunning) IconButton( onPressed: () async { bool delete = await AddEntriesDialogHelper.deleteCompleteRouteDialog( context, ); if (delete) { setState(() { pathList = []; }); } }, icon: Icon( Icons.delete, color: Theme.of(context).colorScheme.errorContainer, ), ), if (positionStreamRunning) IconButton( onPressed: () { setState(() { positionStreamRunning = false; positionStream!.cancel(); NotificationService().deleteNotification(); }); }, icon: Icon( Icons.stop_rounded, color: Theme.of(context).colorScheme.errorContainer, ), ), IconButton( onPressed: () { if (positionStreamRunning) { positionStreamRunning = false; positionStream?.pause(); } else { positionStreamRunning = true; onTrackingStart(); } setState(() {}); }, icon: positionStreamRunning ? Icon(Icons.pause) : Icon(Icons.play_arrow), ), ], ), floatingActionButton: FloatingActionButton( onPressed: () { mapController.move( LatLng( locationMarkerPosition!.latitude, locationMarkerPosition!.longitude, ), 16, ); }, child: Icon(Icons.my_location), ), body: FlutterMap( mapController: mapController, options: MapOptions( interactionOptions: const InteractionOptions( flags: InteractiveFlag.pinchZoom | InteractiveFlag.drag | InteractiveFlag.pinchMove, ), initialCenter: LatLng( widget.startPosition.latitude, widget.startPosition.longitude, ), initialZoom: 16.0, ), children: [ TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', userAgentPackageName: 'de.lupus.apps', ), if (pathList.isNotEmpty) PolylineLayer( polylines: [ Polyline(strokeWidth: 2.0, points: pathList, color: Colors.red), ], ), // CircleLayer( // circles: [ // CircleMarker( // color: Colors.blue, // point: pathList.isEmpty ? widget.startPosition : pathList.last, // radius: 5, // useRadiusInMeter: true, // ), // ], // ), CurrentLocationLayer(), ], ), ); } }