Skip to content

Commit

Permalink
ref: use coroutines for getProductStateFull
Browse files Browse the repository at this point in the history
  • Loading branch information
VaiTon committed Jul 2, 2021
1 parent 9ac2dbc commit 40e5062
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 105 deletions.
Expand Up @@ -39,11 +39,8 @@ import com.hootsuite.nachos.validator.ChipifyingNachoValidator
import com.squareup.picasso.Callback
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx2.await
import kotlinx.coroutines.rx2.awaitSingleOrNull
import kotlinx.coroutines.withContext
import openfoodfacts.github.scrachx.openfood.AppFlavors.OBF
import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF
import openfoodfacts.github.scrachx.openfood.AppFlavors.OPF
Expand Down Expand Up @@ -591,9 +588,7 @@ class EditOverviewFragment : ProductEditFragment() {
binding.name.isActivated = false

val productState = try {
withContext(Dispatchers.IO) {
client.getProductStateFull(product!!.code, fields).await()
}
client.getProductStateFull(product!!.code, fields)
} catch (err: Exception) {
Log.e(EditOverviewFragment::class.simpleName, "Error retrieving product state from server api.", err)
binding.name.setText(StringUtils.EMPTY)
Expand Down
@@ -0,0 +1,5 @@
package openfoodfacts.github.scrachx.openfood.features.product.view

interface IProductView {
fun showIngredientsTab(action: ProductViewActivity.ShowIngredientsAction)
}
Expand Up @@ -29,10 +29,7 @@ import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx2.await
import openfoodfacts.github.scrachx.openfood.AppFlavors.OBF
import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF
import openfoodfacts.github.scrachx.openfood.AppFlavors.OPF
Expand All @@ -46,6 +43,8 @@ import openfoodfacts.github.scrachx.openfood.features.listeners.OnRefreshListene
import openfoodfacts.github.scrachx.openfood.features.product.ProductFragmentPagerAdapter
import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity
import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.Companion.KEY_STATE
import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewActivity.ShowIngredientsAction.PERFORM_OCR
import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewActivity.ShowIngredientsAction.SEND_UPDATED
import openfoodfacts.github.scrachx.openfood.features.product.view.contributors.ContributorsFragment
import openfoodfacts.github.scrachx.openfood.features.product.view.environment.EnvironmentProductFragment
import openfoodfacts.github.scrachx.openfood.features.product.view.ingredients.IngredientsProductFragment
Expand All @@ -65,7 +64,7 @@ import org.greenrobot.eventbus.Subscribe
import javax.inject.Inject

@AndroidEntryPoint
class ProductViewActivity : BaseActivity(), OnRefreshListener {
class ProductViewActivity : BaseActivity(), IProductView, OnRefreshListener {
private var _binding: ActivityProductBinding? = null
private val binding get() = _binding!!

Expand All @@ -75,8 +74,6 @@ class ProductViewActivity : BaseActivity(), OnRefreshListener {
@Inject
lateinit var sharedPreferences: SharedPreferences

private val disp = CompositeDisposable()

private var productState: ProductState? = null
private var adapterResult: ProductFragmentPagerAdapter? = null

Expand Down Expand Up @@ -115,33 +112,26 @@ class ProductViewActivity : BaseActivity(), OnRefreshListener {
super.onStop()
}

override fun onDestroy() {
disp.dispose()
super.onDestroy()
}

/**
* Get the product data from the barcode. This takes the barcode and retrieves the information.
*
* @param barcode from the URL.
*/
private fun fetchProduct(barcode: String) = client.getProductStateFull(barcode, Utils.HEADER_USER_AGENT_SCAN)
.observeOn(AndroidSchedulers.mainThread())
.doOnError {
Log.w(this::class.simpleName, "Failed to load product $barcode.", it)
finish()
}
private suspend fun fetchProduct(barcode: String) = try {
client.getProductStateFull(barcode, Utils.HEADER_USER_AGENT_SCAN)
} catch (err: Exception) {
Log.w(this::class.simpleName, "Failed to load product $barcode.", err)
finish()
null
}


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == LOGIN_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
// Open product editing after successful login
Intent(this@ProductViewActivity, ProductEditActivity::class.java).apply {
putExtra(ProductEditActivity.KEY_EDIT_PRODUCT, productState!!.product)
startActivity(this)
}

// Open product editing after successful login
if (requestCode == LOGIN_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK) {
ProductEditActivity.start(this, productState!!.product!!)
}
}

Expand Down Expand Up @@ -176,17 +166,17 @@ class ProductViewActivity : BaseActivity(), OnRefreshListener {
}


fun showIngredientsTab(action: ShowIngredientsAction) {
override fun showIngredientsTab(action: ShowIngredientsAction) {
if (adapterResult == null || adapterResult!!.itemCount == 0) return

for (i in 0 until adapterResult!!.itemCount) {
val fragment = adapterResult!!.createFragment(i)

if (fragment is IngredientsProductFragment) {
binding.pager.currentItem = i
if (action == ShowIngredientsAction.PERFORM_OCR) {
fragment.extractIngredients()
} else if (action == ShowIngredientsAction.SEND_UPDATED) {
fragment.changeIngImage()
when (action) {
PERFORM_OCR -> fragment.extractIngredients()
SEND_UPDATED -> fragment.changeIngImage()
}
return
}
Expand All @@ -211,7 +201,7 @@ class ProductViewActivity : BaseActivity(), OnRefreshListener {

// Fetch product from server, then initialize views
lifecycleScope.launch {
val pState = fetchProduct(barcode).await()
val pState = fetchProduct(barcode) ?: return@launch

productState = pState
intent.putExtra(KEY_STATE, pState)
Expand Down
Expand Up @@ -11,12 +11,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.coroutines.launch
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.databinding.ActivityProductBinding
import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.installBottomNavigation
Expand All @@ -38,7 +38,7 @@ import openfoodfacts.github.scrachx.openfood.utils.requireProductState
import javax.inject.Inject

@AndroidEntryPoint
class ProductViewFragment : Fragment(), OnRefreshListener {
class ProductViewFragment : Fragment(), IProductView, OnRefreshListener {
private var _binding: ActivityProductBinding? = null
private val binding get() = _binding!!

Expand Down Expand Up @@ -93,36 +93,39 @@ class ProductViewFragment : Fragment(), OnRefreshListener {
}

private fun setupViewPager(viewPager: ViewPager2) = setupViewPager(
viewPager,
productState,
requireActivity()
viewPager,
productState,
requireActivity()
)

override fun onOptionsItemSelected(item: MenuItem) = onOptionsItemSelected(requireActivity(), item)

override fun onRefresh() {
client.getProductStateFull(productState.product!!.code)
.observeOn(AndroidSchedulers.mainThread())
.doOnError { adapterResult.refresh(productState) }
.subscribe { newState ->
productState = newState
adapterResult.refresh(newState)
}.addTo(disp)

lifecycleScope.launch {
val newState = try {
client.getProductStateFull(productState.product!!.code)
} catch (err: Exception) {
adapterResult.refresh(productState)
return@launch
}
productState = newState
adapterResult.refresh(newState)
}
}

fun bottomSheetWillGrow() {
if (adapterResult.itemCount == 0) return

// without this, the view can be centered vertically on initial show. we force the scroll to top !
if (adapterResult.createFragment(0) is SummaryProductFragment) {
(adapterResult.createFragment(0) as SummaryProductFragment).resetScroll()
}
(adapterResult.createFragment(0) as? SummaryProductFragment)?.resetScroll()
}

fun showIngredientsTab(action: ShowIngredientsAction) {
override fun showIngredientsTab(action: ShowIngredientsAction) {
if (adapterResult.itemCount == 0) return
(0 until adapterResult.itemCount).forEach { i ->

for (i in 0 until adapterResult.itemCount) {
val fragment = adapterResult.createFragment(i)

if (fragment is IngredientsProductFragment) {
binding.pager.currentItem = i
when (action) {
Expand All @@ -137,7 +140,6 @@ class ProductViewFragment : Fragment(), OnRefreshListener {
companion object {
private const val LOGIN_ACTIVITY_REQUEST_CODE = 1

@JvmStatic
fun newInstance(productState: ProductState) = ProductViewFragment().apply {
arguments = Bundle().apply {
putSerializable(KEY_STATE, productState)
Expand Down
Expand Up @@ -25,8 +25,8 @@ import dagger.hilt.android.AndroidEntryPoint
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper
import openfoodfacts.github.scrachx.openfood.databinding.IngredientsWithTagBinding
import openfoodfacts.github.scrachx.openfood.features.product.view.IProductView
import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewActivity
import openfoodfacts.github.scrachx.openfood.features.scan.ContinuousScanActivity
import openfoodfacts.github.scrachx.openfood.models.Product
import openfoodfacts.github.scrachx.openfood.models.entities.analysistagconfig.AnalysisTagConfig
import java.util.*
Expand Down Expand Up @@ -67,8 +67,8 @@ class IngredientsWithTagDialogFragment : DialogFragment() {
val ingredientsImageUrl = arguments.getString(INGREDIENTS_IMAGE_URL_KEY)

picasso
.load(iconUrl)
.into(binding.icon)
.load(iconUrl)
.into(binding.icon)
binding.iconFrame.background = ResourcesCompat.getDrawable(requireActivity().resources, R.drawable.rounded_button, requireActivity().theme)?.apply {
colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(Color.parseColor(color), BlendModeCompat.SRC_IN)
}
Expand All @@ -91,7 +91,8 @@ class IngredientsWithTagDialogFragment : DialogFragment() {
binding.helpNeeded.text = HtmlCompat.fromHtml(getString(R.string.add_photo_to_extract_ingredients), HtmlCompat.FROM_HTML_MODE_LEGACY)
binding.helpNeeded.setOnClickListener { goToAddPhoto() }
} else if (tag != null && ambiguousIngredient != null) {
messageToBeShown = HtmlCompat.fromHtml(getString(R.string.unknown_status_ambiguous_ingredients, ambiguousIngredient), HtmlCompat.FROM_HTML_MODE_LEGACY)
messageToBeShown =
HtmlCompat.fromHtml(getString(R.string.unknown_status_ambiguous_ingredients, ambiguousIngredient), HtmlCompat.FROM_HTML_MODE_LEGACY)
binding.helpNeeded.visibility = View.GONE
} else if (showHelpTranslate && arguments.getBoolean(MISSING_INGREDIENTS_KEY, false)) {
picasso.load(ingredientsImageUrl).into(binding.image)
Expand All @@ -110,9 +111,9 @@ class IngredientsWithTagDialogFragment : DialogFragment() {
binding.helpNeeded.setOnClickListener {
val customTabsIntent = CustomTabsIntent.Builder().build()
CustomTabActivityHelper.openCustomTab(
requireActivity(), // activity
customTabsIntent,
Uri.parse(getString(R.string.help_translate_ingredients_link, Locale.getDefault().language))
requireActivity(), // activity
customTabsIntent,
Uri.parse(getString(R.string.help_translate_ingredients_link, Locale.getDefault().language))
) { activity: Activity, uri: Uri ->
val i = Intent(Intent.ACTION_VIEW)
i.data = uri
Expand Down Expand Up @@ -142,24 +143,12 @@ class IngredientsWithTagDialogFragment : DialogFragment() {

private fun goToAddPhoto() {
dismiss()
when (requireActivity()) {
is ContinuousScanActivity -> {
(activity as ContinuousScanActivity).showIngredientsTab(ProductViewActivity.ShowIngredientsAction.SEND_UPDATED)
}
is ProductViewActivity -> {
(activity as ProductViewActivity).showIngredientsTab(ProductViewActivity.ShowIngredientsAction.SEND_UPDATED)
}
}
(activity as? IProductView)?.showIngredientsTab(ProductViewActivity.ShowIngredientsAction.SEND_UPDATED)
}

private fun goToExtract() {
dismiss()
when (requireActivity()) {
is ContinuousScanActivity -> (activity as ContinuousScanActivity)
.showIngredientsTab(ProductViewActivity.ShowIngredientsAction.PERFORM_OCR)
is ProductViewActivity -> (activity as ProductViewActivity)
.showIngredientsTab(ProductViewActivity.ShowIngredientsAction.PERFORM_OCR)
}
(activity as? IProductView)?.showIngredientsTab(ProductViewActivity.ShowIngredientsAction.PERFORM_OCR)
}

override fun onDismiss(dialog: DialogInterface) {
Expand Down Expand Up @@ -211,9 +200,9 @@ class IngredientsWithTagDialogFragment : DialogFragment() {
putSerializable(INGREDIENTS_KEY, getMatchingIngredientsText(product, showIngredients.split(":").toTypedArray()))
}
val ambiguousIngredient = product.ingredients
.filter { it.containsKey(config.type) && it.containsValue("maybe") }
.filter { it.containsKey("text") }
.mapNotNull { it["text"] }
.filter { it.containsKey(config.type) && it.containsValue("maybe") }
.filter { it.containsKey("text") }
.mapNotNull { it["text"] }
if (ambiguousIngredient.isNotEmpty()) {
putString(AMBIGUOUS_INGREDIENT_KEY, ambiguousIngredient.joinToString(","))
}
Expand Down
Expand Up @@ -69,6 +69,7 @@ import openfoodfacts.github.scrachx.openfood.features.compare.ProductCompareActi
import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.installBottomNavigation
import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.selectNavigationItem
import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity
import openfoodfacts.github.scrachx.openfood.features.product.view.IProductView
import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewActivity.ShowIngredientsAction
import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewFragment
import openfoodfacts.github.scrachx.openfood.features.product.view.ingredients_analysis.IngredientsWithTagDialogFragment
Expand Down Expand Up @@ -97,7 +98,7 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject

@AndroidEntryPoint
class ContinuousScanActivity : BaseActivity() {
class ContinuousScanActivity : BaseActivity(), IProductView {
private var _binding: ActivityContinuousScanBinding? = null
internal val binding get() = _binding!!

Expand Down Expand Up @@ -210,9 +211,7 @@ class ContinuousScanActivity : BaseActivity() {
binding.quickViewProgressText.text = getString(R.string.loading_product, barcode)

val productState = try {
withContext(Dispatchers.IO) {
client.getProductStateFull(barcode, userAgent = Utils.HEADER_USER_AGENT_SCAN).await()
}
client.getProductStateFull(barcode, userAgent = Utils.HEADER_USER_AGENT_SCAN)
} catch (err: Exception) {
// A network error happened
if (err is IOException) {
Expand Down Expand Up @@ -781,7 +780,7 @@ class ContinuousScanActivity : BaseActivity() {
quickViewBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}

fun showIngredientsTab(action: ShowIngredientsAction) {
override fun showIngredientsTab(action: ShowIngredientsAction) {
quickViewBehavior.state = BottomSheetBehavior.STATE_EXPANDED
productViewFragment?.showIngredientsTab(action)
}
Expand All @@ -803,6 +802,7 @@ class ContinuousScanActivity : BaseActivity() {
return true
}
lastBarcode = barcodeText

textView.visibility = View.GONE
setShownProduct(barcodeText)
return true
Expand Down

0 comments on commit 40e5062

Please sign in to comment.