From ca1f907ec52699901ac952582af5d2d508ce125c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 19 Jan 2024 17:48:26 +0100 Subject: [PATCH] Use new Rust fields `numUnreadMessages` and `numUnreadMentions`, and iterate on the room badge rendering. --- .../impl/InviteListPresenterTests.kt | 3 - ...DefaultNotificationSettingStateProvider.kt | 1 - .../roomlist/impl/RoomListStateProvider.kt | 4 +- .../impl/components/RoomSummaryRow.kt | 90 +++++++++++++------ .../datasource/RoomListRoomSummaryFactory.kt | 6 +- .../impl/model/RoomListRoomSummary.kt | 13 ++- .../impl/model/RoomListRoomSummaryProvider.kt | 77 ++++++++++++---- .../roomlist/impl/RoomListPresenterTests.kt | 3 +- .../matrix/api/roomlist/RoomSummary.kt | 3 +- .../roomlist/RoomSummaryDetailsFactory.kt | 3 +- .../matrix/test/room/RoomSummaryFixture.kt | 12 ++- .../matrix/ui/components/SelectedRoom.kt | 6 +- 12 files changed, 159 insertions(+), 62 deletions(-) diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index a841b21c56..0fa899e033 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -431,7 +431,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, displayName = A_USER_NAME, @@ -459,7 +458,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = true, lastMessage = null, - unreadNotificationCount = 0, inviter = RoomMember( userId = A_USER_ID, displayName = A_USER_NAME, @@ -484,7 +482,6 @@ class InviteListPresenterTests { avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, ) ) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt index 3c7df8fc52..1eb7c0389e 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt @@ -55,7 +55,6 @@ private fun aRoomSummary() = RoomSummary.Filled( avatarUrl = null, isDirect = false, lastMessage = null, - unreadNotificationCount = 0, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, ) ) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index 33736ab592..b1e43f147e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -73,7 +73,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { return persistentListOf( aRoomListRoomSummary( name = "Room", - hasUnread = true, + numberOfUnreadMessages = 1, timestamp = "14:18", lastMessage = "A very very very very long message which suites on two lines", avatarData = AvatarData("!id", "R", size = AvatarSize.RoomListItem), @@ -81,7 +81,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { ), aRoomListRoomSummary( name = "Room#2", - hasUnread = false, + numberOfUnreadMessages = 0, timestamp = "14:16", lastMessage = "A short message", avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index d8ee21093f..dd16a281c2 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -43,6 +43,7 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider +import io.element.android.features.roomlist.impl.model.isTimestampHighlighted import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.components.avatar.Avatar @@ -141,7 +142,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { Text( text = room.timestamp ?: "", style = ElementTheme.typography.fontBodySmMedium, - color = if (room.hasUnread) { + color = if (room.isTimestampHighlighted()) { ElementTheme.colors.unreadIndicator } else { MaterialTheme.roomListRoomMessageDate() @@ -173,40 +174,77 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { verticalAlignment = Alignment.CenterVertically, ) { // Video call - if (room.hasRoomCall) { - Icon( - modifier = Modifier.size(16.dp), - imageVector = CompoundIcons.VideoCallSolid, - contentDescription = null, - tint = ElementTheme.colors.unreadIndicator, - ) - } - NotificationIcon(room) - if (room.hasUnread) { - UnreadIndicatorAtom() - } + OnGoingCallIcon( + room.hasRoomCall, + ) + // Other indicators + NotificationIcons( + room.userDefinedNotificationMode, + room.numberOfUnreadMessages, + room.numberOfUnreadMentions, + ) } } @Composable -private fun NotificationIcon(room: RoomListRoomSummary) { - val tint = if (room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary - when (room.userDefinedNotificationMode) { - null, RoomNotificationMode.ALL_MESSAGES -> return - RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> - Icon( - modifier = Modifier.size(16.dp), - contentDescription = null, - imageVector = CompoundIcons.Mention, - tint = tint, - ) - RoomNotificationMode.MUTE -> +private fun OnGoingCallIcon( + hasRoomCall: Boolean, +) { + if (hasRoomCall) { + Icon( + modifier = Modifier.size(16.dp), + imageVector = CompoundIcons.VideoCallSolid, + contentDescription = null, + tint = ElementTheme.colors.unreadIndicator, + ) + } +} + +@Composable +private fun RowScope.NotificationIcons( + userDefinedNotificationMode: RoomNotificationMode?, + numberOfUnreadMessages: Int, + numberOfUnreadMentions: Int, +) { + when (userDefinedNotificationMode) { + null, + RoomNotificationMode.ALL_MESSAGES -> { + if (numberOfUnreadMentions > 0) { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.Mention, + tint = ElementTheme.colors.unreadIndicator, + ) + UnreadIndicatorAtom() + } else if (numberOfUnreadMessages > 0) { + UnreadIndicatorAtom() + } + } + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { + if (numberOfUnreadMentions > 0) { + Icon( + modifier = Modifier.size(16.dp), + contentDescription = null, + imageVector = CompoundIcons.Mention, + tint = ElementTheme.colors.unreadIndicator, + ) + UnreadIndicatorAtom() + } else if (numberOfUnreadMessages > 0) { + UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) + } + } + RoomNotificationMode.MUTE -> { Icon( modifier = Modifier.size(16.dp), contentDescription = null, imageVector = CompoundIcons.NotificationsSolidOff, - tint = tint, + tint = ElementTheme.colors.iconQuaternary, ) + if (numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0) { + UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary) + } + } } } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt index da430d7b73..e12674658a 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt @@ -41,7 +41,8 @@ class RoomListRoomSummaryFactory @Inject constructor( timestamp = "hh:mm", lastMessage = "Last message for placeholder", avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), - hasUnread = false, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 0, userDefinedNotificationMode = null, hasRoomCall = false, isDm = false, @@ -66,7 +67,8 @@ class RoomListRoomSummaryFactory @Inject constructor( id = roomIdentifier, roomId = RoomId(roomIdentifier), name = roomSummary.details.name, - hasUnread = roomSummary.details.unreadNotificationCount > 0, + numberOfUnreadMessages = roomSummary.details.numUnreadMessages, + numberOfUnreadMentions = roomSummary.details.numUnreadMentions, timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), lastMessage = roomSummary.details.lastMessage?.let { message -> roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt index 81638ee2e3..0669be0031 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummary.kt @@ -26,7 +26,8 @@ data class RoomListRoomSummary( val id: String, val roomId: RoomId, val name: String, - val hasUnread: Boolean, + val numberOfUnreadMessages: Int, + val numberOfUnreadMentions: Int, val timestamp: String?, val lastMessage: CharSequence?, val avatarData: AvatarData, @@ -35,3 +36,13 @@ data class RoomListRoomSummary( val hasRoomCall: Boolean, val isDm: Boolean, ) + +fun RoomListRoomSummary.isTimestampHighlighted(): Boolean { + return hasRoomCall || + when (userDefinedNotificationMode) { + null, + RoomNotificationMode.ALL_MESSAGES -> numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0 + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> numberOfUnreadMentions > 0 + RoomNotificationMode.MUTE -> false + } +} diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt index 0a45aa10f9..f1b0403f5b 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/model/RoomListRoomSummaryProvider.kt @@ -25,29 +25,69 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode open class RoomListRoomSummaryProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( - aRoomListRoomSummary(), - aRoomListRoomSummary(lastMessage = null), - aRoomListRoomSummary(hasUnread = true, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary(notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), - aRoomListRoomSummary(notificationMode = RoomNotificationMode.MUTE), - aRoomListRoomSummary(hasUnread = true), - aRoomListRoomSummary(isPlaceholder = true), - aRoomListRoomSummary( - name = "A very long room name that should be truncated", - lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + - " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + - "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - timestamp = "yesterday", - hasUnread = true, + listOf( + aRoomListRoomSummary(isPlaceholder = true), + aRoomListRoomSummary(), + aRoomListRoomSummary(lastMessage = null), + aRoomListRoomSummary( + name = "A very long room name that should be truncated", + lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + + " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + + "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", + timestamp = "yesterday", + numberOfUnreadMessages = 1, + ), ), - aRoomListRoomSummary(hasUnread = true, hasRoomCall = true), - ) + listOf(false, true).map { hasCall -> + listOf( + RoomNotificationMode.ALL_MESSAGES, + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, + RoomNotificationMode.MUTE, + ).map { roomNotificationMode -> + listOf( + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "No activity" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 0, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New messages" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 1, + numberOfUnreadMentions = 0, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New messages, mentions" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 1, + numberOfUnreadMentions = 1, + hasRoomCall = hasCall, + ), + aRoomListRoomSummary( + name = roomNotificationMode.name, + lastMessage = "New mentions" + if (hasCall) ", call" else "", + notificationMode = roomNotificationMode, + numberOfUnreadMessages = 0, + numberOfUnreadMentions = 1, + hasRoomCall = hasCall, + ), + ) + }.flatten() + }.flatten(), + ).flatten() } internal fun aRoomListRoomSummary( id: String = "!roomId:domain", name: String = "Room name", - hasUnread: Boolean = false, + numberOfUnreadMessages: Int = 0, + numberOfUnreadMentions: Int = 0, lastMessage: String? = "Last message", timestamp: String? = lastMessage?.let { "88:88" }, isPlaceholder: Boolean = false, @@ -59,7 +99,8 @@ internal fun aRoomListRoomSummary( id = id, roomId = RoomId(id), name = name, - hasUnread = hasUnread, + numberOfUnreadMessages = numberOfUnreadMessages, + numberOfUnreadMentions = numberOfUnreadMentions, timestamp = timestamp, lastMessage = lastMessage, avatarData = avatarData, diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index b868c950e5..27d8fca783 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -440,7 +440,8 @@ private val aRoomListRoomSummary = RoomListRoomSummary( id = A_ROOM_ID.value, roomId = A_ROOM_ID, name = A_ROOM_NAME, - hasUnread = true, + numberOfUnreadMentions = 1, + numberOfUnreadMessages = 2, timestamp = A_FORMATTED_DATE, lastMessage = "", avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt index 6c43ee1fef..09862c7879 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt @@ -40,7 +40,8 @@ data class RoomSummaryDetails( val isDirect: Boolean, val avatarUrl: String?, val lastMessage: RoomMessage?, - val unreadNotificationCount: Int, + val numUnreadMessages: Int, + val numUnreadMentions: Int, val inviter: RoomMember?, val userDefinedNotificationMode: RoomNotificationMode?, val hasRoomCall: Boolean, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index 5dd6f1ff8a..d308f2b1d3 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -35,7 +35,8 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto canonicalAlias = roomInfo.canonicalAlias, isDirect = roomInfo.isDirect, avatarUrl = roomInfo.avatarUrl, - unreadNotificationCount = roomInfo.notificationCount.toInt(), + numUnreadMentions = roomInfo.numUnreadMentions.toInt(), + numUnreadMessages = roomInfo.numUnreadMessages.toInt(), lastMessage = latestRoomMessage, inviter = roomInfo.inviter?.let(RoomMemberMapper::map), userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt index a0a69bfe7b..9e8c438ee3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt @@ -37,7 +37,8 @@ fun aRoomSummaryFilled( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - unreadNotificationCount: Int = 2, + numUnreadMentions: Int = 1, + numUnreadMessages: Int = 2, notificationMode: RoomNotificationMode? = null, ) = RoomSummary.Filled( aRoomSummaryDetails( @@ -46,7 +47,8 @@ fun aRoomSummaryFilled( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, notificationMode = notificationMode, ) ) @@ -57,7 +59,8 @@ fun aRoomSummaryDetails( isDirect: Boolean = false, avatarUrl: String? = null, lastMessage: RoomMessage? = aRoomMessage(), - unreadNotificationCount: Int = 2, + numUnreadMentions: Int = 0, + numUnreadMessages: Int = 0, notificationMode: RoomNotificationMode? = null, inviter: RoomMember? = null, canonicalAlias: String? = null, @@ -69,7 +72,8 @@ fun aRoomSummaryDetails( isDirect = isDirect, avatarUrl = avatarUrl, lastMessage = lastMessage, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, userDefinedNotificationMode = notificationMode, inviter = inviter, canonicalAlias = canonicalAlias, diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt index c47fdbdf64..734f7eef1f 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt @@ -113,7 +113,8 @@ fun aRoomSummaryDetails( notificationMode: RoomNotificationMode? = null, hasRoomCall: Boolean = false, isDm: Boolean = false, - unreadNotificationCount: Int = 0 + numUnreadMentions: Int = 0, + numUnreadMessages: Int = 0, ) = RoomSummaryDetails( roomId = roomId, name = name, @@ -125,5 +126,6 @@ fun aRoomSummaryDetails( userDefinedNotificationMode = notificationMode, hasRoomCall = hasRoomCall, isDm = isDm, - unreadNotificationCount = unreadNotificationCount, + numUnreadMentions = numUnreadMentions, + numUnreadMessages = numUnreadMessages, )