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,7 +174,23 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
// Video call // Video call
if (room.hasRoomCall) { OnGoingCallIcon(
room.hasRoomCall,
)
// Other indicators
NotificationIcons(
room.userDefinedNotificationMode,
room.numberOfUnreadMessages,
room.numberOfUnreadMentions,
)
}
}
@Composable
private fun OnGoingCallIcon(
hasRoomCall: Boolean,
) {
if (hasRoomCall) {
Icon( Icon(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
imageVector = CompoundIcons.VideoCallSolid, imageVector = CompoundIcons.VideoCallSolid,
@ -181,32 +198,53 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
tint = ElementTheme.colors.unreadIndicator, tint = ElementTheme.colors.unreadIndicator,
) )
} }
NotificationIcon(room)
if (room.hasUnread) {
UnreadIndicatorAtom()
}
}
} }
@Composable @Composable
private fun NotificationIcon(room: RoomListRoomSummary) { private fun RowScope.NotificationIcons(
val tint = if (room.hasUnread) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary userDefinedNotificationMode: RoomNotificationMode?,
when (room.userDefinedNotificationMode) { numberOfUnreadMessages: Int,
null, RoomNotificationMode.ALL_MESSAGES -> return numberOfUnreadMentions: Int,
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> ) {
when (userDefinedNotificationMode) {
null,
RoomNotificationMode.ALL_MESSAGES -> {
if (numberOfUnreadMentions > 0) {
Icon( Icon(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
contentDescription = null, contentDescription = null,
imageVector = CompoundIcons.Mention, imageVector = CompoundIcons.Mention,
tint = tint, tint = ElementTheme.colors.unreadIndicator,
) )
RoomNotificationMode.MUTE -> 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(
listOf(
aRoomListRoomSummary(isPlaceholder = true),
aRoomListRoomSummary(), aRoomListRoomSummary(),
aRoomListRoomSummary(lastMessage = null), 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( aRoomListRoomSummary(
name = "A very long room name that should be truncated", name = "A very long room name that should be truncated",
lastMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + 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" + " 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.", "modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
timestamp = "yesterday", timestamp = "yesterday",
hasUnread = true, numberOfUnreadMessages = 1,
),
),
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,
), ),
aRoomListRoomSummary(hasUnread = true, hasRoomCall = true),
) )
}.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,
) )