diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingAction.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingAction.kt index dc8f260c13..40900ca2b0 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingAction.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingAction.kt @@ -48,6 +48,8 @@ sealed interface OnboardingAction : VectorViewModelAction { data class WebLoginSuccess(val credentials: Credentials) : OnboardingAction data class InitWith(val loginConfig: LoginConfig?) : OnboardingAction data class ResetPassword(val email: String, val newPassword: String?) : OnboardingAction + data class ConfirmNewPassword(val newPassword: String) : OnboardingAction + object ResendResetPassword : OnboardingAction object ResetPasswordMailConfirmed : OnboardingAction data class MaybeUpdateHomeserverFromMatrixId(val userId: String) : OnboardingAction diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt index ffd65b1287..01de7c073a 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewEvents.kt @@ -49,6 +49,7 @@ sealed class OnboardingViewEvents : VectorViewEvents { object OnForgetPasswordClicked : OnboardingViewEvents() data class OnResetPasswordSendThreePidDone(val email: String) : OnboardingViewEvents() object OnResetPasswordMailConfirmationSuccess : OnboardingViewEvents() + object OnResetPasswordBreakerConfirmed : OnboardingViewEvents() object OnResetPasswordMailConfirmationSuccessDone : OnboardingViewEvents() data class OnSendEmailSuccess(val email: String) : OnboardingViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt index 5bac6ec0bc..b4257a0abf 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt @@ -149,6 +149,8 @@ class OnboardingViewModel @AssistedInject constructor( is OnboardingAction.LoginWithToken -> handleLoginWithToken(action) is OnboardingAction.WebLoginSuccess -> handleWebLoginSuccess(action) is OnboardingAction.ResetPassword -> handleResetPassword(action) + OnboardingAction.ResendResetPassword -> handleResendResetPassword() + is OnboardingAction.ConfirmNewPassword -> handleConfirmNewPassword(action) is OnboardingAction.ResetPasswordMailConfirmed -> handleResetPasswordMailConfirmed() is OnboardingAction.PostRegisterAction -> handleRegisterAction(action.registerAction) is OnboardingAction.ResetAction -> handleResetAction(action) @@ -439,25 +441,9 @@ class OnboardingViewModel @AssistedInject constructor( } private fun handleResetPassword(action: OnboardingAction.ResetPassword) { - val safeLoginWizard = loginWizard - setState { copy(isLoading = true) } - currentJob = viewModelScope.launch { - runCatching { safeLoginWizard.resetPassword(action.email) }.fold( - onSuccess = { - val state = awaitState() - setState { - copy( - isLoading = false, - resetState = createResetState(action, state.selectedHomeserver) - ) - } - _viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone(action.email)) - }, - onFailure = { - setState { copy(isLoading = false) } - _viewEvents.post(OnboardingViewEvents.Failure(it)) - } - ) + startResetPasswordFlow(action.email) { + setState { copy(isLoading = false, resetState = createResetState(action, selectedHomeserver)) } + _viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone(action.email)) } } @@ -467,6 +453,42 @@ class OnboardingViewModel @AssistedInject constructor( supportsLogoutAllDevices = selectedHomeserverState.isLogoutDevicesSupported ) + private fun handleResendResetPassword() { + withState { state -> + val resetState = state.resetState + when (resetState.email) { + null -> { + setState { copy(isLoading = false) } + _viewEvents.post(OnboardingViewEvents.Failure(IllegalStateException("Developer error - No reset email has been set"))) + } + else -> { + startResetPasswordFlow(resetState.email) { + setState { copy(isLoading = false) } + } + } + } + } + } + + private fun startResetPasswordFlow(email: String, onSuccess: suspend () -> Unit) { + val safeLoginWizard = loginWizard + setState { copy(isLoading = true) } + currentJob = viewModelScope.launch { + runCatching { safeLoginWizard.resetPassword(email) }.fold( + onSuccess = { onSuccess.invoke() }, + onFailure = { + setState { copy(isLoading = false) } + _viewEvents.post(OnboardingViewEvents.Failure(it)) + } + ) + } + } + + private fun handleConfirmNewPassword(action: OnboardingAction.ConfirmNewPassword) { + setState { copy(resetState = resetState.copy(newPassword = action.newPassword)) } + handleResetPasswordMailConfirmed() + } + private fun handleResetPasswordMailConfirmed() { setState { copy(isLoading = true) } currentJob = viewModelScope.launch { diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt index 07e628d9fb..5a8ced28df 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthResetPasswordBreakerFragment.kt @@ -27,7 +27,7 @@ import im.vector.app.R import im.vector.app.core.utils.colorTerminatingFullStop import im.vector.app.databinding.FragmentFtueResetPasswordBreakerBinding import im.vector.app.features.onboarding.OnboardingAction -import im.vector.app.features.onboarding.RegisterAction +import im.vector.app.features.onboarding.OnboardingViewEvents import im.vector.app.features.themes.ThemeProvider import im.vector.app.features.themes.ThemeUtils import kotlinx.parcelize.Parcelize @@ -63,8 +63,9 @@ class FtueAuthResetPasswordBreakerFragment : AbstractFtueAuthFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueResetPasswordInputBinding { + return FragmentFtueResetPasswordInputBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setupViews() + } + + private fun setupViews() { + views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit) + views.emailEntryInput.setOnImeDoneListener { resetPassword() } + views.emailEntrySubmit.debouncedClicks { resetPassword() } + + views.emailEntryInput.editText().textChanges() + .onEach { + views.emailEntryInput.error = null + views.emailEntrySubmit.isEnabled = it.isEmail() + } + .launchIn(viewLifecycleOwner.lifecycleScope) + } + + private fun resetPassword() { + val password = views.emailEntryInput.content() + viewModel.handle(OnboardingAction.ConfirmNewPassword(newPassword = password)) + } + + override fun onError(throwable: Throwable) { + views.emailEntryInput.error = errorFormatter.toHumanReadable(throwable) + } + + override fun resetViewModel() { + viewModel.handle(OnboardingAction.ResetResetPassword) + } +} diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt index 49c937827e..5f1c3d4314 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt @@ -190,6 +190,14 @@ class FtueAuthVariant( ) } } + OnboardingViewEvents.OnResetPasswordBreakerConfirmed -> { + supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) + activity.addFragmentToBackstack( + views.loginFragmentContainer, + FtueAuthResetPasswordEntryFragment::class.java, + option = commonOption + ) + } is OnboardingViewEvents.OnResetPasswordMailConfirmationSuccess -> { supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE) activity.addFragmentToBackstack( diff --git a/vector/src/main/res/layout/fragment_ftue_reset_password_input.xml b/vector/src/main/res/layout/fragment_ftue_reset_password_input.xml new file mode 100644 index 0000000000..c9da572df5 --- /dev/null +++ b/vector/src/main/res/layout/fragment_ftue_reset_password_input.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +