feat: Color in the notification silhouette

This commit is contained in:
PapaTutuWawa 2023-07-29 12:34:40 +02:00
parent daf40aed0b
commit 8f93821617
11 changed files with 107 additions and 30 deletions

View File

@ -45,6 +45,8 @@ class MyAppState extends State<MyApp> {
"Test notification channel", "Test notification channel",
channelId, channelId,
false, false,
);
await MoxplatformPlugin.notifications.setI18n(
NotificationI18nData( NotificationI18nData(
reply: "答える", reply: "答える",
markAsRead: "読みた", markAsRead: "読みた",
@ -128,9 +130,8 @@ class MyHomePage extends StatelessWidget {
title: const Text('Moxplatform Demo'), title: const Text('Moxplatform Demo'),
), ),
body: Center( body: Center(
child: Column( child: ListView(
mainAxisAlignment: MainAxisAlignment.center, children: [
children: <Widget>[
ElevatedButton( ElevatedButton(
onPressed: _cryptoTest, onPressed: _cryptoTest,
child: const Text('Test cryptography'), child: const Text('Test cryptography'),

View File

@ -703,12 +703,14 @@ public class Api {
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ /** Generated interface from Pigeon that represents a handler of messages from Flutter. */
public interface MoxplatformApi { 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 showMessagingNotification(@NonNull MessagingNotification notification);
void setNotificationSelfAvatar(@NonNull String path); void setNotificationSelfAvatar(@NonNull String path);
void setNotificationI18n(@NonNull NotificationI18nData data);
@NonNull @NonNull
String getPersistentDataPath(); String getPersistentDataPath();
@ -735,9 +737,8 @@ public class Api {
String titleArg = (String) args.get(0); String titleArg = (String) args.get(0);
String idArg = (String) args.get(1); String idArg = (String) args.get(1);
Boolean urgentArg = (Boolean) args.get(2); Boolean urgentArg = (Boolean) args.get(2);
NotificationI18nData i18nArg = (NotificationI18nData) args.get(3);
try { try {
api.createNotificationChannel(titleArg, idArg, urgentArg, i18nArg); api.createNotificationChannel(titleArg, idArg, urgentArg);
wrapped.add(0, null); wrapped.add(0, null);
} }
catch (Throwable exception) { catch (Throwable exception) {
@ -788,6 +789,30 @@ public class Api {
api.setNotificationSelfAvatar(pathArg); api.setNotificationSelfAvatar(pathArg);
wrapped.add(0, null); wrapped.add(0, null);
} }
catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError;
}
reply.reply(wrapped);
});
} else {
channel.setMessageHandler(null);
}
}
{
BasicMessageChannel<Object> channel =
new BasicMessageChannel<>(
binaryMessenger, "dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationI18n", getCodec());
if (api != null) {
channel.setMessageHandler(
(message, reply) -> {
ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message;
NotificationI18nData dataArg = (NotificationI18nData) args.get(0);
try {
api.setNotificationI18n(dataArg);
wrapped.add(0, null);
}
catch (Throwable exception) { catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception); ArrayList<Object> wrappedError = wrapError(exception);
wrapped = wrappedError; wrapped = wrappedError;

View File

@ -288,7 +288,7 @@ import kotlin.jvm.functions.Function1;
} }
@Override @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( final NotificationChannel channel = new NotificationChannel(
id, id,
title, title,
@ -298,11 +298,6 @@ import kotlin.jvm.functions.Function1;
channel.enableLights(true); channel.enableLights(true);
final NotificationManager manager = getSystemService(context, NotificationManager.class); final NotificationManager manager = getSystemService(context, NotificationManager.class);
manager.createNotificationChannel(channel); manager.createNotificationChannel(channel);
// Configure i18n
NotificationDataManager.INSTANCE.setYou(i18n.getYou());
NotificationDataManager.INSTANCE.setReply(i18n.getReply());
NotificationDataManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead());
} }
@Override @Override
@ -315,6 +310,14 @@ import kotlin.jvm.functions.Function1;
NotificationDataManager.INSTANCE.setAvatarPath(path); 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 @NonNull
@Override @Override
public String getPersistentDataPath() { public String getPersistentDataPath() {

View File

@ -1,9 +1,11 @@
package me.polynom.moxplatform_android package me.polynom.moxplatform_android
import android.app.Notification
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person import androidx.core.app.Person
@ -38,8 +40,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
PendingIntent.FLAG_UPDATE_CURRENT, PendingIntent.FLAG_UPDATE_CURRENT,
) )
val replyAction = NotificationCompat.Action.Builder( val replyAction = NotificationCompat.Action.Builder(
// TODO: Wrong icon? R.drawable.reply,
R.drawable.ic_service_icon,
NotificationDataManager.reply, NotificationDataManager.reply,
replyPendingIntent, replyPendingIntent,
).apply { ).apply {
@ -60,8 +61,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
PendingIntent.FLAG_UPDATE_CURRENT, PendingIntent.FLAG_UPDATE_CURRENT,
) )
val markAsReadAction = NotificationCompat.Action.Builder( val markAsReadAction = NotificationCompat.Action.Builder(
// TODO: Wrong icon R.drawable.mark_as_read,
R.drawable.ic_service_icon,
NotificationDataManager.markAsRead, NotificationDataManager.markAsRead,
markAsReadPendingIntent, markAsReadPendingIntent,
).build() ).build()
@ -141,8 +141,11 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
// Assemble the notification // Assemble the notification
val finalNotification = NotificationCompat.Builder(context, notification.channelId).apply { val finalNotification = NotificationCompat.Builder(context, notification.channelId).apply {
setStyle(style) 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) setSmallIcon(R.drawable.ic_service_icon)
color = Color.argb(255, 207, 74, 255)
setColorized(true)
// Tap action // Tap action
setContentIntent(tapPendingIntent) setContentIntent(tapPendingIntent)
@ -151,6 +154,9 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
addAction(replyAction) addAction(replyAction)
addAction(markAsReadAction) addAction(markAsReadAction)
setAllowSystemGeneratedContextualActions(true)
setCategory(Notification.CATEGORY_MESSAGE)
// Prevent no notification when we replied before // Prevent no notification when we replied before
setOnlyAlertOnce(false) setOnlyAlertOnce(false)
}.build() }.build()

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17.34,20l-3.54,-3.54l1.41,-1.41l2.12,2.12l4.24,-4.24L23,14.34L17.34,20zM12,17c0,-3.87 3.13,-7 7,-7c1.08,0 2.09,0.25 3,0.68V4c0,-1.1 -0.9,-2 -2,-2H4C2.9,2 2,2.9 2,4v18l4,-4h6v0c0,-0.17 0.01,-0.33 0.03,-0.5C12.01,17.34 12,17.17 12,17z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#FFFFFF" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/>
</vector>

View File

@ -13,9 +13,8 @@ class AndroidNotificationsImplementation extends NotificationsImplementation {
String title, String title,
String id, String id,
bool urgent, bool urgent,
NotificationI18nData i18n,
) async { ) async {
return _api.createNotificationChannel(title, id, urgent, i18n); return _api.createNotificationChannel(title, id, urgent);
} }
@override @override
@ -30,6 +29,11 @@ class AndroidNotificationsImplementation extends NotificationsImplementation {
return _api.setNotificationSelfAvatar(path); return _api.setNotificationSelfAvatar(path);
} }
@override
Future<void> setI18n(NotificationI18nData data) {
return _api.setNotificationI18n(data);
}
@override @override
Stream<NotificationEvent> getEventStream() => _channel Stream<NotificationEvent> getEventStream() => _channel
.receiveBroadcastStream() .receiveBroadcastStream()

View File

@ -262,12 +262,12 @@ class MoxplatformApi {
static const MessageCodec<Object?> codec = _MoxplatformApiCodec(); static const MessageCodec<Object?> codec = _MoxplatformApiCodec();
Future<void> createNotificationChannel(String arg_title, String arg_id, bool arg_urgent, NotificationI18nData arg_i18n) async { Future<void> createNotificationChannel(String arg_title, String arg_id, bool arg_urgent) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationChannel', codec, 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationChannel', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList =
await channel.send(<Object?>[arg_title, arg_id, arg_urgent, arg_i18n]) as List<Object?>?; await channel.send(<Object?>[arg_title, arg_id, arg_urgent]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -328,6 +328,28 @@ class MoxplatformApi {
} }
} }
Future<void> setNotificationI18n(NotificationI18nData arg_data) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationI18n', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(<Object?>[arg_data]) as List<Object?>?;
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<String> getPersistentDataPath() async { Future<String> getPersistentDataPath() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath', codec, 'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath', codec,

View File

@ -2,11 +2,18 @@ import 'dart:async';
import 'package:moxplatform_platform_interface/src/api.g.dart'; import 'package:moxplatform_platform_interface/src/api.g.dart';
abstract class NotificationsImplementation { abstract class NotificationsImplementation {
Future<void> 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<void> createNotificationChannel(String title, String id, bool urgent);
/// Shows a notification [notification] in the messaging style with everyting it needs.
Future<void> showMessagingNotification(MessagingNotification notification); Future<void> showMessagingNotification(MessagingNotification notification);
/// Sets the path to the self-avatar for in-notification replies.
Future<void> setNotificationSelfAvatar(String path); Future<void> setNotificationSelfAvatar(String path);
/// Configures the i18n data for usage in notifications.
Future<void> setI18n(NotificationI18nData data);
Stream<NotificationEvent> getEventStream(); Stream<NotificationEvent> getEventStream();
} }

View File

@ -4,7 +4,7 @@ import 'package:moxplatform_platform_interface/src/notifications.dart';
class StubNotificationsImplementation extends NotificationsImplementation { class StubNotificationsImplementation extends NotificationsImplementation {
@override @override
Future<void> createNotificationChannel(String title, String id, bool urgent, NotificationI18nData i18n) async {} Future<void> createNotificationChannel(String title, String id, bool urgent) async {}
@override @override
Future<void> showMessagingNotification(MessagingNotification notification) async {} Future<void> showMessagingNotification(MessagingNotification notification) async {}
@ -12,6 +12,9 @@ class StubNotificationsImplementation extends NotificationsImplementation {
@override @override
Future<void> setNotificationSelfAvatar(String path) async {} Future<void> setNotificationSelfAvatar(String path) async {}
@override
Future<void> setI18n(NotificationI18nData data) async {}
@override @override
Stream<NotificationEvent> getEventStream() { Stream<NotificationEvent> getEventStream() {
return StreamController<NotificationEvent>().stream; return StreamController<NotificationEvent>().stream;

View File

@ -112,15 +112,11 @@ class NotificationI18nData {
@HostApi() @HostApi()
abstract class MoxplatformApi { 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 showMessagingNotification(MessagingNotification notification);
void setNotificationSelfAvatar(String path); void setNotificationSelfAvatar(String path);
void setNotificationI18n(NotificationI18nData data);
String getPersistentDataPath(); String getPersistentDataPath();
String getCacheDataPath(); String getCacheDataPath();
void eventStub(NotificationEvent event); void eventStub(NotificationEvent event);
} }