282 lines
8.2 KiB
Dart
282 lines
8.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:geolocator/geolocator.dart';
|
|
import '../../services/geolocation.dart';
|
|
import '../models/ptv_logistic_model.dart';
|
|
import '../services/ptv_api_simple.dart';
|
|
|
|
/// GetX Controller für Geolocation Funktionalität
|
|
class GeolocationController extends GetxController {
|
|
// Reactive Variablen
|
|
final _currentPosition = Rxn<Position>();
|
|
final _statusText = 'Noch keine Position ermittelt'.obs;
|
|
final _isTracking = false.obs;
|
|
final _isLoading = false.obs;
|
|
final _ptvModel = Rxn<PTVModel>();
|
|
|
|
// Getter für reactive Variablen
|
|
Position? get currentPosition => _currentPosition.value;
|
|
String get statusText => _statusText.value;
|
|
bool get isTracking => _isTracking.value;
|
|
bool get isLoading => _isLoading.value;
|
|
PTVModel? get ptvModel => _ptvModel.value;
|
|
|
|
@override
|
|
void onClose() {
|
|
// Cleanup beim Schließen des Controllers
|
|
stopTracking();
|
|
super.onClose();
|
|
}
|
|
|
|
/// Holt die aktuelle Position einmalig
|
|
Future<void> getCurrentPosition() async {
|
|
try {
|
|
_isLoading.value = true;
|
|
_statusText.value = 'Position wird ermittelt...';
|
|
|
|
Position? position = await GeolocationService.getCurrentPosition();
|
|
|
|
if (position != null) {
|
|
_currentPosition.value = position;
|
|
_statusText.value = GeolocationService.positionToString(position);
|
|
var resultData = await PtvApiServiceSimple.getLocationsByPosition(
|
|
latitude: position.latitude,
|
|
longitude: position.longitude,
|
|
);
|
|
if (resultData != null) {
|
|
_ptvModel.value = PTVModel.fromJson(resultData);
|
|
} else {
|
|
_ptvModel.value = null;
|
|
}
|
|
debugPrint('Position ermittelt: ${_currentPosition.value}');
|
|
} else {
|
|
_statusText.value = 'Position konnte nicht ermittelt werden';
|
|
debugPrint('Fehler beim Abrufen der Position');
|
|
// Fehler-Snackbar anzeigen
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Position konnte nicht ermittelt werden',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
_statusText.value = 'Fehler beim Abrufen der Position: $e';
|
|
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Unerwarteter Fehler: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} finally {
|
|
_isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
/// Startet kontinuierliches Position Tracking
|
|
Future<void> startTracking() async {
|
|
if (_isTracking.value) return;
|
|
|
|
try {
|
|
_isLoading.value = true;
|
|
_statusText.value = 'Tracking wird gestartet...';
|
|
|
|
bool success = await GeolocationService.startPositionStream(
|
|
onPositionChanged: (Position position) {
|
|
_currentPosition.value = position;
|
|
_statusText.value = GeolocationService.positionToString(position);
|
|
},
|
|
onError: (String error) {
|
|
_statusText.value = 'Tracking Fehler: $error';
|
|
_isTracking.value = false;
|
|
|
|
Get.snackbar(
|
|
'Tracking Fehler',
|
|
error,
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
},
|
|
accuracy: LocationAccuracy.high,
|
|
distanceFilter: 5, // Updates alle 5 Meter
|
|
);
|
|
|
|
if (success) {
|
|
_isTracking.value = true;
|
|
_statusText.value = 'Tracking aktiv - Warten auf erste Position...';
|
|
|
|
Get.snackbar(
|
|
'Tracking gestartet',
|
|
'Position wird kontinuierlich überwacht',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} else {
|
|
_statusText.value = 'Tracking konnte nicht gestartet werden';
|
|
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Tracking konnte nicht gestartet werden',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
_statusText.value = 'Fehler beim Starten des Trackings: $e';
|
|
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Tracking-Fehler: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} finally {
|
|
_isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
/// Stoppt das Position Tracking
|
|
Future<void> stopTracking() async {
|
|
if (!_isTracking.value) return;
|
|
|
|
try {
|
|
await GeolocationService.stopPositionStream();
|
|
_isTracking.value = false;
|
|
_statusText.value = 'Tracking gestoppt';
|
|
|
|
Get.snackbar(
|
|
'Tracking gestoppt',
|
|
'Position wird nicht mehr überwacht',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Fehler beim Stoppen des Trackings: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Togglet das Tracking (Start/Stop)
|
|
Future<void> toggleTracking() async {
|
|
if (_isTracking.value) {
|
|
await stopTracking();
|
|
} else {
|
|
await startTracking();
|
|
}
|
|
}
|
|
|
|
/// Prüft Permission Status
|
|
Future<void> checkPermissions() async {
|
|
try {
|
|
_isLoading.value = true;
|
|
_statusText.value = 'Berechtigungen werden geprüft...';
|
|
|
|
LocationPermission permission =
|
|
await GeolocationService.checkPermission();
|
|
bool serviceEnabled = await GeolocationService.isLocationServiceEnabled();
|
|
|
|
_statusText.value =
|
|
'Service aktiv: $serviceEnabled\n'
|
|
'Berechtigung: ${LocationPermissionHelper.getPermissionStatusText(permission)}';
|
|
|
|
// Detaillierte Information in Snackbar
|
|
String permissionStatus =
|
|
LocationPermissionHelper.getPermissionStatusText(permission);
|
|
Get.snackbar(
|
|
'Berechtigungs-Status',
|
|
'Location Service: ${serviceEnabled ? "Aktiv" : "Inaktiv"}\n$permissionStatus',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
duration: const Duration(seconds: 4),
|
|
);
|
|
} catch (e) {
|
|
_statusText.value = 'Fehler beim Prüfen der Berechtigungen: $e';
|
|
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Berechtigungen konnten nicht geprüft werden: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} finally {
|
|
_isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
/// Öffnet die Location Einstellungen
|
|
Future<void> openLocationSettings() async {
|
|
try {
|
|
bool opened = await GeolocationService.openLocationSettings();
|
|
|
|
if (opened) {
|
|
Get.snackbar(
|
|
'Einstellungen geöffnet',
|
|
'Location-Einstellungen wurden geöffnet',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} else {
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Location-Einstellungen konnten nicht geöffnet werden',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Fehler beim Öffnen der Location-Einstellungen: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Öffnet die App Einstellungen
|
|
Future<void> openAppSettings() async {
|
|
try {
|
|
bool opened = await GeolocationService.openAppSettings();
|
|
|
|
if (opened) {
|
|
Get.snackbar(
|
|
'Einstellungen geöffnet',
|
|
'App-Einstellungen wurden geöffnet',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
} else {
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'App-Einstellungen konnten nicht geöffnet werden',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
Get.snackbar(
|
|
'Fehler',
|
|
'Fehler beim Öffnen der App-Einstellungen: $e',
|
|
snackPosition: SnackPosition.BOTTOM,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Formatiert die aktuelle Position als lesbaren String
|
|
String get formattedPosition {
|
|
if (_currentPosition.value == null) return 'Keine Position verfügbar';
|
|
return GeolocationService.positionToString(_currentPosition.value!);
|
|
}
|
|
|
|
/// Prüft ob eine Position verfügbar ist
|
|
bool get hasPosition => _currentPosition.value != null;
|
|
|
|
/// Holt die Genauigkeit der aktuellen Position
|
|
double get currentAccuracy => _currentPosition.value?.accuracy ?? 0.0;
|
|
|
|
/// Holt die Geschwindigkeit der aktuellen Position in km/h
|
|
double get currentSpeedKmh {
|
|
if (_currentPosition.value?.speed == null) return 0.0;
|
|
return (_currentPosition.value!.speed * 3.6); // m/s zu km/h
|
|
}
|
|
|
|
/// Resettet alle Werte auf ihre Anfangszustände
|
|
void reset() {
|
|
stopTracking();
|
|
_currentPosition.value = null;
|
|
_statusText.value = 'Noch keine Position ermittelt';
|
|
_isTracking.value = false;
|
|
_isLoading.value = false;
|
|
}
|
|
}
|