Hide error when text is entered (#14)
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user