From daf40aed0beb8e9136f0e86bda5e29b7a155eaa0 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Fri, 28 Jul 2023 21:46:47 +0200 Subject: [PATCH] feat: Allow setting the self-avatar --- example/lib/main.dart | 11 ++++++++ .../me/polynom/moxplatform_android/Api.java | 26 ++++++++++++++++++ .../MoxplatformAndroidPlugin.java | 13 ++++++--- .../NotificationReceiver.kt | 27 ++++++++++++++----- .../moxplatform_android/Notifications.kt | 25 ++++++++++++----- .../lib/src/notifications_android.dart | 5 ++++ .../lib/src/api.g.dart | 22 +++++++++++++++ .../lib/src/notifications.dart | 2 ++ .../lib/src/notifications_stub.dart | 3 +++ pigeons/api.dart | 2 ++ 10 files changed, 119 insertions(+), 17 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 0ad4575..3e01ac7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -189,6 +189,17 @@ class MyHomePage extends StatelessWidget { }, child: const Text('Show messaging notification'), ), + ElevatedButton( + onPressed: () async { + final result = await FilePicker.platform.pickFiles( + type: FileType.image, + ); + if (result == null) return; + + MoxplatformPlugin.notifications.setNotificationSelfAvatar(result.files.single.path!); + }, + child: const Text('Set notification self-avatar'), + ), ElevatedButton( onPressed: () async { print(await MoxplatformPlugin.platform.getPersistentDataPath()); diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java index db3ce05..c53cdf9 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Api.java @@ -707,6 +707,8 @@ public class Api { void showMessagingNotification(@NonNull MessagingNotification notification); + void setNotificationSelfAvatar(@NonNull String path); + @NonNull String getPersistentDataPath(); @@ -762,6 +764,30 @@ public class Api { api.showMessagingNotification(notificationArg); wrapped.add(0, null); } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationSelfAvatar", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + String pathArg = (String) args.get(0); + try { + api.setNotificationSelfAvatar(pathArg); + wrapped.add(0, null); + } catch (Throwable exception) { ArrayList wrappedError = wrapError(exception); wrapped = wrappedError; diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java index 55d5342..c85f8b6 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/MoxplatformAndroidPlugin.java @@ -300,9 +300,9 @@ import kotlin.jvm.functions.Function1; manager.createNotificationChannel(channel); // Configure i18n - NotificationI18nManager.INSTANCE.setYou(i18n.getYou()); - NotificationI18nManager.INSTANCE.setReply(i18n.getReply()); - NotificationI18nManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead()); + NotificationDataManager.INSTANCE.setYou(i18n.getYou()); + NotificationDataManager.INSTANCE.setReply(i18n.getReply()); + NotificationDataManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead()); } @Override @@ -310,7 +310,12 @@ import kotlin.jvm.functions.Function1; NotificationsKt.showMessagingNotification(context, notification); } - @NonNull + @Override + public void setNotificationSelfAvatar(@NonNull String path) { + NotificationDataManager.INSTANCE.setAvatarPath(path); + } + + @NonNull @Override public String getPersistentDataPath() { return context.getFilesDir().getPath(); diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt index 6ec8bf2..800f2e8 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/NotificationReceiver.kt @@ -6,6 +6,8 @@ import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import android.graphics.BitmapFactory +import android.graphics.drawable.Icon import android.os.Build import android.util.Log import androidx.core.app.NotificationCompat @@ -13,6 +15,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.core.app.Person import androidx.core.app.RemoteInput import androidx.core.content.FileProvider +import androidx.core.graphics.drawable.IconCompat import me.polynom.moxplatform_android.Api.NotificationEvent import java.io.File import java.time.Instant @@ -43,8 +46,6 @@ class NotificationReceiver : BroadcastReceiver() { NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt()) MoxplatformAndroidPlugin.notificationSink?.success( NotificationEvent().apply { - // TODO: Use constant for key - // TODO: Fix jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!! type = Api.NotificationEventType.MARK_AS_READ payload = null @@ -59,7 +60,6 @@ class NotificationReceiver : BroadcastReceiver() { val replyPayload = remoteInput.getCharSequence(REPLY_TEXT_KEY) MoxplatformAndroidPlugin.notificationSink?.success( NotificationEvent().apply { - // TODO: Use constant for key jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!! type = Api.NotificationEventType.REPLY payload = replyPayload.toString() @@ -80,10 +80,25 @@ class NotificationReceiver : BroadcastReceiver() { // Thanks https://medium.com/@sidorovroman3/android-how-to-use-messagingstyle-for-notifications-without-caching-messages-c414ef2b816c val recoveredStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification)!! - // TODO: Use a person and cache this data somewhere - val newStyle = Notification.MessagingStyle(NotificationI18nManager.you).apply { + val newStyle = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) + Notification.MessagingStyle( + android.app.Person.Builder().apply { + setName(NotificationDataManager.you) + + // Set an avatar, if we have one + if (NotificationDataManager.avatarPath != null) { + setIcon( + Icon.createWithAdaptiveBitmap( + BitmapFactory.decodeFile(NotificationDataManager.avatarPath) + ) + ) + } + }.build() + ) + else Notification.MessagingStyle(NotificationDataManager.you) + + newStyle.apply { conversationTitle = recoveredStyle.conversationTitle - // TODO: Use person recoveredStyle.messages.forEach { // Check if we have to request (or refresh) the content URI to be able to still // see the embedded image. diff --git a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt index 13a2ecb..81c7b0f 100644 --- a/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt +++ b/packages/moxplatform_android/android/src/main/java/me/polynom/moxplatform_android/Notifications.kt @@ -12,10 +12,11 @@ import androidx.core.content.FileProvider import androidx.core.graphics.drawable.IconCompat import java.io.File -object NotificationI18nManager { +object NotificationDataManager { var you: String = "You" var markAsRead: String = "Mark as read" var reply: String = "Reply" + var avatarPath: String? = null } /// Show a messaging style notification described by @notification. @@ -23,7 +24,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif // Build the actions // -> Reply action val remoteInput = RemoteInput.Builder(REPLY_TEXT_KEY).apply { - setLabel(NotificationI18nManager.reply) + setLabel(NotificationDataManager.reply) }.build() val replyIntent = Intent(context, NotificationReceiver::class.java).apply { action = REPLY_ACTION @@ -39,7 +40,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif val replyAction = NotificationCompat.Action.Builder( // TODO: Wrong icon? R.drawable.ic_service_icon, - NotificationI18nManager.reply, + NotificationDataManager.reply, replyPendingIntent, ).apply { addRemoteInput(remoteInput) @@ -61,8 +62,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif val markAsReadAction = NotificationCompat.Action.Builder( // TODO: Wrong icon R.drawable.ic_service_icon, - // TODO: i18n - NotificationI18nManager.markAsRead, + NotificationDataManager.markAsRead, markAsReadPendingIntent, ).build() @@ -81,8 +81,19 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif ) // Build the notification - // TODO: Use a person - val style = NotificationCompat.MessagingStyle(NotificationI18nManager.you); + val selfPerson = Person.Builder().apply { + setName(NotificationDataManager.you) + + // Set an avatar, if we have one + if (NotificationDataManager.avatarPath != null) { + setIcon( + IconCompat.createWithAdaptiveBitmap( + BitmapFactory.decodeFile(NotificationDataManager.avatarPath), + ), + ) + } + }.build() + val style = NotificationCompat.MessagingStyle(selfPerson); for (message in notification.messages) { // Build the sender val sender = Person.Builder().apply { diff --git a/packages/moxplatform_android/lib/src/notifications_android.dart b/packages/moxplatform_android/lib/src/notifications_android.dart index ff14296..45cb9b6 100644 --- a/packages/moxplatform_android/lib/src/notifications_android.dart +++ b/packages/moxplatform_android/lib/src/notifications_android.dart @@ -25,6 +25,11 @@ class AndroidNotificationsImplementation extends NotificationsImplementation { return _api.showMessagingNotification(notification); } + @override + Future setNotificationSelfAvatar(String path) async { + return _api.setNotificationSelfAvatar(path); + } + @override Stream getEventStream() => _channel .receiveBroadcastStream() diff --git a/packages/moxplatform_platform_interface/lib/src/api.g.dart b/packages/moxplatform_platform_interface/lib/src/api.g.dart index 42f8a0f..893266b 100644 --- a/packages/moxplatform_platform_interface/lib/src/api.g.dart +++ b/packages/moxplatform_platform_interface/lib/src/api.g.dart @@ -306,6 +306,28 @@ class MoxplatformApi { } } + Future setNotificationSelfAvatar(String arg_path) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationSelfAvatar', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_path]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + Future getPersistentDataPath() async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath', codec, diff --git a/packages/moxplatform_platform_interface/lib/src/notifications.dart b/packages/moxplatform_platform_interface/lib/src/notifications.dart index bcf9fc5..abdf1a0 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications.dart @@ -6,5 +6,7 @@ abstract class NotificationsImplementation { Future showMessagingNotification(MessagingNotification notification); + Future setNotificationSelfAvatar(String path); + Stream getEventStream(); } diff --git a/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart b/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart index 40e2f71..c1b7fcc 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart @@ -9,6 +9,9 @@ class StubNotificationsImplementation extends NotificationsImplementation { @override Future showMessagingNotification(MessagingNotification notification) async {} + @override + Future setNotificationSelfAvatar(String path) async {} + @override Stream getEventStream() { return StreamController().stream; diff --git a/pigeons/api.dart b/pigeons/api.dart index d8471cd..0b951ee 100644 --- a/pigeons/api.dart +++ b/pigeons/api.dart @@ -116,6 +116,8 @@ abstract class MoxplatformApi { void showMessagingNotification(MessagingNotification notification); + void setNotificationSelfAvatar(String path); + String getPersistentDataPath(); String getCacheDataPath();