Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Android Notification Manager that could override the default notification appearance #91

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal actual val platformModule = module {
context = get(),
channelData = configuration.notificationChannelData
),
displayNotificationManager = configuration.displayNotificationManager,
permissionUtil = get()
)
} bind Notifier::class
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.mmk.kmpnotifier.notification

import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import com.mmk.kmpnotifier.notification.configuration.NotificationPlatformConfiguration

public class AndroidNotificationData private constructor(
public val context: Context,
public val notificationManager: NotificationManager
) {
public var notificationChannelData: NotificationPlatformConfiguration.Android.NotificationChannelData? = null
private set
public var notificationId: Int = -1
private set
public var notificationIconResId: Int = -1
private set
public var notificationIconColorResId: Int? = null
private set
public var pendingIntent: PendingIntent? = null
private set
public var payloadData: Map<String, String>? = null
private set

internal companion object {

/**
* Builder that assembles data required for the Android notification
* @param context Android application context. By default
* using androidx-startup Context reference is passed without needing to pass one manually.
* @param notificationManager System notification manager that could post notifications
*/
class Builder(context: Context, notificationManager: NotificationManager) {
private val builder: AndroidNotificationData = AndroidNotificationData(
context = context,
notificationManager = notificationManager
)

/**
* Set notification id
* @param notificationId ID of the notification
*/
fun setNotificationId(notificationId: Int): Builder {
builder.notificationId = notificationId
return this
}

/**
* Set channel data
* @param channelData notification channel data for General or Miscellaneous notifications
*/
fun setChannelData(
channelData: NotificationPlatformConfiguration.Android.NotificationChannelData
): Builder {
builder.notificationChannelData = channelData
return this
}

/**
* @param notificationIconResId icon ResourceId (R.drawable.ic_notification)
*/
fun setNotificationIconRes(notificationIconResId: Int): Builder {
builder.notificationIconResId = notificationIconResId
return this
}

/**
* @param notificationIconColorResId icon color ResourceId (R.color.yellow)
*/
fun setNotificationIconColorResId(notificationIconColorResId: Int?): Builder {
builder.notificationIconColorResId = notificationIconColorResId
return this
}

/**
* @param pendingIntent action that invokes on notification click
*/
fun setPendingIntent(pendingIntent: PendingIntent?): Builder {
builder.pendingIntent = pendingIntent
return this
}

/**
* @param payloadData extra data for the push notification
*/
fun setPayloadData(payloadData: Map<String, String>): Builder {
builder.payloadData = payloadData
return this
}

/**
* @return notification data required for its displaying
*/
fun build(): AndroidNotificationData {
return builder
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mmk.kmpnotifier.notification

/**
* Provides all data required for the Android notification
*/
public interface AndroidNotificationManager {
/**
* Provide Android notification data
* @param notificationData - data required for displaying notification
*/
public fun setData(notificationData: AndroidNotificationData)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.mmk.kmpnotifier.Constants.ACTION_NOTIFICATION_CLICK
import com.mmk.kmpnotifier.extensions.notificationManager
import com.mmk.kmpnotifier.notification.configuration.DisplayNotificationManager
import com.mmk.kmpnotifier.notification.configuration.NotificationPlatformConfiguration
import com.mmk.kmpnotifier.permission.PermissionUtil
import kotlin.random.Random
Expand All @@ -18,6 +17,7 @@ internal class AndroidNotifier(
private val context: Context,
private val androidNotificationConfiguration: NotificationPlatformConfiguration.Android,
private val notificationChannelFactory: NotificationChannelFactory,
private val displayNotificationManager: DisplayNotificationManager?,
private val permissionUtil: PermissionUtil,
) : Notifier {

Expand All @@ -38,22 +38,23 @@ internal class AndroidNotifier(
val notificationManager = context.notificationManager ?: return
val pendingIntent = getPendingIntent(payloadData)
notificationChannelFactory.createChannels()
val notification = NotificationCompat.Builder(
context,
androidNotificationConfiguration.notificationChannelData.id
).apply {
setChannelId(androidNotificationConfiguration.notificationChannelData.id)
setContentTitle(title)
setContentText(body)
setSmallIcon(androidNotificationConfiguration.notificationIconResId)
setAutoCancel(true)
setContentIntent(pendingIntent)
androidNotificationConfiguration.notificationIconColorResId?.let {
color = ContextCompat.getColor(context, it)
}
}.build()

notificationManager.notify(id, notification)
val androidNotificationData = AndroidNotificationData.Companion.Builder(
context = context,
notificationManager = notificationManager
)
.setNotificationId(id)
.setChannelData(androidNotificationConfiguration.notificationChannelData)
.setNotificationIconRes(androidNotificationConfiguration.notificationIconResId)
.setNotificationIconColorResId(androidNotificationConfiguration.notificationIconColorResId)
.setPayloadData(payloadData)
.setPendingIntent(pendingIntent)
.build()
val notificationFct = (displayNotificationManager ?: DefaultDisplayNotificationManager())
val androidNotificationManager = notificationFct as AndroidNotificationManager?
?: throw IllegalStateException("Factory doesn't implement AndroidNotificationFactory")
androidNotificationManager.setData(androidNotificationData)
notificationFct.displayNotification(title, body)

}

override fun remove(id: Int) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.mmk.kmpnotifier.notification

import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.mmk.kmpnotifier.notification.configuration.DisplayNotificationManager

/**
* Default implementation of the Android notification manager
*/
internal class DefaultDisplayNotificationManager : DisplayNotificationManager, AndroidNotificationManager {
private var notificationData: AndroidNotificationData? = null

override fun setData(notificationData: AndroidNotificationData) {
this.notificationData = notificationData
}

override fun displayNotification(title: String, body: String) {
val data = notificationData ?: throw IllegalStateException("Android Notification data must be provided")
val notificationChannelData =
data.notificationChannelData ?: throw IllegalStateException("Notification Channel Data must be provided")

val notification = NotificationCompat.Builder(
data.context,
notificationChannelData.id
).apply {
setChannelId(notificationChannelData.id)
setContentTitle(title)
setContentText(body)
setSmallIcon(data.notificationIconResId)
setAutoCancel(true)
setContentIntent(data.pendingIntent)
data.notificationIconColorResId?.let {
color = ContextCompat.getColor(data.context, it)
}
}.build()

data.notificationManager.notify(data.notificationId, notification)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.mmk.kmpnotifier.notification.configuration

/**
* You can provide your own implementation of the notification UI
*/
public interface DisplayNotificationManager {

/**
* Implement mechanism of notification displaying
*
* @param title of the notification
* @param body of the notification
*/
public fun displayNotification(title: String, body: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ public sealed interface NotificationPlatformConfiguration {
* received it will be shown to user. When set to false, it will not be shown to user,
* but you can still get notification content using
* @see com.mmk.kmpnotifier.notification.NotifierManager.Listener.onPushNotification
* @param displayNotificationManager Assembles and displays notification. If not provided the default manager
* [com.mmk.kmpnotifier.notification.DefaultDisplayNotificationManager] is used. Also
*/
public class Android(
public val notificationIconResId: Int,
public val notificationIconColorResId: Int? = null,
public val notificationChannelData: NotificationChannelData = NotificationChannelData(),
public val showPushNotification: Boolean = true,
public val displayNotificationManager: DisplayNotificationManager? = null
) : NotificationPlatformConfiguration {

/**
Expand Down