Files
fforte/lib/screens/excursion/widgets/tracking.dart
2025-06-03 22:31:55 +02:00

260 lines
7.9 KiB
Dart

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<Tracking> createState() => _TrackingState();
}
class _TrackingState extends State<Tracking> {
List<LatLng> pathList = [];
StreamSubscription<Position>? 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<String> 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)
TextButton(
onPressed: () {
setState(() {
positionStreamRunning = false;
positionStream!.cancel();
NotificationService().deleteNotification();
});
},
child: Text(AppLocalizations.of(context)!.trackingStop),
),
TextButton(
onPressed: () {
if (positionStreamRunning) {
positionStreamRunning = false;
positionStream?.pause();
} else {
positionStreamRunning = true;
onTrackingStart();
}
setState(() {});
},
child:
positionStreamRunning
? Text(AppLocalizations.of(context)!.trackingPause)
: Text(AppLocalizations.of(context)!.trackingStart)
),
],
),
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(),
],
),
);
}
}