@@ -9,6 +9,7 @@ package io.element.android.features.createroom.impl.joinbyaddress
99
1010import androidx.compose.runtime.Composable
1111import androidx.compose.runtime.LaunchedEffect
12+ import androidx.compose.runtime.derivedStateOf
1213import androidx.compose.runtime.getValue
1314import androidx.compose.runtime.mutableStateOf
1415import androidx.compose.runtime.remember
@@ -22,9 +23,13 @@ import io.element.android.libraries.architecture.Presenter
2223import io.element.android.libraries.core.data.tryOrNull
2324import io.element.android.libraries.matrix.api.MatrixClient
2425import io.element.android.libraries.matrix.api.core.RoomAlias
25- import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
26+ import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
2627import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
2728import kotlinx.coroutines.delay
29+ import kotlinx.coroutines.withTimeoutOrNull
30+ import kotlin.time.Duration.Companion.seconds
31+
32+ private const val ADDRESS_RESOLVE_TIMEOUT_IN_SECONDS = 10
2833
2934class JoinRoomByAddressPresenter @AssistedInject constructor(
3035 @Assisted private val navigator : CreateRoomNavigator ,
@@ -40,58 +45,94 @@ class JoinRoomByAddressPresenter @AssistedInject constructor(
4045 @Composable
4146 override fun present (): JoinRoomByAddressState {
4247 var address by remember { mutableStateOf(" " ) }
43- var addressState by remember { mutableStateOf<RoomAddressState >(RoomAddressState .Unknown ) }
48+ var internalAddressState by remember { mutableStateOf<RoomAddressState >(RoomAddressState .Unknown ) }
49+ var validateAddress: Boolean by remember { mutableStateOf(false ) }
4450
4551 fun handleEvents (event : JoinRoomByAddressEvents ) {
4652 when (event) {
4753 JoinRoomByAddressEvents .Continue -> {
48- navigator.onDismissJoinRoomByAddress()
49- navigator.onOpenRoom(RoomIdOrAlias .Alias (RoomAlias (address)))
54+ when (val currentState = internalAddressState) {
55+ is RoomAddressState .RoomFound -> onRoomFound(currentState)
56+ else -> validateAddress = true
57+ }
5058 }
5159 JoinRoomByAddressEvents .Dismiss -> navigator.onDismissJoinRoomByAddress()
5260 is JoinRoomByAddressEvents .UpdateAddress -> {
61+ validateAddress = false
5362 address = event.address.trim()
5463 }
5564 }
5665 }
5766
5867 RoomAddressStateEffect (
5968 fullAddress = address,
60- onRoomAddressStateChange = { addressState = it }
69+ onRoomAddressStateChange = { addressState ->
70+ internalAddressState = addressState
71+ if (addressState is RoomAddressState .RoomFound && validateAddress) {
72+ onRoomFound(addressState)
73+ }
74+ }
6175 )
6276
77+ val addressState by remember {
78+ derivedStateOf {
79+ // We only want to show the "RoomFound" state as long as the user didn't validate the address.
80+ if (validateAddress || internalAddressState is RoomAddressState .RoomFound ) {
81+ internalAddressState
82+ } else {
83+ RoomAddressState .Unknown
84+ }
85+ }
86+ }
87+
6388 return JoinRoomByAddressState (
6489 address = address,
6590 addressState = addressState,
6691 eventSink = ::handleEvents
6792 )
6893 }
6994
95+ private fun onRoomFound (state : RoomAddressState .RoomFound ) {
96+ navigator.onDismissJoinRoomByAddress()
97+ navigator.onOpenRoom(state.resolved.roomId.toRoomIdOrAlias())
98+ }
99+
70100 @Composable
71101 private fun RoomAddressStateEffect (
72102 fullAddress : String ,
73103 onRoomAddressStateChange : (RoomAddressState ) -> Unit ,
74104 ) {
75105 val onChange by rememberUpdatedState(onRoomAddressStateChange)
76106 LaunchedEffect (fullAddress) {
77- if (fullAddress.isEmpty()) {
78- onChange(RoomAddressState .Unknown )
79- return @LaunchedEffect
80- }
81- // debounce the room address validation
107+ // Whenever the address changes, reset the state to unknown
108+ onChange(RoomAddressState .Unknown )
109+ // debounce the room address resolution
82110 delay(300 )
83111 val roomAlias = tryOrNull { RoomAlias (fullAddress) }
84- if (roomAlias == null || ! roomAliasHelper.isRoomAliasValid(roomAlias)) {
85- onChange(RoomAddressState .Invalid )
112+ if (roomAlias != null && roomAliasHelper.isRoomAliasValid(roomAlias)) {
113+ onChange(RoomAddressState .Resolving )
114+ onChange(client.resolveRoomAddress(roomAlias))
86115 } else {
87- onChange(RoomAddressState .Valid (matchingRoomFound = false ))
88- client.resolveRoomAlias(roomAlias)
89- .onSuccess { resolved ->
90- onChange(RoomAddressState .Valid (matchingRoomFound = resolved.isPresent))
91- }
116+ onChange(RoomAddressState .Invalid )
92117 }
93118 }
94119 }
120+
121+ private suspend fun MatrixClient.resolveRoomAddress (roomAlias : RoomAlias ): RoomAddressState {
122+ return withTimeoutOrNull(ADDRESS_RESOLVE_TIMEOUT_IN_SECONDS .seconds) {
123+ resolveRoomAlias(roomAlias)
124+ .fold(
125+ onSuccess = { resolved ->
126+ if (resolved.isPresent) {
127+ RoomAddressState .RoomFound (resolved.get())
128+ } else {
129+ RoomAddressState .RoomNotFound
130+ }
131+ },
132+ onFailure = { _ -> RoomAddressState .RoomNotFound }
133+ )
134+ } ? : RoomAddressState .RoomNotFound
135+ }
95136}
96137
97138
0 commit comments