feat: Allow setting the self-avatar
This commit is contained in:
parent
e975e749e4
commit
daf40aed0b
@ -189,6 +189,17 @@ class MyHomePage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: const Text('Show messaging notification'),
|
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(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
print(await MoxplatformPlugin.platform.getPersistentDataPath());
|
print(await MoxplatformPlugin.platform.getPersistentDataPath());
|
||||||
|
@ -707,6 +707,8 @@ public class Api {
|
|||||||
|
|
||||||
void showMessagingNotification(@NonNull MessagingNotification notification);
|
void showMessagingNotification(@NonNull MessagingNotification notification);
|
||||||
|
|
||||||
|
void setNotificationSelfAvatar(@NonNull String path);
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
String getPersistentDataPath();
|
String getPersistentDataPath();
|
||||||
|
|
||||||
@ -762,6 +764,30 @@ public class Api {
|
|||||||
api.showMessagingNotification(notificationArg);
|
api.showMessagingNotification(notificationArg);
|
||||||
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.setNotificationSelfAvatar", getCodec());
|
||||||
|
if (api != null) {
|
||||||
|
channel.setMessageHandler(
|
||||||
|
(message, reply) -> {
|
||||||
|
ArrayList<Object> wrapped = new ArrayList<Object>();
|
||||||
|
ArrayList<Object> args = (ArrayList<Object>) message;
|
||||||
|
String pathArg = (String) args.get(0);
|
||||||
|
try {
|
||||||
|
api.setNotificationSelfAvatar(pathArg);
|
||||||
|
wrapped.add(0, null);
|
||||||
|
}
|
||||||
catch (Throwable exception) {
|
catch (Throwable exception) {
|
||||||
ArrayList<Object> wrappedError = wrapError(exception);
|
ArrayList<Object> wrappedError = wrapError(exception);
|
||||||
wrapped = wrappedError;
|
wrapped = wrappedError;
|
||||||
|
@ -300,9 +300,9 @@ import kotlin.jvm.functions.Function1;
|
|||||||
manager.createNotificationChannel(channel);
|
manager.createNotificationChannel(channel);
|
||||||
|
|
||||||
// Configure i18n
|
// Configure i18n
|
||||||
NotificationI18nManager.INSTANCE.setYou(i18n.getYou());
|
NotificationDataManager.INSTANCE.setYou(i18n.getYou());
|
||||||
NotificationI18nManager.INSTANCE.setReply(i18n.getReply());
|
NotificationDataManager.INSTANCE.setReply(i18n.getReply());
|
||||||
NotificationI18nManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead());
|
NotificationDataManager.INSTANCE.setMarkAsRead(i18n.getMarkAsRead());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -310,6 +310,11 @@ import kotlin.jvm.functions.Function1;
|
|||||||
NotificationsKt.showMessagingNotification(context, notification);
|
NotificationsKt.showMessagingNotification(context, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNotificationSelfAvatar(@NonNull String path) {
|
||||||
|
NotificationDataManager.INSTANCE.setAvatarPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String getPersistentDataPath() {
|
public String getPersistentDataPath() {
|
||||||
|
@ -6,6 +6,8 @@ import android.app.PendingIntent
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
@ -13,6 +15,7 @@ import androidx.core.app.NotificationManagerCompat
|
|||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
import androidx.core.app.RemoteInput
|
import androidx.core.app.RemoteInput
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import me.polynom.moxplatform_android.Api.NotificationEvent
|
import me.polynom.moxplatform_android.Api.NotificationEvent
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
@ -43,8 +46,6 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt())
|
NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt())
|
||||||
MoxplatformAndroidPlugin.notificationSink?.success(
|
MoxplatformAndroidPlugin.notificationSink?.success(
|
||||||
NotificationEvent().apply {
|
NotificationEvent().apply {
|
||||||
// TODO: Use constant for key
|
|
||||||
// TODO: Fix
|
|
||||||
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
||||||
type = Api.NotificationEventType.MARK_AS_READ
|
type = Api.NotificationEventType.MARK_AS_READ
|
||||||
payload = null
|
payload = null
|
||||||
@ -59,7 +60,6 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
val replyPayload = remoteInput.getCharSequence(REPLY_TEXT_KEY)
|
val replyPayload = remoteInput.getCharSequence(REPLY_TEXT_KEY)
|
||||||
MoxplatformAndroidPlugin.notificationSink?.success(
|
MoxplatformAndroidPlugin.notificationSink?.success(
|
||||||
NotificationEvent().apply {
|
NotificationEvent().apply {
|
||||||
// TODO: Use constant for key
|
|
||||||
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
||||||
type = Api.NotificationEventType.REPLY
|
type = Api.NotificationEventType.REPLY
|
||||||
payload = replyPayload.toString()
|
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
|
// Thanks https://medium.com/@sidorovroman3/android-how-to-use-messagingstyle-for-notifications-without-caching-messages-c414ef2b816c
|
||||||
val recoveredStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification)!!
|
val recoveredStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification)!!
|
||||||
// TODO: Use a person and cache this data somewhere
|
val newStyle = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||||
val newStyle = Notification.MessagingStyle(NotificationI18nManager.you).apply {
|
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
|
conversationTitle = recoveredStyle.conversationTitle
|
||||||
// TODO: Use person
|
|
||||||
recoveredStyle.messages.forEach {
|
recoveredStyle.messages.forEach {
|
||||||
// Check if we have to request (or refresh) the content URI to be able to still
|
// Check if we have to request (or refresh) the content URI to be able to still
|
||||||
// see the embedded image.
|
// see the embedded image.
|
||||||
|
@ -12,10 +12,11 @@ import androidx.core.content.FileProvider
|
|||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object NotificationI18nManager {
|
object NotificationDataManager {
|
||||||
var you: String = "You"
|
var you: String = "You"
|
||||||
var markAsRead: String = "Mark as read"
|
var markAsRead: String = "Mark as read"
|
||||||
var reply: String = "Reply"
|
var reply: String = "Reply"
|
||||||
|
var avatarPath: String? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show a messaging style notification described by @notification.
|
/// Show a messaging style notification described by @notification.
|
||||||
@ -23,7 +24,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
|
|||||||
// Build the actions
|
// Build the actions
|
||||||
// -> Reply action
|
// -> Reply action
|
||||||
val remoteInput = RemoteInput.Builder(REPLY_TEXT_KEY).apply {
|
val remoteInput = RemoteInput.Builder(REPLY_TEXT_KEY).apply {
|
||||||
setLabel(NotificationI18nManager.reply)
|
setLabel(NotificationDataManager.reply)
|
||||||
}.build()
|
}.build()
|
||||||
val replyIntent = Intent(context, NotificationReceiver::class.java).apply {
|
val replyIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
action = REPLY_ACTION
|
action = REPLY_ACTION
|
||||||
@ -39,7 +40,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
|
|||||||
val replyAction = NotificationCompat.Action.Builder(
|
val replyAction = NotificationCompat.Action.Builder(
|
||||||
// TODO: Wrong icon?
|
// TODO: Wrong icon?
|
||||||
R.drawable.ic_service_icon,
|
R.drawable.ic_service_icon,
|
||||||
NotificationI18nManager.reply,
|
NotificationDataManager.reply,
|
||||||
replyPendingIntent,
|
replyPendingIntent,
|
||||||
).apply {
|
).apply {
|
||||||
addRemoteInput(remoteInput)
|
addRemoteInput(remoteInput)
|
||||||
@ -61,8 +62,7 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
|
|||||||
val markAsReadAction = NotificationCompat.Action.Builder(
|
val markAsReadAction = NotificationCompat.Action.Builder(
|
||||||
// TODO: Wrong icon
|
// TODO: Wrong icon
|
||||||
R.drawable.ic_service_icon,
|
R.drawable.ic_service_icon,
|
||||||
// TODO: i18n
|
NotificationDataManager.markAsRead,
|
||||||
NotificationI18nManager.markAsRead,
|
|
||||||
markAsReadPendingIntent,
|
markAsReadPendingIntent,
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
@ -81,8 +81,19 @@ fun showMessagingNotification(context: Context, notification: Api.MessagingNotif
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Build the notification
|
// Build the notification
|
||||||
// TODO: Use a person
|
val selfPerson = Person.Builder().apply {
|
||||||
val style = NotificationCompat.MessagingStyle(NotificationI18nManager.you);
|
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) {
|
for (message in notification.messages) {
|
||||||
// Build the sender
|
// Build the sender
|
||||||
val sender = Person.Builder().apply {
|
val sender = Person.Builder().apply {
|
||||||
|
@ -25,6 +25,11 @@ class AndroidNotificationsImplementation extends NotificationsImplementation {
|
|||||||
return _api.showMessagingNotification(notification);
|
return _api.showMessagingNotification(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setNotificationSelfAvatar(String path) async {
|
||||||
|
return _api.setNotificationSelfAvatar(path);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<NotificationEvent> getEventStream() => _channel
|
Stream<NotificationEvent> getEventStream() => _channel
|
||||||
.receiveBroadcastStream()
|
.receiveBroadcastStream()
|
||||||
|
@ -306,6 +306,28 @@ class MoxplatformApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> setNotificationSelfAvatar(String arg_path) async {
|
||||||
|
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||||
|
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.setNotificationSelfAvatar', codec,
|
||||||
|
binaryMessenger: _binaryMessenger);
|
||||||
|
final List<Object?>? replyList =
|
||||||
|
await channel.send(<Object?>[arg_path]) 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,
|
||||||
|
@ -6,5 +6,7 @@ abstract class NotificationsImplementation {
|
|||||||
|
|
||||||
Future<void> showMessagingNotification(MessagingNotification notification);
|
Future<void> showMessagingNotification(MessagingNotification notification);
|
||||||
|
|
||||||
|
Future<void> setNotificationSelfAvatar(String path);
|
||||||
|
|
||||||
Stream<NotificationEvent> getEventStream();
|
Stream<NotificationEvent> getEventStream();
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ class StubNotificationsImplementation extends NotificationsImplementation {
|
|||||||
@override
|
@override
|
||||||
Future<void> showMessagingNotification(MessagingNotification notification) async {}
|
Future<void> showMessagingNotification(MessagingNotification notification) async {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> setNotificationSelfAvatar(String path) async {}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<NotificationEvent> getEventStream() {
|
Stream<NotificationEvent> getEventStream() {
|
||||||
return StreamController<NotificationEvent>().stream;
|
return StreamController<NotificationEvent>().stream;
|
||||||
|
@ -116,6 +116,8 @@ abstract class MoxplatformApi {
|
|||||||
|
|
||||||
void showMessagingNotification(MessagingNotification notification);
|
void showMessagingNotification(MessagingNotification notification);
|
||||||
|
|
||||||
|
void setNotificationSelfAvatar(String path);
|
||||||
|
|
||||||
String getPersistentDataPath();
|
String getPersistentDataPath();
|
||||||
|
|
||||||
String getCacheDataPath();
|
String getCacheDataPath();
|
||||||
|
Reference in New Issue
Block a user