From 21e7c3f8cb3898306ba47788a962fba4ef24673d Mon Sep 17 00:00:00 2001 From: Krille Date: Mon, 29 Jul 2024 08:36:54 +0200 Subject: [PATCH 1/4] build: Update matrix dart sdk --- assets/l10n/intl_en.arb | 6 ++++++ lib/pages/settings/settings.dart | 2 -- lib/utils/matrix_sdk_extensions/matrix_locals.dart | 3 +++ pubspec.lock | 4 ++-- pubspec.yaml | 4 ++-- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 7132187c1..30a8f9131 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2279,6 +2279,12 @@ "user": {} } }, + "invitedBy": "📩 Invited by {user}", + "@invitedBy": { + "placeholders": { + "user": {} + } + }, "youInvitedUser": "📩 You invited {user}", "@youInvitedUser": { "placeholders": { diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 97bbec66d..d844063b1 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -209,8 +209,6 @@ class SettingsController extends State { final client = Matrix.of(context).client; profileFuture ??= client.getProfileFromUserId( client.userID!, - cache: !profileUpdated, - getFromRooms: !profileUpdated, ); return SettingsView(this); } diff --git a/lib/utils/matrix_sdk_extensions/matrix_locals.dart b/lib/utils/matrix_sdk_extensions/matrix_locals.dart index 5714baa22..cbba6b630 100644 --- a/lib/utils/matrix_sdk_extensions/matrix_locals.dart +++ b/lib/utils/matrix_sdk_extensions/matrix_locals.dart @@ -344,4 +344,7 @@ class MatrixLocals extends MatrixLocalizations { @override String startedKeyVerification(String senderName) => l10n.startedKeyVerification(senderName); + + @override + String invitedBy(String senderName) => l10n.invitedBy(senderName); } diff --git a/pubspec.lock b/pubspec.lock index 7e3909e54..c46a3944f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1210,10 +1210,10 @@ packages: dependency: "direct main" description: name: matrix - sha256: a27c2f73d28ea292e0f67f3d36396fb8acd7cfc97a07901dc7b22f46e082c3d6 + sha256: d1955846aaf5a5c6d353a90ce4133b9c99581cd64f4fe9e389e5f8b95157ca3b url: "https://pub.dev" source: hosted - version: "0.30.0" + version: "0.31.0" meta: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a013aeea3..69c80d6e1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: keyboard_shortcuts: ^0.1.4 latlong2: ^0.9.1 linkify: ^5.0.0 - matrix: ^0.30.0 + matrix: ^0.31.0 native_imaging: ^0.1.1 package_info_plus: ^6.0.0 pasteboard: ^0.2.0 @@ -160,4 +160,4 @@ dependency_overrides: git: url: https://github.com/TheOneWithTheBraid/keyboard_shortcuts.git ref: null-safety - win32: 5.5.0 \ No newline at end of file + win32: 5.5.0 From e5bbb755d99c54ec051d66c9cdbf37b2f8568e18 Mon Sep 17 00:00:00 2001 From: Krille Date: Wed, 31 Jul 2024 15:23:25 +0200 Subject: [PATCH 2/4] design: Add snackbar with link to changelog on new version --- assets/l10n/intl_en.arb | 10 +++- lib/config/app_config.dart | 2 + lib/config/themes.dart | 3 -- lib/pages/chat_list/chat_list.dart | 2 + .../chat_list/client_chooser_button.dart | 6 ++- lib/utils/show_update_snackbar.dart | 52 +++++++++++++++++++ 6 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 lib/utils/show_update_snackbar.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 30a8f9131..1ec5f8327 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2746,5 +2746,13 @@ "changeTheCanonicalRoomAlias": "Change the main public chat address", "sendRoomNotifications": "Send a @room notifications", "changeTheDescriptionOfTheGroup": "Change the description of the chat", - "chatPermissionsDescription": "Define which power level is necessary for certain actions in this chat. The power levels 0, 50 and 100 are usually representing users, moderators and admins, but any gradation is possible." + "chatPermissionsDescription": "Define which power level is necessary for certain actions in this chat. The power levels 0, 50 and 100 are usually representing users, moderators and admins, but any gradation is possible.", + "updateInstalled": "🎉 Update {version} installed!", + "@updateInstalled": { + "type": "text", + "placeholders": { + "version": {} + } + }, + "changelog": "Changelog" } diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 298b8743c..2c1ee1f4c 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -35,6 +35,8 @@ abstract class AppConfig { 'https://github.com/krille-chan/fluffychat'; static const String supportUrl = 'https://github.com/krille-chan/fluffychat/issues'; + static const String changelogUrl = + 'https://github.com/krille-chan/fluffychat/blob/main/CHANGELOG.md'; static final Uri newIssueUrl = Uri( scheme: 'https', host: 'github.com', diff --git a/lib/config/themes.dart b/lib/config/themes.dart index fc1ec0b4c..f83b69a2b 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -77,9 +77,6 @@ abstract class FluffyThemes { ? Typography.material2018().black.merge(fallbackTextTheme) : Typography.material2018().white.merge(fallbackTextTheme) : null, - snackBarTheme: const SnackBarThemeData( - behavior: SnackBarBehavior.floating, - ), dividerColor: brightness == Brightness.light ? Colors.blueGrey.shade50 : Colors.blueGrey.shade900, diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 99d31bf58..7b89f0997 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -21,6 +21,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_view.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:fluffychat/utils/show_update_snackbar.dart'; import 'package:fluffychat/widgets/avatar.dart'; import '../../../utils/account_bundles.dart'; import '../../config/setting_keys.dart'; @@ -511,6 +512,7 @@ class ChatListController extends State searchServer = Matrix.of(context).store.getString(_serverStoreNamespace); Matrix.of(context).backgroundPush?.setupPush(); + UpdateNotifier.showUpdateSnackBar(context); } // Workaround for system UI overlay style not applied on app start diff --git a/lib/pages/chat_list/client_chooser_button.dart b/lib/pages/chat_list/client_chooser_button.dart index d937b7cb1..c004bd167 100644 --- a/lib/pages/chat_list/client_chooser_button.dart +++ b/lib/pages/chat_list/client_chooser_button.dart @@ -68,7 +68,9 @@ class ClientChooserButton extends StatelessWidget { ], ), ), - PopupMenuItem( + // Currently disabled because of: + // https://github.com/matrix-org/matrix-react-sdk/pull/12286 + /*PopupMenuItem( value: SettingsAction.archive, child: Row( children: [ @@ -77,7 +79,7 @@ class ClientChooserButton extends StatelessWidget { Text(L10n.of(context)!.archive), ], ), - ), + ),*/ PopupMenuItem( value: SettingsAction.settings, child: Row( diff --git a/lib/utils/show_update_snackbar.dart b/lib/utils/show_update_snackbar.dart new file mode 100644 index 000000000..96d08378e --- /dev/null +++ b/lib/utils/show_update_snackbar.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; + +abstract class UpdateNotifier { + static const String versionStoreKey = 'last_known_version'; + + static void showUpdateSnackBar(BuildContext context) async { + final scaffoldMessenger = ScaffoldMessenger.of(context); + final currentVersion = await PlatformInfos.getVersion(); + final store = await SharedPreferences.getInstance(); + final storedVersion = store.getString(versionStoreKey); + + if (currentVersion != storedVersion) { + if (storedVersion != null) { + ScaffoldFeatureController? controller; + controller = scaffoldMessenger.showSnackBar( + SnackBar( + duration: const Duration(seconds: 30), + content: Row( + children: [ + IconButton( + icon: Icon( + Icons.close_outlined, + size: 20, + color: Theme.of(context).colorScheme.onPrimary, + ), + onPressed: () => controller?.close(), + ), + Expanded( + child: Text( + L10n.of(context)!.updateInstalled(currentVersion), + ), + ), + ], + ), + action: SnackBarAction( + label: L10n.of(context)!.changelog, + onPressed: () => launchUrlString(AppConfig.changelogUrl), + ), + ), + ); + } + await store.setString(versionStoreKey, currentVersion); + } + } +} From d3a13705bde9195d0c86825382d787493607a2d2 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 1 Aug 2024 09:18:12 +0200 Subject: [PATCH 3/4] refactor: Only initialize FlutterLocalNotificationsPlugin once --- lib/utils/background_push.dart | 4 +- lib/utils/push_helper.dart | 601 +++++++++++++++++---------------- 2 files changed, 309 insertions(+), 296 deletions(-) diff --git a/lib/utils/background_push.dart b/lib/utils/background_push.dart index 039dde895..a561ea371 100644 --- a/lib/utils/background_push.dart +++ b/lib/utils/background_push.dart @@ -71,7 +71,7 @@ class BackgroundPush { BackgroundPush._(this.client) { firebase?.setListeners( - onMessage: (message) => pushHelper( + onMessage: (message) => PushHelper.processNotification( PushNotification.fromJson( Map.from(message['data'] ?? message), ), @@ -393,7 +393,7 @@ class BackgroundPush { ); // UP may strip the devices list data['devices'] ??= []; - await pushHelper( + await PushHelper.processNotification( PushNotification.fromJson(data), client: client, l10n: l10n, diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index edfdb4941..5a7e725ad 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -18,27 +18,20 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/voip/callkeep_manager.dart'; -Future pushHelper( - PushNotification notification, { - Client? client, - L10n? l10n, - String? activeRoomId, - void Function(NotificationResponse?)? onSelectNotification, -}) async { - try { - await _tryPushHelper( - notification, - client: client, - l10n: l10n, - activeRoomId: activeRoomId, - onSelectNotification: onSelectNotification, - ); - } catch (e, s) { - Logs().v('Push Helper has crashed!', e, s); +abstract class PushHelper { + static FlutterLocalNotificationsPlugin? _flutterLocalNotificationsPlugin; + + static Future _getLocalNotificationsPlugin({ + void Function(NotificationResponse?)? onSelectNotification, + }) async { + var flutterlocalNotifcationsPlugin = _flutterLocalNotificationsPlugin; + if (flutterlocalNotifcationsPlugin != null) { + return flutterlocalNotifcationsPlugin; + } - // Initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - await flutterLocalNotificationsPlugin.initialize( + flutterlocalNotifcationsPlugin = + _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + await flutterlocalNotifcationsPlugin.initialize( const InitializationSettings( android: AndroidInitializationSettings('notifications_icon'), iOS: DarwinInitializationSettings(), @@ -46,299 +39,319 @@ Future pushHelper( onDidReceiveNotificationResponse: onSelectNotification, onDidReceiveBackgroundNotificationResponse: onSelectNotification, ); + return flutterlocalNotifcationsPlugin; + } - l10n ??= lookupL10n(const Locale('en')); - flutterLocalNotificationsPlugin.show( - notification.roomId?.hashCode ?? 0, - l10n.newMessageInFluffyChat, - l10n.openAppToReadMessages, - NotificationDetails( - iOS: const DarwinNotificationDetails(), - android: AndroidNotificationDetails( - AppConfig.pushNotificationsChannelId, - l10n.incomingMessages, - number: notification.counts?.unread, - ticker: l10n.unreadChatsInApp( - AppConfig.applicationName, - (notification.counts?.unread ?? 0).toString(), + static Future processNotification( + PushNotification notification, { + Client? client, + L10n? l10n, + String? activeRoomId, + void Function(NotificationResponse?)? onSelectNotification, + }) async { + try { + await _tryPushHelper( + notification, + client: client, + l10n: l10n, + activeRoomId: activeRoomId, + onSelectNotification: onSelectNotification, + ); + } catch (e, s) { + Logs().v('Push Helper has crashed!', e, s); + + final flutterLocalNotificationsPlugin = + await _getLocalNotificationsPlugin( + onSelectNotification: onSelectNotification, + ); + + l10n ??= lookupL10n(const Locale('en')); + flutterLocalNotificationsPlugin.show( + notification.roomId?.hashCode ?? 0, + l10n.newMessageInFluffyChat, + l10n.openAppToReadMessages, + NotificationDetails( + iOS: const DarwinNotificationDetails(), + android: AndroidNotificationDetails( + AppConfig.pushNotificationsChannelId, + l10n.incomingMessages, + number: notification.counts?.unread, + ticker: l10n.unreadChatsInApp( + AppConfig.applicationName, + (notification.counts?.unread ?? 0).toString(), + ), + importance: Importance.high, + priority: Priority.max, + shortcutId: notification.roomId, ), - importance: Importance.high, - priority: Priority.max, - shortcutId: notification.roomId, ), - ), - ); - rethrow; + ); + rethrow; + } } -} -Future _tryPushHelper( - PushNotification notification, { - Client? client, - L10n? l10n, - String? activeRoomId, - void Function(NotificationResponse?)? onSelectNotification, -}) async { - final isBackgroundMessage = client == null; - Logs().v( - 'Push helper has been started (background=$isBackgroundMessage).', - notification.toJson(), - ); - - if (notification.roomId != null && - activeRoomId == notification.roomId && - WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) { - Logs().v('Room is in foreground. Stop push helper here.'); - return; - } + static Future _tryPushHelper( + PushNotification notification, { + Client? client, + L10n? l10n, + String? activeRoomId, + void Function(NotificationResponse?)? onSelectNotification, + }) async { + final isBackgroundMessage = client == null; + Logs().v( + 'Push helper has been started (background=$isBackgroundMessage).', + notification.toJson(), + ); + + if (notification.roomId != null && + activeRoomId == notification.roomId && + WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) { + Logs().v('Room is in foreground. Stop push helper here.'); + return; + } + + final flutterLocalNotificationsPlugin = await _getLocalNotificationsPlugin( + onSelectNotification: onSelectNotification, + ); + + client ??= (await ClientManager.getClients( + initialize: false, + store: await SharedPreferences.getInstance(), + )) + .first; + final event = await client.getEventByPushNotification( + notification, + storeInDatabase: isBackgroundMessage, + ); - // Initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project - final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - await flutterLocalNotificationsPlugin.initialize( - const InitializationSettings( - android: AndroidInitializationSettings('notifications_icon'), - iOS: DarwinInitializationSettings(), - ), - onDidReceiveNotificationResponse: onSelectNotification, - //onDidReceiveBackgroundNotificationResponse: onSelectNotification, - ); - - client ??= (await ClientManager.getClients( - initialize: false, - store: await SharedPreferences.getInstance(), - )) - .first; - final event = await client.getEventByPushNotification( - notification, - storeInDatabase: isBackgroundMessage, - ); - - if (event == null) { - Logs().v('Notification is a clearing indicator.'); - if (notification.counts?.unread == null || - notification.counts?.unread == 0) { - await flutterLocalNotificationsPlugin.cancelAll(); - } else { - // Make sure client is fully loaded and synced before dismiss notifications: - await client.roomsLoading; - await client.oneShotSync(); - final activeNotifications = - await flutterLocalNotificationsPlugin.getActiveNotifications(); - for (final activeNotification in activeNotifications) { - final room = client.rooms.singleWhereOrNull( - (room) => room.id.hashCode == activeNotification.id, - ); - if (room == null || !room.isUnreadOrInvited) { - flutterLocalNotificationsPlugin.cancel(activeNotification.id!); + if (event == null) { + Logs().v('Notification is a clearing indicator.'); + if (notification.counts?.unread == null || + notification.counts?.unread == 0) { + await flutterLocalNotificationsPlugin.cancelAll(); + } else { + // Make sure client is fully loaded and synced before dismiss notifications: + await client.roomsLoading; + await client.oneShotSync(); + final activeNotifications = + await flutterLocalNotificationsPlugin.getActiveNotifications(); + for (final activeNotification in activeNotifications) { + final room = client.rooms.singleWhereOrNull( + (room) => room.id.hashCode == activeNotification.id, + ); + if (room == null || !room.isUnreadOrInvited) { + flutterLocalNotificationsPlugin.cancel(activeNotification.id!); + } } } + return; } - return; - } - Logs().v('Push helper got notification event of type ${event.type}.'); + Logs().v('Push helper got notification event of type ${event.type}.'); - if (event.type.startsWith('m.call')) { - // make sure bg sync is on (needed to update hold, unhold events) - // prevent over write from app life cycle change - client.backgroundSync = true; - } + if (event.type.startsWith('m.call')) { + // make sure bg sync is on (needed to update hold, unhold events) + // prevent over write from app life cycle change + client.backgroundSync = true; + } - if (event.type == EventTypes.CallInvite) { - CallKeepManager().initialize(); - } else if (event.type == EventTypes.CallHangup) { - client.backgroundSync = false; - } + if (event.type == EventTypes.CallInvite) { + CallKeepManager().initialize(); + } else if (event.type == EventTypes.CallHangup) { + client.backgroundSync = false; + } - if (event.type.startsWith('m.call') && event.type != EventTypes.CallInvite) { - Logs().v('Push message is a m.call but not invite. Do not display.'); - return; - } + if (event.type.startsWith('m.call') && + event.type != EventTypes.CallInvite) { + Logs().v('Push message is a m.call but not invite. Do not display.'); + return; + } - if ((event.type.startsWith('m.call') && - event.type != EventTypes.CallInvite) || - event.type == 'org.matrix.call.sdp_stream_metadata_changed') { - Logs().v('Push message was for a call, but not call invite.'); - return; - } + if ((event.type.startsWith('m.call') && + event.type != EventTypes.CallInvite) || + event.type == 'org.matrix.call.sdp_stream_metadata_changed') { + Logs().v('Push message was for a call, but not call invite.'); + return; + } - l10n ??= await L10n.delegate.load(PlatformDispatcher.instance.locale); - final matrixLocals = MatrixLocals(l10n); - - // Calculate the body - final body = event.type == EventTypes.Encrypted - ? l10n.newMessageInFluffyChat - : await event.calcLocalizedBody( - matrixLocals, - plaintextBody: true, - withSenderNamePrefix: false, - hideReply: true, - hideEdit: true, - removeMarkdown: true, - ); - - // The person object for the android message style notification - final avatar = event.room.avatar - ?.getThumbnail( - client, - width: 256, - height: 256, - ) - .toString(); - final senderAvatar = event.room.isDirectChat - ? avatar - : event.senderFromMemoryOrFallback.avatarUrl - ?.getThumbnail( - client, - width: 256, - height: 256, - ) - .toString(); - - File? roomAvatarFile, senderAvatarFile; - try { - roomAvatarFile = avatar == null - ? null - : await DefaultCacheManager().getSingleFile(avatar); - } catch (e, s) { - Logs().e('Unable to get avatar picture', e, s); - } - try { - senderAvatarFile = event.room.isDirectChat - ? roomAvatarFile - : senderAvatar == null + l10n ??= await L10n.delegate.load(PlatformDispatcher.instance.locale); + final matrixLocals = MatrixLocals(l10n); + + // Calculate the body + final body = event.type == EventTypes.Encrypted + ? l10n.newMessageInFluffyChat + : await event.calcLocalizedBody( + matrixLocals, + plaintextBody: true, + withSenderNamePrefix: false, + hideReply: true, + hideEdit: true, + removeMarkdown: true, + ); + + // The person object for the android message style notification + final avatar = event.room.avatar + ?.getThumbnail( + client, + width: 256, + height: 256, + ) + .toString(); + final senderAvatar = event.room.isDirectChat + ? avatar + : event.senderFromMemoryOrFallback.avatarUrl + ?.getThumbnail( + client, + width: 256, + height: 256, + ) + .toString(); + + File? roomAvatarFile, senderAvatarFile; + try { + roomAvatarFile = avatar == null + ? null + : await DefaultCacheManager().getSingleFile(avatar); + } catch (e, s) { + Logs().e('Unable to get avatar picture', e, s); + } + try { + senderAvatarFile = event.room.isDirectChat + ? roomAvatarFile + : senderAvatar == null + ? null + : await DefaultCacheManager().getSingleFile(senderAvatar); + } catch (e, s) { + Logs().e('Unable to get avatar picture', e, s); + } + + final id = notification.roomId.hashCode; + + // Show notification + + final newMessage = Message( + body, + event.originServerTs, + Person( + bot: event.messageType == MessageTypes.Notice, + key: event.senderId, + name: event.senderFromMemoryOrFallback.calcDisplayname(), + icon: senderAvatarFile == null ? null - : await DefaultCacheManager().getSingleFile(senderAvatar); - } catch (e, s) { - Logs().e('Unable to get avatar picture', e, s); - } + : BitmapFilePathAndroidIcon(senderAvatarFile.path), + ), + ); - final id = notification.roomId.hashCode; + final messagingStyleInformation = PlatformInfos.isAndroid + ? await AndroidFlutterLocalNotificationsPlugin() + .getActiveNotificationMessagingStyle(id) + : null; + messagingStyleInformation?.messages?.add(newMessage); - // Show notification + final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); - final newMessage = Message( - body, - event.originServerTs, - Person( - bot: event.messageType == MessageTypes.Notice, - key: event.senderId, - name: event.senderFromMemoryOrFallback.calcDisplayname(), - icon: senderAvatarFile == null - ? null - : BitmapFilePathAndroidIcon(senderAvatarFile.path), - ), - ); - - final messagingStyleInformation = PlatformInfos.isAndroid - ? await AndroidFlutterLocalNotificationsPlugin() - .getActiveNotificationMessagingStyle(id) - : null; - messagingStyleInformation?.messages?.add(newMessage); - - final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); - - final notificationGroupId = - event.room.isDirectChat ? 'directChats' : 'groupChats'; - final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups; - - final messageRooms = AndroidNotificationChannelGroup( - notificationGroupId, - groupName, - ); - final roomsChannel = AndroidNotificationChannel( - event.room.id, - roomName, - groupId: notificationGroupId, - ); - - await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannelGroup(messageRooms); - await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannel(roomsChannel); - - final androidPlatformChannelSpecifics = AndroidNotificationDetails( - AppConfig.pushNotificationsChannelId, - l10n.incomingMessages, - number: notification.counts?.unread, - category: AndroidNotificationCategory.message, - shortcutId: event.room.id, - styleInformation: messagingStyleInformation ?? - MessagingStyleInformation( - Person( - name: event.senderFromMemoryOrFallback.calcDisplayname(), - icon: roomAvatarFile == null - ? null - : BitmapFilePathAndroidIcon(roomAvatarFile.path), - key: event.roomId, - important: event.room.isFavourite, + final notificationGroupId = + event.room.isDirectChat ? 'directChats' : 'groupChats'; + final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups; + + final messageRooms = AndroidNotificationChannelGroup( + notificationGroupId, + groupName, + ); + final roomsChannel = AndroidNotificationChannel( + event.room.id, + roomName, + groupId: notificationGroupId, + ); + + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannelGroup(messageRooms); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(roomsChannel); + + final androidPlatformChannelSpecifics = AndroidNotificationDetails( + AppConfig.pushNotificationsChannelId, + l10n.incomingMessages, + number: notification.counts?.unread, + category: AndroidNotificationCategory.message, + shortcutId: event.room.id, + styleInformation: messagingStyleInformation ?? + MessagingStyleInformation( + Person( + name: event.senderFromMemoryOrFallback.calcDisplayname(), + icon: roomAvatarFile == null + ? null + : BitmapFilePathAndroidIcon(roomAvatarFile.path), + key: event.roomId, + important: event.room.isFavourite, + ), + conversationTitle: roomName, + groupConversation: !event.room.isDirectChat, + messages: [newMessage], ), - conversationTitle: roomName, - groupConversation: !event.room.isDirectChat, - messages: [newMessage], - ), - ticker: event.calcLocalizedBodyFallback( - matrixLocals, - plaintextBody: true, - withSenderNamePrefix: true, - hideReply: true, - hideEdit: true, - removeMarkdown: true, - ), - importance: Importance.high, - priority: Priority.max, - groupKey: notificationGroupId, - ); - const iOSPlatformChannelSpecifics = DarwinNotificationDetails(); - final platformChannelSpecifics = NotificationDetails( - android: androidPlatformChannelSpecifics, - iOS: iOSPlatformChannelSpecifics, - ); - - final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); - - if (PlatformInfos.isAndroid && messagingStyleInformation == null) { - await _setShortcut(event, l10n, title, roomAvatarFile); - } + ticker: event.calcLocalizedBodyFallback( + matrixLocals, + plaintextBody: true, + withSenderNamePrefix: true, + hideReply: true, + hideEdit: true, + removeMarkdown: true, + ), + importance: Importance.high, + priority: Priority.max, + groupKey: notificationGroupId, + ); + const iOSPlatformChannelSpecifics = DarwinNotificationDetails(); + final platformChannelSpecifics = NotificationDetails( + android: androidPlatformChannelSpecifics, + iOS: iOSPlatformChannelSpecifics, + ); - await flutterLocalNotificationsPlugin.show( - id, - title, - body, - platformChannelSpecifics, - payload: event.roomId, - ); - Logs().v('Push helper has been completed!'); -} + final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); -/// Creates a shortcut for Android platform but does not block displaying the -/// notification. This is optional but provides a nicer view of the -/// notification popup. -Future _setShortcut( - Event event, - L10n l10n, - String title, - File? avatarFile, -) async { - final flutterShortcuts = FlutterShortcuts(); - await flutterShortcuts.initialize(debug: !kReleaseMode); - await flutterShortcuts.pushShortcutItem( - shortcut: ShortcutItem( - id: event.room.id, - action: AppConfig.inviteLinkPrefix + event.room.id, - shortLabel: title, - conversationShortcut: true, - icon: avatarFile == null - ? null - : ShortcutMemoryIcon(jpegImage: await avatarFile.readAsBytes()) - .toString(), - shortcutIconAsset: avatarFile == null - ? ShortcutIconAsset.androidAsset - : ShortcutIconAsset.memoryAsset, - isImportant: event.room.isFavourite, - ), - ); + if (PlatformInfos.isAndroid && messagingStyleInformation == null) { + await _setShortcut(event, l10n, title, roomAvatarFile); + } + + await flutterLocalNotificationsPlugin.show( + id, + title, + body, + platformChannelSpecifics, + payload: event.roomId, + ); + Logs().v('Push helper has been completed!'); + } + + /// Creates a shortcut for Android platform but does not block displaying the + /// notification. This is optional but provides a nicer view of the + /// notification popup. + static Future _setShortcut( + Event event, + L10n l10n, + String title, + File? avatarFile, + ) async { + final flutterShortcuts = FlutterShortcuts(); + await flutterShortcuts.initialize(debug: !kReleaseMode); + await flutterShortcuts.pushShortcutItem( + shortcut: ShortcutItem( + id: event.room.id, + action: AppConfig.inviteLinkPrefix + event.room.id, + shortLabel: title, + conversationShortcut: true, + icon: avatarFile == null + ? null + : ShortcutMemoryIcon(jpegImage: await avatarFile.readAsBytes()) + .toString(), + shortcutIconAsset: avatarFile == null + ? ShortcutIconAsset.androidAsset + : ShortcutIconAsset.memoryAsset, + isImportant: event.room.isFavourite, + ), + ); + } } From a928ecec1e0272417fa35ef97112032e6de184f0 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 1 Aug 2024 09:47:49 +0200 Subject: [PATCH 4/4] Revert "refactor: Only initialize FlutterLocalNotificationsPlugin once" This reverts commit d3a13705bde9195d0c86825382d787493607a2d2. --- lib/utils/background_push.dart | 4 +- lib/utils/push_helper.dart | 601 ++++++++++++++++----------------- 2 files changed, 296 insertions(+), 309 deletions(-) diff --git a/lib/utils/background_push.dart b/lib/utils/background_push.dart index a561ea371..039dde895 100644 --- a/lib/utils/background_push.dart +++ b/lib/utils/background_push.dart @@ -71,7 +71,7 @@ class BackgroundPush { BackgroundPush._(this.client) { firebase?.setListeners( - onMessage: (message) => PushHelper.processNotification( + onMessage: (message) => pushHelper( PushNotification.fromJson( Map.from(message['data'] ?? message), ), @@ -393,7 +393,7 @@ class BackgroundPush { ); // UP may strip the devices list data['devices'] ??= []; - await PushHelper.processNotification( + await pushHelper( PushNotification.fromJson(data), client: client, l10n: l10n, diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index 5a7e725ad..edfdb4941 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -18,20 +18,27 @@ import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/voip/callkeep_manager.dart'; -abstract class PushHelper { - static FlutterLocalNotificationsPlugin? _flutterLocalNotificationsPlugin; - - static Future _getLocalNotificationsPlugin({ - void Function(NotificationResponse?)? onSelectNotification, - }) async { - var flutterlocalNotifcationsPlugin = _flutterLocalNotificationsPlugin; - if (flutterlocalNotifcationsPlugin != null) { - return flutterlocalNotifcationsPlugin; - } +Future pushHelper( + PushNotification notification, { + Client? client, + L10n? l10n, + String? activeRoomId, + void Function(NotificationResponse?)? onSelectNotification, +}) async { + try { + await _tryPushHelper( + notification, + client: client, + l10n: l10n, + activeRoomId: activeRoomId, + onSelectNotification: onSelectNotification, + ); + } catch (e, s) { + Logs().v('Push Helper has crashed!', e, s); - flutterlocalNotifcationsPlugin = - _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - await flutterlocalNotifcationsPlugin.initialize( + // Initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project + final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + await flutterLocalNotificationsPlugin.initialize( const InitializationSettings( android: AndroidInitializationSettings('notifications_icon'), iOS: DarwinInitializationSettings(), @@ -39,319 +46,299 @@ abstract class PushHelper { onDidReceiveNotificationResponse: onSelectNotification, onDidReceiveBackgroundNotificationResponse: onSelectNotification, ); - return flutterlocalNotifcationsPlugin; - } - static Future processNotification( - PushNotification notification, { - Client? client, - L10n? l10n, - String? activeRoomId, - void Function(NotificationResponse?)? onSelectNotification, - }) async { - try { - await _tryPushHelper( - notification, - client: client, - l10n: l10n, - activeRoomId: activeRoomId, - onSelectNotification: onSelectNotification, - ); - } catch (e, s) { - Logs().v('Push Helper has crashed!', e, s); - - final flutterLocalNotificationsPlugin = - await _getLocalNotificationsPlugin( - onSelectNotification: onSelectNotification, - ); - - l10n ??= lookupL10n(const Locale('en')); - flutterLocalNotificationsPlugin.show( - notification.roomId?.hashCode ?? 0, - l10n.newMessageInFluffyChat, - l10n.openAppToReadMessages, - NotificationDetails( - iOS: const DarwinNotificationDetails(), - android: AndroidNotificationDetails( - AppConfig.pushNotificationsChannelId, - l10n.incomingMessages, - number: notification.counts?.unread, - ticker: l10n.unreadChatsInApp( - AppConfig.applicationName, - (notification.counts?.unread ?? 0).toString(), - ), - importance: Importance.high, - priority: Priority.max, - shortcutId: notification.roomId, + l10n ??= lookupL10n(const Locale('en')); + flutterLocalNotificationsPlugin.show( + notification.roomId?.hashCode ?? 0, + l10n.newMessageInFluffyChat, + l10n.openAppToReadMessages, + NotificationDetails( + iOS: const DarwinNotificationDetails(), + android: AndroidNotificationDetails( + AppConfig.pushNotificationsChannelId, + l10n.incomingMessages, + number: notification.counts?.unread, + ticker: l10n.unreadChatsInApp( + AppConfig.applicationName, + (notification.counts?.unread ?? 0).toString(), ), + importance: Importance.high, + priority: Priority.max, + shortcutId: notification.roomId, ), - ); - rethrow; - } - } - - static Future _tryPushHelper( - PushNotification notification, { - Client? client, - L10n? l10n, - String? activeRoomId, - void Function(NotificationResponse?)? onSelectNotification, - }) async { - final isBackgroundMessage = client == null; - Logs().v( - 'Push helper has been started (background=$isBackgroundMessage).', - notification.toJson(), - ); - - if (notification.roomId != null && - activeRoomId == notification.roomId && - WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) { - Logs().v('Room is in foreground. Stop push helper here.'); - return; - } - - final flutterLocalNotificationsPlugin = await _getLocalNotificationsPlugin( - onSelectNotification: onSelectNotification, + ), ); + rethrow; + } +} - client ??= (await ClientManager.getClients( - initialize: false, - store: await SharedPreferences.getInstance(), - )) - .first; - final event = await client.getEventByPushNotification( - notification, - storeInDatabase: isBackgroundMessage, - ); +Future _tryPushHelper( + PushNotification notification, { + Client? client, + L10n? l10n, + String? activeRoomId, + void Function(NotificationResponse?)? onSelectNotification, +}) async { + final isBackgroundMessage = client == null; + Logs().v( + 'Push helper has been started (background=$isBackgroundMessage).', + notification.toJson(), + ); + + if (notification.roomId != null && + activeRoomId == notification.roomId && + WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) { + Logs().v('Room is in foreground. Stop push helper here.'); + return; + } - if (event == null) { - Logs().v('Notification is a clearing indicator.'); - if (notification.counts?.unread == null || - notification.counts?.unread == 0) { - await flutterLocalNotificationsPlugin.cancelAll(); - } else { - // Make sure client is fully loaded and synced before dismiss notifications: - await client.roomsLoading; - await client.oneShotSync(); - final activeNotifications = - await flutterLocalNotificationsPlugin.getActiveNotifications(); - for (final activeNotification in activeNotifications) { - final room = client.rooms.singleWhereOrNull( - (room) => room.id.hashCode == activeNotification.id, - ); - if (room == null || !room.isUnreadOrInvited) { - flutterLocalNotificationsPlugin.cancel(activeNotification.id!); - } + // Initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project + final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + await flutterLocalNotificationsPlugin.initialize( + const InitializationSettings( + android: AndroidInitializationSettings('notifications_icon'), + iOS: DarwinInitializationSettings(), + ), + onDidReceiveNotificationResponse: onSelectNotification, + //onDidReceiveBackgroundNotificationResponse: onSelectNotification, + ); + + client ??= (await ClientManager.getClients( + initialize: false, + store: await SharedPreferences.getInstance(), + )) + .first; + final event = await client.getEventByPushNotification( + notification, + storeInDatabase: isBackgroundMessage, + ); + + if (event == null) { + Logs().v('Notification is a clearing indicator.'); + if (notification.counts?.unread == null || + notification.counts?.unread == 0) { + await flutterLocalNotificationsPlugin.cancelAll(); + } else { + // Make sure client is fully loaded and synced before dismiss notifications: + await client.roomsLoading; + await client.oneShotSync(); + final activeNotifications = + await flutterLocalNotificationsPlugin.getActiveNotifications(); + for (final activeNotification in activeNotifications) { + final room = client.rooms.singleWhereOrNull( + (room) => room.id.hashCode == activeNotification.id, + ); + if (room == null || !room.isUnreadOrInvited) { + flutterLocalNotificationsPlugin.cancel(activeNotification.id!); } } - return; - } - Logs().v('Push helper got notification event of type ${event.type}.'); - - if (event.type.startsWith('m.call')) { - // make sure bg sync is on (needed to update hold, unhold events) - // prevent over write from app life cycle change - client.backgroundSync = true; - } - - if (event.type == EventTypes.CallInvite) { - CallKeepManager().initialize(); - } else if (event.type == EventTypes.CallHangup) { - client.backgroundSync = false; - } - - if (event.type.startsWith('m.call') && - event.type != EventTypes.CallInvite) { - Logs().v('Push message is a m.call but not invite. Do not display.'); - return; } + return; + } + Logs().v('Push helper got notification event of type ${event.type}.'); - if ((event.type.startsWith('m.call') && - event.type != EventTypes.CallInvite) || - event.type == 'org.matrix.call.sdp_stream_metadata_changed') { - Logs().v('Push message was for a call, but not call invite.'); - return; - } + if (event.type.startsWith('m.call')) { + // make sure bg sync is on (needed to update hold, unhold events) + // prevent over write from app life cycle change + client.backgroundSync = true; + } - l10n ??= await L10n.delegate.load(PlatformDispatcher.instance.locale); - final matrixLocals = MatrixLocals(l10n); - - // Calculate the body - final body = event.type == EventTypes.Encrypted - ? l10n.newMessageInFluffyChat - : await event.calcLocalizedBody( - matrixLocals, - plaintextBody: true, - withSenderNamePrefix: false, - hideReply: true, - hideEdit: true, - removeMarkdown: true, - ); - - // The person object for the android message style notification - final avatar = event.room.avatar - ?.getThumbnail( - client, - width: 256, - height: 256, - ) - .toString(); - final senderAvatar = event.room.isDirectChat - ? avatar - : event.senderFromMemoryOrFallback.avatarUrl - ?.getThumbnail( - client, - width: 256, - height: 256, - ) - .toString(); - - File? roomAvatarFile, senderAvatarFile; - try { - roomAvatarFile = avatar == null - ? null - : await DefaultCacheManager().getSingleFile(avatar); - } catch (e, s) { - Logs().e('Unable to get avatar picture', e, s); - } - try { - senderAvatarFile = event.room.isDirectChat - ? roomAvatarFile - : senderAvatar == null - ? null - : await DefaultCacheManager().getSingleFile(senderAvatar); - } catch (e, s) { - Logs().e('Unable to get avatar picture', e, s); - } + if (event.type == EventTypes.CallInvite) { + CallKeepManager().initialize(); + } else if (event.type == EventTypes.CallHangup) { + client.backgroundSync = false; + } - final id = notification.roomId.hashCode; + if (event.type.startsWith('m.call') && event.type != EventTypes.CallInvite) { + Logs().v('Push message is a m.call but not invite. Do not display.'); + return; + } - // Show notification + if ((event.type.startsWith('m.call') && + event.type != EventTypes.CallInvite) || + event.type == 'org.matrix.call.sdp_stream_metadata_changed') { + Logs().v('Push message was for a call, but not call invite.'); + return; + } - final newMessage = Message( - body, - event.originServerTs, - Person( - bot: event.messageType == MessageTypes.Notice, - key: event.senderId, - name: event.senderFromMemoryOrFallback.calcDisplayname(), - icon: senderAvatarFile == null + l10n ??= await L10n.delegate.load(PlatformDispatcher.instance.locale); + final matrixLocals = MatrixLocals(l10n); + + // Calculate the body + final body = event.type == EventTypes.Encrypted + ? l10n.newMessageInFluffyChat + : await event.calcLocalizedBody( + matrixLocals, + plaintextBody: true, + withSenderNamePrefix: false, + hideReply: true, + hideEdit: true, + removeMarkdown: true, + ); + + // The person object for the android message style notification + final avatar = event.room.avatar + ?.getThumbnail( + client, + width: 256, + height: 256, + ) + .toString(); + final senderAvatar = event.room.isDirectChat + ? avatar + : event.senderFromMemoryOrFallback.avatarUrl + ?.getThumbnail( + client, + width: 256, + height: 256, + ) + .toString(); + + File? roomAvatarFile, senderAvatarFile; + try { + roomAvatarFile = avatar == null + ? null + : await DefaultCacheManager().getSingleFile(avatar); + } catch (e, s) { + Logs().e('Unable to get avatar picture', e, s); + } + try { + senderAvatarFile = event.room.isDirectChat + ? roomAvatarFile + : senderAvatar == null ? null - : BitmapFilePathAndroidIcon(senderAvatarFile.path), - ), - ); - - final messagingStyleInformation = PlatformInfos.isAndroid - ? await AndroidFlutterLocalNotificationsPlugin() - .getActiveNotificationMessagingStyle(id) - : null; - messagingStyleInformation?.messages?.add(newMessage); - - final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); + : await DefaultCacheManager().getSingleFile(senderAvatar); + } catch (e, s) { + Logs().e('Unable to get avatar picture', e, s); + } - final notificationGroupId = - event.room.isDirectChat ? 'directChats' : 'groupChats'; - final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups; + final id = notification.roomId.hashCode; - final messageRooms = AndroidNotificationChannelGroup( - notificationGroupId, - groupName, - ); - final roomsChannel = AndroidNotificationChannel( - event.room.id, - roomName, - groupId: notificationGroupId, - ); + // Show notification - await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannelGroup(messageRooms); - await flutterLocalNotificationsPlugin - .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>() - ?.createNotificationChannel(roomsChannel); - - final androidPlatformChannelSpecifics = AndroidNotificationDetails( - AppConfig.pushNotificationsChannelId, - l10n.incomingMessages, - number: notification.counts?.unread, - category: AndroidNotificationCategory.message, - shortcutId: event.room.id, - styleInformation: messagingStyleInformation ?? - MessagingStyleInformation( - Person( - name: event.senderFromMemoryOrFallback.calcDisplayname(), - icon: roomAvatarFile == null - ? null - : BitmapFilePathAndroidIcon(roomAvatarFile.path), - key: event.roomId, - important: event.room.isFavourite, - ), - conversationTitle: roomName, - groupConversation: !event.room.isDirectChat, - messages: [newMessage], + final newMessage = Message( + body, + event.originServerTs, + Person( + bot: event.messageType == MessageTypes.Notice, + key: event.senderId, + name: event.senderFromMemoryOrFallback.calcDisplayname(), + icon: senderAvatarFile == null + ? null + : BitmapFilePathAndroidIcon(senderAvatarFile.path), + ), + ); + + final messagingStyleInformation = PlatformInfos.isAndroid + ? await AndroidFlutterLocalNotificationsPlugin() + .getActiveNotificationMessagingStyle(id) + : null; + messagingStyleInformation?.messages?.add(newMessage); + + final roomName = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); + + final notificationGroupId = + event.room.isDirectChat ? 'directChats' : 'groupChats'; + final groupName = event.room.isDirectChat ? l10n.directChats : l10n.groups; + + final messageRooms = AndroidNotificationChannelGroup( + notificationGroupId, + groupName, + ); + final roomsChannel = AndroidNotificationChannel( + event.room.id, + roomName, + groupId: notificationGroupId, + ); + + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannelGroup(messageRooms); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.createNotificationChannel(roomsChannel); + + final androidPlatformChannelSpecifics = AndroidNotificationDetails( + AppConfig.pushNotificationsChannelId, + l10n.incomingMessages, + number: notification.counts?.unread, + category: AndroidNotificationCategory.message, + shortcutId: event.room.id, + styleInformation: messagingStyleInformation ?? + MessagingStyleInformation( + Person( + name: event.senderFromMemoryOrFallback.calcDisplayname(), + icon: roomAvatarFile == null + ? null + : BitmapFilePathAndroidIcon(roomAvatarFile.path), + key: event.roomId, + important: event.room.isFavourite, ), - ticker: event.calcLocalizedBodyFallback( - matrixLocals, - plaintextBody: true, - withSenderNamePrefix: true, - hideReply: true, - hideEdit: true, - removeMarkdown: true, - ), - importance: Importance.high, - priority: Priority.max, - groupKey: notificationGroupId, - ); - const iOSPlatformChannelSpecifics = DarwinNotificationDetails(); - final platformChannelSpecifics = NotificationDetails( - android: androidPlatformChannelSpecifics, - iOS: iOSPlatformChannelSpecifics, - ); - - final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); - - if (PlatformInfos.isAndroid && messagingStyleInformation == null) { - await _setShortcut(event, l10n, title, roomAvatarFile); - } - - await flutterLocalNotificationsPlugin.show( - id, - title, - body, - platformChannelSpecifics, - payload: event.roomId, - ); - Logs().v('Push helper has been completed!'); + conversationTitle: roomName, + groupConversation: !event.room.isDirectChat, + messages: [newMessage], + ), + ticker: event.calcLocalizedBodyFallback( + matrixLocals, + plaintextBody: true, + withSenderNamePrefix: true, + hideReply: true, + hideEdit: true, + removeMarkdown: true, + ), + importance: Importance.high, + priority: Priority.max, + groupKey: notificationGroupId, + ); + const iOSPlatformChannelSpecifics = DarwinNotificationDetails(); + final platformChannelSpecifics = NotificationDetails( + android: androidPlatformChannelSpecifics, + iOS: iOSPlatformChannelSpecifics, + ); + + final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); + + if (PlatformInfos.isAndroid && messagingStyleInformation == null) { + await _setShortcut(event, l10n, title, roomAvatarFile); } - /// Creates a shortcut for Android platform but does not block displaying the - /// notification. This is optional but provides a nicer view of the - /// notification popup. - static Future _setShortcut( - Event event, - L10n l10n, - String title, - File? avatarFile, - ) async { - final flutterShortcuts = FlutterShortcuts(); - await flutterShortcuts.initialize(debug: !kReleaseMode); - await flutterShortcuts.pushShortcutItem( - shortcut: ShortcutItem( - id: event.room.id, - action: AppConfig.inviteLinkPrefix + event.room.id, - shortLabel: title, - conversationShortcut: true, - icon: avatarFile == null - ? null - : ShortcutMemoryIcon(jpegImage: await avatarFile.readAsBytes()) - .toString(), - shortcutIconAsset: avatarFile == null - ? ShortcutIconAsset.androidAsset - : ShortcutIconAsset.memoryAsset, - isImportant: event.room.isFavourite, - ), - ); - } + await flutterLocalNotificationsPlugin.show( + id, + title, + body, + platformChannelSpecifics, + payload: event.roomId, + ); + Logs().v('Push helper has been completed!'); +} + +/// Creates a shortcut for Android platform but does not block displaying the +/// notification. This is optional but provides a nicer view of the +/// notification popup. +Future _setShortcut( + Event event, + L10n l10n, + String title, + File? avatarFile, +) async { + final flutterShortcuts = FlutterShortcuts(); + await flutterShortcuts.initialize(debug: !kReleaseMode); + await flutterShortcuts.pushShortcutItem( + shortcut: ShortcutItem( + id: event.room.id, + action: AppConfig.inviteLinkPrefix + event.room.id, + shortLabel: title, + conversationShortcut: true, + icon: avatarFile == null + ? null + : ShortcutMemoryIcon(jpegImage: await avatarFile.readAsBytes()) + .toString(), + shortcutIconAsset: avatarFile == null + ? ShortcutIconAsset.androidAsset + : ShortcutIconAsset.memoryAsset, + isImportant: event.room.isFavourite, + ), + ); }