Login screens: set initial device name

This commit is contained in:
Benoit Marty 2019-11-20 14:39:19 +01:00
parent ac377fceba
commit 20ad3abb60
6 changed files with 59 additions and 77 deletions

View file

@ -38,10 +38,15 @@ interface Authenticator {
* @param homeServerConnectionConfig this param is used to configure the Homeserver * @param homeServerConnectionConfig this param is used to configure the Homeserver
* @param login the login field * @param login the login field
* @param password the password field * @param password the password field
* @param deviceName the initial device name
* @param callback the matrix callback on which you'll receive the result of authentication. * @param callback the matrix callback on which you'll receive the result of authentication.
* @return return a [Cancelable] * @return return a [Cancelable]
*/ */
fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, callback: MatrixCallback<Session>): Cancelable fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig,
login: String,
password: String,
deviceName: String,
callback: MatrixCallback<Session>): Cancelable
/** /**
* Check if there is an authenticated [Session]. * Check if there is an authenticated [Session].

View file

@ -77,10 +77,11 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
override fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, override fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig,
login: String, login: String,
password: String, password: String,
deviceName: String,
callback: MatrixCallback<Session>): Cancelable { callback: MatrixCallback<Session>): Cancelable {
val job = GlobalScope.launch(coroutineDispatchers.main) { val job = GlobalScope.launch(coroutineDispatchers.main) {
val sessionOrFailure = runCatching { val sessionOrFailure = runCatching {
authenticate(homeServerConnectionConfig, login, password) authenticate(homeServerConnectionConfig, login, password, deviceName)
} }
sessionOrFailure.foldToCallback(callback) sessionOrFailure.foldToCallback(callback)
} }
@ -97,12 +98,13 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
private suspend fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, private suspend fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig,
login: String, login: String,
password: String) = withContext(coroutineDispatchers.io) { password: String,
deviceName: String) = withContext(coroutineDispatchers.io) {
val authAPI = buildAuthAPI(homeServerConnectionConfig) val authAPI = buildAuthAPI(homeServerConnectionConfig)
val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) { val loginParams = if (Patterns.EMAIL_ADDRESS.matcher(login).matches()) {
PasswordLoginParams.thirdPartyIdentifier(ThreePidMedium.EMAIL, login, password, "Mobile") PasswordLoginParams.thirdPartyIdentifier(ThreePidMedium.EMAIL, login, password, deviceName)
} else { } else {
PasswordLoginParams.userIdentifier(login, password, "Mobile") PasswordLoginParams.userIdentifier(login, password, deviceName)
} }
val credentials = executeRequest<Credentials> { val credentials = executeRequest<Credentials> {
apiCall = authAPI.login(loginParams) apiCall = authAPI.login(loginParams)

View file

@ -23,7 +23,7 @@ sealed class LoginAction : VectorViewModelAction {
data class UpdateServerType(val serverType: ServerType) : LoginAction() data class UpdateServerType(val serverType: ServerType) : LoginAction()
data class UpdateHomeServer(val homeServerUrl: String) : LoginAction() data class UpdateHomeServer(val homeServerUrl: String) : LoginAction()
data class UpdateSignMode(val signMode: SignMode) : LoginAction() data class UpdateSignMode(val signMode: SignMode) : LoginAction()
data class Login(val login: String, val password: String) : LoginAction() data class Login(val login: String, val password: String, val initialDeviceName: String) : LoginAction()
data class WebLoginSuccess(val credentials: Credentials) : LoginAction() data class WebLoginSuccess(val credentials: Credentials) : LoginAction()
data class InitWith(val loginConfig: LoginConfig) : LoginAction() data class InitWith(val loginConfig: LoginConfig) : LoginAction()
data class ResetPassword(val email: String, val newPassword: String) : LoginAction() data class ResetPassword(val email: String, val newPassword: String) : LoginAction()
@ -31,7 +31,7 @@ sealed class LoginAction : VectorViewModelAction {
// Register actions // Register actions
open class RegisterAction : LoginAction() open class RegisterAction : LoginAction()
data class RegisterWith(val username: String, val password: String) : RegisterAction() data class RegisterWith(val username: String, val password: String, val initialDeviceName: String) : RegisterAction()
data class AddEmail(val email: String) : RegisterAction() data class AddEmail(val email: String) : RegisterAction()
data class AddMsisdn(val msisdn: String) : RegisterAction() data class AddMsisdn(val msisdn: String) : RegisterAction()
data class ConfirmMsisdn(val code: String) : RegisterAction() data class ConfirmMsisdn(val code: String) : RegisterAction()

View file

@ -66,8 +66,8 @@ class LoginFragment @Inject constructor(
when (loginViewModel.signMode) { when (loginViewModel.signMode) {
SignMode.Unknown -> error("developer error") SignMode.Unknown -> error("developer error")
SignMode.SignUp -> loginViewModel.handle(LoginAction.RegisterWith(login, password)) SignMode.SignUp -> loginViewModel.handle(LoginAction.RegisterWith(login, password, getString(R.string.login_mobile_device)))
SignMode.SignIn -> loginViewModel.handle(LoginAction.Login(login, password)) SignMode.SignIn -> loginViewModel.handle(LoginAction.Login(login, password, getString(R.string.login_mobile_device)))
} }
} }

View file

@ -42,7 +42,7 @@ import im.vector.riotx.features.session.SessionListener
import timber.log.Timber import timber.log.Timber
/** /**
* TODO To speed up registration, consider fetching registration flow instead of login flow at startup *
*/ */
class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginViewState, class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginViewState,
private val authenticator: Authenticator, private val authenticator: Authenticator,
@ -113,12 +113,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
} }
private fun handleConfirmMsisdn(action: LoginAction.ConfirmMsisdn) { private fun handleConfirmMsisdn(action: LoginAction.ConfirmMsisdn) {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.confirmMsisdn(action.code, registrationCallback) currentTask = registrationWizard?.confirmMsisdn(action.code, registrationCallback)
} }
@ -134,7 +129,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
setState { setState {
copy( copy(
asyncRegistration = Success(data) asyncRegistration = Uninitialized
) )
} }
@ -155,69 +150,43 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
} }
private fun handleAddMsisdn(action: LoginAction.AddMsisdn) { private fun handleAddMsisdn(action: LoginAction.AddMsisdn) {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.addMsisdn(action.msisdn, registrationCallback) currentTask = registrationWizard?.addMsisdn(action.msisdn, registrationCallback)
} }
private fun handleAddEmail(action: LoginAction.AddEmail) { private fun handleAddEmail(action: LoginAction.AddEmail) {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.addEmail(action.email, registrationCallback) currentTask = registrationWizard?.addEmail(action.email, registrationCallback)
} }
private fun handleAcceptTerms() { private fun handleAcceptTerms() {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.acceptTerms(registrationCallback) currentTask = registrationWizard?.acceptTerms(registrationCallback)
} }
private fun handleRegisterDummy() { private fun handleRegisterDummy() {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.dummy(registrationCallback) currentTask = registrationWizard?.dummy(registrationCallback)
} }
private fun handleRegisterWith(action: LoginAction.RegisterWith) { private fun handleRegisterWith(action: LoginAction.RegisterWith) {
setState { setState { copy(asyncRegistration = Loading()) }
copy( currentTask = registrationWizard?.createAccount(
asyncRegistration = Loading() action.username,
) action.password,
} action.initialDeviceName,
object : MatrixCallbackDelegate<RegistrationResult>(registrationCallback) {
currentTask = registrationWizard?.createAccount(action.username, action.password, null /* TODO InitialDisplayName */, object : MatrixCallbackDelegate<RegistrationResult>(registrationCallback) { override fun onSuccess(data: RegistrationResult) {
override fun onSuccess(data: RegistrationResult) { isPasswordSent = true
isPasswordSent = true // Not sure that this will work:
// Not sure that this will work: // super.onSuccess(data)
// super.onSuccess(data) registrationCallback.onSuccess(data)
registrationCallback.onSuccess(data) }
} })
})
} }
private fun handleCaptchaDone(action: LoginAction.CaptchaDone) { private fun handleCaptchaDone(action: LoginAction.CaptchaDone) {
setState { setState { copy(asyncRegistration = Loading()) }
copy(
asyncRegistration = Loading()
)
}
currentTask = registrationWizard?.performReCaptcha(action.captchaResponse, registrationCallback) currentTask = registrationWizard?.performReCaptcha(action.captchaResponse, registrationCallback)
} }
@ -337,20 +306,25 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
) )
} }
currentTask = authenticator.authenticate(homeServerConnectionConfigFinal, action.login, action.password, object : MatrixCallback<Session> { currentTask = authenticator.authenticate(
override fun onSuccess(data: Session) { homeServerConnectionConfigFinal,
onSessionCreated(data) action.login,
} action.password,
action.initialDeviceName,
object : MatrixCallback<Session> {
override fun onSuccess(data: Session) {
onSessionCreated(data)
}
override fun onFailure(failure: Throwable) { override fun onFailure(failure: Throwable) {
// TODO Handled JobCancellationException // TODO Handled JobCancellationException
setState { setState {
copy( copy(
asyncLoginAction = Fail(failure) asyncLoginAction = Fail(failure)
) )
} }
} }
}) })
} }
} }
@ -358,9 +332,11 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
val homeServerConnectionConfigFinal = homeServerConnectionConfig val homeServerConnectionConfigFinal = homeServerConnectionConfig
if (homeServerConnectionConfigFinal == null) { if (homeServerConnectionConfigFinal == null) {
// Notify the user
_viewEvents.post(LoginViewEvents.RegistrationError(Throwable("Bad configuration")))
setState { setState {
copy( copy(
asyncRegistration = Fail(Throwable("Bad configuration")) asyncRegistration = Uninitialized
) )
} }
} else { } else {

View file

@ -17,13 +17,12 @@
package im.vector.riotx.features.login package im.vector.riotx.features.login
import com.airbnb.mvrx.* import com.airbnb.mvrx.*
import im.vector.matrix.android.api.auth.registration.RegistrationResult
data class LoginViewState( data class LoginViewState(
val asyncLoginAction: Async<Unit> = Uninitialized, val asyncLoginAction: Async<Unit> = Uninitialized,
val asyncHomeServerLoginFlowRequest: Async<LoginMode> = Uninitialized, val asyncHomeServerLoginFlowRequest: Async<LoginMode> = Uninitialized,
val asyncResetPassword: Async<Unit> = Uninitialized, val asyncResetPassword: Async<Unit> = Uninitialized,
val asyncRegistration: Async<RegistrationResult> = Uninitialized val asyncRegistration: Async<Unit> = Uninitialized
) : MvRxState { ) : MvRxState {
fun isLoading(): Boolean { fun isLoading(): Boolean {