diff --git a/app/src/main/java/com/hifeful/mealmania/domain/model/Meal.kt b/app/src/main/java/com/hifeful/mealmania/domain/model/Meal.kt index 984750b..c779411 100644 --- a/app/src/main/java/com/hifeful/mealmania/domain/model/Meal.kt +++ b/app/src/main/java/com/hifeful/mealmania/domain/model/Meal.kt @@ -6,6 +6,18 @@ import androidx.room.Entity import androidx.room.PrimaryKey import kotlinx.parcelize.Parcelize +/** + * 1️⃣ It should be inside the data layer as it's a database entity(i.e., MealEntity) + * 2️⃣ In the domain layer you are going to have a model (i.e., Meal) which is mapped + * in the data layer based on received entity + * 3️⃣ Domain has only models and repository contracts + * In some cases, use-cases as well + * + * 🎁 When we have multi-modular architecture: + * > the domain layer shouldn't have any dependencies, even to another domain + * > the data layer should have only the dedicated domain dependency, and no another data layers + * > of course, there might be exception, but usually we should avoid it + */ @Parcelize @Entity(tableName = "meal") data class Meal( diff --git a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/FavouriteMealsAdapter.kt b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/FavouriteMealsAdapter.kt index fb8fb35..dacf325 100644 --- a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/FavouriteMealsAdapter.kt +++ b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/FavouriteMealsAdapter.kt @@ -13,6 +13,9 @@ class FavouriteMealsAdapter : ListAdapter Unit = {} var onMealClickListener: ((String) -> Unit)? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FavouriteMealsViewHolder = @@ -32,6 +35,7 @@ class FavouriteMealsAdapter : ListAdapter, @@ -19,7 +65,11 @@ class MyMealsFeature @Inject constructor( MyMealsFeature.State, Nothing>(initialState = initialState, actor = actor, reducer = reducer) { + // Should be extracted to outside 😉 + // The same for Wish, Effect, etc. data class State( + // State should expose UI models or primitive types. + // Or UI model that holds the domain model val recentMeals: List? = null, val favouriteMeals: List? = null ) @@ -34,6 +84,8 @@ class MyMealsFeature @Inject constructor( data class LoadedFavouriteMeals(val meals: List) : Effect() } + // Wish and Effect types seem are the same from the syntax sense at least. + // In other words, kinda of duplication that causes the complexity. class ActorImpl( private val mealsRepository: MealsRepository ) : Actor { diff --git a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsFragment.kt b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsFragment.kt index 99a0ede..b1ef7bc 100644 --- a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsFragment.kt +++ b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsFragment.kt @@ -15,12 +15,25 @@ import dagger.hilt.android.AndroidEntryPoint import io.reactivex.functions.Consumer import javax.inject.Inject +/** + * 1️⃣ Please, avoid custom base classes. The exceptions are: + * 👌 Framework obligation: Activity, Fragment, ViewModel, etc. + * 👌 Data classes modeling + * + * 💢 The architectural components (generated by us) mustn't rely on the inheritance + */ @AndroidEntryPoint class MyMealsFragment : ObservableSourceFragment(), Consumer { @Inject lateinit var myMealsFeature: MyMealsFeature + /** + * 1️⃣ Things might be improved to avoid having the same two variables + * https://zhuinden.medium.com/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c + * 2️⃣ The not-null assertion operator (!!) mustn't be used in the code. + * The only place where it's allowed is unit-tests. + */ private var _binding: FragmentMyMealsBinding? = null private val binding get() = _binding!! @@ -45,6 +58,10 @@ class MyMealsFragment : ObservableSourceFragment(), Consumer(), Consumer(), Consumer(), Consumer Unit?) = + object : RecyclerView.AdapterDataObserver() { + + override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { + block() ?: super.onItemRangeChanged(positionStart, itemCount) + } + } + + fun itemRangeInsertedObserver(block: () -> Unit?) = + object : RecyclerView.AdapterDataObserver() { + + override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { + block() ?: super.onItemRangeInserted(positionStart, itemCount) + } + } + 2️⃣ added an observer to RecyclerView.Adapter + RecentMealsAdapter().apply { + registerAdapterDataObserver( + itemRangeInsertedObserver { binding.content.scrollToPosition(0) } + ) + } + */ recyclerViewFavouriteMeals.smoothScrollToPosition(0) } favouriteMealsAdapter?.submitList(viewState.favouriteMeals) diff --git a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsUiEvent.kt b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsUiEvent.kt index 21f8b76..ec0d817 100644 --- a/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsUiEvent.kt +++ b/app/src/main/java/com/hifeful/mealmania/presentation/myMeals/MyMealsUiEvent.kt @@ -1,5 +1,6 @@ package com.hifeful.mealmania.presentation.myMeals +// Better to keep it as the sealed interface sealed class MyMealsUiEvent { object LoadRecentMeals : MyMealsUiEvent()