Show load end/load failure toasts

This commit is contained in:
Kirill Kamakin
2022-11-04 22:13:57 +01:00
parent 714ff7d33f
commit 33bdaf9726
4 changed files with 72 additions and 1 deletions

View File

@@ -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)
}

View File

@@ -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" }

View File

@@ -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>

View File

@@ -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>