Use new Rust fields numUnreadMessages and numUnreadMentions, and iterate on the room badge rendering.

This commit is contained in:
Benoit Marty 2024-01-19 17:48:26 +01:00 committed by Benoit Marty
parent c14dc0b4b6
commit ca1f907ec5
12 changed files with 159 additions and 62 deletions

View file

@ -431,7 +431,6 @@ class InviteListPresenterTests {
avatarUrl = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
unreadNotificationCount = 0,
inviter = RoomMember( inviter = RoomMember(
userId = A_USER_ID, userId = A_USER_ID,
displayName = A_USER_NAME, displayName = A_USER_NAME,
@ -459,7 +458,6 @@ class InviteListPresenterTests {
avatarUrl = null, avatarUrl = null,
isDirect = true, isDirect = true,
lastMessage = null, lastMessage = null,
unreadNotificationCount = 0,
inviter = RoomMember( inviter = RoomMember(
userId = A_USER_ID, userId = A_USER_ID,
displayName = A_USER_NAME, displayName = A_USER_NAME,
@ -484,7 +482,6 @@ class InviteListPresenterTests {
avatarUrl = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
unreadNotificationCount = 0,
) )
) )

View file

@ -55,7 +55,6 @@ private fun aRoomSummary() = RoomSummary.Filled(
avatarUrl = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
unreadNotificationCount = 0,
notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
) )
) )

View file

@ -73,7 +73,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
return persistentListOf( return persistentListOf(
aRoomListRoomSummary( aRoomListRoomSummary(
name = "Room", name = "Room",
hasUnread = true, numberOfUnreadMessages = 1,
timestamp = "14:18", timestamp = "14:18",
lastMessage = "A very very very very long message which suites on two lines", lastMessage = "A very very very very long message which suites on two lines",
avatarData = AvatarData("!id", "R", size = AvatarSize.RoomListItem), avatarData = AvatarData("!id", "R", size = AvatarSize.RoomListItem),
@ -81,7 +81,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
), ),
aRoomListRoomSummary( aRoomListRoomSummary(
name = "Room#2", name = "Room#2",
hasUnread = false, numberOfUnreadMessages = 0,
timestamp = "14:16", timestamp = "14:16",
lastMessage = "A short message", lastMessage = "A short message",
avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem), avatarData = AvatarData("!id", "Z", size = AvatarSize.RoomListItem),

View file

@ -43,6 +43,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons 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.RoomListRoomSummary
import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider 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.core.extensions.orEmpty
import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAtom
import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.components.avatar.Avatar
@ -141,7 +142,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) {
Text( Text(
text = room.timestamp ?: "", text = room.timestamp ?: "",
style = ElementTheme.typography.fontBodySmMedium, style = ElementTheme.typography.fontBodySmMedium,
color = if (room.hasUnread) { color = if (room.isTimestampHighlighted()) {
ElementTheme.colors.unreadIndicator ElementTheme.colors.unreadIndicator
} else { } else {
MaterialTheme.roomListRoomMessageDate() MaterialTheme.roomListRoomMessageDate()
@ -173,40 +174,77 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
// Video call // Video call
if (room.hasRoomCall) { OnGoingCallIcon(
Icon( room.hasRoomCall,
modifier = Modifier.size(16.dp), )
imageVector = CompoundIcons.VideoCallSolid, // Other indicators
contentDescription = null, NotificationIcons(
tint = ElementTheme.colors.unreadIndicator, room.userDefinedNotificationMode,
) room.numberOfUnreadMessages,
} room.numberOfUnreadMentions,
NotificationIcon(room) )
if (room.hasUnread) {
UnreadIndicatorAtom()
}
} }
} }
@Composable @Composable
private fun NotificationIcon(room: RoomListRoomSummary) { private fun OnGoingCallIcon(
val tint = if (room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary hasRoomCall: Boolean,
when (room.userDefinedNotificationMode) { ) {
null, RoomNotificationMode.ALL_MESSAGES -> return if (hasRoomCall) {
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> Icon(
Icon( modifier = Modifier.size(16.dp),
modifier = Modifier.size(16.dp), imageVector = CompoundIcons.VideoCallSolid,
contentDescription = null, contentDescription = null,
imageVector = CompoundIcons.Mention, tint = ElementTheme.colors.unreadIndicator,
tint = tint, )
) }
RoomNotificationMode.MUTE -> }
@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( Icon(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
contentDescription = null, contentDescription = null,
imageVector = CompoundIcons.NotificationsSolidOff, imageVector = CompoundIcons.NotificationsSolidOff,
tint = tint, tint = ElementTheme.colors.iconQuaternary,
) )
if (numberOfUnreadMessages > 0 || numberOfUnreadMentions > 0) {
UnreadIndicatorAtom(color = ElementTheme.colors.iconQuaternary)
}
}
} }
} }

View file

@ -41,7 +41,8 @@ class RoomListRoomSummaryFactory @Inject constructor(
timestamp = "hh:mm", timestamp = "hh:mm",
lastMessage = "Last message for placeholder", lastMessage = "Last message for placeholder",
avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem), avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem),
hasUnread = false, numberOfUnreadMessages = 0,
numberOfUnreadMentions = 0,
userDefinedNotificationMode = null, userDefinedNotificationMode = null,
hasRoomCall = false, hasRoomCall = false,
isDm = false, isDm = false,
@ -66,7 +67,8 @@ class RoomListRoomSummaryFactory @Inject constructor(
id = roomIdentifier, id = roomIdentifier,
roomId = RoomId(roomIdentifier), roomId = RoomId(roomIdentifier),
name = roomSummary.details.name, name = roomSummary.details.name,
hasUnread = roomSummary.details.unreadNotificationCount > 0, numberOfUnreadMessages = roomSummary.details.numUnreadMessages,
numberOfUnreadMentions = roomSummary.details.numUnreadMentions,
timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp), timestamp = lastMessageTimestampFormatter.format(roomSummary.details.lastMessageTimestamp),
lastMessage = roomSummary.details.lastMessage?.let { message -> lastMessage = roomSummary.details.lastMessage?.let { message ->
roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect) roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect)

View file

@ -26,7 +26,8 @@ data class RoomListRoomSummary(
val id: String, val id: String,
val roomId: RoomId, val roomId: RoomId,
val name: String, val name: String,
val hasUnread: Boolean, val numberOfUnreadMessages: Int,
val numberOfUnreadMentions: Int,
val timestamp: String?, val timestamp: String?,
val lastMessage: CharSequence?, val lastMessage: CharSequence?,
val avatarData: AvatarData, val avatarData: AvatarData,
@ -35,3 +36,13 @@ data class RoomListRoomSummary(
val hasRoomCall: Boolean, val hasRoomCall: Boolean,
val isDm: 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
}
}

View file

@ -25,29 +25,69 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode
open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSummary> { open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSummary> {
override val values: Sequence<RoomListRoomSummary> override val values: Sequence<RoomListRoomSummary>
get() = sequenceOf( get() = sequenceOf(
aRoomListRoomSummary(), listOf(
aRoomListRoomSummary(lastMessage = null), aRoomListRoomSummary(isPlaceholder = true),
aRoomListRoomSummary(hasUnread = true, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), aRoomListRoomSummary(),
aRoomListRoomSummary(notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), aRoomListRoomSummary(lastMessage = null),
aRoomListRoomSummary(notificationMode = RoomNotificationMode.MUTE), aRoomListRoomSummary(
aRoomListRoomSummary(hasUnread = true), name = "A very long room name that should be truncated",
aRoomListRoomSummary(isPlaceholder = true), lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" +
aRoomListRoomSummary( " ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" +
name = "A very long room name that should be truncated", "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + timestamp = "yesterday",
" ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea com" + numberOfUnreadMessages = 1,
"modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", ),
timestamp = "yesterday",
hasUnread = true,
), ),
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( internal fun aRoomListRoomSummary(
id: String = "!roomId:domain", id: String = "!roomId:domain",
name: String = "Room name", name: String = "Room name",
hasUnread: Boolean = false, numberOfUnreadMessages: Int = 0,
numberOfUnreadMentions: Int = 0,
lastMessage: String? = "Last message", lastMessage: String? = "Last message",
timestamp: String? = lastMessage?.let { "88:88" }, timestamp: String? = lastMessage?.let { "88:88" },
isPlaceholder: Boolean = false, isPlaceholder: Boolean = false,
@ -59,7 +99,8 @@ internal fun aRoomListRoomSummary(
id = id, id = id,
roomId = RoomId(id), roomId = RoomId(id),
name = name, name = name,
hasUnread = hasUnread, numberOfUnreadMessages = numberOfUnreadMessages,
numberOfUnreadMentions = numberOfUnreadMentions,
timestamp = timestamp, timestamp = timestamp,
lastMessage = lastMessage, lastMessage = lastMessage,
avatarData = avatarData, avatarData = avatarData,

View file

@ -440,7 +440,8 @@ private val aRoomListRoomSummary = RoomListRoomSummary(
id = A_ROOM_ID.value, id = A_ROOM_ID.value,
roomId = A_ROOM_ID, roomId = A_ROOM_ID,
name = A_ROOM_NAME, name = A_ROOM_NAME,
hasUnread = true, numberOfUnreadMentions = 1,
numberOfUnreadMessages = 2,
timestamp = A_FORMATTED_DATE, timestamp = A_FORMATTED_DATE,
lastMessage = "", lastMessage = "",
avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem), avatarData = AvatarData(id = A_ROOM_ID.value, name = A_ROOM_NAME, size = AvatarSize.RoomListItem),

View file

@ -40,7 +40,8 @@ data class RoomSummaryDetails(
val isDirect: Boolean, val isDirect: Boolean,
val avatarUrl: String?, val avatarUrl: String?,
val lastMessage: RoomMessage?, val lastMessage: RoomMessage?,
val unreadNotificationCount: Int, val numUnreadMessages: Int,
val numUnreadMentions: Int,
val inviter: RoomMember?, val inviter: RoomMember?,
val userDefinedNotificationMode: RoomNotificationMode?, val userDefinedNotificationMode: RoomNotificationMode?,
val hasRoomCall: Boolean, val hasRoomCall: Boolean,

View file

@ -35,7 +35,8 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
canonicalAlias = roomInfo.canonicalAlias, canonicalAlias = roomInfo.canonicalAlias,
isDirect = roomInfo.isDirect, isDirect = roomInfo.isDirect,
avatarUrl = roomInfo.avatarUrl, avatarUrl = roomInfo.avatarUrl,
unreadNotificationCount = roomInfo.notificationCount.toInt(), numUnreadMentions = roomInfo.numUnreadMentions.toInt(),
numUnreadMessages = roomInfo.numUnreadMessages.toInt(),
lastMessage = latestRoomMessage, lastMessage = latestRoomMessage,
inviter = roomInfo.inviter?.let(RoomMemberMapper::map), inviter = roomInfo.inviter?.let(RoomMemberMapper::map),
userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode),

View file

@ -37,7 +37,8 @@ fun aRoomSummaryFilled(
isDirect: Boolean = false, isDirect: Boolean = false,
avatarUrl: String? = null, avatarUrl: String? = null,
lastMessage: RoomMessage? = aRoomMessage(), lastMessage: RoomMessage? = aRoomMessage(),
unreadNotificationCount: Int = 2, numUnreadMentions: Int = 1,
numUnreadMessages: Int = 2,
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
) = RoomSummary.Filled( ) = RoomSummary.Filled(
aRoomSummaryDetails( aRoomSummaryDetails(
@ -46,7 +47,8 @@ fun aRoomSummaryFilled(
isDirect = isDirect, isDirect = isDirect,
avatarUrl = avatarUrl, avatarUrl = avatarUrl,
lastMessage = lastMessage, lastMessage = lastMessage,
unreadNotificationCount = unreadNotificationCount, numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
notificationMode = notificationMode, notificationMode = notificationMode,
) )
) )
@ -57,7 +59,8 @@ fun aRoomSummaryDetails(
isDirect: Boolean = false, isDirect: Boolean = false,
avatarUrl: String? = null, avatarUrl: String? = null,
lastMessage: RoomMessage? = aRoomMessage(), lastMessage: RoomMessage? = aRoomMessage(),
unreadNotificationCount: Int = 2, numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
inviter: RoomMember? = null, inviter: RoomMember? = null,
canonicalAlias: String? = null, canonicalAlias: String? = null,
@ -69,7 +72,8 @@ fun aRoomSummaryDetails(
isDirect = isDirect, isDirect = isDirect,
avatarUrl = avatarUrl, avatarUrl = avatarUrl,
lastMessage = lastMessage, lastMessage = lastMessage,
unreadNotificationCount = unreadNotificationCount, numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
userDefinedNotificationMode = notificationMode, userDefinedNotificationMode = notificationMode,
inviter = inviter, inviter = inviter,
canonicalAlias = canonicalAlias, canonicalAlias = canonicalAlias,

View file

@ -113,7 +113,8 @@ fun aRoomSummaryDetails(
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
hasRoomCall: Boolean = false, hasRoomCall: Boolean = false,
isDm: Boolean = false, isDm: Boolean = false,
unreadNotificationCount: Int = 0 numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
) = RoomSummaryDetails( ) = RoomSummaryDetails(
roomId = roomId, roomId = roomId,
name = name, name = name,
@ -125,5 +126,6 @@ fun aRoomSummaryDetails(
userDefinedNotificationMode = notificationMode, userDefinedNotificationMode = notificationMode,
hasRoomCall = hasRoomCall, hasRoomCall = hasRoomCall,
isDm = isDm, isDm = isDm,
unreadNotificationCount = unreadNotificationCount, numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
) )