splitting dm and group notifications into separate channels
- adding notification system group - only notifying the summary to avoid overlapping notifications
This commit is contained in:
parent
b0a438ee98
commit
2a0f28d3b3
|
@ -1,10 +1,14 @@
|
|||
package app.dapk.st.notifications
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationChannelGroup
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build
|
||||
|
||||
const val channelId = "message"
|
||||
const val DIRECT_CHANNEL_ID = "direct_channel_id"
|
||||
const val GROUP_CHANNEL_ID = "group_channel_id"
|
||||
|
||||
private const val CHATS_NOTIFICATION_GROUP_ID = "chats_notification_group"
|
||||
|
||||
class NotificationChannels(
|
||||
private val notificationManager: NotificationManager
|
||||
|
@ -12,13 +16,31 @@ class NotificationChannels(
|
|||
|
||||
fun initChannels() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
if (notificationManager.getNotificationChannel(channelId) == null) {
|
||||
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(CHATS_NOTIFICATION_GROUP_ID, "Chats"))
|
||||
|
||||
if (notificationManager.getNotificationChannel(DIRECT_CHANNEL_ID) == null) {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
channelId,
|
||||
"messages",
|
||||
DIRECT_CHANNEL_ID,
|
||||
"Direct notifications",
|
||||
NotificationManager.IMPORTANCE_HIGH,
|
||||
)
|
||||
).also {
|
||||
it.enableVibration(true)
|
||||
it.enableLights(true)
|
||||
it.group = CHATS_NOTIFICATION_GROUP_ID
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (notificationManager.getNotificationChannel(GROUP_CHANNEL_ID) == null) {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
GROUP_CHANNEL_ID,
|
||||
"Group notifications",
|
||||
NotificationManager.IMPORTANCE_HIGH,
|
||||
).also {
|
||||
it.group = CHATS_NOTIFICATION_GROUP_ID
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,17 +34,21 @@ class NotificationFactory(
|
|||
else -> newRooms.contains(roomOverview.roomId)
|
||||
}
|
||||
|
||||
val last = sortedEvents.last()
|
||||
return NotificationTypes.Room(
|
||||
AndroidNotification(
|
||||
channelId = channelId,
|
||||
whenTimestamp = sortedEvents.last().utcTimestamp,
|
||||
channelId = when {
|
||||
roomOverview.isDm() -> DIRECT_CHANNEL_ID
|
||||
else -> GROUP_CHANNEL_ID
|
||||
},
|
||||
whenTimestamp = last.utcTimestamp,
|
||||
groupId = GROUP_ID,
|
||||
groupAlertBehavior = deviceMeta.whenPOrHigher(
|
||||
block = { Notification.GROUP_ALERT_SUMMARY },
|
||||
fallback = { null }
|
||||
),
|
||||
shortcutId = roomOverview.roomId.value,
|
||||
alertMoreThanOnce = shouldAlertMoreThanOnce,
|
||||
alertMoreThanOnce = false,
|
||||
contentIntent = openRoomIntent,
|
||||
messageStyle = messageStyle,
|
||||
category = Notification.CATEGORY_MESSAGE,
|
||||
|
@ -53,7 +57,7 @@ class NotificationFactory(
|
|||
autoCancel = true
|
||||
),
|
||||
roomId = roomOverview.roomId,
|
||||
summary = sortedEvents.last().content,
|
||||
summary = last.content,
|
||||
messageCount = sortedEvents.size,
|
||||
isAlerting = shouldAlertMoreThanOnce
|
||||
)
|
||||
|
@ -63,7 +67,7 @@ class NotificationFactory(
|
|||
val summaryInboxStyle = notificationStyleFactory.summary(notifications)
|
||||
val openAppIntent = intentFactory.notificationOpenApp(context)
|
||||
return AndroidNotification(
|
||||
channelId = channelId,
|
||||
channelId = notifications.firstOrNull { it.isAlerting }?.notification?.channelId ?: notifications.first().notification.channelId,
|
||||
messageStyle = summaryInboxStyle,
|
||||
alertMoreThanOnce = notifications.any { it.isAlerting },
|
||||
smallIcon = R.drawable.ic_notification_small_icon,
|
||||
|
@ -74,6 +78,7 @@ class NotificationFactory(
|
|||
fallback = { null }
|
||||
),
|
||||
isGroupSummary = true,
|
||||
category = Notification.CATEGORY_MESSAGE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,14 @@ class NotificationStateMapper(
|
|||
val messageEvents = roomEventsToNotifiableMapper.map(events)
|
||||
when (messageEvents.isEmpty()) {
|
||||
true -> NotificationTypes.DismissRoom(roomOverview.roomId)
|
||||
false -> notificationFactory.createMessageNotification(messageEvents, roomOverview, state.roomsWithNewEvents, state.newRooms)
|
||||
false -> {
|
||||
notificationFactory.createMessageNotification(
|
||||
events = messageEvents,
|
||||
roomOverview = roomOverview,
|
||||
roomsWithNewEvents = state.roomsWithNewEvents,
|
||||
newRooms = state.newRooms
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package app.dapk.st.notifications
|
||||
|
||||
import app.dapk.st.core.AppLogTag.NOTIFICATION
|
||||
import app.dapk.st.core.log
|
||||
import app.dapk.st.matrix.sync.RoomEvent
|
||||
import app.dapk.st.matrix.sync.RoomOverview
|
||||
import kotlinx.coroutines.flow.collect
|
||||
|
@ -22,7 +20,6 @@ class RenderNotificationsUseCase(
|
|||
}
|
||||
|
||||
private suspend fun renderUnreadChange(allUnread: Map<RoomOverview, List<RoomEvent>>, diff: NotificationDiff) {
|
||||
log(NOTIFICATION, "unread changed - render notifications")
|
||||
notificationRenderer.render(
|
||||
NotificationState(
|
||||
allUnread = allUnread,
|
||||
|
|
|
@ -7,6 +7,7 @@ import app.dapk.st.core.DeviceMeta
|
|||
import app.dapk.st.matrix.common.AvatarUrl
|
||||
import app.dapk.st.matrix.sync.RoomOverview
|
||||
import fake.FakeContext
|
||||
import fixture.NotificationDelegateFixtures.anAndroidNotification
|
||||
import fixture.NotificationDelegateFixtures.anInboxStyle
|
||||
import fixture.NotificationFixtures.aRoomNotification
|
||||
import fixture.aRoomId
|
||||
|
@ -16,6 +17,7 @@ import kotlinx.coroutines.test.runTest
|
|||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private const val A_CHANNEL_ID = "a channel id"
|
||||
private val AN_OPEN_APP_INTENT = aPendingIntent()
|
||||
private val AN_OPEN_ROOM_INTENT = aPendingIntent()
|
||||
private val A_NOTIFICATION_STYLE = anInboxStyle()
|
||||
|
@ -48,24 +50,24 @@ class NotificationFactoryTest {
|
|||
|
||||
@Test
|
||||
fun `given alerting room notification, when creating summary, then is alerting`() {
|
||||
val notifications = listOf(aRoomNotification(isAlerting = true))
|
||||
val notifications = listOf(aRoomNotification(notification = anAndroidNotification(channelId = A_CHANNEL_ID), isAlerting = true))
|
||||
fakeIntentFactory.givenNotificationOpenApp(fakeContext.instance).returns(AN_OPEN_APP_INTENT)
|
||||
fakeNotificationStyleFactory.givenSummary(notifications).returns(anInboxStyle())
|
||||
|
||||
val result = notificationFactory.createSummary(notifications)
|
||||
|
||||
result shouldBeEqualTo expectedSummary(shouldAlertMoreThanOnce = true)
|
||||
result shouldBeEqualTo expectedSummary(channelId = A_CHANNEL_ID, shouldAlertMoreThanOnce = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given non alerting room notification, when creating summary, then is alerting`() {
|
||||
val notifications = listOf(aRoomNotification(isAlerting = false))
|
||||
val notifications = listOf(aRoomNotification(notification = anAndroidNotification(channelId = A_CHANNEL_ID), isAlerting = false))
|
||||
fakeIntentFactory.givenNotificationOpenApp(fakeContext.instance).returns(AN_OPEN_APP_INTENT)
|
||||
fakeNotificationStyleFactory.givenSummary(notifications).returns(anInboxStyle())
|
||||
|
||||
val result = notificationFactory.createSummary(notifications)
|
||||
|
||||
result shouldBeEqualTo expectedSummary(shouldAlertMoreThanOnce = false)
|
||||
result shouldBeEqualTo expectedSummary(channelId = A_CHANNEL_ID, shouldAlertMoreThanOnce = false)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -75,6 +77,7 @@ class NotificationFactoryTest {
|
|||
val result = notificationFactory.createMessageNotification(EVENTS, A_GROUP_ROOM_OVERVIEW, setOf(A_ROOM_ID), newRooms = setOf(A_ROOM_ID))
|
||||
|
||||
result shouldBeEqualTo expectedMessage(
|
||||
channel = GROUP_CHANNEL_ID,
|
||||
shouldAlertMoreThanOnce = true,
|
||||
)
|
||||
}
|
||||
|
@ -86,6 +89,7 @@ class NotificationFactoryTest {
|
|||
val result = notificationFactory.createMessageNotification(EVENTS, A_GROUP_ROOM_OVERVIEW, setOf(A_ROOM_ID), newRooms = emptySet())
|
||||
|
||||
result shouldBeEqualTo expectedMessage(
|
||||
channel = GROUP_CHANNEL_ID,
|
||||
shouldAlertMoreThanOnce = false,
|
||||
)
|
||||
}
|
||||
|
@ -97,6 +101,7 @@ class NotificationFactoryTest {
|
|||
val result = notificationFactory.createMessageNotification(EVENTS, A_DM_ROOM_OVERVIEW, setOf(A_ROOM_ID), newRooms = setOf(A_ROOM_ID))
|
||||
|
||||
result shouldBeEqualTo expectedMessage(
|
||||
channel = DIRECT_CHANNEL_ID,
|
||||
shouldAlertMoreThanOnce = true,
|
||||
)
|
||||
}
|
||||
|
@ -108,6 +113,7 @@ class NotificationFactoryTest {
|
|||
val result = notificationFactory.createMessageNotification(EVENTS, A_DM_ROOM_OVERVIEW, setOf(A_ROOM_ID), newRooms = emptySet())
|
||||
|
||||
result shouldBeEqualTo expectedMessage(
|
||||
channel = DIRECT_CHANNEL_ID,
|
||||
shouldAlertMoreThanOnce = true,
|
||||
)
|
||||
}
|
||||
|
@ -119,15 +125,16 @@ class NotificationFactoryTest {
|
|||
}
|
||||
|
||||
private fun expectedMessage(
|
||||
channel: String,
|
||||
shouldAlertMoreThanOnce: Boolean,
|
||||
) = NotificationTypes.Room(
|
||||
AndroidNotification(
|
||||
channelId = "message",
|
||||
channelId = channel,
|
||||
whenTimestamp = LATEST_EVENT.utcTimestamp,
|
||||
groupId = "st",
|
||||
groupAlertBehavior = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) Notification.GROUP_ALERT_SUMMARY else null,
|
||||
shortcutId = A_ROOM_ID.value,
|
||||
alertMoreThanOnce = shouldAlertMoreThanOnce,
|
||||
alertMoreThanOnce = false,
|
||||
contentIntent = AN_OPEN_ROOM_INTENT,
|
||||
messageStyle = A_NOTIFICATION_STYLE,
|
||||
category = Notification.CATEGORY_MESSAGE,
|
||||
|
@ -141,13 +148,14 @@ class NotificationFactoryTest {
|
|||
isAlerting = shouldAlertMoreThanOnce,
|
||||
)
|
||||
|
||||
private fun expectedSummary(shouldAlertMoreThanOnce: Boolean) = AndroidNotification(
|
||||
channelId = "message",
|
||||
private fun expectedSummary(channelId: String, shouldAlertMoreThanOnce: Boolean) = AndroidNotification(
|
||||
channelId = channelId,
|
||||
messageStyle = A_NOTIFICATION_STYLE,
|
||||
alertMoreThanOnce = shouldAlertMoreThanOnce,
|
||||
smallIcon = R.drawable.ic_notification_small_icon,
|
||||
contentIntent = AN_OPEN_APP_INTENT,
|
||||
groupId = "st",
|
||||
category = Notification.CATEGORY_MESSAGE,
|
||||
isGroupSummary = true,
|
||||
autoCancel = true
|
||||
)
|
||||
|
|
|
@ -14,11 +14,12 @@ object NotificationFixtures {
|
|||
) = Notifications(summaryNotification, delegates)
|
||||
|
||||
fun aRoomNotification(
|
||||
notification: AndroidNotification = anAndroidNotification(),
|
||||
summary: String = "a summary line",
|
||||
messageCount: Int = 1,
|
||||
isAlerting: Boolean = false,
|
||||
) = NotificationTypes.Room(
|
||||
anAndroidNotification(),
|
||||
notification,
|
||||
aRoomId(),
|
||||
summary = summary,
|
||||
messageCount = messageCount,
|
||||
|
|
Loading…
Reference in New Issue