253 lines
7.3 KiB
Dart
253 lines
7.3 KiB
Dart
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
class NotificationService {
|
|
static final NotificationService _instance = NotificationService._internal();
|
|
factory NotificationService() => _instance;
|
|
NotificationService._internal();
|
|
|
|
FirebaseMessaging? _messaging;
|
|
|
|
static const String vapidKey = 'BKrFSFm2cb2DNtEpTNmEy3acpi2ziRA5DhzKSyjshqAWANaoydztUTa0Cn3jwh1v7KN6pHUQfsODFXUWrKG6aSU';
|
|
|
|
static const List<String> topics = [
|
|
'all',
|
|
'newposts',
|
|
'newinvites',
|
|
'invitesfollowup',
|
|
'appnews',
|
|
];
|
|
|
|
Future<void> initialize() async {
|
|
try {
|
|
if (!kIsWeb) {
|
|
print('Notifications are only supported on web platform');
|
|
return;
|
|
}
|
|
|
|
if (!_isNotificationSupported()) {
|
|
print('Notifications are not supported in this browser');
|
|
return;
|
|
}
|
|
|
|
_messaging = FirebaseMessaging.instance;
|
|
await _setupMessageHandlers();
|
|
} catch (e) {
|
|
print('Error initializing notifications: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> requestPermissionAndSetup() async {
|
|
try {
|
|
if (!kIsWeb) {
|
|
print('Notifications are only supported on web platform');
|
|
return;
|
|
}
|
|
|
|
if (!_isNotificationSupported()) {
|
|
print('Notifications are not supported in this browser');
|
|
return;
|
|
}
|
|
|
|
if (_messaging == null) {
|
|
_messaging = FirebaseMessaging.instance;
|
|
await _setupMessageHandlers();
|
|
}
|
|
|
|
await _requestPermission();
|
|
await _subscribeToTopics();
|
|
} catch (e) {
|
|
print('Error requesting notification permission: $e');
|
|
}
|
|
}
|
|
|
|
bool _isNotificationSupported() {
|
|
if (!kIsWeb) return false;
|
|
|
|
// Check if the browser supports notifications
|
|
try {
|
|
// This will throw an error if notifications are not supported
|
|
return true; // Firebase already handles browser support checks
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> _requestPermission() async {
|
|
if (_messaging == null) return;
|
|
|
|
try {
|
|
NotificationSettings settings = await _messaging!.requestPermission(
|
|
alert: true,
|
|
announcement: false,
|
|
badge: true,
|
|
carPlay: false,
|
|
criticalAlert: false,
|
|
provisional: false,
|
|
sound: true,
|
|
);
|
|
|
|
print('User granted permission: ${settings.authorizationStatus}');
|
|
|
|
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
|
print('User granted permission for notifications');
|
|
} else if (settings.authorizationStatus == AuthorizationStatus.provisional) {
|
|
print('User granted provisional permission for notifications');
|
|
} else {
|
|
print('User declined or has not accepted permission for notifications');
|
|
}
|
|
} catch (e) {
|
|
print('Error requesting notification permission: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _subscribeToTopics() async {
|
|
if (_messaging == null) return;
|
|
|
|
for (String topic in topics) {
|
|
try {
|
|
await _messaging!.subscribeToTopic(topic);
|
|
print('Subscribed to topic: $topic');
|
|
} catch (e) {
|
|
print('Error subscribing to topic $topic: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _setupMessageHandlers() async {
|
|
if (_messaging == null) return;
|
|
|
|
// Handle foreground messages
|
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
|
print('Got a message whilst in the foreground!');
|
|
print('Message data: ${message.data}');
|
|
|
|
if (message.notification != null) {
|
|
print('Message also contained a notification: ${message.notification}');
|
|
_showNotification(message.notification!);
|
|
}
|
|
});
|
|
|
|
// Handle background messages
|
|
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
|
|
|
// Handle notification taps
|
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
|
print('A new onMessageOpenedApp event was published!');
|
|
print('Message data: ${message.data}');
|
|
_handleNotificationTap(message);
|
|
});
|
|
|
|
// Get the initial message if the app was opened from a notification
|
|
RemoteMessage? initialMessage = await _messaging!.getInitialMessage();
|
|
if (initialMessage != null) {
|
|
print('App opened from notification: ${initialMessage.data}');
|
|
_handleNotificationTap(initialMessage);
|
|
}
|
|
|
|
// Get the FCM token for this device
|
|
String? token = await _messaging!.getToken(vapidKey: vapidKey);
|
|
print('FCM Token: $token');
|
|
}
|
|
|
|
void _showNotification(RemoteNotification notification) {
|
|
// For web, we rely on the service worker to show notifications
|
|
// This is mainly for logging and debugging
|
|
print('Notification Title: ${notification.title}');
|
|
print('Notification Body: ${notification.body}');
|
|
}
|
|
|
|
void _handleNotificationTap(RemoteMessage message) {
|
|
// Handle notification tap actions here
|
|
print('Notification tapped: ${message.data}');
|
|
|
|
// You can navigate to specific screens based on the notification data
|
|
// For example:
|
|
// if (message.data['type'] == 'newpost') {
|
|
// // Navigate to posts screen
|
|
// } else if (message.data['type'] == 'newinvite') {
|
|
// // Navigate to invitations screen
|
|
// }
|
|
}
|
|
|
|
Future<void> unsubscribeFromTopic(String topic) async {
|
|
if (_messaging == null) return;
|
|
|
|
try {
|
|
await _messaging!.unsubscribeFromTopic(topic);
|
|
print('Unsubscribed from topic: $topic');
|
|
} catch (e) {
|
|
print('Error unsubscribing from topic $topic: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> subscribeToTopic(String topic) async {
|
|
if (_messaging == null) return;
|
|
|
|
try {
|
|
await _messaging!.subscribeToTopic(topic);
|
|
print('Subscribed to topic: $topic');
|
|
} catch (e) {
|
|
print('Error subscribing to topic $topic: $e');
|
|
}
|
|
}
|
|
|
|
Future<String?> getToken() async {
|
|
if (_messaging == null) return null;
|
|
return await _messaging!.getToken(vapidKey: vapidKey);
|
|
}
|
|
|
|
Future<NotificationStatus> getNotificationStatus() async {
|
|
if (!kIsWeb) {
|
|
return NotificationStatus.notSupported;
|
|
}
|
|
|
|
if (!_isNotificationSupported()) {
|
|
return NotificationStatus.notSupported;
|
|
}
|
|
|
|
if (_messaging == null) {
|
|
return NotificationStatus.notInitialized;
|
|
}
|
|
|
|
try {
|
|
NotificationSettings settings = await _messaging!.getNotificationSettings();
|
|
|
|
switch (settings.authorizationStatus) {
|
|
case AuthorizationStatus.authorized:
|
|
return NotificationStatus.enabled;
|
|
case AuthorizationStatus.provisional:
|
|
return NotificationStatus.provisional;
|
|
case AuthorizationStatus.denied:
|
|
return NotificationStatus.denied;
|
|
case AuthorizationStatus.notDetermined:
|
|
return NotificationStatus.notDetermined;
|
|
default:
|
|
return NotificationStatus.denied;
|
|
}
|
|
} catch (e) {
|
|
print('Error getting notification status: $e');
|
|
return NotificationStatus.error;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum NotificationStatus {
|
|
enabled,
|
|
provisional,
|
|
denied,
|
|
notDetermined,
|
|
notSupported,
|
|
notInitialized,
|
|
error
|
|
}
|
|
|
|
// Background message handler must be a top-level function
|
|
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
|
print('Handling a background message: ${message.messageId}');
|
|
print('Message data: ${message.data}');
|
|
|
|
if (message.notification != null) {
|
|
print('Background message contained a notification: ${message.notification}');
|
|
}
|
|
} |