diff --git a/lib/core/services/push_notification_service.dart b/lib/core/services/push_notification_service.dart index b0283e4..3987d3d 100644 --- a/lib/core/services/push_notification_service.dart +++ b/lib/core/services/push_notification_service.dart @@ -123,11 +123,18 @@ class PushNotificationService { Future _getAndRegisterToken() async { try { - // On iOS, wait for APNS token before requesting FCM token + // On iOS, wait for APNS token before requesting FCM token. + // Apple may not deliver it immediately — retry a few times. if (Platform.isIOS) { - final apnsToken = await _messaging!.getAPNSToken(); + String? apnsToken; + for (int attempt = 0; attempt < 5; attempt++) { + apnsToken = await _messaging!.getAPNSToken(); + if (apnsToken != null) break; + debugPrint('[FCM] APNS token not available yet, retrying in ${attempt + 1}s...'); + await Future.delayed(Duration(seconds: attempt + 1)); + } if (apnsToken == null) { - debugPrint('[FCM] APNS token not available yet (iOS simulator?), skipping FCM token registration'); + debugPrint('[FCM] APNS token not available after retries (simulator?), skipping FCM token registration'); return; } } diff --git a/lib/features/notifications/presentation/screens/notifications_screen.dart b/lib/features/notifications/presentation/screens/notifications_screen.dart index e6e0d27..537dc47 100644 --- a/lib/features/notifications/presentation/screens/notifications_screen.dart +++ b/lib/features/notifications/presentation/screens/notifications_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; import 'package:real_estate_mobile/core/constants/app_colors.dart'; import 'package:real_estate_mobile/features/notifications/data/models/notification_model.dart'; import 'package:real_estate_mobile/features/notifications/presentation/providers/notification_provider.dart'; @@ -248,6 +249,7 @@ class _NotificationsScreenState extends ConsumerState { .read(notificationListProvider.notifier) .markAsRead(notification.id); } + _navigateToNotification(notification); }, behavior: HitTestBehavior.opaque, child: Column( @@ -359,6 +361,36 @@ class _NotificationsScreenState extends ConsumerState { ); } + void _navigateToNotification(AppNotification notification) { + final data = notification.data; + final type = data?['type'] ?? notification.type; + + switch (type) { + case 'message': + final conversationId = data?['conversationId']; + if (conversationId != null) { + context.push('/messages/chat/$conversationId'); + } else { + context.go('/messages'); + } + break; + case 'connection_request': + case 'connection': + context.go('/agent/network'); + break; + case 'connection_response': + final status = data?['status']; + if (status == 'ACCEPTED') { + context.go('/messages'); + } else { + context.go('/home'); + } + break; + default: + break; + } + } + IconData _iconForType(String type) { switch (type) { case 'connection': diff --git a/lib/features/profile/presentation/widgets/notifications_tab.dart b/lib/features/profile/presentation/widgets/notifications_tab.dart index e5f1024..46c20ff 100644 --- a/lib/features/profile/presentation/widgets/notifications_tab.dart +++ b/lib/features/profile/presentation/widgets/notifications_tab.dart @@ -22,6 +22,10 @@ class _NotificationsTabState extends ConsumerState { bool _isLoadingNotifications = false; bool _isSavingNotifications = false; + // Snapshot of original values for cancel/reset + Map> _originalPrefs = {}; + String _originalFrequency = 'instant'; + @override void initState() { super.initState(); @@ -55,6 +59,12 @@ class _NotificationsTabState extends ConsumerState { _digestFrequency = data['digestFrequency'] as String? ?? 'instant'; _isLoadingNotifications = false; _notificationsLoaded = true; + // Save snapshot for cancel/reset + _originalPrefs = { + for (final e in _notificationPrefs.entries) + e.key: Map.from(e.value), + }; + _originalFrequency = _digestFrequency; }); } catch (_) { setState(() { @@ -144,8 +154,12 @@ class _NotificationsTabState extends ConsumerState { ProfileActionButtons( onSave: _saveNotificationSettings, onCancel: () { - _notificationsLoaded = false; - _loadNotificationPreferences(); + setState(() { + for (final key in _originalPrefs.keys) { + _notificationPrefs[key] = Map.from(_originalPrefs[key]!); + } + _digestFrequency = _originalFrequency; + }); }, isSaving: _isSavingNotifications, ), diff --git a/lib/features/profile/presentation/widgets/privacy_tab.dart b/lib/features/profile/presentation/widgets/privacy_tab.dart index 88af8fd..0a6107b 100644 --- a/lib/features/profile/presentation/widgets/privacy_tab.dart +++ b/lib/features/profile/presentation/widgets/privacy_tab.dart @@ -23,6 +23,14 @@ class _PrivacyTabState extends ConsumerState { bool _isSavingPrivacy = false; bool _privacyLoaded = false; + // Snapshot for cancel/reset + String _origProfileVisibility = 'public'; + String _origContactInfo = 'connections'; + String _origActivityStatus = 'public'; + bool _origShareAnalytics = false; + bool _origPersonalizedAds = false; + bool _origThirdPartySharing = false; + @override void initState() { super.initState(); @@ -50,6 +58,13 @@ class _PrivacyTabState extends ConsumerState { dataSettings['thirdPartySharing'] as bool? ?? false; _isLoadingPrivacy = false; _privacyLoaded = true; + // Save snapshot for cancel/reset + _origProfileVisibility = _profileVisibility; + _origContactInfo = _contactInfo; + _origActivityStatus = _activityStatus; + _origShareAnalytics = _shareAnalytics; + _origPersonalizedAds = _personalizedAds; + _origThirdPartySharing = _thirdPartySharing; }); } catch (_) { setState(() => _isLoadingPrivacy = false); @@ -150,8 +165,14 @@ class _PrivacyTabState extends ConsumerState { ProfileActionButtons( onSave: _savePrivacyPreferences, onCancel: () { - _privacyLoaded = false; - _loadPrivacyPreferences(); + setState(() { + _profileVisibility = _origProfileVisibility; + _contactInfo = _origContactInfo; + _activityStatus = _origActivityStatus; + _shareAnalytics = _origShareAnalytics; + _personalizedAds = _origPersonalizedAds; + _thirdPartySharing = _origThirdPartySharing; + }); }, isSaving: _isSavingPrivacy), const SizedBox(height: 24),