From 35c65b2e6ec4f67fe5c0a2c64fd8675744a62679 Mon Sep 17 00:00:00 2001 From: Jhaman Date: Wed, 30 Sep 2020 16:21:06 +0500 Subject: [PATCH] Converted Recipes adapter in Binding Adpater setting directly from XML layout. --- app/build.gradle | 2 + .../main/java/com/task/data/DataRepository.kt | 7 ++ .../com/task/data/DataRepositorySource.kt | 2 + .../java/com/task/data/remote/RemoteData.kt | 14 +++ .../com/task/data/remote/RemoteDataSource.kt | 1 + .../component/recipes/RecipesListActivity.kt | 32 +++---- .../component/recipes/RecipesListViewModel.kt | 30 +++++- .../recipes/adapter/RecipesAdapter.kt | 9 +- .../recipes/adapter/RecipesBindingAdapter.kt | 33 +++++++ app/src/main/res/layout/home_activity.xml | 94 +++++++++++-------- local.properties | 8 +- 11 files changed, 163 insertions(+), 69 deletions(-) create mode 100644 app/src/main/java/com/task/ui/component/recipes/adapter/RecipesBindingAdapter.kt diff --git a/app/build.gradle b/app/build.gradle index 7c49279..a8de980 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,7 +19,9 @@ android { } buildFeatures{ viewBinding = true + dataBinding = true } + buildTypes { debug { debuggable true diff --git a/app/src/main/java/com/task/data/DataRepository.kt b/app/src/main/java/com/task/data/DataRepository.kt index 145a84d..fbc9d7b 100644 --- a/app/src/main/java/com/task/data/DataRepository.kt +++ b/app/src/main/java/com/task/data/DataRepository.kt @@ -24,6 +24,13 @@ class DataRepository @Inject constructor(private val remoteRepository: RemoteDat }.flowOn(ioDispatcher) } + override suspend fun requestRecipes2(): Flow { + return flow { + emit(remoteRepository.requestRecipes2()) + }.flowOn(ioDispatcher) + } + + override suspend fun doLogin(loginRequest: LoginRequest): Flow> { return flow { emit(localRepository.doLogin(loginRequest)) diff --git a/app/src/main/java/com/task/data/DataRepositorySource.kt b/app/src/main/java/com/task/data/DataRepositorySource.kt index a03c51f..d3a17a2 100644 --- a/app/src/main/java/com/task/data/DataRepositorySource.kt +++ b/app/src/main/java/com/task/data/DataRepositorySource.kt @@ -11,6 +11,8 @@ import kotlinx.coroutines.flow.Flow interface DataRepositorySource { suspend fun requestRecipes(): Flow> + suspend fun requestRecipes2(): Flow + suspend fun doLogin(loginRequest: LoginRequest): Flow> suspend fun addToFavourite(id: String): Flow> suspend fun removeFromFavourite(id: String): Flow> diff --git a/app/src/main/java/com/task/data/remote/RemoteData.kt b/app/src/main/java/com/task/data/remote/RemoteData.kt index dc005de..47de876 100644 --- a/app/src/main/java/com/task/data/remote/RemoteData.kt +++ b/app/src/main/java/com/task/data/remote/RemoteData.kt @@ -30,6 +30,20 @@ constructor(private val serviceGenerator: ServiceGenerator, private val networkC } } + override suspend fun requestRecipes2(): Recipes { + val recipesService = serviceGenerator.createService(RecipesService::class.java) + return when (val response = processCall(recipesService::fetchRecipes)) { + is List<*> -> { + Recipes(response as ArrayList) + } + else -> { + //response as Int + Recipes(response as ArrayList) + + } + } + } + private suspend fun processCall(responseCall: suspend () -> Response<*>): Any? { if (!networkConnectivity.isConnected()) { return NO_INTERNET_CONNECTION diff --git a/app/src/main/java/com/task/data/remote/RemoteDataSource.kt b/app/src/main/java/com/task/data/remote/RemoteDataSource.kt index eb4c3ec..b258ab2 100644 --- a/app/src/main/java/com/task/data/remote/RemoteDataSource.kt +++ b/app/src/main/java/com/task/data/remote/RemoteDataSource.kt @@ -9,4 +9,5 @@ import com.task.data.dto.recipes.Recipes internal interface RemoteDataSource { suspend fun requestRecipes(): Resource + suspend fun requestRecipes2(): Recipes } diff --git a/app/src/main/java/com/task/ui/component/recipes/RecipesListActivity.kt b/app/src/main/java/com/task/ui/component/recipes/RecipesListActivity.kt index 96d30a5..2633485 100644 --- a/app/src/main/java/com/task/ui/component/recipes/RecipesListActivity.kt +++ b/app/src/main/java/com/task/ui/component/recipes/RecipesListActivity.kt @@ -10,6 +10,7 @@ import android.view.View.GONE import android.view.View.VISIBLE import android.widget.SearchView import android.widget.SearchView.OnQueryTextListener +import androidx.databinding.DataBindingUtil import androidx.lifecycle.LiveData import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar @@ -39,25 +40,24 @@ class RecipesListActivity : BaseActivity() { @Inject lateinit var viewModelFactory: ViewModelFactory - private lateinit var recipesAdapter: RecipesAdapter override fun initViewBinding() { - binding = HomeActivityBinding.inflate(layoutInflater) - val view = binding.root - setContentView(view) + + binding = DataBindingUtil.setContentView(this,R.layout.home_activity) + binding.lifecycleOwner= this + } override fun initializeViewModel() { recipesListViewModel = viewModelFactory.create(RecipesListViewModel::class.java) + binding.vm = recipesListViewModel + binding.vm?.getRecipes() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportActionBar?.title = getString(R.string.recipe) - val layoutManager = LinearLayoutManager(this) - binding.rvRecipesList.layoutManager = layoutManager - binding.rvRecipesList.setHasFixedSize(true) - recipesListViewModel.getRecipes() + } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -97,16 +97,6 @@ class RecipesListActivity : BaseActivity() { } - private fun bindListData(recipes: Recipes) { - if (!(recipes.recipesList.isNullOrEmpty())) { - recipesAdapter = RecipesAdapter(recipesListViewModel, recipes.recipesList) - binding.rvRecipesList.adapter = recipesAdapter - showDataView(true) - } else { - showDataView(false) - } - } - private fun navigateToDetailsScreen(navigateEvent: SingleEvent) { navigateEvent.getContentIfNotHandled()?.let { val nextScreenIntent = Intent(this, DetailsActivity::class.java).apply { @@ -154,7 +144,10 @@ class RecipesListActivity : BaseActivity() { private fun handleRecipesList(status: Resource) { when (status) { is Resource.Loading -> showLoadingView() - is Resource.Success -> status.data?.let { bindListData(recipes = it) } + is Resource.Success -> status.data?.let { +// bindListData(recipes = it) +// recipesListViewModel.recipesLiveData.value = it + } is Resource.DataError -> { showDataView(false) status.errorCode?.let { recipesListViewModel.showToastMessage(it) } @@ -163,7 +156,6 @@ class RecipesListActivity : BaseActivity() { } override fun observeViewModel() { - observe(recipesListViewModel.recipesLiveData, ::handleRecipesList) observe(recipesListViewModel.recipeSearchFound, ::showSearchResult) observe(recipesListViewModel.noSearchFound, ::noSearchResult) observeEvent(recipesListViewModel.openRecipeDetails, ::navigateToDetailsScreen) diff --git a/app/src/main/java/com/task/ui/component/recipes/RecipesListViewModel.kt b/app/src/main/java/com/task/ui/component/recipes/RecipesListViewModel.kt index 9e09407..bad2a41 100644 --- a/app/src/main/java/com/task/ui/component/recipes/RecipesListViewModel.kt +++ b/app/src/main/java/com/task/ui/component/recipes/RecipesListViewModel.kt @@ -30,7 +30,14 @@ constructor(private val dataRepositoryRepository: DataRepositorySource) : BaseVi val recipesLiveDataPrivate = MutableLiveData>() val recipesLiveData: LiveData> get() = recipesLiveDataPrivate +// @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +// val recipesLiveDataPrivate2 = MutableLiveData>() +// val recipesLiveData2: MutableLiveData> get() = recipesLiveDataPrivate2 + + private val _loading: MutableLiveData = + MutableLiveData(true).apply { value = true } + val loading: MutableLiveData get() = _loading //TODO check to make them as one Resource @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) val recipeSearchFoundPrivate: MutableLiveData = MutableLiveData() @@ -64,9 +71,30 @@ constructor(private val dataRepositoryRepository: DataRepositorySource) : BaseVi recipesLiveDataPrivate.value = Resource.Loading() wrapEspressoIdlingResource { dataRepositoryRepository.requestRecipes().collect { - recipesLiveDataPrivate.value = it + when(it!!){ + is Resource.Loading -> _loading.value = true + is Resource.Success -> { + _loading.value = false + it?.let { + recipesLiveDataPrivate.value = it + + } + } + is Resource.DataError ->{ + + _loading.value = false + it.errorCode?.let { + showToastMessage(it) + } + } + } + + + + } } + } } diff --git a/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesAdapter.kt b/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesAdapter.kt index 078bcd7..e18aabf 100644 --- a/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesAdapter.kt +++ b/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesAdapter.kt @@ -3,6 +3,7 @@ package com.task.ui.component.recipes.adapter import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.task.data.dto.recipes.Recipes import com.task.data.dto.recipes.RecipesItem import com.task.databinding.RecipeItemBinding import com.task.ui.base.listeners.RecyclerItemListener @@ -12,7 +13,7 @@ import com.task.ui.component.recipes.RecipesListViewModel * Created by AhmedEltaher */ -class RecipesAdapter(private val recipesListViewModel: RecipesListViewModel, private val recipes: List) : RecyclerView.Adapter() { +class RecipesAdapter(private val recipesListViewModel: RecipesListViewModel, var recipes: Recipes?) : RecyclerView.Adapter() { private val onItemClickListener: RecyclerItemListener = object : RecyclerItemListener { override fun onItemSelected(recipe: RecipesItem) { @@ -26,11 +27,13 @@ class RecipesAdapter(private val recipesListViewModel: RecipesListViewModel, pri } override fun onBindViewHolder(holder: RecipeViewHolder, position: Int) { - holder.bind(recipes[position], onItemClickListener) + holder.bind(recipes!!.recipesList[position], onItemClickListener) } override fun getItemCount(): Int { - return recipes.size + if (recipes != null) + return recipes?.recipesList!!.size + else return 0; } } diff --git a/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesBindingAdapter.kt b/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesBindingAdapter.kt new file mode 100644 index 0000000..b4cbe01 --- /dev/null +++ b/app/src/main/java/com/task/ui/component/recipes/adapter/RecipesBindingAdapter.kt @@ -0,0 +1,33 @@ +package com.task.ui.component.recipes.adapter + +import android.util.Log +import android.view.View +import androidx.databinding.BindingAdapter +import androidx.recyclerview.widget.RecyclerView +import com.task.data.dto.recipes.Recipes +import com.task.data.dto.recipes.RecipesItem +import com.task.ui.component.recipes.RecipesListViewModel + + +@BindingAdapter(value = ["recipes", "viewModel"]) +fun setRepositories(view: RecyclerView, recipes: Recipes?, vm: RecipesListViewModel) { + + view.adapter?.run { + if (this is RecipesAdapter) { + this.recipes = recipes + this.notifyDataSetChanged() + } + } ?: run { + RecipesAdapter(vm,recipes).apply { view.adapter = this } + } +} + +@BindingAdapter("android:loader") +fun View.toVisble(visibility: Boolean) { + if (visibility) { + this.visibility = View.VISIBLE + } else { + this.visibility = View.GONE + + } +} diff --git a/app/src/main/res/layout/home_activity.xml b/app/src/main/res/layout/home_activity.xml index 49ff386..769c248 100644 --- a/app/src/main/res/layout/home_activity.xml +++ b/app/src/main/res/layout/home_activity.xml @@ -1,47 +1,61 @@ - + xmlns:tools="http://schemas.android.com/tools"> - - - + + + + + android:layout_height="match_parent"> + + + - + + + + + - - - - - + android:text="@string/no_data" + android:textColor="@android:color/holo_red_dark" + android:textSize="@dimen/font_32x" + android:textStyle="italic|bold" + android:visibility="gone" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + diff --git a/local.properties b/local.properties index aea0dbe..9be5893 100644 --- a/local.properties +++ b/local.properties @@ -1,10 +1,8 @@ -## This file is automatically generated by Android Studio. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file should *NOT* be checked into Version Control Systems, +## This file must *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -sdk.dir=/Users/amohamed/Library/Android/sdk \ No newline at end of file +#Wed Sep 30 10:43:52 PKT 2020 +sdk.dir=C\:\\Users\\Jaman\\AppData\\Local\\Android\\Sdk