From e6df2b39b42ad0b24e253a80cc3153ac1a399823 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 26 Jul 2022 16:58:19 +0100 Subject: [PATCH 01/10] handling unverified email as a dialog error in the reset password flow with a friendly error message --- .../org/matrix/android/sdk/api/failure/Extensions.kt | 4 ++++ .../main/java/im/vector/app/core/error/ErrorFormatter.kt | 4 ++++ .../ftueauth/FtueAuthResetPasswordEntryFragment.kt | 9 ++++++++- vector/src/main/res/values/strings.xml | 1 + 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt index d3cc8fc8e4..6e198fb98c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/failure/Extensions.kt @@ -86,6 +86,10 @@ fun Throwable.isInvalidUIAAuth() = this is Failure.ServerError && fun Throwable.isHomeserverUnavailable() = this is Failure.NetworkConnection && this.ioException is UnknownHostException +fun Throwable.isMissingEmailVerification() = this is Failure.ServerError && + error.code == MatrixError.M_UNAUTHORIZED && + error.message == "Unable to get validated threepid" + /** * Try to convert to a RegistrationFlowResponse. Return null in the cases it's not possible */ diff --git a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt index 8fbd89a6c1..d9a08bd81a 100644 --- a/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt +++ b/vector/src/main/java/im/vector/app/core/error/ErrorFormatter.kt @@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.failure.MatrixError import org.matrix.android.sdk.api.failure.MatrixIdFailure import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.failure.isLimitExceededError +import org.matrix.android.sdk.api.failure.isMissingEmailVerification import org.matrix.android.sdk.api.session.identity.IdentityServiceError import java.net.HttpURLConnection import java.net.SocketTimeoutException @@ -105,6 +106,9 @@ class DefaultErrorFormatter @Inject constructor( throwable.error.message == "Not allowed to join this room" -> { stringProvider.getString(R.string.room_error_access_unauthorized) } + throwable.isMissingEmailVerification() -> { + stringProvider.getString(R.string.auth_reset_password_error_unverified) + } else -> { throwable.error.message.takeIf { it.isNotEmpty() } ?: throwable.error.code.takeIf { it.isNotEmpty() } diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt index 6282fded61..cede32008c 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt @@ -31,6 +31,8 @@ import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.databinding.FragmentFtueResetPasswordInputBinding import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingViewState +import org.matrix.android.sdk.api.failure.isInvalidPassword +import org.matrix.android.sdk.api.failure.isMissingEmailVerification @AndroidEntryPoint class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment() { @@ -61,7 +63,12 @@ class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment super.onError(throwable) + else -> { + views.newPasswordInput.error = errorFormatter.toHumanReadable(throwable) + } + } } override fun updateWithState(state: OnboardingViewState) { diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 8f0e0ac7ab..96ea65c5a7 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -524,6 +524,7 @@ This homeserver would like to make sure you are not a robot The email address linked to your account must be entered. Failed to verify email address: make sure you clicked the link in the email + Email not verified, check your inbox "Please review and accept the policies of this homeserver:" From 2dae13f6c8af66978c30a1fbf4e920036d431e13 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 26 Jul 2022 17:05:25 +0100 Subject: [PATCH 02/10] applying the password character limit to the keyboard done action --- .../ftueauth/FtueAuthCombinedRegisterFragment.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt index 639045b5c0..c69706a17b 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedRegisterFragment.kt @@ -75,7 +75,11 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu setupSubmitButton() views.createAccountRoot.realignPercentagesToParent() views.editServerButton.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.EditServerSelection)) } - views.createAccountPasswordInput.setOnImeDoneListener { submit() } + views.createAccountPasswordInput.setOnImeDoneListener { + if (canSubmit(views.createAccountInput.content(), views.createAccountPasswordInput.content())) { + submit() + } + } views.createAccountInput.onTextChange(viewLifecycleOwner) { viewModel.handle(OnboardingAction.ResetSelectedRegistrationUserName) @@ -87,15 +91,19 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu } } + private fun canSubmit(account: CharSequence, password: CharSequence): Boolean { + val accountIsValid = account.isNotEmpty() + val passwordIsValid = password.length >= MINIMUM_PASSWORD_LENGTH + return accountIsValid && passwordIsValid + } + private fun setupSubmitButton() { views.createAccountSubmit.setOnClickListener { submit() } views.createAccountInput.clearErrorOnChange(viewLifecycleOwner) views.createAccountPasswordInput.clearErrorOnChange(viewLifecycleOwner) combine(views.createAccountInput.editText().textChanges(), views.createAccountPasswordInput.editText().textChanges()) { account, password -> - val accountIsValid = account.isNotEmpty() - val passwordIsValid = password.length >= MINIMUM_PASSWORD_LENGTH - views.createAccountSubmit.isEnabled = accountIsValid && passwordIsValid + views.createAccountSubmit.isEnabled = canSubmit(account, password) }.launchIn(viewLifecycleOwner.lifecycleScope) } From 653c97b40d2b4b95280daa58b2a2b5b709e3e63e Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 26 Jul 2022 17:19:20 +0100 Subject: [PATCH 03/10] disabling the server url selection submit button when the selection is empty --- .../FtueAuthCombinedServerSelectionFragment.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt index bc44a7dbdb..502b9c771b 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt @@ -20,12 +20,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.inputmethod.EditorInfo import im.vector.app.R +import im.vector.app.core.extensions.associateContentStateWith import im.vector.app.core.extensions.clearErrorOnChange import im.vector.app.core.extensions.content import im.vector.app.core.extensions.editText import im.vector.app.core.extensions.realignPercentagesToParent +import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.core.extensions.toReducedUrl import im.vector.app.core.utils.ensureProtocol import im.vector.app.core.utils.ensureTrailingSlash @@ -53,19 +54,19 @@ class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFt views.chooseServerToolbar.setNavigationOnClickListener { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnBack)) } - views.chooseServerInput.editText?.setOnEditorActionListener { _, actionId, _ -> - when (actionId) { - EditorInfo.IME_ACTION_DONE -> { - updateServerUrl() - } + views.chooseServerInput.associateContentStateWith(button = views.chooseServerSubmit, enabledPredicate = { canSubmit(it) }) + views.chooseServerInput.setOnImeDoneListener { + if (canSubmit(views.chooseServerInput.content())) { + updateServerUrl() } - false } views.chooseServerGetInTouch.debouncedClicks { openUrlInExternalBrowser(requireContext(), getString(R.string.ftue_ems_url)) } views.chooseServerSubmit.debouncedClicks { updateServerUrl() } views.chooseServerInput.clearErrorOnChange(viewLifecycleOwner) } + private fun canSubmit(url: String) = url.isNotEmpty() + private fun updateServerUrl() { viewModel.handle(OnboardingAction.HomeServerChange.EditHomeServer(views.chooseServerInput.content().ensureProtocol().ensureTrailingSlash())) } From 616c1d780fa2079cf21c5701021ae22af1dc5cd9 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 09:36:12 +0100 Subject: [PATCH 04/10] updating sign in specific subtitle for the server selection screen --- .../ftueauth/FtueAuthCombinedServerSelectionFragment.kt | 9 +++++++++ .../layout/fragment_ftue_server_selection_combined.xml | 5 +++-- vector/src/main/res/values/strings.xml | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt index 502b9c771b..749aac2898 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthCombinedServerSelectionFragment.kt @@ -33,6 +33,7 @@ import im.vector.app.core.utils.ensureTrailingSlash import im.vector.app.core.utils.openUrlInExternalBrowser import im.vector.app.databinding.FragmentFtueServerSelectionCombinedBinding import im.vector.app.features.onboarding.OnboardingAction +import im.vector.app.features.onboarding.OnboardingFlow import im.vector.app.features.onboarding.OnboardingViewEvents import im.vector.app.features.onboarding.OnboardingViewState import org.matrix.android.sdk.api.failure.isHomeserverUnavailable @@ -76,6 +77,14 @@ class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFt } override fun updateWithState(state: OnboardingViewState) { + views.chooseServerHeaderSubtitle.setText( + when (state.onboardingFlow) { + OnboardingFlow.SignIn -> R.string.ftue_auth_choose_server_sign_in_subtitle + OnboardingFlow.SignUp -> R.string.ftue_auth_choose_server_subtitle + else -> throw IllegalStateException("Invalid flow state") + } + ) + if (views.chooseServerInput.content().isEmpty()) { val userUrlInput = state.selectedHomeserver.userFacingUrl?.toReducedUrlKeepingSchemaIfInsecure() views.chooseServerInput.editText().setText(userUrlInput) diff --git a/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml b/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml index afe7a06183..f1944e25ad 100644 --- a/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml +++ b/vector/src/main/res/layout/fragment_ftue_server_selection_combined.xml @@ -1,6 +1,7 @@ + app:layout_constraintTop_toBottomOf="@id/chooseServerHeaderTitle" + tools:text="@string/ftue_auth_choose_server_subtitle" /> Select your server What is the address of your server? This is like a home for all your data + What is the address of your server? Server URL Want to host your own server? From b6695c70096f974b6446b661fc66b1c746d4486a Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 09:37:50 +0100 Subject: [PATCH 05/10] using dedicated sign in copy for the server selection header --- vector/src/main/res/layout/fragment_ftue_combined_login.xml | 2 +- vector/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/vector/src/main/res/layout/fragment_ftue_combined_login.xml b/vector/src/main/res/layout/fragment_ftue_combined_login.xml index b23ea9d7cc..9533ab29fc 100644 --- a/vector/src/main/res/layout/fragment_ftue_combined_login.xml +++ b/vector/src/main/res/layout/fragment_ftue_combined_login.xml @@ -66,7 +66,7 @@ android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginTop="4dp" - android:text="@string/ftue_auth_create_account_choose_server_header" + android:text="@string/ftue_auth_sign_in_choose_server_header" android:textColor="?vctr_content_secondary" app:layout_constraintBottom_toTopOf="@id/selectedServerName" app:layout_constraintEnd_toStartOf="@id/editServerButton" diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 62b81530ee..64beab4107 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1930,6 +1930,7 @@ Others can discover you %s Must be 8 characters or more Where your conversations will live + Where your conversations live Or Edit From 87995abc7fea21ee3eefee28e23ae95a9b74d91c Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 09:40:39 +0100 Subject: [PATCH 06/10] updating verification copy to match latest --- vector/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 64beab4107..e7ea0642e4 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1973,9 +1973,9 @@ A code was sent to %s Resend code - Check your email to verify. + Verify your email - To confirm your email, tap the button in the email we just sent to %s + Follow the instructions sent to %s Did not receive an email? Resend email Forgot password From abcde349f0275539c3372a0666431ca1b82f6462 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 10:08:26 +0100 Subject: [PATCH 07/10] using invisible visibility to avoid loading spinner from jumping around and hiding the loading when resending the email --- .../ftueauth/FtueAuthWaitForEmailFragment.kt | 12 +++++++++++- .../fragment_ftue_wait_for_email_verification.xml | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt index 4649c7c799..f0536e9cab 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt @@ -21,6 +21,7 @@ import android.os.Parcelable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isInvisible import androidx.core.view.isVisible import com.airbnb.mvrx.args import im.vector.app.R @@ -63,6 +64,7 @@ class FtueAuthWaitForEmailFragment @Inject constructor( .colorTerminatingFullStop(ThemeUtils.getColor(requireContext(), R.attr.colorSecondary)) views.emailVerificationSubtitle.text = getString(R.string.ftue_auth_email_verification_subtitle, params.email) views.emailVerificationResendEmail.debouncedClicks { + hideWaitingForVerificationLoading() viewModel.handle(OnboardingAction.PostRegisterAction(RegisterAction.SendAgainThreePid)) } } @@ -75,13 +77,21 @@ class FtueAuthWaitForEmailFragment @Inject constructor( private fun showLoadingIfReturningToScreen() { when (inferHasLeftAndReturnedToScreen) { - true -> views.emailVerificationWaiting.isVisible = true + true -> showWaitingForVerificationLoading() false -> { inferHasLeftAndReturnedToScreen = true } } } + private fun hideWaitingForVerificationLoading() { + views.emailVerificationWaiting.isInvisible = true + } + + private fun showWaitingForVerificationLoading() { + views.emailVerificationWaiting.isInvisible = false + } + override fun onPause() { super.onPause() viewModel.handle(OnboardingAction.StopEmailValidationCheck) diff --git a/vector/src/main/res/layout/fragment_ftue_wait_for_email_verification.xml b/vector/src/main/res/layout/fragment_ftue_wait_for_email_verification.xml index fff7d42720..d745d4f0c4 100644 --- a/vector/src/main/res/layout/fragment_ftue_wait_for_email_verification.xml +++ b/vector/src/main/res/layout/fragment_ftue_wait_for_email_verification.xml @@ -96,7 +96,7 @@ android:id="@+id/emailVerificationWaiting" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:visibility="gone" + android:visibility="invisible" app:layout_constraintBottom_toBottomOf="@id/emailVerificationSpace4" app:layout_constraintEnd_toEndOf="@id/ftueAuthGutterEnd" app:layout_constraintStart_toStartOf="@id/ftueAuthGutterStart" From 12b6f54cf97486eda273032006dcfc581810bedd Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 10:16:22 +0100 Subject: [PATCH 08/10] updating captcha icon --- vector/src/main/res/drawable/ic_robot.xml | 10 ++++++++++ .../main/res/layout/fragment_ftue_login_captcha.xml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/res/drawable/ic_robot.xml diff --git a/vector/src/main/res/drawable/ic_robot.xml b/vector/src/main/res/drawable/ic_robot.xml new file mode 100644 index 0000000000..cdc358f7eb --- /dev/null +++ b/vector/src/main/res/drawable/ic_robot.xml @@ -0,0 +1,10 @@ + + + diff --git a/vector/src/main/res/layout/fragment_ftue_login_captcha.xml b/vector/src/main/res/layout/fragment_ftue_login_captcha.xml index becb745305..2f6970c785 100644 --- a/vector/src/main/res/layout/fragment_ftue_login_captcha.xml +++ b/vector/src/main/res/layout/fragment_ftue_login_captcha.xml @@ -38,7 +38,7 @@ android:background="@drawable/circle" android:backgroundTint="?colorSecondary" android:contentDescription="@null" - android:src="@drawable/ic_user_fg" + android:src="@drawable/ic_robot" app:layout_constraintBottom_toTopOf="@id/captchaHeaderTitle" app:layout_constraintEnd_toEndOf="@id/captchaGutterEnd" app:layout_constraintHeight_percent="0.10" From c153a833aa97d5b74bbcf6f15e7059b25206a8ee Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 10:25:25 +0100 Subject: [PATCH 09/10] adding changelog entries --- changelog.d/6620.feature | 1 + changelog.d/6621.feature | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/6620.feature create mode 100644 changelog.d/6621.feature diff --git a/changelog.d/6620.feature b/changelog.d/6620.feature new file mode 100644 index 0000000000..ad192edd5c --- /dev/null +++ b/changelog.d/6620.feature @@ -0,0 +1 @@ +FTUE - Test session feedback diff --git a/changelog.d/6621.feature b/changelog.d/6621.feature new file mode 100644 index 0000000000..b893c968b4 --- /dev/null +++ b/changelog.d/6621.feature @@ -0,0 +1 @@ +FTUE - Improved reset password error message From f21a9786089afb6a763418c5496735fabe939c29 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 27 Jul 2022 10:33:34 +0100 Subject: [PATCH 10/10] removing unused imports --- .../onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt | 1 - .../features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt index cede32008c..61826352bf 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordEntryFragment.kt @@ -31,7 +31,6 @@ import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.databinding.FragmentFtueResetPasswordInputBinding import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingViewState -import org.matrix.android.sdk.api.failure.isInvalidPassword import org.matrix.android.sdk.api.failure.isMissingEmailVerification @AndroidEntryPoint diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt index f0536e9cab..b1a3258cae 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt @@ -22,7 +22,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isInvisible -import androidx.core.view.isVisible import com.airbnb.mvrx.args import im.vector.app.R import im.vector.app.core.utils.colorTerminatingFullStop