triggering an initial enabled state when using associateContentStateWith and extracts the resetting of errors on content change to an extension

This commit is contained in:
Adam Brown 2022-06-29 14:11:39 +01:00
parent 7c0d340bd0
commit 1361852721
5 changed files with 23 additions and 42 deletions

View File

@ -19,9 +19,13 @@ package im.vector.app.core.extensions
import android.text.Editable import android.text.Editable
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import im.vector.app.core.platform.SimpleTextWatcher import im.vector.app.core.platform.SimpleTextWatcher
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.textChanges import reactivecircus.flowbinding.android.widget.textChanges
fun TextInputLayout.editText() = this.editText!! fun TextInputLayout.editText() = this.editText!!
@ -37,11 +41,18 @@ fun TextInputLayout.content() = editText().text.toString()
fun TextInputLayout.hasContent() = !editText().text.isNullOrEmpty() fun TextInputLayout.hasContent() = !editText().text.isNullOrEmpty()
fun TextInputLayout.associateContentStateWith(button: View) { fun TextInputLayout.clearErrorOnChange(lifecycleOwner: LifecycleOwner) {
editText().textChanges()
.onEach { error = null }
.launchIn(lifecycleOwner.lifecycleScope)
}
fun TextInputLayout.associateContentStateWith(button: View, enabledPredicate: (String) -> Boolean = { it.isNotEmpty() }) {
button.isEnabled = enabledPredicate(content())
editText().addTextChangedListener(object : SimpleTextWatcher() { editText().addTextChangedListener(object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
val newContent = s.toString() val newContent = s.toString()
button.isEnabled = newContent.isNotEmpty() button.isEnabled = enabledPredicate(newContent)
} }
}) })
} }

View File

@ -21,8 +21,8 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import androidx.lifecycle.lifecycleScope
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.clearErrorOnChange
import im.vector.app.core.extensions.content import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.realignPercentagesToParent import im.vector.app.core.extensions.realignPercentagesToParent
@ -34,10 +34,7 @@ import im.vector.app.databinding.FragmentFtueServerSelectionCombinedBinding
import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingAction
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.onEach
import org.matrix.android.sdk.api.failure.isHomeserverUnavailable import org.matrix.android.sdk.api.failure.isHomeserverUnavailable
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject import javax.inject.Inject
class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFtueAuthFragment<FragmentFtueServerSelectionCombinedBinding>() { class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFtueAuthFragment<FragmentFtueServerSelectionCombinedBinding>() {
@ -66,9 +63,7 @@ class FtueAuthCombinedServerSelectionFragment @Inject constructor() : AbstractFt
} }
views.chooseServerGetInTouch.debouncedClicks { openUrlInExternalBrowser(requireContext(), getString(R.string.ftue_ems_url)) } views.chooseServerGetInTouch.debouncedClicks { openUrlInExternalBrowser(requireContext(), getString(R.string.ftue_ems_url)) }
views.chooseServerSubmit.debouncedClicks { updateServerUrl() } views.chooseServerSubmit.debouncedClicks { updateServerUrl() }
views.chooseServerInput.editText().textChanges() views.chooseServerInput.clearErrorOnChange(viewLifecycleOwner)
.onEach { views.chooseServerInput.error = null }
.launchIn(viewLifecycleOwner.lifecycleScope)
} }
private fun updateServerUrl() { private fun updateServerUrl() {

View File

@ -20,19 +20,15 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import im.vector.app.core.extensions.associateContentStateWith import im.vector.app.core.extensions.associateContentStateWith
import im.vector.app.core.extensions.clearErrorOnChange
import im.vector.app.core.extensions.content import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.isEmail
import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.core.extensions.setOnImeDoneListener
import im.vector.app.databinding.FragmentFtueEmailInputBinding import im.vector.app.databinding.FragmentFtueEmailInputBinding
import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.RegisterAction import im.vector.app.features.onboarding.RegisterAction
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.auth.registration.RegisterThreePid import org.matrix.android.sdk.api.auth.registration.RegisterThreePid
import reactivecircus.flowbinding.android.widget.textChanges
import javax.inject.Inject import javax.inject.Inject
class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragment<FragmentFtueEmailInputBinding>() { class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragment<FragmentFtueEmailInputBinding>() {
@ -47,16 +43,10 @@ class FtueAuthEmailEntryFragment @Inject constructor() : AbstractFtueAuthFragmen
} }
private fun setupViews() { private fun setupViews() {
views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit) views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit, enabledPredicate = { it.isEmail() })
views.emailEntryInput.setOnImeDoneListener { updateEmail() } views.emailEntryInput.setOnImeDoneListener { updateEmail() }
views.emailEntryInput.clearErrorOnChange(viewLifecycleOwner)
views.emailEntrySubmit.debouncedClicks { updateEmail() } views.emailEntrySubmit.debouncedClicks { updateEmail() }
views.emailEntryInput.editText().textChanges()
.onEach {
views.emailEntryInput.error = null
views.emailEntrySubmit.isEnabled = it.isEmail()
}
.launchIn(viewLifecycleOwner.lifecycleScope)
} }
private fun updateEmail() { private fun updateEmail() {

View File

@ -20,18 +20,14 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.associateContentStateWith import im.vector.app.core.extensions.associateContentStateWith
import im.vector.app.core.extensions.clearErrorOnChange
import im.vector.app.core.extensions.content import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.isEmail
import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.core.extensions.setOnImeDoneListener
import im.vector.app.databinding.FragmentFtueResetPasswordEmailInputBinding import im.vector.app.databinding.FragmentFtueResetPasswordEmailInputBinding
import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingAction
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.textChanges
@AndroidEntryPoint @AndroidEntryPoint
class FtueAuthResetPasswordEmailEntryFragment : AbstractFtueAuthFragment<FragmentFtueResetPasswordEmailInputBinding>() { class FtueAuthResetPasswordEmailEntryFragment : AbstractFtueAuthFragment<FragmentFtueResetPasswordEmailInputBinding>() {
@ -46,14 +42,9 @@ class FtueAuthResetPasswordEmailEntryFragment : AbstractFtueAuthFragment<Fragmen
} }
private fun setupViews() { private fun setupViews() {
views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit) views.emailEntryInput.associateContentStateWith(button = views.emailEntrySubmit, enabledPredicate = { it.isEmail() })
views.emailEntryInput.setOnImeDoneListener { startPasswordReset() } views.emailEntryInput.setOnImeDoneListener { startPasswordReset() }
views.emailEntryInput.editText().textChanges() views.emailEntryInput.clearErrorOnChange(viewLifecycleOwner)
.onEach {
views.emailEntryInput.error = null
views.emailEntrySubmit.isEnabled = it.isEmail()
}
.launchIn(viewLifecycleOwner.lifecycleScope)
views.emailEntrySubmit.debouncedClicks { startPasswordReset() } views.emailEntrySubmit.debouncedClicks { startPasswordReset() }
} }

View File

@ -21,20 +21,16 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.associateContentStateWith import im.vector.app.core.extensions.associateContentStateWith
import im.vector.app.core.extensions.clearErrorOnChange
import im.vector.app.core.extensions.content import im.vector.app.core.extensions.content
import im.vector.app.core.extensions.editText import im.vector.app.core.extensions.editText
import im.vector.app.core.extensions.hidePassword import im.vector.app.core.extensions.hidePassword
import im.vector.app.core.extensions.isEmail
import im.vector.app.core.extensions.setOnImeDoneListener import im.vector.app.core.extensions.setOnImeDoneListener
import im.vector.app.databinding.FragmentFtueResetPasswordInputBinding import im.vector.app.databinding.FragmentFtueResetPasswordInputBinding
import im.vector.app.features.onboarding.OnboardingAction import im.vector.app.features.onboarding.OnboardingAction
import im.vector.app.features.onboarding.OnboardingViewState import im.vector.app.features.onboarding.OnboardingViewState
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.android.widget.textChanges
@AndroidEntryPoint @AndroidEntryPoint
class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment<FragmentFtueResetPasswordInputBinding>() { class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment<FragmentFtueResetPasswordInputBinding>() {
@ -51,9 +47,7 @@ class FtueAuthResetPasswordEntryFragment : AbstractFtueAuthFragment<FragmentFtue
private fun setupViews() { private fun setupViews() {
views.newPasswordInput.associateContentStateWith(button = views.newPasswordSubmit) views.newPasswordInput.associateContentStateWith(button = views.newPasswordSubmit)
views.newPasswordInput.setOnImeDoneListener { resetPassword() } views.newPasswordInput.setOnImeDoneListener { resetPassword() }
views.newPasswordInput.editText().textChanges() views.newPasswordInput.clearErrorOnChange(viewLifecycleOwner)
.onEach { views.newPasswordInput.error = null }
.launchIn(viewLifecycleOwner.lifecycleScope)
views.newPasswordSubmit.debouncedClicks { resetPassword() } views.newPasswordSubmit.debouncedClicks { resetPassword() }
} }