From d50b690523a68555b6dadc2d5539e2f4f173e21c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 14 Nov 2019 21:48:06 +0100 Subject: [PATCH] Login screens: improve LoginFragment --- .../im/vector/riotx/core/utils/ViewUtils.kt | 55 +++++++++++++++++++ .../riotx/features/login/LoginFragment.kt | 39 +++++++++++-- .../riotx/features/login/LoginViewModel.kt | 1 + vector/src/main/res/layout/fragment_login.xml | 20 +++++-- 4 files changed, 103 insertions(+), 12 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/core/utils/ViewUtils.kt diff --git a/vector/src/main/java/im/vector/riotx/core/utils/ViewUtils.kt b/vector/src/main/java/im/vector/riotx/core/utils/ViewUtils.kt new file mode 100644 index 0000000000..335b9112ef --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/utils/ViewUtils.kt @@ -0,0 +1,55 @@ +/* + * 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.core.utils + +import android.text.Editable +import android.view.ViewGroup +import androidx.core.view.children +import com.google.android.material.textfield.TextInputLayout +import im.vector.riotx.core.platform.SimpleTextWatcher + +/** + * Find all TextInputLayout in a ViewGroup and in all its descendants + */ +fun ViewGroup.findAllTextInputLayout(): List { + val res = ArrayList() + + children.forEach { + if (it is TextInputLayout) { + res.add(it) + } else if (it is ViewGroup) { + // Recursive call + res.addAll(it.findAllTextInputLayout()) + } + } + + return res +} + +/** + * Add a text change listener to all TextInputEditText to reset error on its TextInputLayout when the text is changed + */ +fun autoResetTextInputLayoutErrors(textInputLayouts: List) { + textInputLayouts.forEach { + it.editText?.addTextChangedListener(object : SimpleTextWatcher() { + override fun afterTextChanged(s: Editable) { + // Reset the error + it.error = null + } + }) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index 571305b722..4cd25d7640 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -18,7 +18,7 @@ package im.vector.riotx.features.login import android.os.Bundle import android.view.View -import androidx.transition.TransitionManager +import androidx.core.view.isVisible import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Success @@ -69,9 +69,14 @@ class LoginFragment @Inject constructor( isLoginNotEmpty && isPasswordNotEmpty } ) - .subscribeBy { authenticateButton.isEnabled = it } - .disposeOnDestroyView() - authenticateButton.setOnClickListener { authenticate() } + .subscribeBy { + loginFieldTil.error = null + passwordFieldTil.error = null + loginSubmit.isEnabled = it + } + .disposeOnDestroy() + + loginSubmit.setOnClickListener { authenticate() } } // // TODO Move to server selection screen @@ -108,7 +113,28 @@ class LoginFragment @Inject constructor( } override fun invalidate() = withState(viewModel) { state -> - TransitionManager.beginDelayedTransition(login_fragment) + when (state.serverType) { + ServerType.MatrixOrg -> { + loginServerIcon.isVisible = true + loginServerIcon.setImageResource(R.drawable.ic_logo_matrix_org) + loginTitle.text = getString(R.string.login_connect_to, "matrix.org") + loginNotice.text = getString(R.string.login_server_matrix_org_text) + } + ServerType.Modular -> { + loginServerIcon.isVisible = true + loginServerIcon.setImageResource(R.drawable.ic_logo_modular) + // TODO + loginTitle.text = getString(R.string.login_connect_to, "TODO") + // TODO Remove https:// + loginNotice.text = viewModel.getHomeServerUrl() + } + ServerType.Other -> { + loginServerIcon.isVisible = false + loginTitle.text = getString(R.string.login_server_other_title) + // TODO Remove https:// + loginNotice.text = viewModel.getHomeServerUrl() + } + } when (state.asyncLoginAction) { is Loading -> { @@ -117,8 +143,9 @@ class LoginFragment @Inject constructor( renderPasswordField() } is Fail -> { + // TODO This does not work, we want the error to be on without text. Fix that + loginFieldTil.error = "" // TODO Handle error text properly - // TODO Reset error when text is changed passwordFieldTil.error = errorFormatter.toHumanReadable(state.asyncLoginAction.error) } // Success is handled by the LoginActivity diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt index ab50d6f036..96f8d5ea99 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginViewModel.kt @@ -152,6 +152,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi } override fun onFailure(failure: Throwable) { + // TODO Handled JobCancellationException setState { copy( asyncLoginAction = Fail(failure) diff --git a/vector/src/main/res/layout/fragment_login.xml b/vector/src/main/res/layout/fragment_login.xml index 03efb60ab2..708afd6943 100644 --- a/vector/src/main/res/layout/fragment_login.xml +++ b/vector/src/main/res/layout/fragment_login.xml @@ -25,24 +25,32 @@ style="@style/LoginTopIcon" android:layout_gravity="center_horizontal" /> - + + + android:textAppearance="@style/TextAppearance.Vector.Login.Text.Small" + tools:text="@string/login_server_matrix_org_text" />