add geolocation View and controller and services, routes and bindings
This commit is contained in:
333
lib/services/geolocation.dart
Normal file
333
lib/services/geolocation.dart
Normal file
@@ -0,0 +1,333 @@
|
||||
import 'dart:async';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
/// Statische Geolocation Services für alle Plattformen
|
||||
/// Unterstützt Android, iOS, Web, Windows, macOS und Linux
|
||||
class GeolocationService {
|
||||
/// Private Konstruktor um Instanziierung zu verhindern
|
||||
GeolocationService._();
|
||||
|
||||
/// Stream Controller für kontinuierliche Position Updates
|
||||
static StreamSubscription<Position>? _positionStreamSubscription;
|
||||
|
||||
/// Prüft ob Location Services verfügbar und aktiviert sind
|
||||
static Future<bool> isLocationServiceEnabled() async {
|
||||
try {
|
||||
return await Geolocator.isLocationServiceEnabled();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Prüfen der Location Services: $e');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Prüft die aktuellen Location Permissions
|
||||
static Future<LocationPermission> checkPermission() async {
|
||||
try {
|
||||
return await Geolocator.checkPermission();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Prüfen der Berechtigung: $e');
|
||||
}
|
||||
return LocationPermission.denied;
|
||||
}
|
||||
}
|
||||
|
||||
/// Fordert Location Permissions an
|
||||
static Future<LocationPermission> requestPermission() async {
|
||||
try {
|
||||
return await Geolocator.requestPermission();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Anfordern der Berechtigung: $e');
|
||||
}
|
||||
return LocationPermission.denied;
|
||||
}
|
||||
}
|
||||
|
||||
/// Prüft und fordert bei Bedarf Permissions an
|
||||
static Future<bool> ensurePermissions() async {
|
||||
// Prüfe ob Location Services aktiviert sind
|
||||
bool serviceEnabled = await isLocationServiceEnabled();
|
||||
if (!serviceEnabled) {
|
||||
if (kDebugMode) {
|
||||
print('Location Services sind nicht aktiviert');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LocationPermission permission = await checkPermission();
|
||||
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
if (kDebugMode) {
|
||||
print('Location Permissions wurden verweigert');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
if (kDebugMode) {
|
||||
print('Location Permissions wurden dauerhaft verweigert');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Holt die aktuelle Position einmalig
|
||||
///
|
||||
/// [accuracy] - Gewünschte Genauigkeit (Standard: LocationAccuracy.high)
|
||||
/// [timeLimit] - Timeout für die Anfrage (Standard: 10 Sekunden)
|
||||
static Future<Position?> getCurrentPosition({
|
||||
LocationAccuracy accuracy = LocationAccuracy.high,
|
||||
Duration timeLimit = const Duration(seconds: 10),
|
||||
}) async {
|
||||
try {
|
||||
// Prüfe Permissions
|
||||
bool hasPermission = await ensurePermissions();
|
||||
if (!hasPermission) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hole aktuelle Position
|
||||
Position position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: LocationSettings(
|
||||
accuracy: accuracy,
|
||||
timeLimit: timeLimit,
|
||||
),
|
||||
);
|
||||
|
||||
return position;
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Abrufen der aktuellen Position: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Startet kontinuierliche Position Updates
|
||||
///
|
||||
/// [onPositionChanged] - Callback Funktion für neue Positionen
|
||||
/// [onError] - Callback Funktion für Fehler
|
||||
/// [accuracy] - Gewünschte Genauigkeit
|
||||
/// [distanceFilter] - Minimale Distanz zwischen Updates in Metern
|
||||
/// [intervalDuration] - Minimale Zeit zwischen Updates
|
||||
static Future<bool> startPositionStream({
|
||||
required Function(Position) onPositionChanged,
|
||||
Function(String)? onError,
|
||||
LocationAccuracy accuracy = LocationAccuracy.high,
|
||||
int distanceFilter = 10,
|
||||
Duration intervalDuration = const Duration(seconds: 5),
|
||||
}) async {
|
||||
try {
|
||||
// Prüfe Permissions
|
||||
bool hasPermission = await ensurePermissions();
|
||||
if (!hasPermission) {
|
||||
onError?.call('Keine Location Permissions');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stoppe vorherigen Stream falls aktiv
|
||||
await stopPositionStream();
|
||||
|
||||
// Erstelle Location Settings basierend auf Plattform
|
||||
LocationSettings locationSettings;
|
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
locationSettings = AndroidSettings(
|
||||
accuracy: accuracy,
|
||||
distanceFilter: distanceFilter,
|
||||
intervalDuration: intervalDuration,
|
||||
forceLocationManager: false,
|
||||
);
|
||||
} else if (defaultTargetPlatform == TargetPlatform.iOS) {
|
||||
locationSettings = AppleSettings(
|
||||
accuracy: accuracy,
|
||||
distanceFilter: distanceFilter,
|
||||
activityType: ActivityType.other,
|
||||
pauseLocationUpdatesAutomatically: true,
|
||||
showBackgroundLocationIndicator: false,
|
||||
);
|
||||
} else {
|
||||
locationSettings = LocationSettings(
|
||||
accuracy: accuracy,
|
||||
distanceFilter: distanceFilter,
|
||||
);
|
||||
}
|
||||
|
||||
// Starte Position Stream
|
||||
_positionStreamSubscription = Geolocator.getPositionStream(
|
||||
locationSettings: locationSettings,
|
||||
).listen(
|
||||
onPositionChanged,
|
||||
onError: (error) {
|
||||
if (kDebugMode) {
|
||||
print('Position Stream Fehler: $error');
|
||||
}
|
||||
onError?.call(error.toString());
|
||||
},
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Starten des Position Streams: $e');
|
||||
}
|
||||
onError?.call(e.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stoppt kontinuierliche Position Updates
|
||||
static Future<void> stopPositionStream() async {
|
||||
try {
|
||||
await _positionStreamSubscription?.cancel();
|
||||
_positionStreamSubscription = null;
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Stoppen des Position Streams: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Prüft ob Position Stream aktiv ist
|
||||
static bool isPositionStreamActive() {
|
||||
return _positionStreamSubscription != null && !_positionStreamSubscription!.isPaused;
|
||||
}
|
||||
|
||||
/// Berechnet die Distanz zwischen zwei Positionen in Metern
|
||||
static double calculateDistance({
|
||||
required double startLatitude,
|
||||
required double startLongitude,
|
||||
required double endLatitude,
|
||||
required double endLongitude,
|
||||
}) {
|
||||
return Geolocator.distanceBetween(
|
||||
startLatitude,
|
||||
startLongitude,
|
||||
endLatitude,
|
||||
endLongitude,
|
||||
);
|
||||
}
|
||||
|
||||
/// Berechnet die Richtung zwischen zwei Positionen in Grad
|
||||
static double calculateBearing({
|
||||
required double startLatitude,
|
||||
required double startLongitude,
|
||||
required double endLatitude,
|
||||
required double endLongitude,
|
||||
}) {
|
||||
return Geolocator.bearingBetween(
|
||||
startLatitude,
|
||||
startLongitude,
|
||||
endLatitude,
|
||||
endLongitude,
|
||||
);
|
||||
}
|
||||
|
||||
/// Öffnet die Geräte-Einstellungen für Location Services
|
||||
static Future<bool> openLocationSettings() async {
|
||||
try {
|
||||
return await Geolocator.openLocationSettings();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Öffnen der Location Settings: $e');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Öffnet die App-Einstellungen
|
||||
static Future<bool> openAppSettings() async {
|
||||
try {
|
||||
return await Geolocator.openAppSettings();
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Öffnen der App Settings: $e');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Formatiert Position zu einem lesbaren String
|
||||
static String positionToString(Position position) {
|
||||
return 'Lat: ${position.latitude.toStringAsFixed(6)}, '
|
||||
'Lng: ${position.longitude.toStringAsFixed(6)}, '
|
||||
'Genauigkeit: ${position.accuracy.toStringAsFixed(1)}m, '
|
||||
'Zeit: ${position.timestamp}';
|
||||
}
|
||||
|
||||
/// Konvertiert Position zu Map für JSON Serialisierung
|
||||
static Map<String, dynamic> positionToMap(Position position) {
|
||||
return {
|
||||
'latitude': position.latitude,
|
||||
'longitude': position.longitude,
|
||||
'accuracy': position.accuracy,
|
||||
'altitude': position.altitude,
|
||||
'speed': position.speed,
|
||||
'speedAccuracy': position.speedAccuracy,
|
||||
'heading': position.heading,
|
||||
'timestamp': position.timestamp.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Erstellt Position aus Map
|
||||
static Position? positionFromMap(Map<String, dynamic> map) {
|
||||
try {
|
||||
return Position(
|
||||
latitude: map['latitude']?.toDouble() ?? 0.0,
|
||||
longitude: map['longitude']?.toDouble() ?? 0.0,
|
||||
timestamp: map['timestamp'] != null
|
||||
? DateTime.parse(map['timestamp'])
|
||||
: DateTime.now(),
|
||||
accuracy: map['accuracy']?.toDouble() ?? 0.0,
|
||||
altitude: map['altitude']?.toDouble() ?? 0.0,
|
||||
altitudeAccuracy: map['altitudeAccuracy']?.toDouble() ?? 0.0,
|
||||
heading: map['heading']?.toDouble() ?? 0.0,
|
||||
headingAccuracy: map['headingAccuracy']?.toDouble() ?? 0.0,
|
||||
speed: map['speed']?.toDouble() ?? 0.0,
|
||||
speedAccuracy: map['speedAccuracy']?.toDouble() ?? 0.0,
|
||||
);
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('Fehler beim Erstellen der Position aus Map: $e');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Cleanup Methode - sollte beim App Shutdown aufgerufen werden
|
||||
static Future<void> dispose() async {
|
||||
await stopPositionStream();
|
||||
}
|
||||
}
|
||||
|
||||
/// Hilfsklasse für Location Permissions Status
|
||||
class LocationPermissionHelper {
|
||||
static String getPermissionStatusText(LocationPermission permission) {
|
||||
switch (permission) {
|
||||
case LocationPermission.denied:
|
||||
return 'Standort-Berechtigung verweigert';
|
||||
case LocationPermission.deniedForever:
|
||||
return 'Standort-Berechtigung dauerhaft verweigert';
|
||||
case LocationPermission.whileInUse:
|
||||
return 'Standort-Berechtigung während App-Nutzung';
|
||||
case LocationPermission.always:
|
||||
return 'Standort-Berechtigung immer';
|
||||
default:
|
||||
return 'Unbekannter Berechtigungs-Status';
|
||||
}
|
||||
}
|
||||
|
||||
static bool isPermissionGranted(LocationPermission permission) {
|
||||
return permission == LocationPermission.whileInUse ||
|
||||
permission == LocationPermission.always;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user