extracting the login error handling to its own class

This commit is contained in:
Adam Brown 2022-05-09 16:04:02 +01:00
parent d1bafc531e
commit fb1a686f90
4 changed files with 94 additions and 20 deletions

View file

@ -101,6 +101,9 @@ import im.vector.app.features.onboarding.ftueauth.FtueAuthAccountCreatedFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthCaptchaFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseDisplayNameFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthChooseProfilePictureFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedLoginFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedRegisterFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthCombinedServerSelectionFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthEmailEntryFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthGenericTextInputFormFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthLegacyStyleCaptchaFragment
@ -521,6 +524,21 @@ interface FragmentModule {
@FragmentKey(FtueAuthPersonalizationCompleteFragment::class)
fun bindFtueAuthPersonalizationCompleteFragment(fragment: FtueAuthPersonalizationCompleteFragment): Fragment
@Binds
@IntoMap
@FragmentKey(FtueAuthCombinedLoginFragment::class)
fun bindFtueAuthCombinedLoginFragment(fragment: FtueAuthCombinedLoginFragment): Fragment
@Binds
@IntoMap
@FragmentKey(FtueAuthCombinedRegisterFragment::class)
fun bindFtueAuthCombinedRegisterFragment(fragment: FtueAuthCombinedRegisterFragment): Fragment
@Binds
@IntoMap
@FragmentKey(FtueAuthCombinedServerSelectionFragment::class)
fun bindFtueAuthCombinedServerSelectionFragment(fragment: FtueAuthCombinedServerSelectionFragment): Fragment
@Binds
@IntoMap
@FragmentKey(UserListFragment::class)

View file

@ -29,7 +29,6 @@ import im.vector.app.R
import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.hasContentFlow
import im.vector.app.core.extensions.hasSurroundingSpaces
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.hidePassword
import im.vector.app.core.extensions.realignPercentagesToParent
@ -45,13 +44,11 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.api.failure.isInvalidUsername
import org.matrix.android.sdk.api.failure.isLoginEmailUnknown
import javax.inject.Inject
class FtueAuthCombinedLoginFragment @Inject constructor(
private val loginFieldsValidation: LoginFieldsValidation
private val loginFieldsValidation: LoginFieldsValidation,
private val loginErrorParser: LoginErrorParser
) : AbstractSSOFtueAuthFragment<FragmentFtueCombinedLoginBinding>() {
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueCombinedLoginBinding {
@ -116,20 +113,10 @@ class FtueAuthCombinedLoginFragment @Inject constructor(
override fun onError(throwable: Throwable) {
// Trick to display the error without text.
views.loginInput.error = " "
when {
throwable.isInvalidUsername() -> {
views.loginInput.error = errorFormatter.toHumanReadable(throwable)
}
throwable.isLoginEmailUnknown() -> {
views.loginInput.error = getString(R.string.login_login_with_email_error)
}
throwable.isInvalidPassword() && views.loginPasswordInput.hasSurroundingSpaces() -> {
views.loginPasswordInput.error = getString(R.string.auth_invalid_login_param_space_in_password)
}
else -> {
super.onError(throwable)
}
}
loginErrorParser.parse(throwable, views.loginPasswordInput.content())
.onUnknown { super.onError(it) }
.onUsernameOrIdError { views.loginInput.error = it }
.onPasswordError { views.loginPasswordInput.error = it }
}
override fun updateWithState(state: OnboardingViewState) {

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.onboarding.ftueauth
import im.vector.app.R
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.onboarding.ftueauth.LoginErrorParser.LoginErrorResult
import org.matrix.android.sdk.api.failure.isInvalidPassword
import org.matrix.android.sdk.api.failure.isInvalidUsername
import org.matrix.android.sdk.api.failure.isLoginEmailUnknown
import javax.inject.Inject
class LoginErrorParser @Inject constructor(
private val errorFormatter: ErrorFormatter,
private val stringProvider: StringProvider,
) {
fun parse(throwable: Throwable, password: String): LoginErrorResult {
return when {
throwable.isInvalidUsername() -> {
LoginErrorResult(throwable, usernameOrIdError = errorFormatter.toHumanReadable(throwable))
}
throwable.isLoginEmailUnknown() -> {
LoginErrorResult(throwable, usernameOrIdError = stringProvider.getString(R.string.login_login_with_email_error))
}
throwable.isInvalidPassword() && password.hasSurroundingSpaces() -> {
LoginErrorResult(throwable, passwordError = stringProvider.getString(R.string.auth_invalid_login_param_space_in_password))
}
else -> {
LoginErrorResult(throwable)
}
}
}
private fun String.hasSurroundingSpaces() = trim() != this
data class LoginErrorResult(val cause: Throwable, val usernameOrIdError: String? = null, val passwordError: String? = null)
}
fun LoginErrorResult.onUnknown(action: (Throwable) -> Unit): LoginErrorResult {
when {
usernameOrIdError == null && passwordError == null -> action(cause)
}
return this
}
fun LoginErrorResult.onUsernameOrIdError(action: (String) -> Unit): LoginErrorResult {
usernameOrIdError?.let(action)
return this
}
fun LoginErrorResult.onPasswordError(action: (String) -> Unit): LoginErrorResult {
passwordError?.let(action)
return this
}

View file

@ -47,7 +47,7 @@ class LoginFieldsValidation @Inject constructor(
fun LoginValidationResult.onValid(action: (String, String) -> Unit): LoginValidationResult {
when {
usernameOrIdError != null && passwordError != null -> action(usernameOrId, password)
usernameOrIdError == null && passwordError == null -> action(usernameOrId, password)
}
return this
}