From 8d213f84bc492e7131764a5f1e2fef235089ef03 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 8 Apr 2022 15:57:27 +0200 Subject: [PATCH 1/5] Fix: wrong number of products for lists + analytics events --- app/build.gradle.kts | 2 +- .../openfood/analytics/AnalyticsEvent.kt | 8 ++++++- .../view/summary/SummaryProductFragment.kt | 14 ++++++++++- .../productlist/ProductListActivity.kt | 21 +++++++++++++++-- .../productlists/ProductListsActivity.kt | 21 +++++++++-------- .../productlists/ProductListsAdapter.kt | 23 +++++++++++++++++-- .../features/productlists/ProductListsDiff.kt | 22 ++++++++++++++++++ 7 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsDiff.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cb992752dc93..ced8ab9369b4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -189,7 +189,7 @@ dependencies { androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-intents:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-web:3.4.0") - androidTestImplementation("androidx.test.espresso:espresso-contrib:3.3.0") { + androidTestImplementation("androidx.test.espresso:espresso-contrib:3.4.0") { exclude(group = "com.android.support", module = "appcompat-v7") exclude(group = "com.android.support", module = "support-v4") exclude(group = "com.android.support", module = "design") diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt index de530d7051a2..52ebd2953d5b 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt @@ -26,7 +26,13 @@ sealed class AnalyticsEvent(val category: String, val action: String, val name: object RobotoffLoggedInAfterPrompt : AnalyticsEvent("user-account", "logged-in-after-prompt", "robotoff", null) - object ShoppingListCreated : AnalyticsEvent("shopping-lists", "created", null, null) + data class ShoppingListCreated(val listName: String?) : AnalyticsEvent("shopping-lists", "created", listName, null) + + data class ShoppingListProductAdded(val barcode: String) : AnalyticsEvent("shopping-lists", "add_product", barcode, null) + + data class ShoppingListProductRemoved(val barcode: String) : AnalyticsEvent("shopping-lists", "remove_product", barcode, null) + + object ShoppingListShared : AnalyticsEvent("shopping-lists", "shared", null, null) object ShoppingListExported : AnalyticsEvent("shopping-lists", "exported", null, null) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt index 0d6a82eb3991..64f776a398d7 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt @@ -82,6 +82,7 @@ import openfoodfacts.github.scrachx.openfood.images.ProductImage import openfoodfacts.github.scrachx.openfood.models.* import openfoodfacts.github.scrachx.openfood.models.entities.ListedProduct import openfoodfacts.github.scrachx.openfood.models.entities.ListedProductDao +import openfoodfacts.github.scrachx.openfood.models.entities.ProductLists import openfoodfacts.github.scrachx.openfood.models.entities.additive.AdditiveName import openfoodfacts.github.scrachx.openfood.models.entities.allergen.AllergenHelper import openfoodfacts.github.scrachx.openfood.models.entities.allergen.AllergenName @@ -883,7 +884,8 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View { it.productDetails = product.getProductBrandsQuantityDetails() it.imageUrl = product.getImageSmallUrl(localeManager.getLanguage()) } - daoSession.listedProductDao.insertOrReplace(product) + addListedProductToDatabase(product, list) + matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListProductAdded(product.barcode)) dialog.dismiss() onRefresh() } @@ -897,6 +899,16 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View { } } + private fun addListedProductToDatabase( + product: ListedProduct, + list: ProductLists + ) { + daoSession.listedProductDao.insertOrReplace(product) + daoSession.productListsDao.update(list.apply { + products.add(product) + numOfProducts++ + }) + } private fun takeMorePicture() { sendOther = true diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt index c7fcf4c8ff4e..ba90786e677b 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt @@ -24,7 +24,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.BuildConfig @@ -372,16 +371,34 @@ class ProductListActivity : BaseActivity(), SwipeController.Actions { putExtra(Intent.EXTRA_TEXT, shareUrl) type = "text/plain" }, null)) + + matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListShared) } override fun onRightClicked(position: Int) { if (adapter.products.isEmpty()) return val productToRemove = adapter.products[position] - daoSession.listedProductDao.delete(productToRemove) + removeListedProductFromDatabase(productToRemove) + + matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListProductRemoved( + barcode = productToRemove.barcode + )) adapter.remove(productToRemove) } + private fun removeListedProductFromDatabase(productToRemove: ListedProduct) { + daoSession.listedProductDao.delete(productToRemove) + + productList.apply { + numOfProducts -= 1 + products.remove(productToRemove) + } + + daoSession.listedProductDao.delete(productToRemove) + daoSession.productListsDao.update(productList) + } + override fun onBackPressed() { setResult(RESULT_OK, Intent().apply { putExtra("update", true) }) super.onBackPressed() diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt index 38655950b742..656dd796a661 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt @@ -67,7 +67,6 @@ import java.io.InputStream import java.io.InputStreamReader import javax.inject.Inject - @AndroidEntryPoint class ProductListsActivity : BaseActivity(), SwipeController.Actions { private var _binding: ActivityProductListsBinding? = null @@ -102,12 +101,7 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { binding.fabAdd.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_plus_blue_24, 0, 0, 0) - // FIXME: remove runBlocking - productListsDao = daoSession.productListsDao.defaultIfEmpty(this) - val productLists = productListsDao.loadAll().toMutableList() - - adapter = ProductListsAdapter(this, productLists) - + adapter = ProductListsAdapter(this, mutableListOf()) binding.productListsRecyclerView.layoutManager = LinearLayoutManager(this) binding.productListsRecyclerView.adapter = adapter @@ -122,6 +116,8 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { binding.productListsRecyclerView.addOnItemTouchListener( RecyclerItemClickListener(this) { _, position -> + val productLists = adapter.lists + val id = productLists[position].id val listName = productLists[position].listName Intent(this, ProductListActivity::class.java).apply { @@ -138,6 +134,12 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { binding.fabAdd.setOnClickListener { showCreateListDialog() } } + private fun refreshLists() { + // FIXME: remove runBlocking + productListsDao = daoSession.productListsDao.defaultIfEmpty(this) + adapter.replaceWith(productListsDao.loadAll()) + } + // On Android < 5, the drawableStart attribute in XML will cause a crash // That's why, it's instead done here in the code private fun fixFabIcon() { @@ -178,10 +180,10 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { } private fun addNewListName(listName: String, productToAdd: Product?) { - matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListCreated) + matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListCreated(listName)) val productList = ProductLists(listName, if (productToAdd != null) 1 else 0) - adapter.lists.add(productList) + adapter.add(productList) productListsDao.insert(productList) adapter.notifyDataSetChanged() @@ -261,6 +263,7 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { public override fun onResume() { super.onResume() + refreshLists() binding.bottomNavigation.bottomNavigation.selectNavigationItem(R.id.my_lists) } diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsAdapter.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsAdapter.kt index e4eb48fd2964..57e0ebcde2c9 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsAdapter.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsAdapter.kt @@ -3,13 +3,14 @@ package openfoodfacts.github.scrachx.openfood.features.productlists import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import openfoodfacts.github.scrachx.openfood.databinding.YourProductListsItemBinding import openfoodfacts.github.scrachx.openfood.models.entities.ProductLists class ProductListsAdapter( - internal val context: Context, - val lists: MutableList + internal val context: Context, + val lists: MutableList ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductListsViewHolder { val binding = YourProductListsItemBinding.inflate(LayoutInflater.from(context), parent, false) @@ -27,12 +28,30 @@ class ProductListsAdapter( override fun getItemCount() = lists.size + fun add(productList: ProductLists) { + lists.add(productList) + notifyItemInserted(lists.size - 1) + } + fun remove(data: ProductLists) { val position = lists.indexOf(data) lists.removeAt(position) notifyItemRemoved(position) } + fun replaceWith(newList: MutableList) { + val oldList = lists.toList() + lists.clear() + lists.addAll(newList) + + DiffUtil.calculateDiff( + ProductListsDiffCallback( + oldList, + newList + ), + ).dispatchUpdatesTo(this) + } + } class ProductListsViewHolder(val binding: YourProductListsItemBinding) : RecyclerView.ViewHolder(binding.root) \ No newline at end of file diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsDiff.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsDiff.kt new file mode 100644 index 000000000000..92fc56e65f4d --- /dev/null +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsDiff.kt @@ -0,0 +1,22 @@ +package openfoodfacts.github.scrachx.openfood.features.productlists + +import androidx.recyclerview.widget.DiffUtil +import openfoodfacts.github.scrachx.openfood.models.entities.ProductLists + +class ProductListsDiffCallback( + private val oldItems: List, + private val newItems: List, +) : DiffUtil.Callback() { + + override fun getOldListSize(): Int = oldItems.size + + override fun getNewListSize(): Int = newItems.size + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].id == newItems[newItemPosition].id + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return areItemsTheSame(oldItemPosition, newItemPosition) + } +} \ No newline at end of file From 31458fb8cc8c8d25bd2c9aee024a1e3c0c2d54db Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 8 Apr 2022 15:59:21 +0200 Subject: [PATCH 2/5] Use the dedicated method to launch ProductListsActivity --- .../features/product/view/summary/SummaryProductFragment.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt index 64f776a398d7..5016269d9ae4 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/SummaryProductFragment.kt @@ -893,9 +893,7 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View { // Add listener to text view val addToNewList = dialog.findViewById(R.id.tvAddToNewList)!! addToNewList.setOnClickListener { - context.startActivity(Intent(context, ProductListsActivity::class.java).apply { - putExtra("product", product) - }) + ProductListsActivity.start(context, productToAdd = product) } } From ebaa69d61747b640ddade6158d88c58684de3af0 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 8 Apr 2022 21:34:47 +0200 Subject: [PATCH 3/5] Shop list name removed from analytics event --- .../github/scrachx/openfood/analytics/AnalyticsEvent.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt index 52ebd2953d5b..67c19847b2e8 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/analytics/AnalyticsEvent.kt @@ -26,7 +26,7 @@ sealed class AnalyticsEvent(val category: String, val action: String, val name: object RobotoffLoggedInAfterPrompt : AnalyticsEvent("user-account", "logged-in-after-prompt", "robotoff", null) - data class ShoppingListCreated(val listName: String?) : AnalyticsEvent("shopping-lists", "created", listName, null) + object ShoppingListCreated : AnalyticsEvent("shopping-lists", "created", null, null) data class ShoppingListProductAdded(val barcode: String) : AnalyticsEvent("shopping-lists", "add_product", barcode, null) From e736adf8ae042441485999f8201cb9cc7ff255a5 Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 8 Apr 2022 21:47:25 +0200 Subject: [PATCH 4/5] Fix build issue --- .../openfood/features/productlists/ProductListsActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt index 656dd796a661..5271963f2c52 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlists/ProductListsActivity.kt @@ -180,7 +180,7 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { } private fun addNewListName(listName: String, productToAdd: Product?) { - matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListCreated(listName)) + matomoAnalytics.trackEvent(AnalyticsEvent.ShoppingListCreated) val productList = ProductLists(listName, if (productToAdd != null) 1 else 0) adapter.add(productList) From 5209c487177a05073f3bb7c7d425d7767130826f Mon Sep 17 00:00:00 2001 From: Edouard Marquez Date: Fri, 8 Apr 2022 22:03:36 +0200 Subject: [PATCH 5/5] =?UTF-8?q?Fix=20build=20issue=20(again=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../scrachx/openfood/features/productlist/ProductListActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt index ba90786e677b..26da3a0049e1 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/productlist/ProductListActivity.kt @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.picasso.Picasso import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.BuildConfig