From dee9323d4749b7b5778ada8ab1fcbf07f8f51936 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Thu, 15 Feb 2024 12:02:32 +0100 Subject: [PATCH] feat: Add notification shortcuts to android --- assets/l10n/intl_en.arb | 3 +- lib/config/app_config.dart | 3 - lib/utils/client_manager.dart | 5 +- lib/utils/push_helper.dart | 103 ++++++++++++++++++++++++++-------- pubspec.lock | 9 +++ pubspec.yaml | 2 + 6 files changed, 96 insertions(+), 29 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 71b6ca6a..afe692eb 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2469,5 +2469,6 @@ "sender": {} } }, - "transparent": "Transparent" + "transparent": "Transparent", + "incomingMessages": "Incoming messages" } \ No newline at end of file diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 92cfb312..69953b1c 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -56,9 +56,6 @@ abstract class AppConfig { static const String deepLinkPrefix = 'im.fluffychat://chat/'; static const String schemePrefix = 'matrix:'; static const String pushNotificationsChannelId = 'fluffychat_push'; - static const String pushNotificationsChannelName = 'FluffyChat push channel'; - static const String pushNotificationsChannelDescription = - 'Push notifications for FluffyChat'; static const String pushNotificationsAppId = 'chat.fluffy.fluffychat'; static const String pushNotificationsGatewayUrl = 'https://push.fluffychat.im/_matrix/push/v1/notify'; diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 2d171336..1c1ab047 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -159,9 +159,8 @@ abstract class ClientManager { body, const NotificationDetails( android: AndroidNotificationDetails( - AppConfig.pushNotificationsChannelId, - AppConfig.pushNotificationsChannelName, - channelDescription: AppConfig.pushNotificationsChannelDescription, + 'error_message', + 'Error Messages', importance: Importance.max, priority: Priority.max, fullScreenIntent: true, // To show notification popup diff --git a/lib/utils/push_helper.dart b/lib/utils/push_helper.dart index 360bde9d..cca6c54d 100644 --- a/lib/utils/push_helper.dart +++ b/lib/utils/push_helper.dart @@ -2,11 +2,13 @@ import 'dart:convert'; import 'dart:io'; import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:flutter_shortcuts/flutter_shortcuts.dart'; import 'package:matrix/matrix.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -55,8 +57,7 @@ Future pushHelper( iOS: const DarwinNotificationDetails(), android: AndroidNotificationDetails( AppConfig.pushNotificationsChannelId, - AppConfig.pushNotificationsChannelName, - channelDescription: AppConfig.pushNotificationsChannelDescription, + l10n.incomingMessages, number: notification.counts?.unread, ticker: l10n.unreadChats(notification.counts?.unread ?? 1), importance: Importance.max, @@ -170,34 +171,53 @@ Future _tryPushHelper( final avatar = event.room.avatar ?.getThumbnail( client, - width: 126, - height: 126, + width: 128, + height: 128, ) .toString(); - File? avatarFile; + final senderAvatar = event.room.isDirectChat + ? avatar + : event.senderFromMemoryOrFallback.avatarUrl + ?.getThumbnail( + client, + width: 128, + height: 128, + ) + .toString(); + + File? roomAvatarFile, senderAvatarFile; try { - avatarFile = avatar == null + 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 = await mapRoomIdToInt(event.room.id); // Show notification - final person = Person( - name: event.senderFromMemoryOrFallback.calcDisplayname(), - icon: - avatarFile == null ? null : BitmapFilePathAndroidIcon(avatarFile.path), - key: event.senderId, - uri: 'matrix:${event.senderId.replaceFirst('@', '')}', - important: event.room.isFavourite, - ); + final newMessage = Message( body, event.originServerTs, - person, + Person( + bot: event.messageType == MessageTypes.Notice, + key: event.senderId, + name: event.senderFromMemoryOrFallback.calcDisplayname(), + icon: senderAvatarFile == null + ? null + : BitmapFilePathAndroidIcon(senderAvatarFile.path), + ), ); final messagingStyleInformation = PlatformInfos.isAndroid @@ -232,15 +252,21 @@ Future _tryPushHelper( ?.createNotificationChannel(roomsChannel); final androidPlatformChannelSpecifics = AndroidNotificationDetails( - event.room.id, - roomName, - channelDescription: groupName, + AppConfig.pushNotificationsChannelId, + l10n.incomingMessages, number: notification.counts?.unread, category: AndroidNotificationCategory.message, shortcutId: event.room.id, styleInformation: messagingStyleInformation ?? MessagingStyleInformation( - person, + 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], @@ -257,11 +283,15 @@ Future _tryPushHelper( iOS: iOSPlatformChannelSpecifics, ); + final title = event.room.getLocalizedDisplayname(MatrixLocals(l10n)); + + if (PlatformInfos.isAndroid) { + _setShortcut(event, l10n, title, roomAvatarFile); + } + await flutterLocalNotificationsPlugin.show( id, - event.room.getLocalizedDisplayname( - MatrixLocals(l10n), - ), + title, body, platformChannelSpecifics, payload: event.roomId, @@ -269,6 +299,35 @@ Future _tryPushHelper( 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. +void _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: l10n.openChat, + 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, + ), + ); +} + /// Workaround for the problem that local notification IDs must be int but we /// sort by [roomId] which is a String. To make sure that we don't have duplicated /// IDs we map the [roomId] to a number and store this number. diff --git a/pubspec.lock b/pubspec.lock index da8a0075..4446ff64 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -712,6 +712,15 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + flutter_shortcuts: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "67158a31e066265ad43463befb57c29ec2cbd77a" + url: "https://github.com/krille-chan/flutter_shortcuts.git" + source: git + version: "1.4.0" flutter_svg: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bce81e21..c404286f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,6 +46,8 @@ dependencies: flutter_openssl_crypto: ^0.3.0 flutter_ringtone_player: ^4.0.0+2 flutter_secure_storage: ^9.0.0 + flutter_shortcuts: + git: https://github.com/krille-chan/flutter_shortcuts.git flutter_typeahead: ^4.8.0 flutter_web_auth_2: ^3.0.4 flutter_webrtc: ^0.9.46