diff --git a/lib/screens/excursion/excursion_main.dart b/lib/screens/excursion/excursion_main.dart index 3c4de14..6ac95d5 100644 --- a/lib/screens/excursion/excursion_main.dart +++ b/lib/screens/excursion/excursion_main.dart @@ -43,18 +43,9 @@ class ExcursionMain extends StatefulWidget { class _ExcursionMainState extends State { 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, - ); + Position? currentPosition; + bool isLoadingPosition = true; + late Future _positionFuture; bool bimaExtended = false; @@ -123,38 +114,8 @@ class _ExcursionMainState extends State { @override void initState() { - 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; - }); + super.initState(); + _positionFuture = _initializePosition(); if (widget.existingData?.isNotEmpty ?? false) { for (var key in widget.existingData!.keys) { @@ -172,8 +133,87 @@ class _ExcursionMainState extends State { } isTemplate = widget.isTemplate; + } - super.initState(); + 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; + }); + } + } } @override @@ -352,76 +392,7 @@ class _ExcursionMainState extends State { content: Column( children: [ // ---------- Tracking - 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), - ), + _buildTrackingButtons(), const SizedBox(height: 10), // ---------- Weather @@ -541,9 +512,9 @@ class _ExcursionMainState extends State { child: Text(AppLocalizations.of(context)!.nein), ), TextButton( - onPressed: () { - saveTemplate(getFieldsText(), DatabasesEnum.excursion); - Navigator.of(context).pop(1); + onPressed: () { + saveTemplate(getFieldsText(), DatabasesEnum.excursion); + Navigator.of(context).pop(1); }, child: Text(AppLocalizations.of(context)!.leaveAndSaveTemplate), ), @@ -673,4 +644,64 @@ 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', + ), + ], + ); + }, + ); + } }