From 51a39909dcf783fc5b787ee98381f90d3eaccbff Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Apr 2021 18:20:01 +0200 Subject: [PATCH] Login UX flow: warning if no profile can ba found --- .../app/core/extensions/MvRxExtension.kt | 32 +++++++++++++++++++ .../login2/LoginFragment2SigninPassword.kt | 12 +++++-- .../app/features/login2/LoginViewModel2.kt | 16 ++++------ .../app/features/login2/LoginViewState2.kt | 4 ++- .../fragment_login_2_signin_password.xml | 11 +++++++ vector/src/main/res/values/colors.xml | 1 + .../src/main/res/values/strings_login_v2.xml | 2 ++ 7 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/extensions/MvRxExtension.kt diff --git a/vector/src/main/java/im/vector/app/core/extensions/MvRxExtension.kt b/vector/src/main/java/im/vector/app/core/extensions/MvRxExtension.kt new file mode 100644 index 0000000000..9daf16a589 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/extensions/MvRxExtension.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 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.core.extensions + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Success + +/** + * It maybe already exist somewhere but I cannot find it + */ +suspend fun tryAsync(block: suspend () -> T): Async { + return try { + Success(block.invoke()) + } catch (failure: Throwable) { + Fail(failure) + } +} diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginFragment2SigninPassword.kt b/vector/src/main/java/im/vector/app/features/login2/LoginFragment2SigninPassword.kt index 9517685a9e..39701cb01b 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginFragment2SigninPassword.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginFragment2SigninPassword.kt @@ -23,6 +23,8 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.autofill.HintConstants +import androidx.core.view.isVisible +import com.airbnb.mvrx.Fail import com.jakewharton.rxbinding3.widget.textChanges import im.vector.app.R import im.vector.app.core.extensions.hideKeyboard @@ -31,8 +33,10 @@ import im.vector.app.databinding.FragmentLogin2SigninPasswordBinding import im.vector.app.features.home.AvatarRenderer import io.reactivex.rxkotlin.subscribeBy import org.matrix.android.sdk.api.auth.login.LoginProfileInfo +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isInvalidPassword import javax.inject.Inject +import javax.net.ssl.HttpsURLConnection /** * In this screen: @@ -103,13 +107,17 @@ class LoginFragment2SigninPassword @Inject constructor( // Name and avatar views.loginWelcomeBack.text = getString( R.string.login_welcome_back, - state.loginProfileInfo?.displayName?.takeIf { it.isNotBlank() } ?: state.userIdentifier() + state.loginProfileInfo()?.displayName?.takeIf { it.isNotBlank() } ?: state.userIdentifier() ) avatarRenderer.render( - profileInfo = state.loginProfileInfo ?: LoginProfileInfo(state.userIdentifier(), null, null), + profileInfo = state.loginProfileInfo() ?: LoginProfileInfo(state.userIdentifier(), null, null), imageView = views.loginUserIcon ) + + views.loginWelcomeBackWarning.isVisible = ((state.loginProfileInfo as? Fail) + ?.error as? Failure.ServerError) + ?.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */ } private fun setupSubmitButton() { diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt index b09fc4ac8a..a6f87f74c7 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginViewModel2.kt @@ -21,6 +21,7 @@ import android.net.Uri import androidx.fragment.app.FragmentActivity import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.ActivityViewModelContext +import com.airbnb.mvrx.Loading import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted @@ -30,6 +31,7 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.tryAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.ensureTrailingSlash @@ -665,17 +667,11 @@ class LoginViewModel2 @AssistedInject constructor( val safeLoginWizard = loginWizard if (safeLoginWizard != null) { - try { - val info = safeLoginWizard.getProfileInfo(username) - setState { - copy( - loginProfileInfo = info - ) - } - } catch (failure: Throwable) { - // Ignore error - // TODO 404 may indicates that the user does not exist, so there is a mistake in the id + setState { copy(loginProfileInfo = Loading()) } + val result = tryAsync { + safeLoginWizard.getProfileInfo(username) } + setState { copy(loginProfileInfo = result) } } } diff --git a/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt b/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt index 3c631af18c..261fd417ee 100644 --- a/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt +++ b/vector/src/main/java/im/vector/app/features/login2/LoginViewState2.kt @@ -16,8 +16,10 @@ package im.vector.app.features.login2 +import com.airbnb.mvrx.Async import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.PersistState +import com.airbnb.mvrx.Uninitialized import im.vector.app.core.extensions.toReducedUrl import im.vector.app.features.login.LoginMode import org.matrix.android.sdk.api.MatrixPatterns @@ -45,7 +47,7 @@ data class LoginViewState2( val deviceId: String? = null, // Network result - val loginProfileInfo: LoginProfileInfo? = null, + val loginProfileInfo: Async = Uninitialized, // True on Matrix.org val isNumericOnlyUserIdForbidden: Boolean = false, diff --git a/vector/src/main/res/layout/fragment_login_2_signin_password.xml b/vector/src/main/res/layout/fragment_login_2_signin_password.xml index 638314cf3f..bc23420312 100644 --- a/vector/src/main/res/layout/fragment_login_2_signin_password.xml +++ b/vector/src/main/res/layout/fragment_login_2_signin_password.xml @@ -31,6 +31,17 @@ android:textAppearance="@style/TextAppearance.Vector.Login.Text" tools:text="Welcome back user!" /> + + #70BF56 #ff4b55 + #ff812d #ff4b55 #2f9edb diff --git a/vector/src/main/res/values/strings_login_v2.xml b/vector/src/main/res/values/strings_login_v2.xml index a32912cc00..73f5ba03b4 100644 --- a/vector/src/main/res/values/strings_login_v2.xml +++ b/vector/src/main/res/values/strings_login_v2.xml @@ -25,6 +25,8 @@ Create a new account I already have an account + Warning: no profile information can be retrieved with this Matrix identifier. Please check that there is no mistake. + We just sent an email to %1$s. Click on the link it contains to continue the account creation. Congratulations!