diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f7c1d889f2..ed1fd31cc27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ - `Attachment.uploadId` is only used locally and removed whenever the attachments are uploaded. [#5395](https://github.com/GetStream/stream-chat-android/pull/5395) ### ✅ Added +Added `notificationTextFormatter` lambda parameter to `NotificationHandlerFactory::createNotificationHandler` which is being used to formats the text of the notification. [#5409](https://github.com/GetStream/stream-chat-android/pull/5409) +Added `actionsProvider` lambda parameter to `NotificationHandlerFactory::createNotificationHandler` which is being used to provide actions for the notification. [#5409](https://github.com/GetStream/stream-chat-android/pull/5409) ### ⚠️ Changed diff --git a/docusaurus/docs/Android/client/guides/push-notifications/02-setup.mdx b/docusaurus/docs/Android/client/guides/push-notifications/02-setup.mdx index 6cd03021755..4a0fae12f94 100644 --- a/docusaurus/docs/Android/client/guides/push-notifications/02-setup.mdx +++ b/docusaurus/docs/Android/client/guides/push-notifications/02-setup.mdx @@ -80,6 +80,7 @@ This function lets you provide a custom `Intent` that can point to any `Activity ```kotlin {1-11,14} val notificationHandler = NotificationHandlerFactory.createNotificationHandler( context = context, + notificationConfig = notificationConfig, newMessageIntent = { message: Message, channel: Channel, @@ -104,7 +105,7 @@ boolean pushNotificationEnabled = true; List pushDeviceGeneratorList = new ArrayList<>(); NotificationConfig notificationConfig = new NotificationConfig(pushNotificationEnabled, pushDeviceGeneratorList); -NotificationHandler notificationHandler = NotificationHandlerFactory.createNotificationHandler(context, (messageId, channelType, channelId) -> { +NotificationHandler notificationHandler = NotificationHandlerFactory.createNotificationHandler(context, notificationConfig, (message, channel) -> { // Return the intent you want to be triggered when the notification is clicked Intent intent = new Intent(); diff --git a/stream-chat-android-client/api/stream-chat-android-client.api b/stream-chat-android-client/api/stream-chat-android-client.api index 183e034d146..d9f1bd6cf43 100644 --- a/stream-chat-android-client/api/stream-chat-android-client.api +++ b/stream-chat-android-client/api/stream-chat-android-client.api @@ -2360,19 +2360,14 @@ public final class io/getstream/chat/android/client/notifications/handler/Notifi public final class io/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory { public static final field INSTANCE Lio/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory; - public static final fun createNotificationHandler (Landroid/content/Context;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static final fun createNotificationHandler (Landroid/content/Context;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static final fun createNotificationHandler (Landroid/content/Context;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static final fun createNotificationHandler (Landroid/content/Context;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static final fun createNotificationHandler (Landroid/content/Context;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static final fun createNotificationHandler (Landroid/content/Context;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;Z)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static synthetic fun createNotificationHandler$default (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;ILjava/lang/Object;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; - public static synthetic fun createNotificationHandler$default (Landroid/content/Context;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;ZILjava/lang/Object;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; + public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;Lkotlin/jvm/functions/Function2;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; + public static final fun createNotificationHandler (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; + public static synthetic fun createNotificationHandler$default (Landroid/content/Context;Lio/getstream/chat/android/client/notifications/handler/NotificationConfig;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;Lio/getstream/chat/android/client/notifications/handler/UserIconBuilder;Lio/getstream/android/push/permissions/NotificationPermissionHandler;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lio/getstream/chat/android/client/notifications/handler/NotificationHandler; } public abstract interface class io/getstream/chat/android/client/notifications/handler/PushDeviceGenerator { diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/ChatNotificationHandler.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/ChatNotificationHandler.kt index 8767484b264..a0fd1beb674 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/ChatNotificationHandler.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/ChatNotificationHandler.kt @@ -25,6 +25,7 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Build import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationCompat.Action import androidx.core.content.ContextCompat import androidx.core.content.edit import io.getstream.android.push.permissions.NotificationPermissionStatus @@ -34,6 +35,7 @@ import io.getstream.chat.android.client.extensions.getUsersExcludingCurrent import io.getstream.chat.android.client.receivers.NotificationMessageReceiver import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.Message +import io.getstream.chat.android.models.User /** * Class responsible for handling chat notifications. @@ -43,8 +45,9 @@ import io.getstream.chat.android.models.Message internal class ChatNotificationHandler( private val context: Context, private val newMessageIntent: (message: Message, channel: Channel) -> Intent, - private val notificationChannel: (() -> NotificationChannel), - private val autoTranslationEnabled: Boolean = false, + private val notificationChannel: () -> NotificationChannel, + private val notificationTextFormatter: (currentUser: User?, message: Message) -> CharSequence, + private val actionsProvider: (notificationId: Int, channel: Channel, message: Message) -> List, ) : NotificationHandler { private val sharedPreferences: SharedPreferences by lazy { @@ -86,20 +89,13 @@ internal class ChatNotificationHandler( ): NotificationCompat.Builder { val currentUser = ChatClient.instance().getCurrentUser() ?: ChatClient.instance().getStoredUser() - val displayedText = when (autoTranslationEnabled) { - true -> currentUser?.language?.let { userLanguage -> - message.getTranslation(userLanguage).ifEmpty { message.text } - } ?: message.text - else -> message.text - } return getNotificationBuilder( contentTitle = channel.getNotificationContentTitle(), - contentText = displayedText, + contentText = notificationTextFormatter(currentUser, message), groupKey = getNotificationGroupKey(channelType = channel.type, channelId = channel.id), intent = getNewMessageIntent(message = message, channel = channel), ).apply { - addAction(NotificationMessageReceiver.createReadAction(context, notificationId, channel, message)) - addAction(NotificationMessageReceiver.createReplyAction(context, notificationId, channel)) + actionsProvider(notificationId, channel, message).forEach(::addAction) setDeleteIntent(NotificationMessageReceiver.createDismissPendingIntent(context, notificationId, channel)) } } @@ -152,7 +148,7 @@ internal class ChatNotificationHandler( private fun getNotificationBuilder( contentTitle: String, - contentText: String, + contentText: CharSequence, groupKey: String, intent: Intent, ): NotificationCompat.Builder { diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/MessagingStyleNotificationHandler.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/MessagingStyleNotificationHandler.kt index c2b668edc22..74c4fab913c 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/MessagingStyleNotificationHandler.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/MessagingStyleNotificationHandler.kt @@ -25,6 +25,7 @@ import android.content.SharedPreferences import android.os.Build import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationCompat.Action import androidx.core.app.Person import androidx.core.content.ContextCompat import androidx.core.content.edit @@ -32,7 +33,6 @@ import io.getstream.android.push.permissions.NotificationPermissionHandler import io.getstream.android.push.permissions.NotificationPermissionStatus import io.getstream.chat.android.client.ChatClient import io.getstream.chat.android.client.R -import io.getstream.chat.android.client.receivers.NotificationMessageReceiver import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.User @@ -44,14 +44,18 @@ import java.util.Date * Notification channel should only be accessed if Build.VERSION.SDK_INT >= Build.VERSION_CODES.O. */ @RequiresApi(Build.VERSION_CODES.M) -@Suppress("TooManyFunctions") +@Suppress( + "TooManyFunctions", + "LongParameterList", +) internal class MessagingStyleNotificationHandler( private val context: Context, private val newMessageIntent: (message: Message, channel: Channel) -> Intent, - private val notificationChannel: (() -> NotificationChannel), + private val notificationChannel: () -> NotificationChannel, private val userIconBuilder: UserIconBuilder, private val permissionHandler: NotificationPermissionHandler?, - private val autoTranslationEnabled: Boolean = false, + private val notificationTextFormatter: (currentUser: User?, message: Message) -> CharSequence, + private val actionsProvider: (notificationId: Int, channel: Channel, message: Message) -> List, ) : NotificationHandler { private val logger by taggedLogger("Chat:MsnHandler") @@ -95,8 +99,7 @@ internal class MessagingStyleNotificationHandler( .setColor(ContextCompat.getColor(context, R.color.stream_ic_notification)) .setStyle(initialMessagingStyle.addMessage(message.toMessagingStyleMessage(context, currentUser))) .setContentIntent(contentPendingIntent) - .addAction(NotificationMessageReceiver.createReadAction(context, notificationId, channel, message)) - .addAction(NotificationMessageReceiver.createReplyAction(context, notificationId, channel)) + .apply { actionsProvider(notificationId, channel, message).forEach(::addAction) } .build() addNotificationId(notificationId) notificationManager.notify(notificationId, notification) @@ -160,13 +163,11 @@ internal class MessagingStyleNotificationHandler( context: Context, currentUser: User?, ): NotificationCompat.MessagingStyle.Message { - val displayedText = when (autoTranslationEnabled) { - true -> currentUser?.language?.let { userLanguage -> - getTranslation(userLanguage).ifEmpty { text } - } ?: text - else -> text - } - return NotificationCompat.MessagingStyle.Message(displayedText, timestamp, person(context)) + return NotificationCompat.MessagingStyle.Message( + notificationTextFormatter(currentUser, this), + timestamp, + person(context), + ) } private suspend fun Message.person(context: Context): Person = user.toPerson(context) diff --git a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory.kt b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory.kt index 950a4757be2..4828bedd24c 100644 --- a/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory.kt +++ b/stream-chat-android-client/src/main/java/io/getstream/chat/android/client/notifications/handler/NotificationHandlerFactory.kt @@ -24,10 +24,12 @@ import android.content.Context import android.content.Intent import android.os.Build import androidx.annotation.RequiresApi +import androidx.core.app.NotificationCompat import androidx.core.graphics.drawable.IconCompat import io.getstream.android.push.permissions.DefaultNotificationPermissionHandler import io.getstream.android.push.permissions.NotificationPermissionHandler import io.getstream.chat.android.client.R +import io.getstream.chat.android.client.receivers.NotificationMessageReceiver import io.getstream.chat.android.models.Channel import io.getstream.chat.android.models.Message import io.getstream.chat.android.models.User @@ -49,6 +51,8 @@ public object NotificationHandlerFactory { * Used in SDK_INT >= VERSION_CODES.O. * @param userIconBuilder Generates [IconCompat] to be shown on notifications. * @param permissionHandler Handles [android.Manifest.permission.POST_NOTIFICATIONS] permission lifecycle. + * @param notificationTextFormatter Lambda expression used to formats the text of the notification. + * @param actionsProvider Lambda expression used to provide actions for the notification. */ @SuppressLint("NewApi") @JvmOverloads @@ -56,57 +60,52 @@ public object NotificationHandlerFactory { public fun createNotificationHandler( context: Context, notificationConfig: NotificationConfig, - newMessageIntent: ((message: Message, channel: Channel) -> Intent)? = null, - notificationChannel: (() -> NotificationChannel)? = null, + newMessageIntent: ((message: Message, channel: Channel) -> Intent) = getDefaultNewMessageIntentFun(context), + notificationChannel: (() -> NotificationChannel) = getDefaultNotificationChannel(context), userIconBuilder: UserIconBuilder = provideDefaultUserIconBuilder(context), permissionHandler: NotificationPermissionHandler? = provideDefaultNotificationPermissionHandler(context), - ): NotificationHandler { - return createNotificationHandler( + notificationTextFormatter: ((currentUser: User?, message: Message) -> CharSequence) = + getDefaultNotificationTextFormatter(notificationConfig), + actionsProvider: (notificationId: Int, channel: Channel, message: Message) -> List = + getDefaultActionsProvider(context), + ): NotificationHandler = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + MessagingStyleNotificationHandler( context = context, newMessageIntent = newMessageIntent, notificationChannel = notificationChannel, userIconBuilder = userIconBuilder, permissionHandler = permissionHandler, - autoTranslationEnabled = notificationConfig.autoTranslationEnabled, + notificationTextFormatter = notificationTextFormatter, + actionsProvider = actionsProvider, + ) + } else { + ChatNotificationHandler( + context = context, + newMessageIntent = newMessageIntent, + notificationChannel = notificationChannel, + notificationTextFormatter = notificationTextFormatter, + actionsProvider = actionsProvider, ) } - /** - * Method that creates a [NotificationHandler]. - * - * @param context The [Context] to build the [NotificationHandler] with. - * @param newMessageIntent Lambda expression used to generate an [Intent] to open your app - * @param notificationChannel Lambda expression used to generate a [NotificationChannel]. - * Used in SDK_INT >= VERSION_CODES.O. - * @param userIconBuilder Generates [IconCompat] to be shown on notifications. - * @param permissionHandler Handles [android.Manifest.permission.POST_NOTIFICATIONS] permission lifecycle. - * @param autoTranslationEnabled Enables automatic translation of push notifications. - */ - @SuppressLint("NewApi") - @JvmOverloads - @JvmStatic - public fun createNotificationHandler( + private fun getDefaultActionsProvider( context: Context, - newMessageIntent: ((message: Message, channel: Channel) -> Intent)? = null, - notificationChannel: (() -> NotificationChannel)? = null, - userIconBuilder: UserIconBuilder = provideDefaultUserIconBuilder(context), - permissionHandler: NotificationPermissionHandler? = provideDefaultNotificationPermissionHandler(context), - autoTranslationEnabled: Boolean = false, - ): NotificationHandler { - val notificationChannelFun = notificationChannel ?: getDefaultNotificationChannel(context) - (newMessageIntent ?: getDefaultNewMessageIntentFun(context)).let { newMessageIntentFun -> - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - MessagingStyleNotificationHandler( - context, - newMessageIntentFun, - notificationChannelFun, - userIconBuilder, - permissionHandler, - autoTranslationEnabled, - ) - } else { - ChatNotificationHandler(context, newMessageIntentFun, notificationChannelFun, autoTranslationEnabled) - } + ): (notificationId: Int, channel: Channel, message: Message) -> List = + { notificationId, channel, message -> + listOf( + NotificationMessageReceiver.createReadAction(context, notificationId, channel, message), + NotificationMessageReceiver.createReplyAction(context, notificationId, channel), + ) + } + + private fun getDefaultNotificationTextFormatter( + notificationConfig: NotificationConfig, + ): (currentUser: User?, message: Message) -> CharSequence = { currentUser, message -> + when (notificationConfig.autoTranslationEnabled) { + true -> currentUser?.language?.let { userLanguage -> + message.getTranslation(userLanguage).ifEmpty { message.text } + } ?: message.text + else -> message.text } } diff --git a/stream-chat-android-docs/src/main/java/io/getstream/chat/docs/java/client/docusaurus/Push.java b/stream-chat-android-docs/src/main/java/io/getstream/chat/docs/java/client/docusaurus/Push.java index 9feab5d1f4c..0dcf2b51a33 100644 --- a/stream-chat-android-docs/src/main/java/io/getstream/chat/docs/java/client/docusaurus/Push.java +++ b/stream-chat-android-docs/src/main/java/io/getstream/chat/docs/java/client/docusaurus/Push.java @@ -67,7 +67,7 @@ public void customNotificationHandler(Context context) { List pushDeviceGeneratorList = new ArrayList<>(); NotificationConfig notificationConfig = new NotificationConfig(pushNotificationEnabled, ignorePushMessagesWhenUserOnline, pushDeviceGeneratorList); - NotificationHandler notificationHandler = NotificationHandlerFactory.createNotificationHandler(context, (message, channel) -> { + NotificationHandler notificationHandler = NotificationHandlerFactory.createNotificationHandler(context, notificationConfig, (message, channel) -> { // Return the intent you want to be triggered when the notification is clicked Intent intent = new Intent(); diff --git a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/client/docusaurus/Push.kt b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/client/docusaurus/Push.kt index fb081b1c27d..94658b0adb0 100644 --- a/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/client/docusaurus/Push.kt +++ b/stream-chat-android-docs/src/main/kotlin/io/getstream/chat/docs/kotlin/client/docusaurus/Push.kt @@ -60,6 +60,7 @@ class Push { val notificationHandler = NotificationHandlerFactory.createNotificationHandler( context = context, + notificationConfig = notificationConfig, newMessageIntent = { message: Message, channel: Channel,