mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-01 11:46:57 +01:00
creating the notifications separate to where they're displayed
- also handles when the event diff means the notifications should be removed
This commit is contained in:
parent
7b0c483134
commit
0f4ec65b7a
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.notifications
|
||||
|
||||
import android.app.Notification
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationFactory @Inject constructor(
|
||||
private val notificationUtils: NotificationUtils,
|
||||
private val roomGroupMessageCreator: RoomGroupMessageCreator,
|
||||
private val summaryGroupMessageCreator: SummaryGroupMessageCreator
|
||||
) {
|
||||
|
||||
fun Map<String, List<NotifiableMessageEvent>>.toNotifications(myUserDisplayName: String, myUserAvatarUrl: String?): List<RoomNotification> {
|
||||
return this.map { (roomId, events) ->
|
||||
when {
|
||||
events.hasNoEventsToDisplay() -> RoomNotification.EmptyRoom(roomId)
|
||||
else -> roomGroupMessageCreator.createRoomMessage(events, roomId, myUserDisplayName, myUserAvatarUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<NotifiableMessageEvent>.hasNoEventsToDisplay() = isEmpty() || all { it.canNotBeDisplayed() }
|
||||
|
||||
private fun NotifiableMessageEvent.canNotBeDisplayed() = hasBeenDisplayed || isRedacted
|
||||
|
||||
fun Map<String, InviteNotifiableEvent?>.toNotifications(myUserId: String): List<OneShotNotification> {
|
||||
return this.map { (roomId, event) ->
|
||||
when (event) {
|
||||
null -> OneShotNotification.Removed(key = roomId)
|
||||
else -> OneShotNotification.Append(
|
||||
notificationUtils.buildRoomInvitationNotification(event, myUserId),
|
||||
OneShotNotification.Append.Meta(key = roomId, summaryLine = event.description, isNoisy = event.noisy)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmName("toNotificationsSimpleNotifiableEvent")
|
||||
fun Map<String, SimpleNotifiableEvent?>.toNotifications(myUserId: String): List<OneShotNotification> {
|
||||
return this.map { (eventId, event) ->
|
||||
when (event) {
|
||||
null -> OneShotNotification.Removed(key = eventId)
|
||||
else -> OneShotNotification.Append(
|
||||
notificationUtils.buildSimpleEventNotification(event, myUserId),
|
||||
OneShotNotification.Append.Meta(key = eventId, summaryLine = event.description, isNoisy = event.noisy)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createSummaryNotification(roomNotifications: List<RoomNotification>,
|
||||
invitationNotifications: List<OneShotNotification>,
|
||||
simpleNotifications: List<OneShotNotification>,
|
||||
useCompleteNotificationFormat: Boolean): Notification {
|
||||
return summaryGroupMessageCreator.createSummaryNotification(
|
||||
roomNotifications = roomNotifications.mapToMeta(),
|
||||
invitationNotifications = invitationNotifications.mapToMeta(),
|
||||
simpleNotifications = simpleNotifications.mapToMeta(),
|
||||
useCompleteNotificationFormat = useCompleteNotificationFormat
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<RoomNotification>.mapToMeta() = filterIsInstance<RoomNotification.Message>().map { it.meta }
|
||||
|
||||
@JvmName("mapToMetaOneShotNotification")
|
||||
private fun List<OneShotNotification>.mapToMeta() = filterIsInstance<OneShotNotification.Append>().map { it.meta }
|
||||
|
||||
sealed interface RoomNotification {
|
||||
data class EmptyRoom(val roomId: String) : RoomNotification
|
||||
data class Message(val notification: Notification, val meta: Meta) : RoomNotification {
|
||||
data class Meta(
|
||||
val summaryLine: CharSequence,
|
||||
val messageCount: Int,
|
||||
val latestTimestamp: Long,
|
||||
val roomId: String,
|
||||
val shouldBing: Boolean
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface OneShotNotification {
|
||||
data class Removed(val key: String) : OneShotNotification
|
||||
data class Append(val notification: Notification, val meta: Meta) : OneShotNotification {
|
||||
data class Meta(
|
||||
val key: String,
|
||||
val summaryLine: CharSequence,
|
||||
val isNoisy: Boolean
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.notifications
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.Person
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import me.gujun.android.span.Span
|
||||
import me.gujun.android.span.span
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomGroupMessageCreator @Inject constructor(
|
||||
private val iconLoader: IconLoader,
|
||||
private val bitmapLoader: BitmapLoader,
|
||||
private val stringProvider: StringProvider,
|
||||
private val notificationUtils: NotificationUtils
|
||||
) {
|
||||
|
||||
fun createRoomMessage(events: List<NotifiableMessageEvent>, roomId: String, userDisplayName: String, userAvatarUrl: String?): RoomNotification.Message {
|
||||
val firstKnownRoomEvent = events[0]
|
||||
val roomName = firstKnownRoomEvent.roomName ?: firstKnownRoomEvent.senderName ?: ""
|
||||
val roomIsGroup = !firstKnownRoomEvent.roomIsDirect
|
||||
val style = NotificationCompat.MessagingStyle(Person.Builder()
|
||||
.setName(userDisplayName)
|
||||
.setIcon(iconLoader.getUserIcon(userAvatarUrl))
|
||||
.setKey(firstKnownRoomEvent.matrixID)
|
||||
.build()
|
||||
).also {
|
||||
it.conversationTitle = roomName.takeIf { roomIsGroup }
|
||||
it.isGroupConversation = roomIsGroup
|
||||
it.addMessagesFromEvents(events)
|
||||
}
|
||||
|
||||
val tickerText = if (roomIsGroup) {
|
||||
stringProvider.getString(R.string.notification_ticker_text_group, roomName, events.last().senderName, events.last().description)
|
||||
} else {
|
||||
stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
|
||||
}
|
||||
|
||||
val lastMessageTimestamp = events.last().timestamp
|
||||
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
||||
val messageCount = (events.size - smartReplyErrors.size)
|
||||
val meta = RoomNotification.Message.Meta(
|
||||
summaryLine = createRoomMessagesGroupSummaryLine(events, roomName, roomIsDirect = !roomIsGroup),
|
||||
messageCount = messageCount,
|
||||
latestTimestamp = lastMessageTimestamp,
|
||||
roomId = roomId,
|
||||
shouldBing = events.any { it.noisy }
|
||||
)
|
||||
return RoomNotification.Message(
|
||||
notificationUtils.buildMessagesListNotification(
|
||||
style,
|
||||
RoomEventGroupInfo(roomId, roomName, isDirect = !roomIsGroup).also {
|
||||
it.hasSmartReplyError = smartReplyErrors.isNotEmpty()
|
||||
it.shouldBing = meta.shouldBing
|
||||
it.customSound = events.last().soundName
|
||||
},
|
||||
largeIcon = getRoomBitmap(events),
|
||||
lastMessageTimestamp,
|
||||
userDisplayName,
|
||||
tickerText
|
||||
),
|
||||
meta
|
||||
)
|
||||
}
|
||||
|
||||
private fun NotificationCompat.MessagingStyle.addMessagesFromEvents(events: List<NotifiableMessageEvent>) {
|
||||
events.forEach { event ->
|
||||
val senderPerson = Person.Builder()
|
||||
.setName(event.senderName)
|
||||
.setIcon(iconLoader.getUserIcon(event.senderAvatarPath))
|
||||
.setKey(event.senderId)
|
||||
.build()
|
||||
when {
|
||||
event.isSmartReplyError() -> addMessage(stringProvider.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson)
|
||||
else -> addMessage(event.body, event.timestamp, senderPerson)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRoomMessagesGroupSummaryLine(events: List<NotifiableMessageEvent>, roomName: String, roomIsDirect: Boolean): CharSequence {
|
||||
return try {
|
||||
when (events.size) {
|
||||
1 -> createFirstMessageSummaryLine(events.first(), roomName, roomIsDirect)
|
||||
else -> {
|
||||
stringProvider.getQuantityString(
|
||||
R.plurals.notification_compat_summary_line_for_room,
|
||||
events.size,
|
||||
roomName,
|
||||
events.size
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// String not found or bad format
|
||||
Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER failed to resolve string")
|
||||
roomName
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFirstMessageSummaryLine(event: NotifiableMessageEvent, roomName: String, roomIsDirect: Boolean): Span {
|
||||
return if (roomIsDirect) {
|
||||
span {
|
||||
span {
|
||||
textStyle = "bold"
|
||||
+String.format("%s: ", event.senderName)
|
||||
}
|
||||
+(event.description)
|
||||
}
|
||||
} else {
|
||||
span {
|
||||
span {
|
||||
textStyle = "bold"
|
||||
+String.format("%s: %s ", roomName, event.senderName)
|
||||
}
|
||||
+(event.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRoomBitmap(events: List<NotifiableMessageEvent>): Bitmap? {
|
||||
if (events.isEmpty()) return null
|
||||
|
||||
// Use the last event (most recent?)
|
||||
val roomAvatarPath = events.last().roomAvatarPath ?: events.last().senderAvatarPath
|
||||
|
||||
return bitmapLoader.getRoomBitmap(roomAvatarPath)
|
||||
}
|
||||
}
|
||||
|
||||
private fun NotifiableMessageEvent.isSmartReplyError() = this.outGoingMessage && this.outGoingMessageFailed
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.notifications
|
||||
|
||||
import android.app.Notification
|
||||
import androidx.core.app.NotificationCompat
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
class SummaryGroupMessageCreator @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
private val notificationUtils: NotificationUtils
|
||||
) {
|
||||
|
||||
/**
|
||||
* ======== Build summary notification =========
|
||||
* On Android 7.0 (API level 24) and higher, the system automatically builds a summary for
|
||||
* your group using snippets of text from each notification. The user can expand this
|
||||
* notification to see each separate notification.
|
||||
* To support older versions, which cannot show a nested group of notifications,
|
||||
* you must create an extra notification that acts as the summary.
|
||||
* This appears as the only notification and the system hides all the others.
|
||||
* So this summary should include a snippet from all the other notifications,
|
||||
* which the user can tap to open your app.
|
||||
* The behavior of the group summary may vary on some device types such as wearables.
|
||||
* To ensure the best experience on all devices and versions, always include a group summary when you create a group
|
||||
* https://developer.android.com/training/notify-user/group
|
||||
*/
|
||||
fun createSummaryNotification(roomNotifications: List<RoomNotification.Message.Meta>,
|
||||
invitationNotifications: List<OneShotNotification.Append.Meta>,
|
||||
simpleNotifications: List<OneShotNotification.Append.Meta>,
|
||||
useCompleteNotificationFormat: Boolean): Notification {
|
||||
val summaryInboxStyle = NotificationCompat.InboxStyle().also { style ->
|
||||
roomNotifications.forEach { style.addLine(it.summaryLine) }
|
||||
invitationNotifications.forEach { style.addLine(it.summaryLine) }
|
||||
simpleNotifications.forEach { style.addLine(it.summaryLine) }
|
||||
}
|
||||
|
||||
val summaryIsNoisy = roomNotifications.any { it.shouldBing }
|
||||
|| invitationNotifications.any { it.isNoisy }
|
||||
|| simpleNotifications.any { it.isNoisy }
|
||||
|
||||
val messageCount = roomNotifications.fold(initial = 0) { acc, current -> acc + current.messageCount }
|
||||
|
||||
val lastMessageTimestamp1 = roomNotifications.last().latestTimestamp
|
||||
|
||||
// FIXME roomIdToEventMap.size is not correct, this is the number of rooms
|
||||
val nbEvents = roomNotifications.size + simpleNotifications.size
|
||||
val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
|
||||
summaryInboxStyle.setBigContentTitle(sumTitle)
|
||||
// TODO get latest event?
|
||||
.setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
|
||||
return if (useCompleteNotificationFormat
|
||||
) {
|
||||
notificationUtils.buildSummaryListNotification(
|
||||
summaryInboxStyle,
|
||||
sumTitle,
|
||||
noisy = summaryIsNoisy,
|
||||
lastMessageTimestamp = lastMessageTimestamp1
|
||||
)
|
||||
} else {
|
||||
processSimpleGroupSummary(summaryIsNoisy, messageCount,
|
||||
simpleNotifications.size, invitationNotifications.size,
|
||||
roomNotifications.size, lastMessageTimestamp1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processSimpleGroupSummary(summaryIsNoisy: Boolean,
|
||||
messageEventsCount: Int,
|
||||
simpleEventsCount: Int,
|
||||
invitationEventsCount: Int,
|
||||
roomCount: Int,
|
||||
lastMessageTimestamp: Long): Notification {
|
||||
// Add the simple events as message (?)
|
||||
val messageNotificationCount = messageEventsCount + simpleEventsCount
|
||||
|
||||
val privacyTitle = if (invitationEventsCount > 0) {
|
||||
val invitationsStr = stringProvider.getQuantityString(R.plurals.notification_invitations, invitationEventsCount, invitationEventsCount)
|
||||
if (messageNotificationCount > 0) {
|
||||
// Invitation and message
|
||||
val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
|
||||
messageNotificationCount, messageNotificationCount)
|
||||
if (roomCount > 1) {
|
||||
// In several rooms
|
||||
val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms,
|
||||
roomCount, roomCount)
|
||||
stringProvider.getString(
|
||||
R.string.notification_unread_notified_messages_in_room_and_invitation,
|
||||
messageStr,
|
||||
roomStr,
|
||||
invitationsStr
|
||||
)
|
||||
} else {
|
||||
// In one room
|
||||
stringProvider.getString(
|
||||
R.string.notification_unread_notified_messages_and_invitation,
|
||||
messageStr,
|
||||
invitationsStr
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Only invitation
|
||||
invitationsStr
|
||||
}
|
||||
} else {
|
||||
// No invitation, only messages
|
||||
val messageStr = stringProvider.getQuantityString(R.plurals.room_new_messages_notification,
|
||||
messageNotificationCount, messageNotificationCount)
|
||||
if (roomCount > 1) {
|
||||
// In several rooms
|
||||
val roomStr = stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages_in_room_rooms, roomCount, roomCount)
|
||||
stringProvider.getString(R.string.notification_unread_notified_messages_in_room, messageStr, roomStr)
|
||||
} else {
|
||||
// In one room
|
||||
messageStr
|
||||
}
|
||||
}
|
||||
return notificationUtils.buildSummaryListNotification(
|
||||
style = null,
|
||||
compatSummary = privacyTitle,
|
||||
noisy = summaryIsNoisy,
|
||||
lastMessageTimestamp = lastMessageTimestamp
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.notifications
|
||||
|
||||
import im.vector.app.test.fakes.FakeNotificationUtils
|
||||
import im.vector.app.test.fakes.FakeRoomGroupMessageCreator
|
||||
import im.vector.app.test.fakes.FakeSummaryGroupMessageCreator
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private const val MY_USER_ID = "user-id"
|
||||
private const val A_ROOM_ID = "room-id"
|
||||
private const val AN_EVENT_ID = "event-id"
|
||||
|
||||
private val MY_AVATAR_URL: String? = null
|
||||
private val AN_INVITATION_EVENT = anInviteNotifiableEvent(roomId = A_ROOM_ID)
|
||||
private val A_SIMPLE_EVENT = aSimpleNotifiableEvent(eventId = AN_EVENT_ID)
|
||||
private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)
|
||||
|
||||
class NotificationFactoryTest {
|
||||
|
||||
private val notificationUtils = FakeNotificationUtils()
|
||||
private val roomGroupMessageCreator = FakeRoomGroupMessageCreator()
|
||||
private val summaryGroupMessageCreator = FakeSummaryGroupMessageCreator()
|
||||
|
||||
private val notificationFactory = NotificationFactory(
|
||||
notificationUtils.instance,
|
||||
roomGroupMessageCreator.instance,
|
||||
summaryGroupMessageCreator.instance
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `given a room invitation when mapping to notification then is Append`() = testWith(notificationFactory) {
|
||||
val expectedNotification = notificationUtils.givenBuildRoomInvitationNotificationFor(AN_INVITATION_EVENT, MY_USER_ID)
|
||||
val roomInvitation = mapOf(A_ROOM_ID to AN_INVITATION_EVENT)
|
||||
|
||||
val result = roomInvitation.toNotifications(MY_USER_ID)
|
||||
|
||||
result shouldBeEqualTo listOf(OneShotNotification.Append(
|
||||
notification = expectedNotification,
|
||||
meta = OneShotNotification.Append.Meta(
|
||||
key = A_ROOM_ID,
|
||||
summaryLine = AN_INVITATION_EVENT.description,
|
||||
isNoisy = AN_INVITATION_EVENT.noisy
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a missing event in room invitation when mapping to notification then is Removed`() = testWith(notificationFactory) {
|
||||
val missingEventRoomInvitation: Map<String, InviteNotifiableEvent?> = mapOf(A_ROOM_ID to null)
|
||||
|
||||
val result = missingEventRoomInvitation.toNotifications(MY_USER_ID)
|
||||
|
||||
result shouldBeEqualTo listOf(OneShotNotification.Removed(
|
||||
key = A_ROOM_ID
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a simple event when mapping to notification then is Append`() = testWith(notificationFactory) {
|
||||
val expectedNotification = notificationUtils.givenBuildSimpleInvitationNotificationFor(A_SIMPLE_EVENT, MY_USER_ID)
|
||||
val roomInvitation = mapOf(AN_EVENT_ID to A_SIMPLE_EVENT)
|
||||
|
||||
val result = roomInvitation.toNotifications(MY_USER_ID)
|
||||
|
||||
result shouldBeEqualTo listOf(OneShotNotification.Append(
|
||||
notification = expectedNotification,
|
||||
meta = OneShotNotification.Append.Meta(
|
||||
key = AN_EVENT_ID,
|
||||
summaryLine = A_SIMPLE_EVENT.description,
|
||||
isNoisy = A_SIMPLE_EVENT.noisy
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a missing simple event when mapping to notification then is Removed`() = testWith(notificationFactory) {
|
||||
val missingEventRoomInvitation: Map<String, SimpleNotifiableEvent?> = mapOf(AN_EVENT_ID to null)
|
||||
|
||||
val result = missingEventRoomInvitation.toNotifications(MY_USER_ID)
|
||||
|
||||
result shouldBeEqualTo listOf(OneShotNotification.Removed(
|
||||
key = AN_EVENT_ID
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given room with message when mapping to notification then delegates to room group message creator`() = testWith(notificationFactory) {
|
||||
val events = listOf(A_MESSAGE_EVENT)
|
||||
val expectedNotification = roomGroupMessageCreator.givenCreatesRoomMessageFor(events, A_ROOM_ID, MY_USER_ID, MY_AVATAR_URL)
|
||||
val roomWithMessage = mapOf(A_ROOM_ID to events)
|
||||
|
||||
val result = roomWithMessage.toNotifications(MY_USER_ID, MY_AVATAR_URL)
|
||||
|
||||
result shouldBeEqualTo listOf(expectedNotification)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a room with no events to display when mapping to notification then is Empty`() = testWith(notificationFactory) {
|
||||
val emptyRoom: Map<String, List<NotifiableMessageEvent>> = mapOf(A_ROOM_ID to emptyList())
|
||||
|
||||
val result = emptyRoom.toNotifications(MY_USER_ID, MY_AVATAR_URL)
|
||||
|
||||
result shouldBeEqualTo listOf(RoomNotification.EmptyRoom(
|
||||
roomId = A_ROOM_ID
|
||||
))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationFactory) {
|
||||
val redactedRoom = mapOf(A_ROOM_ID to listOf(A_MESSAGE_EVENT.copy().apply { isRedacted = true }))
|
||||
|
||||
val result = redactedRoom.toNotifications(MY_USER_ID, MY_AVATAR_URL)
|
||||
|
||||
result shouldBeEqualTo listOf(RoomNotification.EmptyRoom(
|
||||
roomId = A_ROOM_ID
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> testWith(receiver: T, block: T.() -> Unit) {
|
||||
receiver.block()
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import android.app.Notification
|
||||
import im.vector.app.features.notifications.InviteNotifiableEvent
|
||||
import im.vector.app.features.notifications.NotificationUtils
|
||||
import im.vector.app.features.notifications.SimpleNotifiableEvent
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
class FakeNotificationUtils {
|
||||
|
||||
val instance = mockk<NotificationUtils>()
|
||||
|
||||
fun givenBuildRoomInvitationNotificationFor(event: InviteNotifiableEvent, myUserId: String): Notification {
|
||||
val mockNotification = mockk<Notification>()
|
||||
every { instance.buildRoomInvitationNotification(event, myUserId) } returns mockNotification
|
||||
return mockNotification
|
||||
}
|
||||
|
||||
fun givenBuildSimpleInvitationNotificationFor(event: SimpleNotifiableEvent, myUserId: String): Notification {
|
||||
val mockNotification = mockk<Notification>()
|
||||
every { instance.buildSimpleEventNotification(event, myUserId) } returns mockNotification
|
||||
return mockNotification
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import im.vector.app.features.notifications.NotifiableMessageEvent
|
||||
import im.vector.app.features.notifications.RoomGroupMessageCreator
|
||||
import im.vector.app.features.notifications.RoomNotification
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
class FakeRoomGroupMessageCreator {
|
||||
|
||||
val instance = mockk<RoomGroupMessageCreator>()
|
||||
|
||||
fun givenCreatesRoomMessageFor(events: List<NotifiableMessageEvent>,
|
||||
roomId: String,
|
||||
userDisplayName: String,
|
||||
userAvatarUrl: String?): RoomNotification.Message {
|
||||
val mockMessage = mockk<RoomNotification.Message>()
|
||||
every { instance.createRoomMessage(events, roomId, userDisplayName, userAvatarUrl) } returns mockMessage
|
||||
return mockMessage
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import im.vector.app.features.notifications.SummaryGroupMessageCreator
|
||||
import io.mockk.mockk
|
||||
|
||||
class FakeSummaryGroupMessageCreator {
|
||||
|
||||
val instance = mockk<SummaryGroupMessageCreator>()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user