diff --git a/lib/screens/excursion/excursion_main.dart b/lib/screens/excursion/excursion_main.dart index d1ac16b..3c4de14 100644 --- a/lib/screens/excursion/excursion_main.dart +++ b/lib/screens/excursion/excursion_main.dart @@ -43,9 +43,18 @@ class ExcursionMain extends StatefulWidget { class _ExcursionMainState extends State { int currentStep = 0; late bool isTemplate; - Position? currentPosition; - bool isLoadingPosition = true; - late Future _positionFuture; + 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, + ); bool bimaExtended = false; @@ -114,9 +123,39 @@ class _ExcursionMainState extends State { @override void initState() { - super.initState(); - _positionFuture = _initializePosition(); - + GeolocatorService.deteterminePosition( + alwaysOnNeeded: false, + ).then((result) => currentPosition = result).catchError((error) async { + 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, + ); + } + } else if (error is NeedAlwaysLocation) { + if (mounted) { + bool reload = + await AddEntriesDialogHelper.locationSettingsDialog(context); + if (reload) { + GeolocatorService.deteterminePosition() + .then((res) => currentPosition = res) + .catchError((error) { + return currentPosition; + }); + } + } + } + return currentPosition; + }); + if (widget.existingData?.isNotEmpty ?? false) { for (var key in widget.existingData!.keys) { rmap[key]!["controller"]!.text = @@ -129,90 +168,12 @@ class _ExcursionMainState extends State { }); rmap["Datum"]!["controller"]!.text = DateTime.now().toString(); + rmap["Sent"]!["controller"]!.text = "0"; } isTemplate = widget.isTemplate; - } - Future _initializePosition() async { - try { - final position = await GeolocatorService.deteterminePosition( - alwaysOnNeeded: true, - ); - if (mounted) { - setState(() { - currentPosition = position; - isLoadingPosition = false; - }); - } - return position; - } catch (error) { - if (!mounted) { - return _getDefaultPosition(); - } - - if (error is LocationDisabledException) { - SnackBarHelper.showSnackBarMessage( - context, - AppLocalizations.of(context)!.locationDisabled, - ); - } else if (error is LocationForbiddenException) { - SnackBarHelper.showSnackBarMessage( - context, - AppLocalizations.of(context)!.locationForbidden, - ); - } else if (error is NeedAlwaysLocation) { - AddEntriesDialogHelper.locationSettingsDialog(context); - } - - // Return default position on any error - final defaultPosition = _getDefaultPosition(); - if (mounted) { - setState(() { - currentPosition = defaultPosition; - isLoadingPosition = false; - }); - } - return defaultPosition; - } - } - - Position _getDefaultPosition() { - return 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, - ); - } - - Future _refreshPosition() async { - setState(() { - isLoadingPosition = true; - }); - _positionFuture = _initializePosition(); - try { - final position = await _positionFuture; - if (mounted) { - setState(() { - currentPosition = position; - isLoadingPosition = false; - }); - } - } catch (e) { - // Error already handled in _initializePosition - if (mounted) { - setState(() { - isLoadingPosition = false; - }); - } - } + super.initState(); } @override @@ -391,7 +352,76 @@ class _ExcursionMainState extends State { content: Column( children: [ // ---------- Tracking - _buildTrackingButtons(), + ElevatedButton( + onPressed: () async { + // Check for always permission before starting tracking + LocationPermission permission = await Geolocator.checkPermission(); + if (permission != LocationPermission.always) { + if (mounted) { + bool? shouldContinue = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context)!.trackingPermissionTitle), + content: Text(AppLocalizations.of(context)!.trackingPermissionContent), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(AppLocalizations.of(context)!.cancel), + ), + TextButton( + onPressed: () async { + await Geolocator.openAppSettings(); + Navigator.of(context).pop(true); + }, + child: Text(AppLocalizations.of(context)!.openSettings), + ), + ], + ), + ); + + if (shouldContinue != true) { + return; + } + + // Wait for user to change settings and return + // Try checking the permission multiple times + for (int i = 0; i < 5; i++) { + await Future.delayed(const Duration(seconds: 1)); + if (!mounted) return; + + permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.always) { + break; + } + + // If this is the last attempt and we still don't have permission + if (i == 4 && permission != LocationPermission.always) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context)!.permissionNotGranted), + duration: const Duration(seconds: 3), + ), + ); + } + return; + } + } + } + } + + await Navigator.push(context, MaterialPageRoute( + builder: (context) { + return Tracking( + weg: rmap["Weg"]!["controller"]!, + startPosition: currentPosition, + ); + }, + )); + setState(() {}); + }, + child: Text(AppLocalizations.of(context)!.trackingAnAusschalten), + ), const SizedBox(height: 10), // ---------- Weather @@ -494,29 +524,32 @@ class _ExcursionMainState extends State { return PopScope( canPop: false, - onPopInvoked: (didPop) async { + onPopInvokedWithResult: (bool didPop, Object? res) async { if (didPop) { return; } - + // Show confirmation dialog final result = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('Seite verlassen?'), - content: const Text('Möchten Sie die Seite wirklich verlassen?'), + title: Text(AppLocalizations.of(context)!.leavePageTitle), + content: Text(AppLocalizations.of(context)!.leavePageContent), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(0), - child: const Text('Nein'), + child: Text(AppLocalizations.of(context)!.nein), ), TextButton( - onPressed: () => Navigator.of(context).pop(1), - child: const Text('Ja und Template speichern'), + onPressed: () { + saveTemplate(getFieldsText(), DatabasesEnum.excursion); + Navigator.of(context).pop(1); + }, + child: Text(AppLocalizations.of(context)!.leaveAndSaveTemplate), ), TextButton( onPressed: () => Navigator.of(context).pop(2), - child: const Text('Ja ohne Template'), + child: Text(AppLocalizations.of(context)!.leaveWithoutSaving), ), ], ), @@ -550,9 +583,11 @@ class _ExcursionMainState extends State { actions: [ // Text(TrackingService().isTracking ? "Tracking" : "Not tracking") Image.asset( - TrackingService().isTracking ? "assets/icons/tracking_on.png" : "assets/icons/tracking_off.png", + TrackingService().isTracking + ? "assets/icons/tracking_on.png" + : "assets/icons/tracking_off.png", width: 40, - ), + ), ], ), body: PageTransitionSwitcher( @@ -617,7 +652,7 @@ class _ExcursionMainState extends State { bool pop = await AddEntriesDialogHelper.showSaveOptionsDialog( context, getFieldsText(), - widget.isTemplate, + isTemplate, DatabasesEnum.excursion, ); if (pop && context.mounted) Navigator.of(context).pop(); @@ -638,60 +673,4 @@ class _ExcursionMainState extends State { ), ); } - - // Add a refresh position button next to the tracking button - Widget _buildTrackingButtons() { - return FutureBuilder( - future: _positionFuture, - builder: (context, snapshot) { - final bool isLoading = snapshot.connectionState == ConnectionState.waiting && !snapshot.hasData; - final Position position = snapshot.data ?? currentPosition ?? _getDefaultPosition(); - - return Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: isLoading - ? null - : () async { - await Navigator.push(context, MaterialPageRoute( - builder: (context) { - return Tracking( - weg: rmap["Weg"]!["controller"]!, - startPosition: position, - ); - }, - )); - setState(() {}); - }, - child: isLoading - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox( - width: 16, - height: 16, - child: CircularProgressIndicator( - strokeWidth: 2, - color: Theme.of(context).colorScheme.onPrimary, - ), - ), - const SizedBox(width: 8), - Text(AppLocalizations.of(context)!.trackingAnAusschalten), - ], - ) - : Text(AppLocalizations.of(context)!.trackingAnAusschalten), - ), - ), - const SizedBox(width: 8), - IconButton( - onPressed: isLoading ? null : _refreshPosition, - icon: const Icon(Icons.refresh), - tooltip: 'Position aktualisieren', - ), - ], - ); - }, - ); - } } diff --git a/lib/services/tracking_service.dart b/lib/services/tracking_service.dart index de2c8f7..c375bba 100644 --- a/lib/services/tracking_service.dart +++ b/lib/services/tracking_service.dart @@ -57,12 +57,17 @@ class TrackingService { Future startTracking(BuildContext context) async { if (isTracking) return; + final LocationSettings locationSettings = LocationSettings( + accuracy: LocationAccuracy.high + ); _lastContext = context; await NotificationService().initNotification(); - NotificationService().showNotification( + if (context.mounted) { + NotificationService().showNotification( title: AppLocalizations.of(context)!.trackingRunningInBackground, ); + } // Get tracking interval from settings final prefs = await SharedPreferences.getInstance(); @@ -71,8 +76,9 @@ class TrackingService { // Create a timer that triggers position updates _positionTimer = Timer.periodic(Duration(seconds: intervalSeconds), (_) async { try { + final Position position = await Geolocator.getCurrentPosition( - desiredAccuracy: LocationAccuracy.high, + locationSettings: locationSettings ); pathList.add(LatLng(position.latitude, position.longitude)); @@ -89,7 +95,7 @@ class TrackingService { // Get initial position immediately try { final Position position = await Geolocator.getCurrentPosition( - desiredAccuracy: LocationAccuracy.high, + locationSettings: locationSettings ); pathList.add(LatLng(position.latitude, position.longitude)); @@ -208,4 +214,4 @@ class TrackingStats { required this.averageAccuracy, required this.totalDistanceMeters, }); -} \ No newline at end of file +}