Login screens: Registration: login/password step
This commit is contained in:
parent
381084b2ab
commit
95fc20dca0
@ -23,6 +23,8 @@ import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.auth.registration.FlowResult
|
||||
import im.vector.matrix.android.api.auth.registration.Stage
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.addFragment
|
||||
@ -85,6 +87,34 @@ class LoginActivity : VectorBaseActivity() {
|
||||
updateWithState(it)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
loginViewModel.viewEvents
|
||||
.observe()
|
||||
.subscribe {
|
||||
handleLoginViewEvents(it)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
}
|
||||
|
||||
private fun handleLoginViewEvents(loginViewEvents: LoginViewEvents) {
|
||||
when (loginViewEvents) {
|
||||
is LoginViewEvents.RegistrationFlowResult -> {
|
||||
// Check that all flows are supported by the application
|
||||
if (loginViewEvents.flowResult.missingStages.any { it is Stage.Other }) {
|
||||
// Display a popup to propose use web fallback
|
||||
// TODO
|
||||
} else {
|
||||
// Go on with registration flow
|
||||
// loginSharedActionViewModel.post(LoginNavigation.OnSignModeSelected)
|
||||
if (loginViewModel.isPasswordSent) {
|
||||
handleRegistrationNavigation(loginViewEvents.flowResult)
|
||||
} else {
|
||||
// First ask for login and password
|
||||
addFragmentToBackstack(R.id.loginFragmentContainer, LoginFragment::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLoginFlowRetrieved() {
|
||||
@ -152,6 +182,38 @@ class LoginActivity : VectorBaseActivity() {
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun handleRegistrationNavigation(flowResult: FlowResult) {
|
||||
// Complete all mandatory stage first
|
||||
val mandatoryStages = flowResult.missingStages.filter { it.mandatory }
|
||||
|
||||
if (mandatoryStages.isEmpty()) {
|
||||
// Consider optional stages
|
||||
val optionalStages = flowResult.missingStages.filter { !it.mandatory }
|
||||
if (optionalStages.isEmpty()) {
|
||||
// Should not happen...
|
||||
} else {
|
||||
doStage(optionalStages.first())
|
||||
}
|
||||
} else {
|
||||
doStage(mandatoryStages.first())
|
||||
}
|
||||
}
|
||||
|
||||
private fun doStage(stage: Stage) {
|
||||
when (stage) {
|
||||
is Stage.ReCaptcha -> addFragmentToBackstack(R.id.loginFragmentContainer, LoginCaptchaFragment::class.java)
|
||||
is Stage.Email -> addFragmentToBackstack(R.id.loginFragmentContainer,
|
||||
LoginGenericTextInputFormFragment::class.java,
|
||||
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetEmail, stage.mandatory))
|
||||
is Stage.Msisdn
|
||||
-> addFragmentToBackstack(R.id.loginFragmentContainer, LoginGenericTextInputFormFragment::class.java,
|
||||
LoginGenericTextInputFormFragmentArgument(TextInputFormFragmentMode.SetMsisdn, stage.mandatory))
|
||||
is Stage.Terms
|
||||
-> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
|
||||
@ -30,16 +30,15 @@ import kotlinx.android.synthetic.main.fragment_login_generic_text_input_form.*
|
||||
import javax.inject.Inject
|
||||
|
||||
enum class TextInputFormFragmentMode {
|
||||
SetEmailMandatory,
|
||||
SetEmailOptional,
|
||||
SetMsisdnMandatory,
|
||||
SetMsisdnOptional,
|
||||
SetEmail,
|
||||
SetMsisdn,
|
||||
ConfirmMsisdn
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class LoginGenericTextInputFormFragmentArgument(
|
||||
val mode: TextInputFormFragmentMode
|
||||
val mode: TextInputFormFragmentMode,
|
||||
val mandatory: Boolean
|
||||
) : Parcelable
|
||||
|
||||
/**
|
||||
@ -60,39 +59,23 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra
|
||||
|
||||
private fun setupUi() {
|
||||
when (params.mode) {
|
||||
TextInputFormFragmentMode.SetEmailMandatory -> {
|
||||
TextInputFormFragmentMode.SetEmail -> {
|
||||
loginGenericTextInputFormTitle.text = getString(R.string.login_set_email_title)
|
||||
loginGenericTextInputFormNotice.text = getString(R.string.login_set_email_notice)
|
||||
loginGenericTextInputFormTil.hint = getString(R.string.login_set_email_mandatory_hint)
|
||||
loginGenericTextInputFormTil.hint = getString(if (params.mandatory) R.string.login_set_email_mandatory_hint else R.string.login_set_email_optional_hint)
|
||||
loginGenericTextInputFormTextInput.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
loginGenericTextInputFormOtherButton.isVisible = false
|
||||
loginGenericTextInputFormSubmit.text = getString(R.string.login_set_email_submit)
|
||||
}
|
||||
TextInputFormFragmentMode.SetEmailOptional -> {
|
||||
loginGenericTextInputFormTitle.text = getString(R.string.login_set_email_title)
|
||||
loginGenericTextInputFormNotice.text = getString(R.string.login_set_email_notice)
|
||||
loginGenericTextInputFormTil.hint = getString(R.string.login_set_email_optional_hint)
|
||||
loginGenericTextInputFormTextInput.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
|
||||
loginGenericTextInputFormOtherButton.isVisible = false
|
||||
loginGenericTextInputFormSubmit.text = getString(R.string.login_set_email_submit)
|
||||
}
|
||||
TextInputFormFragmentMode.SetMsisdnMandatory -> {
|
||||
TextInputFormFragmentMode.SetMsisdn -> {
|
||||
loginGenericTextInputFormTitle.text = getString(R.string.login_set_msisdn_title)
|
||||
loginGenericTextInputFormNotice.text = getString(R.string.login_set_msisdn_notice)
|
||||
loginGenericTextInputFormTil.hint = getString(R.string.login_set_msisdn_mandatory_hint)
|
||||
loginGenericTextInputFormTil.hint = getString(if (params.mandatory) R.string.login_set_msisdn_mandatory_hint else R.string.login_set_msisdn_optional_hint)
|
||||
loginGenericTextInputFormTextInput.inputType = InputType.TYPE_CLASS_PHONE
|
||||
loginGenericTextInputFormOtherButton.isVisible = false
|
||||
loginGenericTextInputFormSubmit.text = getString(R.string.login_set_msisdn_submit)
|
||||
}
|
||||
TextInputFormFragmentMode.SetMsisdnOptional -> {
|
||||
loginGenericTextInputFormTitle.text = getString(R.string.login_set_msisdn_title)
|
||||
loginGenericTextInputFormNotice.text = getString(R.string.login_set_msisdn_notice)
|
||||
loginGenericTextInputFormTil.hint = getString(R.string.login_set_msisdn_optional_hint)
|
||||
loginGenericTextInputFormTextInput.inputType = InputType.TYPE_CLASS_PHONE
|
||||
loginGenericTextInputFormOtherButton.isVisible = false
|
||||
loginGenericTextInputFormSubmit.text = getString(R.string.login_set_msisdn_submit)
|
||||
}
|
||||
TextInputFormFragmentMode.ConfirmMsisdn -> {
|
||||
TextInputFormFragmentMode.ConfirmMsisdn -> {
|
||||
loginGenericTextInputFormTitle.text = getString(R.string.login_msisdn_confirm_title)
|
||||
loginGenericTextInputFormNotice.text = getString(R.string.login_msisdn_confirm_notice)
|
||||
loginGenericTextInputFormTil.hint = getString(R.string.login_msisdn_confirm_hint)
|
||||
@ -115,22 +98,16 @@ class LoginGenericTextInputFormFragment @Inject constructor() : AbstractLoginFra
|
||||
}
|
||||
|
||||
private fun setupSubmitButton() {
|
||||
when (params.mode) {
|
||||
TextInputFormFragmentMode.SetEmailMandatory,
|
||||
TextInputFormFragmentMode.SetMsisdnMandatory,
|
||||
TextInputFormFragmentMode.ConfirmMsisdn -> {
|
||||
loginGenericTextInputFormSubmit.isEnabled = false
|
||||
loginGenericTextInputFormTextInput.textChanges()
|
||||
.subscribe {
|
||||
// TODO Better check for email format, etc?
|
||||
loginGenericTextInputFormSubmit.isEnabled = it.isNotBlank()
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
TextInputFormFragmentMode.SetEmailOptional,
|
||||
TextInputFormFragmentMode.SetMsisdnOptional -> {
|
||||
loginGenericTextInputFormSubmit.isEnabled = true
|
||||
}
|
||||
if (params.mandatory) {
|
||||
loginGenericTextInputFormSubmit.isEnabled = false
|
||||
loginGenericTextInputFormTextInput.textChanges()
|
||||
.subscribe {
|
||||
// TODO Better check for email format, etc?
|
||||
loginGenericTextInputFormSubmit.isEnabled = it.isNotBlank()
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
} else {
|
||||
loginGenericTextInputFormSubmit.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,11 +21,7 @@ import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import butterknife.OnClick
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.withState
|
||||
import im.vector.matrix.android.api.auth.registration.FlowResult
|
||||
import im.vector.matrix.android.api.auth.registration.RegistrationResult
|
||||
import im.vector.matrix.android.api.auth.registration.Stage
|
||||
import im.vector.riotx.R
|
||||
import kotlinx.android.synthetic.main.fragment_login_signup_signin_selection.*
|
||||
import javax.inject.Inject
|
||||
@ -83,32 +79,12 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLoginFr
|
||||
|
||||
override fun invalidate() = withState(loginViewModel) {
|
||||
when (it.asyncRegistration) {
|
||||
is Success -> {
|
||||
when (val res = it.asyncRegistration()) {
|
||||
is RegistrationResult.Success ->
|
||||
// Should not happen
|
||||
Unit
|
||||
is RegistrationResult.FlowResponse -> handleFlowResult(res.flowResult)
|
||||
}
|
||||
}
|
||||
is Fail -> {
|
||||
// TODO Registration disabled, etc
|
||||
is Fail -> {
|
||||
// TODO Registration disabled, (move to Activity?)
|
||||
when (it.asyncRegistration.error) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFlowResult(flowResult: FlowResult) {
|
||||
// Check that all flows are supported by the application
|
||||
if (flowResult.missingStages.any { it is Stage.Other }) {
|
||||
// Display a popup to propose use web fallback
|
||||
// TODO
|
||||
} else {
|
||||
// Go on with registration flow
|
||||
loginSharedActionViewModel.post(LoginNavigation.OnSignModeSelected)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2019 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.riotx.features.login
|
||||
|
||||
import im.vector.matrix.android.api.auth.registration.FlowResult
|
||||
|
||||
/**
|
||||
* Transient events for Login
|
||||
*/
|
||||
sealed class LoginViewEvents {
|
||||
data class RegistrationFlowResult(val flowResult: FlowResult) : LoginViewEvents()
|
||||
}
|
||||
@ -34,6 +34,8 @@ import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
|
||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||
import im.vector.riotx.core.extensions.configureAndStart
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.utils.DataSource
|
||||
import im.vector.riotx.core.utils.PublishDataSource
|
||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.riotx.features.session.SessionListener
|
||||
import timber.log.Timber
|
||||
@ -60,6 +62,9 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
}
|
||||
}
|
||||
|
||||
var isPasswordSent: Boolean = false
|
||||
private set
|
||||
|
||||
private var registrationWizard: RegistrationWizard? = null
|
||||
|
||||
var serverType: ServerType = ServerType.MatrixOrg
|
||||
@ -74,23 +79,8 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
private var homeServerConnectionConfig: HomeServerConnectionConfig? = null
|
||||
private var currentTask: Cancelable? = null
|
||||
|
||||
private val registrationCallback = object : MatrixCallback<RegistrationResult> {
|
||||
override fun onSuccess(data: RegistrationResult) {
|
||||
when (data) {
|
||||
is RegistrationResult.Success -> onSessionCreated(data.session)
|
||||
is RegistrationResult.FlowResponse -> onFlowResponse(data.flowResult)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// TODO Handled JobCancellationException
|
||||
setState {
|
||||
copy(
|
||||
asyncRegistration = Fail(failure)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val _viewEvents = PublishDataSource<LoginViewEvents>()
|
||||
val viewEvents: DataSource<LoginViewEvents> = _viewEvents
|
||||
|
||||
override fun handle(action: LoginAction) {
|
||||
when (action) {
|
||||
@ -109,6 +99,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
private fun handleRegisterAction(action: LoginAction.RegisterAction) {
|
||||
when (action) {
|
||||
is LoginAction.RegisterWith -> handleRegisterWith(action)
|
||||
// TODO Add other actions here
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +110,25 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
)
|
||||
}
|
||||
|
||||
currentTask = registrationWizard?.createAccount(action.username, action.password, null /* TODO InitialDisplayName */, registrationCallback)
|
||||
currentTask = registrationWizard?.createAccount(action.username, action.password, null /* TODO InitialDisplayName */, object : MatrixCallback<RegistrationResult> {
|
||||
override fun onSuccess(data: RegistrationResult) {
|
||||
isPasswordSent = true
|
||||
|
||||
when (data) {
|
||||
is RegistrationResult.Success -> onSessionCreated(data.session)
|
||||
is RegistrationResult.FlowResponse -> onFlowResponse(data.flowResult)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// TODO Handled JobCancellationException
|
||||
setState {
|
||||
copy(
|
||||
asyncRegistration = Fail(failure)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleResetAction(action: LoginAction.ResetAction) {
|
||||
@ -129,6 +138,8 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
|
||||
when (action) {
|
||||
LoginAction.ResetLogin -> {
|
||||
isPasswordSent = false
|
||||
|
||||
setState {
|
||||
copy(
|
||||
asyncLoginAction = Uninitialized,
|
||||
@ -292,9 +303,12 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
||||
}
|
||||
|
||||
private fun onFlowResponse(flowResult: FlowResult) {
|
||||
// Notify the user
|
||||
_viewEvents.post(LoginViewEvents.RegistrationFlowResult(flowResult))
|
||||
|
||||
setState {
|
||||
copy(
|
||||
asyncRegistration = Success(RegistrationResult.FlowResponse(flowResult))
|
||||
asyncRegistration = Uninitialized
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user