feat: Enhance APNS token retrieval with retries and add cancel functionality to revert changes in notification and privacy settings.

This commit is contained in:
pradeepkumar
2026-03-20 02:48:41 +05:30
parent cbb9034424
commit 744787bae2
4 changed files with 81 additions and 7 deletions

View File

@@ -123,11 +123,18 @@ class PushNotificationService {
Future<void> _getAndRegisterToken() async { Future<void> _getAndRegisterToken() async {
try { 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) { 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) { 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; return;
} }
} }

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/core/constants/app_colors.dart';
import 'package:real_estate_mobile/features/notifications/data/models/notification_model.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'; import 'package:real_estate_mobile/features/notifications/presentation/providers/notification_provider.dart';
@@ -248,6 +249,7 @@ class _NotificationsScreenState extends ConsumerState<NotificationsScreen> {
.read(notificationListProvider.notifier) .read(notificationListProvider.notifier)
.markAsRead(notification.id); .markAsRead(notification.id);
} }
_navigateToNotification(notification);
}, },
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: Column( child: Column(
@@ -359,6 +361,36 @@ class _NotificationsScreenState extends ConsumerState<NotificationsScreen> {
); );
} }
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) { IconData _iconForType(String type) {
switch (type) { switch (type) {
case 'connection': case 'connection':

View File

@@ -22,6 +22,10 @@ class _NotificationsTabState extends ConsumerState<NotificationsTab> {
bool _isLoadingNotifications = false; bool _isLoadingNotifications = false;
bool _isSavingNotifications = false; bool _isSavingNotifications = false;
// Snapshot of original values for cancel/reset
Map<String, Map<String, bool>> _originalPrefs = {};
String _originalFrequency = 'instant';
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -55,6 +59,12 @@ class _NotificationsTabState extends ConsumerState<NotificationsTab> {
_digestFrequency = data['digestFrequency'] as String? ?? 'instant'; _digestFrequency = data['digestFrequency'] as String? ?? 'instant';
_isLoadingNotifications = false; _isLoadingNotifications = false;
_notificationsLoaded = true; _notificationsLoaded = true;
// Save snapshot for cancel/reset
_originalPrefs = {
for (final e in _notificationPrefs.entries)
e.key: Map<String, bool>.from(e.value),
};
_originalFrequency = _digestFrequency;
}); });
} catch (_) { } catch (_) {
setState(() { setState(() {
@@ -144,8 +154,12 @@ class _NotificationsTabState extends ConsumerState<NotificationsTab> {
ProfileActionButtons( ProfileActionButtons(
onSave: _saveNotificationSettings, onSave: _saveNotificationSettings,
onCancel: () { onCancel: () {
_notificationsLoaded = false; setState(() {
_loadNotificationPreferences(); for (final key in _originalPrefs.keys) {
_notificationPrefs[key] = Map<String, bool>.from(_originalPrefs[key]!);
}
_digestFrequency = _originalFrequency;
});
}, },
isSaving: _isSavingNotifications, isSaving: _isSavingNotifications,
), ),

View File

@@ -23,6 +23,14 @@ class _PrivacyTabState extends ConsumerState<PrivacyTab> {
bool _isSavingPrivacy = false; bool _isSavingPrivacy = false;
bool _privacyLoaded = 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 @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -50,6 +58,13 @@ class _PrivacyTabState extends ConsumerState<PrivacyTab> {
dataSettings['thirdPartySharing'] as bool? ?? false; dataSettings['thirdPartySharing'] as bool? ?? false;
_isLoadingPrivacy = false; _isLoadingPrivacy = false;
_privacyLoaded = true; _privacyLoaded = true;
// Save snapshot for cancel/reset
_origProfileVisibility = _profileVisibility;
_origContactInfo = _contactInfo;
_origActivityStatus = _activityStatus;
_origShareAnalytics = _shareAnalytics;
_origPersonalizedAds = _personalizedAds;
_origThirdPartySharing = _thirdPartySharing;
}); });
} catch (_) { } catch (_) {
setState(() => _isLoadingPrivacy = false); setState(() => _isLoadingPrivacy = false);
@@ -150,8 +165,14 @@ class _PrivacyTabState extends ConsumerState<PrivacyTab> {
ProfileActionButtons( ProfileActionButtons(
onSave: _savePrivacyPreferences, onSave: _savePrivacyPreferences,
onCancel: () { onCancel: () {
_privacyLoaded = false; setState(() {
_loadPrivacyPreferences(); _profileVisibility = _origProfileVisibility;
_contactInfo = _origContactInfo;
_activityStatus = _origActivityStatus;
_shareAnalytics = _origShareAnalytics;
_personalizedAds = _origPersonalizedAds;
_thirdPartySharing = _origThirdPartySharing;
});
}, },
isSaving: _isSavingPrivacy), isSaving: _isSavingPrivacy),
const SizedBox(height: 24), const SizedBox(height: 24),