Add ability to forward a message to several rooms. (#7013)
* Forward message to multiple rooms * Ensure event is sent only once per room. * `RoomSelectEvents` -> `RoomSelectEvent` * Use test extension on presenter. * Room selection: add a limitation of 10 rooms for Share and Forward actions. * Update screenshots * Fix padding issue * Update screenshots * `RadioButton` -> `Checkbox` * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
+4
-1
@@ -74,7 +74,10 @@ class ForwardMessagesNode(
|
||||
return roomSelectEntryPoint.createNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
params = RoomSelectEntryPoint.Params(mode = RoomSelectMode.Forward),
|
||||
params = RoomSelectEntryPoint.Params(
|
||||
mode = RoomSelectMode.Forward,
|
||||
maxNumberOfRooms = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS,
|
||||
),
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
|
||||
+4
-1
@@ -70,7 +70,10 @@ class ShareNode(
|
||||
return roomSelectEntryPoint.createNode(
|
||||
parentNode = this,
|
||||
buildContext = buildContext,
|
||||
params = RoomSelectEntryPoint.Params(mode = RoomSelectMode.Share),
|
||||
params = RoomSelectEntryPoint.Params(
|
||||
mode = RoomSelectMode.Share,
|
||||
maxNumberOfRooms = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS,
|
||||
),
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ class RoomContentForwarder(
|
||||
val content = (messageLikeContent.kind as? MsgLikeKind.Message)?.content
|
||||
?: throw ForwardEventException(toRoomIds)
|
||||
|
||||
val targetRooms = toRoomIds.mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) }
|
||||
val targetRooms = toRoomIds.toSet().mapNotNull { roomId -> roomListService.roomOrNull(roomId.value) }
|
||||
val failedForwardingTo = mutableSetOf<RoomId>()
|
||||
targetRooms.parallelMap { room ->
|
||||
room.use { targetRoom ->
|
||||
|
||||
+5
@@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
interface RoomSelectEntryPoint : FeatureEntryPoint {
|
||||
data class Params(
|
||||
val mode: RoomSelectMode,
|
||||
val maxNumberOfRooms: Int,
|
||||
)
|
||||
|
||||
fun createNode(
|
||||
@@ -30,4 +31,8 @@ interface RoomSelectEntryPoint : FeatureEntryPoint {
|
||||
fun onRoomSelected(roomIds: List<RoomId>)
|
||||
fun onCancel()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_MAX_NUMBER_OF_ROOMS = 10
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -26,7 +26,10 @@ class DefaultRoomSelectEntryPoint : RoomSelectEntryPoint {
|
||||
return parentNode.createNode<RoomSelectNode>(
|
||||
buildContext = buildContext,
|
||||
plugins = listOf(
|
||||
RoomSelectNode.Inputs(mode = params.mode),
|
||||
RoomSelectNode.Inputs(
|
||||
mode = params.mode,
|
||||
maxNumberOfRooms = params.maxNumberOfRooms,
|
||||
),
|
||||
callback,
|
||||
)
|
||||
)
|
||||
|
||||
+4
-7
@@ -10,11 +10,8 @@ package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import io.element.android.libraries.matrix.ui.model.SelectRoomInfo
|
||||
|
||||
sealed interface RoomSelectEvents {
|
||||
data class SetSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvents
|
||||
|
||||
// TODO remove to restore multi-selection
|
||||
data object RemoveSelectedRoom : RoomSelectEvents
|
||||
data object ToggleSearchActive : RoomSelectEvents
|
||||
data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvents
|
||||
sealed interface RoomSelectEvent {
|
||||
data class ToggleSelectedRoom(val room: SelectRoomInfo) : RoomSelectEvent
|
||||
data object ToggleSearchActive : RoomSelectEvent
|
||||
data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvent
|
||||
}
|
||||
+5
-1
@@ -35,10 +35,14 @@ class RoomSelectNode(
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
data class Inputs(
|
||||
val mode: RoomSelectMode,
|
||||
val maxNumberOfRooms: Int,
|
||||
) : NodeInputs
|
||||
|
||||
private val inputs: Inputs = inputs()
|
||||
private val presenter = presenterFactory.create(inputs.mode)
|
||||
private val presenter = presenterFactory.create(
|
||||
mode = inputs.mode,
|
||||
maxNumberOfRooms = inputs.maxNumberOfRooms,
|
||||
)
|
||||
private val stateFlow = launchMolecule { presenter.present() }
|
||||
private val callback: RoomSelectEntryPoint.Callback = callback()
|
||||
|
||||
|
||||
+16
-14
@@ -34,11 +34,15 @@ import kotlinx.coroutines.launch
|
||||
@AssistedInject
|
||||
class RoomSelectPresenter(
|
||||
@Assisted private val mode: RoomSelectMode,
|
||||
@Assisted private val maxNumberOfRooms: Int,
|
||||
private val dataSourceFactory: RoomSelectSearchDataSource.Factory,
|
||||
) : Presenter<RoomSelectState> {
|
||||
@AssistedFactory
|
||||
fun interface Factory {
|
||||
fun create(mode: RoomSelectMode): RoomSelectPresenter
|
||||
fun create(
|
||||
mode: RoomSelectMode,
|
||||
maxNumberOfRooms: Int,
|
||||
): RoomSelectPresenter
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -67,21 +71,18 @@ class RoomSelectPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvent(event: RoomSelectEvents) {
|
||||
fun handleEvent(event: RoomSelectEvent) {
|
||||
when (event) {
|
||||
is RoomSelectEvents.SetSelectedRoom -> {
|
||||
selectedRooms = persistentListOf(event.room)
|
||||
// Restore for multi-selection
|
||||
// val index = selectedRooms.indexOfFirst { it.roomId == event.room.roomId }
|
||||
// selectedRooms = if (index >= 0) {
|
||||
// selectedRooms.removeAt(index)
|
||||
// } else {
|
||||
// selectedRooms.add(event.room)
|
||||
// }
|
||||
is RoomSelectEvent.ToggleSelectedRoom -> {
|
||||
val index = selectedRooms.indexOfFirst { it.roomId == event.room.roomId }
|
||||
selectedRooms = if (index >= 0) {
|
||||
selectedRooms.removeAt(index)
|
||||
} else {
|
||||
selectedRooms.add(event.room)
|
||||
}
|
||||
}
|
||||
RoomSelectEvents.RemoveSelectedRoom -> selectedRooms = persistentListOf()
|
||||
RoomSelectEvents.ToggleSearchActive -> isSearchActive = !isSearchActive
|
||||
is RoomSelectEvents.UpdateVisibleRange -> coroutineScope.launch {
|
||||
RoomSelectEvent.ToggleSearchActive -> isSearchActive = !isSearchActive
|
||||
is RoomSelectEvent.UpdateVisibleRange -> coroutineScope.launch {
|
||||
dataSource.updateVisibleRange(event.range)
|
||||
}
|
||||
}
|
||||
@@ -89,6 +90,7 @@ class RoomSelectPresenter(
|
||||
|
||||
return RoomSelectState(
|
||||
mode = mode,
|
||||
maxNumberOfRooms = maxNumberOfRooms,
|
||||
resultState = searchResults,
|
||||
searchQuery = queryState,
|
||||
isSearchActive = isSearchActive,
|
||||
|
||||
+5
-2
@@ -16,9 +16,12 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class RoomSelectState(
|
||||
val mode: RoomSelectMode,
|
||||
val maxNumberOfRooms: Int,
|
||||
val resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>>,
|
||||
val searchQuery: TextFieldState,
|
||||
val isSearchActive: Boolean,
|
||||
val selectedRooms: ImmutableList<SelectRoomInfo>,
|
||||
val eventSink: (RoomSelectEvents) -> Unit
|
||||
)
|
||||
val eventSink: (RoomSelectEvent) -> Unit,
|
||||
) {
|
||||
val canSelectMoreRooms = selectedRooms.size < maxNumberOfRooms
|
||||
}
|
||||
|
||||
+9
-1
@@ -40,18 +40,26 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
|
||||
mode = RoomSelectMode.Share,
|
||||
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
|
||||
),
|
||||
aRoomSelectState(
|
||||
mode = RoomSelectMode.Share,
|
||||
resultState = SearchBarResultState.Results(aRoomSelectRoomList()),
|
||||
selectedRooms = aRoomSelectRoomList().subList(0, 1),
|
||||
maxNumberOfRooms = 1,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aRoomSelectState(
|
||||
mode: RoomSelectMode = RoomSelectMode.Forward,
|
||||
maxNumberOfRooms: Int = 10,
|
||||
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
|
||||
searchQuery: String = "",
|
||||
isSearchActive: Boolean = false,
|
||||
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
|
||||
eventSink: (RoomSelectEvents) -> Unit = {},
|
||||
eventSink: (RoomSelectEvent) -> Unit = {},
|
||||
) = RoomSelectState(
|
||||
mode = mode,
|
||||
maxNumberOfRooms = maxNumberOfRooms,
|
||||
resultState = resultState,
|
||||
searchQuery = TextFieldState(initialText = searchQuery),
|
||||
isSearchActive = isSearchActive,
|
||||
|
||||
+36
-29
@@ -44,8 +44,8 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarType
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
|
||||
import io.element.android.libraries.designsystem.theme.components.RadioButton
|
||||
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
|
||||
@@ -71,26 +71,30 @@ fun RoomSelectView(
|
||||
onSubmit: (List<RoomId>) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onRoomRemoved(roomInfo: SelectRoomInfo) {
|
||||
// TODO toggle selection when multi-selection is enabled
|
||||
state.eventSink(RoomSelectEvents.RemoveSelectedRoom)
|
||||
state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo))
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SelectedRoomsHelper(isForwarding: Boolean, selectedRooms: ImmutableList<SelectRoomInfo>) {
|
||||
if (isForwarding) return
|
||||
SelectedRooms(
|
||||
selectedRooms = selectedRooms,
|
||||
onRemoveRoom = ::onRoomRemoved,
|
||||
modifier = Modifier.padding(vertical = 16.dp)
|
||||
)
|
||||
fun SelectedRoomsHelper(
|
||||
selectedRooms: ImmutableList<SelectRoomInfo>,
|
||||
showVerticalSpace: Boolean,
|
||||
) {
|
||||
if (selectedRooms.isNotEmpty()) {
|
||||
SelectedRooms(
|
||||
selectedRooms = selectedRooms,
|
||||
onRemoveRoom = ::onRoomRemoved,
|
||||
modifier = Modifier.padding(vertical = 16.dp)
|
||||
)
|
||||
} else if (showVerticalSpace) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
}
|
||||
|
||||
var canHandleBack by remember { mutableStateOf(true) }
|
||||
fun onBackButton(state: RoomSelectState) {
|
||||
if (state.isSearchActive) {
|
||||
state.eventSink(RoomSelectEvents.ToggleSearchActive)
|
||||
state.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
} else if (canHandleBack) {
|
||||
canHandleBack = false
|
||||
onDismiss()
|
||||
@@ -104,7 +108,7 @@ fun RoomSelectView(
|
||||
|
||||
val lazyListState = rememberLazyListState()
|
||||
OnVisibleRangeChangeEffect(lazyListState) { visibleRange ->
|
||||
state.eventSink(RoomSelectEvents.UpdateVisibleRange(visibleRange))
|
||||
state.eventSink(RoomSelectEvent.UpdateVisibleRange(visibleRange))
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
@@ -141,16 +145,15 @@ fun RoomSelectView(
|
||||
placeHolderTitle = stringResource(CommonStrings.action_search),
|
||||
queryState = state.searchQuery,
|
||||
active = state.isSearchActive,
|
||||
onActiveChange = { state.eventSink(RoomSelectEvents.ToggleSearchActive) },
|
||||
onActiveChange = { state.eventSink(RoomSelectEvent.ToggleSearchActive) },
|
||||
resultState = state.resultState,
|
||||
showBackButton = false,
|
||||
) { summaries ->
|
||||
LazyColumn(state = lazyListState) {
|
||||
item {
|
||||
SelectedRoomsHelper(
|
||||
// TODO state.isForwarding
|
||||
isForwarding = false,
|
||||
selectedRooms = state.selectedRooms
|
||||
selectedRooms = state.selectedRooms,
|
||||
showVerticalSpace = false,
|
||||
)
|
||||
}
|
||||
items(summaries, key = { it.roomId.value }) { roomSummary ->
|
||||
@@ -159,8 +162,9 @@ fun RoomSelectView(
|
||||
roomSummary,
|
||||
isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId },
|
||||
onSelection = { roomSummary ->
|
||||
state.eventSink(RoomSelectEvents.SetSelectedRoom(roomSummary))
|
||||
}
|
||||
state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary))
|
||||
},
|
||||
canBeSelected = state.canSelectMoreRooms,
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
@@ -169,13 +173,10 @@ fun RoomSelectView(
|
||||
}
|
||||
|
||||
if (!state.isSearchActive) {
|
||||
// TODO restore for multi-selection
|
||||
// SelectedRoomsHelper(
|
||||
// isForwarding = state.isForwarding,
|
||||
// selectedRooms = state.selectedRooms
|
||||
// )
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
SelectedRoomsHelper(
|
||||
selectedRooms = state.selectedRooms,
|
||||
showVerticalSpace = true,
|
||||
)
|
||||
if (state.resultState is SearchBarResultState.Results) {
|
||||
LazyColumn(state = lazyListState) {
|
||||
items(state.resultState.results, key = { it.roomId.value }) { roomSummary ->
|
||||
@@ -184,8 +185,9 @@ fun RoomSelectView(
|
||||
roomSummary,
|
||||
isSelected = state.selectedRooms.any { it.roomId == roomSummary.roomId },
|
||||
onSelection = { roomSummary ->
|
||||
state.eventSink(RoomSelectEvents.SetSelectedRoom(roomSummary))
|
||||
}
|
||||
state.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomSummary))
|
||||
},
|
||||
canBeSelected = state.canSelectMoreRooms,
|
||||
)
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
@@ -218,6 +220,7 @@ private fun SelectedRooms(
|
||||
private fun RoomSummaryView(
|
||||
roomInfo: SelectRoomInfo,
|
||||
isSelected: Boolean,
|
||||
canBeSelected: Boolean,
|
||||
onSelection: (SelectRoomInfo) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
@@ -262,7 +265,11 @@ private fun RoomSummaryView(
|
||||
)
|
||||
}
|
||||
}
|
||||
RadioButton(selected = isSelected, onClick = { onSelection(roomInfo) })
|
||||
Checkbox(
|
||||
checked = isSelected,
|
||||
enabled = isSelected || canBeSelected,
|
||||
onCheckedChange = { onSelection(roomInfo) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-4
@@ -33,13 +33,15 @@ class DefaultRoomSelectEntryPointTest {
|
||||
fun `test node builder`() = runTest {
|
||||
val entryPoint = DefaultRoomSelectEntryPoint()
|
||||
val testMode = RoomSelectMode.Share
|
||||
val testMaxNumberOfRooms = 12
|
||||
val parentNode = TestParentNode.create { buildContext, plugins ->
|
||||
RoomSelectNode(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
presenterFactory = { mode ->
|
||||
presenterFactory = { mode, maxNumberOfRooms ->
|
||||
assertThat(mode).isEqualTo(testMode)
|
||||
createRoomSelectPresenter(mode)
|
||||
assertThat(maxNumberOfRooms).isEqualTo(testMaxNumberOfRooms)
|
||||
createRoomSelectPresenter(mode, maxNumberOfRooms)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -47,7 +49,10 @@ class DefaultRoomSelectEntryPointTest {
|
||||
override fun onRoomSelected(roomIds: List<RoomId>) = lambdaError()
|
||||
override fun onCancel() = lambdaError()
|
||||
}
|
||||
val params = RoomSelectEntryPoint.Params(testMode)
|
||||
val params = RoomSelectEntryPoint.Params(
|
||||
mode = testMode,
|
||||
maxNumberOfRooms = testMaxNumberOfRooms,
|
||||
)
|
||||
val result = entryPoint.createNode(
|
||||
parentNode = parentNode,
|
||||
buildContext = BuildContext.root(null),
|
||||
@@ -55,7 +60,7 @@ class DefaultRoomSelectEntryPointTest {
|
||||
callback = callback,
|
||||
)
|
||||
assertThat(result).isInstanceOf(RoomSelectNode::class.java)
|
||||
assertThat(result.plugins).contains(RoomSelectNode.Inputs(params.mode))
|
||||
assertThat(result.plugins).contains(RoomSelectNode.Inputs(params.mode, params.maxNumberOfRooms))
|
||||
assertThat(result.plugins).contains(callback)
|
||||
}
|
||||
}
|
||||
|
||||
+26
-26
@@ -9,9 +9,6 @@
|
||||
package io.element.android.libraries.roomselect.impl
|
||||
|
||||
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
@@ -20,10 +17,12 @@ import io.element.android.libraries.matrix.test.room.aRoomSummary
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectEntryPoint
|
||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.test
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -40,26 +39,24 @@ class RoomSelectPresenterTest {
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = createRoomSelectPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - toggle search active`() = runTest {
|
||||
val presenter = createRoomSelectPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(RoomSelectEvents.ToggleSearchActive)
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
assertThat(awaitItem().isSearchActive).isTrue()
|
||||
initialState.eventSink(RoomSelectEvents.ToggleSearchActive)
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
assertThat(awaitItem().isSearchActive).isFalse()
|
||||
}
|
||||
}
|
||||
@@ -76,15 +73,13 @@ class RoomSelectPresenterTest {
|
||||
val presenter = createRoomSelectPresenter(
|
||||
roomListService = roomListService
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val expectedRoomInfo = roomSummary.toSelectRoomInfo()
|
||||
// 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(RoomSelectEvents.ToggleSearchActive)
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSearchActive)
|
||||
skipItems(1)
|
||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained")
|
||||
assertThat(
|
||||
@@ -110,17 +105,22 @@ class RoomSelectPresenterTest {
|
||||
createRoomListLambda = { roomList }
|
||||
)
|
||||
val presenter = createRoomSelectPresenter(
|
||||
maxNumberOfRooms = 1,
|
||||
roomListService = roomListService,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
val roomInfo = roomSummary.toSelectRoomInfo()
|
||||
initialState.eventSink(RoomSelectEvents.SetSelectedRoom(roomInfo))
|
||||
assertThat(awaitItem().selectedRooms).isEqualTo(persistentListOf(roomInfo))
|
||||
initialState.eventSink(RoomSelectEvents.RemoveSelectedRoom)
|
||||
assertThat(awaitItem().selectedRooms).isEmpty()
|
||||
initialState.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo))
|
||||
awaitItem().let {
|
||||
assertThat(it.selectedRooms).isEqualTo(persistentListOf(roomInfo))
|
||||
assertThat(it.canSelectMoreRooms).isFalse()
|
||||
it.eventSink(RoomSelectEvent.ToggleSelectedRoom(roomInfo))
|
||||
}
|
||||
awaitItem().let {
|
||||
assertThat(it.selectedRooms).isEmpty()
|
||||
assertThat(it.canSelectMoreRooms).isTrue()
|
||||
}
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
@@ -136,9 +136,7 @@ class RoomSelectPresenterTest {
|
||||
createRoomListLambda = { roomList }
|
||||
)
|
||||
val presenter = createRoomSelectPresenter(roomListService = roomListService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
// Post some rooms to simulate loaded content
|
||||
val rooms = (1..10).map { aRoomSummary() }
|
||||
@@ -146,7 +144,7 @@ class RoomSelectPresenterTest {
|
||||
skipItems(1)
|
||||
|
||||
// UpdateVisibleRange near end should trigger loadMore
|
||||
initialState.eventSink(RoomSelectEvents.UpdateVisibleRange(IntRange(0, 9)))
|
||||
initialState.eventSink(RoomSelectEvent.UpdateVisibleRange(IntRange(0, 9)))
|
||||
// Give time for the coroutine to complete
|
||||
testScheduler.advanceUntilIdle()
|
||||
|
||||
@@ -157,9 +155,11 @@ class RoomSelectPresenterTest {
|
||||
|
||||
internal fun TestScope.createRoomSelectPresenter(
|
||||
mode: RoomSelectMode = RoomSelectMode.Forward,
|
||||
maxNumberOfRooms: Int = RoomSelectEntryPoint.DEFAULT_MAX_NUMBER_OF_ROOMS,
|
||||
roomListService: RoomListService = FakeRoomListService(),
|
||||
) = RoomSelectPresenter(
|
||||
mode = mode,
|
||||
maxNumberOfRooms = maxNumberOfRooms,
|
||||
dataSourceFactory = object : RoomSelectSearchDataSource.Factory {
|
||||
override fun create(coroutineScope: CoroutineScope): RoomSelectSearchDataSource {
|
||||
return RoomSelectSearchDataSource(
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d06e84c695086a799c8377bcf48869675b98dcadd1b5320e685d775589ac40c7
|
||||
size 30950
|
||||
oid sha256:2a93b747f763fc0613c3fa5fdb492be034426916a4b3761a61f4c1d5fc655440
|
||||
size 28772
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3825e3c312d75a865545745ee00b64d8c2259e515dc45fad64236963e91f2427
|
||||
size 28999
|
||||
oid sha256:feaf2f316024a21d49c7b71b1e3df892e60924a715fc892871ee1f06006145ab
|
||||
size 26657
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7b0f7e2b97a343d0e1bedd9595a1057a03a4429c3fa72613451ac86a7146392a
|
||||
size 33382
|
||||
oid sha256:19f984bbf1f12dc3774b24c4fbadaae40c024cc876c8bf172af29a22429b43e0
|
||||
size 31248
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cccff3215bc81e2a6491f3b0da3f4d8997179b54c698f962eb245f535e6cc9fc
|
||||
size 28655
|
||||
oid sha256:c3ff0ef8dc9adc1378bef8a87479aed5a4cc1d43050851f516e9de17ef7201ee
|
||||
size 26450
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b1dd54a38725d9fdc035a73aebfbe9447377970e1b9e33dd512f0d41e2a11ec1
|
||||
size 30975
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b38450dc7cc24e6f9a0db829aa11058d10ae45d433945afd534627534f362554
|
||||
size 30261
|
||||
oid sha256:c3545c6c2b173b70bfba5dd571ea23db31ca7c2e64554131ba5cdbbb0555ea35
|
||||
size 28229
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c1b36608e269c7572c93c6f10cddeaf42bfeba404c6699a6e050144bc28bc55e
|
||||
size 28569
|
||||
oid sha256:947bb1138d11180f6174db8b9fadf51cec8d8d2947f0f47db148b479fa1f4d86
|
||||
size 26340
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96f198461d8d60d8610f337c3dbe90bebd8c98f32a4739310532d629ca336a1f
|
||||
size 33113
|
||||
oid sha256:e035e0c89cf000340d17257a9ad0e3e2ea1937f7408664742d9c4ba0c5b8c2c3
|
||||
size 31149
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:12350783e27c09074bdaba2e74ac445b643ff6a13251c13a7cdf98999274325d
|
||||
size 27915
|
||||
oid sha256:f0159ba2e298d8c3c7663ed0fdb4dca4ae179e00d40e5fdec8223ca597adbe6a
|
||||
size 25871
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:42ff2caf57dc21ea2681423082d91592091ad062ba350e91a7bbd10500768d58
|
||||
size 30515
|
||||
Reference in New Issue
Block a user