From 4f16db59b2812d48b34728ded04267b47d871f1a Mon Sep 17 00:00:00 2001 From: fiatcode Date: Thu, 30 Apr 2026 16:33:38 +0700 Subject: [PATCH] fix: permission screen location request - request WhenInUse first then Always --- lib/permission_screen.dart | 48 +++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/permission_screen.dart b/lib/permission_screen.dart index d2b1b97..95d31d0 100644 --- a/lib/permission_screen.dart +++ b/lib/permission_screen.dart @@ -56,32 +56,54 @@ class _PermissionScreenState extends State { _locationGranted && _notificationGranted && _batteryOptOut; Future _requestLocation() async { - final status = await Permission.locationAlways.request(); + // Check current status first + var status = await Permission.locationAlways.status; + if (status.isGranted) { + if (mounted) setState(() => _locationGranted = true); + return; + } + + // On Android, request locationWhenInUse first before locationAlways + var whenInUse = await Permission.locationWhenInUse.status; + if (!whenInUse.isGranted) { + whenInUse = await Permission.locationWhenInUse.request(); + } + + // Now request locationAlways (background permission) + status = await Permission.locationAlways.request(); + if (!status.isGranted && status.isPermanentlyDenied) { - // Permission permanently denied - open app settings await openAppSettings(); } + + final finalStatus = await Permission.locationAlways.status; if (mounted) { - final newStatus = await Permission.locationAlways.status; - setState(() => _locationGranted = newStatus.isGranted); + setState(() => _locationGranted = finalStatus.isGranted); } } Future _requestNotification() async { - final status = await Permission.notification.request(); + var status = await Permission.notification.status; + if (status.isGranted) { + if (mounted) setState(() => _notificationGranted = true); + return; + } + + status = await Permission.notification.request(); + if (!status.isGranted && status.isPermanentlyDenied) { await openAppSettings(); } + + final finalStatus = await Permission.notification.status; if (mounted) { - final newStatus = await Permission.notification.status; - setState(() => _notificationGranted = newStatus.isGranted); + setState(() => _notificationGranted = finalStatus.isGranted); } } Future _requestBatteryOptOut() async { final opened = await LocationBridge.openBatteryOptimizationSettings(); if (mounted) { - // Show dialog after the settings screen opens _showBatteryOptDialog(opened); } } @@ -109,8 +131,8 @@ class _PermissionScreenState extends State { content: Text( settingsOpened ? 'A settings screen has opened.\n\n' - 'Find "Traccar Client" and set it to "Don\'t optimize" or "Unrestricted", then come back and tap DONE below.' - : 'Open Settings → Apps → Traccar Client → Battery and select "Don\'t optimize" or "Unrestricted", then come back and tap DONE below.', + 'Find "Traccar Client" and set it to "Don\'t optimize" or "Unrestricted", then come back and tap CHECK & DONE.' + : 'Open Settings → Apps → Traccar Client → Battery and select "Don\'t optimize" or "Unrestricted", then come back and tap CHECK & DONE.', style: const TextStyle( fontFamily: 'monospace', fontSize: 12, @@ -121,7 +143,6 @@ class _PermissionScreenState extends State { TextButton( onPressed: () { Navigator.pop(ctx); - // Open app details settings as fallback openAppSettings(); }, child: const Text( @@ -138,7 +159,6 @@ class _PermissionScreenState extends State { TextButton( onPressed: () async { Navigator.pop(ctx); - // Re-check battery optimization state via native final disabled = await _isBatteryOptimizationDisabled(); if (mounted) { setState(() => _batteryOptOut = disabled); @@ -273,8 +293,8 @@ class _PermissionScreenState extends State { size: 20, ), ), - SizedBox(width: 14), - Expanded( + const SizedBox(width: 14), + const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [