Browse Source

Update dependency org.matrix.rustcomponents:sdk-android to v0.2.31 (#3145)

* Update dependency org.matrix.rustcomponents:sdk-android to v0.2.31

* Use new Rust client side sorting API

* Make `RoomListEntriesUpdate.describe()` an extension function

* Remove `RoomListSummary.Filled` and `RoomListSummary.Empty`

* Fix icon sizes to pass the lint checks

* Update screenshots

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorge Martín <jorgem@element.io>
Co-authored-by: ElementBot <benoitm+elementbot@element.io>
pull/3154/head
renovate[bot] 2 months ago committed by GitHub
parent
commit
68efc918ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. BIN
      appicon/enterprise/src/main/res/mipmap-hdpi/ic_launcher_background_enterprise.webp
  2. BIN
      appicon/enterprise/src/main/res/mipmap-mdpi/ic_launcher_background_enterprise.webp
  3. BIN
      appicon/enterprise/src/main/res/mipmap-xhdpi/ic_launcher_background_enterprise.webp
  4. BIN
      appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_background_enterprise.webp
  5. BIN
      appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_enterprise.webp
  6. BIN
      appicon/enterprise/src/main/res/mipmap-xxxhdpi/ic_launcher_background_enterprise.webp
  7. 6
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt
  8. 14
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt
  9. 2
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt
  10. 17
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt
  11. 10
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt
  12. 9
      features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt
  13. 1
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt
  14. 13
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt
  15. 24
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt
  16. 12
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt
  17. 36
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt
  18. 2
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchDataSource.kt
  19. 52
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt
  20. 8
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchPresenterTest.kt
  21. 2
      gradle/libs.versions.toml
  22. 6
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt
  23. 14
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt
  24. 2
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt
  25. 57
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListEntriesUpdateExt.kt
  26. 5
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt
  27. 14
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt
  28. 6
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt
  29. 43
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt
  30. 18
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt
  31. 45
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt
  32. 123
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt
  33. 31
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt
  34. 7
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt
  35. 8
      libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt
  36. 10
      libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt
  37. 4
      libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomSummaryExtension.kt
  38. 4
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt
  39. 4
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt
  40. 5
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt
  41. 6
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt
  42. 6
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt
  43. 14
      libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt
  44. 11
      libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt
  45. 4
      tests/uitests/src/test/snapshots/images/appicon.enterprise_Icon_en.png
  46. 4
      tests/uitests/src/test/snapshots/images/appicon.enterprise_RoundIcon_en.png

BIN
appicon/enterprise/src/main/res/mipmap-hdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
appicon/enterprise/src/main/res/mipmap-mdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxhdpi/ic_launcher_foreground_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
appicon/enterprise/src/main/res/mipmap-xxxhdpi/ic_launcher_background_enterprise.webp

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 14 KiB

6
features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt

@ -25,7 +25,7 @@ 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.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.aRoomSummaryDetails import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
@ -64,7 +64,7 @@ class ForwardMessagesPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
skipItems(1) skipItems(1)
val summary = aRoomSummaryDetails() val summary = aRoomSummary()
presenter.onRoomSelected(listOf(summary.roomId)) presenter.onRoomSelected(listOf(summary.roomId))
val forwardingState = awaitItem() val forwardingState = awaitItem()
assertThat(forwardingState.forwardAction.isLoading()).isTrue() assertThat(forwardingState.forwardAction.isLoading()).isTrue()
@ -88,7 +88,7 @@ class ForwardMessagesPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
skipItems(1) skipItems(1)
val summary = aRoomSummaryDetails() val summary = aRoomSummary()
presenter.onRoomSelected(listOf(summary.roomId)) presenter.onRoomSelected(listOf(summary.roomId))
skipItems(1) skipItems(1)
val failedForwardState = awaitItem() val failedForwardState = awaitItem()

14
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingPresenter.kt

@ -66,7 +66,7 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
val changeNotificationSettingAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) } val changeNotificationSettingAction: MutableState<AsyncAction<Unit>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
val roomsWithUserDefinedMode: MutableState<List<RoomSummary.Filled>> = remember { val roomsWithUserDefinedMode: MutableState<List<RoomSummary>> = remember {
mutableStateOf(listOf()) mutableStateOf(listOf())
} }
@ -115,7 +115,7 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
.launchIn(this) .launchIn(this)
} }
private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState<List<RoomSummary.Filled>>) { private fun CoroutineScope.observeRoomSummaries(roomsWithUserDefinedMode: MutableState<List<RoomSummary>>) {
roomListService.allRooms roomListService.allRooms
.summaries .summaries
.onEach { .onEach {
@ -126,18 +126,18 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
private fun CoroutineScope.updateRoomsWithUserDefinedMode( private fun CoroutineScope.updateRoomsWithUserDefinedMode(
summaries: List<RoomSummary>, summaries: List<RoomSummary>,
roomsWithUserDefinedMode: MutableState<List<RoomSummary.Filled>> roomsWithUserDefinedMode: MutableState<List<RoomSummary>>
) = launch { ) = launch {
val roomWithUserDefinedRules: Set<String> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrThrow().toSet() val roomWithUserDefinedRules: Set<String> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrThrow().toSet()
val sortedSummaries = summaries val sortedSummaries = summaries
.filterIsInstance<RoomSummary.Filled>() .filterIsInstance<RoomSummary>()
.filter { .filter {
val room = matrixClient.getRoom(it.details.roomId) ?: return@filter false val room = matrixClient.getRoom(it.roomId) ?: return@filter false
roomWithUserDefinedRules.contains(it.identifier()) && isOneToOne == room.isOneToOne roomWithUserDefinedRules.contains(it.roomId.value) && isOneToOne == room.isOneToOne
} }
// locale sensitive sorting // locale sensitive sorting
.sortedWith(compareBy(Collator.getInstance()) { it.details.name }) .sortedWith(compareBy(Collator.getInstance()) { it.name })
roomsWithUserDefinedMode.value = sortedSummaries roomsWithUserDefinedMode.value = sortedSummaries
} }

2
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingState.kt

@ -24,7 +24,7 @@ import kotlinx.collections.immutable.ImmutableList
data class EditDefaultNotificationSettingState( data class EditDefaultNotificationSettingState(
val isOneToOne: Boolean, val isOneToOne: Boolean,
val mode: RoomNotificationMode?, val mode: RoomNotificationMode?,
val roomsWithUserDefinedMode: ImmutableList<RoomSummary.Filled>, val roomsWithUserDefinedMode: ImmutableList<RoomSummary>,
val changeNotificationSettingAction: AsyncAction<Unit>, val changeNotificationSettingAction: AsyncAction<Unit>,
val displayMentionsOnlyDisclaimer: Boolean, val displayMentionsOnlyDisclaimer: Boolean,
val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit, val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit,

17
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingStateProvider.kt

@ -20,7 +20,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
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.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
@ -53,13 +52,11 @@ private fun anEditDefaultNotificationSettingsState(
private fun aRoomSummary( private fun aRoomSummary(
name: String?, name: String?,
) = RoomSummary.Filled( ) = aRoomSummaryDetails(
aRoomSummaryDetails( roomId = RoomId("!roomId:domain"),
roomId = RoomId("!roomId:domain"), name = name,
name = name, avatarUrl = null,
avatarUrl = null, isDirect = false,
isDirect = false, lastMessage = null,
lastMessage = null, notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
notificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
)
) )

10
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/edit/EditDefaultNotificationSettingView.kt

@ -89,7 +89,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.userDefinedNotificationMode) { val subtitle = when (summary.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)
@ -99,7 +99,7 @@ fun EditDefaultNotificationSettingView(
} }
ListItem( ListItem(
headlineContent = { headlineContent = {
val roomName = summary.details.name val roomName = summary.name
Text( Text(
text = roomName ?: stringResource(id = CommonStrings.common_no_room_name), text = roomName ?: stringResource(id = CommonStrings.common_no_room_name),
fontStyle = FontStyle.Italic.takeIf { roomName == null } fontStyle = FontStyle.Italic.takeIf { roomName == null }
@ -110,14 +110,14 @@ fun EditDefaultNotificationSettingView(
}, },
leadingContent = ListItemContent.Custom { leadingContent = ListItemContent.Custom {
CompositeAvatar( CompositeAvatar(
avatarData = summary.details.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting), avatarData = summary.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting),
heroes = summary.details.heroes.map { user -> heroes = summary.heroes.map { user ->
user.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting) user.getAvatarData(size = AvatarSize.CustomRoomNotificationSetting)
}.toPersistentList() }.toPersistentList()
) )
}, },
onClick = { onClick = {
openRoomNotificationSettings(summary.details.roomId) openRoomNotificationSettings(summary.roomId)
} }
) )
} }

9
features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/notifications/EditDefaultNotificationSettingsPresenterTest.kt

@ -23,13 +23,12 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents
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.roomlist.RoomSummary
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_THROWABLE 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.aRoomSummaryDetails import io.element.android.libraries.matrix.test.room.aRoomSummary
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 +71,11 @@ class EditDefaultNotificationSettingsPresenterTest {
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
roomListService.postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails(notificationMode = RoomNotificationMode.ALL_MESSAGES)))) roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = RoomNotificationMode.ALL_MESSAGES)))
val loadedState = consumeItemsUntilPredicate { state -> val loadedState = consumeItemsUntilPredicate { state ->
state.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES } state.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }
}.last() }.last()
assertThat(loadedState.roomsWithUserDefinedMode.any { it.details.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue() assertThat(loadedState.roomsWithUserDefinedMode.any { it.userDefinedNotificationMode == RoomNotificationMode.ALL_MESSAGES }).isTrue()
} }
} }

1
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt

@ -20,7 +20,6 @@ import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
sealed interface RoomListEvents { sealed interface RoomListEvents {
data class UpdateVisibleRange(val range: IntRange) : RoomListEvents
data object DismissRequestVerificationPrompt : RoomListEvents data object DismissRequestVerificationPrompt : RoomListEvents
data object DismissRecoveryKeyPrompt : RoomListEvents data object DismissRecoveryKeyPrompt : RoomListEvents
data object ToggleSearchResults : RoomListEvents data object ToggleSearchResults : RoomListEvents

13
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt

@ -78,8 +78,6 @@ import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
private const val EXTENDED_RANGE_SIZE = 40
class RoomListPresenter @Inject constructor( class RoomListPresenter @Inject constructor(
private val client: MatrixClient, private val client: MatrixClient,
private val networkMonitor: NetworkMonitor, private val networkMonitor: NetworkMonitor,
@ -124,7 +122,6 @@ class RoomListPresenter @Inject constructor(
fun handleEvents(event: RoomListEvents) { fun handleEvents(event: RoomListEvents) {
when (event) { when (event) {
is RoomListEvents.UpdateVisibleRange -> updateVisibleRange(event.range)
RoomListEvents.DismissRequestVerificationPrompt -> securityBannerDismissed = true RoomListEvents.DismissRequestVerificationPrompt -> securityBannerDismissed = true
RoomListEvents.DismissRecoveryKeyPrompt -> securityBannerDismissed = true RoomListEvents.DismissRecoveryKeyPrompt -> securityBannerDismissed = true
RoomListEvents.ToggleSearchResults -> searchState.eventSink(RoomListSearchEvents.ToggleSearchVisibility) RoomListEvents.ToggleSearchResults -> searchState.eventSink(RoomListSearchEvents.ToggleSearchVisibility)
@ -286,16 +283,6 @@ class RoomListPresenter @Inject constructor(
} }
} }
} }
private fun updateVisibleRange(range: IntRange) {
if (range.isEmpty()) return
val midExtendedRangeSize = EXTENDED_RANGE_SIZE / 2
val extendedRangeStart = (range.first - midExtendedRangeSize).coerceAtLeast(0)
// Safe to give bigger size than room list
val extendedRangeEnd = range.last + midExtendedRangeSize
val extendedRange = IntRange(extendedRangeStart, extendedRangeEnd)
client.roomListService.updateAllRoomsVisibleRange(extendedRange)
}
} }
@VisibleForTesting @VisibleForTesting

24
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListContentView.kt

@ -30,17 +30,11 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
@ -171,25 +165,9 @@ private fun RoomsViewList(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val visibleRange by remember {
derivedStateOf {
val layoutInfo = lazyListState.layoutInfo
val firstItemIndex = layoutInfo.visibleItemsInfo.firstOrNull()?.index ?: 0
val size = layoutInfo.visibleItemsInfo.size
firstItemIndex until firstItemIndex + size
}
}
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
eventSink(RoomListEvents.UpdateVisibleRange(visibleRange))
return super.onPostFling(consumed, available)
}
}
}
LazyColumn( LazyColumn(
state = lazyListState, state = lazyListState,
modifier = modifier.nestedScroll(nestedScrollConnection), modifier = modifier,
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80 // FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80
contentPadding = PaddingValues(bottom = 80.dp) contentPadding = PaddingValues(bottom = 80.dp)
) { ) {

12
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt

@ -54,7 +54,7 @@ class RoomListDataSource @Inject constructor(
private val lock = Mutex() private val lock = Mutex()
private val diffCache = MutableListDiffCache<RoomListRoomSummary>() private val diffCache = MutableListDiffCache<RoomListRoomSummary>()
private val diffCacheUpdater = DiffCacheUpdater<RoomSummary, RoomListRoomSummary>(diffCache = diffCache, detectMoves = true) { old, new -> private val diffCacheUpdater = DiffCacheUpdater<RoomSummary, RoomListRoomSummary>(diffCache = diffCache, detectMoves = true) { old, new ->
old?.identifier() == new?.identifier() old?.roomId == new?.roomId
} }
fun launchIn(coroutineScope: CoroutineScope) { fun launchIn(coroutineScope: CoroutineScope) {
@ -96,12 +96,8 @@ class RoomListDataSource @Inject constructor(
} }
private fun buildAndCacheItem(roomSummaries: List<RoomSummary>, index: Int): RoomListRoomSummary? { private fun buildAndCacheItem(roomSummaries: List<RoomSummary>, index: Int): RoomListRoomSummary? {
val roomListRoomSummary = when (val roomSummary = roomSummaries.getOrNull(index)) { val roomListSummary = roomSummaries.getOrNull(index)?.let { roomListRoomSummaryFactory.create(it) }
is RoomSummary.Empty -> RoomListRoomSummaryFactory.createPlaceholder(roomSummary.identifier) diffCache[index] = roomListSummary
is RoomSummary.Filled -> roomListRoomSummaryFactory.create(roomSummary) return roomListSummary
null -> null
}
diffCache[index] = roomListRoomSummary
return roomListRoomSummary
} }
} }

36
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListRoomSummaryFactory.kt

@ -20,16 +20,12 @@ import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType import io.element.android.features.roomlist.impl.model.RoomSummaryDisplayType
import io.element.android.libraries.core.extensions.orEmpty import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.CurrentUserMembership
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.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.matrix.ui.model.toInviteSender import io.element.android.libraries.matrix.ui.model.toInviteSender
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject import javax.inject.Inject
@ -37,37 +33,7 @@ class RoomListRoomSummaryFactory @Inject constructor(
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter, private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
private val roomLastMessageFormatter: RoomLastMessageFormatter, private val roomLastMessageFormatter: RoomLastMessageFormatter,
) { ) {
companion object { fun create(details: RoomSummary): RoomListRoomSummary {
fun createPlaceholder(id: String): RoomListRoomSummary {
return RoomListRoomSummary(
id = id,
roomId = RoomId(id),
displayType = RoomSummaryDisplayType.PLACEHOLDER,
name = "Short name",
timestamp = "hh:mm",
lastMessage = "Last message for placeholder",
avatarData = AvatarData(id, "S", size = AvatarSize.RoomListItem),
numberOfUnreadMessages = 0,
numberOfUnreadMentions = 0,
numberOfUnreadNotifications = 0,
isMarkedUnread = false,
userDefinedNotificationMode = null,
hasRoomCall = false,
isDirect = false,
isFavorite = false,
inviteSender = null,
isDm = false,
canonicalAlias = null,
heroes = persistentListOf(),
)
}
}
fun create(roomSummary: RoomSummary.Filled): RoomListRoomSummary {
return create(roomSummary.details)
}
private fun create(details: RoomSummaryDetails): RoomListRoomSummary {
val avatarData = details.getAvatarData(size = AvatarSize.RoomListItem) val avatarData = details.getAvatarData(size = AvatarSize.RoomListItem)
return RoomListRoomSummary( return RoomListRoomSummary(
id = details.roomId.value, id = details.roomId.value,

2
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchDataSource.kt

@ -22,7 +22,6 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.roomlist.RoomList import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
@ -48,7 +47,6 @@ class RoomListSearchDataSource @Inject constructor(
val roomSummaries: Flow<PersistentList<RoomListRoomSummary>> = roomList.filteredSummaries val roomSummaries: Flow<PersistentList<RoomListRoomSummary>> = roomList.filteredSummaries
.map { roomSummaries -> .map { roomSummaries ->
roomSummaries roomSummaries
.filterIsInstance<RoomSummary.Filled>()
.map(roomSummaryFactory::create) .map(roomSummaryFactory::create)
.toPersistentList() .toPersistentList()
} }

52
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt

@ -68,7 +68,7 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
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.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
@ -183,7 +183,7 @@ class RoomListPresenterTest {
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
roomListService.postAllRooms( roomListService.postAllRooms(
listOf( listOf(
aRoomSummaryFilled( aRoomSummary(
numUnreadMentions = 1, numUnreadMentions = 1,
numUnreadMessages = 2, numUnreadMessages = 2,
) )
@ -203,48 +203,6 @@ class RoomListPresenterTest {
} }
} }
@Test
fun `present - update visible range`() = runTest {
val roomListService = FakeRoomListService()
val matrixClient = FakeMatrixClient(
roomListService = roomListService
)
val scope = CoroutineScope(coroutineContext + SupervisorJob())
val presenter = createRoomListPresenter(client = matrixClient, coroutineScope = scope)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
roomListService.postAllRooms(listOf(aRoomSummaryFilled()))
val loadedState = awaitItem()
// check initial value
assertThat(roomListService.latestSlidingSyncRange).isNull()
// Test empty range
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(1, 0)))
assertThat(roomListService.latestSlidingSyncRange).isNull()
// Update visible range and check that range is transmitted to the SDK after computation
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(0, 0)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(0, 20))
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(0, 1)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(0, 21))
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(19, 29)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(0, 49))
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(49, 59)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(29, 79))
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(149, 159)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(129, 179))
loadedState.eventSink.invoke(RoomListEvents.UpdateVisibleRange(IntRange(149, 259)))
assertThat(roomListService.latestSlidingSyncRange)
.isEqualTo(IntRange(129, 279))
cancelAndIgnoreRemainingEvents()
scope.cancel()
}
}
@Test @Test
fun `present - handle DismissRequestVerificationPrompt`() = runTest { fun `present - handle DismissRequestVerificationPrompt`() = runTest {
val scope = CoroutineScope(context = coroutineContext + SupervisorJob()) val scope = CoroutineScope(context = coroutineContext + SupervisorJob())
@ -449,7 +407,7 @@ class RoomListPresenterTest {
val notificationSettingsService = FakeNotificationSettingsService() val notificationSettingsService = FakeNotificationSettingsService()
val roomListService = FakeRoomListService() val roomListService = FakeRoomListService()
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
roomListService.postAllRooms(listOf(aRoomSummaryFilled(notificationMode = userDefinedMode))) roomListService.postAllRooms(listOf(aRoomSummary(notificationMode = userDefinedMode)))
val matrixClient = FakeMatrixClient( val matrixClient = FakeMatrixClient(
roomListService = roomListService, roomListService = roomListService,
notificationSettingsService = notificationSettingsService notificationSettingsService = notificationSettingsService
@ -594,7 +552,7 @@ class RoomListPresenterTest {
val matrixClient = FakeMatrixClient( val matrixClient = FakeMatrixClient(
roomListService = roomListService, roomListService = roomListService,
) )
val roomSummary = aRoomSummaryFilled( val roomSummary = aRoomSummary(
currentUserMembership = CurrentUserMembership.INVITED currentUserMembership = CurrentUserMembership.INVITED
) )
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1)) roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
@ -610,7 +568,7 @@ class RoomListPresenterTest {
}.last() }.last()
val roomListRoomSummary = state.contentAsRooms().summaries.first { val roomListRoomSummary = state.contentAsRooms().summaries.first {
it.id == roomSummary.identifier() it.id == roomSummary.roomId.value
} }
state.eventSink(RoomListEvents.AcceptInvite(roomListRoomSummary)) state.eventSink(RoomListEvents.AcceptInvite(roomListRoomSummary))
state.eventSink(RoomListEvents.DeclineInvite(roomListRoomSummary)) state.eventSink(RoomListEvents.DeclineInvite(roomListRoomSummary))

8
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/search/RoomListSearchPresenterTest.kt

@ -28,8 +28,7 @@ import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
@ -117,10 +116,7 @@ class RoomListSearchPresenterTest {
assertThat(state.results).isEmpty() assertThat(state.results).isEmpty()
} }
roomListService.postAllRooms( roomListService.postAllRooms(
listOf( listOf(aRoomSummary())
RoomSummary.Empty("1"),
aRoomSummaryFilled()
)
) )
awaitItem().let { state -> awaitItem().let { state ->
assertThat(state.results).hasSize(1) assertThat(state.results).hasSize(1)

2
gradle/libs.versions.toml

@ -162,7 +162,7 @@ jsoup = "org.jsoup:jsoup:1.17.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0"
timber = "com.jakewharton.timber:timber:5.0.1" timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.30" matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.31"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }

6
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListService.kt

@ -59,12 +59,6 @@ interface RoomListService {
*/ */
val allRooms: DynamicRoomList val allRooms: DynamicRoomList
/**
* Will set the visible range of all rooms.
* This is useful to load more data when the user scrolls down.
*/
fun updateAllRoomsVisibleRange(range: IntRange)
/** /**
* The sync indicator as a flow. * The sync indicator as a flow.
*/ */

14
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomSummary.kt

@ -24,19 +24,7 @@ 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.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
sealed interface RoomSummary { data class RoomSummary(
data class Empty(val identifier: String) : RoomSummary
data class Filled(val details: RoomSummaryDetails) : RoomSummary
fun identifier(): String {
return when (this) {
is Empty -> identifier
is Filled -> details.roomId.value
}
}
}
data class RoomSummaryDetails(
val roomId: RoomId, val roomId: RoomId,
val name: String?, val name: String?,
val canonicalAlias: RoomAlias?, val canonicalAlias: RoomAlias?,

2
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt

@ -311,7 +311,7 @@ class RustMatrixClient(
withTimeout(timeout) { withTimeout(timeout) {
roomListService.allRooms.summaries roomListService.allRooms.summaries
.filter { roomSummaries -> .filter { roomSummaries ->
roomSummaries.map { it.identifier() }.contains(roomId.value) roomSummaries.map { it.roomId }.contains(roomId)
} }
.first() .first()
} }

57
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListEntriesUpdateExt.kt

@ -0,0 +1,57 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.matrix.impl.roomlist
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
internal fun RoomListEntriesUpdate.describe(): String {
return when (this) {
is RoomListEntriesUpdate.Set -> {
"Set #$index to '${value.displayName()}'"
}
is RoomListEntriesUpdate.Append -> {
"Append ${values.map { "'" + it.displayName() + "'" }}"
}
is RoomListEntriesUpdate.PushBack -> {
"PushBack '${value.displayName()}'"
}
is RoomListEntriesUpdate.PushFront -> {
"PushFront '${value.displayName()}'"
}
is RoomListEntriesUpdate.Insert -> {
"Insert at #$index: '${value.displayName()}'"
}
is RoomListEntriesUpdate.Remove -> {
"Remove #$index"
}
is RoomListEntriesUpdate.Reset -> {
"Reset all to ${values.map { "'" + it.displayName() + "'" }}"
}
RoomListEntriesUpdate.PopBack -> {
"PopBack"
}
RoomListEntriesUpdate.PopFront -> {
"PopFront"
}
RoomListEntriesUpdate.Clear -> {
"Clear"
}
is RoomListEntriesUpdate.Truncate -> {
"Truncate to $length items"
}
}
}

5
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListExtensions.kt

@ -76,7 +76,7 @@ internal fun RoomListInterface.entriesFlow(
} }
} }
val result = entriesWithDynamicAdapters(pageSize.toUInt(), listener) val result = entriesWithDynamicAdapters(pageSize.toUInt(), listener)
val controller = result.controller val controller = result.controller()
controller.setFilter(initialFilterKind) controller.setFilter(initialFilterKind)
roomListDynamicEvents.onEach { controllerEvents -> roomListDynamicEvents.onEach { controllerEvents ->
when (controllerEvents) { when (controllerEvents) {
@ -92,7 +92,8 @@ internal fun RoomListInterface.entriesFlow(
} }
}.launchIn(this) }.launchIn(this)
awaitClose { awaitClose {
result.entriesStream.cancelAndDestroy() result.entriesStream().cancelAndDestroy()
controller.destroy()
result.destroy() result.destroy()
} }
}.catch { }.catch {

14
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilter.kt

@ -26,21 +26,19 @@ val RoomListFilter.predicate
is RoomListFilter.Any -> { _: RoomSummary -> true } is RoomListFilter.Any -> { _: RoomSummary -> true }
RoomListFilter.None -> { _: RoomSummary -> false } RoomListFilter.None -> { _: RoomSummary -> false }
RoomListFilter.Category.Group -> { roomSummary: RoomSummary -> RoomListFilter.Category.Group -> { roomSummary: RoomSummary ->
roomSummary is RoomSummary.Filled && !roomSummary.details.isDirect && !roomSummary.isInvited() !roomSummary.isDirect && !roomSummary.isInvited()
} }
RoomListFilter.Category.People -> { roomSummary: RoomSummary -> RoomListFilter.Category.People -> { roomSummary: RoomSummary ->
roomSummary is RoomSummary.Filled && roomSummary.details.isDirect && !roomSummary.isInvited() roomSummary.isDirect && !roomSummary.isInvited()
} }
RoomListFilter.Favorite -> { roomSummary: RoomSummary -> RoomListFilter.Favorite -> { roomSummary: RoomSummary ->
roomSummary is RoomSummary.Filled && roomSummary.details.isFavorite && !roomSummary.isInvited() roomSummary.isFavorite && !roomSummary.isInvited()
} }
RoomListFilter.Unread -> { roomSummary: RoomSummary -> RoomListFilter.Unread -> { roomSummary: RoomSummary ->
roomSummary is RoomSummary.Filled && !roomSummary.isInvited() && (roomSummary.numUnreadNotifications > 0 || roomSummary.isMarkedUnread)
!roomSummary.isInvited() &&
(roomSummary.details.numUnreadNotifications > 0 || roomSummary.details.isMarkedUnread)
} }
is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary -> is RoomListFilter.NormalizedMatchRoomName -> { roomSummary: RoomSummary ->
roomSummary is RoomSummary.Filled && roomSummary.details.name.orEmpty().contains(pattern, ignoreCase = true) roomSummary.name.orEmpty().contains(pattern, ignoreCase = true)
} }
RoomListFilter.Invite -> { roomSummary: RoomSummary -> RoomListFilter.Invite -> { roomSummary: RoomSummary ->
roomSummary.isInvited() roomSummary.isInvited()
@ -61,4 +59,4 @@ fun List<RoomSummary>.filter(filter: RoomListFilter): List<RoomSummary> {
} }
} }
private fun RoomSummary.isInvited() = this is RoomSummary.Filled && this.details.currentUserMembership == CurrentUserMembership.INVITED private fun RoomSummary.isInvited() = currentUserMembership == CurrentUserMembership.INVITED

6
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt

@ -18,7 +18,7 @@ package io.element.android.libraries.matrix.impl.roomlist
import io.element.android.libraries.matrix.api.core.RoomAlias import io.element.android.libraries.matrix.api.core.RoomAlias
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.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.impl.notificationsettings.RoomNotificationSettingsMapper import io.element.android.libraries.matrix.impl.notificationsettings.RoomNotificationSettingsMapper
import io.element.android.libraries.matrix.impl.room.elementHeroes import io.element.android.libraries.matrix.impl.room.elementHeroes
import io.element.android.libraries.matrix.impl.room.map import io.element.android.libraries.matrix.impl.room.map
@ -28,12 +28,12 @@ import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.use
class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) {
suspend fun create(roomListItem: RoomListItem): RoomSummaryDetails { suspend fun create(roomListItem: RoomListItem): RoomSummary {
val roomInfo = roomListItem.roomInfo() val roomInfo = roomListItem.roomInfo()
val latestRoomMessage = roomListItem.latestEvent()?.use { val latestRoomMessage = roomListItem.latestEvent()?.use {
roomMessageFactory.create(it) roomMessageFactory.create(it)
} }
return RoomSummaryDetails( return RoomSummary(
roomId = RoomId(roomInfo.id), roomId = RoomId(roomInfo.id),
name = roomInfo.displayName, name = roomInfo.displayName,
canonicalAlias = roomInfo.canonicalAlias?.let(::RoomAlias), canonicalAlias = roomInfo.canonicalAlias?.let(::RoomAlias),

43
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessor.kt

@ -22,11 +22,10 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
import org.matrix.rustcomponents.sdk.RoomListEntry import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.RoomListServiceInterface import org.matrix.rustcomponents.sdk.RoomListServiceInterface
import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.use
import timber.log.Timber import timber.log.Timber
import java.util.UUID
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class RoomSummaryListProcessor( class RoomSummaryListProcessor(
@ -50,15 +49,17 @@ class RoomSummaryListProcessor(
suspend fun rebuildRoomSummaries() { suspend fun rebuildRoomSummaries() {
updateRoomSummaries { updateRoomSummaries {
forEachIndexed { i, summary -> forEachIndexed { i, summary ->
this[i] = when (summary) { val result = buildAndCacheRoomSummaryForIdentifier(summary.roomId.value)
is RoomSummary.Empty -> summary if (result != null) {
is RoomSummary.Filled -> buildAndCacheRoomSummaryForIdentifier(summary.identifier()) this[i] = result
} }
} }
} }
} }
private suspend fun MutableList<RoomSummary>.applyUpdate(update: RoomListEntriesUpdate) { private suspend fun MutableList<RoomSummary>.applyUpdate(update: RoomListEntriesUpdate) {
// Remove this comment to debug changes in the room list
// Timber.d("Apply room list update: ${update.describe()}")
when (update) { when (update) {
is RoomListEntriesUpdate.Append -> { is RoomListEntriesUpdate.Append -> {
val roomSummaries = update.values.map { val roomSummaries = update.values.map {
@ -104,27 +105,25 @@ class RoomSummaryListProcessor(
} }
} }
private suspend fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary { private suspend fun buildSummaryForRoomListEntry(entry: RoomListItem): RoomSummary {
return when (entry) { return buildAndCacheRoomSummaryForRoomListItem(entry)
RoomListEntry.Empty -> buildEmptyRoomSummary()
is RoomListEntry.Filled -> buildAndCacheRoomSummaryForIdentifier(entry.roomId)
is RoomListEntry.Invalidated -> {
roomSummariesByIdentifier[entry.roomId] ?: buildAndCacheRoomSummaryForIdentifier(entry.roomId)
}
}
} }
private fun buildEmptyRoomSummary(): RoomSummary { private suspend fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary? {
return RoomSummary.Empty(UUID.randomUUID().toString()) val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem ->
buildAndCacheRoomSummaryForRoomListItem(roomListItem)
}
if (builtRoomSummary != null) {
roomSummariesByIdentifier[identifier] = builtRoomSummary
} else {
roomSummariesByIdentifier.remove(identifier)
}
return builtRoomSummary
} }
private suspend fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary { private suspend fun buildAndCacheRoomSummaryForRoomListItem(roomListItem: RoomListItem): RoomSummary {
val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem -> val builtRoomSummary = roomSummaryDetailsFactory.create(roomListItem = roomListItem)
RoomSummary.Filled( roomSummariesByIdentifier[builtRoomSummary.roomId.value] = builtRoomSummary
details = roomSummaryDetailsFactory.create(roomListItem)
)
} ?: buildEmptyRoomSummary()
roomSummariesByIdentifier[builtRoomSummary.identifier()] = builtRoomSummary
return builtRoomSummary return builtRoomSummary
} }

18
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListService.kt

@ -29,10 +29,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.matrix.rustcomponents.sdk.RoomListException
import org.matrix.rustcomponents.sdk.RoomListInput
import org.matrix.rustcomponents.sdk.RoomListRange
import org.matrix.rustcomponents.sdk.RoomListServiceState import org.matrix.rustcomponents.sdk.RoomListServiceState
import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator
import timber.log.Timber import timber.log.Timber
@ -73,20 +69,6 @@ internal class RustRoomListService(
allRooms.loadAllIncrementally(sessionCoroutineScope) allRooms.loadAllIncrementally(sessionCoroutineScope)
} }
override fun updateAllRoomsVisibleRange(range: IntRange) {
Timber.v("setVisibleRange=$range")
sessionCoroutineScope.launch {
try {
val ranges = listOf(RoomListRange(range.first.toUInt(), range.last.toUInt()))
innerRoomListService.applyInput(
RoomListInput.Viewport(ranges)
)
} catch (exception: RoomListException) {
Timber.e(exception, "Failed updating visible range")
}
}
}
override val syncIndicator: StateFlow<RoomListService.SyncIndicator> = override val syncIndicator: StateFlow<RoomListService.SyncIndicator> =
innerRoomListService.syncIndicator() innerRoomListService.syncIndicator()
.map { it.toSyncIndicator() } .map { it.toSyncIndicator() }

45
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFilterTest.kt

@ -19,46 +19,31 @@ package io.element.android.libraries.matrix.impl.roomlist
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.room.CurrentUserMembership import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.test.room.aRoomSummaryDetails import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
class RoomListFilterTest { class RoomListFilterTest {
private val regularRoom = aRoomSummaryFilled( private val regularRoom = aRoomSummary(
aRoomSummaryDetails( isDirect = false
isDirect = false
)
) )
private val directRoom = aRoomSummaryFilled( private val directRoom = aRoomSummary(
aRoomSummaryDetails( isDirect = true
isDirect = true
)
) )
private val favoriteRoom = aRoomSummaryFilled( private val favoriteRoom = aRoomSummary(
aRoomSummaryDetails( isFavorite = true
isFavorite = true
)
) )
private val markedAsUnreadRoom = aRoomSummaryFilled( private val markedAsUnreadRoom = aRoomSummary(
aRoomSummaryDetails( isMarkedUnread = true
isMarkedUnread = true
)
) )
private val unreadNotificationRoom = aRoomSummaryFilled( private val unreadNotificationRoom = aRoomSummary(
aRoomSummaryDetails( numUnreadNotifications = 1
numUnreadNotifications = 1
)
) )
private val roomToSearch = aRoomSummaryFilled( private val roomToSearch = aRoomSummary(
aRoomSummaryDetails( name = "Room to search"
name = "Room to search"
)
) )
private val invitedRoom = aRoomSummaryFilled( private val invitedRoom = aRoomSummary(
aRoomSummaryDetails( currentUserMembership = CurrentUserMembership.INVITED
currentUserMembership = CurrentUserMembership.INVITED
)
) )
private val roomSummaries = listOf( private val roomSummaries = listOf(

123
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryListProcessorTest.kt

@ -18,23 +18,31 @@ package io.element.android.libraries.matrix.impl.roomlist
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import com.sun.jna.Pointer import com.sun.jna.Pointer
import io.element.android.libraries.matrix.api.core.RoomId
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.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
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
import org.matrix.rustcomponents.sdk.EventTimelineItem
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.NoPointer
import org.matrix.rustcomponents.sdk.RoomHero
import org.matrix.rustcomponents.sdk.RoomInfo
import org.matrix.rustcomponents.sdk.RoomList import org.matrix.rustcomponents.sdk.RoomList
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
import org.matrix.rustcomponents.sdk.RoomListEntry
import org.matrix.rustcomponents.sdk.RoomListInput
import org.matrix.rustcomponents.sdk.RoomListItem import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.RoomListServiceInterface import org.matrix.rustcomponents.sdk.RoomListServiceInterface
import org.matrix.rustcomponents.sdk.RoomListServiceStateListener import org.matrix.rustcomponents.sdk.RoomListServiceStateListener
import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicatorListener import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicatorListener
import org.matrix.rustcomponents.sdk.RoomMember
import org.matrix.rustcomponents.sdk.RoomNotificationMode
import org.matrix.rustcomponents.sdk.TaskHandle import org.matrix.rustcomponents.sdk.TaskHandle
// NOTE: this class is using a fake implementation of a Rust SDK interface which returns actual Rust objects with pointers. // NOTE: this class is using a fake implementation of a Rust SDK interface which returns actual Rust objects with pointers.
@ -44,33 +52,34 @@ class RoomSummaryListProcessorTest {
@Test @Test
fun `Append adds new entries at the end of the list`() = runTest { fun `Append adds new entries at the end of the list`() = runTest {
summaries.value = listOf(aRoomSummaryFilled()) summaries.value = listOf(aRoomSummary())
val processor = createProcessor() val processor = createProcessor()
processor.postUpdate(listOf(RoomListEntriesUpdate.Append(listOf(RoomListEntry.Empty, RoomListEntry.Empty, RoomListEntry.Empty)))) val newEntry = FakeRoomListItem(A_ROOM_ID_2)
processor.postUpdate(listOf(RoomListEntriesUpdate.Append(listOf(newEntry, newEntry, newEntry))))
assertThat(summaries.value.count()).isEqualTo(4) assertThat(summaries.value.count()).isEqualTo(4)
assertThat(summaries.value.subList(1, 4).all { it is RoomSummary.Empty }).isTrue() assertThat(summaries.value.subList(1, 4).all { it.roomId == A_ROOM_ID_2 }).isTrue()
} }
@Test @Test
fun `PushBack adds a new entry at the end of the list`() = runTest { fun `PushBack adds a new entry at the end of the list`() = runTest {
summaries.value = listOf(aRoomSummaryFilled()) summaries.value = listOf(aRoomSummaryFilled())
val processor = createProcessor() val processor = createProcessor()
processor.postUpdate(listOf(RoomListEntriesUpdate.PushBack(RoomListEntry.Empty))) processor.postUpdate(listOf(RoomListEntriesUpdate.PushBack(FakeRoomListItem(A_ROOM_ID_2))))
assertThat(summaries.value.count()).isEqualTo(2) assertThat(summaries.value.count()).isEqualTo(2)
assertThat(summaries.value.last()).isInstanceOf(RoomSummary.Empty::class.java) assertThat(summaries.value.last().roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
fun `PushFront inserts a new entry at the start of the list`() = runTest { fun `PushFront inserts a new entry at the start of the list`() = runTest {
summaries.value = listOf(aRoomSummaryFilled()) summaries.value = listOf(aRoomSummaryFilled())
val processor = createProcessor() val processor = createProcessor()
processor.postUpdate(listOf(RoomListEntriesUpdate.PushFront(RoomListEntry.Empty))) processor.postUpdate(listOf(RoomListEntriesUpdate.PushFront(FakeRoomListItem(A_ROOM_ID_2))))
assertThat(summaries.value.count()).isEqualTo(2) assertThat(summaries.value.count()).isEqualTo(2)
assertThat(summaries.value.first()).isInstanceOf(RoomSummary.Empty::class.java) assertThat(summaries.value.first().roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
@ -79,10 +88,10 @@ class RoomSummaryListProcessorTest {
val processor = createProcessor() val processor = createProcessor()
val index = 0 val index = 0
processor.postUpdate(listOf(RoomListEntriesUpdate.Set(index.toUInt(), RoomListEntry.Empty))) processor.postUpdate(listOf(RoomListEntriesUpdate.Set(index.toUInt(), FakeRoomListItem(A_ROOM_ID_2))))
assertThat(summaries.value.count()).isEqualTo(1) assertThat(summaries.value.count()).isEqualTo(1)
assertThat(summaries.value[index]).isInstanceOf(RoomSummary.Empty::class.java) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
@ -91,10 +100,10 @@ class RoomSummaryListProcessorTest {
val processor = createProcessor() val processor = createProcessor()
val index = 0 val index = 0
processor.postUpdate(listOf(RoomListEntriesUpdate.Insert(index.toUInt(), RoomListEntry.Empty))) processor.postUpdate(listOf(RoomListEntriesUpdate.Insert(index.toUInt(), FakeRoomListItem(A_ROOM_ID_2))))
assertThat(summaries.value.count()).isEqualTo(2) assertThat(summaries.value.count()).isEqualTo(2)
assertThat(summaries.value[index]).isInstanceOf(RoomSummary.Empty::class.java) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
@ -106,7 +115,7 @@ class RoomSummaryListProcessorTest {
processor.postUpdate(listOf(RoomListEntriesUpdate.Remove(index.toUInt()))) processor.postUpdate(listOf(RoomListEntriesUpdate.Remove(index.toUInt())))
assertThat(summaries.value.count()).isEqualTo(1) assertThat(summaries.value.count()).isEqualTo(1)
assertThat((summaries.value[index] as RoomSummary.Filled).identifier()).isEqualTo(A_ROOM_ID_2.value) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
@ -118,7 +127,7 @@ class RoomSummaryListProcessorTest {
processor.postUpdate(listOf(RoomListEntriesUpdate.PopBack)) processor.postUpdate(listOf(RoomListEntriesUpdate.PopBack))
assertThat(summaries.value.count()).isEqualTo(1) assertThat(summaries.value.count()).isEqualTo(1)
assertThat((summaries.value[index] as RoomSummary.Filled).identifier()).isEqualTo(A_ROOM_ID.value) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID)
} }
@Test @Test
@ -130,7 +139,7 @@ class RoomSummaryListProcessorTest {
processor.postUpdate(listOf(RoomListEntriesUpdate.PopFront)) processor.postUpdate(listOf(RoomListEntriesUpdate.PopFront))
assertThat(summaries.value.count()).isEqualTo(1) assertThat(summaries.value.count()).isEqualTo(1)
assertThat((summaries.value[index] as RoomSummary.Filled).identifier()).isEqualTo(A_ROOM_ID_2.value) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID_2)
} }
@Test @Test
@ -152,7 +161,7 @@ class RoomSummaryListProcessorTest {
processor.postUpdate(listOf(RoomListEntriesUpdate.Truncate(1u))) processor.postUpdate(listOf(RoomListEntriesUpdate.Truncate(1u)))
assertThat(summaries.value.count()).isEqualTo(1) assertThat(summaries.value.count()).isEqualTo(1)
assertThat((summaries.value[index] as RoomSummary.Filled).identifier()).isEqualTo(A_ROOM_ID.value) assertThat(summaries.value[index].roomId).isEqualTo(A_ROOM_ID)
} }
private fun TestScope.createProcessor() = RoomSummaryListProcessor( private fun TestScope.createProcessor() = RoomSummaryListProcessor(
@ -168,8 +177,6 @@ class RoomSummaryListProcessorTest {
return RoomList(Pointer.NULL) return RoomList(Pointer.NULL)
} }
override suspend fun applyInput(input: RoomListInput) = Unit
override fun room(roomId: String): RoomListItem { override fun room(roomId: String): RoomListItem {
return RoomListItem(Pointer.NULL) return RoomListItem(Pointer.NULL)
} }
@ -183,3 +190,81 @@ class RoomSummaryListProcessorTest {
} }
} }
} }
private fun aRustRoomInfo(
id: String = A_ROOM_ID.value,
displayName: String = A_ROOM_NAME,
rawName: String = A_ROOM_NAME,
topic: String? = null,
avatarUrl: String? = null,
isDirect: Boolean = false,
isPublic: Boolean = false,
isSpace: Boolean = false,
isTombstoned: Boolean = false,
isFavourite: Boolean = false,
canonicalAlias: String? = null,
alternativeAliases: List<String> = listOf(),
membership: Membership = Membership.JOINED,
inviter: RoomMember? = null,
heroes: List<RoomHero> = listOf(),
activeMembersCount: ULong = 0uL,
invitedMembersCount: ULong = 0uL,
joinedMembersCount: ULong = 0uL,
userPowerLevels: Map<String, Long> = mapOf(),
highlightCount: ULong = 0uL,
notificationCount: ULong = 0uL,
userDefinedNotificationMode: RoomNotificationMode? = null,
hasRoomCall: Boolean = false,
activeRoomCallParticipants: List<String> = listOf(),
isMarkedUnread: Boolean = false,
numUnreadMessages: ULong = 0uL,
numUnreadNotifications: ULong = 0uL,
numUnreadMentions: ULong = 0uL,
) = RoomInfo(
id = id,
displayName = displayName,
rawName = rawName,
topic = topic,
avatarUrl = avatarUrl,
isDirect = isDirect,
isPublic = isPublic,
isSpace = isSpace,
isTombstoned = isTombstoned,
isFavourite = isFavourite,
canonicalAlias = canonicalAlias,
alternativeAliases = alternativeAliases,
membership = membership,
inviter = inviter,
heroes = heroes,
activeMembersCount = activeMembersCount,
invitedMembersCount = invitedMembersCount,
joinedMembersCount = joinedMembersCount,
userPowerLevels = userPowerLevels,
highlightCount = highlightCount,
notificationCount = notificationCount,
userDefinedNotificationMode = userDefinedNotificationMode,
hasRoomCall = hasRoomCall,
activeRoomCallParticipants = activeRoomCallParticipants,
isMarkedUnread = isMarkedUnread,
numUnreadMessages = numUnreadMessages,
numUnreadNotifications = numUnreadNotifications,
numUnreadMentions = numUnreadMentions
)
class FakeRoomListItem(
private val roomId: RoomId,
private val roomInfo: RoomInfo = aRustRoomInfo(id = roomId.value),
private val latestEvent: EventTimelineItem? = null,
) : RoomListItem(NoPointer) {
override fun id(): String {
return roomId.value
}
override suspend fun roomInfo(): RoomInfo {
return roomInfo
}
override suspend fun latestEvent(): EventTimelineItem? {
return latestEvent
}
}

31
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/RoomSummaryFixture.kt

@ -25,7 +25,6 @@ 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
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
@ -44,25 +43,19 @@ fun aRoomSummaryFilled(
numUnreadMessages: Int = 0, numUnreadMessages: Int = 0,
notificationMode: RoomNotificationMode? = null, notificationMode: RoomNotificationMode? = null,
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
) = RoomSummary.Filled( ) = aRoomSummary(
aRoomSummaryDetails( roomId = roomId,
roomId = roomId, name = name,
name = name, isDirect = isDirect,
isDirect = isDirect, avatarUrl = avatarUrl,
avatarUrl = avatarUrl, lastMessage = lastMessage,
lastMessage = lastMessage, numUnreadMentions = numUnreadMentions,
numUnreadMentions = numUnreadMentions, numUnreadMessages = numUnreadMessages,
numUnreadMessages = numUnreadMessages, notificationMode = notificationMode,
notificationMode = notificationMode, currentUserMembership = currentUserMembership,
currentUserMembership = currentUserMembership,
)
) )
fun aRoomSummaryFilled( fun aRoomSummary(
details: RoomSummaryDetails = aRoomSummaryDetails(),
) = RoomSummary.Filled(details)
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,
@ -80,7 +73,7 @@ fun aRoomSummaryDetails(
isFavorite: Boolean = false, isFavorite: Boolean = false,
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
heroes: List<MatrixUser> = emptyList(), heroes: List<MatrixUser> = emptyList(),
) = RoomSummaryDetails( ) = RoomSummary(
roomId = roomId, roomId = roomId,
name = name, name = name,
isDirect = isDirect, isDirect = isDirect,

7
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/FakeRoomListService.kt

@ -46,9 +46,6 @@ class FakeRoomListService : RoomListService {
syncIndicatorStateFlow.emit(value) syncIndicatorStateFlow.emit(value)
} }
var latestSlidingSyncRange: IntRange? = null
private set
override fun createRoomList( override fun createRoomList(
pageSize: Int, pageSize: Int,
initialFilter: RoomListFilter, initialFilter: RoomListFilter,
@ -65,10 +62,6 @@ class FakeRoomListService : RoomListService {
MutableStateFlow(RoomListFilter.all()) MutableStateFlow(RoomListFilter.all())
) )
override fun updateAllRoomsVisibleRange(range: IntRange) {
latestSlidingSyncRange = range
}
override val state: StateFlow<RoomListService.State> = roomListStateFlow override val state: StateFlow<RoomListService.State> = roomListStateFlow
override val syncIndicator: StateFlow<RoomListService.SyncIndicator> = syncIndicatorStateFlow override val syncIndicator: StateFlow<RoomListService.SyncIndicator> = syncIndicatorStateFlow

8
libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/RoomSummaryDetailsProvider.kt

@ -23,11 +23,11 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
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.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.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
open class RoomSummaryDetailsProvider : PreviewParameterProvider<RoomSummaryDetails> { open class RoomSummaryDetailsProvider : PreviewParameterProvider<RoomSummary> {
override val values: Sequence<RoomSummaryDetails> override val values: Sequence<RoomSummary>
get() = sequenceOf( get() = sequenceOf(
aRoomSummaryDetails(), aRoomSummaryDetails(),
aRoomSummaryDetails(name = null), aRoomSummaryDetails(name = null),
@ -52,7 +52,7 @@ fun aRoomSummaryDetails(
isFavorite: Boolean = false, isFavorite: Boolean = false,
currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED, currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,
heroes: List<MatrixUser> = emptyList(), heroes: List<MatrixUser> = emptyList(),
) = RoomSummaryDetails( ) = RoomSummary(
roomId = roomId, roomId = roomId,
name = name, name = name,
canonicalAlias = canonicalAlias, canonicalAlias = canonicalAlias,

10
libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/SelectedRoom.kt

@ -43,15 +43,15 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon 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.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.ui.strings.CommonStrings import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@Composable @Composable
fun SelectedRoom( fun SelectedRoom(
roomSummary: RoomSummaryDetails, roomSummary: RoomSummary,
onRemoveRoom: (RoomSummaryDetails) -> Unit, onRemoveRoom: (RoomSummary) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Box( Box(
@ -100,10 +100,10 @@ fun SelectedRoom(
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun SelectedRoomPreview( internal fun SelectedRoomPreview(
@PreviewParameter(RoomSummaryDetailsProvider::class) roomSummaryDetails: RoomSummaryDetails @PreviewParameter(RoomSummaryDetailsProvider::class) roomSummary: RoomSummary
) = ElementPreview { ) = ElementPreview {
SelectedRoom( SelectedRoom(
roomSummary = roomSummaryDetails, roomSummary = roomSummary,
onRemoveRoom = {}, onRemoveRoom = {},
) )
} }

4
libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/model/RoomSummaryExtension.kt

@ -18,9 +18,9 @@ package io.element.android.libraries.matrix.ui.model
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
fun RoomSummaryDetails.getAvatarData(size: AvatarSize) = AvatarData( fun RoomSummary.getAvatarData(size: AvatarSize) = AvatarData(
id = roomId.value, id = roomId.value,
name = name, name = name,
url = avatarUrl, url = avatarUrl,

4
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectEvents.kt

@ -16,10 +16,10 @@
package io.element.android.libraries.roomselect.impl package io.element.android.libraries.roomselect.impl
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
sealed interface RoomSelectEvents { sealed interface RoomSelectEvents {
data class SetSelectedRoom(val room: RoomSummaryDetails) : RoomSelectEvents data class SetSelectedRoom(val room: RoomSummary) : RoomSelectEvents
// TODO remove to restore multi-selection // TODO remove to restore multi-selection
data object RemoveSelectedRoom : RoomSelectEvents data object RemoveSelectedRoom : RoomSelectEvents

4
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenter.kt

@ -29,7 +29,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
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.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@ -45,7 +45,7 @@ class RoomSelectPresenter @AssistedInject constructor(
@Composable @Composable
override fun present(): RoomSelectState { override fun present(): RoomSelectState {
var selectedRooms by remember { mutableStateOf(persistentListOf<RoomSummaryDetails>()) } var selectedRooms by remember { mutableStateOf(persistentListOf<RoomSummary>()) }
var searchQuery by remember { mutableStateOf("") } var searchQuery by remember { mutableStateOf("") }
var isSearchActive by remember { mutableStateOf(false) } var isSearchActive by remember { mutableStateOf(false) }

5
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectSearchDataSource.kt

@ -22,7 +22,6 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
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.api.roomlist.loadAllIncrementally import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.toPersistentList import kotlinx.collections.immutable.toPersistentList
@ -48,11 +47,9 @@ class RoomSelectSearchDataSource @Inject constructor(
source = RoomList.Source.All, source = RoomList.Source.All,
) )
val roomSummaries: Flow<PersistentList<RoomSummaryDetails>> = roomList.filteredSummaries val roomSummaries: Flow<PersistentList<RoomSummary>> = roomList.filteredSummaries
.map { roomSummaries -> .map { roomSummaries ->
roomSummaries roomSummaries
.filterIsInstance<RoomSummary.Filled>()
.map { it.details }
.filter { it.currentUserMembership == CurrentUserMembership.JOINED } .filter { it.currentUserMembership == CurrentUserMembership.JOINED }
.distinctBy { it.roomId } // This should be removed once we're sure no duplicate Rooms can be received .distinctBy { it.roomId } // This should be removed once we're sure no duplicate Rooms can be received
.toPersistentList() .toPersistentList()

6
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectState.kt

@ -17,15 +17,15 @@
package io.element.android.libraries.roomselect.impl package io.element.android.libraries.roomselect.impl
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.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
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
data class RoomSelectState( data class RoomSelectState(
val mode: RoomSelectMode, val mode: RoomSelectMode,
val resultState: SearchBarResultState<ImmutableList<RoomSummaryDetails>>, val resultState: SearchBarResultState<ImmutableList<RoomSummary>>,
val query: String, val query: String,
val isSearchActive: Boolean, val isSearchActive: Boolean,
val selectedRooms: ImmutableList<RoomSummaryDetails>, val selectedRooms: ImmutableList<RoomSummary>,
val eventSink: (RoomSelectEvents) -> Unit val eventSink: (RoomSelectEvents) -> Unit
) )

6
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectStateProvider.kt

@ -20,7 +20,7 @@ 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.RoomAlias import io.element.android.libraries.matrix.api.core.RoomAlias
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.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.components.aRoomSummaryDetails 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
@ -52,10 +52,10 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
private fun aRoomSelectState( private fun aRoomSelectState(
mode: RoomSelectMode = RoomSelectMode.Forward, mode: RoomSelectMode = RoomSelectMode.Forward,
resultState: SearchBarResultState<ImmutableList<RoomSummaryDetails>> = SearchBarResultState.Initial(), resultState: SearchBarResultState<ImmutableList<RoomSummary>> = SearchBarResultState.Initial(),
query: String = "", query: String = "",
isSearchActive: Boolean = false, isSearchActive: Boolean = false,
selectedRooms: ImmutableList<RoomSummaryDetails> = persistentListOf(), selectedRooms: ImmutableList<RoomSummary> = persistentListOf(),
) = RoomSelectState( ) = RoomSelectState(
mode = mode, mode = mode,
resultState = resultState, resultState = resultState,

14
libraries/roomselect/impl/src/main/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectView.kt

@ -56,7 +56,7 @@ import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TextButton import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.designsystem.theme.components.TopAppBar import io.element.android.libraries.designsystem.theme.components.TopAppBar
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.roomlist.RoomSummaryDetails import io.element.android.libraries.matrix.api.roomlist.RoomSummary
import io.element.android.libraries.matrix.ui.components.SelectedRoom import io.element.android.libraries.matrix.ui.components.SelectedRoom
import io.element.android.libraries.matrix.ui.model.getAvatarData import io.element.android.libraries.matrix.ui.model.getAvatarData
import io.element.android.libraries.roomselect.api.RoomSelectMode import io.element.android.libraries.roomselect.api.RoomSelectMode
@ -73,13 +73,13 @@ fun RoomSelectView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
fun onRoomRemoved(roomSummaryDetails: RoomSummaryDetails) { fun onRoomRemoved(roomSummary: RoomSummary) {
// TODO toggle selection when multi-selection is enabled // TODO toggle selection when multi-selection is enabled
state.eventSink(RoomSelectEvents.RemoveSelectedRoom) state.eventSink(RoomSelectEvents.RemoveSelectedRoom)
} }
@Composable @Composable
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<RoomSummaryDetails>) { fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<RoomSummary>) {
if (isForwarding) return if (isForwarding) return
SelectedRooms( SelectedRooms(
selectedRooms = selectedRooms, selectedRooms = selectedRooms,
@ -193,8 +193,8 @@ fun RoomSelectView(
@Composable @Composable
private fun SelectedRooms( private fun SelectedRooms(
selectedRooms: ImmutableList<RoomSummaryDetails>, selectedRooms: ImmutableList<RoomSummary>,
onRemoveRoom: (RoomSummaryDetails) -> Unit, onRemoveRoom: (RoomSummary) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
LazyRow( LazyRow(
@ -210,9 +210,9 @@ private fun SelectedRooms(
@Composable @Composable
private fun RoomSummaryView( private fun RoomSummaryView(
summary: RoomSummaryDetails, summary: RoomSummary,
isSelected: Boolean, isSelected: Boolean,
onSelection: (RoomSummaryDetails) -> Unit, onSelection: (RoomSummary) -> Unit,
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier

11
libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt

@ -23,8 +23,7 @@ import com.google.common.truth.Truth.assertThat
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.RoomListFilter import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.RoomSummary import io.element.android.libraries.matrix.test.room.aRoomSummary
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.roomselect.api.RoomSelectMode import io.element.android.libraries.roomselect.api.RoomSelectMode
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
@ -69,7 +68,7 @@ class RoomSelectPresenterTest {
@Test @Test
fun `present - update query`() = runTest { fun `present - update query`() = runTest {
val roomListService = FakeRoomListService().apply { val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails()))) postAllRooms(listOf(aRoomSummary()))
} }
val presenter = createRoomSelectPresenter( val presenter = createRoomSelectPresenter(
roomListService = roomListService roomListService = roomListService
@ -78,7 +77,7 @@ class RoomSelectPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummaryDetails()))) assertThat(awaitItem().resultState as? SearchBarResultState.Results).isEqualTo(SearchBarResultState.Results(listOf(aRoomSummary())))
initialState.eventSink(RoomSelectEvents.ToggleSearchActive) initialState.eventSink(RoomSelectEvents.ToggleSearchActive)
skipItems(1) skipItems(1)
initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained")) initialState.eventSink(RoomSelectEvents.UpdateQuery("string not contained"))
@ -98,7 +97,7 @@ class RoomSelectPresenterTest {
@Test @Test
fun `present - select and remove a room`() = runTest { fun `present - select and remove a room`() = runTest {
val roomListService = FakeRoomListService().apply { val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(RoomSummary.Filled(aRoomSummaryDetails()))) postAllRooms(listOf(aRoomSummary()))
} }
val presenter = createRoomSelectPresenter( val presenter = createRoomSelectPresenter(
roomListService = roomListService, roomListService = roomListService,
@ -107,7 +106,7 @@ class RoomSelectPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
val summary = aRoomSummaryDetails() val summary = aRoomSummary()
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary)) initialState.eventSink(RoomSelectEvents.SetSelectedRoom(summary))
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary)) assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(summary))
initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom) initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom)

4
tests/uitests/src/test/snapshots/images/appicon.enterprise_Icon_en.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:fda6dfc8c57df5456535a8ec33f78830beaab61cc27ba4119e9576c5d641023b oid sha256:fe7dd8d4416b397b63fa2b3295e94e53af62f731eaeecca43b5df298a3e834d3
size 47856 size 17253

4
tests/uitests/src/test/snapshots/images/appicon.enterprise_RoundIcon_en.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:60b169ac392d4b51e8260c595a97dd14f267facd8f428ad69814bd27e502e189 oid sha256:dd6e7de23ed7048d02a2e7f412158e2372a19c0f6106d0f2876345aadfff906e
size 44355 size 16247

Loading…
Cancel
Save