Avoid using runBlocking in Node resolve function.
This commit is contained in:
parent
7559385439
commit
16acfa28d7
10 changed files with 159 additions and 26 deletions
|
|
@ -26,16 +26,13 @@ import io.element.android.libraries.architecture.BackstackView
|
||||||
import io.element.android.libraries.architecture.BaseFlowNode
|
import io.element.android.libraries.architecture.BaseFlowNode
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@ContributesNode(SessionScope::class)
|
@ContributesNode(SessionScope::class)
|
||||||
class CreateRoomFlowNode @AssistedInject constructor(
|
class CreateRoomFlowNode @AssistedInject constructor(
|
||||||
@Assisted buildContext: BuildContext,
|
@Assisted buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
private val client: MatrixClient,
|
|
||||||
) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
|
) : BaseFlowNode<CreateRoomFlowNode.NavTarget>(
|
||||||
backstack = BackStack(
|
backstack = BackStack(
|
||||||
initialElement = NavTarget.ConfigureRoom,
|
initialElement = NavTarget.ConfigureRoom,
|
||||||
|
|
@ -59,8 +56,7 @@ class CreateRoomFlowNode @AssistedInject constructor(
|
||||||
createNode<ConfigureRoomNode>(buildContext, plugins = listOf(callback))
|
createNode<ConfigureRoomNode>(buildContext, plugins = listOf(callback))
|
||||||
}
|
}
|
||||||
is NavTarget.AddPeople -> {
|
is NavTarget.AddPeople -> {
|
||||||
val joinedRoom = runBlocking { client.getJoinedRoom(navTarget.roomId) } ?: error("Room not found")
|
val inputs = AddPeopleNode.Inputs(navTarget.roomId)
|
||||||
val inputs = AddPeopleNode.Inputs(joinedRoom)
|
|
||||||
val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback {
|
val callback: AddPeopleNode.Callback = object : AddPeopleNode.Callback {
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
onRoomCreated(navTarget.roomId)
|
onRoomCreated(navTarget.roomId)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import io.element.android.features.invitepeople.api.InvitePeopleRenderer
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
|
||||||
@ContributesNode(SessionScope::class)
|
@ContributesNode(SessionScope::class)
|
||||||
class AddPeopleNode @AssistedInject constructor(
|
class AddPeopleNode @AssistedInject constructor(
|
||||||
|
|
@ -31,7 +31,7 @@ class AddPeopleNode @AssistedInject constructor(
|
||||||
private val invitePeopleRenderer: InvitePeopleRenderer,
|
private val invitePeopleRenderer: InvitePeopleRenderer,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
data class Inputs(
|
data class Inputs(
|
||||||
val joinedRoom: JoinedRoom
|
val roomId: RoomId,
|
||||||
) : NodeInputs
|
) : NodeInputs
|
||||||
|
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
|
|
@ -42,8 +42,11 @@ class AddPeopleNode @AssistedInject constructor(
|
||||||
plugins<Callback>().forEach { it.onFinish() }
|
plugins<Callback>().forEach { it.onFinish() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val joinedRoom = inputs<Inputs>().joinedRoom
|
private val roomId = inputs<Inputs>().roomId
|
||||||
private val invitePeoplePresenter = invitePeoplePresenterFactory.create(joinedRoom)
|
private val invitePeoplePresenter = invitePeoplePresenterFactory.create(
|
||||||
|
joinedRoom = null,
|
||||||
|
roomId = roomId,
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,14 @@
|
||||||
package io.element.android.features.invitepeople.api
|
package io.element.android.features.invitepeople.api
|
||||||
|
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
|
|
||||||
interface InvitePeoplePresenter : Presenter<InvitePeopleState> {
|
interface InvitePeoplePresenter : Presenter<InvitePeopleState> {
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(room: JoinedRoom): InvitePeoplePresenter
|
fun create(
|
||||||
|
joinedRoom: JoinedRoom?,
|
||||||
|
roomId: RoomId,
|
||||||
|
): InvitePeoplePresenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
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
|
||||||
|
|
@ -23,11 +24,14 @@ import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||||
import io.element.android.features.invitepeople.api.InvitePeoplePresenter
|
import io.element.android.features.invitepeople.api.InvitePeoplePresenter
|
||||||
import io.element.android.features.invitepeople.api.InvitePeopleState
|
import io.element.android.features.invitepeople.api.InvitePeopleState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.architecture.map
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||||
|
|
@ -46,16 +50,18 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
@Assisted private val room: JoinedRoom,
|
@Assisted private val joinedRoom: JoinedRoom?,
|
||||||
|
@Assisted private val roomId: RoomId,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val coroutineDispatchers: CoroutineDispatchers,
|
private val coroutineDispatchers: CoroutineDispatchers,
|
||||||
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
|
||||||
private val appErrorStateService: AppErrorStateService,
|
private val appErrorStateService: AppErrorStateService,
|
||||||
|
private val matrixClient: MatrixClient,
|
||||||
) : InvitePeoplePresenter {
|
) : InvitePeoplePresenter {
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
interface Factory : InvitePeoplePresenter.Factory {
|
interface Factory : InvitePeoplePresenter.Factory {
|
||||||
override fun create(room: JoinedRoom): DefaultInvitePeoplePresenter
|
override fun create(joinedRoom: JoinedRoom?, roomId: RoomId): DefaultInvitePeoplePresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -66,9 +72,21 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
var searchQuery by rememberSaveable { mutableStateOf("") }
|
var searchQuery by rememberSaveable { mutableStateOf("") }
|
||||||
var searchActive by rememberSaveable { mutableStateOf(false) }
|
var searchActive by rememberSaveable { mutableStateOf(false) }
|
||||||
val showSearchLoader = rememberSaveable { mutableStateOf(false) }
|
val showSearchLoader = rememberSaveable { mutableStateOf(false) }
|
||||||
|
val room by produceState(if (joinedRoom != null) AsyncData.Success(joinedRoom) else AsyncData.Loading()) {
|
||||||
|
if (joinedRoom == null) {
|
||||||
|
val result = matrixClient.getJoinedRoom(roomId)
|
||||||
|
value = if (result == null) {
|
||||||
|
AsyncData.Failure(Exception("Room not found"))
|
||||||
|
} else {
|
||||||
|
AsyncData.Success(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(room.isSuccess()) {
|
||||||
fetchMembers(roomMembers)
|
room.dataOrNull()?.let {
|
||||||
|
fetchMembers(it, roomMembers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LaunchedEffect(searchQuery, roomMembers) {
|
LaunchedEffect(searchQuery, roomMembers) {
|
||||||
performSearch(
|
performSearch(
|
||||||
|
|
@ -96,7 +114,9 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
searchResults.toggleUser(event.user)
|
searchResults.toggleUser(event.user)
|
||||||
}
|
}
|
||||||
is InvitePeopleEvents.SendInvites -> {
|
is InvitePeopleEvents.SendInvites -> {
|
||||||
sessionCoroutineScope.sendInvites(selectedUsers.value)
|
room.dataOrNull()?.let {
|
||||||
|
sessionCoroutineScope.sendInvites(it, selectedUsers.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is InvitePeopleEvents.CloseSearch -> {
|
is InvitePeopleEvents.CloseSearch -> {
|
||||||
searchActive = false
|
searchActive = false
|
||||||
|
|
@ -106,6 +126,7 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefaultInvitePeopleState(
|
return DefaultInvitePeopleState(
|
||||||
|
room = room.map { },
|
||||||
canInvite = selectedUsers.value.isNotEmpty(),
|
canInvite = selectedUsers.value.isNotEmpty(),
|
||||||
selectedUsers = selectedUsers.value,
|
selectedUsers = selectedUsers.value,
|
||||||
searchQuery = searchQuery,
|
searchQuery = searchQuery,
|
||||||
|
|
@ -116,7 +137,10 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.sendInvites(selectedUsers: List<MatrixUser>) = launch {
|
private fun CoroutineScope.sendInvites(
|
||||||
|
room: JoinedRoom,
|
||||||
|
selectedUsers: List<MatrixUser>,
|
||||||
|
) = launch {
|
||||||
val anyInviteFailed = selectedUsers
|
val anyInviteFailed = selectedUsers
|
||||||
.map { room.inviteUserById(it.userId) }
|
.map { room.inviteUserById(it.userId) }
|
||||||
.any { it.isFailure }
|
.any { it.isFailure }
|
||||||
|
|
@ -186,7 +210,10 @@ class DefaultInvitePeoplePresenter @AssistedInject constructor(
|
||||||
}.launchIn(this)
|
}.launchIn(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchMembers(roomMembers: MutableState<AsyncData<ImmutableList<RoomMember>>>) {
|
private suspend fun fetchMembers(
|
||||||
|
room: JoinedRoom,
|
||||||
|
roomMembers: MutableState<AsyncData<ImmutableList<RoomMember>>>
|
||||||
|
) {
|
||||||
suspend {
|
suspend {
|
||||||
room.filterMembers("", coroutineDispatchers.io).toImmutableList()
|
room.filterMembers("", coroutineDispatchers.io).toImmutableList()
|
||||||
}.runCatchingUpdatingState(roomMembers)
|
}.runCatchingUpdatingState(roomMembers)
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ package io.element.android.features.invitepeople.impl
|
||||||
|
|
||||||
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||||
import io.element.android.features.invitepeople.api.InvitePeopleState
|
import io.element.android.features.invitepeople.api.InvitePeopleState
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
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.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
data class DefaultInvitePeopleState(
|
data class DefaultInvitePeopleState(
|
||||||
|
val room: AsyncData<Unit>,
|
||||||
override val canInvite: Boolean,
|
override val canInvite: Boolean,
|
||||||
val searchQuery: String,
|
val searchQuery: String,
|
||||||
val showSearchLoader: Boolean,
|
val showSearchLoader: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.invitepeople.impl
|
package io.element.android.features.invitepeople.impl
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
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.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
|
|
@ -66,6 +67,7 @@ internal class DefaultInvitePeopleStateProvider : PreviewParameterProvider<Defau
|
||||||
),
|
),
|
||||||
showSearchLoader = true,
|
showSearchLoader = true,
|
||||||
),
|
),
|
||||||
|
aDefaultInvitePeopleState(room = AsyncData.Failure(Exception("Room not found"))),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,6 +86,7 @@ private fun anInvitableUser(
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun aDefaultInvitePeopleState(
|
private fun aDefaultInvitePeopleState(
|
||||||
|
room: AsyncData<Unit> = AsyncData.Success(Unit),
|
||||||
canInvite: Boolean = false,
|
canInvite: Boolean = false,
|
||||||
searchQuery: String = "",
|
searchQuery: String = "",
|
||||||
searchResults: SearchBarResultState<ImmutableList<InvitableUser>> = SearchBarResultState.Initial(),
|
searchResults: SearchBarResultState<ImmutableList<InvitableUser>> = SearchBarResultState.Initial(),
|
||||||
|
|
@ -92,6 +95,7 @@ private fun aDefaultInvitePeopleState(
|
||||||
showSearchLoader: Boolean = false,
|
showSearchLoader: Boolean = false,
|
||||||
): DefaultInvitePeopleState {
|
): DefaultInvitePeopleState {
|
||||||
return DefaultInvitePeopleState(
|
return DefaultInvitePeopleState(
|
||||||
|
room = room,
|
||||||
canInvite = canInvite,
|
canInvite = canInvite,
|
||||||
searchQuery = searchQuery,
|
searchQuery = searchQuery,
|
||||||
searchResults = searchResults,
|
searchResults = searchResults,
|
||||||
|
|
|
||||||
|
|
@ -8,19 +8,24 @@
|
||||||
package io.element.android.features.invitepeople.impl
|
package io.element.android.features.invitepeople.impl
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
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.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.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.designsystem.components.async.AsyncFailure
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncLoading
|
import io.element.android.libraries.designsystem.components.async.AsyncLoading
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
|
@ -42,9 +47,39 @@ import kotlinx.collections.immutable.ImmutableList
|
||||||
fun InvitePeopleView(
|
fun InvitePeopleView(
|
||||||
state: DefaultInvitePeopleState,
|
state: DefaultInvitePeopleState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
when (state.room) {
|
||||||
|
is AsyncData.Failure -> InvitePeopleViewError(state.room.error, modifier)
|
||||||
|
AsyncData.Uninitialized,
|
||||||
|
is AsyncData.Loading,
|
||||||
|
is AsyncData.Success -> InvitePeopleContentView(state, modifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InvitePeopleViewError(
|
||||||
|
error: Throwable,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
AsyncFailure(
|
||||||
|
throwable = error,
|
||||||
|
onRetry = null,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun InvitePeopleContentView(
|
||||||
|
state: DefaultInvitePeopleState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxSize(),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
InvitePeopleSearchBar(
|
InvitePeopleSearchBar(
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,21 @@ package io.element.android.features.invitepeople.impl
|
||||||
import app.cash.turbine.ReceiveTurbine
|
import app.cash.turbine.ReceiveTurbine
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
import io.element.android.features.invitepeople.api.InvitePeopleEvents
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
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.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomMemberList
|
import io.element.android.libraries.matrix.test.room.aRoomMemberList
|
||||||
|
|
@ -54,7 +60,7 @@ internal class DefaultInvitePeoplePresenterTest {
|
||||||
val presenter = createDefaultInvitePeoplePresenter()
|
val presenter = createDefaultInvitePeoplePresenter()
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitItemAsDefault()
|
val initialState = awaitItemAsDefault()
|
||||||
|
assertThat(initialState.room).isEqualTo(AsyncData.Success(Unit))
|
||||||
assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java)
|
assertThat(initialState.searchResults).isInstanceOf(SearchBarResultState.Initial::class.java)
|
||||||
assertThat(initialState.isSearchActive).isFalse()
|
assertThat(initialState.isSearchActive).isFalse()
|
||||||
assertThat(initialState.canInvite).isFalse()
|
assertThat(initialState.canInvite).isFalse()
|
||||||
|
|
@ -452,6 +458,40 @@ internal class DefaultInvitePeoplePresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient`() = runTest {
|
||||||
|
val matrixClient = FakeMatrixClient().apply {
|
||||||
|
givenGetRoomResult(A_ROOM_ID, FakeJoinedRoom())
|
||||||
|
}
|
||||||
|
val presenter = createDefaultInvitePeoplePresenter(
|
||||||
|
joinedRoom = null,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
matrixClient = matrixClient,
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitItemAsDefault()
|
||||||
|
assertThat(initialState.room.isLoading()).isTrue()
|
||||||
|
val finalState = awaitItemAsDefault()
|
||||||
|
assertThat(finalState.room).isEqualTo(AsyncData.Success(Unit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - when joinedRoom is not provided, it is retrieved on the MatrixClient - error case`() = runTest {
|
||||||
|
val matrixClient = FakeMatrixClient()
|
||||||
|
val presenter = createDefaultInvitePeoplePresenter(
|
||||||
|
joinedRoom = null,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
matrixClient = matrixClient,
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitItemAsDefault()
|
||||||
|
assertThat(initialState.room.isLoading()).isTrue()
|
||||||
|
val finalState = awaitItemAsDefault()
|
||||||
|
assertThat(finalState.room.errorOrNull()?.message).isEqualTo("Room not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun FakeUserRepository.emitStateWithUsers(
|
private suspend fun FakeUserRepository.emitStateWithUsers(
|
||||||
users: List<MatrixUser>,
|
users: List<MatrixUser>,
|
||||||
isSearching: Boolean = false
|
isSearching: Boolean = false
|
||||||
|
|
@ -484,19 +524,24 @@ private suspend fun <T> ReceiveTurbine<T>.awaitItemAsDefault(): DefaultInvitePeo
|
||||||
fun TestScope.createDefaultInvitePeoplePresenter(
|
fun TestScope.createDefaultInvitePeoplePresenter(
|
||||||
roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()),
|
roomMembersState: RoomMembersState = RoomMembersState.Ready(aRoomMemberList()),
|
||||||
inviteUserResult: (UserId) -> Result<Unit> = { lambdaError() },
|
inviteUserResult: (UserId) -> Result<Unit> = { lambdaError() },
|
||||||
|
joinedRoom: JoinedRoom? = FakeJoinedRoom(
|
||||||
|
inviteUserResult = inviteUserResult,
|
||||||
|
).apply {
|
||||||
|
givenRoomMembersState(roomMembersState)
|
||||||
|
},
|
||||||
|
roomId: RoomId = A_ROOM_ID,
|
||||||
userRepository: UserRepository = FakeUserRepository(),
|
userRepository: UserRepository = FakeUserRepository(),
|
||||||
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
|
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
|
||||||
appErrorStateService: AppErrorStateService = FakeAppErrorStateService(),
|
appErrorStateService: AppErrorStateService = FakeAppErrorStateService(),
|
||||||
|
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||||
): DefaultInvitePeoplePresenter {
|
): DefaultInvitePeoplePresenter {
|
||||||
return DefaultInvitePeoplePresenter(
|
return DefaultInvitePeoplePresenter(
|
||||||
room = FakeJoinedRoom(
|
joinedRoom = joinedRoom,
|
||||||
inviteUserResult = inviteUserResult,
|
roomId = roomId,
|
||||||
).apply {
|
|
||||||
givenRoomMembersState(roomMembersState)
|
|
||||||
},
|
|
||||||
userRepository = userRepository,
|
userRepository = userRepository,
|
||||||
coroutineDispatchers = coroutineDispatchers,
|
coroutineDispatchers = coroutineDispatchers,
|
||||||
coroutineScope = backgroundScope,
|
sessionCoroutineScope = backgroundScope,
|
||||||
appErrorStateService = appErrorStateService,
|
appErrorStateService = appErrorStateService,
|
||||||
|
matrixClient = matrixClient,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ class RoomInviteMembersNode @AssistedInject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val invitePeoplePresenter = invitePeoplePresenterFactory.create(room)
|
private val invitePeoplePresenter = invitePeoplePresenterFactory.create(
|
||||||
|
joinedRoom = room,
|
||||||
|
roomId = room.roomId,
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
|
|
|
||||||
|
|
@ -160,3 +160,17 @@ suspend inline fun <T> runUpdatingState(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <T, R> AsyncData<T>.map(
|
||||||
|
transform: (T?) -> R,
|
||||||
|
): AsyncData<R> {
|
||||||
|
return when (this) {
|
||||||
|
is AsyncData.Failure -> AsyncData.Failure(
|
||||||
|
error = error,
|
||||||
|
prevData = transform(prevData)
|
||||||
|
)
|
||||||
|
is AsyncData.Loading -> AsyncData.Loading(transform(prevData))
|
||||||
|
is AsyncData.Success -> AsyncData.Success(transform(data))
|
||||||
|
AsyncData.Uninitialized -> AsyncData.Uninitialized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue