chore(android,base,interface): Move notification stuff into Moxxy
This commit is contained in:
parent
7cc2d0e4be
commit
f2b140de18
@ -4,7 +4,5 @@ class MoxplatformPlugin {
|
||||
static IsolateHandler get handler => MoxplatformInterface.handler;
|
||||
static CryptographyImplementation get crypto => MoxplatformInterface.crypto;
|
||||
static ContactsImplementation get contacts => MoxplatformInterface.contacts;
|
||||
static NotificationsImplementation get notifications =>
|
||||
MoxplatformInterface.notifications;
|
||||
static PlatformImplementation get platform => MoxplatformInterface.platform;
|
||||
}
|
||||
|
@ -8,16 +8,6 @@
|
||||
|
||||
|
||||
<application>
|
||||
<provider
|
||||
android:name="me.polynom.moxplatform_android.MoxplatformFileProvider"
|
||||
android:authorities="me.polynom.moxplatform_android.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<service
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
@ -38,7 +28,5 @@
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".NotificationReceiver" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +0,0 @@
|
||||
package me.polynom.moxplatform_android
|
||||
|
||||
import androidx.core.content.FileProvider
|
||||
|
||||
class MoxplatformFileProvider : FileProvider(R.xml.file_paths) {
|
||||
}
|
@ -6,13 +6,12 @@ import static androidx.core.content.ContextCompat.startActivity;
|
||||
import static me.polynom.moxplatform_android.ConstantsKt.MOXPLATFORM_FILEPROVIDER_ID;
|
||||
import static me.polynom.moxplatform_android.ConstantsKt.SHARED_PREFERENCES_KEY;
|
||||
import static me.polynom.moxplatform_android.CryptoKt.*;
|
||||
import static me.polynom.moxplatform_android.NotificationsKt.createNotificationChannelsImpl;
|
||||
import static me.polynom.moxplatform_android.NotificationsKt.createNotificationGroupsImpl;
|
||||
import static me.polynom.moxplatform_android.RecordSentMessageKt.*;
|
||||
import static me.polynom.moxplatform_android.ThumbnailsKt.generateVideoThumbnailImplementation;
|
||||
|
||||
import me.polynom.moxplatform_android.Api.*;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@ -60,7 +59,7 @@ import io.flutter.plugin.common.JSONMethodCodec;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
|
||||
public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, EventChannel.StreamHandler, ServiceAware, MoxplatformApi {
|
||||
public class MoxplatformAndroidPlugin extends BroadcastReceiver implements FlutterPlugin, MethodCallHandler, ServiceAware, MoxplatformApi {
|
||||
public static final String entrypointKey = "entrypoint_handle";
|
||||
public static final String extraDataKey = "extra_data";
|
||||
private static final String autoStartAtBootKey = "auto_start_at_boot";
|
||||
@ -71,8 +70,8 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
private static final List<MoxplatformAndroidPlugin> _instances = new ArrayList<>();
|
||||
private BackgroundService service;
|
||||
private MethodChannel channel;
|
||||
private static EventChannel notificationChannel;
|
||||
public static EventSink notificationSink;
|
||||
|
||||
public static Activity activity;
|
||||
|
||||
private Context context;
|
||||
|
||||
@ -86,10 +85,6 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
channel.setMethodCallHandler(this);
|
||||
context = flutterPluginBinding.getApplicationContext();
|
||||
|
||||
notificationChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "me.polynom/notification_stream");
|
||||
notificationChannel.setStreamHandler(this);
|
||||
|
||||
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this.context);
|
||||
localBroadcastManager.registerReceiver(this, new IntentFilter(methodChannelKey));
|
||||
|
||||
@ -102,6 +97,7 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(registrar.context());
|
||||
final MoxplatformAndroidPlugin plugin = new MoxplatformAndroidPlugin();
|
||||
localBroadcastManager.registerReceiver(plugin, new IntentFilter(methodChannelKey));
|
||||
activity = registrar.activity();
|
||||
|
||||
final MethodChannel channel = new MethodChannel(registrar.messenger(), "me.polynom/background_service_android", JSONMethodCodec.INSTANCE);
|
||||
channel.setMethodCallHandler(plugin);
|
||||
@ -110,18 +106,6 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
Log.d(TAG, "Registered against registrar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(Object arguments) {
|
||||
Log.d(TAG, "Removed listener");
|
||||
notificationSink = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onListen(Object arguments, EventChannel.EventSink eventSink) {
|
||||
Log.d(TAG, "Attached listener");
|
||||
notificationSink = eventSink;
|
||||
}
|
||||
|
||||
/// Store the entrypoint handle and extra data for the background service.
|
||||
private void configure(long entrypointHandle, String extraData) {
|
||||
SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE);
|
||||
@ -226,60 +210,6 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
this.service = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createNotificationGroups(@NonNull List<NotificationGroup> groups) {
|
||||
createNotificationGroupsImpl(context, groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteNotificationGroups(@NonNull List<String> ids) {
|
||||
final NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
for (final String id : ids) {
|
||||
notificationManager.deleteNotificationChannelGroup(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createNotificationChannels(@NonNull List<Api.NotificationChannel> channels) {
|
||||
createNotificationChannelsImpl(context, channels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteNotificationChannels(@NonNull List<String> ids) {
|
||||
final NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
|
||||
for (final String id : ids) {
|
||||
notificationManager.deleteNotificationChannel(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessagingNotification(@NonNull MessagingNotification notification) {
|
||||
NotificationsKt.showMessagingNotification(context, notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showNotification(@NonNull RegularNotification notification) {
|
||||
NotificationsKt.showNotification(context, notification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissNotification(@NonNull Long id) {
|
||||
NotificationManagerCompat.from(context).cancel(id.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationSelfAvatar(@NonNull String path) {
|
||||
NotificationDataManager.INSTANCE.setAvatarPath(context, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationI18n(@NonNull NotificationI18nData data) {
|
||||
// Configure i18n
|
||||
NotificationDataManager.INSTANCE.setYou(context, data.getYou());
|
||||
NotificationDataManager.INSTANCE.setReply(context, data.getReply());
|
||||
NotificationDataManager.INSTANCE.setMarkAsRead(context, data.getMarkAsRead());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getPersistentDataPath() {
|
||||
@ -349,9 +279,4 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
|
||||
public Boolean generateVideoThumbnail(@NonNull String src, @NonNull String dest, @NonNull Long maxWidth) {
|
||||
return generateVideoThumbnailImplementation(src, dest, maxWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventStub(@NonNull NotificationEvent event) {
|
||||
// Stub to trick pigeon into
|
||||
}
|
||||
}
|
||||
|
@ -1,197 +0,0 @@
|
||||
package me.polynom.moxplatform_android
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
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
|
||||
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
|
||||
|
||||
class NotificationReceiver : BroadcastReceiver() {
|
||||
/*
|
||||
* Dismisses the notification through which we received @intent.
|
||||
* */
|
||||
private fun dismissNotification(context: Context, intent: Intent) {
|
||||
// Dismiss the notification
|
||||
val notificationId = intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1).toInt()
|
||||
if (notificationId != -1) {
|
||||
NotificationManagerCompat.from(context).cancel(
|
||||
notificationId,
|
||||
)
|
||||
} else {
|
||||
Log.e("NotificationReceiver", "No id specified. Cannot dismiss notification")
|
||||
}
|
||||
}
|
||||
|
||||
private fun findActiveNotification(context: Context, id: Int): Notification? {
|
||||
return (context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
|
||||
.activeNotifications
|
||||
.find { it.id == id }?.notification
|
||||
}
|
||||
|
||||
private fun extractPayloadMapFromIntent(intent: Intent): Map<String?, String?> {
|
||||
val extras = mutableMapOf<String?, String?>()
|
||||
intent.extras?.keySet()!!.forEach {
|
||||
Log.d(TAG, "Checking $it -> ${intent.extras!!.get(it)}")
|
||||
if (it.startsWith("payload_")) {
|
||||
Log.d(TAG, "Adding $it")
|
||||
extras[it.substring(8)] = intent.extras!!.getString(it)
|
||||
}
|
||||
}
|
||||
|
||||
return extras
|
||||
}
|
||||
|
||||
private fun handleMarkAsRead(context: Context, intent: Intent) {
|
||||
MoxplatformAndroidPlugin.notificationSink?.success(
|
||||
NotificationEvent().apply {
|
||||
id = intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1)
|
||||
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
||||
type = Api.NotificationEventType.MARK_AS_READ
|
||||
payload = null
|
||||
extra = extractPayloadMapFromIntent(intent)
|
||||
}.toList()
|
||||
)
|
||||
|
||||
NotificationManagerCompat.from(context).cancel(intent.getLongExtra(MARK_AS_READ_ID_KEY, -1).toInt())
|
||||
dismissNotification(context, intent);
|
||||
}
|
||||
|
||||
private fun handleReply(context: Context, intent: Intent) {
|
||||
val remoteInput = RemoteInput.getResultsFromIntent(intent) ?: return
|
||||
val replyPayload = remoteInput.getCharSequence(REPLY_TEXT_KEY)
|
||||
MoxplatformAndroidPlugin.notificationSink?.success(
|
||||
NotificationEvent().apply {
|
||||
id = intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1)
|
||||
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
||||
type = Api.NotificationEventType.REPLY
|
||||
payload = replyPayload.toString()
|
||||
extra = extractPayloadMapFromIntent(intent)
|
||||
}.toList()
|
||||
)
|
||||
|
||||
val id = intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1).toInt()
|
||||
if (id == -1) {
|
||||
Log.e(TAG, "Failed to find notification id for reply")
|
||||
return;
|
||||
}
|
||||
|
||||
val notification = findActiveNotification(context, id)
|
||||
if (notification == null) {
|
||||
Log.e(TAG, "Failed to find notification for id $id")
|
||||
return
|
||||
}
|
||||
|
||||
// Thanks https://medium.com/@sidorovroman3/android-how-to-use-messagingstyle-for-notifications-without-caching-messages-c414ef2b816c
|
||||
val recoveredStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification)!!
|
||||
val newStyle = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||
Notification.MessagingStyle(
|
||||
android.app.Person.Builder().apply {
|
||||
setName(NotificationDataManager.getYou(context))
|
||||
|
||||
// Set an avatar, if we have one
|
||||
val avatarPath = NotificationDataManager.getAvatarPath(context)
|
||||
if (avatarPath != null) {
|
||||
setIcon(
|
||||
Icon.createWithAdaptiveBitmap(
|
||||
BitmapFactory.decodeFile(avatarPath)
|
||||
)
|
||||
)
|
||||
}
|
||||
}.build()
|
||||
)
|
||||
else Notification.MessagingStyle(NotificationDataManager.getYou(context))
|
||||
|
||||
newStyle.apply {
|
||||
conversationTitle = recoveredStyle.conversationTitle
|
||||
recoveredStyle.messages.forEach {
|
||||
// Check if we have to request (or refresh) the content URI to be able to still
|
||||
// see the embedded image.
|
||||
val mime = it.extras.getString(NOTIFICATION_MESSAGE_EXTRA_MIME)
|
||||
val path = it.extras.getString(NOTIFICATION_MESSAGE_EXTRA_PATH)
|
||||
val message = Notification.MessagingStyle.Message(it.text, it.timestamp, it.sender)
|
||||
if (mime != null && path != null) {
|
||||
// Request a new URI from the file provider to ensure we can still see the image
|
||||
// in the notification
|
||||
val fileUri = FileProvider.getUriForFile(
|
||||
context,
|
||||
MOXPLATFORM_FILEPROVIDER_ID,
|
||||
File(path),
|
||||
)
|
||||
message.setData(
|
||||
mime,
|
||||
fileUri,
|
||||
)
|
||||
|
||||
// As we're creating a new message, also recreate the additional metadata
|
||||
message.extras.apply {
|
||||
putString(NOTIFICATION_MESSAGE_EXTRA_MIME, mime)
|
||||
putString(NOTIFICATION_MESSAGE_EXTRA_PATH, path)
|
||||
}
|
||||
}
|
||||
|
||||
// Append the old message
|
||||
addMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
// Append our new message
|
||||
newStyle.addMessage(
|
||||
Notification.MessagingStyle.Message(
|
||||
replyPayload!!,
|
||||
Instant.now().toEpochMilli(),
|
||||
null as CharSequence?
|
||||
)
|
||||
)
|
||||
|
||||
// Post the new notification
|
||||
val recoveredBuilder = Notification.Builder.recoverBuilder(context, notification).apply {
|
||||
style = newStyle
|
||||
setOnlyAlertOnce(true)
|
||||
}
|
||||
NotificationManagerCompat.from(context).notify(id, recoveredBuilder.build())
|
||||
}
|
||||
|
||||
private fun handleTap(context: Context, intent: Intent) {
|
||||
MoxplatformAndroidPlugin.notificationSink?.success(
|
||||
NotificationEvent().apply {
|
||||
id = intent.getLongExtra(NOTIFICATION_EXTRA_ID_KEY, -1)
|
||||
jid = intent.getStringExtra(NOTIFICATION_EXTRA_JID_KEY)!!
|
||||
type = Api.NotificationEventType.OPEN
|
||||
payload = null
|
||||
extra = extractPayloadMapFromIntent(intent)
|
||||
}.toList()
|
||||
)
|
||||
|
||||
// Bring the app into the foreground
|
||||
val tapIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)!!
|
||||
context.startActivity(tapIntent)
|
||||
|
||||
// Dismiss the notification
|
||||
dismissNotification(context, intent)
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
// TODO: We need to be careful to ensure that the Flutter engine is running.
|
||||
// If it's not, we have to start it. However, that's only an issue when we expect to
|
||||
// receive notifications while not running, i.e. Push Notifications.
|
||||
when (intent.action) {
|
||||
MARK_AS_READ_ACTION -> handleMarkAsRead(context, intent)
|
||||
REPLY_ACTION -> handleReply(context, intent)
|
||||
TAP_ACTION -> handleTap(context, intent)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
package me.polynom.moxplatform_android
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationChannelGroup
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
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 java.io.File
|
||||
|
||||
/*
|
||||
* Holds "persistent" data for notifications, like i18n strings. While not useful now, this is
|
||||
* useful for when the app is dead and we receive a notification.
|
||||
* */
|
||||
object NotificationDataManager {
|
||||
private var you: String? = null
|
||||
private var markAsRead: String? = null
|
||||
private var reply: String? = null
|
||||
|
||||
private var fetchedAvatarPath = false
|
||||
private var avatarPath: String? = null
|
||||
|
||||
private fun getString(context: Context, key: String, fallback: String): String {
|
||||
return context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)!!.getString(key, fallback)!!
|
||||
}
|
||||
|
||||
private fun setString(context: Context, key: String, value: String) {
|
||||
val prefs = context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
|
||||
prefs.edit()
|
||||
.putString(key, value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun getYou(context: Context): String {
|
||||
if (you == null) you = getString(context, SHARED_PREFERENCES_YOU_KEY, "You")
|
||||
return you!!
|
||||
}
|
||||
|
||||
fun setYou(context: Context, value: String) {
|
||||
setString(context, SHARED_PREFERENCES_YOU_KEY, value)
|
||||
you = value
|
||||
}
|
||||
|
||||
fun getMarkAsRead(context: Context): String {
|
||||
if (markAsRead == null) markAsRead = getString(context, SHARED_PREFERENCES_MARK_AS_READ_KEY, "Mark as read")
|
||||
return markAsRead!!
|
||||
}
|
||||
|
||||
fun setMarkAsRead(context: Context, value: String) {
|
||||
setString(context, SHARED_PREFERENCES_MARK_AS_READ_KEY, value)
|
||||
markAsRead = value
|
||||
}
|
||||
|
||||
fun getReply(context: Context): String {
|
||||
if (reply != null) reply = getString(context, SHARED_PREFERENCES_REPLY_KEY, "Reply")
|
||||
return reply!!
|
||||
}
|
||||
|
||||
fun setReply(context: Context, value: String) {
|
||||
setString(context, SHARED_PREFERENCES_REPLY_KEY, value)
|
||||
reply = value
|
||||
}
|
||||
|
||||
fun getAvatarPath(context: Context): String? {
|
||||
if (avatarPath == null && !fetchedAvatarPath) {
|
||||
val path = getString(context, SHARED_PREFERENCES_AVATAR_KEY, "")
|
||||
if (path.isNotEmpty()) {
|
||||
avatarPath = path
|
||||
}
|
||||
}
|
||||
|
||||
return avatarPath
|
||||
}
|
||||
|
||||
fun setAvatarPath(context: Context, value: String) {
|
||||
setString(context, SHARED_PREFERENCES_AVATAR_KEY, value)
|
||||
fetchedAvatarPath = true
|
||||
avatarPath = value
|
||||
}
|
||||
}
|
||||
|
||||
fun createNotificationGroupsImpl(context: Context, groups: List<Api.NotificationGroup>) {
|
||||
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
for (group in groups) {
|
||||
notificationManager.createNotificationChannelGroup(
|
||||
NotificationChannelGroup(group.id, group.description),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun createNotificationChannelsImpl(context: Context, channels: List<Api.NotificationChannel>) {
|
||||
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
for (channel in channels) {
|
||||
val importance = when(channel.importance) {
|
||||
Api.NotificationChannelImportance.DEFAULT -> NotificationManager.IMPORTANCE_DEFAULT
|
||||
Api.NotificationChannelImportance.MIN -> NotificationManager.IMPORTANCE_MIN
|
||||
Api.NotificationChannelImportance.HIGH -> NotificationManager.IMPORTANCE_HIGH
|
||||
}
|
||||
val notificationChannel = NotificationChannel(channel.id, channel.title, importance).apply {
|
||||
description = channel.description
|
||||
|
||||
enableVibration(channel.vibration)
|
||||
enableLights(channel.enableLights)
|
||||
setShowBadge(channel.showBadge)
|
||||
if (channel.groupId != null) {
|
||||
group = channel.groupId
|
||||
}
|
||||
}
|
||||
notificationManager.createNotificationChannel(notificationChannel)
|
||||
}
|
||||
}
|
||||
|
||||
/// Show a messaging style notification described by @notification.
|
||||
fun showMessagingNotification(context: Context, notification: Api.MessagingNotification) {
|
||||
// Build the actions
|
||||
// -> Reply action
|
||||
val remoteInput = RemoteInput.Builder(REPLY_TEXT_KEY).apply {
|
||||
setLabel(NotificationDataManager.getReply(context))
|
||||
}.build()
|
||||
val replyIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = REPLY_ACTION
|
||||
putExtra(NOTIFICATION_EXTRA_JID_KEY, notification.jid)
|
||||
putExtra(NOTIFICATION_EXTRA_ID_KEY, notification.id)
|
||||
|
||||
notification.extra?.forEach {
|
||||
putExtra("payload_${it.key}", it.value)
|
||||
}
|
||||
}
|
||||
val replyPendingIntent = PendingIntent.getBroadcast(
|
||||
context.applicationContext,
|
||||
0,
|
||||
replyIntent,
|
||||
PendingIntent.FLAG_MUTABLE,
|
||||
)
|
||||
val replyAction = NotificationCompat.Action.Builder(
|
||||
R.drawable.reply,
|
||||
NotificationDataManager.getReply(context),
|
||||
replyPendingIntent,
|
||||
).apply {
|
||||
addRemoteInput(remoteInput)
|
||||
setAllowGeneratedReplies(true)
|
||||
}.build()
|
||||
|
||||
// -> Mark as read action
|
||||
val markAsReadIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = MARK_AS_READ_ACTION
|
||||
putExtra(NOTIFICATION_EXTRA_JID_KEY, notification.jid)
|
||||
putExtra(NOTIFICATION_EXTRA_ID_KEY, notification.id)
|
||||
|
||||
notification.extra?.forEach {
|
||||
putExtra("payload_${it.key}", it.value)
|
||||
}
|
||||
}
|
||||
val markAsReadPendingIntent = PendingIntent.getBroadcast(
|
||||
context.applicationContext,
|
||||
0,
|
||||
markAsReadIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
val markAsReadAction = NotificationCompat.Action.Builder(
|
||||
R.drawable.mark_as_read,
|
||||
NotificationDataManager.getMarkAsRead(context),
|
||||
markAsReadPendingIntent,
|
||||
).build()
|
||||
|
||||
// -> Tap action
|
||||
// Thanks https://github.com/MaikuB/flutter_local_notifications/blob/master/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java#L246
|
||||
val tapIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||
action = TAP_ACTION
|
||||
putExtra(NOTIFICATION_EXTRA_JID_KEY, notification.jid)
|
||||
putExtra(NOTIFICATION_EXTRA_ID_KEY, notification.id)
|
||||
|
||||
notification.extra?.forEach {
|
||||
putExtra("payload_${it.key}", it.value)
|
||||
}
|
||||
}
|
||||
val tapPendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
notification.id.toInt(),
|
||||
tapIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
// Build the notification
|
||||
val selfPerson = Person.Builder().apply {
|
||||
setName(NotificationDataManager.getYou(context))
|
||||
|
||||
// Set an avatar, if we have one
|
||||
val avatarPath = NotificationDataManager.getAvatarPath(context)
|
||||
if (avatarPath != null) {
|
||||
setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
BitmapFactory.decodeFile(avatarPath),
|
||||
),
|
||||
)
|
||||
}
|
||||
}.build()
|
||||
val style = NotificationCompat.MessagingStyle(selfPerson);
|
||||
style.isGroupConversation = notification.isGroupchat
|
||||
if (notification.isGroupchat) {
|
||||
style.conversationTitle = notification.title
|
||||
}
|
||||
|
||||
for (i in notification.messages.indices) {
|
||||
val message = notification.messages[i]
|
||||
|
||||
// Build the sender
|
||||
// NOTE: Note that we set it to null if message.sender == null because otherwise this results in
|
||||
// a bogus Person object which messes with the "self-message" display as Android expects
|
||||
// null in that case.
|
||||
val sender = if (message.sender == null)
|
||||
null
|
||||
else Person.Builder().apply {
|
||||
setName(message.sender)
|
||||
setKey(message.jid)
|
||||
|
||||
// Set the avatar, if available
|
||||
if (message.avatarPath != null) {
|
||||
try {
|
||||
setIcon(
|
||||
IconCompat.createWithAdaptiveBitmap(
|
||||
BitmapFactory.decodeFile(message.avatarPath),
|
||||
),
|
||||
)
|
||||
} catch (ex: Throwable) {
|
||||
Log.w(TAG, "Failed to open avatar at ${message.avatarPath}")
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
// Build the message
|
||||
val body = message.content.body ?: ""
|
||||
val msg = NotificationCompat.MessagingStyle.Message(
|
||||
body,
|
||||
message.timestamp,
|
||||
sender,
|
||||
)
|
||||
// If we got an image, turn it into a content URI and set it
|
||||
if (message.content.mime != null && message.content.path != null) {
|
||||
val fileUri = FileProvider.getUriForFile(
|
||||
context,
|
||||
MOXPLATFORM_FILEPROVIDER_ID,
|
||||
File(message.content.path),
|
||||
)
|
||||
msg.apply {
|
||||
setData(message.content.mime, fileUri)
|
||||
|
||||
extras.apply {
|
||||
putString(NOTIFICATION_MESSAGE_EXTRA_MIME, message.content.mime)
|
||||
putString(NOTIFICATION_MESSAGE_EXTRA_PATH, message.content.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append the message
|
||||
style.addMessage(msg)
|
||||
}
|
||||
|
||||
// Assemble the notification
|
||||
val finalNotification = NotificationCompat.Builder(context, notification.channelId).apply {
|
||||
setStyle(style)
|
||||
// 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)
|
||||
|
||||
// Notification actions
|
||||
addAction(replyAction)
|
||||
addAction(markAsReadAction)
|
||||
|
||||
// Groupchat title
|
||||
if (notification.isGroupchat) {
|
||||
setContentTitle(notification.title)
|
||||
}
|
||||
|
||||
// Prevent grouping with the foreground service
|
||||
if (notification.groupId != null) {
|
||||
setGroup(notification.groupId)
|
||||
}
|
||||
|
||||
setAllowSystemGeneratedContextualActions(true)
|
||||
setCategory(Notification.CATEGORY_MESSAGE)
|
||||
|
||||
// Prevent no notification when we replied before
|
||||
setOnlyAlertOnce(false)
|
||||
}.build()
|
||||
|
||||
// Post the notification
|
||||
NotificationManagerCompat.from(context).notify(
|
||||
notification.id.toInt(),
|
||||
finalNotification,
|
||||
)
|
||||
}
|
||||
|
||||
fun showNotification(context: Context, notification: Api.RegularNotification) {
|
||||
val builtNotification = NotificationCompat.Builder(context, notification.channelId).apply {
|
||||
setContentTitle(notification.title)
|
||||
setContentText(notification.body)
|
||||
|
||||
when (notification.icon) {
|
||||
Api.NotificationIcon.ERROR -> setSmallIcon(R.drawable.error)
|
||||
Api.NotificationIcon.WARNING -> setSmallIcon(R.drawable.warning)
|
||||
Api.NotificationIcon.NONE -> {}
|
||||
}
|
||||
|
||||
if (notification.groupId != null) {
|
||||
setGroup(notification.groupId)
|
||||
}
|
||||
}.build()
|
||||
|
||||
// Post the notification
|
||||
NotificationManagerCompat.from(context).notify(notification.id.toInt(), builtNotification)
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- For testing -->
|
||||
<cache-path name="file_picker" path="file_picker/"/>
|
||||
|
||||
<!-- Moxxy -->
|
||||
<files-path name="media" path="media/" />
|
||||
</paths>
|
@ -1,64 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:moxplatform_platform_interface/moxplatform_platform_interface.dart';
|
||||
|
||||
class AndroidNotificationsImplementation extends NotificationsImplementation {
|
||||
final MoxplatformApi _api = MoxplatformApi();
|
||||
|
||||
final EventChannel _channel =
|
||||
const EventChannel('me.polynom/notification_stream');
|
||||
|
||||
@override
|
||||
Future<void> createNotificationChannels(
|
||||
List<NotificationChannel> channels) async {
|
||||
return _api.createNotificationChannels(channels);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteNotificationChannels(List<String> ids) {
|
||||
return _api.deleteNotificationChannels(ids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> createNotificationGroups(List<NotificationGroup> groups) async {
|
||||
return _api.createNotificationGroups(groups);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteNotificationGroups(List<String> ids) {
|
||||
return _api.deleteNotificationGroups(ids);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> showMessagingNotification(
|
||||
MessagingNotification notification,
|
||||
) async {
|
||||
return _api.showMessagingNotification(notification);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> showNotification(RegularNotification notification) async {
|
||||
return _api.showNotification(notification);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dismissNotification(int id) async {
|
||||
return _api.dismissNotification(id);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setNotificationSelfAvatar(String path) async {
|
||||
return _api.setNotificationSelfAvatar(path);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setI18n(NotificationI18nData data) {
|
||||
return _api.setNotificationI18n(data);
|
||||
}
|
||||
|
||||
@override
|
||||
Stream<NotificationEvent> getEventStream() => _channel
|
||||
.receiveBroadcastStream()
|
||||
.cast<Object>()
|
||||
.map(NotificationEvent.decode);
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import 'package:moxplatform_android/src/contacts_android.dart';
|
||||
import 'package:moxplatform_android/src/crypto_android.dart';
|
||||
import 'package:moxplatform_android/src/isolate_android.dart';
|
||||
import 'package:moxplatform_android/src/notifications_android.dart';
|
||||
import 'package:moxplatform_android/src/platform_android.dart';
|
||||
import 'package:moxplatform_platform_interface/moxplatform_platform_interface.dart';
|
||||
|
||||
@ -12,7 +11,6 @@ class MoxplatformAndroidPlugin extends MoxplatformInterface {
|
||||
MoxplatformInterface.contacts = AndroidContactsImplementation();
|
||||
MoxplatformInterface.crypto = AndroidCryptographyImplementation();
|
||||
MoxplatformInterface.handler = AndroidIsolateHandler();
|
||||
MoxplatformInterface.notifications = AndroidNotificationsImplementation();
|
||||
MoxplatformInterface.platform = AndroidPlatformImplementation();
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,6 @@ export 'src/crypto_stub.dart';
|
||||
export 'src/interface.dart';
|
||||
export 'src/isolate.dart';
|
||||
export 'src/isolate_stub.dart';
|
||||
export 'src/notifications.dart';
|
||||
export 'src/notifications_stub.dart';
|
||||
export 'src/platform.dart';
|
||||
export 'src/platform_stub.dart';
|
||||
export 'src/service.dart';
|
||||
|
@ -8,18 +8,6 @@ import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;
|
||||
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
enum NotificationIcon {
|
||||
warning,
|
||||
error,
|
||||
none,
|
||||
}
|
||||
|
||||
enum NotificationEventType {
|
||||
markAsRead,
|
||||
reply,
|
||||
open,
|
||||
}
|
||||
|
||||
enum CipherAlgorithm {
|
||||
aes128GcmNoPadding,
|
||||
aes256GcmNoPadding,
|
||||
@ -32,295 +20,6 @@ enum FallbackIconType {
|
||||
notes,
|
||||
}
|
||||
|
||||
enum NotificationChannelImportance {
|
||||
MIN,
|
||||
HIGH,
|
||||
DEFAULT,
|
||||
}
|
||||
|
||||
class NotificationMessageContent {
|
||||
NotificationMessageContent({
|
||||
this.body,
|
||||
this.mime,
|
||||
this.path,
|
||||
});
|
||||
|
||||
/// The textual body of the message.
|
||||
String? body;
|
||||
|
||||
/// The path and mime type of the media to show.
|
||||
String? mime;
|
||||
|
||||
String? path;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
body,
|
||||
mime,
|
||||
path,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationMessageContent decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationMessageContent(
|
||||
body: result[0] as String?,
|
||||
mime: result[1] as String?,
|
||||
path: result[2] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationMessage {
|
||||
NotificationMessage({
|
||||
this.groupId,
|
||||
this.sender,
|
||||
this.jid,
|
||||
required this.content,
|
||||
required this.timestamp,
|
||||
this.avatarPath,
|
||||
});
|
||||
|
||||
/// The grouping key for the notification.
|
||||
String? groupId;
|
||||
|
||||
/// The sender of the message.
|
||||
String? sender;
|
||||
|
||||
/// The jid of the sender.
|
||||
String? jid;
|
||||
|
||||
/// The body of the message.
|
||||
NotificationMessageContent content;
|
||||
|
||||
/// Milliseconds since epoch.
|
||||
int timestamp;
|
||||
|
||||
/// The path to the avatar to use
|
||||
String? avatarPath;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
groupId,
|
||||
sender,
|
||||
jid,
|
||||
content.encode(),
|
||||
timestamp,
|
||||
avatarPath,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationMessage decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationMessage(
|
||||
groupId: result[0] as String?,
|
||||
sender: result[1] as String?,
|
||||
jid: result[2] as String?,
|
||||
content: NotificationMessageContent.decode(result[3]! as List<Object?>),
|
||||
timestamp: result[4]! as int,
|
||||
avatarPath: result[5] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MessagingNotification {
|
||||
MessagingNotification({
|
||||
required this.title,
|
||||
required this.id,
|
||||
required this.channelId,
|
||||
required this.jid,
|
||||
required this.messages,
|
||||
required this.isGroupchat,
|
||||
this.groupId,
|
||||
this.extra,
|
||||
});
|
||||
|
||||
/// The title of the conversation.
|
||||
String title;
|
||||
|
||||
/// The id of the notification.
|
||||
int id;
|
||||
|
||||
/// The id of the notification channel the notification should appear on.
|
||||
String channelId;
|
||||
|
||||
/// The JID of the chat in which the notifications happen.
|
||||
String jid;
|
||||
|
||||
/// Messages to show.
|
||||
List<NotificationMessage?> messages;
|
||||
|
||||
/// Flag indicating whether this notification is from a groupchat or not.
|
||||
bool isGroupchat;
|
||||
|
||||
/// The id for notification grouping.
|
||||
String? groupId;
|
||||
|
||||
/// Additional data to include.
|
||||
Map<String?, String?>? extra;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
title,
|
||||
id,
|
||||
channelId,
|
||||
jid,
|
||||
messages,
|
||||
isGroupchat,
|
||||
groupId,
|
||||
extra,
|
||||
];
|
||||
}
|
||||
|
||||
static MessagingNotification decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return MessagingNotification(
|
||||
title: result[0]! as String,
|
||||
id: result[1]! as int,
|
||||
channelId: result[2]! as String,
|
||||
jid: result[3]! as String,
|
||||
messages: (result[4] as List<Object?>?)!.cast<NotificationMessage?>(),
|
||||
isGroupchat: result[5]! as bool,
|
||||
groupId: result[6] as String?,
|
||||
extra: (result[7] as Map<Object?, Object?>?)?.cast<String?, String?>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RegularNotification {
|
||||
RegularNotification({
|
||||
required this.title,
|
||||
required this.body,
|
||||
required this.channelId,
|
||||
this.groupId,
|
||||
required this.id,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
/// The title of the notification.
|
||||
String title;
|
||||
|
||||
/// The body of the notification.
|
||||
String body;
|
||||
|
||||
/// The id of the channel to show the notification on.
|
||||
String channelId;
|
||||
|
||||
/// The id for notification grouping.
|
||||
String? groupId;
|
||||
|
||||
/// The id of the notification.
|
||||
int id;
|
||||
|
||||
/// The icon to use.
|
||||
NotificationIcon icon;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
title,
|
||||
body,
|
||||
channelId,
|
||||
groupId,
|
||||
id,
|
||||
icon.index,
|
||||
];
|
||||
}
|
||||
|
||||
static RegularNotification decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return RegularNotification(
|
||||
title: result[0]! as String,
|
||||
body: result[1]! as String,
|
||||
channelId: result[2]! as String,
|
||||
groupId: result[3] as String?,
|
||||
id: result[4]! as int,
|
||||
icon: NotificationIcon.values[result[5]! as int],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationEvent {
|
||||
NotificationEvent({
|
||||
required this.id,
|
||||
required this.jid,
|
||||
required this.type,
|
||||
this.payload,
|
||||
this.extra,
|
||||
});
|
||||
|
||||
/// The notification id.
|
||||
int id;
|
||||
|
||||
/// The JID the notification was for.
|
||||
String jid;
|
||||
|
||||
/// The type of event.
|
||||
NotificationEventType type;
|
||||
|
||||
/// An optional payload.
|
||||
/// - type == NotificationType.reply: The reply message text.
|
||||
/// Otherwise: undefined.
|
||||
String? payload;
|
||||
|
||||
/// Extra data. Only set when type == NotificationType.reply.
|
||||
Map<String?, String?>? extra;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
id,
|
||||
jid,
|
||||
type.index,
|
||||
payload,
|
||||
extra,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationEvent decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationEvent(
|
||||
id: result[0]! as int,
|
||||
jid: result[1]! as String,
|
||||
type: NotificationEventType.values[result[2]! as int],
|
||||
payload: result[3] as String?,
|
||||
extra: (result[4] as Map<Object?, Object?>?)?.cast<String?, String?>(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationI18nData {
|
||||
NotificationI18nData({
|
||||
required this.reply,
|
||||
required this.markAsRead,
|
||||
required this.you,
|
||||
});
|
||||
|
||||
/// The content of the reply button.
|
||||
String reply;
|
||||
|
||||
/// The content of the "mark as read" button.
|
||||
String markAsRead;
|
||||
|
||||
/// The text to show when *you* reply.
|
||||
String you;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
reply,
|
||||
markAsRead,
|
||||
you,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationI18nData decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationI18nData(
|
||||
reply: result[0]! as String,
|
||||
markAsRead: result[1]! as String,
|
||||
you: result[2]! as String,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CryptographyResult {
|
||||
CryptographyResult({
|
||||
required this.plaintextHash,
|
||||
@ -347,88 +46,6 @@ class CryptographyResult {
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationGroup {
|
||||
NotificationGroup({
|
||||
required this.id,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
String id;
|
||||
|
||||
String description;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
id,
|
||||
description,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationGroup decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationGroup(
|
||||
id: result[0]! as String,
|
||||
description: result[1]! as String,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationChannel {
|
||||
NotificationChannel({
|
||||
required this.title,
|
||||
required this.description,
|
||||
required this.id,
|
||||
required this.importance,
|
||||
required this.showBadge,
|
||||
this.groupId,
|
||||
required this.vibration,
|
||||
required this.enableLights,
|
||||
});
|
||||
|
||||
String title;
|
||||
|
||||
String description;
|
||||
|
||||
String id;
|
||||
|
||||
NotificationChannelImportance importance;
|
||||
|
||||
bool showBadge;
|
||||
|
||||
String? groupId;
|
||||
|
||||
bool vibration;
|
||||
|
||||
bool enableLights;
|
||||
|
||||
Object encode() {
|
||||
return <Object?>[
|
||||
title,
|
||||
description,
|
||||
id,
|
||||
importance.index,
|
||||
showBadge,
|
||||
groupId,
|
||||
vibration,
|
||||
enableLights,
|
||||
];
|
||||
}
|
||||
|
||||
static NotificationChannel decode(Object result) {
|
||||
result as List<Object?>;
|
||||
return NotificationChannel(
|
||||
title: result[0]! as String,
|
||||
description: result[1]! as String,
|
||||
id: result[2]! as String,
|
||||
importance: NotificationChannelImportance.values[result[3]! as int],
|
||||
showBadge: result[4]! as bool,
|
||||
groupId: result[5] as String?,
|
||||
vibration: result[6]! as bool,
|
||||
enableLights: result[7]! as bool,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MoxplatformApiCodec extends StandardMessageCodec {
|
||||
const _MoxplatformApiCodec();
|
||||
@override
|
||||
@ -436,30 +53,6 @@ class _MoxplatformApiCodec extends StandardMessageCodec {
|
||||
if (value is CryptographyResult) {
|
||||
buffer.putUint8(128);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is MessagingNotification) {
|
||||
buffer.putUint8(129);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationChannel) {
|
||||
buffer.putUint8(130);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationEvent) {
|
||||
buffer.putUint8(131);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationGroup) {
|
||||
buffer.putUint8(132);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationI18nData) {
|
||||
buffer.putUint8(133);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationMessage) {
|
||||
buffer.putUint8(134);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is NotificationMessageContent) {
|
||||
buffer.putUint8(135);
|
||||
writeValue(buffer, value.encode());
|
||||
} else if (value is RegularNotification) {
|
||||
buffer.putUint8(136);
|
||||
writeValue(buffer, value.encode());
|
||||
} else {
|
||||
super.writeValue(buffer, value);
|
||||
}
|
||||
@ -468,24 +61,8 @@ class _MoxplatformApiCodec extends StandardMessageCodec {
|
||||
@override
|
||||
Object? readValueOfType(int type, ReadBuffer buffer) {
|
||||
switch (type) {
|
||||
case 128:
|
||||
case 128:
|
||||
return CryptographyResult.decode(readValue(buffer)!);
|
||||
case 129:
|
||||
return MessagingNotification.decode(readValue(buffer)!);
|
||||
case 130:
|
||||
return NotificationChannel.decode(readValue(buffer)!);
|
||||
case 131:
|
||||
return NotificationEvent.decode(readValue(buffer)!);
|
||||
case 132:
|
||||
return NotificationGroup.decode(readValue(buffer)!);
|
||||
case 133:
|
||||
return NotificationI18nData.decode(readValue(buffer)!);
|
||||
case 134:
|
||||
return NotificationMessage.decode(readValue(buffer)!);
|
||||
case 135:
|
||||
return NotificationMessageContent.decode(readValue(buffer)!);
|
||||
case 136:
|
||||
return RegularNotification.decode(readValue(buffer)!);
|
||||
default:
|
||||
return super.readValueOfType(type, buffer);
|
||||
}
|
||||
@ -502,224 +79,13 @@ class MoxplatformApi {
|
||||
|
||||
static const MessageCodec<Object?> codec = _MoxplatformApiCodec();
|
||||
|
||||
/// Notification APIs
|
||||
Future<void> createNotificationGroups(
|
||||
List<NotificationGroup?> arg_groups) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationGroups',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_groups]) 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<void> deleteNotificationGroups(List<String?> arg_ids) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.deleteNotificationGroups',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_ids]) 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<void> createNotificationChannels(
|
||||
List<NotificationChannel?> arg_channels) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.createNotificationChannels',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_channels]) 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<void> deleteNotificationChannels(List<String?> arg_ids) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.deleteNotificationChannels',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_ids]) 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<void> showMessagingNotification(
|
||||
MessagingNotification arg_notification) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.showMessagingNotification',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_notification]) 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<void> showNotification(RegularNotification arg_notification) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.showNotification',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_notification]) 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<void> dismissNotification(int arg_id) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.dismissNotification',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_id]) 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<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<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;
|
||||
}
|
||||
}
|
||||
|
||||
/// Platform APIs
|
||||
Future<String> getPersistentDataPath() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getPersistentDataPath', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -743,10 +109,10 @@ class MoxplatformApi {
|
||||
|
||||
Future<String> getCacheDataPath() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getCacheDataPath',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.getCacheDataPath', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -770,10 +136,10 @@ class MoxplatformApi {
|
||||
|
||||
Future<void> openBatteryOptimisationSettings() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.openBatteryOptimisationSettings',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.openBatteryOptimisationSettings', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -792,10 +158,10 @@ class MoxplatformApi {
|
||||
|
||||
Future<bool> isIgnoringBatteryOptimizations() async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.isIgnoringBatteryOptimizations',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.isIgnoringBatteryOptimizations', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(null) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -818,18 +184,12 @@ class MoxplatformApi {
|
||||
}
|
||||
|
||||
/// Contacts APIs
|
||||
Future<void> recordSentMessage(String arg_name, String arg_jid,
|
||||
String? arg_avatarPath, FallbackIconType arg_fallbackIcon) async {
|
||||
Future<void> recordSentMessage(String arg_name, String arg_jid, String? arg_avatarPath, FallbackIconType arg_fallbackIcon) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.recordSentMessage',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.recordSentMessage', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
||||
arg_name,
|
||||
arg_jid,
|
||||
arg_avatarPath,
|
||||
arg_fallbackIcon.index
|
||||
]) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_name, arg_jid, arg_avatarPath, arg_fallbackIcon.index]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -847,25 +207,12 @@ class MoxplatformApi {
|
||||
}
|
||||
|
||||
/// Cryptography APIs
|
||||
Future<CryptographyResult?> encryptFile(
|
||||
String arg_sourcePath,
|
||||
String arg_destPath,
|
||||
Uint8List arg_key,
|
||||
Uint8List arg_iv,
|
||||
CipherAlgorithm arg_algorithm,
|
||||
String arg_hashSpec) async {
|
||||
Future<CryptographyResult?> encryptFile(String arg_sourcePath, String arg_destPath, Uint8List arg_key, Uint8List arg_iv, CipherAlgorithm arg_algorithm, String arg_hashSpec) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.encryptFile',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.encryptFile', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
||||
arg_sourcePath,
|
||||
arg_destPath,
|
||||
arg_key,
|
||||
arg_iv,
|
||||
arg_algorithm.index,
|
||||
arg_hashSpec
|
||||
]) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_sourcePath, arg_destPath, arg_key, arg_iv, arg_algorithm.index, arg_hashSpec]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -882,25 +229,12 @@ class MoxplatformApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<CryptographyResult?> decryptFile(
|
||||
String arg_sourcePath,
|
||||
String arg_destPath,
|
||||
Uint8List arg_key,
|
||||
Uint8List arg_iv,
|
||||
CipherAlgorithm arg_algorithm,
|
||||
String arg_hashSpec) async {
|
||||
Future<CryptographyResult?> decryptFile(String arg_sourcePath, String arg_destPath, Uint8List arg_key, Uint8List arg_iv, CipherAlgorithm arg_algorithm, String arg_hashSpec) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.decryptFile',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.decryptFile', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel.send(<Object?>[
|
||||
arg_sourcePath,
|
||||
arg_destPath,
|
||||
arg_key,
|
||||
arg_iv,
|
||||
arg_algorithm.index,
|
||||
arg_hashSpec
|
||||
]) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_sourcePath, arg_destPath, arg_key, arg_iv, arg_algorithm.index, arg_hashSpec]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -917,14 +251,12 @@ class MoxplatformApi {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List?> hashFile(
|
||||
String arg_sourcePath, String arg_hashSpec) async {
|
||||
Future<Uint8List?> hashFile(String arg_sourcePath, String arg_hashSpec) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.hashFile',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.hashFile', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel
|
||||
.send(<Object?>[arg_sourcePath, arg_hashSpec]) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_sourcePath, arg_hashSpec]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -942,14 +274,12 @@ class MoxplatformApi {
|
||||
}
|
||||
|
||||
/// Media APIs
|
||||
Future<bool> generateVideoThumbnail(
|
||||
String arg_src, String arg_dest, int arg_maxWidth) async {
|
||||
Future<bool> generateVideoThumbnail(String arg_src, String arg_dest, int arg_maxWidth) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.generateVideoThumbnail',
|
||||
codec,
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.generateVideoThumbnail', codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList = await channel
|
||||
.send(<Object?>[arg_src, arg_dest, arg_maxWidth]) as List<Object?>?;
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_src, arg_dest, arg_maxWidth]) as List<Object?>?;
|
||||
if (replyList == null) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
@ -970,28 +300,4 @@ class MoxplatformApi {
|
||||
return (replyList[0] as bool?)!;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stubs
|
||||
Future<void> eventStub(NotificationEvent arg_event) async {
|
||||
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
|
||||
'dev.flutter.pigeon.moxplatform_platform_interface.MoxplatformApi.eventStub',
|
||||
codec,
|
||||
binaryMessenger: _binaryMessenger);
|
||||
final List<Object?>? replyList =
|
||||
await channel.send(<Object?>[arg_event]) 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ import 'package:moxplatform_platform_interface/src/crypto.dart';
|
||||
import 'package:moxplatform_platform_interface/src/crypto_stub.dart';
|
||||
import 'package:moxplatform_platform_interface/src/isolate.dart';
|
||||
import 'package:moxplatform_platform_interface/src/isolate_stub.dart';
|
||||
import 'package:moxplatform_platform_interface/src/notifications.dart';
|
||||
import 'package:moxplatform_platform_interface/src/notifications_stub.dart';
|
||||
import 'package:moxplatform_platform_interface/src/platform.dart';
|
||||
import 'package:moxplatform_platform_interface/src/platform_stub.dart';
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
@ -21,8 +19,6 @@ abstract class MoxplatformInterface extends PlatformInterface {
|
||||
static IsolateHandler handler = StubIsolateHandler();
|
||||
static CryptographyImplementation crypto = StubCryptographyImplementation();
|
||||
static ContactsImplementation contacts = StubContactsImplementation();
|
||||
static NotificationsImplementation notifications =
|
||||
StubNotificationsImplementation();
|
||||
static PlatformImplementation platform = StubPlatformImplementation();
|
||||
|
||||
/// Return the current platform name.
|
||||
|
@ -1,32 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:moxplatform_platform_interface/src/api.g.dart';
|
||||
|
||||
abstract class NotificationsImplementation {
|
||||
/// 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> createNotificationChannels(List<NotificationChannel> channels);
|
||||
|
||||
Future<void> deleteNotificationChannels(List<String> ids);
|
||||
|
||||
/// Creates notification groups.
|
||||
Future<void> createNotificationGroups(List<NotificationGroup> groups);
|
||||
|
||||
Future<void> deleteNotificationGroups(List<String> ids);
|
||||
|
||||
/// Shows a notification [notification] in the messaging style with everyting it needs.
|
||||
Future<void> showMessagingNotification(MessagingNotification notification);
|
||||
|
||||
/// Shows a regular notification [notification].
|
||||
Future<void> showNotification(RegularNotification notification);
|
||||
|
||||
/// Dismisses the notification with id [id].
|
||||
Future<void> dismissNotification(int id);
|
||||
|
||||
/// Sets the path to the self-avatar for in-notification replies.
|
||||
Future<void> setNotificationSelfAvatar(String path);
|
||||
|
||||
/// Configures the i18n data for usage in notifications.
|
||||
Future<void> setI18n(NotificationI18nData data);
|
||||
|
||||
Stream<NotificationEvent> getEventStream();
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:moxplatform_platform_interface/src/api.g.dart';
|
||||
import 'package:moxplatform_platform_interface/src/notifications.dart';
|
||||
|
||||
class StubNotificationsImplementation extends NotificationsImplementation {
|
||||
@override
|
||||
Future<void> createNotificationChannels(
|
||||
List<NotificationChannel> channels,
|
||||
) async {}
|
||||
|
||||
@override
|
||||
Future<void> deleteNotificationChannels(
|
||||
List<String> ids,
|
||||
) async {}
|
||||
|
||||
Future<void> createNotificationGroups(
|
||||
List<NotificationGroup> groups,
|
||||
) async {}
|
||||
|
||||
@override
|
||||
Future<void> deleteNotificationGroups(
|
||||
List<String> ids,
|
||||
) async {}
|
||||
|
||||
@override
|
||||
Future<void> showMessagingNotification(
|
||||
MessagingNotification notification,
|
||||
) async {}
|
||||
|
||||
@override
|
||||
Future<void> showNotification(RegularNotification notification) async {}
|
||||
|
||||
@override
|
||||
Future<void> dismissNotification(int id) async {}
|
||||
|
||||
@override
|
||||
Future<void> setNotificationSelfAvatar(String path) async {}
|
||||
|
||||
@override
|
||||
Future<void> setI18n(NotificationI18nData data) async {}
|
||||
|
||||
@override
|
||||
Stream<NotificationEvent> getEventStream() {
|
||||
return StreamController<NotificationEvent>().stream;
|
||||
}
|
||||
}
|
193
pigeons/api.dart
193
pigeons/api.dart
@ -13,152 +13,6 @@ import 'package:pigeon/pigeon.dart';
|
||||
),
|
||||
),
|
||||
)
|
||||
class NotificationMessageContent {
|
||||
const NotificationMessageContent(
|
||||
this.body,
|
||||
this.mime,
|
||||
this.path,
|
||||
);
|
||||
|
||||
/// The textual body of the message.
|
||||
final String? body;
|
||||
|
||||
/// The path and mime type of the media to show.
|
||||
final String? mime;
|
||||
final String? path;
|
||||
}
|
||||
|
||||
class NotificationMessage {
|
||||
const NotificationMessage(
|
||||
this.sender,
|
||||
this.content,
|
||||
this.jid,
|
||||
this.timestamp,
|
||||
this.avatarPath, {
|
||||
this.groupId,
|
||||
});
|
||||
|
||||
/// The grouping key for the notification.
|
||||
final String? groupId;
|
||||
|
||||
/// The sender of the message.
|
||||
final String? sender;
|
||||
|
||||
/// The jid of the sender.
|
||||
final String? jid;
|
||||
|
||||
/// The body of the message.
|
||||
final NotificationMessageContent content;
|
||||
|
||||
/// Milliseconds since epoch.
|
||||
final int timestamp;
|
||||
|
||||
/// The path to the avatar to use
|
||||
final String? avatarPath;
|
||||
}
|
||||
|
||||
class MessagingNotification {
|
||||
const MessagingNotification(this.title, this.id, this.jid, this.messages, this.channelId, this.isGroupchat, this.extra, {this.groupId});
|
||||
|
||||
/// The title of the conversation.
|
||||
final String title;
|
||||
|
||||
/// The id of the notification.
|
||||
final int id;
|
||||
|
||||
/// The id of the notification channel the notification should appear on.
|
||||
final String channelId;
|
||||
|
||||
/// The JID of the chat in which the notifications happen.
|
||||
final String jid;
|
||||
|
||||
/// Messages to show.
|
||||
final List<NotificationMessage?> messages;
|
||||
|
||||
/// Flag indicating whether this notification is from a groupchat or not.
|
||||
final bool isGroupchat;
|
||||
|
||||
/// The id for notification grouping.
|
||||
final String? groupId;
|
||||
|
||||
/// Additional data to include.
|
||||
final Map<String?, String?>? extra;
|
||||
}
|
||||
|
||||
enum NotificationIcon {
|
||||
warning,
|
||||
error,
|
||||
none,
|
||||
}
|
||||
|
||||
class RegularNotification {
|
||||
const RegularNotification(this.title, this.body, this.channelId, this.id, this.icon, {this.groupId});
|
||||
|
||||
/// The title of the notification.
|
||||
final String title;
|
||||
|
||||
/// The body of the notification.
|
||||
final String body;
|
||||
|
||||
/// The id of the channel to show the notification on.
|
||||
final String channelId;
|
||||
|
||||
/// The id for notification grouping.
|
||||
final String? groupId;
|
||||
|
||||
/// The id of the notification.
|
||||
final int id;
|
||||
|
||||
/// The icon to use.
|
||||
final NotificationIcon icon;
|
||||
}
|
||||
|
||||
enum NotificationEventType {
|
||||
markAsRead,
|
||||
reply,
|
||||
open,
|
||||
}
|
||||
|
||||
class NotificationEvent {
|
||||
const NotificationEvent(
|
||||
this.id,
|
||||
this.jid,
|
||||
this.type,
|
||||
this.payload,
|
||||
this.extra,
|
||||
);
|
||||
|
||||
/// The notification id.
|
||||
final int id;
|
||||
|
||||
/// The JID the notification was for.
|
||||
final String jid;
|
||||
|
||||
/// The type of event.
|
||||
final NotificationEventType type;
|
||||
|
||||
/// An optional payload.
|
||||
/// - type == NotificationType.reply: The reply message text.
|
||||
/// Otherwise: undefined.
|
||||
final String? payload;
|
||||
|
||||
/// Extra data. Only set when type == NotificationType.reply.
|
||||
final Map<String?, String?>? extra;
|
||||
}
|
||||
|
||||
class NotificationI18nData {
|
||||
const NotificationI18nData(this.reply, this.markAsRead, this.you);
|
||||
|
||||
/// The content of the reply button.
|
||||
final String reply;
|
||||
|
||||
/// The content of the "mark as read" button.
|
||||
final String markAsRead;
|
||||
|
||||
/// The text to show when *you* reply.
|
||||
final String you;
|
||||
}
|
||||
|
||||
enum CipherAlgorithm {
|
||||
aes128GcmNoPadding,
|
||||
aes256GcmNoPadding,
|
||||
@ -178,52 +32,8 @@ enum FallbackIconType {
|
||||
notes;
|
||||
}
|
||||
|
||||
class NotificationGroup {
|
||||
const NotificationGroup(this.id, this.description);
|
||||
final String id;
|
||||
final String description;
|
||||
}
|
||||
|
||||
enum NotificationChannelImportance {
|
||||
MIN,
|
||||
HIGH,
|
||||
DEFAULT
|
||||
}
|
||||
|
||||
class NotificationChannel {
|
||||
const NotificationChannel(
|
||||
this.id,
|
||||
this.title,
|
||||
this.description, {
|
||||
this.importance = NotificationChannelImportance.DEFAULT,
|
||||
this.showBadge = true,
|
||||
this.groupId,
|
||||
this.vibration = true,
|
||||
this.enableLights = true,
|
||||
});
|
||||
final String title;
|
||||
final String description;
|
||||
final String id;
|
||||
final NotificationChannelImportance importance;
|
||||
final bool showBadge;
|
||||
final String? groupId;
|
||||
final bool vibration;
|
||||
final bool enableLights;
|
||||
}
|
||||
|
||||
@HostApi()
|
||||
abstract class MoxplatformApi {
|
||||
/// Notification APIs
|
||||
void createNotificationGroups(List<NotificationGroup> groups);
|
||||
void deleteNotificationGroups(List<String> ids);
|
||||
void createNotificationChannels(List<NotificationChannel> channels);
|
||||
void deleteNotificationChannels(List<String> ids);
|
||||
void showMessagingNotification(MessagingNotification notification);
|
||||
void showNotification(RegularNotification notification);
|
||||
void dismissNotification(int id);
|
||||
void setNotificationSelfAvatar(String path);
|
||||
void setNotificationI18n(NotificationI18nData data);
|
||||
|
||||
/// Platform APIs
|
||||
String getPersistentDataPath();
|
||||
String getCacheDataPath();
|
||||
@ -240,7 +50,4 @@ abstract class MoxplatformApi {
|
||||
|
||||
/// Media APIs
|
||||
bool generateVideoThumbnail(String src, String dest, int maxWidth);
|
||||
|
||||
/// Stubs
|
||||
void eventStub(NotificationEvent event);
|
||||
}
|
||||
|
Reference in New Issue
Block a user