From 2e07b7bcf179033c654b5759bfd80e2604188e9c Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 3 Oct 2024 17:06:59 +0200 Subject: [PATCH] feat: Notification actions on android --- android/app/src/main/AndroidManifest.xml | 3 + lib/utils/background_push.dart | 41 ++++------ .../notification_background_handler.dart | 80 +++++++++++++++++++ lib/utils/push_helper.dart | 14 ++++ 4 files changed, 112 insertions(+), 26 deletions(-) create mode 100644 lib/utils/notification_background_handler.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 167602f73..f7688fc0e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -135,6 +135,9 @@ + + + notificationTap( + response, + client: client, + router: FluffyChatApp.router, + ), + onDidReceiveBackgroundNotificationResponse: notificationTapBackground, ); Logs().v('Flutter Local Notifications initialized'); //firebase.setListeners( @@ -278,7 +284,14 @@ class BackgroundPush { return; } _wentToRoomOnStartup = true; - goToRoom(details.notificationResponse); + final response = details.notificationResponse; + if (response != null) { + notificationTap( + response, + client: client, + router: FluffyChatApp.router, + ); + } }); } @@ -323,30 +336,6 @@ class BackgroundPush { ); } - Future goToRoom(NotificationResponse? response) async { - try { - final roomId = response?.payload; - Logs().v('[Push] Attempting to go to room $roomId...'); - if (roomId == null) { - return; - } - await client.roomsLoading; - await client.accountDataLoading; - if (client.getRoomById(roomId) == null) { - await client - .waitForRoomInSync(roomId) - .timeout(const Duration(seconds: 30)); - } - FluffyChatApp.router.go( - client.getRoomById(roomId)?.membership == Membership.invite - ? '/rooms' - : '/rooms/$roomId', - ); - } catch (e, s) { - Logs().e('[Push] Failed to open room', e, s); - } - } - Future setupUp() async { await UnifiedPushUi(matrix!.context, ["default"], UPFunctions()) .registerAppWithDialog(); diff --git a/lib/utils/notification_background_handler.dart b/lib/utils/notification_background_handler.dart new file mode 100644 index 000000000..e604ddcad --- /dev/null +++ b/lib/utils/notification_background_handler.dart @@ -0,0 +1,80 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:fluffychat/utils/client_manager.dart'; + +@pragma('vm:entry-point') +void notificationTapBackground( + NotificationResponse notificationResponse, +) async { + final client = (await ClientManager.getClients( + initialize: false, + store: await SharedPreferences.getInstance(), + )) + .first; + notificationTap(notificationResponse, client: client); +} + +void notificationTap( + NotificationResponse notificationResponse, { + GoRouter? router, + required Client client, +}) async { + switch (notificationResponse.notificationResponseType) { + case NotificationResponseType.selectedNotification: + final roomId = notificationResponse.payload; + if (roomId == null) return; + + if (router == null) { + Logs().v('Ignore select notification action in background mode'); + return; + } + Logs().v('Open room from notification tap', roomId); + await client.roomsLoading; + await client.accountDataLoading; + if (client.getRoomById(roomId) == null) { + await client + .waitForRoomInSync(roomId) + .timeout(const Duration(seconds: 30)); + } + router.go( + client.getRoomById(roomId)?.membership == Membership.invite + ? '/rooms' + : '/rooms/$roomId', + ); + case NotificationResponseType.selectedNotificationAction: + final actionType = FluffyChatNotificationActions.values.singleWhereOrNull( + (action) => action.name == notificationResponse.actionId, + ); + if (actionType == null) { + throw Exception('Selected notification with action but no action ID'); + } + final roomId = notificationResponse.payload; + if (roomId == null) { + throw Exception('Selected notification with action but no payload'); + } + final room = client.getRoomById(roomId); + if (room == null) { + throw Exception( + 'Selected notification with action but unknown room $roomId', + ); + } + switch (actionType) { + case FluffyChatNotificationActions.markAsRead: + await room.setReadMarker(room.lastEvent!.eventId); + case FluffyChatNotificationActions.reply: + final input = notificationResponse.input; + if (input == null || input.isEmpty) { + throw Exception( + 'Selected notification with reply action but without input', + ); + } + await room.sendTextEvent(input); + } + } +} + +enum FluffyChatNotificationActions { markAsRead, reply } diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index 39f6bd90f..078746c61 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -15,6 +15,7 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/utils/client_download_content_extension.dart'; import 'package:fluffychat/utils/client_manager.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; +import 'package:fluffychat/utils/notification_background_handler.dart'; import 'package:fluffychat/utils/platform_infos.dart'; const notificationAvatarDimension = 128; @@ -277,6 +278,19 @@ Future _tryPushHelper( importance: Importance.high, priority: Priority.max, groupKey: event.room.spaceParents.firstOrNull?.roomId ?? 'rooms', + actions: [ + AndroidNotificationAction( + FluffyChatNotificationActions.markAsRead.name, + l10n.markAsRead, + ), + AndroidNotificationAction( + FluffyChatNotificationActions.reply.name, + l10n.reply, + inputs: [ + const AndroidNotificationActionInput(), + ], + ), + ], ); const iOSPlatformChannelSpecifics = DarwinNotificationDetails(); final platformChannelSpecifics = NotificationDetails(