Show load end/load failure toasts
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
package gq.kirmanak.mealient.extensions
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
|
||||
fun <T> Fragment.collectWhenViewResumed(
|
||||
flow: Flow<T>,
|
||||
@@ -13,4 +15,8 @@ fun <T> Fragment.collectWhenViewResumed(
|
||||
|
||||
fun Fragment.launchWhenViewResumed(
|
||||
block: suspend CoroutineScope.() -> Unit,
|
||||
) = viewLifecycleOwner.lifecycleScope.launchWhenResumed(block)
|
||||
) = viewLifecycleOwner.lifecycleScope.launchWhenResumed(block)
|
||||
|
||||
fun <T> Flow<T>.launchIn(lifecycleOwner: LifecycleOwner) {
|
||||
launchIn(lifecycleOwner.lifecycleScope)
|
||||
}
|
||||
@@ -2,21 +2,26 @@ package gq.kirmanak.mealient.ui.recipes
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.paging.LoadState
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import gq.kirmanak.mealient.R
|
||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.databinding.FragmentRecipesBinding
|
||||
import gq.kirmanak.mealient.datasource.NetworkError
|
||||
import gq.kirmanak.mealient.extensions.collectWhenViewResumed
|
||||
import gq.kirmanak.mealient.extensions.launchIn
|
||||
import gq.kirmanak.mealient.extensions.refreshRequestFlow
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||
import gq.kirmanak.mealient.ui.recipes.images.RecipeImageLoader
|
||||
import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -78,6 +83,8 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
||||
binding.refresher.isRefreshing = false
|
||||
}
|
||||
|
||||
observeLoadStateChanges(recipesAdapter)
|
||||
|
||||
collectWhenViewResumed(binding.refresher.refreshRequestFlow(logger)) {
|
||||
logger.v { "setupRecipeAdapter: received refresh request" }
|
||||
recipesAdapter.refresh()
|
||||
@@ -93,6 +100,52 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeLoadStateChanges(recipesAdapter: RecipesPagingAdapter) {
|
||||
recipesAdapter.loadStateFlow
|
||||
.map { it.append }
|
||||
.distinctUntilChanged()
|
||||
.filter { it.endOfPaginationReached }
|
||||
.onEach { onPaginationEnd() }
|
||||
.launchIn(viewLifecycleOwner)
|
||||
|
||||
recipesAdapter.loadStateFlow
|
||||
.map { it.refresh }
|
||||
.distinctUntilChanged()
|
||||
.filterIsInstance<LoadState.Error>()
|
||||
.onEach { onLoadFailure(it.error) }
|
||||
.launchIn(viewLifecycleOwner)
|
||||
}
|
||||
|
||||
private fun onPaginationEnd() {
|
||||
logger.v { "onPaginationEnd() called" }
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.fragment_recipes_last_page_loaded_toast),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
private fun onLoadFailure(error: Throwable) {
|
||||
logger.v(error) { "onLoadFailure() called" }
|
||||
|
||||
val reason = when (error) {
|
||||
is NetworkError.Unauthorized -> R.string.fragment_recipes_load_failure_toast_unauthorized
|
||||
is NetworkError.NoServerConnection -> R.string.fragment_recipes_load_failure_toast_no_connection
|
||||
is NetworkError.NotMealie, is NetworkError.MalformedUrl -> R.string.fragment_recipes_load_failure_toast_unexpected_response
|
||||
else -> null
|
||||
}?.let { getString(it) }
|
||||
|
||||
val generalText = getString(R.string.fragment_recipes_load_failure_toast_general)
|
||||
|
||||
val text = if (reason == null) {
|
||||
generalText
|
||||
} else {
|
||||
getString(R.string.fragment_recipes_load_failure_toast, generalText, reason)
|
||||
}
|
||||
|
||||
Toast.makeText(requireContext(), text, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
logger.v { "onDestroyView() called" }
|
||||
|
||||
@@ -41,4 +41,10 @@
|
||||
<string name="fragment_base_url_url_input_helper_text">Пример: demo.mealie.io</string>
|
||||
<string name="fragment_authentication_email_input_helper_text">Пример: changeme@email.com</string>
|
||||
<string name="fragment_authentication_password_input_helper_text">Пример: demo</string>
|
||||
<string name="fragment_recipes_last_page_loaded_toast">Последняя страница</string>
|
||||
<string name="fragment_recipes_load_failure_toast">%1$s %2$s</string>
|
||||
<string name="fragment_recipes_load_failure_toast_general">Ошибка загрузки.</string>
|
||||
<string name="fragment_recipes_load_failure_toast_unauthorized">Неавторизован</string>
|
||||
<string name="fragment_recipes_load_failure_toast_unexpected_response">Неожиданный ответ</string>
|
||||
<string name="fragment_recipes_load_failure_toast_no_connection">Нет соединения</string>
|
||||
</resources>
|
||||
@@ -45,4 +45,10 @@
|
||||
<string name="fragment_base_url_url_input_helper_text">Example: demo.mealie.io</string>
|
||||
<string name="fragment_authentication_email_input_helper_text">Example: changeme@email.com</string>
|
||||
<string name="fragment_authentication_password_input_helper_text">Example: demo</string>
|
||||
<string name="fragment_recipes_last_page_loaded_toast">Last page loaded</string>
|
||||
<string name="fragment_recipes_load_failure_toast" comment="EXAMPLE: Load failed! Unauthorized">%1$s %2$s</string>
|
||||
<string name="fragment_recipes_load_failure_toast_general">Load failed.</string>
|
||||
<string name="fragment_recipes_load_failure_toast_unauthorized">Unauthorized</string>
|
||||
<string name="fragment_recipes_load_failure_toast_unexpected_response">Unexpected response</string>
|
||||
<string name="fragment_recipes_load_failure_toast_no_connection">No connection</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user