Update favorite status on icon click
This commit is contained in:
@@ -68,4 +68,26 @@ class MealieDataSourceWrapper @Inject constructor(
|
||||
ServerVersion.V0 -> v0Source.requestUserInfo().favoriteRecipes
|
||||
ServerVersion.V1 -> v1Source.requestUserInfo().favoriteRecipes
|
||||
}
|
||||
|
||||
override suspend fun removeFavoriteRecipe(recipeSlug: String) = when (getVersion()) {
|
||||
ServerVersion.V0 -> {
|
||||
val userId = v0Source.requestUserInfo().id
|
||||
v0Source.removeFavoriteRecipe(userId, recipeSlug)
|
||||
}
|
||||
ServerVersion.V1 -> {
|
||||
val userId = v1Source.requestUserInfo().id
|
||||
v1Source.removeFavoriteRecipe(userId, recipeSlug)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun addFavoriteRecipe(recipeSlug: String) = when (getVersion()) {
|
||||
ServerVersion.V0 -> {
|
||||
val userId = v0Source.requestUserInfo().id
|
||||
v0Source.addFavoriteRecipe(userId, recipeSlug)
|
||||
}
|
||||
ServerVersion.V1 -> {
|
||||
val userId = v1Source.requestUserInfo().id
|
||||
v1Source.addFavoriteRecipe(userId, recipeSlug)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,4 +17,8 @@ interface RecipeRepo {
|
||||
fun updateNameQuery(name: String?)
|
||||
|
||||
suspend fun refreshRecipes()
|
||||
|
||||
suspend fun removeFavoriteRecipe(recipeSlug: String)
|
||||
|
||||
suspend fun addFavoriteRecipe(recipeSlug: String)
|
||||
}
|
||||
@@ -72,6 +72,24 @@ class RecipeRepoImpl @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun removeFavoriteRecipe(recipeSlug: String) {
|
||||
logger.v { "removeFavoriteRecipe() called with: recipeSlug = $recipeSlug" }
|
||||
runCatchingExceptCancel {
|
||||
dataSource.removeFavoriteRecipe(recipeSlug)
|
||||
}.onFailure {
|
||||
logger.e(it) { "Can't remove a favorite recipe" }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun addFavoriteRecipe(recipeSlug: String) {
|
||||
logger.v { "addFavoriteRecipe() called with: recipeSlug = $recipeSlug" }
|
||||
runCatchingExceptCancel {
|
||||
dataSource.addFavoriteRecipe(recipeSlug)
|
||||
}.onFailure {
|
||||
logger.e(it) { "Can't add a favorite recipe" }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val LOAD_PAGE_SIZE = 50
|
||||
private const val INITIAL_LOAD_PAGE_SIZE = LOAD_PAGE_SIZE * 3
|
||||
|
||||
@@ -6,4 +6,8 @@ interface RecipeDataSource {
|
||||
suspend fun requestRecipeInfo(slug: String): FullRecipeInfo
|
||||
|
||||
suspend fun getFavoriteRecipes(): List<String>
|
||||
|
||||
suspend fun removeFavoriteRecipe(recipeSlug: String)
|
||||
|
||||
suspend fun addFavoriteRecipe(recipeSlug: String)
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package gq.kirmanak.mealient.ui.recipes
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.hilt.android.scopes.FragmentScoped
|
||||
import gq.kirmanak.mealient.R
|
||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.databinding.ViewHolderRecipeBinding
|
||||
@@ -10,28 +11,41 @@ import gq.kirmanak.mealient.extensions.resources
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import gq.kirmanak.mealient.ui.recipes.images.RecipeImageLoader
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class RecipeViewHolder private constructor(
|
||||
private val logger: Logger,
|
||||
private val binding: ViewHolderRecipeBinding,
|
||||
private val recipeImageLoader: RecipeImageLoader,
|
||||
private val clickListener: (RecipeSummaryEntity) -> Unit,
|
||||
private val clickListener: (ClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
@Singleton
|
||||
@FragmentScoped
|
||||
class Factory @Inject constructor(
|
||||
private val recipeImageLoader: RecipeImageLoader,
|
||||
private val logger: Logger,
|
||||
) {
|
||||
|
||||
fun build(
|
||||
recipeImageLoader: RecipeImageLoader,
|
||||
binding: ViewHolderRecipeBinding,
|
||||
clickListener: (RecipeSummaryEntity) -> Unit,
|
||||
clickListener: (ClickEvent) -> Unit,
|
||||
) = RecipeViewHolder(logger, binding, recipeImageLoader, clickListener)
|
||||
|
||||
}
|
||||
|
||||
sealed class ClickEvent {
|
||||
|
||||
abstract val recipeSummaryEntity: RecipeSummaryEntity
|
||||
|
||||
data class FavoriteClick(
|
||||
override val recipeSummaryEntity: RecipeSummaryEntity
|
||||
) : ClickEvent()
|
||||
|
||||
data class RecipeClick(
|
||||
override val recipeSummaryEntity: RecipeSummaryEntity
|
||||
) : ClickEvent()
|
||||
|
||||
}
|
||||
|
||||
private val loadingPlaceholder by lazy {
|
||||
binding.resources.getString(R.string.view_holder_recipe_text_placeholder)
|
||||
}
|
||||
@@ -43,7 +57,10 @@ class RecipeViewHolder private constructor(
|
||||
item?.let { entity ->
|
||||
binding.root.setOnClickListener {
|
||||
logger.d { "bind: item clicked $entity" }
|
||||
clickListener(entity)
|
||||
clickListener(ClickEvent.RecipeClick(entity))
|
||||
}
|
||||
binding.favoriteIcon.setOnClickListener {
|
||||
clickListener(ClickEvent.FavoriteClick(entity))
|
||||
}
|
||||
binding.favoriteIcon.setImageResource(
|
||||
if (item.isFavorite) {
|
||||
|
||||
@@ -90,7 +90,16 @@ class RecipesListFragment : Fragment(R.layout.fragment_recipes_list) {
|
||||
private fun setupRecipeAdapter() {
|
||||
logger.v { "setupRecipeAdapter() called" }
|
||||
|
||||
val recipesAdapter = recipePagingAdapterFactory.build { onRecipeClicked(it) }
|
||||
val recipesAdapter = recipePagingAdapterFactory.build {
|
||||
when (it) {
|
||||
is RecipeViewHolder.ClickEvent.FavoriteClick -> {
|
||||
viewModel.onFavoriteIconClick(it.recipeSummaryEntity)
|
||||
}
|
||||
is RecipeViewHolder.ClickEvent.RecipeClick -> {
|
||||
onRecipeClicked(it.recipeSummaryEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with(binding.recipes) {
|
||||
adapter = recipesAdapter
|
||||
|
||||
@@ -8,10 +8,12 @@ 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.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.extensions.valueUpdatesOnly
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -38,4 +40,15 @@ class RecipesListViewModel @Inject constructor(
|
||||
emit(result)
|
||||
}
|
||||
}
|
||||
|
||||
fun onFavoriteIconClick(recipeSummaryEntity: RecipeSummaryEntity) {
|
||||
logger.v { "onFavoriteIconClick() called with: recipeSummaryEntity = $recipeSummaryEntity" }
|
||||
viewModelScope.launch {
|
||||
if (recipeSummaryEntity.isFavorite) {
|
||||
recipeRepo.removeFavoriteRecipe(recipeSummaryEntity.slug)
|
||||
} else {
|
||||
recipeRepo.addFavoriteRecipe(recipeSummaryEntity.slug)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,28 +8,22 @@ import dagger.hilt.android.scopes.FragmentScoped
|
||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||
import gq.kirmanak.mealient.databinding.ViewHolderRecipeBinding
|
||||
import gq.kirmanak.mealient.logging.Logger
|
||||
import gq.kirmanak.mealient.ui.recipes.images.RecipeImageLoader
|
||||
import javax.inject.Inject
|
||||
|
||||
class RecipesPagingAdapter private constructor(
|
||||
private val logger: Logger,
|
||||
private val recipeImageLoader: RecipeImageLoader,
|
||||
private val recipeViewHolderFactory: RecipeViewHolder.Factory,
|
||||
private val clickListener: (RecipeSummaryEntity) -> Unit
|
||||
private val clickListener: (RecipeViewHolder.ClickEvent) -> Unit
|
||||
) : PagingDataAdapter<RecipeSummaryEntity, RecipeViewHolder>(RecipeDiffCallback) {
|
||||
|
||||
@FragmentScoped
|
||||
class Factory @Inject constructor(
|
||||
private val logger: Logger,
|
||||
private val recipeViewHolderFactory: RecipeViewHolder.Factory,
|
||||
private val recipeImageLoader: RecipeImageLoader,
|
||||
) {
|
||||
|
||||
fun build(clickListener: (RecipeSummaryEntity) -> Unit) = RecipesPagingAdapter(
|
||||
logger,
|
||||
recipeImageLoader,
|
||||
recipeViewHolderFactory,
|
||||
clickListener
|
||||
fun build(clickListener: (RecipeViewHolder.ClickEvent) -> Unit) = RecipesPagingAdapter(
|
||||
logger, recipeViewHolderFactory, clickListener
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,18 +37,16 @@ class RecipesPagingAdapter private constructor(
|
||||
logger.v { "onCreateViewHolder() called with: parent = $parent, viewType = $viewType" }
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val binding = ViewHolderRecipeBinding.inflate(inflater, parent, false)
|
||||
return recipeViewHolderFactory.build(recipeImageLoader, binding, clickListener)
|
||||
return recipeViewHolderFactory.build(binding, clickListener)
|
||||
}
|
||||
|
||||
private object RecipeDiffCallback : DiffUtil.ItemCallback<RecipeSummaryEntity>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: RecipeSummaryEntity,
|
||||
newItem: RecipeSummaryEntity
|
||||
oldItem: RecipeSummaryEntity, newItem: RecipeSummaryEntity
|
||||
): Boolean = oldItem.remoteId == newItem.remoteId
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: RecipeSummaryEntity,
|
||||
newItem: RecipeSummaryEntity
|
||||
oldItem: RecipeSummaryEntity, newItem: RecipeSummaryEntity
|
||||
): Boolean = oldItem.name == newItem.name && oldItem.slug == newItem.slug
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user