Room navigation : reuse accept/decline presentation logic

This commit is contained in:
ganfra 2024-04-09 14:16:17 +02:00
parent 7d59884922
commit 6a255a1b10
23 changed files with 220 additions and 79 deletions

View file

@ -350,6 +350,10 @@ class LoggedInFlowNode @AssistedInject constructor(
backstack.pop()
}
override fun onInviteClicked(roomId: RoomId) {
backstack.push(NavTarget.Room(roomId))
}
override fun onInviteAccepted(roomId: RoomId) {
backstack.push(NavTarget.Room(roomId))
}

View file

@ -24,6 +24,7 @@ import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.invite.api.response.AcceptDeclineInviteView
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.SessionScope
@ -34,6 +35,7 @@ class JoinRoomNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: JoinRoomPresenter.Factory,
private val acceptDeclineInviteView: AcceptDeclineInviteView,
) : Node(buildContext, plugins = plugins) {
data class Inputs(
@ -51,5 +53,11 @@ class JoinRoomNode @AssistedInject constructor(
onBackPressed = ::navigateUp,
modifier = modifier
)
acceptDeclineInviteView.Render(
state = state.acceptDeclineInviteState,
onInviteAccepted = {},
onInviteDeclined = { navigateUp() },
modifier = Modifier
)
}
}

View file

@ -20,16 +20,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.rememberCoroutineScope
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.features.invite.api.response.InviteData
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
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.CurrentUserMembership
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import kotlinx.coroutines.launch
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
@ -37,6 +38,7 @@ class JoinRoomPresenter @AssistedInject constructor(
@Assisted private val roomId: RoomId,
private val matrixClient: MatrixClient,
private val roomListService: RoomListService,
private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
) : Presenter<JoinRoomState> {
interface Factory {
@ -47,6 +49,7 @@ class JoinRoomPresenter @AssistedInject constructor(
override fun present(): JoinRoomState {
val userMembership by roomListService.getUserMembershipForRoom(roomId).collectAsState(initial = Optional.empty())
val joinAuthorisationStatus = joinAuthorisationStatus(userMembership)
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
val roomInfo by produceState<AsyncData<RoomInfo>>(initialValue = AsyncData.Uninitialized, key1 = userMembership) {
value = when {
userMembership.isPresent -> {
@ -56,6 +59,7 @@ class JoinRoomPresenter @AssistedInject constructor(
roomName = it.displayName,
roomAlias = it.alias,
memberCount = it.activeMemberCount,
isDirect = it.isDirect,
roomAvatarUrl = it.avatarUrl
)
}
@ -65,21 +69,17 @@ class JoinRoomPresenter @AssistedInject constructor(
}
}
val coroutineScope = rememberCoroutineScope()
fun handleEvents(event: JoinRoomEvents) {
when (event) {
JoinRoomEvents.AcceptInvite, JoinRoomEvents.JoinRoom -> {
coroutineScope.launch {
matrixClient.joinRoom(roomId)
}
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(roomInfo.toInviteData())
)
}
JoinRoomEvents.DeclineInvite -> {
coroutineScope.launch {
matrixClient.getRoom(roomId)?.use {
it.leave()
}
}
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(roomInfo.toInviteData())
)
}
}
}
@ -87,11 +87,21 @@ class JoinRoomPresenter @AssistedInject constructor(
return JoinRoomState(
roomInfo = roomInfo,
joinAuthorisationStatus = joinAuthorisationStatus,
currentAction = CurrentAction.None,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = ::handleEvents
)
}
private fun AsyncData<RoomInfo>.toInviteData(): InviteData {
return dataOrNull().let {
InviteData(
roomId = roomId,
roomName = it?.roomName ?: "",
isDirect = it?.isDirect ?: false
)
}
}
@Composable
private fun joinAuthorisationStatus(userMembership: Optional<CurrentUserMembership>): JoinAuthorisationStatus {
return when {

View file

@ -17,6 +17,7 @@
package io.element.android.appnav.room.join
import androidx.compose.runtime.Immutable
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
@ -26,7 +27,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
data class JoinRoomState(
val roomInfo: AsyncData<RoomInfo>,
val joinAuthorisationStatus: JoinAuthorisationStatus,
val currentAction: CurrentAction,
val acceptDeclineInviteState: AcceptDeclineInviteState,
val eventSink: (JoinRoomEvents) -> Unit
){
val showMemberCount = roomInfo.dataOrNull()?.memberCount != null
@ -37,6 +38,7 @@ data class RoomInfo(
val roomName: String,
val roomAlias: String?,
val memberCount: Long?,
val isDirect: Boolean,
val roomAvatarUrl: String?,
) {
fun avatarData(size: AvatarSize): AvatarData {
@ -55,7 +57,3 @@ enum class JoinAuthorisationStatus {
CanJoin,
Unknown,
}
sealed interface CurrentAction {
data object None : CurrentAction
}

View file

@ -17,6 +17,8 @@
package io.element.android.appnav.room.join
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.matrix.api.core.RoomId
@ -45,16 +47,17 @@ fun aJoinRoomState(
roomName = "Element x android",
roomAlias = "#exa:matrix.org",
memberCount = null,
isDirect = false,
roomAvatarUrl = null
)
),
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown,
currentAction: CurrentAction = CurrentAction.None,
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
eventSink: (JoinRoomEvents) -> Unit = {}
) = JoinRoomState(
roomInfo = roomInfo,
joinAuthorisationStatus = joinAuthorisationStatus,
currentAction = currentAction,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = eventSink
)

View file

@ -20,6 +20,7 @@ import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.appnav.room.join.JoinRoomPresenter
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
@ -32,13 +33,15 @@ object JoinRoomModule {
fun providesJoinRoomPresenterFactory(
roomListService: RoomListService,
client: MatrixClient,
acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
): JoinRoomPresenter.Factory {
return object : JoinRoomPresenter.Factory {
override fun create(roomId: RoomId): JoinRoomPresenter {
return JoinRoomPresenter(
roomId = roomId,
matrixClient = client,
roomListService = roomListService
roomListService = roomListService,
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
)
}
}