Files
mywhatsapp/whatsapp_app/lib/services/firebase_service.dart
2026-05-18 14:22:09 +03:00

121 lines
3.8 KiB
Dart

import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart';
import '../models/conversation_model.dart';
import '../screens/chat_screen.dart';
import 'whatsapp_service.dart';
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// We can't access GetX services easily here since it's a separate isolate,
// but Firebase automatically shows the notification.
print("Handling a background message: ${message.messageId}");
}
class FirebaseService extends GetxService {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin();
Future<FirebaseService> init() async {
// 1. Request Permission
await _messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
// 2. Initialize Local Notifications (for foreground)
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
const iosInit = DarwinInitializationSettings();
const initSettings = InitializationSettings(android: androidInit, iOS: iosInit);
await _localNotifications.initialize(
initSettings,
onDidReceiveNotificationResponse: _onNotificationTap,
);
// 3. Background Handler
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// 4. Foreground Message Handler
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final chatId = message.data['chatId'];
final activeChatId = Get.find<WhatsAppService>().activeChatId.value;
// Smart Notification: Only show if we are NOT currently in this chat
if (chatId != null && activeChatId == chatId) {
print('[FCM] Silent notification, user is currently in chat $chatId');
return; // Silent
}
_showLocalNotification(message);
});
// 5. Handle tapping on a background notification when app opens
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
_handleNotificationClick(message.data);
});
// 6. Check if app was opened from a terminated state via a notification
final initialMessage = await _messaging.getInitialMessage();
if (initialMessage != null) {
Future.delayed(const Duration(seconds: 1), () {
_handleNotificationClick(initialMessage.data);
});
}
return this;
}
void _showLocalNotification(RemoteMessage message) {
final notification = message.notification;
if (notification == null) return;
const androidDetails = AndroidNotificationDetails(
'whatsapp_channel',
'WhatsApp Messages',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker',
);
const iosDetails = DarwinNotificationDetails();
const details = NotificationDetails(android: androidDetails, iOS: iosDetails);
_localNotifications.show(
notification.hashCode,
notification.title,
notification.body,
details,
payload: jsonEncode(message.data),
);
}
void _onNotificationTap(NotificationResponse response) {
if (response.payload != null) {
final data = jsonDecode(response.payload!);
_handleNotificationClick(data);
}
}
void _handleNotificationClick(Map<String, dynamic> data) {
final chatId = data['chatId'];
final name = data['name'] ?? 'Chat';
if (chatId != null) {
// Mock a conversation model to navigate to ChatScreen
final dummyChat = ConversationModel(
id: chatId,
name: name,
isGroup: false,
unreadCount: 0,
timestamp: 0,
pinned: false,
isMuted: false,
);
Get.to(() => ChatScreen(conversation: dummyChat));
}
}
}