checking user name is available at the point of user name entry during the registration flow
This commit is contained in:
parent
b8d4ff552f
commit
1062bfe039
@ -58,6 +58,7 @@ sealed interface OnboardingAction : VectorViewModelAction {
|
|||||||
}
|
}
|
||||||
sealed interface AuthenticateAction : OnboardingAction {
|
sealed interface AuthenticateAction : OnboardingAction {
|
||||||
data class Register(val username: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
data class Register(val username: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
||||||
|
data class RegisterWithMatrixId(val matrixId: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
||||||
data class Login(val username: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
data class Login(val username: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
||||||
data class LoginDirect(val matrixId: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
data class LoginDirect(val matrixId: String, val password: String, val initialDeviceName: String) : AuthenticateAction
|
||||||
}
|
}
|
||||||
@ -74,6 +75,7 @@ sealed interface OnboardingAction : VectorViewModelAction {
|
|||||||
object ResetSignMode : ResetAction
|
object ResetSignMode : ResetAction
|
||||||
object ResetAuthenticationAttempt : ResetAction
|
object ResetAuthenticationAttempt : ResetAction
|
||||||
object ResetResetPassword : ResetAction
|
object ResetResetPassword : ResetAction
|
||||||
|
object ResetSelectedRegistrationUserName : ResetAction
|
||||||
|
|
||||||
// Homeserver history
|
// Homeserver history
|
||||||
object ClearHomeServerHistory : OnboardingAction
|
object ClearHomeServerHistory : OnboardingAction
|
||||||
|
|||||||
@ -28,6 +28,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
|
|||||||
import im.vector.app.core.extensions.cancelCurrentOnSet
|
import im.vector.app.core.extensions.cancelCurrentOnSet
|
||||||
import im.vector.app.core.extensions.configureAndStart
|
import im.vector.app.core.extensions.configureAndStart
|
||||||
import im.vector.app.core.extensions.inferNoConnectivity
|
import im.vector.app.core.extensions.inferNoConnectivity
|
||||||
|
import im.vector.app.core.extensions.isMatrixId
|
||||||
|
import im.vector.app.core.extensions.toReducedUrl
|
||||||
import im.vector.app.core.extensions.vectorStore
|
import im.vector.app.core.extensions.vectorStore
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.BuildMeta
|
import im.vector.app.core.resources.BuildMeta
|
||||||
@ -57,6 +59,7 @@ import org.matrix.android.sdk.api.auth.HomeServerHistoryService
|
|||||||
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.auth.login.LoginWizard
|
import org.matrix.android.sdk.api.auth.login.LoginWizard
|
||||||
|
import org.matrix.android.sdk.api.auth.registration.RegistrationAvailability
|
||||||
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
|
||||||
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
@ -168,19 +171,46 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUserNameEntered(action: OnboardingAction.UserNameEnteredAction) {
|
private fun handleUserNameEntered(action: OnboardingAction.UserNameEnteredAction) {
|
||||||
when(action) {
|
when (action) {
|
||||||
is OnboardingAction.UserNameEnteredAction.Login -> maybeUpdateHomeserver(action.userId)
|
is OnboardingAction.UserNameEnteredAction.Login -> maybeUpdateHomeserver(action.userId)
|
||||||
is OnboardingAction.UserNameEnteredAction.Registration -> maybeUpdateHomeserver(action.userId)
|
is OnboardingAction.UserNameEnteredAction.Registration -> maybeUpdateHomeserver(action.userId, continuation = { userName ->
|
||||||
|
checkUserNameAvailability(userName)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeUpdateHomeserver(userNameOrMatrixId: String) {
|
private fun maybeUpdateHomeserver(userNameOrMatrixId: String, continuation: suspend (String) -> Unit = {}) {
|
||||||
val isFullMatrixId = MatrixPatterns.isUserId(userNameOrMatrixId)
|
val isFullMatrixId = MatrixPatterns.isUserId(userNameOrMatrixId)
|
||||||
if (isFullMatrixId) {
|
if (isFullMatrixId) {
|
||||||
val domain = userNameOrMatrixId.getServerName().substringBeforeLast(":").ensureProtocol()
|
val domain = userNameOrMatrixId.getServerName().substringBeforeLast(":").ensureProtocol()
|
||||||
handleHomeserverChange(OnboardingAction.HomeServerChange.EditHomeServer(domain))
|
handleHomeserverChange(OnboardingAction.HomeServerChange.EditHomeServer(domain), postAction = {
|
||||||
|
val userName = MatrixPatterns.extractUserNameFromId(userNameOrMatrixId) ?: throw IllegalStateException("unexpected non matrix id")
|
||||||
|
continuation(userName)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// ignore the action
|
currentJob = viewModelScope.launch { continuation(userNameOrMatrixId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun checkUserNameAvailability(userName: String) {
|
||||||
|
when (val result = registrationWizard.registrationAvailable(userName)) {
|
||||||
|
RegistrationAvailability.Available -> {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
registrationState = RegistrationState(
|
||||||
|
isUserNameAvailable = true,
|
||||||
|
selectedMatrixId = when {
|
||||||
|
userName.isMatrixId() -> userName
|
||||||
|
else -> "@$userName:${selectedHomeserver.userFacingUrl.toReducedUrl()}"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is RegistrationAvailability.NotAvailable -> {
|
||||||
|
_viewEvents.post(OnboardingViewEvents.Failure(result.failure))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +221,12 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private fun handleAuthenticateAction(action: AuthenticateAction) {
|
private fun handleAuthenticateAction(action: AuthenticateAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
is AuthenticateAction.Register -> handleRegisterWith(action)
|
is AuthenticateAction.Register -> handleRegisterWith(action.username, action.password, action.initialDeviceName)
|
||||||
|
is AuthenticateAction.RegisterWithMatrixId -> handleRegisterWith(
|
||||||
|
MatrixPatterns.extractUserNameFromId(action.matrixId) ?: throw IllegalStateException("unexpected non matrix id"),
|
||||||
|
action.password,
|
||||||
|
action.initialDeviceName
|
||||||
|
)
|
||||||
is AuthenticateAction.Login -> handleLogin(action)
|
is AuthenticateAction.Login -> handleLogin(action)
|
||||||
is AuthenticateAction.LoginDirect -> handleDirectLogin(action, homeServerConnectionConfig = null)
|
is AuthenticateAction.LoginDirect -> handleDirectLogin(action, homeServerConnectionConfig = null)
|
||||||
}
|
}
|
||||||
@ -329,17 +364,17 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRegisterWith(action: AuthenticateAction.Register) {
|
private fun handleRegisterWith(userName: String, password: String, initialDeviceName: String) {
|
||||||
setState {
|
setState {
|
||||||
val authDescription = AuthenticationDescription.Register(AuthenticationDescription.AuthenticationType.Password)
|
val authDescription = AuthenticationDescription.Register(AuthenticationDescription.AuthenticationType.Password)
|
||||||
copy(selectedAuthenticationState = SelectedAuthenticationState(authDescription))
|
copy(selectedAuthenticationState = SelectedAuthenticationState(authDescription))
|
||||||
}
|
}
|
||||||
reAuthHelper.data = action.password
|
reAuthHelper.data = password
|
||||||
handleRegisterAction(
|
handleRegisterAction(
|
||||||
RegisterAction.CreateAccount(
|
RegisterAction.CreateAccount(
|
||||||
action.username,
|
userName,
|
||||||
action.password,
|
password,
|
||||||
action.initialDeviceName
|
initialDeviceName
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -375,7 +410,12 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
OnboardingAction.ResetAuthenticationAttempt -> {
|
OnboardingAction.ResetAuthenticationAttempt -> {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
authenticationService.cancelPendingLoginOrRegistration()
|
authenticationService.cancelPendingLoginOrRegistration()
|
||||||
setState { copy(isLoading = false) }
|
setState {
|
||||||
|
copy(
|
||||||
|
isLoading = false,
|
||||||
|
registrationState = RegistrationState(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OnboardingAction.ResetResetPassword -> {
|
OnboardingAction.ResetResetPassword -> {
|
||||||
@ -387,6 +427,11 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
OnboardingAction.ResetDeeplinkConfig -> loginConfig = null
|
OnboardingAction.ResetDeeplinkConfig -> loginConfig = null
|
||||||
|
OnboardingAction.ResetSelectedRegistrationUserName -> {
|
||||||
|
setState {
|
||||||
|
copy(registrationState = RegistrationState())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,27 +671,31 @@ class OnboardingViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleHomeserverChange(action: OnboardingAction.HomeServerChange, serverTypeOverride: ServerType? = null) {
|
private fun handleHomeserverChange(action: OnboardingAction.HomeServerChange, serverTypeOverride: ServerType? = null, postAction: suspend () -> Unit = {}) {
|
||||||
val homeServerConnectionConfig = homeServerConnectionConfigFactory.create(action.homeServerUrl)
|
val homeServerConnectionConfig = homeServerConnectionConfigFactory.create(action.homeServerUrl)
|
||||||
if (homeServerConnectionConfig == null) {
|
if (homeServerConnectionConfig == null) {
|
||||||
// This is invalid
|
// This is invalid
|
||||||
_viewEvents.post(OnboardingViewEvents.Failure(Throwable("Unable to create a HomeServerConnectionConfig")))
|
_viewEvents.post(OnboardingViewEvents.Failure(Throwable("Unable to create a HomeServerConnectionConfig")))
|
||||||
} else {
|
} else {
|
||||||
startAuthenticationFlow(action, homeServerConnectionConfig, serverTypeOverride)
|
startAuthenticationFlow(action, homeServerConnectionConfig, serverTypeOverride, postAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startAuthenticationFlow(
|
private fun startAuthenticationFlow(
|
||||||
trigger: OnboardingAction.HomeServerChange,
|
trigger: OnboardingAction.HomeServerChange,
|
||||||
homeServerConnectionConfig: HomeServerConnectionConfig,
|
homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
serverTypeOverride: ServerType?
|
serverTypeOverride: ServerType?,
|
||||||
|
postAction: suspend () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
currentHomeServerConnectionConfig = homeServerConnectionConfig
|
currentHomeServerConnectionConfig = homeServerConnectionConfig
|
||||||
|
|
||||||
currentJob = viewModelScope.launch {
|
currentJob = viewModelScope.launch {
|
||||||
setState { copy(isLoading = true) }
|
setState { copy(isLoading = true) }
|
||||||
runCatching { startAuthenticationFlowUseCase.execute(homeServerConnectionConfig) }.fold(
|
runCatching { startAuthenticationFlowUseCase.execute(homeServerConnectionConfig) }.fold(
|
||||||
onSuccess = { onAuthenticationStartedSuccess(trigger, homeServerConnectionConfig, it, serverTypeOverride) },
|
onSuccess = {
|
||||||
|
onAuthenticationStartedSuccess(trigger, homeServerConnectionConfig, it, serverTypeOverride)
|
||||||
|
postAction()
|
||||||
|
},
|
||||||
onFailure = { onAuthenticationStartError(it, trigger) }
|
onFailure = { onAuthenticationStartError(it, trigger) }
|
||||||
)
|
)
|
||||||
setState { copy(isLoading = false) }
|
setState { copy(isLoading = false) }
|
||||||
|
|||||||
@ -48,6 +48,9 @@ data class OnboardingViewState(
|
|||||||
val knownCustomHomeServersUrls: List<String> = emptyList(),
|
val knownCustomHomeServersUrls: List<String> = emptyList(),
|
||||||
val isForceLoginFallbackEnabled: Boolean = false,
|
val isForceLoginFallbackEnabled: Boolean = false,
|
||||||
|
|
||||||
|
@PersistState
|
||||||
|
val registrationState: RegistrationState = RegistrationState(),
|
||||||
|
|
||||||
@PersistState
|
@PersistState
|
||||||
val selectedHomeserver: SelectedHomeserverState = SelectedHomeserverState(),
|
val selectedHomeserver: SelectedHomeserverState = SelectedHomeserverState(),
|
||||||
|
|
||||||
@ -95,3 +98,9 @@ data class ResetState(
|
|||||||
data class SelectedAuthenticationState(
|
data class SelectedAuthenticationState(
|
||||||
val description: AuthenticationDescription? = null,
|
val description: AuthenticationDescription? = null,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class RegistrationState(
|
||||||
|
val isUserNameAvailable: Boolean = false,
|
||||||
|
val selectedMatrixId: String? = null,
|
||||||
|
) : Parcelable
|
||||||
|
|||||||
@ -33,6 +33,8 @@ import im.vector.app.core.extensions.editText
|
|||||||
import im.vector.app.core.extensions.hasSurroundingSpaces
|
import im.vector.app.core.extensions.hasSurroundingSpaces
|
||||||
import im.vector.app.core.extensions.hideKeyboard
|
import im.vector.app.core.extensions.hideKeyboard
|
||||||
import im.vector.app.core.extensions.hidePassword
|
import im.vector.app.core.extensions.hidePassword
|
||||||
|
import im.vector.app.core.extensions.isMatrixId
|
||||||
|
import im.vector.app.core.extensions.onTextChange
|
||||||
import im.vector.app.core.extensions.realignPercentagesToParent
|
import im.vector.app.core.extensions.realignPercentagesToParent
|
||||||
import im.vector.app.core.extensions.setOnFocusLostListener
|
import im.vector.app.core.extensions.setOnFocusLostListener
|
||||||
import im.vector.app.core.extensions.setOnImeDoneListener
|
import im.vector.app.core.extensions.setOnImeDoneListener
|
||||||
@ -47,6 +49,7 @@ import im.vector.app.features.onboarding.OnboardingAction.AuthenticateAction
|
|||||||
import im.vector.app.features.onboarding.OnboardingViewEvents
|
import im.vector.app.features.onboarding.OnboardingViewEvents
|
||||||
import im.vector.app.features.onboarding.OnboardingViewState
|
import im.vector.app.features.onboarding.OnboardingViewState
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
import org.matrix.android.sdk.api.auth.data.SsoIdentityProvider
|
||||||
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
|
||||||
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
import org.matrix.android.sdk.api.failure.isInvalidPassword
|
||||||
@ -55,6 +58,7 @@ import org.matrix.android.sdk.api.failure.isLoginEmailUnknown
|
|||||||
import org.matrix.android.sdk.api.failure.isRegistrationDisabled
|
import org.matrix.android.sdk.api.failure.isRegistrationDisabled
|
||||||
import org.matrix.android.sdk.api.failure.isUsernameInUse
|
import org.matrix.android.sdk.api.failure.isUsernameInUse
|
||||||
import org.matrix.android.sdk.api.failure.isWeakPassword
|
import org.matrix.android.sdk.api.failure.isWeakPassword
|
||||||
|
import reactivecircus.flowbinding.android.widget.textChanges
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAuthFragment<FragmentFtueCombinedRegisterBinding>() {
|
class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAuthFragment<FragmentFtueCombinedRegisterBinding>() {
|
||||||
@ -69,6 +73,12 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu
|
|||||||
views.createAccountRoot.realignPercentagesToParent()
|
views.createAccountRoot.realignPercentagesToParent()
|
||||||
views.editServerButton.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.EditServerSelection)) }
|
views.editServerButton.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.EditServerSelection)) }
|
||||||
views.createAccountPasswordInput.setOnImeDoneListener { submit() }
|
views.createAccountPasswordInput.setOnImeDoneListener { submit() }
|
||||||
|
|
||||||
|
views.createAccountInput.onTextChange(viewLifecycleOwner) {
|
||||||
|
viewModel.handle(OnboardingAction.ResetSelectedRegistrationUserName)
|
||||||
|
views.createAccountEntryFooter.text = ""
|
||||||
|
}
|
||||||
|
|
||||||
views.createAccountInput.setOnFocusLostListener {
|
views.createAccountInput.setOnFocusLostListener {
|
||||||
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(views.createAccountInput.content()))
|
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(views.createAccountInput.content()))
|
||||||
}
|
}
|
||||||
@ -103,7 +113,12 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
viewModel.handle(AuthenticateAction.Register(login, password, getString(R.string.login_default_session_public_name)))
|
val initialDeviceName = getString(R.string.login_default_session_public_name)
|
||||||
|
val registerAction = when {
|
||||||
|
login.isMatrixId() -> AuthenticateAction.RegisterWithMatrixId(login, password, initialDeviceName)
|
||||||
|
else -> AuthenticateAction.Register(login, password, initialDeviceName)
|
||||||
|
}
|
||||||
|
viewModel.handle(registerAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,16 +168,25 @@ class FtueAuthCombinedRegisterFragment @Inject constructor() : AbstractSSOFtueAu
|
|||||||
override fun updateWithState(state: OnboardingViewState) {
|
override fun updateWithState(state: OnboardingViewState) {
|
||||||
setupUi(state)
|
setupUi(state)
|
||||||
setupAutoFill()
|
setupAutoFill()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupUi(state: OnboardingViewState) {
|
||||||
views.selectedServerName.text = state.selectedHomeserver.userFacingUrl.toReducedUrl()
|
views.selectedServerName.text = state.selectedHomeserver.userFacingUrl.toReducedUrl()
|
||||||
|
|
||||||
if (state.isLoading) {
|
if (state.isLoading) {
|
||||||
// Ensure password is hidden
|
// Ensure password is hidden
|
||||||
views.createAccountPasswordInput.editText().hidePassword()
|
views.createAccountPasswordInput.editText().hidePassword()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
views.createAccountEntryFooter.text = when {
|
||||||
|
state.registrationState.isUserNameAvailable -> getString(
|
||||||
|
R.string.ftue_auth_create_account_username_entry_footer,
|
||||||
|
state.registrationState.selectedMatrixId
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupUi(state: OnboardingViewState) {
|
|
||||||
when (state.selectedHomeserver.preferredLoginMode) {
|
when (state.selectedHomeserver.preferredLoginMode) {
|
||||||
is LoginMode.SsoAndPassword -> renderSsoProviders(state.deviceId, state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders)
|
is LoginMode.SsoAndPassword -> renderSsoProviders(state.deviceId, state.selectedHomeserver.preferredLoginMode.ssoIdentityProviders)
|
||||||
else -> hideSsoProviders()
|
else -> hideSsoProviders()
|
||||||
|
|||||||
@ -34,8 +34,8 @@
|
|||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/createAccountHeaderIcon"
|
app:layout_constraintBottom_toTopOf="@id/createAccountHeaderIcon"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_bias="0"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
app:layout_constraintVertical_chainStyle="packed" />
|
app:layout_constraintVertical_bias="0" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/createAccountHeaderIcon"
|
android:id="@+id/createAccountHeaderIcon"
|
||||||
@ -62,7 +62,7 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/ftue_auth_create_account_title"
|
android:text="@string/ftue_auth_create_account_title"
|
||||||
android:textColor="?vctr_content_primary"
|
android:textColor="?vctr_content_primary"
|
||||||
app:layout_constraintBottom_toTopOf="@id/createAccountHeaderTitle"
|
app:layout_constraintBottom_toTopOf="@id/titleContentSpacing"
|
||||||
app:layout_constraintEnd_toEndOf="@id/createAccountGutterEnd"
|
app:layout_constraintEnd_toEndOf="@id/createAccountGutterEnd"
|
||||||
app:layout_constraintStart_toStartOf="@id/createAccountGutterStart"
|
app:layout_constraintStart_toStartOf="@id/createAccountGutterStart"
|
||||||
app:layout_constraintTop_toBottomOf="@id/createAccountHeaderIcon" />
|
app:layout_constraintTop_toBottomOf="@id/createAccountHeaderIcon" />
|
||||||
@ -160,18 +160,18 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="@string/ftue_auth_create_account_username_entry_footer"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/entrySpacing"
|
app:layout_constraintBottom_toTopOf="@id/entrySpacing"
|
||||||
app:layout_constraintEnd_toEndOf="@id/createAccountGutterEnd"
|
app:layout_constraintEnd_toEndOf="@id/createAccountGutterEnd"
|
||||||
app:layout_constraintStart_toStartOf="@id/createAccountGutterStart"
|
app:layout_constraintStart_toStartOf="@id/createAccountGutterStart"
|
||||||
app:layout_constraintTop_toBottomOf="@id/createAccountInput" />
|
app:layout_constraintTop_toBottomOf="@id/createAccountInput"
|
||||||
|
tools:text="Others can discover you %s" />
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:id="@+id/entrySpacing"
|
android:id="@+id/entrySpacing"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toTopOf="@id/createAccountPasswordInput"
|
app:layout_constraintBottom_toTopOf="@id/createAccountPasswordInput"
|
||||||
app:layout_constraintHeight_percent="0.03"
|
app:layout_constraintHeight_percent="0.02"
|
||||||
app:layout_constraintTop_toBottomOf="@id/createAccountEntryFooter" />
|
app:layout_constraintTop_toBottomOf="@id/createAccountEntryFooter" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
|||||||
@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
<!-- WIP -->
|
<!-- WIP -->
|
||||||
<string name="ftue_auth_create_account_title">Create your account</string>
|
<string name="ftue_auth_create_account_title">Create your account</string>
|
||||||
<string name="ftue_auth_create_account_username_entry_footer">You can\'t change this later</string>
|
<!-- Note for translators, %s is the full matrix of the account being created, eg @hello:matrix.org -->
|
||||||
|
<string name="ftue_auth_create_account_username_entry_footer">Others can discover you %s</string>
|
||||||
<string name="ftue_auth_create_account_password_entry_footer">Must be 8 characters or more</string>
|
<string name="ftue_auth_create_account_password_entry_footer">Must be 8 characters or more</string>
|
||||||
<string name="ftue_auth_create_account_choose_server_header">Choose your server to store your data</string>
|
<string name="ftue_auth_create_account_choose_server_header">Where your conversations will live</string>
|
||||||
<string name="ftue_auth_create_account_sso_section_header">Or</string>
|
<string name="ftue_auth_create_account_sso_section_header">Or</string>
|
||||||
<string name="ftue_auth_create_account_matrix_dot_org_server_description">Join millions for free on the largest public server</string>
|
<string name="ftue_auth_create_account_matrix_dot_org_server_description">Join millions for free on the largest public server</string>
|
||||||
<string name="ftue_auth_create_account_edit_server_selection">Edit</string>
|
<string name="ftue_auth_create_account_edit_server_selection">Edit</string>
|
||||||
|
|||||||
@ -290,13 +290,13 @@ class OnboardingViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a full matrix id, when maybe updating homeserver, then updates selected homeserver state and emits edited event`() = runTest {
|
fun `given a full matrix id, when a login username is entered, then updates selected homeserver state and emits edited event`() = runTest {
|
||||||
viewModelWith(initialState.copy(onboardingFlow = OnboardingFlow.SignUp))
|
viewModelWith(initialState.copy(onboardingFlow = OnboardingFlow.SignIn))
|
||||||
givenCanSuccessfullyUpdateHomeserver(A_HOMESERVER_URL, SELECTED_HOMESERVER_STATE)
|
givenCanSuccessfullyUpdateHomeserver(A_HOMESERVER_URL, SELECTED_HOMESERVER_STATE)
|
||||||
val test = viewModel.test()
|
val test = viewModel.test()
|
||||||
val fullMatrixId = "@a-user:${A_HOMESERVER_URL.removePrefix("https://")}"
|
val fullMatrixId = "@a-user:${A_HOMESERVER_URL.removePrefix("https://")}"
|
||||||
|
|
||||||
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(fullMatrixId))
|
viewModel.handle(OnboardingAction.UserNameEnteredAction.Login(fullMatrixId))
|
||||||
|
|
||||||
test
|
test
|
||||||
.assertStatesChanges(
|
.assertStatesChanges(
|
||||||
@ -311,12 +311,11 @@ class OnboardingViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a username, when maybe updating homeserver, then does nothing`() = runTest {
|
fun `given a username, when a login username is entered, then does nothing`() = runTest {
|
||||||
viewModelWith(initialState.copy(onboardingFlow = OnboardingFlow.SignUp))
|
|
||||||
val test = viewModel.test()
|
val test = viewModel.test()
|
||||||
val onlyUsername = "a-username"
|
val onlyUsername = "a-username"
|
||||||
|
|
||||||
viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(onlyUsername))
|
viewModel.handle(OnboardingAction.UserNameEnteredAction.Login(onlyUsername))
|
||||||
|
|
||||||
test
|
test
|
||||||
.assertStates(initialState)
|
.assertStates(initialState)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user