diff --git a/app/src/androidTest/java/com/pabji/myfridge/ui/UITest.kt b/app/src/androidTest/java/com/pabji/myfridge/ui/UITest.kt index e63ab5e..f36e11a 100644 --- a/app/src/androidTest/java/com/pabji/myfridge/ui/UITest.kt +++ b/app/src/androidTest/java/com/pabji/myfridge/ui/UITest.kt @@ -88,6 +88,8 @@ class UITest : KoinTest { ) ) + onView(withId(R.id.btn_add)).perform(click()) + onView(isRoot()).perform(pressBack()) onView(withId(R.id.fab)).perform(click()) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c700645..90f0aab 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,11 +34,10 @@ + android:theme="@style/AppTheme.NoActionBar" /> - + android:name=".ui.barcode.BarcodeReaderActivity" + android:theme="@style/AppTheme.NoActionBar" /> \ No newline at end of file diff --git a/app/src/main/java/com/pabji/myfridge/di/Modules.kt b/app/src/main/java/com/pabji/myfridge/di/Modules.kt index a9cb871..512609e 100644 --- a/app/src/main/java/com/pabji/myfridge/di/Modules.kt +++ b/app/src/main/java/com/pabji/myfridge/di/Modules.kt @@ -68,8 +68,17 @@ val scopesModule = module { } scope(named()) { - viewModel { (product: ItemProduct) -> ProductDetailViewModel(product, get(), get(), get()) } + viewModel { (product: ItemProduct) -> + ProductDetailViewModel( + product, + get(), + get(), + get(), + get() + ) + } scoped { GetProductDetail(get()) } + scoped { RemoveProduct(get()) } scoped { SaveProduct(get()) } } diff --git a/app/src/main/java/com/pabji/myfridge/model/ItemProduct.kt b/app/src/main/java/com/pabji/myfridge/model/ItemProduct.kt index 1cee01f..0e9745c 100644 --- a/app/src/main/java/com/pabji/myfridge/model/ItemProduct.kt +++ b/app/src/main/java/com/pabji/myfridge/model/ItemProduct.kt @@ -4,7 +4,6 @@ import com.pabji.domain.Product import java.io.Serializable data class ItemProduct( - val id: Long? = null, val name: String = "", val previewUrl: String = "", val existInFridge: Boolean = false, @@ -13,7 +12,6 @@ data class ItemProduct( fun Product.toItemProduct(): ItemProduct = ItemProduct( - id, name, previewUrl, existInFridge, @@ -21,4 +19,4 @@ fun Product.toItemProduct(): ItemProduct = ) fun ItemProduct.toProduct(): Product = - Product(id = id, name = name, barcode = barcode) + Product(name = name, barcode = barcode) diff --git a/app/src/main/java/com/pabji/myfridge/model/database/RoomDataSource.kt b/app/src/main/java/com/pabji/myfridge/model/database/RoomDataSource.kt index 3dce01d..4bd50cd 100644 --- a/app/src/main/java/com/pabji/myfridge/model/database/RoomDataSource.kt +++ b/app/src/main/java/com/pabji/myfridge/model/database/RoomDataSource.kt @@ -20,13 +20,6 @@ class RoomDataSource(database: RoomDatabase) : LocalDatasource { } ?: Either.Left(DetailError) } - override suspend fun getProductById(productId: Long) = - withContext(Dispatchers.IO) { - productDao.getProductById(productId)?.run { - Either.Right(toProduct()) - } ?: Either.Left(DetailError) - } - override suspend fun getProductList() = withContext(Dispatchers.IO) { productDao.getAll().map { it.toProduct() } } diff --git a/app/src/main/java/com/pabji/myfridge/model/database/daos/ProductDao.kt b/app/src/main/java/com/pabji/myfridge/model/database/daos/ProductDao.kt index 20d026f..a886562 100644 --- a/app/src/main/java/com/pabji/myfridge/model/database/daos/ProductDao.kt +++ b/app/src/main/java/com/pabji/myfridge/model/database/daos/ProductDao.kt @@ -9,9 +9,6 @@ interface ProductDao { @Query("SELECT * FROM products") suspend fun getAll(): List - @Query("SELECT * FROM products WHERE id = :productId") - suspend fun getProductById(productId: Long): ProductEntity? - @Query("SELECT * FROM products WHERE barcode = :barcode") suspend fun getProductByBarcode(barcode: String): ProductEntity? diff --git a/app/src/main/java/com/pabji/myfridge/model/database/entities/ProductEntity.kt b/app/src/main/java/com/pabji/myfridge/model/database/entities/ProductEntity.kt index 67c940e..8f4de70 100644 --- a/app/src/main/java/com/pabji/myfridge/model/database/entities/ProductEntity.kt +++ b/app/src/main/java/com/pabji/myfridge/model/database/entities/ProductEntity.kt @@ -7,8 +7,7 @@ import com.pabji.myfridge.model.common.extensions.getListByDelimit @Entity(tableName = "products") data class ProductEntity( - @PrimaryKey(autoGenerate = true) val id: Long?, - val barcode: String, + @PrimaryKey val barcode: String, val name: String, val previewUrl: String, val imageUrl: String, @@ -25,7 +24,6 @@ data class ProductEntity( internal fun ProductEntity.toProduct() = Product( - id, barcode, name, previewUrl, @@ -43,7 +41,6 @@ internal fun ProductEntity.toProduct() = ) internal fun Product.toProductEntity() = ProductEntity( - id, barcode, name, previewUrl, diff --git a/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailActivity.kt b/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailActivity.kt index 6925ac2..c8d36f4 100644 --- a/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailActivity.kt +++ b/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailActivity.kt @@ -3,6 +3,7 @@ package com.pabji.myfridge.ui.productDetail import android.os.Bundle import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import coil.api.load import coil.size.Scale @@ -10,7 +11,6 @@ import com.pabji.domain.Product import com.pabji.myfridge.R import com.pabji.myfridge.model.ItemProduct import com.pabji.myfridge.ui.common.extensions.gone -import com.pabji.myfridge.ui.common.extensions.setVisible import com.pabji.myfridge.ui.common.extensions.visible import com.pabji.myfridge.ui.productDetail.ProductDetailViewModel.UiModel import kotlinx.android.synthetic.main.activity_product_detail.* @@ -27,31 +27,58 @@ class ProductDetailActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_product_detail) - setTitle(R.string.product_detail_title) + + setSupportActionBar(toolbar) + supportActionBar?.setDisplayHomeAsUpEnabled(true) + supportActionBar?.setDisplayShowHomeEnabled(true) viewModel.model.observe(this, Observer(::updateUI)) - btn_add.setOnClickListener { viewModel.onClickButtonAdd() } + btn_add.setOnClickListener { viewModel.onClickButton() } + } + + override fun onSupportNavigateUp(): Boolean { + onBackPressed() + return true } private fun updateUI(viewState: UiModel?) { when (viewState) { - UiModel.Loading -> { - } - is UiModel.Content -> showProduct(viewState.product) + is UiModel.BasicContent -> showBasicProduct(viewState.product) + is UiModel.FullContent -> showProduct(viewState.product) is UiModel.ProductSaved -> showSaved(viewState.product) + is UiModel.ProductRemoved -> showRemoved(viewState.product) UiModel.Error -> showError() } } + private fun showBasicProduct(product: ItemProduct?) { + product?.run { + title = name + setButton(existInFridge) + setProductImage(previewUrl) + setProductName(name) + } + } + + private fun showRemoved(product: Product) { + Toast.makeText( + this, + "${product.name} has been removed from your fridge", + Toast.LENGTH_SHORT + ) + .show() + setButton(false) + } + private fun showSaved(product: Product) { Toast.makeText(this, "${product.name} has been saved in your fridge", Toast.LENGTH_SHORT) .show() - btn_add.gone() + setButton(true) } private fun showProduct(product: Product) { product.run { - btn_add.setVisible(!existInFridge) + setButton(existInFridge) setProductImage(imageUrl) setProductName(name) setGenericName(genericName) @@ -61,10 +88,23 @@ class ProductDetailActivity : AppCompatActivity() { } } + private fun setButton(existInFridge: Boolean) { + if (existInFridge) { + btn_add.setBackgroundColor(ContextCompat.getColor(this, R.color.colorAccent)) + btn_add.text = getString(R.string.remove_from_fridge) + } else { + btn_add.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary)) + btn_add.text = getString(R.string.add_to_the_fridge) + } + btn_add.visible() + } + private fun setStores(stores: String) { if (stores.isNotEmpty()) { tv_stores.text = stores ll_stores.visible() + } else { + ll_stores.gone() } } @@ -72,12 +112,18 @@ class ProductDetailActivity : AppCompatActivity() { if (categories.isNotEmpty()) { tv_categories.text = categories ll_categories.visible() + } else { + ll_categories.gone() } } private fun setIngredientsText(ingredientsText: String) { - tv_ingredients.text = ingredientsText - ll_ingredients.visible() + if (ingredientsText.isNotEmpty()) { + tv_ingredients.text = ingredientsText + ll_ingredients.visible() + } else { + ll_ingredients.gone() + } } private fun setGenericName(genericName: String) { diff --git a/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailViewModel.kt b/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailViewModel.kt index 5fd4923..34152be 100644 --- a/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailViewModel.kt +++ b/app/src/main/java/com/pabji/myfridge/ui/productDetail/ProductDetailViewModel.kt @@ -8,6 +8,7 @@ import com.pabji.myfridge.model.ItemProduct import com.pabji.myfridge.model.toProduct import com.pabji.myfridge.ui.common.BaseViewModel import com.pabji.usecases.GetProductDetail +import com.pabji.usecases.RemoveProduct import com.pabji.usecases.SaveProduct import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.launch @@ -16,9 +17,11 @@ class ProductDetailViewModel( private var itemProduct: ItemProduct?, private val getProductDetail: GetProductDetail, private val saveProduct: SaveProduct, + private val removeProduct: RemoveProduct, uiDispatcher: CoroutineDispatcher ) : BaseViewModel(uiDispatcher) { + private var product: Product? = null private val _model = MutableLiveData() val model: LiveData get() { @@ -27,31 +30,41 @@ class ProductDetailViewModel( } sealed class UiModel { - object Loading : UiModel() - data class Content(val product: Product) : UiModel() + data class BasicContent(val product: ItemProduct?) : UiModel() + data class FullContent(val product: Product) : UiModel() data class ProductSaved(val product: Product) : UiModel() + data class ProductRemoved(val product: Product) : UiModel() object Error : UiModel() } - private fun loadProduct(product: ItemProduct?) { + private fun loadProduct(itemProduct: ItemProduct?) { launch { - _model.value = UiModel.Loading - _model.value = product?.run { + _model.value = UiModel.BasicContent(itemProduct) + _model.value = itemProduct?.run { getProductDetail(toProduct()).fold({ UiModel.Error }, { - UiModel.Content(it) + product = it + UiModel.FullContent(it) }) } ?: UiModel.Error } } - fun onClickButtonAdd() { + fun onClickButton() { launch { - when (val value = _model.value) { - is UiModel.Content -> { - saveProduct(value.product) - _model.value = UiModel.ProductSaved(value.product) + product?.run { + _model.value = when { + existInFridge -> { + removeProduct(this) + existInFridge = false + UiModel.ProductRemoved(this) + } + else -> { + saveProduct(this) + existInFridge = true + UiModel.ProductSaved(this) + } } } } diff --git a/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsFragment.kt b/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsFragment.kt index 5d09d21..6bcdaf1 100644 --- a/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsFragment.kt +++ b/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsFragment.kt @@ -32,6 +32,11 @@ class SearchProductsFragment : BaseFragment() { setHasOptionsMenu(true) } + override fun onResume() { + super.onResume() + viewModel.onSearch() + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsViewModel.kt b/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsViewModel.kt index b724611..ea6626a 100644 --- a/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsViewModel.kt +++ b/app/src/main/java/com/pabji/myfridge/ui/searchProducts/SearchProductsViewModel.kt @@ -16,11 +16,7 @@ class SearchProductsViewModel( ) : BaseViewModel(uiDispatcher) { private val _model = MutableLiveData() - val model: LiveData - get() { - if (_model.value == null) onSearch() - return _model - } + val model: LiveData = _model private val _navigation = MutableLiveData>() val navigation: LiveData> = _navigation diff --git a/app/src/main/res/layout/activity_product_detail.xml b/app/src/main/res/layout/activity_product_detail.xml index 012e98c..7396bde 100644 --- a/app/src/main/res/layout/activity_product_detail.xml +++ b/app/src/main/res/layout/activity_product_detail.xml @@ -3,52 +3,160 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:background="@color/lightgreen"> + - + + + + + app:cardBackgroundColor="@color/white" + app:cardElevation="2dp" + app:cardUseCompatPadding="true" + app:layout_constraintHeight_percent="0.4" + app:layout_constraintTop_toBottomOf="@id/app_bar"> - + android:layout_height="match_parent"> + + + + + + + + + + - + - + + + + + + +