diff --git a/example/lib/main.dart b/example/lib/main.dart index 3e01ac7..b4cd52a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -45,6 +45,8 @@ class MyAppState extends State { "Test notification channel", channelId, false, + ); + await MoxplatformPlugin.notifications.setI18n( NotificationI18nData( reply: "答える", markAsRead: "読みた", @@ -128,9 +130,8 @@ class MyHomePage extends StatelessWidget { title: const Text('Moxplatform Demo'), ), body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ + child: ListView( + children: [ ElevatedButton( onPressed: _cryptoTest, child: const Text('Test cryptography'), 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 c53cdf9..4e910d7 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 @@ -703,12 +703,14 @@ public class Api { /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface MoxplatformApi { - void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent, @NonNull NotificationI18nData i18n); + void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent); void showMessagingNotification(@NonNull MessagingNotification notification); void setNotificationSelfAvatar(@NonNull String path); + void setNotificationI18n(@NonNull NotificationI18nData data); + @NonNull String getPersistentDataPath(); @@ -735,9 +737,8 @@ public class Api { String titleArg = (String) args.get(0); String idArg = (String) args.get(1); Boolean urgentArg = (Boolean) args.get(2); - NotificationI18nData i18nArg = (NotificationI18nData) args.get(3); try { - api.createNotificationChannel(titleArg, idArg, urgentArg, i18nArg); + api.createNotificationChannel(titleArg, idArg, urgentArg); wrapped.add(0, null); } catch (Throwable exception) { @@ -788,6 +789,30 @@ public class Api { api.setNotificationSelfAvatar(pathArg); 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.setNotificationI18n", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + NotificationI18nData dataArg = (NotificationI18nData) args.get(0); + try { + api.setNotificationI18n(dataArg); + 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 c85f8b6..d1bf10b 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 @@ -288,7 +288,7 @@ import kotlin.jvm.functions.Function1; } @Override - public void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent, @NonNull NotificationI18nData i18n) { + public void createNotificationChannel(@NonNull String title, @NonNull String id, @NonNull Boolean urgent) { final NotificationChannel channel = new NotificationChannel( id, title, @@ -298,11 +298,6 @@ import kotlin.jvm.functions.Function1; channel.enableLights(true); final NotificationManager manager = getSystemService(context, NotificationManager.class); manager.createNotificationChannel(channel); - - // Configure i18n - NotificationDataManager.INSTANCE.setYou(i18n.getYou()); - NotificationDataManager.INSTANCE.setReply(i18n.getReply()); - NotificationDataManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead()); } @Override @@ -315,6 +310,14 @@ import kotlin.jvm.functions.Function1; NotificationDataManager.INSTANCE.setAvatarPath(path); } + @Override + public void setNotificationI18n(@NonNull NotificationI18nData data) { + // Configure i18n + NotificationDataManager.INSTANCE.setYou(data.getYou()); + NotificationDataManager.INSTANCE.setReply(data.getReply()); + NotificationDataManager.INSTANCE.setMarkAsRead(data.getMarkAsRead()); + } + @NonNull @Override public String getPersistentDataPath() { 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 81c7b0f..337a333 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 @@ -1,9 +1,11 @@ package me.polynom.moxplatform_android +import android.app.Notification import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.BitmapFactory +import android.graphics.Color import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.app.Person @@ -38,8 +40,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif PendingIntent.FLAG_UPDATE_CURRENT, ) val replyAction = NotificationCompat.Action.Builder( - // TODO: Wrong icon? - R.drawable.ic_service_icon, + R.drawable.reply, NotificationDataManager.reply, replyPendingIntent, ).apply { @@ -60,8 +61,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif PendingIntent.FLAG_UPDATE_CURRENT, ) val markAsReadAction = NotificationCompat.Action.Builder( - // TODO: Wrong icon - R.drawable.ic_service_icon, + R.drawable.mark_as_read, NotificationDataManager.markAsRead, markAsReadPendingIntent, ).build() @@ -141,8 +141,11 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif // Assemble the notification val finalNotification = NotificationCompat.Builder(context, notification.channelId).apply { setStyle(style) - // TODO: I think this is wrong + // NOTE: It's okay to use the service icon here as I cannot get Android to display the + // actual logo. So we'll have to make do with the silhouette and the color purple. setSmallIcon(R.drawable.ic_service_icon) + color = Color.argb(255, 207, 74, 255) + setColorized(true) // Tap action setContentIntent(tapPendingIntent) @@ -151,6 +154,9 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif addAction(replyAction) addAction(markAsReadAction) + setAllowSystemGeneratedContextualActions(true) + setCategory(Notification.CATEGORY_MESSAGE) + // Prevent no notification when we replied before setOnlyAlertOnce(false) }.build() diff --git a/packages/moxplatform_android/android/src/main/res/drawable/mark_as_read.xml b/packages/moxplatform_android/android/src/main/res/drawable/mark_as_read.xml new file mode 100644 index 0000000..5b80636 --- /dev/null +++ b/packages/moxplatform_android/android/src/main/res/drawable/mark_as_read.xml @@ -0,0 +1,5 @@ + + + diff --git a/packages/moxplatform_android/android/src/main/res/drawable/reply.xml b/packages/moxplatform_android/android/src/main/res/drawable/reply.xml new file mode 100644 index 0000000..fb8b6df --- /dev/null +++ b/packages/moxplatform_android/android/src/main/res/drawable/reply.xml @@ -0,0 +1,5 @@ + + + diff --git a/packages/moxplatform_android/lib/src/notifications_android.dart b/packages/moxplatform_android/lib/src/notifications_android.dart index 45cb9b6..7fd95fa 100644 --- a/packages/moxplatform_android/lib/src/notifications_android.dart +++ b/packages/moxplatform_android/lib/src/notifications_android.dart @@ -13,9 +13,8 @@ class AndroidNotificationsImplementation extends NotificationsImplementation { String title, String id, bool urgent, - NotificationI18nData i18n, ) async { - return _api.createNotificationChannel(title, id, urgent, i18n); + return _api.createNotificationChannel(title, id, urgent); } @override @@ -28,7 +27,12 @@ class AndroidNotificationsImplementation extends NotificationsImplementation { @override Future setNotificationSelfAvatar(String path) async { return _api.setNotificationSelfAvatar(path); - } + } + + @override + Future setI18n(NotificationI18nData data) { + return _api.setNotificationI18n(data); + } @override Stream getEventStream() => _channel diff --git a/packages/moxplatform_platform_interface/lib/src/api.g.dart b/packages/moxplatform_platform_interface/lib/src/api.g.dart index 893266b..d81daaa 100644 --- a/packages/moxplatform_platform_interface/lib/src/api.g.dart +++ b/packages/moxplatform_platform_interface/lib/src/api.g.dart @@ -262,12 +262,12 @@ class MoxplatformApi { static const MessageCodec codec = _MoxplatformApiCodec(); - Future createNotificationChannel(String arg_title, String arg_id, bool arg_urgent, NotificationI18nData arg_i18n) async { + Future createNotificationChannel(String arg_title, String arg_id, bool arg_urgent) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationChannel', codec, binaryMessenger: _binaryMessenger); final List? replyList = - await channel.send([arg_title, arg_id, arg_urgent, arg_i18n]) as List?; + await channel.send([arg_title, arg_id, arg_urgent]) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', @@ -328,6 +328,28 @@ class MoxplatformApi { } } + Future setNotificationI18n(NotificationI18nData arg_data) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationI18n', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_data]) 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 abdf1a0..31ef838 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications.dart @@ -2,11 +2,18 @@ import 'dart:async'; import 'package:moxplatform_platform_interface/src/api.g.dart'; abstract class NotificationsImplementation { - Future createNotificationChannel(String title, String id, bool urgent, NotificationI18nData i18n); + /// Creates a notification channel with the name [title] and id [id]. If [urgent] is true, then + /// it configures the channel as carrying urgent information. + Future createNotificationChannel(String title, String id, bool urgent); + /// Shows a notification [notification] in the messaging style with everyting it needs. Future showMessagingNotification(MessagingNotification notification); + /// Sets the path to the self-avatar for in-notification replies. Future setNotificationSelfAvatar(String path); + /// Configures the i18n data for usage in notifications. + Future setI18n(NotificationI18nData data); + 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 c1b7fcc..2bc36fe 100644 --- a/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart +++ b/packages/moxplatform_platform_interface/lib/src/notifications_stub.dart @@ -4,7 +4,7 @@ import 'package:moxplatform_platform_interface/src/notifications.dart'; class StubNotificationsImplementation extends NotificationsImplementation { @override - Future createNotificationChannel(String title, String id, bool urgent, NotificationI18nData i18n) async {} + Future createNotificationChannel(String title, String id, bool urgent) async {} @override Future showMessagingNotification(MessagingNotification notification) async {} @@ -12,6 +12,9 @@ class StubNotificationsImplementation extends NotificationsImplementation { @override Future setNotificationSelfAvatar(String path) async {} + @override + Future setI18n(NotificationI18nData data) async {} + @override Stream getEventStream() { return StreamController().stream; diff --git a/pigeons/api.dart b/pigeons/api.dart index 0b951ee..d1877fc 100644 --- a/pigeons/api.dart +++ b/pigeons/api.dart @@ -112,15 +112,11 @@ class NotificationI18nData { @HostApi() abstract class MoxplatformApi { - void createNotificationChannel(String title, String id, bool urgent, NotificationI18nData i18n); - + void createNotificationChannel(String title, String id, bool urgent); void showMessagingNotification(MessagingNotification notification); - void setNotificationSelfAvatar(String path); - + void setNotificationI18n(NotificationI18nData data); String getPersistentDataPath(); - String getCacheDataPath(); - void eventStub(NotificationEvent event); }