diff --git a/app/src/main/java/gq/kirmanak/mealient/data/recipes/RecipeRepo.kt b/app/src/main/java/gq/kirmanak/mealient/data/recipes/RecipeRepo.kt index 4cd3b1b..1c200b1 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/recipes/RecipeRepo.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/recipes/RecipeRepo.kt @@ -10,4 +10,6 @@ interface RecipeRepo { suspend fun clearLocalData() suspend fun loadRecipeInfo(recipeId: String, recipeSlug: String): FullRecipeEntity + + suspend fun loadRecipeInfoFromDb(recipeId: String, recipeSlug: String): FullRecipeEntity? } \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/data/recipes/impl/RecipeRepoImpl.kt b/app/src/main/java/gq/kirmanak/mealient/data/recipes/impl/RecipeRepoImpl.kt index a48691f..c6412c7 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/recipes/impl/RecipeRepoImpl.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/recipes/impl/RecipeRepoImpl.kt @@ -49,4 +49,14 @@ class RecipeRepoImpl @Inject constructor( return storage.queryRecipeInfo(recipeId) } + + override suspend fun loadRecipeInfoFromDb( + recipeId: String, + recipeSlug: String + ): FullRecipeEntity? { + logger.v { "loadRecipeInfoFromDb() called with: recipeId = $recipeId, recipeSlug = $recipeSlug" } + return runCatchingExceptCancel { storage.queryRecipeInfo(recipeId) } + .onFailure { logger.e(it) { "loadRecipeInfoFromDb failed" } } + .getOrNull() + } } \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipeViewModel.kt b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipeViewModel.kt index 7e3a733..9fe0df0 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipeViewModel.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipeViewModel.kt @@ -1,13 +1,13 @@ package gq.kirmanak.mealient.ui.recipes -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.* import androidx.paging.cachedIn import dagger.hilt.android.lifecycle.HiltViewModel import gq.kirmanak.mealient.data.auth.AuthRepo import gq.kirmanak.mealient.data.recipes.RecipeRepo +import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity +import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity +import gq.kirmanak.mealient.datasource.runCatchingExceptCancel import gq.kirmanak.mealient.extensions.valueUpdatesOnly import gq.kirmanak.mealient.logging.Logger import kotlinx.coroutines.flow.launchIn @@ -16,7 +16,7 @@ import javax.inject.Inject @HiltViewModel class RecipeViewModel @Inject constructor( - recipeRepo: RecipeRepo, + private val recipeRepo: RecipeRepo, authRepo: AuthRepo, private val logger: Logger, ) : ViewModel() { @@ -37,4 +37,13 @@ class RecipeViewModel @Inject constructor( logger.v { "onAuthorizationSuccessHandled() called" } _isAuthorized.postValue(null) } + + fun loadRecipeInfo( + summaryEntity: RecipeSummaryEntity + ): LiveData> = liveData { + val result = runCatchingExceptCancel { + recipeRepo.loadRecipeInfo(summaryEntity.remoteId, summaryEntity.slug) + } + emit(result) + } } \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt index b0fe05b..37c9af8 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/RecipesFragment.kt @@ -3,6 +3,7 @@ package gq.kirmanak.mealient.ui.recipes import android.os.Bundle import android.view.View import androidx.annotation.StringRes +import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels @@ -16,10 +17,7 @@ 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.refreshRequestFlow -import gq.kirmanak.mealient.extensions.showLongToast -import gq.kirmanak.mealient.extensions.valueUpdatesOnly +import gq.kirmanak.mealient.extensions.* import gq.kirmanak.mealient.logging.Logger import gq.kirmanak.mealient.ui.activity.MainActivityViewModel import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory @@ -45,6 +43,8 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) { @Inject lateinit var recipePreloaderFactory: RecipePreloaderFactory + private var ignoreRecipeClicks = false + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) logger.v { "onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState" } @@ -63,10 +63,22 @@ class RecipesFragment : Fragment(R.layout.fragment_recipes) { ) } + private fun onRecipeClicked(recipe: RecipeSummaryEntity) { + logger.d { "onRecipeClicked() called with: recipe = $recipe" } + if (ignoreRecipeClicks) return + binding.progress.isVisible = true + ignoreRecipeClicks = true // TODO doesn't really work + viewModel.loadRecipeInfo(recipe).observeOnce(viewLifecycleOwner) { result -> + binding.progress.isVisible = false + if (result.isSuccess) navigateToRecipeInfo(recipe) + ignoreRecipeClicks = false + } + } + private fun setupRecipeAdapter() { logger.v { "setupRecipeAdapter() called" } - val recipesAdapter = recipePagingAdapterFactory.build { navigateToRecipeInfo(it) } + val recipesAdapter = recipePagingAdapterFactory.build { onRecipeClicked(it) } with(binding.recipes) { adapter = recipesAdapter @@ -135,17 +147,11 @@ private fun Throwable.toLoadErrorReasonText(): Int? = when (this) { } private fun PagingDataAdapter.refreshErrors(): Flow { - return loadStateFlow - .map { it.refresh } - .valueUpdatesOnly() - .filterIsInstance() + return loadStateFlow.map { it.refresh }.valueUpdatesOnly().filterIsInstance() .map { it.error } } private fun PagingDataAdapter.appendPaginationEnd(): Flow { - return loadStateFlow - .map { it.append.endOfPaginationReached } - .valueUpdatesOnly() - .filter { it } + return loadStateFlow.map { it.append.endOfPaginationReached }.valueUpdatesOnly().filter { it } .map { } } diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/info/RecipeInfoViewModel.kt b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/info/RecipeInfoViewModel.kt index fb73554..6abe446 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/recipes/info/RecipeInfoViewModel.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/recipes/info/RecipeInfoViewModel.kt @@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.liveData import dagger.hilt.android.lifecycle.HiltViewModel import gq.kirmanak.mealient.data.recipes.RecipeRepo -import gq.kirmanak.mealient.datasource.runCatchingExceptCancel import gq.kirmanak.mealient.logging.Logger import javax.inject.Inject @@ -21,20 +20,14 @@ class RecipeInfoViewModel @Inject constructor( val uiState: LiveData = liveData { logger.v { "Initializing UI state with args = $args" } - emit(RecipeInfoUiState()) - runCatchingExceptCancel { - recipeRepo.loadRecipeInfo(args.recipeId, args.recipeSlug) - }.onSuccess { - logger.d { "loadRecipeInfo: received recipe info = $it" } - val newState = RecipeInfoUiState( + val state = recipeRepo.loadRecipeInfoFromDb(args.recipeId, args.recipeSlug)?.let { + RecipeInfoUiState( areIngredientsVisible = it.recipeIngredients.isNotEmpty(), areInstructionsVisible = it.recipeInstructions.isNotEmpty(), recipeInfo = it, ) - emit(newState) - }.onFailure { - logger.e(it) { "loadRecipeInfo: can't load recipe info" } - } + } ?: RecipeInfoUiState() + emit(state) } } diff --git a/app/src/main/res/layout/fragment_recipes.xml b/app/src/main/res/layout/fragment_recipes.xml index 878c94e..3a9f114 100644 --- a/app/src/main/res/layout/fragment_recipes.xml +++ b/app/src/main/res/layout/fragment_recipes.xml @@ -19,4 +19,10 @@ tools:listitem="@layout/view_holder_recipe" /> + + \ No newline at end of file