diff --git a/lib/screens/settings_screen_sections/proximity_alerts_section.dart b/lib/screens/settings_screen_sections/proximity_alerts_section.dart index 40ead36..437147c 100644 --- a/lib/screens/settings_screen_sections/proximity_alerts_section.dart +++ b/lib/screens/settings_screen_sections/proximity_alerts_section.dart @@ -4,6 +4,7 @@ import 'package:provider/provider.dart'; import '../../app_state.dart'; import '../../services/localization_service.dart'; +import '../../services/proximity_alert_service.dart'; import '../../dev_config.dart'; /// Settings section for proximity alerts configuration @@ -17,6 +18,8 @@ class ProximityAlertsSection extends StatefulWidget { class _ProximityAlertsSectionState extends State { late final TextEditingController _distanceController; + bool _notificationsEnabled = false; + bool _checkingPermissions = false; @override void initState() { @@ -25,6 +28,37 @@ class _ProximityAlertsSectionState extends State { _distanceController = TextEditingController( text: appState.proximityAlertDistance.toString(), ); + _checkNotificationPermissions(); + } + + Future _checkNotificationPermissions() async { + setState(() { + _checkingPermissions = true; + }); + + final enabled = await ProximityAlertService().areNotificationsEnabled(); + + if (mounted) { + setState(() { + _notificationsEnabled = enabled; + _checkingPermissions = false; + }); + } + } + + Future _requestNotificationPermissions() async { + setState(() { + _checkingPermissions = true; + }); + + final enabled = await ProximityAlertService().requestNotificationPermissions(); + + if (mounted) { + setState(() { + _notificationsEnabled = enabled; + _checkingPermissions = false; + }); + } } @override @@ -62,18 +96,82 @@ class _ProximityAlertsSectionState extends State { // Enable/disable toggle SwitchListTile( title: const Text('Enable proximity alerts'), - subtitle: const Text( + subtitle: Text( 'Get notified when approaching surveillance devices\n' - 'Uses extra battery for continuous location monitoring', - style: TextStyle(fontSize: 12), + 'Uses extra battery for continuous location monitoring\n' + '${_notificationsEnabled ? "✓ Notifications enabled" : "⚠ Notifications disabled"}', + style: const TextStyle(fontSize: 12), ), value: appState.proximityAlertsEnabled, onChanged: (enabled) { appState.setProximityAlertsEnabled(enabled); + if (enabled && !_notificationsEnabled) { + // Automatically try to request permissions when enabling + _requestNotificationPermissions(); + } }, contentPadding: EdgeInsets.zero, ), + // Notification permissions section (only show when proximity alerts are enabled) + if (appState.proximityAlertsEnabled && !_notificationsEnabled && !_checkingPermissions) ...[ + const SizedBox(height: 8), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.orange.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.orange.withOpacity(0.3)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.notifications_off, color: Colors.orange, size: 20), + const SizedBox(width: 8), + const Text( + 'Notification permission required', + style: TextStyle(fontWeight: FontWeight.w600), + ), + ], + ), + const SizedBox(height: 8), + const Text( + 'Push notifications are disabled. You\'ll only see in-app alerts and won\'t be notified when the app is in background.', + style: TextStyle(fontSize: 12), + ), + const SizedBox(height: 8), + ElevatedButton.icon( + onPressed: _requestNotificationPermissions, + icon: const Icon(Icons.settings, size: 16), + label: const Text('Enable Notifications'), + style: ElevatedButton.styleFrom( + minimumSize: const Size(0, 32), + textStyle: const TextStyle(fontSize: 12), + ), + ), + ], + ), + ), + ], + + // Loading indicator + if (_checkingPermissions) ...[ + const SizedBox(height: 8), + const Row( + children: [ + SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator(strokeWidth: 2), + ), + SizedBox(width: 8), + Text('Checking permissions...', style: TextStyle(fontSize: 12)), + ], + ), + ], + // Distance setting (only show when enabled) if (appState.proximityAlertsEnabled) ...[ const SizedBox(height: 12), diff --git a/lib/services/proximity_alert_service.dart b/lib/services/proximity_alert_service.dart index 4c420a2..ea1de30 100644 --- a/lib/services/proximity_alert_service.dart +++ b/lib/services/proximity_alert_service.dart @@ -33,7 +33,7 @@ class ProximityAlertService { // Callback for showing in-app visual alerts VoidCallback? _onVisualAlert; - /// Initialize the notification plugin + /// Initialize the notification plugin and request permissions Future initialize({VoidCallback? onVisualAlert}) async { _onVisualAlert = onVisualAlert; @@ -54,6 +54,12 @@ class ProximityAlertService { try { final initialized = await _notifications!.initialize(initSettings); _isInitialized = initialized ?? false; + + // Request notification permissions (especially important for Android 13+) + if (_isInitialized) { + await _requestNotificationPermissions(); + } + debugPrint('[ProximityAlertService] Initialized: $_isInitialized'); } catch (e) { debugPrint('[ProximityAlertService] Failed to initialize: $e'); @@ -61,6 +67,31 @@ class ProximityAlertService { } } + /// Request notification permissions on both platforms + Future _requestNotificationPermissions() async { + if (_notifications == null) return; + + try { + // Request permissions - this will show the permission dialog on Android 13+ + final result = await _notifications! + .resolvePlatformSpecificImplementation() + ?.requestNotificationsPermission(); + + debugPrint('[ProximityAlertService] Android notification permission result: $result'); + + // Also request for iOS (though this was already done in initialization) + await _notifications! + .resolvePlatformSpecificImplementation() + ?.requestPermissions( + alert: true, + badge: true, + sound: true, + ); + } catch (e) { + debugPrint('[ProximityAlertService] Failed to request permissions: $e'); + } + } + /// Check proximity to nodes and trigger alerts if needed /// This should be called on GPS position updates Future checkProximity({ @@ -196,4 +227,31 @@ class ProximityAlertService { void clearRecentAlerts() { _recentAlerts.clear(); } + + /// Check if notification permissions are granted + Future areNotificationsEnabled() async { + if (!_isInitialized || _notifications == null) return false; + + try { + // Check Android permissions + final androidImpl = _notifications! + .resolvePlatformSpecificImplementation(); + if (androidImpl != null) { + final result = await androidImpl.areNotificationsEnabled(); + return result ?? false; + } + + // For iOS, assume enabled if we got this far (permissions were requested during init) + return true; + } catch (e) { + debugPrint('[ProximityAlertService] Failed to check notification permissions: $e'); + return false; + } + } + + /// Request permissions again (can be called from settings) + Future requestNotificationPermissions() async { + await _requestNotificationPermissions(); + return await areNotificationsEnabled(); + } } \ No newline at end of file