refactor: Move the notification code into its own file
This commit is contained in:
parent
c22b35b4ac
commit
42ff70a966
@ -1,14 +1,12 @@
|
|||||||
package org.moxxy.moxxy_native
|
package org.moxxy.moxxy_native
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.result.PickVisualMediaRequest
|
import androidx.activity.result.PickVisualMediaRequest
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
import io.flutter.embedding.engine.plugins.activity.ActivityAware
|
||||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||||
@ -19,17 +17,9 @@ import org.moxxy.moxxy_native.cryptography.CryptographyImplementation
|
|||||||
import org.moxxy.moxxy_native.cryptography.MoxxyCryptographyApi
|
import org.moxxy.moxxy_native.cryptography.MoxxyCryptographyApi
|
||||||
import org.moxxy.moxxy_native.media.MediaImplementation
|
import org.moxxy.moxxy_native.media.MediaImplementation
|
||||||
import org.moxxy.moxxy_native.media.MoxxyMediaApi
|
import org.moxxy.moxxy_native.media.MoxxyMediaApi
|
||||||
import org.moxxy.moxxy_native.notifications.MessagingNotification
|
|
||||||
import org.moxxy.moxxy_native.notifications.MoxxyNotificationsApi
|
import org.moxxy.moxxy_native.notifications.MoxxyNotificationsApi
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationChannel
|
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationDataManager
|
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationEvent
|
import org.moxxy.moxxy_native.notifications.NotificationEvent
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationGroup
|
import org.moxxy.moxxy_native.notifications.NotificationsImplementation
|
||||||
import org.moxxy.moxxy_native.notifications.NotificationI18nData
|
|
||||||
import org.moxxy.moxxy_native.notifications.RegularNotification
|
|
||||||
import org.moxxy.moxxy_native.notifications.createNotificationChannelsImpl
|
|
||||||
import org.moxxy.moxxy_native.notifications.createNotificationGroupsImpl
|
|
||||||
import org.moxxy.moxxy_native.notifications.showNotificationImpl
|
|
||||||
import org.moxxy.moxxy_native.picker.FilePickerType
|
import org.moxxy.moxxy_native.picker.FilePickerType
|
||||||
import org.moxxy.moxxy_native.picker.MoxxyPickerApi
|
import org.moxxy.moxxy_native.picker.MoxxyPickerApi
|
||||||
import org.moxxy.moxxy_native.picker.PickerResultListener
|
import org.moxxy.moxxy_native.picker.PickerResultListener
|
||||||
@ -60,7 +50,7 @@ object NotificationCache {
|
|||||||
var lastEvent: NotificationEvent? = null
|
var lastEvent: NotificationEvent? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNotificationsApi {
|
class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi {
|
||||||
private var context: Context? = null
|
private var context: Context? = null
|
||||||
private var activity: Activity? = null
|
private var activity: Activity? = null
|
||||||
private lateinit var pickerListener: PickerResultListener
|
private lateinit var pickerListener: PickerResultListener
|
||||||
@ -68,15 +58,17 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNot
|
|||||||
private lateinit var contactsImplementation: ContactsImplementation
|
private lateinit var contactsImplementation: ContactsImplementation
|
||||||
private lateinit var platformImplementation: PlatformImplementation
|
private lateinit var platformImplementation: PlatformImplementation
|
||||||
private val mediaImplementation = MediaImplementation()
|
private val mediaImplementation = MediaImplementation()
|
||||||
|
private lateinit var notificationsImplementation: NotificationsImplementation
|
||||||
|
|
||||||
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
|
||||||
context = flutterPluginBinding.applicationContext
|
context = flutterPluginBinding.applicationContext
|
||||||
contactsImplementation = ContactsImplementation(context!!)
|
contactsImplementation = ContactsImplementation(context!!)
|
||||||
platformImplementation = PlatformImplementation(context!!)
|
platformImplementation = PlatformImplementation(context!!)
|
||||||
|
notificationsImplementation = NotificationsImplementation(context!!)
|
||||||
|
|
||||||
// Register the pigeon handlers
|
// Register the pigeon handlers
|
||||||
MoxxyPickerApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
MoxxyPickerApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
||||||
MoxxyNotificationsApi.setUp(flutterPluginBinding.binaryMessenger, this)
|
MoxxyNotificationsApi.setUp(flutterPluginBinding.binaryMessenger, notificationsImplementation)
|
||||||
MoxxyCryptographyApi.setUp(flutterPluginBinding.binaryMessenger, cryptographyImplementation)
|
MoxxyCryptographyApi.setUp(flutterPluginBinding.binaryMessenger, cryptographyImplementation)
|
||||||
MoxxyContactsApi.setUp(flutterPluginBinding.binaryMessenger, contactsImplementation)
|
MoxxyContactsApi.setUp(flutterPluginBinding.binaryMessenger, contactsImplementation)
|
||||||
MoxxyPlatformApi.setUp(flutterPluginBinding.binaryMessenger, platformImplementation)
|
MoxxyPlatformApi.setUp(flutterPluginBinding.binaryMessenger, platformImplementation)
|
||||||
@ -167,54 +159,4 @@ class MoxxyNativePlugin : FlutterPlugin, ActivityAware, MoxxyPickerApi, MoxxyNot
|
|||||||
val pickIntent = contract.createIntent(context!!, PickVisualMediaRequest(pickType))
|
val pickIntent = contract.createIntent(context!!, PickVisualMediaRequest(pickType))
|
||||||
activity?.startActivityForResult(pickIntent, PICK_FILE_WITH_DATA_REQUEST)
|
activity?.startActivityForResult(pickIntent, PICK_FILE_WITH_DATA_REQUEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createNotificationGroups(groups: List<NotificationGroup>) {
|
|
||||||
createNotificationGroupsImpl(context!!, groups)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deleteNotificationGroups(ids: List<String>) {
|
|
||||||
val notificationManager = context!!.getSystemService(NotificationManager::class.java)
|
|
||||||
for (id in ids) {
|
|
||||||
notificationManager.deleteNotificationChannelGroup(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createNotificationChannels(channels: List<NotificationChannel>) {
|
|
||||||
createNotificationChannelsImpl(context!!, channels)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deleteNotificationChannels(ids: List<String>) {
|
|
||||||
val notificationManager = context!!.getSystemService(NotificationManager::class.java)
|
|
||||||
for (id in ids) {
|
|
||||||
notificationManager.deleteNotificationChannel(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showMessagingNotification(notification: MessagingNotification) {
|
|
||||||
org.moxxy.moxxy_native.notifications.showMessagingNotification(context!!, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun showNotification(notification: RegularNotification) {
|
|
||||||
showNotificationImpl(context!!, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dismissNotification(id: Long) {
|
|
||||||
NotificationManagerCompat.from(context!!).cancel(id.toInt())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setNotificationSelfAvatar(path: String) {
|
|
||||||
NotificationDataManager.setAvatarPath(context!!, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setNotificationI18n(data: NotificationI18nData) {
|
|
||||||
NotificationDataManager.apply {
|
|
||||||
setYou(context!!, data.you)
|
|
||||||
setReply(context!!, data.reply)
|
|
||||||
setMarkAsRead(context!!, data.markAsRead)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun notificationStub(event: NotificationEvent) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.moxxy.moxxy_native.notifications
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import org.moxxy.moxxy_native.TAG
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract all user-added extra key-value pairs from @intent.
|
||||||
|
* */
|
||||||
|
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
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package org.moxxy.moxxy_native.notifications
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import org.moxxy.moxxy_native.SHARED_PREFERENCES_AVATAR_KEY
|
||||||
|
import org.moxxy.moxxy_native.SHARED_PREFERENCES_KEY
|
||||||
|
import org.moxxy.moxxy_native.SHARED_PREFERENCES_MARK_AS_READ_KEY
|
||||||
|
import org.moxxy.moxxy_native.SHARED_PREFERENCES_REPLY_KEY
|
||||||
|
import org.moxxy.moxxy_native.SHARED_PREFERENCES_YOU_KEY
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
@ -27,19 +27,6 @@ import org.moxxy.moxxy_native.TAP_ACTION
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotificationReceiver : BroadcastReceiver() {
|
class NotificationReceiver : BroadcastReceiver() {
|
||||||
/*
|
/*
|
||||||
* Dismisses the notification through which we received @intent.
|
* Dismisses the notification through which we received @intent.
|
||||||
|
@ -1,362 +0,0 @@
|
|||||||
package org.moxxy.moxxy_native.notifications
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Notification
|
|
||||||
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.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.app.TaskStackBuilder
|
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
|
||||||
import org.moxxy.moxxy_native.MARK_AS_READ_ACTION
|
|
||||||
import org.moxxy.moxxy_native.MOXXY_FILEPROVIDER_ID
|
|
||||||
import org.moxxy.moxxy_native.NOTIFICATION_EXTRA_ID_KEY
|
|
||||||
import org.moxxy.moxxy_native.NOTIFICATION_EXTRA_JID_KEY
|
|
||||||
import org.moxxy.moxxy_native.NOTIFICATION_MESSAGE_EXTRA_MIME
|
|
||||||
import org.moxxy.moxxy_native.NOTIFICATION_MESSAGE_EXTRA_PATH
|
|
||||||
import org.moxxy.moxxy_native.R
|
|
||||||
import org.moxxy.moxxy_native.REPLY_ACTION
|
|
||||||
import org.moxxy.moxxy_native.REPLY_TEXT_KEY
|
|
||||||
import org.moxxy.moxxy_native.SHARED_PREFERENCES_AVATAR_KEY
|
|
||||||
import org.moxxy.moxxy_native.SHARED_PREFERENCES_KEY
|
|
||||||
import org.moxxy.moxxy_native.SHARED_PREFERENCES_MARK_AS_READ_KEY
|
|
||||||
import org.moxxy.moxxy_native.SHARED_PREFERENCES_REPLY_KEY
|
|
||||||
import org.moxxy.moxxy_native.SHARED_PREFERENCES_YOU_KEY
|
|
||||||
import org.moxxy.moxxy_native.TAG
|
|
||||||
import org.moxxy.moxxy_native.TAP_ACTION
|
|
||||||
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<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<NotificationChannel>) {
|
|
||||||
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
|
||||||
for (channel in channels) {
|
|
||||||
val importance = when (channel.importance) {
|
|
||||||
NotificationChannelImportance.DEFAULT -> NotificationManager.IMPORTANCE_DEFAULT
|
|
||||||
NotificationChannelImportance.MIN -> NotificationManager.IMPORTANCE_MIN
|
|
||||||
NotificationChannelImportance.HIGH -> NotificationManager.IMPORTANCE_HIGH
|
|
||||||
}
|
|
||||||
val notificationChannel = android.app.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.
|
|
||||||
@SuppressLint("WrongConstant")
|
|
||||||
fun showMessagingNotification(context: Context, notification: 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 to flutter_local_notifications for this "workaround"
|
|
||||||
val tapIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)!!.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not launch a new task
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
|
||||||
}
|
|
||||||
val tapPendingIntent = TaskStackBuilder.create(context).run {
|
|
||||||
addNextIntentWithParentStack(tapIntent)
|
|
||||||
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or 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,
|
|
||||||
MOXXY_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)
|
|
||||||
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)
|
|
||||||
|
|
||||||
// Automatically dismiss the notification on tap
|
|
||||||
setAutoCancel(true)
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
// Post the notification
|
|
||||||
try {
|
|
||||||
NotificationManagerCompat.from(context).notify(
|
|
||||||
notification.id.toInt(),
|
|
||||||
finalNotification,
|
|
||||||
)
|
|
||||||
} catch (ex: SecurityException) {
|
|
||||||
// Should never happen as Moxxy checks for the permission before posting the notification
|
|
||||||
Log.e(TAG, "Failed to post notification: ${ex.message}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showNotificationImpl(context: Context, notification: RegularNotification) {
|
|
||||||
val builtNotification = NotificationCompat.Builder(context, notification.channelId).apply {
|
|
||||||
setContentTitle(notification.title)
|
|
||||||
setContentText(notification.body)
|
|
||||||
|
|
||||||
when (notification.icon) {
|
|
||||||
NotificationIcon.ERROR -> setSmallIcon(R.drawable.error)
|
|
||||||
NotificationIcon.WARNING -> setSmallIcon(R.drawable.warning)
|
|
||||||
NotificationIcon.NONE -> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notification.groupId != null) {
|
|
||||||
setGroup(notification.groupId)
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
// Post the notification
|
|
||||||
try {
|
|
||||||
NotificationManagerCompat.from(context).notify(notification.id.toInt(), builtNotification)
|
|
||||||
} catch (ex: SecurityException) {
|
|
||||||
// Should never happen as Moxxy checks for the permission before posting the notification
|
|
||||||
Log.e(TAG, "Failed to post notification: ${ex.message}")
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,331 @@
|
|||||||
|
package org.moxxy.moxxy_native.notifications
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
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.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.app.TaskStackBuilder
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import org.moxxy.moxxy_native.MARK_AS_READ_ACTION
|
||||||
|
import org.moxxy.moxxy_native.MOXXY_FILEPROVIDER_ID
|
||||||
|
import org.moxxy.moxxy_native.NOTIFICATION_EXTRA_ID_KEY
|
||||||
|
import org.moxxy.moxxy_native.NOTIFICATION_EXTRA_JID_KEY
|
||||||
|
import org.moxxy.moxxy_native.NOTIFICATION_MESSAGE_EXTRA_MIME
|
||||||
|
import org.moxxy.moxxy_native.NOTIFICATION_MESSAGE_EXTRA_PATH
|
||||||
|
import org.moxxy.moxxy_native.R
|
||||||
|
import org.moxxy.moxxy_native.REPLY_ACTION
|
||||||
|
import org.moxxy.moxxy_native.REPLY_TEXT_KEY
|
||||||
|
import org.moxxy.moxxy_native.TAG
|
||||||
|
import org.moxxy.moxxy_native.TAP_ACTION
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class NotificationsImplementation(private val context: Context) : MoxxyNotificationsApi {
|
||||||
|
override fun createNotificationGroups(groups: List<NotificationGroup>) {
|
||||||
|
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||||
|
for (group in groups) {
|
||||||
|
notificationManager.createNotificationChannelGroup(
|
||||||
|
NotificationChannelGroup(group.id, group.description),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteNotificationGroups(ids: List<String>) {
|
||||||
|
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||||
|
for (id in ids) {
|
||||||
|
notificationManager.deleteNotificationChannelGroup(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createNotificationChannels(channels: List<NotificationChannel>) {
|
||||||
|
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||||
|
for (channel in channels) {
|
||||||
|
val importance = when (channel.importance) {
|
||||||
|
NotificationChannelImportance.DEFAULT -> NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
NotificationChannelImportance.MIN -> NotificationManager.IMPORTANCE_MIN
|
||||||
|
NotificationChannelImportance.HIGH -> NotificationManager.IMPORTANCE_HIGH
|
||||||
|
}
|
||||||
|
val notificationChannel =
|
||||||
|
android.app.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteNotificationChannels(ids: List<String>) {
|
||||||
|
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||||
|
for (id in ids) {
|
||||||
|
notificationManager.deleteNotificationChannel(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showMessagingNotification(notification: 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 to flutter_local_notifications for this "workaround"
|
||||||
|
val tapIntent =
|
||||||
|
context.packageManager.getLaunchIntentForPackage(context.packageName)!!.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not launch a new task
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
|
}
|
||||||
|
val tapPendingIntent = TaskStackBuilder.create(context).run {
|
||||||
|
addNextIntentWithParentStack(tapIntent)
|
||||||
|
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT or 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,
|
||||||
|
MOXXY_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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
// Automatically dismiss the notification on tap
|
||||||
|
setAutoCancel(true)
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
// Post the notification
|
||||||
|
try {
|
||||||
|
NotificationManagerCompat.from(context).notify(
|
||||||
|
notification.id.toInt(),
|
||||||
|
finalNotification,
|
||||||
|
)
|
||||||
|
} catch (ex: SecurityException) {
|
||||||
|
// Should never happen as Moxxy checks for the permission before posting the notification
|
||||||
|
Log.e(TAG, "Failed to post notification: ${ex.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun showNotification(notification: RegularNotification) {
|
||||||
|
val builtNotification = NotificationCompat.Builder(context, notification.channelId).apply {
|
||||||
|
setContentTitle(notification.title)
|
||||||
|
setContentText(notification.body)
|
||||||
|
|
||||||
|
when (notification.icon) {
|
||||||
|
NotificationIcon.ERROR -> setSmallIcon(R.drawable.error)
|
||||||
|
NotificationIcon.WARNING -> setSmallIcon(R.drawable.warning)
|
||||||
|
NotificationIcon.NONE -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.groupId != null) {
|
||||||
|
setGroup(notification.groupId)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
// Post the notification
|
||||||
|
try {
|
||||||
|
NotificationManagerCompat.from(context)
|
||||||
|
.notify(notification.id.toInt(), builtNotification)
|
||||||
|
} catch (ex: SecurityException) {
|
||||||
|
// Should never happen as Moxxy checks for the permission before posting the notification
|
||||||
|
Log.e(TAG, "Failed to post notification: ${ex.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dismissNotification(id: Long) {
|
||||||
|
NotificationManagerCompat.from(context).cancel(id.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setNotificationSelfAvatar(path: String) {
|
||||||
|
NotificationDataManager.setAvatarPath(context, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setNotificationI18n(data: NotificationI18nData) {
|
||||||
|
NotificationDataManager.apply {
|
||||||
|
setYou(
|
||||||
|
context,
|
||||||
|
data.you,
|
||||||
|
)
|
||||||
|
setReply(
|
||||||
|
context,
|
||||||
|
data.reply,
|
||||||
|
)
|
||||||
|
setMarkAsRead(
|
||||||
|
context,
|
||||||
|
data.markAsRead,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun notificationStub(event: NotificationEvent) {
|
||||||
|
// N/A
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user