diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 06ebb24..4e5e7f2 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -28,6 +28,7 @@ import 'coordinators/sheet_coordinator.dart'; import 'coordinators/navigation_coordinator.dart'; import 'coordinators/map_interaction_handler.dart'; import 'package:geolocator/geolocator.dart'; +import '../services/location_permission_gate.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -177,7 +178,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { } // Request location permission (this will show system dialog if needed) - final permission = await Geolocator.requestPermission(); + final permission = await requestLocationPermissionOnce(); debugPrint('[HomeScreen] First launch location permission result: $permission'); } } catch (e) { diff --git a/lib/services/location_permission_gate.dart b/lib/services/location_permission_gate.dart new file mode 100644 index 0000000..f68c55e --- /dev/null +++ b/lib/services/location_permission_gate.dart @@ -0,0 +1,21 @@ +import 'package:geolocator/geolocator.dart'; + +/// Single-flight guard around [Geolocator.requestPermission]. +/// +/// The Android geolocator plugin can only track one in-flight permission +/// request at a time. If a second `requestPermission()` call is made while +/// the system dialog from a first call is still pending, the plugin tries to +/// reply to the same result callback twice and crashes with +/// `IllegalStateException: Reply already submitted`. +/// +/// We have more than one place in the app that may want to (re)check/request +/// location permission around app startup (GPS controller, first-launch +/// prompt). Rather than coordinate all of them, just make sure only one real +/// native call is ever in flight - everyone else awaits that same result. +Future? _inFlight; + +Future requestLocationPermissionOnce() { + return _inFlight ??= Geolocator.requestPermission().whenComplete(() { + _inFlight = null; + }); +} diff --git a/lib/widgets/map/gps_controller.dart b/lib/widgets/map/gps_controller.dart index 02402fb..dc7f29e 100644 --- a/lib/widgets/map/gps_controller.dart +++ b/lib/widgets/map/gps_controller.dart @@ -11,6 +11,7 @@ import '../../app_state.dart' show FollowMeMode; import '../../services/proximity_alert_service.dart'; import '../../services/coordinate_validation.dart'; import '../../services/localization_service.dart'; +import '../../services/location_permission_gate.dart'; import '../../models/osm_node.dart'; import '../../models/node_profile.dart'; import '../../services/geo_bounds.dart'; @@ -152,7 +153,7 @@ class GpsController { } // Check permissions - final permission = await Geolocator.requestPermission(); + final permission = await requestLocationPermissionOnce(); debugPrint('[GpsController] Location permission result: $permission'); switch (permission) {