Hide edit text cursor on list scroll

This commit is contained in:
Kirill Kamakin
2022-11-20 15:49:14 +01:00
parent cadb762ed4
commit d7c94d29d4
5 changed files with 31 additions and 27 deletions

View File

@@ -2,19 +2,11 @@ package gq.kirmanak.mealient.extensions
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.launch
fun <T> Fragment.collectWhenViewResumed(flow: Flow<T>, collector: FlowCollector<T>) { fun <T> Fragment.collectWhenViewResumed(flow: Flow<T>, collector: FlowCollector<T>) {
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.collectWhenResumed(flow, collector)
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
flow.collect(collector)
}
}
} }
fun Fragment.showLongToast(@StringRes text: Int) = context?.showLongToast(text) != null fun Fragment.showLongToast(@StringRes text: Int) = context?.showLongToast(text) != null

View File

@@ -13,10 +13,7 @@ import android.widget.Toast
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.widget.doAfterTextChanged import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.*
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import gq.kirmanak.mealient.logging.Logger import gq.kirmanak.mealient.logging.Logger
@@ -24,10 +21,7 @@ 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
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
fun SwipeRefreshLayout.refreshRequestFlow(logger: Logger): Flow<Unit> = callbackFlow { fun SwipeRefreshLayout.refreshRequestFlow(logger: Logger): Flow<Unit> = callbackFlow {
@@ -125,3 +119,11 @@ fun Context.isDarkThemeOn(): Boolean {
else else
resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
} }
fun <T> LifecycleOwner.collectWhenResumed(flow: Flow<T>, collector: FlowCollector<T>) {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
flow.collect(collector)
}
}
}

View File

@@ -20,6 +20,7 @@ import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalBaseURLFrag
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalRecipesListFragment import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalRecipesListFragment
import gq.kirmanak.mealient.R import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.databinding.MainActivityBinding import gq.kirmanak.mealient.databinding.MainActivityBinding
import gq.kirmanak.mealient.extensions.collectWhenResumed
import gq.kirmanak.mealient.extensions.isDarkThemeOn import gq.kirmanak.mealient.extensions.isDarkThemeOn
import gq.kirmanak.mealient.extensions.observeOnce import gq.kirmanak.mealient.extensions.observeOnce
import gq.kirmanak.mealient.logging.Logger import gq.kirmanak.mealient.logging.Logger
@@ -69,6 +70,10 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
isAppearanceLightStatusBars = isAppearanceLightBars isAppearanceLightStatusBars = isAppearanceLightBars
} }
viewModel.uiStateLive.observe(this, ::onUiStateChange) viewModel.uiStateLive.observe(this, ::onUiStateChange)
collectWhenResumed(viewModel.clearSearchViewFocus) {
logger.d { "clearSearchViewFocus(): received event" }
binding.toolbar.clearSearchFocus()
}
} }
private fun onNavigationItemSelected(menuItem: MenuItem): Boolean { private fun onNavigationItemSelected(menuItem: MenuItem): Boolean {

View File

@@ -8,8 +8,11 @@ import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
import gq.kirmanak.mealient.data.recipes.RecipeRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.logging.Logger import gq.kirmanak.mealient.logging.Logger
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@@ -32,6 +35,9 @@ class MainActivityViewModel @Inject constructor(
private val _startDestination = MutableLiveData<Int>() private val _startDestination = MutableLiveData<Int>()
val startDestination: LiveData<Int> = _startDestination val startDestination: LiveData<Int> = _startDestination
private val _clearSearchViewFocusChannel = Channel<Unit>()
val clearSearchViewFocus: Flow<Unit> = _clearSearchViewFocusChannel.receiveAsFlow()
init { init {
authRepo.isAuthorizedFlow authRepo.isAuthorizedFlow
.onEach { isAuthorized -> updateUiState { it.copy(isAuthorized = isAuthorized) } } .onEach { isAuthorized -> updateUiState { it.copy(isAuthorized = isAuthorized) } }
@@ -59,4 +65,9 @@ class MainActivityViewModel @Inject constructor(
logger.v { "onSearchQuery() called with: query = $query" } logger.v { "onSearchQuery() called with: query = $query" }
recipeRepo.updateNameQuery(query) recipeRepo.updateNameQuery(query)
} }
fun clearSearchViewFocus() {
logger.v { "clearSearchViewFocus() called" }
_clearSearchViewFocusChannel.trySend(Unit)
}
} }

View File

@@ -61,8 +61,8 @@ class RecipesListFragment : Fragment(R.layout.fragment_recipes_list) {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun hideKeyboardOnScroll() { private fun hideKeyboardOnScroll() {
binding.recipes.setOnTouchListener { view, _ -> binding.recipes.setOnTouchListener { _, _ ->
view?.hideKeyboard() activityViewModel.clearSearchViewFocus()
false false
} }
} }
@@ -155,18 +155,12 @@ private fun Throwable.toLoadErrorReasonText(): Int? = when (this) {
} }
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.refreshErrors(): Flow<Throwable> { private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.refreshErrors(): Flow<Throwable> {
return loadStateFlow return loadStateFlow.map { it.refresh }.valueUpdatesOnly().filterIsInstance<LoadState.Error>()
.map { it.refresh }
.valueUpdatesOnly()
.filterIsInstance<LoadState.Error>()
.map { it.error } .map { it.error }
} }
private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.appendPaginationEnd(): Flow<Unit> { private fun <T : Any, VH : RecyclerView.ViewHolder> PagingDataAdapter<T, VH>.appendPaginationEnd(): Flow<Unit> {
return loadStateFlow return loadStateFlow.map { it.append.endOfPaginationReached }.valueUpdatesOnly().filter { it }
.map { it.append.endOfPaginationReached }
.valueUpdatesOnly()
.filter { it }
.map { } .map { }
} }