Firebase Service
The Firebase service file provides the implementation of internal notifications using Firebase Firestore. It contains the necessary methods and structures to interact with Firebase Firestore and manage internal notifications.
However, developers should note that this file is not meant to be directly instantiated. Instead, it is used by the main internal notifications file, which provides a unified interface for integrating different notification services.
Internal Notifications With Firebase Class
The InternalNotificationsWithFirebase class implements the InternalNotificationsService abstract class specifically for handling internal notifications using Firebase Firestore. It includes methods for initializing the service, subscribing to and unsubscribing from notifications, pushing notifications to users, and managing internal notification streams.
Integration
To integrate Firebase-based internal notifications using this service file, follow these steps:
- Ensure that you have set up Firebase Firestore in your Flutter project separately and have the required collections and permissions in place to store internal notifications.
- Ensure that you have the necessary Firebase-related configurations set up in your Flutter project by running the
flutterfire configure
command. This step ensures that your project is properly connected to Firebase. - Implement the necessary logic to initialize Firebase Firestore and retrieve the user ID based on your application's authentication or identification system. Also when subscribing for perticular user user id is needed so for that logic should be implemented by developer in the
init()
method of this class to assign user id in the service, the logic may vary depending on the project.
::alert{type="info" }class="flex items-center p-4 mb-4 text-sm text-blue-800 border border-blue-300 rounded-lg bg-blue-50 dark:bg-gray-800 dark:text-blue-400 dark:border-blue-800" role="alert"
Note:
Remember, the Firebase service file provided here serves as a part of the overall internal notifications system and should be used within the context of the main internal notifications file. It provides the implementation for Firebase Firestore-based notifications, while the main file acts as a central point for integrating different notification services.
::
Souce Code
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import './base_service.dart';
import '../../models/notification.dart';
class InternalNotificationsWithFirebase implements InternalNotificationsService {
final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;
final StreamController<int> _pendingNotificationsCountStreamController =
StreamController<int>.broadcast();
@override
late final Stream<int> pendingNotificationsCountStream;
final StreamController<List<InternalNotification>> _notificationsStreamController =
StreamController<List<InternalNotification>>.broadcast();
@override
late final Stream<List<InternalNotification>> notificationsStream;
List<InternalNotification> _notifications = [];
@override
List<InternalNotification> get notifications => _notifications;
// collection ids
final String _notificationsCollection = 'notifications';
final String _notificationsDataCollection = 'notification_data';
late final String userId;
StreamSubscription? _firebaseNotificationStream;
@override
Future<void> init() async {
pendingNotificationsCountStream = _pendingNotificationsCountStreamController.stream;
notificationsStream = _notificationsStreamController.stream;
// Write your logic here to get user id
userId = 'test';
final bool hasSubscribed =
(await _firebaseFirestore.collection(_notificationsCollection).doc(userId).get())
.data()?['has_subscribed'];
if (hasSubscribed) {
_firebaseNotificationStream = _firebaseFirestore
.collection(_notificationsCollection)
.doc(userId)
.collection(_notificationsDataCollection)
.snapshots()
.listen(_notificationsUpdated);
}
}
@override
Future<void> dispose() async {
_firebaseNotificationStream?.cancel();
_pendingNotificationsCountStreamController.close();
_notificationsStreamController.close();
}
@override
Future<void> subscribe() async {
await _firebaseFirestore
.collection(_notificationsCollection)
.doc(userId)
.set({'has_subscribed': true});
_firebaseNotificationStream?.cancel(); // To be safe we cancel old subscription if there is any
_firebaseNotificationStream = _firebaseFirestore
.collection(_notificationsCollection)
.doc(userId)
.collection(_notificationsDataCollection)
.snapshots()
.listen(_notificationsUpdated);
}
@override
Future<void> unsubscribe() async {
await _firebaseFirestore
.collection(_notificationsCollection)
.doc(userId)
.set({'has_subscribed': false});
_firebaseNotificationStream?.cancel();
}
@override
Future<void> push(List<String> userIds, InternalNotification notification) async {
for (final id in userIds) {
await _firebaseFirestore
.collection(_notificationsCollection)
.doc(id)
.collection(_notificationsDataCollection)
.add(notification.toJson());
}
}
void _notificationsUpdated(QuerySnapshot<Map<String, dynamic>> event) {
int count = 0;
final List<InternalNotification> updatedNotifications = [];
for (final doc in event.docs) {
final InternalNotification notification = InternalNotification.fromJson(doc.data());
if (!notification.opened) count++;
updatedNotifications.add(notification);
}
_pendingNotificationsCountStreamController.add(count);
_notificationsStreamController.add(updatedNotifications);
_notifications = updatedNotifications;
}
}