Let HomeserverResolver emit the List and not the Async.
This commit is contained in:
parent
f7fbab6ea7
commit
f7b20e2373
2 changed files with 33 additions and 30 deletions
|
|
@ -17,7 +17,6 @@
|
|||
package io.element.android.features.login.impl.resolver
|
||||
|
||||
import io.element.android.features.login.impl.resolver.network.WellknownRequest
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
|
|
@ -26,7 +25,6 @@ import io.element.android.libraries.core.uri.isValidUrl
|
|||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -42,24 +40,20 @@ class HomeserverResolver @Inject constructor(
|
|||
private val wellknownRequest: WellknownRequest,
|
||||
) {
|
||||
|
||||
suspend fun resolve(userInput: String): Flow<Async<List<HomeserverData>>> = flow {
|
||||
suspend fun resolve(userInput: String): Flow<List<HomeserverData>> = flow {
|
||||
val flowContext = currentCoroutineContext()
|
||||
emit(Async.Uninitialized)
|
||||
// Debounce
|
||||
delay(300)
|
||||
val trimmedUserInput = userInput.trim()
|
||||
if (trimmedUserInput.length < 4) return@flow
|
||||
emit(Async.Loading())
|
||||
val candidateBase = trimmedUserInput.ensureProtocol().removeSuffix("/")
|
||||
val list = getUrlCandidates(candidateBase)
|
||||
val currentList = Collections.synchronizedList(mutableListOf<HomeserverData>())
|
||||
// Run all the requests in parallel
|
||||
withContext(dispatchers.io) {
|
||||
list.map {
|
||||
list.map { url ->
|
||||
async {
|
||||
val wellKnown = tryOrNull {
|
||||
withTimeout(5000) {
|
||||
wellknownRequest.execute(it)
|
||||
wellknownRequest.execute(url)
|
||||
}
|
||||
}
|
||||
val isValid = wellKnown?.isValid().orFalse()
|
||||
|
|
@ -68,35 +62,29 @@ class HomeserverResolver @Inject constructor(
|
|||
// Emit the list as soon as possible
|
||||
currentList.add(
|
||||
HomeserverData(
|
||||
homeserverUrl = it,
|
||||
homeserverUrl = url,
|
||||
isWellknownValid = true,
|
||||
supportSlidingSync = supportSlidingSync
|
||||
)
|
||||
)
|
||||
withContext(flowContext) {
|
||||
emit(Async.Success(currentList))
|
||||
emit(currentList.toList())
|
||||
}
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
// If list is empty, and the user has entered an URL, do not block the user.
|
||||
if (currentList.isEmpty()) {
|
||||
if (trimmedUserInput.isValidUrl()) {
|
||||
emit(
|
||||
Async.Success(
|
||||
listOf(
|
||||
HomeserverData(
|
||||
homeserverUrl = trimmedUserInput,
|
||||
isWellknownValid = false,
|
||||
supportSlidingSync = false,
|
||||
)
|
||||
)
|
||||
if (currentList.isEmpty() && trimmedUserInput.isValidUrl()) {
|
||||
emit(
|
||||
listOf(
|
||||
HomeserverData(
|
||||
homeserverUrl = trimmedUserInput,
|
||||
isWellknownValid = false,
|
||||
supportSlidingSync = false,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
emit(Async.Uninitialized)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.login.impl.screens.searchaccountprovider
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -28,6 +29,9 @@ import io.element.android.features.login.impl.resolver.HomeserverData
|
|||
import io.element.android.features.login.impl.resolver.HomeserverResolver
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class SearchAccountProviderPresenter @Inject constructor(
|
||||
|
|
@ -42,14 +46,12 @@ class SearchAccountProviderPresenter @Inject constructor(
|
|||
}
|
||||
val changeServerState = changeServerPresenter.present()
|
||||
|
||||
var data: Async<List<HomeserverData>> by remember {
|
||||
val data: MutableState<Async<List<HomeserverData>>> = remember {
|
||||
mutableStateOf(Async.Uninitialized)
|
||||
}
|
||||
|
||||
LaunchedEffect(userInput) {
|
||||
homeserverResolver.resolve(userInput).collect {
|
||||
data = it
|
||||
}
|
||||
onUserInput(userInput, data)
|
||||
}
|
||||
|
||||
fun handleEvents(event: SearchAccountProviderEvents) {
|
||||
|
|
@ -62,9 +64,22 @@ class SearchAccountProviderPresenter @Inject constructor(
|
|||
|
||||
return SearchAccountProviderState(
|
||||
userInput = userInput,
|
||||
userInputResult = data,
|
||||
userInputResult = data.value,
|
||||
changeServerState = changeServerState,
|
||||
eventSink = ::handleEvents
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.onUserInput(userInput: String, data: MutableState<Async<List<HomeserverData>>>) = launch {
|
||||
data.value = Async.Uninitialized
|
||||
// Debounce
|
||||
delay(300)
|
||||
data.value = Async.Loading()
|
||||
homeserverResolver.resolve(userInput).collect {
|
||||
data.value = Async.Success(it)
|
||||
}
|
||||
if (data.value !is Async.Success) {
|
||||
data.value = Async.Uninitialized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue