added tracking function. Not testet on a walk yet. Also the notifiation doesnt work

time

forgot to save tracking file
This commit is contained in:
Nico
2025-05-15 22:01:36 +02:00
parent 0e621ba1ef
commit 895bcf1d5c
10 changed files with 301 additions and 6 deletions

View File

@@ -1,5 +1,8 @@
import 'package:animations/animations.dart';
import 'package:fforte/enums/databases.dart';
import 'package:fforte/screens/addCam/exceptions/location_disabled_exception.dart';
import 'package:fforte/screens/addCam/exceptions/location_forbidden_exception.dart';
import 'package:fforte/screens/addCam/services/geolocator_service.dart';
import 'package:fforte/screens/excursion/widgets/anzahlen.dart';
import 'package:fforte/screens/excursion/widgets/bima_nutzer.dart';
import 'package:fforte/screens/excursion/widgets/hinweise.dart';
@@ -7,13 +10,17 @@ import 'package:fforte/screens/excursion/widgets/hund_u_leine.dart';
import 'package:fforte/screens/excursion/widgets/letzter_niederschlag.dart';
import 'package:fforte/screens/excursion/widgets/spur_gefunden.dart';
import 'package:fforte/screens/excursion/widgets/strecke_u_spurbedingungen.dart';
import 'package:fforte/screens/excursion/widgets/tracking.dart';
import 'package:fforte/screens/helper/add_entries_dialog_helper.dart';
import 'package:fforte/screens/helper/snack_bar_helper.dart';
import 'package:fforte/screens/sharedMethods/check_required.dart';
import 'package:fforte/screens/sharedMethods/save_template.dart';
import 'package:fforte/screens/sharedWidgets/datum.dart';
import 'package:fforte/screens/sharedWidgets/var_text_field.dart';
import 'package:fforte/l10n/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
class ExcursionMain extends StatefulWidget {
final bool isTemplate;
@@ -34,6 +41,18 @@ class ExcursionMain extends StatefulWidget {
class _ExcursionMainState extends State<ExcursionMain> {
int currentStep = 0;
late bool isTemplate;
Position currentPosition = Position(
longitude: 10.0,
latitude: 51.0,
timestamp: DateTime.now(),
accuracy: 0.0,
altitude: 0.0,
heading: 0.0,
speed: 0.0,
speedAccuracy: 0.0,
altitudeAccuracy: 0.0,
headingAccuracy: 0.0,
);
// all TextEditingController because its easier
Map<String, Map<String, dynamic>> rmap = {
@@ -55,6 +74,7 @@ class _ExcursionMainState extends State<ExcursionMain> {
"BimaAGV": {"controller": TextEditingController(), "required": false},
// Step 2
"Weg": {"controller": TextEditingController(), "required": false},
"Wetter": {"controller": TextEditingController(), "required": false},
"Temperat": {"controller": TextEditingController(), "required": false},
"RegenVor": {"controller": TextEditingController(), "required": false},
@@ -100,6 +120,27 @@ class _ExcursionMainState extends State<ExcursionMain> {
@override
void initState() {
GeolocatorService.deteterminePosition()
.then((result) => currentPosition = result)
.catchError((error) {
if (error is LocationDisabledException) {
if (mounted) {
SnackBarHelper.showSnackBarMessage(
context,
AppLocalizations.of(context)!.locationDisabled,
);
}
} else if (error is LocationForbiddenException) {
if (mounted) {
SnackBarHelper.showSnackBarMessage(
context,
AppLocalizations.of(context)!.locationForbidden,
);
}
}
return currentPosition;
});
if (widget.existingData?.isNotEmpty ?? false) {
for (var key in widget.existingData!.keys) {
rmap[key]!["controller"]!.text =
@@ -130,7 +171,6 @@ class _ExcursionMainState extends State<ExcursionMain> {
return puff;
}
@override
Widget build(BuildContext context) {
List<Step> getSteps() => [
@@ -253,6 +293,27 @@ class _ExcursionMainState extends State<ExcursionMain> {
title: Text(AppLocalizations.of(context)!.umstaendeUndAktionen),
content: Column(
children: [
// ---------- Tracking
ElevatedButton(
onPressed:
() => Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Tracking(
weg: rmap["Weg"]!["controller"]!,
startPosition: LatLng(
currentPosition.latitude,
currentPosition.longitude,
),
);
},
),
),
child: Text(AppLocalizations.of(context)!.tracking),
),
const SizedBox(height: 10),
// ---------- Weather
VarTextField(
textController: rmap["Wetter"]!["controller"]!,
@@ -390,7 +451,6 @@ class _ExcursionMainState extends State<ExcursionMain> {
currentStep += 1;
});
} else {
if (widget.isSent) {
Navigator.pushNamedAndRemoveUntil(
context,

View File

@@ -0,0 +1,186 @@
import 'dart:async';
import 'dart:math';
import 'package:fforte/l10n/app_localizations.dart';
import 'package:fforte/screens/helper/snack_bar_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
class Tracking extends StatefulWidget {
final LatLng 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;
bool positionStreamRunning = false;
Random rand = Random();
@override
void initState() {
// TODO 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])),
);
}
}
super.initState();
}
@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}";
}
}
super.dispose();
}
final LocationSettings streamLocationSettings = LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10,
);
void onTrackingStart() async {
// // notification handling for tracking in background notification
// PermissionStatus permissionStatus =
// await NotificationPermissions.getNotificationPermissionStatus();
//
// if (permissionStatus != PermissionStatus.granted) {
// await NotificationPermissions.requestNotificationPermissions();
// }
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) {
// pathList.add(LatLng(position.latitude, position.longitude));
setState(() {
pathList.add(LatLng(rand.nextInt(5) + 40, position.longitude));
});
} else {
if (mounted) {
SnackBarHelper.showSnackBarMessage(
context,
AppLocalizations.of(context)!.couldntDeterminePosition,
);
}
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.tracking),
// leading: IconButton(onPressed: () {}, icon: Icon(Icons.arrow_back_rounded)),
actions: [
if (positionStreamRunning)
IconButton(
onPressed: () {
setState(() {
positionStreamRunning = false;
positionStream!.cancel();
});
},
icon: Icon(Icons.stop_rounded),
),
IconButton(
onPressed: () {
if (positionStreamRunning) {
positionStreamRunning = false;
positionStream?.pause();
} else {
positionStreamRunning = true;
onTrackingStart();
}
setState(() {});
},
icon:
positionStreamRunning
? Icon(Icons.pause)
: Icon(Icons.play_arrow),
),
],
),
body: FlutterMap(
mapController: MapController(),
options: MapOptions(
interactionOptions: const InteractionOptions(
flags:
InteractiveFlag.pinchZoom |
InteractiveFlag.drag |
InteractiveFlag.pinchMove,
),
initialCenter: widget.startPosition,
initialZoom: 16.0,
),
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.example.app',
),
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,
),
],
),
],
),
);
}
}