besprechung
This commit is contained in:
@@ -8,16 +8,23 @@ import 'package:geolocator/geolocator.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Service, with the Singleton design pattern, that runs the geolocator service that tracks the position of the device.
|
||||
/// This is needed for excursions
|
||||
///
|
||||
/// Start the tracking service via [startTracking]
|
||||
/// Manage the position stream via [pauseTracking], [stopTracking] and [resumeTracking]
|
||||
class TrackingService {
|
||||
// Singleton stuff
|
||||
static TrackingService? _instance;
|
||||
|
||||
|
||||
factory TrackingService() {
|
||||
_instance ??= TrackingService._internal();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
|
||||
TrackingService._internal();
|
||||
|
||||
/// Resets all values, making it possible to start tracking again.
|
||||
static void resetInstance() {
|
||||
if (_instance != null) {
|
||||
_instance!.dispose();
|
||||
@@ -25,48 +32,55 @@ class TrackingService {
|
||||
}
|
||||
}
|
||||
|
||||
// Variables
|
||||
// - Stores the tracked coordinates
|
||||
List<LatLng> pathList = [];
|
||||
// - Stores all gotten accuracies
|
||||
List<double> accuracyList = [];
|
||||
// - Stores timer so that is responsible vor the periodically tracking
|
||||
Timer? _positionTimer;
|
||||
bool isTracking = false;
|
||||
// - Some more Singleton stuff (i guess. Vibecoded it because of lack of time)
|
||||
BuildContext? _lastContext;
|
||||
final _positionController = StreamController<Position>.broadcast();
|
||||
final _statsController = StreamController<TrackingStats>.broadcast();
|
||||
|
||||
// - Getter
|
||||
Stream<Position> get positionStream$ => _positionController.stream;
|
||||
Stream<TrackingStats> get statsStream$ => _statsController.stream;
|
||||
|
||||
double? currentAccuracy;
|
||||
|
||||
// - Stores the last measured accuracy so that it can be displayed in the excursions view double? currentAccuracy;
|
||||
|
||||
// Name says it all
|
||||
double _calculateMedianAccuracy(List<double> accuracies) {
|
||||
// if one or less values for accuracy are available return that accuracy or 0
|
||||
if (accuracies.isEmpty) return 0;
|
||||
if (accuracies.length == 1) return accuracies.first;
|
||||
|
||||
// Kopiere die Liste, um die Originaldaten nicht zu verändern
|
||||
|
||||
// Copy the list so that the original data doesnt get modified
|
||||
var sorted = List<double>.from(accuracies)..sort();
|
||||
|
||||
|
||||
// Calculates median (not arithmetic mean!!). That is because often the firsed tracked accuracy is about 9000m
|
||||
if (sorted.length % 2 == 0) {
|
||||
// Bei gerader Anzahl: Durchschnitt der beiden mittleren Werte
|
||||
int midIndex = sorted.length ~/ 2;
|
||||
return (sorted[midIndex - 1] + sorted[midIndex]) / 2;
|
||||
} else {
|
||||
// Bei ungerader Anzahl: Der mittlere Wert
|
||||
return sorted[sorted.length ~/ 2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Starts tracking
|
||||
Future<void> startTracking(BuildContext context) async {
|
||||
if (isTracking) return;
|
||||
final LocationSettings locationSettings = LocationSettings(
|
||||
accuracy: LocationAccuracy.high
|
||||
);
|
||||
final LocationSettings locationSettings =
|
||||
LocationSettings(accuracy: LocationAccuracy.high);
|
||||
|
||||
_lastContext = context;
|
||||
await NotificationService().initNotification();
|
||||
if (context.mounted) {
|
||||
NotificationService().showNotification(
|
||||
title: AppLocalizations.of(context)!.trackingRunningInBackground,
|
||||
);
|
||||
title: AppLocalizations.of(context)!.trackingRunningInBackground,
|
||||
);
|
||||
}
|
||||
|
||||
// Get tracking interval from settings
|
||||
@@ -74,13 +88,12 @@ class TrackingService {
|
||||
final intervalSeconds = prefs.getInt('trackingInterval') ?? 60;
|
||||
|
||||
// Create a timer that triggers position updates
|
||||
_positionTimer = Timer.periodic(Duration(seconds: intervalSeconds), (_) async {
|
||||
_positionTimer =
|
||||
Timer.periodic(Duration(seconds: intervalSeconds), (_) async {
|
||||
try {
|
||||
|
||||
final Position position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: locationSettings
|
||||
);
|
||||
|
||||
locationSettings: locationSettings);
|
||||
|
||||
pathList.add(LatLng(position.latitude, position.longitude));
|
||||
accuracyList.add(position.accuracy);
|
||||
currentAccuracy = position.accuracy;
|
||||
@@ -95,9 +108,8 @@ class TrackingService {
|
||||
// Get initial position immediately
|
||||
try {
|
||||
final Position position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: locationSettings
|
||||
);
|
||||
|
||||
locationSettings: locationSettings);
|
||||
|
||||
pathList.add(LatLng(position.latitude, position.longitude));
|
||||
accuracyList.add(position.accuracy);
|
||||
currentAccuracy = position.accuracy;
|
||||
@@ -117,31 +129,28 @@ class TrackingService {
|
||||
void _updateStats() {
|
||||
if (pathList.isEmpty) {
|
||||
_lastStats = TrackingStats(
|
||||
currentAccuracy: currentAccuracy ?? 0,
|
||||
averageAccuracy: 0,
|
||||
totalDistanceMeters: 0
|
||||
);
|
||||
currentAccuracy: currentAccuracy ?? 0,
|
||||
averageAccuracy: 0,
|
||||
totalDistanceMeters: 0);
|
||||
_statsController.add(_lastStats!);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
double totalDistance = 0;
|
||||
for (int i = 1; i < pathList.length; i++) {
|
||||
totalDistance += _calculateDistance(
|
||||
pathList[i-1].latitude,
|
||||
pathList[i-1].longitude,
|
||||
pathList[i].latitude,
|
||||
pathList[i].longitude
|
||||
);
|
||||
pathList[i - 1].latitude,
|
||||
pathList[i - 1].longitude,
|
||||
pathList[i].latitude,
|
||||
pathList[i].longitude);
|
||||
}
|
||||
|
||||
double medianAccuracy = _calculateMedianAccuracy(accuracyList);
|
||||
|
||||
_lastStats = TrackingStats(
|
||||
currentAccuracy: currentAccuracy ?? 0,
|
||||
averageAccuracy: medianAccuracy,
|
||||
totalDistanceMeters: totalDistance
|
||||
);
|
||||
currentAccuracy: currentAccuracy ?? 0,
|
||||
averageAccuracy: medianAccuracy,
|
||||
totalDistanceMeters: totalDistance);
|
||||
_statsController.add(_lastStats!);
|
||||
}
|
||||
|
||||
@@ -149,19 +158,22 @@ class TrackingService {
|
||||
_updateStats();
|
||||
}
|
||||
|
||||
double _calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
double _calculateDistance(
|
||||
double lat1, double lon1, double lat2, double lon2) {
|
||||
const double earthRadius = 6371000; // Erdradius in Metern
|
||||
|
||||
|
||||
double lat1Rad = lat1 * math.pi / 180;
|
||||
double lat2Rad = lat2 * math.pi / 180;
|
||||
double deltaLat = (lat2 - lat1) * math.pi / 180;
|
||||
double deltaLon = (lon2 - lon1) * math.pi / 180;
|
||||
|
||||
double a = math.sin(deltaLat/2) * math.sin(deltaLat/2) +
|
||||
math.cos(lat1Rad) * math.cos(lat2Rad) *
|
||||
math.sin(deltaLon/2) * math.sin(deltaLon/2);
|
||||
|
||||
double c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a));
|
||||
double a = math.sin(deltaLat / 2) * math.sin(deltaLat / 2) +
|
||||
math.cos(lat1Rad) *
|
||||
math.cos(lat2Rad) *
|
||||
math.sin(deltaLon / 2) *
|
||||
math.sin(deltaLon / 2);
|
||||
|
||||
double c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
|
||||
return earthRadius * c;
|
||||
}
|
||||
|
||||
@@ -214,4 +226,4 @@ class TrackingStats {
|
||||
required this.averageAccuracy,
|
||||
required this.totalDistanceMeters,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user