Add an empty state to the room list.
- Make `RoomListDataSource.allRooms` a `SharedFlow` so we can know when we don't have a value yet. - Map its output in `RoomListPresenter` to `AsyncData`. - Display the new empty state when the room list has loaded and has no items.
This commit is contained in:
parent
732d3d5f83
commit
b390215701
7 changed files with 115 additions and 58 deletions
1
changelog.d/2330.feature
Normal file
1
changelog.d/2330.feature
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add empty state to the room list.
|
||||||
|
|
@ -23,6 +23,7 @@ import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
|
@ -32,6 +33,7 @@ import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||||
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
|
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
|
||||||
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||||
|
|
@ -68,7 +70,9 @@ class RoomListPresenter @Inject constructor(
|
||||||
val matrixUser: MutableState<MatrixUser?> = rememberSaveable {
|
val matrixUser: MutableState<MatrixUser?> = rememberSaveable {
|
||||||
mutableStateOf(null)
|
mutableStateOf(null)
|
||||||
}
|
}
|
||||||
val roomList by roomListDataSource.allRooms.collectAsState()
|
val roomList by produceState(initialValue = AsyncData.Loading()) {
|
||||||
|
roomListDataSource.allRooms.collect { value = AsyncData.Success(it) }
|
||||||
|
}
|
||||||
val filteredRoomList by roomListDataSource.filteredRooms.collectAsState()
|
val filteredRoomList by roomListDataSource.filteredRooms.collectAsState()
|
||||||
val filter by roomListDataSource.filter.collectAsState()
|
val filter by roomListDataSource.filter.collectAsState()
|
||||||
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
val networkConnectionStatus by networkMonitor.connectivity.collectAsState()
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.features.roomlist.impl
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||||
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.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
@ -28,7 +29,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
data class RoomListState(
|
data class RoomListState(
|
||||||
val matrixUser: MatrixUser?,
|
val matrixUser: MatrixUser?,
|
||||||
val showAvatarIndicator: Boolean,
|
val showAvatarIndicator: Boolean,
|
||||||
val roomList: ImmutableList<RoomListRoomSummary>,
|
val roomList: AsyncData<ImmutableList<RoomListRoomSummary>>,
|
||||||
val filter: String?,
|
val filter: String?,
|
||||||
val filteredRoomList: ImmutableList<RoomListRoomSummary>,
|
val filteredRoomList: ImmutableList<RoomListRoomSummary>,
|
||||||
val displayVerificationPrompt: Boolean,
|
val displayVerificationPrompt: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
||||||
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.aRoomListRoomSummary
|
import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
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.designsystem.utils.snackbar.SnackbarMessage
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||||
|
|
@ -49,13 +50,15 @@ open class RoomListStateProvider : PreviewParameterProvider<RoomListState> {
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
aRoomListState().copy(displayRecoveryKeyPrompt = true),
|
aRoomListState().copy(displayRecoveryKeyPrompt = true),
|
||||||
|
aRoomListState().copy(roomList = AsyncData.Success(persistentListOf())),
|
||||||
|
aRoomListState().copy(roomList = AsyncData.Loading()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun aRoomListState() = RoomListState(
|
internal fun aRoomListState() = RoomListState(
|
||||||
matrixUser = MatrixUser(userId = UserId("@id:domain"), displayName = "User#1"),
|
matrixUser = MatrixUser(userId = UserId("@id:domain"), displayName = "User#1"),
|
||||||
showAvatarIndicator = false,
|
showAvatarIndicator = false,
|
||||||
roomList = aRoomListRoomSummaryList(),
|
roomList = AsyncData.Success(aRoomListRoomSummaryList()),
|
||||||
filter = "filter",
|
filter = "filter",
|
||||||
filteredRoomList = aRoomListRoomSummaryList(),
|
filteredRoomList = aRoomListRoomSummaryList(),
|
||||||
hasNetworkConnection = true,
|
hasNetworkConnection = true,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
package io.element.android.features.roomlist.impl
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
|
@ -35,6 +37,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
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.NestedScrollConnection
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
|
@ -42,6 +45,7 @@ import androidx.compose.ui.res.stringResource
|
||||||
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.Velocity
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomView
|
import io.element.android.features.leaveroom.api.LeaveRoomView
|
||||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
||||||
import io.element.android.features.roomlist.impl.components.ConfirmRecoveryKeyBanner
|
import io.element.android.features.roomlist.impl.components.ConfirmRecoveryKeyBanner
|
||||||
|
|
@ -51,17 +55,22 @@ import io.element.android.features.roomlist.impl.components.RoomListTopBar
|
||||||
import io.element.android.features.roomlist.impl.components.RoomSummaryRow
|
import io.element.android.features.roomlist.impl.components.RoomSummaryRow
|
||||||
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.search.RoomListSearchResultView
|
import io.element.android.features.roomlist.impl.search.RoomListSearchResultView
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
|
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
|
||||||
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.IconSource
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListView(
|
fun RoomListView(
|
||||||
|
|
@ -122,6 +131,35 @@ fun RoomListView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun EmptyRoomListView(
|
||||||
|
onCreateRoomClicked: () -> Unit,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.screen_roomlist_empty_title),
|
||||||
|
style = ElementTheme.typography.fontBodyLgRegular,
|
||||||
|
color = ElementTheme.colors.textSecondary,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.screen_roomlist_empty_message),
|
||||||
|
style = ElementTheme.typography.fontBodyLgRegular,
|
||||||
|
color = ElementTheme.colors.textSecondary,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Button(
|
||||||
|
text = stringResource(CommonStrings.action_start_chat),
|
||||||
|
leadingIcon = IconSource.Resource(CommonDrawables.ic_new_message),
|
||||||
|
onClick = onCreateRoomClicked,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun RoomListContent(
|
private fun RoomListContent(
|
||||||
|
|
@ -182,56 +220,62 @@ private fun RoomListContent(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = { padding ->
|
content = { padding ->
|
||||||
LazyColumn(
|
println(state.roomList)
|
||||||
modifier = Modifier
|
if (state.roomList is AsyncData.Success && state.roomList.data.isEmpty()) {
|
||||||
.padding(padding)
|
EmptyRoomListView(onCreateRoomClicked)
|
||||||
.consumeWindowInsets(padding)
|
} else {
|
||||||
.nestedScroll(nestedScrollConnection),
|
LazyColumn(
|
||||||
state = lazyListState,
|
modifier = Modifier
|
||||||
) {
|
.padding(padding)
|
||||||
when {
|
.consumeWindowInsets(padding)
|
||||||
state.displayVerificationPrompt -> {
|
.nestedScroll(nestedScrollConnection),
|
||||||
item {
|
state = lazyListState,
|
||||||
RequestVerificationHeader(
|
) {
|
||||||
onVerifyClicked = onVerifyClicked,
|
when {
|
||||||
onDismissClicked = { state.eventSink(RoomListEvents.DismissRequestVerificationPrompt) }
|
state.displayVerificationPrompt -> {
|
||||||
)
|
item {
|
||||||
|
RequestVerificationHeader(
|
||||||
|
onVerifyClicked = onVerifyClicked,
|
||||||
|
onDismissClicked = { state.eventSink(RoomListEvents.DismissRequestVerificationPrompt) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.displayRecoveryKeyPrompt -> {
|
||||||
|
item {
|
||||||
|
ConfirmRecoveryKeyBanner(
|
||||||
|
onContinueClicked = onOpenSettings,
|
||||||
|
onDismissClicked = { state.eventSink(RoomListEvents.DismissRecoveryKeyPrompt) }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.displayRecoveryKeyPrompt -> {
|
|
||||||
item {
|
|
||||||
ConfirmRecoveryKeyBanner(
|
|
||||||
onContinueClicked = onOpenSettings,
|
|
||||||
onDismissClicked = { state.eventSink(RoomListEvents.DismissRecoveryKeyPrompt) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.invitesState != InvitesState.NoInvites) {
|
if (state.invitesState != InvitesState.NoInvites) {
|
||||||
|
item {
|
||||||
|
InvitesEntryPointView(onInvitesClicked, state.invitesState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val roomList = state.roomList.dataOrNull().orEmpty()
|
||||||
|
itemsIndexed(
|
||||||
|
items = roomList,
|
||||||
|
contentType = { _, room -> room.contentType() },
|
||||||
|
) { index, room ->
|
||||||
|
RoomSummaryRow(
|
||||||
|
room = room,
|
||||||
|
onClick = ::onRoomClicked,
|
||||||
|
onLongClick = onRoomLongClicked,
|
||||||
|
)
|
||||||
|
if (index != roomList.lastIndex) {
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a last Spacer item to ensure that the FAB does not hide the last room item
|
||||||
|
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80
|
||||||
item {
|
item {
|
||||||
InvitesEntryPointView(onInvitesClicked, state.invitesState)
|
Spacer(modifier = Modifier.height(80.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itemsIndexed(
|
|
||||||
items = state.roomList,
|
|
||||||
contentType = { _, room -> room.contentType() },
|
|
||||||
) { index, room ->
|
|
||||||
RoomSummaryRow(
|
|
||||||
room = room,
|
|
||||||
onClick = ::onRoomClicked,
|
|
||||||
onLongClick = onRoomLongClicked,
|
|
||||||
)
|
|
||||||
if (index != state.roomList.lastIndex) {
|
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add a last Spacer item to ensure that the FAB does not hide the last room item
|
|
||||||
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80
|
|
||||||
item {
|
|
||||||
Spacer(modifier = Modifier.height(80.dp))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,9 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
|
|
@ -52,7 +54,7 @@ class RoomListDataSource @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _filter = MutableStateFlow("")
|
private val _filter = MutableStateFlow("")
|
||||||
private val _allRooms = MutableStateFlow<ImmutableList<RoomListRoomSummary>>(persistentListOf())
|
private val _allRooms = MutableSharedFlow<ImmutableList<RoomListRoomSummary>>(replay = 1)
|
||||||
private val _filteredRooms = MutableStateFlow<ImmutableList<RoomListRoomSummary>>(persistentListOf())
|
private val _filteredRooms = MutableStateFlow<ImmutableList<RoomListRoomSummary>>(persistentListOf())
|
||||||
|
|
||||||
private val lock = Mutex()
|
private val lock = Mutex()
|
||||||
|
|
@ -90,7 +92,7 @@ class RoomListDataSource @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val filter: StateFlow<String> = _filter
|
val filter: StateFlow<String> = _filter
|
||||||
val allRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _allRooms
|
val allRooms: SharedFlow<ImmutableList<RoomListRoomSummary>> = _allRooms
|
||||||
val filteredRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _filteredRooms
|
val filteredRooms: StateFlow<ImmutableList<RoomListRoomSummary>> = _filteredRooms
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
|
|
|
||||||
|
|
@ -166,14 +166,16 @@ class RoomListPresenterTests {
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = consumeItemsUntilPredicate { state -> state.roomList.size == 16 }.last()
|
val initialState = consumeItemsUntilPredicate { state -> state.roomList.dataOrNull()?.size == 16 }.last()
|
||||||
// Room list is loaded with 16 placeholders
|
// Room list is loaded with 16 placeholders
|
||||||
assertThat(initialState.roomList.size).isEqualTo(16)
|
val initialItems = initialState.roomList.dataOrNull().orEmpty()
|
||||||
assertThat(initialState.roomList.all { it.isPlaceholder }).isTrue()
|
assertThat(initialItems.size).isEqualTo(16)
|
||||||
|
assertThat(initialItems.all { it.isPlaceholder }).isTrue()
|
||||||
roomListService.postAllRooms(listOf(aRoomSummaryFilled()))
|
roomListService.postAllRooms(listOf(aRoomSummaryFilled()))
|
||||||
val withRoomState = consumeItemsUntilPredicate { state -> state.roomList.size == 1 }.last()
|
val withRoomState = consumeItemsUntilPredicate { state -> state.roomList.dataOrNull()?.size == 1 }.last()
|
||||||
assertThat(withRoomState.roomList.size).isEqualTo(1)
|
val withRoomStateItems = withRoomState.roomList.dataOrNull().orEmpty()
|
||||||
assertThat(withRoomState.roomList.first())
|
assertThat(withRoomStateItems.size).isEqualTo(1)
|
||||||
|
assertThat(withRoomStateItems.first())
|
||||||
.isEqualTo(aRoomListRoomSummary)
|
.isEqualTo(aRoomListRoomSummary)
|
||||||
scope.cancel()
|
scope.cancel()
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +196,7 @@ class RoomListPresenterTests {
|
||||||
skipItems(3)
|
skipItems(3)
|
||||||
val loadedState = awaitItem()
|
val loadedState = awaitItem()
|
||||||
// Test filtering with result
|
// Test filtering with result
|
||||||
assertThat(loadedState.roomList.size).isEqualTo(1)
|
assertThat(loadedState.roomList.dataOrNull().orEmpty().size).isEqualTo(1)
|
||||||
loadedState.eventSink.invoke(RoomListEvents.UpdateFilter(A_ROOM_NAME.substring(0, 3)))
|
loadedState.eventSink.invoke(RoomListEvents.UpdateFilter(A_ROOM_NAME.substring(0, 3)))
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val withFilteredRoomState = awaitItem()
|
val withFilteredRoomState = awaitItem()
|
||||||
|
|
@ -384,10 +386,10 @@ 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.userDefinedNotificationMode == userDefinedMode }
|
state.roomList.dataOrNull().orEmpty().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.dataOrNull()?.find { it.id == A_ROOM_ID.value }
|
||||||
assertThat(room?.userDefinedNotificationMode).isEqualTo(userDefinedMode)
|
assertThat(room?.userDefinedNotificationMode).isEqualTo(userDefinedMode)
|
||||||
cancelAndIgnoreRemainingEvents()
|
cancelAndIgnoreRemainingEvents()
|
||||||
scope.cancel()
|
scope.cancel()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue