Ensure user cannot select unsupported homeserver. In this case show the appropriate error (parity with iOS)

This commit is contained in:
Benoit Marty
2025-11-06 15:07:44 +01:00
committed by Benoit Marty
parent 6006537bdc
commit c397c8e2c3
4 changed files with 45 additions and 2 deletions

View File

@@ -13,6 +13,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import dev.zacsweers.metro.Inject
import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl
import io.element.android.features.login.impl.accountprovider.AccountProvider
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
@@ -60,7 +61,13 @@ class ChangeServerPresenter(
title = data.title,
accountProviderUrl = data.url,
)
authenticationService.setHomeserver(data.url).getOrThrow()
val details = authenticationService.setHomeserver(data.url).getOrThrow()
if (details.supportsOidcLogin.not() && details.supportsPasswordLogin.not()) {
// Unsupported homeserver
throw ChangeServerError.Error(
messageId = R.string.screen_login_error_unsupported_authentication,
)
}
// Homeserver is valid, remember user choice
accountProviderDataSource.userSelection(data)
}.runCatchingUpdatingState(changeServerAction, errorTransform = ChangeServerError::from)

View File

@@ -8,6 +8,7 @@
package io.element.android.features.login.impl.changeserver
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.error.ChangeServerError
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.ui.strings.CommonStrings
@@ -34,6 +35,13 @@ open class ChangeServerStateProvider : PreviewParameterProvider<ChangeServerStat
),
)
),
aChangeServerState(
changeServerAction = AsyncData.Failure(
ChangeServerError.Error(
R.string.screen_login_error_unsupported_authentication
)
)
),
)
}

View File

@@ -40,6 +40,7 @@ sealed class ChangeServerError : Exception() {
companion object {
fun from(error: Throwable): ChangeServerError = when (error) {
is ChangeServerError -> error
is AuthenticationException.SlidingSyncVersion -> SlidingSyncAlert
is AuthenticationException.Oidc -> Error(messageStr = error.message)
is AccountProviderAccessException.NeedElementProException -> NeedElementPro(

View File

@@ -10,6 +10,7 @@ package io.element.android.features.login.impl.changeserver
import com.google.common.truth.Truth.assertThat
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.impl.R
import io.element.android.features.login.impl.aMatrixHomeServerDetails
import io.element.android.features.login.impl.accesscontrol.DefaultAccountProviderAccessControl
import io.element.android.features.login.impl.accountprovider.AccountProvider
@@ -49,7 +50,7 @@ class ChangeServerPresenterTest {
fun `present - change server ok`() = runTest {
val authenticationService = FakeMatrixAuthenticationService(
setHomeserverResult = {
Result.success(aMatrixHomeServerDetails())
Result.success(aMatrixHomeServerDetails(supportsOidcLogin = true))
},
)
createPresenter(
@@ -95,6 +96,32 @@ class ChangeServerPresenterTest {
}
}
@Test
fun `present - change server unsupported server`() = runTest {
val authenticationService = FakeMatrixAuthenticationService(
setHomeserverResult = {
Result.success(aMatrixHomeServerDetails())
},
)
createPresenter(
enterpriseService = FakeEnterpriseService(
isAllowedToConnectToHomeserverResult = { true },
),
authenticationService = authenticationService,
).test {
val initialState = awaitItem()
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(AccountProvider(url = A_HOMESERVER_URL)))
val loadingState = awaitItem()
assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java)
val failureState = awaitItem()
assertThat(failureState.changeServerAction).isInstanceOf(AsyncData.Failure::class.java)
assertThat(failureState.changeServerAction.errorOrNull()).isEqualTo(
ChangeServerError.Error(R.string.screen_login_error_unsupported_authentication)
)
}
}
@Test
fun `present - change server not allowed error`() = runTest {
val isAllowedToConnectToHomeserverResult = lambdaRecorder<String, Boolean> { false }