Hide error when text is entered (#14)

This commit is contained in:
Kirill Kamakin
2021-11-27 19:36:30 +03:00
committed by GitHub
parent 44458dd146
commit a15fac7c7e
2 changed files with 39 additions and 4 deletions

View File

@@ -4,12 +4,15 @@ import android.app.Activity
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import android.view.WindowInsets import android.view.WindowInsets
import android.widget.TextView
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData import androidx.lifecycle.asLiveData
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.ChannelResult
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.onClosed import kotlinx.coroutines.channels.onClosed
import kotlinx.coroutines.channels.onFailure import kotlinx.coroutines.channels.onFailure
@@ -22,9 +25,7 @@ fun SwipeRefreshLayout.refreshesLiveData(): LiveData<Unit> {
val callbackFlow: Flow<Unit> = callbackFlow { val callbackFlow: Flow<Unit> = callbackFlow {
val listener = SwipeRefreshLayout.OnRefreshListener { val listener = SwipeRefreshLayout.OnRefreshListener {
Timber.v("Refresh requested") Timber.v("Refresh requested")
trySend(Unit) trySend(Unit).logErrors("refreshesFlow")
.onFailure { Timber.e(it, "refreshesFlow: can't send refresh callback") }
.onClosed { Timber.e(it, "refreshesFlow: flow has been closed") }
} }
Timber.v("Adding refresh request listener") Timber.v("Adding refresh request listener")
setOnRefreshListener(listener) setOnRefreshListener(listener)
@@ -61,3 +62,21 @@ fun AppCompatActivity.setActionBarVisibility(isVisible: Boolean) {
supportActionBar?.apply { if (isVisible) show() else hide() } supportActionBar?.apply { if (isVisible) show() else hide() }
?: Timber.w("setActionBarVisibility: action bar is null") ?: Timber.w("setActionBarVisibility: action bar is null")
} }
@ExperimentalCoroutinesApi
fun TextView.textChangesFlow(): Flow<CharSequence?> = callbackFlow {
Timber.v("textChangesFlow() called")
val textWatcher = doAfterTextChanged {
trySend(it).logErrors("textChangesFlow")
}
awaitClose {
Timber.d("textChangesFlow: flow is closing")
removeTextChangedListener(textWatcher)
}
}
fun <T> ChannelResult<T>.logErrors(methodName: String): ChannelResult<T> {
onFailure { Timber.e(it, "$methodName: can't send event") }
onClosed { Timber.e(it, "$methodName: flow has been closed") }
return this
}

View File

@@ -9,14 +9,20 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.data.auth.impl.AuthenticationError.* import gq.kirmanak.mealient.data.auth.impl.AuthenticationError.*
import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding
import gq.kirmanak.mealient.ui.textChangesFlow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import timber.log.Timber import timber.log.Timber
@ExperimentalCoroutinesApi
@AndroidEntryPoint @AndroidEntryPoint
class AuthenticationFragment : Fragment() { class AuthenticationFragment : Fragment() {
private var _binding: FragmentAuthenticationBinding? = null private var _binding: FragmentAuthenticationBinding? = null
@@ -107,13 +113,23 @@ class AuthenticationFragment : Fragment() {
Timber.v("checkIfInputIsEmpty() called with: input = $input, inputLayout = $inputLayout, errorText = $errorText") Timber.v("checkIfInputIsEmpty() called with: input = $input, inputLayout = $inputLayout, errorText = $errorText")
val text = input.text?.toString() val text = input.text?.toString()
Timber.d("Input text is \"$text\"") Timber.d("Input text is \"$text\"")
if (text.isNullOrBlank()) { if (text.isNullOrEmpty()) {
inputLayout.error = errorText() inputLayout.error = errorText()
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
waitUntilNotEmpty(input)
inputLayout.error = null
}
return null return null
} }
return text return text
} }
private suspend fun waitUntilNotEmpty(input: EditText) {
Timber.v("waitUntilNotEmpty() called with: input = $input")
input.textChangesFlow().filterNotNull().first { it.isNotEmpty() }
Timber.v("waitUntilNotEmpty() returned")
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
Timber.v("onDestroyView() called") Timber.v("onDestroyView() called")