Aidra Connect 10.0.2+16
Aidra Connect Mobile Application
Loading...
Searching...
No Matches
notification_service.dart
Go to the documentation of this file.
1import 'dart:async';
2import 'dart:convert';
3import 'dart:io';
4
5import 'package:connect/core/router/routes.dart';
6import 'package:firebase_core/firebase_core.dart';
7import 'package:firebase_messaging/firebase_messaging.dart';
8import 'package:flutter_local_notifications/flutter_local_notifications.dart';
9import 'package:cloud_firestore/cloud_firestore.dart';
10import 'package:go_router/go_router.dart';
11import 'package:connect/core/router/router.dart' show rootNavigatorKey;
12import 'package:shared_preferences/shared_preferences.dart';
13import '../../features/authentication/domain/entities/session_entity.dart';
14import 'package:flutter_bloc/flutter_bloc.dart';
15import '../../features/collections/presentation/logic/collection_requests_history_bloc/collection_requests_history_bloc.dart';
16import '../../features/authentication/presentation/logic/authentication_bloc/authentication_bloc.dart';
17
18@pragma('vm:entry-point')
19Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
20 await Firebase.initializeApp();
21 await SharedPreferences.getInstance().then((prefs) {
22 if (message.data['type'] == 'business') {
23 prefs.setString('pending_notification', json.encode(message.data));
24 }
25 });
26}
27
33
35
37
38 final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
39 final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
40 FlutterLocalNotificationsPlugin();
41
43 _currentSession = session;
44 }
45
46 Future<void> init() async {
47 await _firebaseMessaging.setForegroundNotificationPresentationOptions(
48 alert: true,
49 badge: true,
50 sound: true,
51 );
52
53 NotificationSettings settings = await _firebaseMessaging.requestPermission(
54 alert: true,
55 badge: true,
56 sound: true,
57 provisional: false,
58 );
59
60 if (settings.authorizationStatus == AuthorizationStatus.authorized) {
62 FirebaseMessaging.onMessage.listen(_handleForegroundMessage);
63 FirebaseMessaging.onMessageOpenedApp.listen(_handleNotificationTap);
64 FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
66 }
67 }
68
69 Future<void> _checkPendingNotification() async {
70 final prefs = await SharedPreferences.getInstance();
71 final pendingNotification = prefs.getString('pending_notification');
72 final wasClicked = prefs.getBool('notification_clicked') ?? false;
73
74 if (pendingNotification != null && wasClicked) {
76 } else {
77 final initialMessage = await _firebaseMessaging.getInitialMessage();
78 if (initialMessage != null) {
79 await prefs.setString(
80 'pending_notification',
81 json.encode(initialMessage.data),
82 );
83 await prefs.setBool('notification_clicked', true);
85 }
86 }
87 }
88
89 Future<void> setupAfterAuthentication(SessionEntity session) async {
90 updateSession(session);
91 String? token = await _firebaseMessaging.getToken();
92 if (token != null) {
93 await _saveDeviceToken(token);
94 }
95 _firebaseMessaging.onTokenRefresh.listen(_saveDeviceToken);
96
98 Future.delayed(const Duration(milliseconds: 500), () async {
100 final prefs = await SharedPreferences.getInstance();
101 final pendingNotification = prefs.getString('pending_notification');
102 if (pendingNotification != null) {
103 final data = json.decode(pendingNotification);
105 // Clear both notification data and click flag
106 await prefs.remove('pending_notification');
107 await prefs.remove('notification_clicked');
108 }
109 });
110 }
111 }
112
113 Future<void> _initLocalNotifications() async {
114 const AndroidInitializationSettings initializationSettingsAndroid =
115 AndroidInitializationSettings('@mipmap/ic_launcher');
116
117 final DarwinInitializationSettings initializationSettingsIOS =
118 DarwinInitializationSettings(
119 requestSoundPermission: true,
120 requestBadgePermission: true,
121 requestAlertPermission: true,
122 );
123
124 final InitializationSettings initializationSettings =
125 InitializationSettings(
126 android: initializationSettingsAndroid,
127 iOS: initializationSettingsIOS,
128 );
129
130 await _flutterLocalNotificationsPlugin.initialize(
131 initializationSettings,
132 onDidReceiveNotificationResponse: _onNotificationTap,
133 );
134 }
135
136 Future<void> _saveDeviceToken(String token) async {
137 if (_currentSession?.partnerId == null) return;
138
139 final parentId = _currentSession!.parentId.toString();
140 final deviceTokenDoc = {
141 'token': token,
142 'platform': Platform.operatingSystem,
143 'loginTimestamp': FieldValue.serverTimestamp(),
144 'isActive': true,
145 };
146
147 await FirebaseFirestore.instance
148 .collection('users')
149 .doc(parentId)
150 .collection('deviceTokens')
151 .doc(token)
152 .set(deviceTokenDoc, SetOptions(merge: true));
153 }
154
155 Future<void> removeDeviceToken(String token) async {
156 if (_currentSession?.parentId == null) return;
157
158 final parentId = _currentSession!.parentId.toString();
159 await FirebaseFirestore.instance
160 .collection('users')
161 .doc(parentId)
162 .collection('deviceTokens')
163 .doc(token)
164 .update({'isActive': false});
165 }
166
167 Future<void> _handleForegroundMessage(RemoteMessage message) async {
168 if (message.notification != null) {
170 title: message.notification!.title ?? 'Notification',
171 body: message.notification!.body ?? '',
172 payload: message.data,
173 );
174 }
175 }
176
178 required String title,
179 required String body,
180 required Map<String, dynamic> payload,
181 }) async {
182 const AndroidNotificationDetails androidPlatformChannelSpecifics =
183 AndroidNotificationDetails(
184 'high_importance_channel',
185 'High Importance Notifications',
186 importance: Importance.max,
187 priority: Priority.high,
188 );
189
190 const DarwinNotificationDetails iOSPlatformChannelSpecifics =
191 DarwinNotificationDetails(
192 presentAlert: true,
193 presentBadge: true,
194 presentSound: true,
195 );
196
197 const NotificationDetails platformChannelSpecifics = NotificationDetails(
198 android: androidPlatformChannelSpecifics,
199 iOS: iOSPlatformChannelSpecifics,
200 );
201
203 0,
204 title,
205 body,
206 platformChannelSpecifics,
207 payload: json.encode(payload),
208 );
209 }
210
211 void _handleNotificationTap(RemoteMessage message) async {
212 await SharedPreferences.getInstance().then((prefs) {
213 prefs.setBool('notification_clicked', true);
214 });
215
217 }
218
219 void _onNotificationTap(NotificationResponse notificationResponse) {
220 if (notificationResponse.payload != null) {
221 final payload = _parsePayload(notificationResponse.payload!);
223 }
224 }
225
226 Map<String, dynamic> _parsePayload(String payloadString) {
227 try {
228 return json.decode(payloadString);
229 } catch (e) {
230 return {};
231 }
232 }
233
234 void _navigateBasedOnNotification(Map<String, dynamic> data) {
235 final String? notificationType = data['type'] as String?;
236 if (notificationType == 'business') {
237 final context = rootNavigatorKey.currentContext!;
238 final authState = context.read<AuthenticationBloc>().state;
239 if (authState is AuthenticatedState) {
240 final String? partnerId = authState.session.partnerId;
241 if (partnerId != null) {
242 context.read<CollectionRequestsHistoryBloc>().add(
245 ),
246 );
247 GoRouter.of(context).push(Routes.transactionHistory.route);
248 }
249 }
250 }
251 }
252}
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin
void _navigateBasedOnNotification(Map< String, dynamic > data)
Future< void > removeDeviceToken(String token) async
Future< void > _initLocalNotifications() async
Future< void > _showLocalNotification({ required String title, required String body, required Map< String, dynamic > payload, }) async
static final NotificationService _instance
final FirebaseMessaging _firebaseMessaging
Future< void > _handleForegroundMessage(RemoteMessage message) async
void _onNotificationTap(NotificationResponse notificationResponse)
Future< void > _checkPendingNotification() async
Future< void > init() async
factory NotificationService()
Future< void > _saveDeviceToken(String token) async
void _handleNotificationTap(RemoteMessage message) async
void updateSession(SessionEntity? session)
Map< String, dynamic > _parsePayload(String payloadString)
Future< void > setupAfterAuthentication(SessionEntity session) async
final num partnerId
const LoadOnGoingCollectionRequestsEvent({required this.partnerId})
final String message
Definition failures.dart:0
pragma('vm:entry-point') Future< void > firebaseMessagingBackgroundHandler(RemoteMessage message) async
final rootNavigatorKey
Definition router.dart:13
Routes
Definition routes.dart:32
settings
Definition routes.dart:72
final String title