Merge pull request #2080 from element-hq/feature/bma/roomListBadges

Room list badges
This commit is contained in:
Benoit Marty 2023-12-21 16:44:10 +01:00 committed by GitHub
commit 93fabfdc56
68 changed files with 384 additions and 231 deletions

View file

@ -16,6 +16,7 @@
<w>snackbar</w> <w>snackbar</w>
<w>swipeable</w> <w>swipeable</w>
<w>textfields</w> <w>textfields</w>
<w>tombstoned</w>
</words> </words>
</dictionary> </dictionary>
</component> </component>

View file

@ -170,7 +170,7 @@ class InviteListPresenter @Inject constructor(
AvatarData( AvatarData(
id = roomId.value, id = roomId.value,
name = name, name = name,
url = avatarURLString, url = avatarUrl,
size = AvatarSize.RoomInviteItem, size = AvatarSize.RoomInviteItem,
) )

View file

@ -30,7 +30,6 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_ID_2
@ -39,6 +38,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager
@ -425,14 +425,12 @@ class InviteListPresenterTests {
postInviteRooms( postInviteRooms(
listOf( listOf(
RoomSummary.Filled( RoomSummary.Filled(
RoomSummaryDetails( aRoomSummaryDetails(
roomId = A_ROOM_ID, roomId = A_ROOM_ID,
name = A_ROOM_NAME, name = A_ROOM_NAME,
avatarURLString = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
lastMessageTimestamp = null,
unreadNotificationCount = 0,
inviter = RoomMember( inviter = RoomMember(
userId = A_USER_ID, userId = A_USER_ID,
displayName = A_USER_NAME, displayName = A_USER_NAME,
@ -454,14 +452,12 @@ class InviteListPresenterTests {
postInviteRooms( postInviteRooms(
listOf( listOf(
RoomSummary.Filled( RoomSummary.Filled(
RoomSummaryDetails( aRoomSummaryDetails(
roomId = A_ROOM_ID, roomId = A_ROOM_ID,
name = A_ROOM_NAME, name = A_ROOM_NAME,
avatarURLString = null, avatarUrl = null,
isDirect = true, isDirect = true,
lastMessage = null, lastMessage = null,
lastMessageTimestamp = null,
unreadNotificationCount = 0,
inviter = RoomMember( inviter = RoomMember(
userId = A_USER_ID, userId = A_USER_ID,
displayName = A_USER_NAME, displayName = A_USER_NAME,
@ -480,14 +476,12 @@ class InviteListPresenterTests {
} }
private fun aRoomSummary(id: RoomId = A_ROOM_ID) = RoomSummary.Filled( private fun aRoomSummary(id: RoomId = A_ROOM_ID) = RoomSummary.Filled(
RoomSummaryDetails( aRoomSummaryDetails(
roomId = id, roomId = id,
name = A_ROOM_NAME, name = A_ROOM_NAME,
avatarURLString = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
lastMessageTimestamp = null,
unreadNotificationCount = 0,
) )
) )

View file

@ -18,9 +18,6 @@ package io.element.android.features.messages.impl.forward
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -51,30 +48,3 @@ fun aForwardMessagesState(
forwardingSucceeded = forwardingSucceeded, forwardingSucceeded = forwardingSucceeded,
eventSink = {} eventSink = {}
) )
internal fun aForwardMessagesRoomList() = persistentListOf(
aRoomDetailsState(),
aRoomDetailsState(roomId = RoomId("!room2:domain"), canonicalAlias = "#element-x-room:matrix.org"),
)
fun aRoomDetailsState(
roomId: RoomId = RoomId("!room:domain"),
name: String = "roomName",
canonicalAlias: String? = null,
isDirect: Boolean = true,
avatarURLString: String? = null,
lastMessage: RoomMessage? = null,
lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 0,
inviter: RoomMember? = null,
) = RoomSummaryDetails(
roomId = roomId,
name = name,
canonicalAlias = canonicalAlias,
isDirect = isDirect,
avatarURLString = avatarURLString,
lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp,
unreadNotificationCount = unreadNotificationCount,
inviter = inviter,
)

View file

@ -23,7 +23,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -55,7 +55,7 @@ class ForwardMessagesPresenterTests {
presenter.present() presenter.present()
}.test { }.test {
skipItems(1) skipItems(1)
val summary = aRoomSummaryDetail() val summary = aRoomSummaryDetails()
presenter.onRoomSelected(listOf(summary.roomId)) presenter.onRoomSelected(listOf(summary.roomId))
val forwardingState = awaitItem() val forwardingState = awaitItem()
assertThat(forwardingState.isForwarding).isTrue() assertThat(forwardingState.isForwarding).isTrue()
@ -75,7 +75,7 @@ class ForwardMessagesPresenterTests {
// Test failed forwarding // Test failed forwarding
room.givenForwardEventResult(Result.failure(Throwable("error"))) room.givenForwardEventResult(Result.failure(Throwable("error")))
skipItems(1) skipItems(1)
val summary = aRoomSummaryDetail() val summary = aRoomSummaryDetails()
presenter.onRoomSelected(listOf(summary.roomId)) presenter.onRoomSelected(listOf(summary.roomId))
skipItems(1) skipItems(1)
val failedForwardState = awaitItem() val failedForwardState = awaitItem()

View file

@ -52,11 +52,14 @@ private fun aRoomSummary() = RoomSummary.Filled(
RoomSummaryDetails( RoomSummaryDetails(
roomId = RoomId("!roomId:domain"), roomId = RoomId("!roomId:domain"),
name = "Room", name = "Room",
avatarURLString = null, avatarUrl = null,
isDirect = false, isDirect = false,
lastMessage = null, lastMessage = null,
lastMessageTimestamp = null, userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
unreadNotificationCount = 0, canonicalAlias = null,
notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, inviter = null,
hasRoomCall = false,
numUnreadMentions = 0,
numUnreadMessages = 0,
) )
) )

View file

@ -86,7 +86,7 @@ fun EditDefaultNotificationSettingView(
if (state.roomsWithUserDefinedMode.isNotEmpty()) { if (state.roomsWithUserDefinedMode.isNotEmpty()) {
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_edit_custom_settings_section_title)) { PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_edit_custom_settings_section_title)) {
state.roomsWithUserDefinedMode.forEach { summary -> state.roomsWithUserDefinedMode.forEach { summary ->
val subtitle = when (summary.details.notificationMode) { val subtitle = when (summary.details.userDefinedNotificationMode) {
RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_notification_settings_edit_mode_all_messages) RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_notification_settings_edit_mode_all_messages)
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> {
stringResource(id = R.string.screen_notification_settings_edit_mode_mentions_and_keywords) stringResource(id = R.string.screen_notification_settings_edit_mode_mentions_and_keywords)
@ -97,7 +97,7 @@ fun EditDefaultNotificationSettingView(
val avatarData = AvatarData( val avatarData = AvatarData(
id = summary.identifier(), id = summary.identifier(),
name = summary.details.name, name = summary.details.name,
url = summary.details.avatarURLString, url = summary.details.avatarUrl,
size = AvatarSize.CustomRoomNotificationSetting, size = AvatarSize.CustomRoomNotificationSetting,
) )
ListItem( ListItem(

View file

@ -29,7 +29,7 @@ import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.awaitLastSequentialItem
import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.consumeItemsUntilPredicate
@ -72,11 +72,11 @@ class EditDefaultNotificationSettingsPresenterTests {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetail(notificationMode = RoomNotificationMode.ALL_MESSAGES)))) roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails(notificationMode = RoomNotificationMode.ALL_MESSAGES))))
val loadedState = consumeItemsUntilPredicate { state -> val loadedState = consumeItemsUntilPredicate { state ->
state.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES } state.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }
}.last() }.last()
assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.notificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
} }
} }

View file

@ -71,7 +71,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
return persistentListOf( return persistentListOf(
RoomListRoomSummary( RoomListRoomSummary(
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),
@ -80,7 +80,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
), ),
RoomListRoomSummary( RoomListRoomSummary(
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.hasOngoingCall) { 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.notificationMode) { 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

@ -146,7 +146,7 @@ class RoomListDataSource @Inject constructor(
val avatarData = AvatarData( val avatarData = AvatarData(
id = roomSummary.identifier(), id = roomSummary.identifier(),
name = roomSummary.details.name, name = roomSummary.details.name,
url = roomSummary.details.avatarURLString, url = roomSummary.details.avatarUrl,
size = AvatarSize.RoomListItem, size = AvatarSize.RoomListItem,
) )
val roomIdentifier = roomSummary.identifier() val roomIdentifier = roomSummary.identifier()
@ -154,14 +154,15 @@ class RoomListDataSource @Inject constructor(
id = roomSummary.identifier(), id = roomSummary.identifier(),
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)
}.orEmpty(), }.orEmpty(),
avatarData = avatarData, avatarData = avatarData,
notificationMode = roomSummary.details.notificationMode, userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode,
hasOngoingCall = roomSummary.details.hasOngoingCall, hasRoomCall = roomSummary.details.hasRoomCall,
) )
} }
null -> null null -> null

View file

@ -27,11 +27,22 @@ data class RoomListRoomSummary(
val id: String, val id: String,
val roomId: RoomId, val roomId: RoomId,
val name: String = "", val name: String = "",
val hasUnread: Boolean = false,
val timestamp: String? = null, val timestamp: String? = null,
val lastMessage: CharSequence? = null, val lastMessage: CharSequence? = null,
val avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem), val avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem),
val isPlaceholder: Boolean = false, val isPlaceholder: Boolean = false,
val notificationMode: RoomNotificationMode? = null, val userDefinedNotificationMode: RoomNotificationMode? = null,
val hasOngoingCall: Boolean = false, val numberOfUnreadMessages: Int = 0,
val numberOfUnreadMentions: Int = 0,
val hasRoomCall: Boolean = false,
) )
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,32 +25,83 @@ 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().copy(lastMessage = null), aRoomListRoomSummary(isPlaceholder = true),
aRoomListRoomSummary().copy(hasUnread = true, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), aRoomListRoomSummary(timestamp = null),
aRoomListRoomSummary().copy(timestamp = "88:88", notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY), aRoomListRoomSummary(lastMessage = "Last message"),
aRoomListRoomSummary().copy(timestamp = "88:88", notificationMode = RoomNotificationMode.MUTE), aRoomListRoomSummary(
aRoomListRoomSummary().copy(timestamp = "88:88", hasUnread = true),
aRoomListRoomSummary().copy(isPlaceholder = true, timestamp = "88:88"),
aRoomListRoomSummary().copy(
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,
hasOngoingCall = hasCall,
),
aRoomListRoomSummary(
name = roomNotificationMode.name,
lastMessage = "New messages" + if (hasCall) ", call" else "",
notificationMode = roomNotificationMode,
numberOfUnreadMessages = 1,
numberOfUnreadMentions = 0,
hasOngoingCall = hasCall,
),
aRoomListRoomSummary(
name = roomNotificationMode.name,
lastMessage = "New messages, mentions" + if (hasCall) ", call" else "",
notificationMode = roomNotificationMode,
numberOfUnreadMessages = 1,
numberOfUnreadMentions = 1,
hasOngoingCall = hasCall,
),
aRoomListRoomSummary(
name = roomNotificationMode.name,
lastMessage = "New mentions" + if (hasCall) ", call" else "",
notificationMode = roomNotificationMode,
numberOfUnreadMessages = 0,
numberOfUnreadMentions = 1,
hasOngoingCall = hasCall,
), ),
aRoomListRoomSummary().copy(hasUnread = true, hasOngoingCall = true),
) )
}.flatten()
}.flatten(),
).flatten()
} }
fun aRoomListRoomSummary() = RoomListRoomSummary( fun aRoomListRoomSummary(
lastMessage: String? = null,
notificationMode: RoomNotificationMode? = null,
numberOfUnreadMessages: Int = 0,
numberOfUnreadMentions: Int = 0,
timestamp: String? = "88:88",
hasOngoingCall: Boolean = false,
isPlaceholder: Boolean = false,
name: String = "Room name",
) = RoomListRoomSummary(
id = "!roomId", id = "!roomId",
roomId = RoomId("!roomId:domain"), roomId = RoomId("!roomId:domain"),
name = "Room name", name = name,
hasUnread = false, numberOfUnreadMessages = numberOfUnreadMessages,
timestamp = null, numberOfUnreadMentions = numberOfUnreadMentions,
lastMessage = "Last message", timestamp = timestamp,
lastMessage = lastMessage,
avatarData = AvatarData("!roomId", "Room name", size = AvatarSize.RoomListItem), avatarData = AvatarData("!roomId", "Room name", size = AvatarSize.RoomListItem),
isPlaceholder = false, isPlaceholder = isPlaceholder,
userDefinedNotificationMode = notificationMode,
hasRoomCall = hasOngoingCall,
) )

View file

@ -123,7 +123,7 @@ class RoomListPresenterTests {
fun `present - should start with no user and then load user with error`() = runTest { fun `present - should start with no user and then load user with error`() = runTest {
val matrixClient = FakeMatrixClient( val matrixClient = FakeMatrixClient(
userDisplayName = Result.failure(AN_EXCEPTION), userDisplayName = Result.failure(AN_EXCEPTION),
userAvatarURLString = Result.failure(AN_EXCEPTION), userAvatarUrl = Result.failure(AN_EXCEPTION),
) )
val scope = CoroutineScope(coroutineContext + SupervisorJob()) val scope = CoroutineScope(coroutineContext + SupervisorJob())
val presenter = createRoomListPresenter(client = matrixClient, coroutineScope = scope) val presenter = createRoomListPresenter(client = matrixClient, coroutineScope = scope)
@ -385,11 +385,11 @@ class RoomListPresenterTests {
notificationSettingsService.setRoomNotificationMode(A_ROOM_ID, userDefinedMode) notificationSettingsService.setRoomNotificationMode(A_ROOM_ID, userDefinedMode)
val updatedState = consumeItemsUntilPredicate { state -> val updatedState = consumeItemsUntilPredicate { state ->
state.roomList.any { it.id == A_ROOM_ID.value && it.notificationMode == userDefinedMode } state.roomList.any { it.id == A_ROOM_ID.value && it.userDefinedNotificationMode == userDefinedMode }
}.last() }.last()
val room = updatedState.roomList.find { it.id == A_ROOM_ID.value } val room = updatedState.roomList.find { it.id == A_ROOM_ID.value }
assertThat(room?.notificationMode).isEqualTo(userDefinedMode) assertThat(room?.userDefinedNotificationMode).isEqualTo(userDefinedMode)
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
scope.cancel() scope.cancel()
} }
@ -439,7 +439,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

@ -72,7 +72,7 @@ interface MatrixClient : Closeable {
*/ */
suspend fun logout(ignoreSdkError: Boolean): String? suspend fun logout(ignoreSdkError: Boolean): String?
suspend fun loadUserDisplayName(): Result<String> suspend fun loadUserDisplayName(): Result<String>
suspend fun loadUserAvatarURLString(): Result<String?> suspend fun loadUserAvatarUrl(): Result<String?>
suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?>
suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String> suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String>
fun roomMembershipObserver(): RoomMembershipObserver fun roomMembershipObserver(): RoomMembershipObserver

View file

@ -36,13 +36,15 @@ sealed interface RoomSummary {
data class RoomSummaryDetails( data class RoomSummaryDetails(
val roomId: RoomId, val roomId: RoomId,
val name: String, val name: String,
val canonicalAlias: String? = null, val canonicalAlias: String?,
val isDirect: Boolean, val isDirect: Boolean,
val avatarURLString: String?, val avatarUrl: String?,
val lastMessage: RoomMessage?, val lastMessage: RoomMessage?,
val lastMessageTimestamp: Long?, val numUnreadMessages: Int,
val unreadNotificationCount: Int, val numUnreadMentions: Int,
val inviter: RoomMember? = null, val inviter: RoomMember?,
val notificationMode: RoomNotificationMode? = null, val userDefinedNotificationMode: RoomNotificationMode?,
val hasOngoingCall: Boolean = false, val hasRoomCall: Boolean,
) ) {
val lastMessageTimestamp = lastMessage?.originServerTs
}

View file

@ -19,11 +19,11 @@ package io.element.android.libraries.matrix.api.user
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
/** /**
* Get the current user, as [MatrixUser], using [MatrixClient.loadUserAvatarURLString] * Get the current user, as [MatrixUser], using [MatrixClient.loadUserAvatarUrl]
* and [MatrixClient.loadUserDisplayName]. * and [MatrixClient.loadUserDisplayName].
*/ */
suspend fun MatrixClient.getCurrentUser(): MatrixUser { suspend fun MatrixClient.getCurrentUser(): MatrixUser {
val userAvatarUrl = loadUserAvatarURLString().getOrNull() val userAvatarUrl = loadUserAvatarUrl().getOrNull()
val userDisplayName = loadUserDisplayName().getOrNull() val userDisplayName = loadUserDisplayName().getOrNull()
return MatrixUser( return MatrixUser(
userId = sessionId, userId = sessionId,

View file

@ -412,7 +412,7 @@ class RustMatrixClient(
} }
} }
override suspend fun loadUserAvatarURLString(): Result<String?> = withContext(sessionDispatcher) { override suspend fun loadUserAvatarUrl(): Result<String?> = withContext(sessionDispatcher) {
runCatching { runCatching {
client.avatarUrl() client.avatarUrl()
} }

View file

@ -35,13 +35,13 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
name = roomInfo.name ?: roomInfo.id, name = roomInfo.name ?: roomInfo.id,
canonicalAlias = roomInfo.canonicalAlias, canonicalAlias = roomInfo.canonicalAlias,
isDirect = roomInfo.isDirect, isDirect = roomInfo.isDirect,
avatarURLString = roomInfo.avatarUrl, avatarUrl = roomInfo.avatarUrl,
unreadNotificationCount = roomInfo.notificationCount.toInt(),
lastMessage = latestRoomMessage, lastMessage = latestRoomMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs,
inviter = roomInfo.inviter?.let(RoomMemberMapper::map), inviter = roomInfo.inviter?.let(RoomMemberMapper::map),
notificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode), userDefinedNotificationMode = roomInfo.userDefinedNotificationMode?.let(RoomNotificationSettingsMapper::mapMode),
hasOngoingCall = roomInfo.hasRoomCall, hasRoomCall = roomInfo.hasRoomCall,
numUnreadMentions = roomInfo.numUnreadMentions.toInt(),
numUnreadMessages = roomInfo.numUnreadMessages.toInt(),
) )
} }
} }

View file

@ -48,7 +48,7 @@ import kotlinx.coroutines.delay
class FakeMatrixClient( class FakeMatrixClient(
override val sessionId: SessionId = A_SESSION_ID, override val sessionId: SessionId = A_SESSION_ID,
private val userDisplayName: Result<String> = Result.success(A_USER_NAME), private val userDisplayName: Result<String> = Result.success(A_USER_NAME),
private val userAvatarURLString: Result<String> = Result.success(AN_AVATAR_URL), private val userAvatarUrl: Result<String> = Result.success(AN_AVATAR_URL),
override val roomListService: RoomListService = FakeRoomListService(), override val roomListService: RoomListService = FakeRoomListService(),
override val mediaLoader: MatrixMediaLoader = FakeMediaLoader(), override val mediaLoader: MatrixMediaLoader = FakeMediaLoader(),
private val sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(), private val sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
@ -136,8 +136,8 @@ class FakeMatrixClient(
return userDisplayName return userDisplayName
} }
override suspend fun loadUserAvatarURLString(): Result<String?> { override suspend fun loadUserAvatarUrl(): Result<String?> {
return userAvatarURLString return userAvatarUrl
} }
override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> { override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> {

View file

@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.test.room
import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.message.RoomMessage import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
@ -34,42 +35,48 @@ fun aRoomSummaryFilled(
roomId: RoomId = A_ROOM_ID, roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME, name: String = A_ROOM_NAME,
isDirect: Boolean = false, isDirect: Boolean = false,
avatarURLString: String? = null, avatarUrl: String? = null,
lastMessage: RoomMessage? = aRoomMessage(), lastMessage: RoomMessage? = aRoomMessage(),
lastMessageTimestamp: Long? = null, numUnreadMentions: Int = 1,
unreadNotificationCount: Int = 2, numUnreadMessages: Int = 2,
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
) = RoomSummary.Filled( ) = RoomSummary.Filled(
aRoomSummaryDetail( aRoomSummaryDetails(
roomId = roomId, roomId = roomId,
name = name, name = name,
isDirect = isDirect, isDirect = isDirect,
avatarURLString = avatarURLString, avatarUrl = avatarUrl,
lastMessage = lastMessage, lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp, numUnreadMentions = numUnreadMentions,
unreadNotificationCount = unreadNotificationCount, numUnreadMessages = numUnreadMessages,
notificationMode = notificationMode, notificationMode = notificationMode,
) )
) )
fun aRoomSummaryDetail( fun aRoomSummaryDetails(
roomId: RoomId = A_ROOM_ID, roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME, name: String = A_ROOM_NAME,
isDirect: Boolean = false, isDirect: Boolean = false,
avatarURLString: String? = null, avatarUrl: String? = null,
lastMessage: RoomMessage? = aRoomMessage(), lastMessage: RoomMessage? = aRoomMessage(),
lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 2,
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
inviter: RoomMember? = null,
canonicalAlias: String? = null,
hasOngoingCall: Boolean = false,
numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
) = RoomSummaryDetails( ) = RoomSummaryDetails(
roomId = roomId, roomId = roomId,
name = name, name = name,
isDirect = isDirect, isDirect = isDirect,
avatarURLString = avatarURLString, avatarUrl = avatarUrl,
lastMessage = lastMessage, lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp, userDefinedNotificationMode = notificationMode,
unreadNotificationCount = unreadNotificationCount, canonicalAlias = canonicalAlias,
notificationMode = notificationMode inviter = inviter,
hasRoomCall = hasOngoingCall,
numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
) )
fun aRoomMessage( fun aRoomMessage(

View file

@ -44,6 +44,9 @@ import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
@ -60,7 +63,7 @@ fun SelectedRoom(
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
Avatar(AvatarData(roomSummary.roomId.value, roomSummary.name, roomSummary.avatarURLString, AvatarSize.SelectedRoom)) Avatar(AvatarData(roomSummary.roomId.value, roomSummary.name, roomSummary.avatarUrl, AvatarSize.SelectedRoom))
Text( Text(
text = roomSummary.name, text = roomSummary.name,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
@ -94,17 +97,33 @@ fun SelectedRoom(
@Composable @Composable
internal fun SelectedRoomPreview() = ElementPreview { internal fun SelectedRoomPreview() = ElementPreview {
SelectedRoom( SelectedRoom(
roomSummary = RoomSummaryDetails( roomSummary = aRoomSummaryDetails(),
roomId = RoomId("!room:domain"),
name = "roomName",
canonicalAlias = null,
isDirect = true,
avatarURLString = null,
lastMessage = null,
lastMessageTimestamp = null,
unreadNotificationCount = 0,
inviter = null,
),
onRoomRemoved = {}, onRoomRemoved = {},
) )
} }
fun aRoomSummaryDetails(
roomId: RoomId = RoomId("!room:domain"),
name: String = "roomName",
canonicalAlias: String? = null,
isDirect: Boolean = true,
avatarUrl: String? = null,
lastMessage: RoomMessage? = null,
inviter: RoomMember? = null,
notificationMode: RoomNotificationMode? = null,
hasOngoingCall: Boolean = false,
numUnreadMentions: Int = 0,
numUnreadMessages: Int = 0,
) = RoomSummaryDetails(
roomId = roomId,
name = name,
canonicalAlias = canonicalAlias,
isDirect = isDirect,
avatarUrl = avatarUrl,
lastMessage = lastMessage,
inviter = inviter,
userDefinedNotificationMode = notificationMode,
hasRoomCall = hasOngoingCall,
numUnreadMentions = numUnreadMentions,
numUnreadMessages = numUnreadMessages,
)

View file

@ -297,7 +297,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
operation = { operation = {
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash // myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
val myUserDisplayName = client.loadUserDisplayName().getOrNull() ?: sessionId.value val myUserDisplayName = client.loadUserDisplayName().getOrNull() ?: sessionId.value
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull() val userAvatarUrl = client.loadUserAvatarUrl().getOrNull()
MatrixUser( MatrixUser(
userId = sessionId, userId = sessionId,
displayName = myUserDisplayName, displayName = myUserDisplayName,

View file

@ -19,9 +19,8 @@ package io.element.android.libraries.roomselect.impl
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -41,7 +40,7 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
resultState = SearchBarResultState.Results(aForwardMessagesRoomList()), resultState = SearchBarResultState.Results(aForwardMessagesRoomList()),
query = "Test", query = "Test",
isSearchActive = true, isSearchActive = true,
selectedRooms = persistentListOf(aRoomDetailsState(roomId = RoomId("!room2:domain"))) selectedRooms = persistentListOf(aRoomSummaryDetails(roomId = RoomId("!room2:domain")))
), ),
// Add other states here // Add other states here
) )
@ -62,32 +61,10 @@ private fun aRoomSelectState(
) )
private fun aForwardMessagesRoomList() = persistentListOf( private fun aForwardMessagesRoomList() = persistentListOf(
aRoomDetailsState(), aRoomSummaryDetails(),
aRoomDetailsState( aRoomSummaryDetails(
roomId = RoomId("!room2:domain"), roomId = RoomId("!room2:domain"),
name = "Room with alias", name = "Room with alias",
canonicalAlias = "#alias:example.org", canonicalAlias = "#alias:example.org",
), ),
) )
private fun aRoomDetailsState(
roomId: RoomId = RoomId("!room:domain"),
name: String = "roomName",
canonicalAlias: String? = null,
isDirect: Boolean = true,
avatarURLString: String? = null,
lastMessage: RoomMessage? = null,
lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 0,
inviter: RoomMember? = null,
) = RoomSummaryDetails(
roomId = roomId,
name = name,
canonicalAlias = canonicalAlias,
isDirect = isDirect,
avatarURLString = avatarURLString,
lastMessage = lastMessage,
lastMessageTimestamp = lastMessageTimestamp,
unreadNotificationCount = unreadNotificationCount,
inviter = inviter,
)

View file

@ -222,7 +222,7 @@ private fun RoomSummaryView(
avatarData = AvatarData( avatarData = AvatarData(
id = summary.roomId.value, id = summary.roomId.value,
name = summary.name, name = summary.name,
url = summary.avatarURLString, url = summary.avatarUrl,
size = AvatarSize.RoomSelectRoomListItem, size = AvatarSize.RoomSelectRoomListItem,
), ),
) )

View file

@ -24,7 +24,7 @@ import io.element.android.libraries.roomselect.api.RoomSelectMode
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.aRoomSummaryDetail import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -73,7 +73,7 @@ class RoomSelectPresenterTests {
@Test @Test
fun `present - update query`() = runTest { fun `present - update query`() = runTest {
val roomListService = FakeRoomListService().apply { val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetail()))) postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails())))
} }
val client = FakeMatrixClient(roomListService = roomListService) val client = FakeMatrixClient(roomListService = roomListService)
val presenter = aPresenter(client = client) val presenter = aPresenter(client = client)
@ -81,7 +81,7 @@ class RoomSelectPresenterTests {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummaryDetail()))) assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummaryDetails())))
initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained")) initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained"))
assertThat(awaitItem().query).isEqualTo("string not contained") assertThat(awaitItem().query).isEqualTo("string not contained")
@ -97,7 +97,7 @@ class RoomSelectPresenterTests {
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
skipItems(1) skipItems(1)
val summary = aRoomSummaryDetail() val summary = aRoomSummaryDetails()
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary)) initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary))
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary)) assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary))

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fde0cc6b7268856b611db66b66b22c51df155f605988fc54f5c7ba18e5f1f713 oid sha256:c978bc799ab79290f89568de692d3ace219a4192ec9706fef63fe977a853f74d
size 11456 size 6046

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:29135db44db4a0150c00880080d7a7baf00476b79924b1cc8f6ef1bc396508b0
size 11398

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:155c93b3301fde110e5749ee6ef691ae145408f37143b4ea21a146e13cb8d8a0
size 12510

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:724166ef1c56802cce8fdb84eee31f8dc6b39b0bc5ebcb2fb550ca5de40df369
size 13870

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d9edd688608123f9fb51b572e8761b7009f9148105c5e3f6f96a493ff48aac8f
size 14222

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:613ac3f93dc090433c55889eda1cff2a6ab581d1f72191045312f0e3aa0bd881
size 15413

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:848ddac47db6b3f98af1285291f0f45a87ffbebe84772d81dadfc3c8fadc29eb
size 17683

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6aa2c9647f848b1d2c48b9915570106e227b2cd872becdb0a02cccc450f28740
size 16252

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0e289397b3e78a904505a3c750ce49f7e76dbf2626449004e489da194c29a457
size 17412

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bbd2feaa5fe2e2971074cf7db593824229ec84a8012ff77b8913c76b84fe4559
size 19669

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:060658e5075ca5e5242acbd8b7366d7a258011db55bfe2db8bc7a350c027bb45
size 12396

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5315627c3cae4b07d3df50054d9a689148517b8fd0a0e88b160ff3f447513999 oid sha256:cf71e045231208529eb524abce7b246a0ac6283c422f9695d560071fda7085f2
size 12653 size 12820

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cd65a0740156ea23aa9130846821f95aecdd22a4faa7b329d0b3f1ea4cfb2311
size 13476

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cd17124c11e7b4a4f27da1b005bc8da4d628f053dcd36cf0ad266afb92f03d7b
size 14999

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:28b9ccdc834d9643694f72ce1c01fb988685a7b0300912bada032be1e426b467 oid sha256:950e80e7e4be904967d35aaffe196548fa4f5ae9afdf2b86e65611ccdb14bf80
size 13539 size 22203

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:3ada109a4f7b3b3bfae402eaddcdc240fd5f08aad41e7f1e70878baa8e257f2b oid sha256:02e8617a838d2f44381de7c1432d16c848f249b671ec5c17313d975c924b6445
size 13288 size 13246

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0b18e5991be70ab16f983b929d08e566c85483e6d79f4de7a4191a800f4cae35 oid sha256:cf2bf4a68d1ed9e3540c5a21b21a9134a2704d00ca1ed53218a3483255fb98f4
size 13305 size 14533

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c978bc799ab79290f89568de692d3ace219a4192ec9706fef63fe977a853f74d oid sha256:5a96d0312ffa61a2594eae8b4d8ff1f21eae1d41cfb7c8c436458823d1d7700e
size 6046 size 16696

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:950e80e7e4be904967d35aaffe196548fa4f5ae9afdf2b86e65611ccdb14bf80 oid sha256:c5ab9f23998f5b6a3c9b2b036ab95e7db588e670e178b0c2ddefa465d3c9d05d
size 22203 size 15261

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:004de09febcc9962bdc710a258f82083ba4ebca1c2831da48db7a1c9038d2caf oid sha256:d88b81264a4d3133b6569541bbb70d4df7e145a6c521b5c88499e79cb8bc7b80
size 12154 size 16403

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:957e2d5a7b52aebcf5dd41d822f70888f3cce680ee01e7f5282d84437b6a0372
size 18723

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f7d6df9f2573241ad0096a1f93fb682713b8d50ffa4808419e246997027c5d43 oid sha256:144decfd898287f548035c89c264eb5f380084bfe69328a115b8c42cda5282f7
size 11392 size 5963

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d1401c858f16dd3c34f59781d21b8a012469462dd4e1abbb3eec033a6831e117
size 11382

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:962b168e3b424c0cf4b11da13a6ec5f784101ac5c17877091a64454c459f21fe
size 12477

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:28f595ba27af8952b02fedfebe80ac33485c7645530e36db10465aaf895ccc2b
size 13756

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d24eaa2b3213d6d915c71c24ab70a6652d7207d5d45d4f1d4962500030e4d52e
size 13837

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9ef4192190d70fe5961bca96c98b8550acfd7d016f8dfff9f8305cebec1685cb
size 14950

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:78bf65a9355ef45c49e8faa6df591bc97115e0090d9d2cb4fe75eb428c1bcf37
size 17074

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8a681f9c2d180639d2e659c4f96c7d20b7c2f60d0a4dcf16a6848328f9cb8cfb
size 15642

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:99f40548153ebc1923bd7247f7057fbab1cdbf84b8bf6ce3b080e5b29827d4fb
size 16730

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:db27d684a012495b94b1b6a92436cd32abbffa2afc8c1a6b4ccd341fbe93215f
size 18859

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2435bb9a2a9fa4841a8da49f2001120159ec69f8986eed2554479c9fbeb9866a
size 12193

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e86ea02d990c5db670a6aa3d9c17be62dad1192d687c1dc27177758b55cece3c oid sha256:7fcbdfc3e45fa0f111cc384c54c40980913e52ff755e9380fba262a4c659a5c5
size 12503 size 12715

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1dd777823ae5f3d7d64953fef64041e5dca59b67cacb0e75075c1185374cebc9
size 13286

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:851bd2a38ccaec9f93b315d3ccf943af8ab089526c352adb19de3133ced92f54
size 14727

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:584487de266a9b3e9cdefee0378023a946b309e19b09acffc5bf1a08dfc0d390 oid sha256:06df893c35c81609b46317f4de733db0bed4f5888eac189d09078ad7bd411cf0
size 13335 size 21340

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8bda8b4f6a84b37548e3926f180ddb282d220b8ff581a60e69e0e309ad3ae06a oid sha256:a85d56feef73a8c4a2497264899dbdbd0c28490f01478d4a5738a776199b5800
size 13119 size 13001

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2c17e87f046bbdd7a0300262737508cd1ffab4b54da9df7e7a7803237e070243 oid sha256:cefbb6125ef4d60e5fc8cfcd5d84344f409fcbc73ffe91b171d996d8f405bb5c
size 13032 size 14089

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:144decfd898287f548035c89c264eb5f380084bfe69328a115b8c42cda5282f7 oid sha256:4c1a87cb60d17fd959983979dd54c2dcfc07f7bc278846dcf57473ccf2e483b4
size 5963 size 16119

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:06df893c35c81609b46317f4de733db0bed4f5888eac189d09078ad7bd411cf0 oid sha256:c67906d19842935a3c2ac18e624bfda2b0909583b3239872cc1e79f4f9560723
size 21340 size 14799

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:53248c6c1d0a05b8fd08bcd35a43a6463b03b9ad808b24f59d1fa7fe5d444d4f oid sha256:4aa2b28ffcfd62de54ad1e4fc49a1c7a4721818840ca19d0ef8e96e5206d1308
size 12051 size 15888

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:05620d20cc1b9b9836a58e7ff80963692a5cc8fba63306a29e38eb7d4acd7bc9
size 17914