MaikuB / flutter_local_notifications

A Flutter plugin for displaying local notifications on Android, iOS, macOS and Linux
2.47k stars 1.4k forks source link

Status bar icon disappear when grouped notification occurs #2427

Open hadiarshad5 opened 1 month ago

hadiarshad5 commented 1 month ago

class PushNotificationService { final ScreenshotController screenshotController = ScreenshotController(); final String projectId = 'flirt-to-go'; final String serviceAccountJsonPath = 'assets/service_account.json'; AndroidNotificationChannel senderChannel = AndroidNotificationChannel( 'FlirtToGo_Sender_Channel', 'FlirtToGo Individual Notifications', importance: Importance.max, );

AndroidNotificationChannel groupChannel = AndroidNotificationChannel( 'FlirtToGo_Group_Channel', 'FlirtToGo Group Summary Notifications', importance: Importance.low, ); FirebaseMessaging messaging = FirebaseMessaging.instance;

final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

Future foregroundMessage() async { await FirebaseMessaging.instance .setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); }

Future _getOauth2AccessToken() async { var scopes = ['https://www.googleapis.com/auth/firebase.messaging']; final jsonString = await rootBundle.loadString(serviceAccountJsonPath); var credentials = ServiceAccountCredentials.fromJson(jsonString); var client = await clientViaServiceAccount(credentials, scopes); return (client.credentials.accessToken).data; }

Future requestNotificationPermission() async { NotificationSettings settings = await messaging.requestPermission( alert: true, announcement: true, badge: true, carPlay: true, criticalAlert: true, provisional: true, sound: true, );

if (settings.authorizationStatus == AuthorizationStatus.authorized) {
  if (kDebugMode) {
    print('User permission granted.');
  }
} else if (settings.authorizationStatus ==
    AuthorizationStatus.provisional) {
  if (kDebugMode) {
    print('User permission granted provisionally.');
  }
} else {
  AppSettings.openAppSettings(type: AppSettingsType.notification);
}

}

Future getDeviceToken() async { String? token = await messaging.getToken(); return token!; }

Future sendPushNotificationApi(String body) async { try { String accessToken = await _getOauth2AccessToken();

  final response = await http.post(
    Uri.parse(
        'https://fcm.googleapis.com/v1/projects/$projectId/messages:send'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer $accessToken',
    },
    body: body,
  );

  if (response.statusCode == 200) {
    if (kDebugMode) {
      print('Notification Sent');
    }
  } else {
    if (kDebugMode) {
      print('FCM request failed with status: ${response.statusCode}');
    }
    if (kDebugMode) {
      print('Response body: ${response.body}');
    }
  }
} catch (e) {
  if (kDebugMode) {
    print('Error sending FCM request: $e');
  }
}

}

void serviceInit() async { initLocalNotifications();

// Use the correct listeners for messages
FirebaseMessaging.onMessage.listen((message) {
  if (Platform.isIOS) {
    foregroundMessage();
  }
  showPushNotification(message);
});

}

void initLocalNotifications() async { var androidInitializationSettings = const AndroidInitializationSettings('@mipmap/ic_launcher'); var iosInitializationSettings = const DarwinInitializationSettings();

var initializationSettings = InitializationSettings(
  android: androidInitializationSettings,
  iOS: iosInitializationSettings,
);

await _flutterLocalNotificationsPlugin.initialize(
  initializationSettings,
  onDidReceiveNotificationResponse: (payload) {},
);

}

Future handleMessage(RemoteMessage message) async { WidgetsBinding.instance.addPostFrameCallback((_) async { if (message.data['type'] == 'm') { String endUserJson = message.data['endUser']; Map<String, dynamic> endUserMap = jsonDecode(endUserJson);

    UserDataModel endUser = UserDataModel.fromMap(endUserMap);

    Get.toNamed(RouteName.chat_screen,
        arguments: {'endUser': endUser, 'chatRoom': null});
  } else if (message.data['type'] == 'r') {
    Get.toNamed(RouteName.notification_screen);
  }
});

}

Future groupNotificationOverAll() async { Map<String, List> allMessages = await _retrieveAllMessagesGrouped();

int totalChats = allMessages.keys.length;
int totalMessages =
    allMessages.values.fold(0, (prev, messages) => prev + messages.length);

String content = "$totalChats chats";
await _flutterLocalNotificationsPlugin.show(
  0,
  content,
  "Total messages $totalMessages",
  NotificationDetails(
    android: AndroidNotificationDetails(
      groupChannel.id,
      groupChannel.name,
      importance: Importance.low,
      priority: Priority.low,
      groupKey: "group_key",
      styleInformation: InboxStyleInformation(
        [],
        contentTitle: content,
        summaryText: "$totalMessages messages from $content ",
      ),
      setAsGroupSummary: true,
    ),
  ),
);

}

Future groupNotificationBySender({ required RemoteMessage message, }) async { Uint8List? imageBytes; Person person; AndroidNotificationDetails androidDetails;

String endUserJson = message.data['endUser'];
Map<String, dynamic> endUserMap = jsonDecode(endUserJson);
UserDataModel endUser = UserDataModel.fromMap(endUserMap);
imageBytes = await _captureCombinedIcon(endUser);

String endUserId = message.data['senderUserId'];
String messageText = message.data['body'];
String senderName = message.data['title'];
DateTime messageTime = DateTime.now();

person = Person(
  name: senderName,
  key: endUserId,
  icon: ByteArrayAndroidIcon(imageBytes!),
);

List<String> storedMessages =
    await _retrieveStoredMessagesForUser(endUserId);
storedMessages.add(messageText);
await _saveMessagesForUser(endUserId, messageText);

var messageStyle = MessagingStyleInformation(
  person,
  groupConversation: true,
  messages: storedMessages.map((msg) {
    return Message(msg, messageTime, person);
  }).toList(),
);

androidDetails = AndroidNotificationDetails(
  senderChannel.id,
  senderChannel.name,
  importance: Importance.high,
  priority: Priority.high,
  styleInformation: messageStyle,
  groupKey: "group_key",
  ticker: 'ticker',
  setAsGroupSummary: false,
  largeIcon: ByteArrayAndroidBitmap(imageBytes),
  icon: '@mipmap/ic_launcher',
);

var platformDetails = NotificationDetails(android: androidDetails);

await _flutterLocalNotificationsPlugin.show(
  endUserId.hashCode,
  'New message from $senderName',
  messageText,
  platformDetails,
);

}

Future<Uint8List?> _captureCombinedIcon(UserDataModel endUser) async { final BuildContext context = Get.context!;

Widget combinedIconWidget = Stack(
  children: [
    PrimaryCustomAvatar(
      user: endUser,
      radius: Rx<double>(100),
    ),
    Positioned(
      bottom: -8,
      right: 0,
      child: Image.asset(
        'assets/images/icon.png',
        height: 80.h,
        width: 80.w,
      ),
    ),
  ],
);

combinedIconWidget = MediaQuery(
  data: MediaQuery.of(context),
  child: combinedIconWidget,
);

return await screenshotController.captureFromWidget(combinedIconWidget);

}

Future showPushNotification(RemoteMessage message) async { await groupNotificationBySender(message: message); await groupNotificationOverAll(); }

Future setupInteractMessage() async { RemoteMessage? initialMessage = await FirebaseMessaging.instance.getInitialMessage();

if (initialMessage != null) {
  handleMessage(initialMessage);
}

FirebaseMessaging.onMessageOpenedApp.listen((message) {
  handleMessage(message);
});

}

Future _saveMessagesForUser(String endUserId, String message) async { SharedPreferences prefs = await SharedPreferences.getInstance(); List messages = prefs.getStringList(endUserId) ?? []; messages.add(message); await prefs.setStringList(endUserId, messages); }

Future clearMessagesForUser(String endUserId) async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove(endUserId); await _flutterLocalNotificationsPlugin.cancel(endUserId.hashCode); }

Future<List> _retrieveStoredMessagesForUser(String endUserId) async { SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getStringList(endUserId) ?? []; }

Future<Map<String, List>> _retrieveAllMessagesGrouped() async { SharedPreferences prefs = await SharedPreferences.getInstance(); Map<String, List> allMessages = {}; Set keys = prefs.getKeys();

for (String key in keys) {
  if (key == 'uid') {
    continue;
  }

  List<String> messages = prefs.getStringList(key) ?? [];
  allMessages[key] = messages;
}

return allMessages;

} } I am trying to show grouped notification like whatsapp but issue is that when single notification it is working fine but when second user notification comes means when it grouped the status bar icon disappeared else notification shows in notification centre . Android Please help me resolve this issue