mirror of
https://github.com/ouchadam/small-talk.git
synced 2025-02-24 07:58:22 +01:00
Merge branch 'main' into dependabot/gradle/com.google.accompanist-accompanist-systemuicontroller-0.24.13-rc
This commit is contained in:
commit
14fc762a46
@ -136,7 +136,7 @@ ext.kotlinTest = { dependencies ->
|
||||
dependencies.testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
|
||||
|
||||
dependencies.testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
|
||||
dependencies.testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
|
||||
dependencies.testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
|
||||
}
|
||||
|
||||
ext.kotlinFixtures = { dependencies ->
|
||||
|
@ -34,6 +34,8 @@ class AndroidNotificationStyleBuilder(
|
||||
.setKey(person.key)
|
||||
.build()
|
||||
).also { style ->
|
||||
style.conversationTitle = title
|
||||
style.isGroupConversation = isGroup
|
||||
content.forEach {
|
||||
val sender = personBuilderFactory()
|
||||
.setName(it.sender.name)
|
||||
|
@ -1,10 +1,15 @@
|
||||
package app.dapk.st.notifications
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationChannelGroup
|
||||
import android.app.NotificationManager
|
||||
import android.os.Build
|
||||
|
||||
private const val channelId = "message"
|
||||
const val DIRECT_CHANNEL_ID = "direct_channel_id"
|
||||
const val GROUP_CHANNEL_ID = "group_channel_id"
|
||||
const val SUMMARY_CHANNEL_ID = "summary_channel_id"
|
||||
|
||||
private const val CHATS_NOTIFICATION_GROUP_ID = "chats_notification_group"
|
||||
|
||||
class NotificationChannels(
|
||||
private val notificationManager: NotificationManager
|
||||
@ -12,13 +17,43 @@ 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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (notificationManager.getNotificationChannel(SUMMARY_CHANNEL_ID) == null) {
|
||||
notificationManager.createNotificationChannel(
|
||||
NotificationChannel(
|
||||
SUMMARY_CHANNEL_ID,
|
||||
"Other notifications",
|
||||
NotificationManager.IMPORTANCE_DEFAULT,
|
||||
).also {
|
||||
it.group = CHATS_NOTIFICATION_GROUP_ID
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import app.dapk.st.matrix.sync.RoomOverview
|
||||
import app.dapk.st.navigator.IntentFactory
|
||||
|
||||
private const val GROUP_ID = "st"
|
||||
private const val channelId = "message"
|
||||
|
||||
class NotificationFactory(
|
||||
private val context: Context,
|
||||
@ -35,17 +34,18 @@ class NotificationFactory(
|
||||
else -> newRooms.contains(roomOverview.roomId)
|
||||
}
|
||||
|
||||
val last = sortedEvents.last()
|
||||
return NotificationTypes.Room(
|
||||
AndroidNotification(
|
||||
channelId = channelId,
|
||||
whenTimestamp = sortedEvents.last().utcTimestamp,
|
||||
channelId = SUMMARY_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,
|
||||
@ -54,9 +54,13 @@ class NotificationFactory(
|
||||
autoCancel = true
|
||||
),
|
||||
roomId = roomOverview.roomId,
|
||||
summary = sortedEvents.last().content,
|
||||
summary = last.content,
|
||||
messageCount = sortedEvents.size,
|
||||
isAlerting = shouldAlertMoreThanOnce
|
||||
isAlerting = shouldAlertMoreThanOnce,
|
||||
summaryChannelId = when {
|
||||
roomOverview.isDm() -> DIRECT_CHANNEL_ID
|
||||
else -> GROUP_CHANNEL_ID
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -64,7 +68,7 @@ class NotificationFactory(
|
||||
val summaryInboxStyle = notificationStyleFactory.summary(notifications)
|
||||
val openAppIntent = intentFactory.notificationOpenApp(context)
|
||||
return AndroidNotification(
|
||||
channelId = channelId,
|
||||
channelId = notifications.mostRecent().summaryChannelId,
|
||||
messageStyle = summaryInboxStyle,
|
||||
alertMoreThanOnce = notifications.any { it.isAlerting },
|
||||
smallIcon = R.drawable.ic_notification_small_icon,
|
||||
@ -75,8 +79,11 @@ class NotificationFactory(
|
||||
fallback = { null }
|
||||
),
|
||||
isGroupSummary = true,
|
||||
category = Notification.CATEGORY_MESSAGE,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<NotificationTypes.Room>.mostRecent() = this.sortedBy { it.notification.whenTimestamp }.first()
|
||||
|
||||
private fun RoomOverview.isDm() = !this.isGroup
|
||||
|
@ -68,7 +68,8 @@ sealed interface NotificationTypes {
|
||||
val roomId: RoomId,
|
||||
val summary: String,
|
||||
val messageCount: Int,
|
||||
val isAlerting: Boolean
|
||||
val isAlerting: Boolean,
|
||||
val summaryChannelId: String,
|
||||
) : NotificationTypes
|
||||
|
||||
data class DismissRoom(val roomId: RoomId) : NotificationTypes
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,12 @@ private fun Flow<UnreadNotifications>.onlyRenderableChanges(): Flow<UnreadNotifi
|
||||
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no renderable changes")
|
||||
false
|
||||
}
|
||||
|
||||
inferredCurrentNotifications.isEmpty() && diff.removed.isNotEmpty() -> {
|
||||
log(AppLogTag.NOTIFICATION, "Ignoring unread change due to no currently showing messages and changes are all messages marked as read")
|
||||
false
|
||||
}
|
||||
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
@ -45,29 +47,48 @@ private fun Flow<UnreadNotifications>.onlyRenderableChanges(): Flow<UnreadNotifi
|
||||
}
|
||||
|
||||
private fun Flow<Map<RoomOverview, List<RoomEvent>>>.mapWithDiff(): Flow<Pair<Map<RoomOverview, List<RoomEvent>>, NotificationDiff>> {
|
||||
val previousUnreadEvents = mutableMapOf<RoomId, List<EventId>>()
|
||||
val previousUnreadEvents = mutableMapOf<RoomId, List<TimestampedEventId>>()
|
||||
return this.map { each ->
|
||||
val allUnreadIds = each.toIds()
|
||||
val allUnreadIds = each.toTimestampedIds()
|
||||
val notificationDiff = calculateDiff(allUnreadIds, previousUnreadEvents)
|
||||
previousUnreadEvents.clearAndPutAll(allUnreadIds)
|
||||
each to notificationDiff
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateDiff(allUnread: Map<RoomId, List<EventId>>, previousUnread: Map<RoomId, List<EventId>>?): NotificationDiff {
|
||||
private fun calculateDiff(allUnread: Map<RoomId, List<TimestampedEventId>>, previousUnread: Map<RoomId, List<TimestampedEventId>>?): NotificationDiff {
|
||||
val previousLatestEventTimestamps = previousUnread.toLatestTimestamps()
|
||||
val newRooms = allUnread.filter { !previousUnread.containsKey(it.key) }.keys
|
||||
val unchanged = previousUnread?.filter { allUnread.containsKey(it.key) && it.value == allUnread[it.key] } ?: emptyMap()
|
||||
val changedOrNew = allUnread.filterNot { unchanged.containsKey(it.key) }
|
||||
|
||||
val unchanged = previousUnread?.filter {
|
||||
allUnread.containsKey(it.key) && (it.value == allUnread[it.key])
|
||||
} ?: emptyMap()
|
||||
val changedOrNew = allUnread.filterNot { unchanged.containsKey(it.key) }.mapValues { (key, value) ->
|
||||
val isChangedRoom = !newRooms.contains(key)
|
||||
if (isChangedRoom) {
|
||||
val latest = previousLatestEventTimestamps[key] ?: 0L
|
||||
value.filter {
|
||||
val isExistingEvent = (previousUnread?.get(key)?.contains(it) ?: false)
|
||||
!isExistingEvent && it.second > latest
|
||||
}
|
||||
} else {
|
||||
value
|
||||
}
|
||||
}.filter { it.value.isNotEmpty() }
|
||||
val removed = previousUnread?.filter { !allUnread.containsKey(it.key) } ?: emptyMap()
|
||||
return NotificationDiff(unchanged, changedOrNew, removed, newRooms)
|
||||
return NotificationDiff(unchanged.toEventIds(), changedOrNew.toEventIds(), removed.toEventIds(), newRooms)
|
||||
}
|
||||
|
||||
private fun List<RoomEvent>.toEventIds() = this.map { it.eventId }
|
||||
private fun Map<RoomId, List<TimestampedEventId>>?.toLatestTimestamps() = this?.mapValues { it.value.maxOf { it.second } } ?: emptyMap()
|
||||
|
||||
private fun Map<RoomOverview, List<RoomEvent>>.toIds() = this
|
||||
private fun Map<RoomId, List<TimestampedEventId>>.toEventIds() = this.mapValues { it.value.map { it.first } }
|
||||
|
||||
private fun Map<RoomOverview, List<RoomEvent>>.toTimestampedIds() = this
|
||||
.mapValues { it.value.toEventIds() }
|
||||
.mapKeys { it.key.roomId }
|
||||
|
||||
private fun List<RoomEvent>.toEventIds() = this.map { it.eventId to it.utcTimestamp }
|
||||
|
||||
private fun <T> Flow<T>.avoidShowingPreviousNotificationsOnLaunch() = drop(1)
|
||||
|
||||
data class NotificationDiff(
|
||||
@ -76,3 +97,5 @@ data class NotificationDiff(
|
||||
val removed: Map<RoomId, List<EventId>>,
|
||||
val newRooms: Set<RoomId>
|
||||
)
|
||||
|
||||
typealias TimestampedEventId = Pair<EventId, Long>
|
@ -1,30 +1,25 @@
|
||||
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
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
|
||||
class RenderNotificationsUseCase(
|
||||
private val notificationRenderer: NotificationRenderer,
|
||||
private val observeRenderableUnreadEventsUseCase: ObserveUnreadNotificationsUseCase,
|
||||
notificationChannels: NotificationChannels,
|
||||
private val notificationChannels: NotificationChannels,
|
||||
) {
|
||||
|
||||
init {
|
||||
notificationChannels.initChannels()
|
||||
}
|
||||
|
||||
suspend fun listenForNotificationChanges() {
|
||||
observeRenderableUnreadEventsUseCase()
|
||||
.onStart { notificationChannels.initChannels() }
|
||||
.onEach { (each, diff) -> renderUnreadChange(each, diff) }
|
||||
.collect()
|
||||
}
|
||||
|
||||
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()
|
||||
@ -30,7 +32,6 @@ private val EVENTS = listOf(
|
||||
aNotifiable("message two", utcTimestamp = 2),
|
||||
)
|
||||
|
||||
|
||||
class NotificationFactoryTest {
|
||||
|
||||
private val fakeContext = FakeContext()
|
||||
@ -48,24 +49,34 @@ class NotificationFactoryTest {
|
||||
|
||||
@Test
|
||||
fun `given alerting room notification, when creating summary, then is alerting`() {
|
||||
val notifications = listOf(aRoomNotification(isAlerting = true))
|
||||
val notifications = listOf(
|
||||
aRoomNotification(
|
||||
summaryChannelId = A_CHANNEL_ID,
|
||||
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(
|
||||
summaryChannelId = A_CHANNEL_ID,
|
||||
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 +86,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 +98,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 +110,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 +122,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 +134,16 @@ class NotificationFactoryTest {
|
||||
}
|
||||
|
||||
private fun expectedMessage(
|
||||
channel: String,
|
||||
shouldAlertMoreThanOnce: Boolean,
|
||||
) = NotificationTypes.Room(
|
||||
AndroidNotification(
|
||||
channelId = "message",
|
||||
channelId = SUMMARY_CHANNEL_ID,
|
||||
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,
|
||||
@ -139,15 +155,17 @@ class NotificationFactoryTest {
|
||||
summary = LATEST_EVENT.content,
|
||||
messageCount = EVENTS.size,
|
||||
isAlerting = shouldAlertMoreThanOnce,
|
||||
summaryChannelId = channel,
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
@ -3,8 +3,11 @@ package app.dapk.st.notifications
|
||||
import app.dapk.st.matrix.sync.RoomEvent
|
||||
import app.dapk.st.matrix.sync.RoomOverview
|
||||
import fake.FakeRoomStore
|
||||
import fixture.*
|
||||
import fixture.NotificationDiffFixtures.aNotificationDiff
|
||||
import fixture.aRoomId
|
||||
import fixture.aRoomMessageEvent
|
||||
import fixture.aRoomOverview
|
||||
import fixture.anEventId
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@ -12,8 +15,8 @@ import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private val NO_UNREADS = emptyMap<RoomOverview, List<RoomEvent>>()
|
||||
private val A_MESSAGE = aRoomMessageEvent(eventId = anEventId("1"), content = "hello")
|
||||
private val A_MESSAGE_2 = aRoomMessageEvent(eventId = anEventId("2"), content = "world")
|
||||
private val A_MESSAGE = aRoomMessageEvent(eventId = anEventId("1"), content = "hello", utcTimestamp = 1000)
|
||||
private val A_MESSAGE_2 = aRoomMessageEvent(eventId = anEventId("2"), content = "world", utcTimestamp = 2000)
|
||||
private val A_ROOM_OVERVIEW = aRoomOverview(roomId = aRoomId("1"))
|
||||
private val A_ROOM_OVERVIEW_2 = aRoomOverview(roomId = aRoomId("2"))
|
||||
|
||||
@ -48,7 +51,7 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
|
||||
changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE),
|
||||
newRooms = setOf(A_ROOM_OVERVIEW.roomId)
|
||||
),
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE, A_MESSAGE_2))
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
|
||||
)
|
||||
}
|
||||
|
||||
@ -61,7 +64,7 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
|
||||
val result = useCase.invoke().toList()
|
||||
|
||||
result shouldBeEqualTo listOf(
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE, A_MESSAGE_2))
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE_2) to aNotificationDiff(changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE_2))
|
||||
)
|
||||
}
|
||||
|
||||
@ -76,6 +79,26 @@ class ObserveUnreadRenderNotificationsUseCaseTest {
|
||||
result shouldBeEqualTo emptyList()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given new and then historical message, when reading a message, then only emits the latest`() = runTest {
|
||||
fakeRoomStore.givenUnreadEvents(
|
||||
flowOf(
|
||||
NO_UNREADS,
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE),
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE, A_MESSAGE.copy(eventId = anEventId("old"), utcTimestamp = -1))
|
||||
)
|
||||
)
|
||||
|
||||
val result = useCase.invoke().toList()
|
||||
|
||||
result shouldBeEqualTo listOf(
|
||||
A_ROOM_OVERVIEW.withUnreads(A_MESSAGE) to aNotificationDiff(
|
||||
changedOrNew = A_ROOM_OVERVIEW.toDiff(A_MESSAGE),
|
||||
newRooms = setOf(A_ROOM_OVERVIEW.roomId)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given initial unreads, when reading a duplicate unread, then emits nothing`() = runTest {
|
||||
fakeRoomStore.givenUnreadEvents(
|
||||
|
@ -25,7 +25,12 @@ class RenderNotificationsUseCaseTest {
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `when creating use case instance, then initiates channels`() {
|
||||
fun `given events, when listening for changes then initiates channels once`() = runTest {
|
||||
fakeNotificationRenderer.instance.expect { it.render(any()) }
|
||||
fakeObserveUnreadNotificationsUseCase.given().emits(AN_UNREAD_NOTIFICATIONS)
|
||||
|
||||
renderNotificationsUseCase.listenForNotificationChanges()
|
||||
|
||||
fakeNotificationChannels.verifyInitiated()
|
||||
}
|
||||
|
||||
|
@ -14,15 +14,18 @@ object NotificationFixtures {
|
||||
) = Notifications(summaryNotification, delegates)
|
||||
|
||||
fun aRoomNotification(
|
||||
notification: AndroidNotification = anAndroidNotification(),
|
||||
summary: String = "a summary line",
|
||||
messageCount: Int = 1,
|
||||
isAlerting: Boolean = false,
|
||||
summaryChannelId: String = "a-summary-channel-id",
|
||||
) = NotificationTypes.Room(
|
||||
anAndroidNotification(),
|
||||
notification,
|
||||
aRoomId(),
|
||||
summary = summary,
|
||||
messageCount = messageCount,
|
||||
isAlerting = isAlerting
|
||||
isAlerting = isAlerting,
|
||||
summaryChannelId = summaryChannelId
|
||||
)
|
||||
|
||||
fun aDismissRoomNotification(
|
||||
|
Loading…
x
Reference in New Issue
Block a user