import 'dart:convert'; import 'dart:developer'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; import 'package:user_repository/user_repository.dart'; import 'package:prosappco/constansts.dart' show API_BASE_URL; part 'notification_event.dart'; part 'notification_state.dart'; // Handles FCM messages when app is terminated/background @pragma('vm:entry-point') Future firebaseMessagingBackgroundHandler(RemoteMessage message) async { // Local notification shown by the system tray automatically for data-only // messages; nothing extra needed here. } class NotificationBloc extends Bloc { final Future Function() requestLocalNotificationPermission; final void Function({ required int id, String? title, String? body, String? data, }) showLocalNotification; NotificationBloc( {required this.requestLocalNotificationPermission, required this.showLocalNotification}) : super(const NotificationState()) { on(_notificationStatusChanged); } void _notificationStatusChanged( NotificationStatusChanged event, Emitter emit) { emit(state.copyWith(status: event.status)); } // Call once after login to register the FCM token and listen for foreground messages. Future initializePushNotifications() async { try { final messaging = FirebaseMessaging.instance; final settings = await messaging.requestPermission(); add(NotificationStatusChanged( settings.authorizationStatus == AuthorizationStatus.authorized || settings.authorizationStatus == AuthorizationStatus.provisional ? AuthorizationStatus.authorized : AuthorizationStatus.denied, )); final token = await messaging.getToken(); if (token != null) await _registerToken(token); // Refresh token (e.g. after reinstall) messaging.onTokenRefresh.listen(_registerToken); // Show local notification when app is in foreground FirebaseMessaging.onMessage.listen((RemoteMessage message) { final n = message.notification; if (n != null) { showLocalNotification( id: message.hashCode, title: n.title, body: n.body, data: jsonEncode(message.data), ); } }); } catch (e) { log('NotificationBloc.initializePushNotifications error: $e'); } } Future _registerToken(String token) async { try { final prefs = await SharedPreferences.getInstance(); final jwt = prefs.getString('token'); if (jwt == null) return; await http.patch( Uri.parse('$API_BASE_URL/users/me/fcm-token'), headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $jwt', }, body: jsonEncode({'token': token}), ); log('FCM token registered'); } catch (e) { log('NotificationBloc._registerToken error: $e'); } } void requestPermission() async { try { await requestLocalNotificationPermission(); } catch (e) { log('NotificationBloc.requestPermission error: $e'); } } }