Disambiguate display name in notifications #2224
This commit is contained in:
parent
c0da3fb45e
commit
6bf1806ed4
6 changed files with 93 additions and 5 deletions
|
|
@ -46,4 +46,5 @@ dependencies {
|
||||||
testImplementation(libs.test.truth)
|
testImplementation(libs.test.truth)
|
||||||
testImplementation(libs.test.robolectric)
|
testImplementation(libs.test.robolectric)
|
||||||
testImplementation(projects.tests.testutils)
|
testImplementation(projects.tests.testutils)
|
||||||
|
testImplementation(projects.libraries.matrix.test)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,9 @@ data class NotificationData(
|
||||||
val roomId: RoomId,
|
val roomId: RoomId,
|
||||||
// mxc url
|
// mxc url
|
||||||
val senderAvatarUrl: String?,
|
val senderAvatarUrl: String?,
|
||||||
val senderDisplayName: String?,
|
// private, must use `getSenderName`
|
||||||
|
private val senderDisplayName: String?,
|
||||||
|
private val senderIsNameAmbiguous: Boolean,
|
||||||
val roomAvatarUrl: String?,
|
val roomAvatarUrl: String?,
|
||||||
val roomDisplayName: String?,
|
val roomDisplayName: String?,
|
||||||
val isDirect: Boolean,
|
val isDirect: Boolean,
|
||||||
|
|
@ -36,7 +38,13 @@ data class NotificationData(
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
val content: NotificationContent,
|
val content: NotificationContent,
|
||||||
val hasMention: Boolean,
|
val hasMention: Boolean,
|
||||||
)
|
) {
|
||||||
|
fun getSenderName(userId: UserId): String = when {
|
||||||
|
senderDisplayName.isNullOrBlank() -> userId.value
|
||||||
|
senderIsNameAmbiguous -> "$senderDisplayName ($userId)"
|
||||||
|
else -> senderDisplayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed interface NotificationContent {
|
sealed interface NotificationContent {
|
||||||
sealed interface MessageLike : NotificationContent {
|
sealed interface MessageLike : NotificationContent {
|
||||||
|
|
@ -54,11 +62,13 @@ sealed interface NotificationContent {
|
||||||
data class ReactionContent(
|
data class ReactionContent(
|
||||||
val relatedEventId: String
|
val relatedEventId: String
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data object RoomEncrypted : MessageLike
|
data object RoomEncrypted : MessageLike
|
||||||
data class RoomMessage(
|
data class RoomMessage(
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val messageType: MessageType
|
val messageType: MessageType
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data object RoomRedaction : MessageLike
|
data object RoomRedaction : MessageLike
|
||||||
data object Sticker : MessageLike
|
data object Sticker : MessageLike
|
||||||
data class Poll(
|
data class Poll(
|
||||||
|
|
@ -83,6 +93,7 @@ sealed interface NotificationContent {
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val membershipState: RoomMembershipState
|
val membershipState: RoomMembershipState
|
||||||
) : StateEvent
|
) : StateEvent
|
||||||
|
|
||||||
data object RoomName : StateEvent
|
data object RoomName : StateEvent
|
||||||
data object RoomPinnedEvents : StateEvent
|
data object RoomPinnedEvents : StateEvent
|
||||||
data object RoomPowerLevels : StateEvent
|
data object RoomPowerLevels : StateEvent
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 io.element.android.libraries.matrix.api.notification
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class NotificationDataTest {
|
||||||
|
@Test
|
||||||
|
fun `getSenderName should return user id if there is no sender name`() {
|
||||||
|
val sut = aNotificationData(
|
||||||
|
senderDisplayName = null,
|
||||||
|
senderIsNameAmbiguous = false,
|
||||||
|
)
|
||||||
|
assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("@alice:server.org")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getSenderName should return sender name if defined`() {
|
||||||
|
val sut = aNotificationData(
|
||||||
|
senderDisplayName = "Alice",
|
||||||
|
senderIsNameAmbiguous = false,
|
||||||
|
)
|
||||||
|
assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("Alice")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getSenderName should return sender name and user id in case of ambiguous display name`() {
|
||||||
|
val sut = aNotificationData(
|
||||||
|
senderDisplayName = "Alice",
|
||||||
|
senderIsNameAmbiguous = true,
|
||||||
|
)
|
||||||
|
assertThat(sut.getSenderName(A_USER_ID)).isEqualTo("Alice (@alice:server.org)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun aNotificationData(
|
||||||
|
senderDisplayName: String?,
|
||||||
|
senderIsNameAmbiguous: Boolean,
|
||||||
|
): NotificationData {
|
||||||
|
return NotificationData(
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
senderAvatarUrl = null,
|
||||||
|
senderDisplayName = senderDisplayName,
|
||||||
|
senderIsNameAmbiguous = senderIsNameAmbiguous,
|
||||||
|
roomAvatarUrl = null,
|
||||||
|
roomDisplayName = null,
|
||||||
|
isDirect = false,
|
||||||
|
isEncrypted = false,
|
||||||
|
isNoisy = false,
|
||||||
|
timestamp = 0L,
|
||||||
|
content = NotificationContent.MessageLike.RoomEncrypted,
|
||||||
|
hasMention = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ class NotificationMapper(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
senderAvatarUrl = item.senderInfo.avatarUrl,
|
senderAvatarUrl = item.senderInfo.avatarUrl,
|
||||||
senderDisplayName = item.senderInfo.displayName,
|
senderDisplayName = item.senderInfo.displayName,
|
||||||
|
senderIsNameAmbiguous = item.senderInfo.isNameAmbiguous,
|
||||||
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { item.roomInfo.isDirect },
|
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { item.roomInfo.isDirect },
|
||||||
roomDisplayName = item.roomInfo.displayName,
|
roomDisplayName = item.roomInfo.displayName,
|
||||||
isDirect = item.roomInfo.isDirect,
|
isDirect = item.roomInfo.isDirect,
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,8 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
): NotifiableEvent? {
|
): NotifiableEvent? {
|
||||||
return when (val content = this.content) {
|
return when (val content = this.content) {
|
||||||
is NotificationContent.MessageLike.RoomMessage -> {
|
is NotificationContent.MessageLike.RoomMessage -> {
|
||||||
val messageBody = descriptionFromMessageContent(content, senderDisplayName ?: content.senderId.value)
|
val senderName = getSenderName(content.senderId)
|
||||||
|
val messageBody = descriptionFromMessageContent(content, senderName)
|
||||||
val notificationBody = if (hasMention) {
|
val notificationBody = if (hasMention) {
|
||||||
stringProvider.getString(R.string.notification_mentioned_you_body, messageBody)
|
stringProvider.getString(R.string.notification_mentioned_you_body, messageBody)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -104,7 +105,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = senderDisplayName,
|
senderName = senderName,
|
||||||
body = notificationBody,
|
body = notificationBody,
|
||||||
imageUriString = fetchImageIfPresent(client)?.toString(),
|
imageUriString = fetchImageIfPresent(client)?.toString(),
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
|
|
@ -161,7 +162,7 @@ class NotifiableEventResolver @Inject constructor(
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
noisy = isNoisy,
|
noisy = isNoisy,
|
||||||
timestamp = this.timestamp,
|
timestamp = this.timestamp,
|
||||||
senderName = senderDisplayName,
|
senderName = getSenderName(content.senderId),
|
||||||
body = stringProvider.getString(CommonStrings.common_poll_summary, content.question),
|
body = stringProvider.getString(CommonStrings.common_poll_summary, content.question),
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
roomName = roomDisplayName,
|
roomName = roomDisplayName,
|
||||||
|
|
|
||||||
|
|
@ -527,6 +527,7 @@ class NotifiableEventResolverTest {
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
senderAvatarUrl = null,
|
senderAvatarUrl = null,
|
||||||
senderDisplayName = "Bob",
|
senderDisplayName = "Bob",
|
||||||
|
senderIsNameAmbiguous = false,
|
||||||
roomAvatarUrl = null,
|
roomAvatarUrl = null,
|
||||||
roomDisplayName = null,
|
roomDisplayName = null,
|
||||||
isDirect = isDirect,
|
isDirect = isDirect,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue