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