mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 06:55:41 +00:00
Merge remote-tracking branch 'origin/develop' into feature/bma/multiAccountShareAtRoot
# Conflicts: # libraries/roomselect/impl/src/test/kotlin/io/element/android/libraries/roomselect/impl/RoomSelectPresenterTest.kt
This commit is contained in:
-1
@@ -13,7 +13,6 @@ import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
|
||||
sealed interface RoomSelectEvent {
|
||||
data class ToggleSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvent
|
||||
data object ToggleSearchActive : RoomSelectEvent
|
||||
data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvent
|
||||
data object ToggleAccountListExpanded : RoomSelectEvent
|
||||
data class SelectAccount(val sessionId: SessionId) : RoomSelectEvent
|
||||
|
||||
+2
-7
@@ -8,7 +8,6 @@
|
||||
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import androidx.compose.foundation.text.input.clearText
|
||||
import androidx.compose.foundation.text.input.rememberTextFieldState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -67,7 +66,6 @@ class RoomSelectPresenter(
|
||||
override fun present(): RoomSelectState {
|
||||
var selectedRooms by remember { mutableStateOf(persistentListOf<SelectRoomInfo>()) }
|
||||
val queryState = rememberTextFieldState()
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
var isAccountListExpanded by remember { mutableStateOf(false) }
|
||||
// Null until the sessions are loaded
|
||||
val sessions by remember { sessionStore.sessionsFlow() }.collectAsState(initial = null)
|
||||
@@ -157,7 +155,7 @@ class RoomSelectPresenter(
|
||||
derivedStateOf {
|
||||
when {
|
||||
roomSummaryDetailsList.isNotEmpty() -> SearchBarResultState.Results(roomSummaryDetailsList.toImmutableList())
|
||||
isSearchActive -> SearchBarResultState.NoResultsFound
|
||||
queryState.text.isNotBlank() -> SearchBarResultState.NoResultsFound
|
||||
else -> SearchBarResultState.Initial
|
||||
}
|
||||
}
|
||||
@@ -173,13 +171,11 @@ class RoomSelectPresenter(
|
||||
selectedRooms.adding(event.room)
|
||||
}
|
||||
}
|
||||
RoomSelectEvent.ToggleSearchActive -> isSearchActive = !isSearchActive
|
||||
RoomSelectEvent.ToggleAccountListExpanded -> isAccountListExpanded = !isAccountListExpanded
|
||||
is RoomSelectEvent.SelectAccount -> {
|
||||
selectedSessionId = event.sessionId
|
||||
// The selected rooms and the search query are specific to the session
|
||||
// The selected rooms are specific to the session. The search query is kept, and applied to the rooms of the new session.
|
||||
selectedRooms = persistentListOf()
|
||||
queryState.clearText()
|
||||
isAccountListExpanded = false
|
||||
}
|
||||
is RoomSelectEvent.UpdateVisibleRange -> coroutineScope.launch {
|
||||
@@ -193,7 +189,6 @@ class RoomSelectPresenter(
|
||||
maxNumberOfRooms = maxNumberOfRooms,
|
||||
resultState = searchResults,
|
||||
searchQuery = queryState,
|
||||
isSearchActive = isSearchActive,
|
||||
selectedRooms = selectedRooms,
|
||||
selectedAccount = selectedAccount,
|
||||
hasRoomListError = hasRoomListError,
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ data class RoomSelectState(
|
||||
val maxNumberOfRooms: Int,
|
||||
val resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>>,
|
||||
val searchQuery: TextFieldState,
|
||||
val isSearchActive: Boolean,
|
||||
val selectedRooms: ImmutableList<SelectRoomInfo>,
|
||||
val selectedAccount: MatrixUser,
|
||||
/**
|
||||
|
||||
+1
-5
@@ -26,17 +26,15 @@ open class RoomSelectStatePreviewParam : PreviewParameterProvider<RoomSelectStat
|
||||
override val values: Sequence<RoomSelectState>
|
||||
get() = sequenceOf(
|
||||
aRoomSelectState(),
|
||||
aRoomSelectState(searchQuery = "Test", isSearchActive = true),
|
||||
aRoomSelectState(searchQuery = "Test", resultState = SearchBarResultState.NoResultsFound),
|
||||
aRoomSelectState(resultState = SearchBarResultState.Results(aRoomSelectRoomList())),
|
||||
aRoomSelectState(
|
||||
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
|
||||
searchQuery = "Test",
|
||||
isSearchActive = true,
|
||||
),
|
||||
aRoomSelectState(
|
||||
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
|
||||
searchQuery = "Test",
|
||||
isSearchActive = true,
|
||||
selectedRooms = aRoomSelectRoomList().subList(0, 1),
|
||||
),
|
||||
aRoomSelectState(
|
||||
@@ -76,7 +74,6 @@ internal fun aRoomSelectState(
|
||||
maxNumberOfRooms: Int = 10,
|
||||
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial,
|
||||
searchQuery: String = "",
|
||||
isSearchActive: Boolean = false,
|
||||
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
|
||||
selectedAccount: MatrixUser = MatrixUser(UserId("@alice:example.org")),
|
||||
hasRoomListError: Boolean = false,
|
||||
@@ -88,7 +85,6 @@ internal fun aRoomSelectState(
|
||||
maxNumberOfRooms = maxNumberOfRooms,
|
||||
resultState = resultState,
|
||||
searchQuery = TextFieldState(initialText = searchQuery),
|
||||
isSearchActive = isSearchActive,
|
||||
selectedRooms = selectedRooms,
|
||||
selectedAccount = selectedAccount,
|
||||
hasRoomListError = hasRoomListError,
|
||||
|
||||
+105
-67
@@ -10,6 +10,7 @@ package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animate
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
@@ -24,18 +25,23 @@ import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -46,9 +52,11 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.heading
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.stateDescription
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -70,8 +78,8 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.ListSectionHeader
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBar
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchField
|
||||
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.TopAppBar
|
||||
@@ -123,10 +131,8 @@ fun RoomSelectView(
|
||||
}
|
||||
|
||||
var canHandleBack by remember { mutableStateOf(true) }
|
||||
fun onBackButton(state: RoomSelectState) {
|
||||
if (state.isSearchActive) {
|
||||
state.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
} else if (canHandleBack) {
|
||||
fun onBackButton() {
|
||||
if (canHandleBack) {
|
||||
canHandleBack = false
|
||||
onDismiss()
|
||||
}
|
||||
@@ -134,16 +140,34 @@ fun RoomSelectView(
|
||||
|
||||
BackHandler(
|
||||
enabled = canHandleBack,
|
||||
onBack = { onBackButton(state) }
|
||||
onBack = ::onBackButton,
|
||||
)
|
||||
|
||||
val searchQuery = state.searchQuery.text.toString()
|
||||
// Use a new list state when the selected account changes, so that the list of rooms is scrolled to the top
|
||||
val lazyListState = key(state.selectedAccount.userId) { rememberLazyListState() }
|
||||
// Scroll the list of rooms to the top when the search query changes
|
||||
LaunchedEffect(lazyListState, searchQuery) {
|
||||
lazyListState.scrollToItem(0)
|
||||
}
|
||||
// Hide the account switch section when the room list is scrolled up, and show it again as soon as it is scrolled down.
|
||||
// Use a new state when the selected account changes, so that the section is fully displayed again.
|
||||
val accountSwitchScrollBehavior = key(state.selectedAccount.userId) {
|
||||
TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
|
||||
}
|
||||
// Collapse the account switch section when the user starts searching. It can be displayed again by scrolling down.
|
||||
val isSearching = searchQuery.isNotBlank()
|
||||
LaunchedEffect(isSearching) {
|
||||
if (isSearching) {
|
||||
val topAppBarState = accountSwitchScrollBehavior.state
|
||||
animate(
|
||||
initialValue = topAppBarState.heightOffset,
|
||||
targetValue = topAppBarState.heightOffsetLimit,
|
||||
) { value, _ ->
|
||||
topAppBarState.heightOffset = value
|
||||
}
|
||||
}
|
||||
}
|
||||
OnVisibleRangeChangeEffect(lazyListState) { visibleRange ->
|
||||
state.eventSink(RoomSelectEvent.UpdateVisibleRange(visibleRange))
|
||||
}
|
||||
@@ -153,13 +177,13 @@ fun RoomSelectView(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
titleStr = when (state.mode) {
|
||||
RoomSelectMode.Forward -> stringResource(CommonStrings.common_forward_message)
|
||||
RoomSelectMode.Forward -> stringResource(CommonStrings.common_forward_to)
|
||||
RoomSelectMode.Share -> stringResource(CommonStrings.common_send_to)
|
||||
},
|
||||
navigationIcon = {
|
||||
BackButton(
|
||||
enabled = canHandleBack,
|
||||
onClick = { onBackButton(state) }
|
||||
onClick = ::onBackButton,
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
@@ -177,82 +201,62 @@ fun RoomSelectView(
|
||||
Modifier
|
||||
.padding(paddingValues)
|
||||
.consumeWindowInsets(paddingValues)
|
||||
.nestedScroll(accountSwitchScrollBehavior.nestedScrollConnection)
|
||||
.then(
|
||||
// Only when the account switch section is displayed, else its unknown height would consume all the scroll events
|
||||
if (state.showAccountSwitch) {
|
||||
Modifier.nestedScroll(accountSwitchScrollBehavior.nestedScrollConnection)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
) {
|
||||
SearchBar(
|
||||
SearchField(
|
||||
state = state.searchQuery,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
WindowInsets.safeDrawing
|
||||
.only(WindowInsetsSides.Horizontal)
|
||||
.asPaddingValues()
|
||||
),
|
||||
placeHolderTitle = stringResource(CommonStrings.action_search),
|
||||
queryState = state.searchQuery,
|
||||
active = state.isSearchActive,
|
||||
onActiveChange = { state.eventSink(RoomSelectEvent.ToggleSearchActive) },
|
||||
resultState = state.resultState,
|
||||
showBackButton = false,
|
||||
) { summaries ->
|
||||
if (summaries.isNotEmpty()) {
|
||||
ListSectionHeader(
|
||||
title = stringResource(CommonStrings.common_header_rooms),
|
||||
hasDivider = false,
|
||||
)
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
placeholder = stringResource(CommonStrings.action_search),
|
||||
)
|
||||
if (state.showAccountSwitch) {
|
||||
// Keep this space outside the collapsing section, so that the section does not touch the search field when it is collapsing
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TopAppBarScrollBehaviorLayout(scrollBehavior = accountSwitchScrollBehavior) {
|
||||
AccountSwitchSection(
|
||||
selectedAccount = state.selectedAccount,
|
||||
otherAccounts = state.otherAccounts,
|
||||
isExpanded = state.isAccountListExpanded,
|
||||
onToggleExpand = { state.eventSink(RoomSelectEvent.ToggleAccountListExpanded) },
|
||||
onSelectAccount = { state.eventSink(RoomSelectEvent.SelectAccount(it)) },
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
contentPadding = lazyColumnContentPadding,
|
||||
) {
|
||||
item {
|
||||
SelectedRoomsHelper(
|
||||
selectedRooms = state.selectedRooms,
|
||||
showVerticalSpace = false,
|
||||
)
|
||||
}
|
||||
items(summaries, key = { it.roomId.value }) { roomSummary ->
|
||||
RoomSummaryView(
|
||||
roomSummary,
|
||||
isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId },
|
||||
onSelection = { roomSummary ->
|
||||
state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary))
|
||||
},
|
||||
canBeSelected = state.canSelectMoreRooms,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!state.isSearchActive) {
|
||||
if (state.showAccountSwitch) {
|
||||
// Keep this space outside the collapsing section, so that the section does not touch the search bar when it is collapsing
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
TopAppBarScrollBehaviorLayout(scrollBehavior = accountSwitchScrollBehavior) {
|
||||
AccountSwitchSection(
|
||||
selectedAccount = state.selectedAccount,
|
||||
otherAccounts = state.otherAccounts,
|
||||
isExpanded = state.isAccountListExpanded,
|
||||
onToggleExpand = { state.eventSink(RoomSelectEvent.ToggleAccountListExpanded) },
|
||||
onSelectAccount = { state.eventSink(RoomSelectEvent.SelectAccount(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
SelectedRoomsHelper(
|
||||
selectedRooms = state.selectedRooms,
|
||||
// showVerticalSpace only if there is no other accounts
|
||||
showVerticalSpace = !state.showAccountSwitch,
|
||||
)
|
||||
if (state.hasRoomListError) {
|
||||
RoomListError()
|
||||
} else if (state.resultState is SearchBarResultState.Results) {
|
||||
SelectedRoomsHelper(
|
||||
selectedRooms = state.selectedRooms,
|
||||
// showVerticalSpace only if there is no other accounts
|
||||
showVerticalSpace = !state.showAccountSwitch,
|
||||
)
|
||||
when {
|
||||
state.hasRoomListError -> RoomListError()
|
||||
state.resultState is SearchBarResultState.NoResultsFound -> NoResultsView(searchQuery = searchQuery)
|
||||
state.resultState is SearchBarResultState.Results -> {
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
contentPadding = lazyColumnContentPadding,
|
||||
) {
|
||||
if (state.resultState.results.isNotEmpty()) {
|
||||
item {
|
||||
val headerText = if (searchQuery.isBlank()) {
|
||||
stringResource(CommonStrings.common_header_rooms)
|
||||
} else {
|
||||
stringResource(CommonStrings.common_results_for, searchQuery)
|
||||
}
|
||||
ListSectionHeader(
|
||||
title = stringResource(CommonStrings.common_header_rooms),
|
||||
title = headerText,
|
||||
hasDivider = false,
|
||||
)
|
||||
}
|
||||
@@ -269,11 +273,45 @@ fun RoomSelectView(
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NoResultsView(
|
||||
searchQuery: String,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
// Scrollable, so that the account switch section can be displayed again by scrolling down
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 24.dp, vertical = 40.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(CommonStrings.common_no_results),
|
||||
modifier = Modifier
|
||||
.semantics {
|
||||
heading()
|
||||
},
|
||||
textAlign = TextAlign.Center,
|
||||
style = ElementTheme.typography.fontHeadingMdBold,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(CommonStrings.common_no_results_for, searchQuery),
|
||||
modifier = Modifier.widthIn(max = 300.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RoomListError() {
|
||||
IconTitleSubtitleMolecule(
|
||||
|
||||
+27
-15
@@ -63,7 +63,6 @@ class RoomSelectPresenterTest {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.selectedRooms).isEmpty()
|
||||
assertThat(initialState.resultState).isInstanceOf(SearchBarResultState.Initial::class.java)
|
||||
assertThat(initialState.isSearchActive).isFalse()
|
||||
assertThat(initialState.maxNumberOfRooms).isEqualTo(10)
|
||||
assertThat(initialState.canSelectMoreRooms).isTrue()
|
||||
assertThat(initialState.selectedAccount).isEqualTo(MatrixUser(A_SESSION_ID))
|
||||
@@ -366,6 +365,33 @@ class RoomSelectPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - select another account keeps the search query and applies it to the rooms of this account`() = runTest {
|
||||
val roomList2 = FakeDynamicRoomList(summaries = MutableStateFlow(listOf(aRoomSummary(roomId = A_ROOM_ID_2))))
|
||||
val roomListServices = mapOf(
|
||||
A_SESSION_ID to FakeRoomListService(createRoomListLambda = { FakeDynamicRoomList(summaries = MutableStateFlow(listOf(aRoomSummary()))) }),
|
||||
A_SESSION_ID_2 to FakeRoomListService(createRoomListLambda = { roomList2 }),
|
||||
)
|
||||
val presenter = createRoomSelectPresenter(
|
||||
mode = RoomSelectMode.Share,
|
||||
sessionStore = aSessionStoreWithTwoAccounts(),
|
||||
matrixClientProvider = FakeMatrixClientProvider { sessionId ->
|
||||
Result.success(FakeMatrixClient(sessionId = sessionId, roomListService = roomListServices.getValue(sessionId)))
|
||||
},
|
||||
)
|
||||
presenter.test {
|
||||
val state = awaitLastSequentialItem()
|
||||
state.searchQuery.setTextAndPlaceCursorAtEnd("query")
|
||||
state.eventSink(RoomSelectEvent.SelectAccount(A_SESSION_ID_2))
|
||||
val finalState = consumeItemsUntilPredicate {
|
||||
it.selectedAccount.userId == A_SESSION_ID_2 && it.resultState is SearchBarResultState.Results
|
||||
}.last()
|
||||
assertThat(finalState.searchQuery.text.toString()).isEqualTo("query")
|
||||
assertThat(finalState.showAccountSwitch).isTrue()
|
||||
assertThat(roomList2.currentFilter.value).isEqualTo(RoomListFilter.NormalizedMatchRoomName("query"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - forward mode with several accounts does not show the account switch`() = runTest {
|
||||
val presenter = createRoomSelectPresenter(
|
||||
@@ -386,18 +412,6 @@ class RoomSelectPresenterTest {
|
||||
),
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `present - toggle search active`() = runTest {
|
||||
val presenter = createRoomSelectPresenter()
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
assertThat(awaitItem().isSearchActive).isTrue()
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
assertThat(awaitItem().isSearchActive).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - update query`() = runTest {
|
||||
val roomSummary = aRoomSummary()
|
||||
@@ -416,8 +430,6 @@ class RoomSelectPresenterTest {
|
||||
// Do not compare the lambda because they will be different. So copy the lambda from expectedRoomSummary to result
|
||||
val result = (awaitItem().resultState as SearchBarResultState.Results).results
|
||||
assertThat(result).isEqualTo(listOf(expectedRoomInfo))
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
skipItems(1)
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained")
|
||||
assertThat(
|
||||
roomList.currentFilter.value
|
||||
|
||||
+50
@@ -13,8 +13,12 @@ import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.AndroidComposeUiTest
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.compose.ui.test.swipeUp
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
@@ -29,6 +33,7 @@ import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.robolectric.RobolectricTest
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.junit.Test
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@@ -123,6 +128,44 @@ class RoomSelectViewTest : RobolectricTest() {
|
||||
onNodeWithText(activity!!.getString(CommonStrings.common_switch_account)).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the room list can be scrolled when there is no other account`() = runAndroidComposeUiTest {
|
||||
setRoomSelectView(
|
||||
aRoomSelectState(
|
||||
mode = RoomSelectMode.Share,
|
||||
resultState = SearchBarResultState.Results(aLongRoomList()),
|
||||
),
|
||||
)
|
||||
onNodeWithText("Room 0").assertIsDisplayed()
|
||||
onRoot().performTouchInput { swipeUp() }
|
||||
onNodeWithText("Room 0").assertIsNotDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `the room list can be scrolled when there are other accounts`() = runAndroidComposeUiTest {
|
||||
setRoomSelectView(
|
||||
aRoomSelectState(
|
||||
mode = RoomSelectMode.Share,
|
||||
resultState = SearchBarResultState.Results(aLongRoomList()),
|
||||
otherAccounts = persistentListOf(aMatrixUser(id = "@bob:example.org", displayName = "Bob")),
|
||||
),
|
||||
)
|
||||
onNodeWithText("Room 0").assertIsDisplayed()
|
||||
onRoot().performTouchInput { swipeUp() }
|
||||
onNodeWithText("Room 0").assertIsNotDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a message is displayed when no room matches the search query`() = runAndroidComposeUiTest {
|
||||
setRoomSelectView(
|
||||
aRoomSelectState(
|
||||
searchQuery = "Test",
|
||||
resultState = SearchBarResultState.NoResultsFound,
|
||||
),
|
||||
)
|
||||
onNodeWithText(activity!!.getString(CommonStrings.common_no_results)).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an error is displayed instead of the rooms if they cannot be loaded`() = runAndroidComposeUiTest<ComponentActivity> {
|
||||
setRoomSelectView(
|
||||
@@ -150,3 +193,10 @@ private fun AndroidComposeUiTest<ComponentActivity>.setRoomSelectView(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun aLongRoomList() = List(30) { index ->
|
||||
aSelectRoomInfo(
|
||||
roomId = RoomId("!room$index:domain"),
|
||||
name = "Room $index",
|
||||
)
|
||||
}.toImmutableList()
|
||||
|
||||
Reference in New Issue
Block a user