Skip to content

Commit

Permalink
fix: labels are not rendered as links in SummaryProductFragment.kt
Browse files Browse the repository at this point in the history
fix: products opened from SearchActivity aren't added to history

fix: analysis are now displayed correctly in SummaryProductFragment.kt

Fixes #4134
  • Loading branch information
VaiTon committed Aug 8, 2021
1 parent 5141f8d commit c4a5314
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 101 deletions.
Expand Up @@ -26,10 +26,10 @@ import openfoodfacts.github.scrachx.openfood.utils.ProductInfoState

open class AbstractSummaryProductPresenter : ISummaryProductPresenter.View {
override fun showAllergens(allergens: List<AllergenName>) = Unit
override fun showProductQuestion(question: Question) = Unit
override suspend fun showProductQuestion(question: Question) = Unit
override fun showAnnotatedInsightToast(annotationResponse: AnnotationResponse) = Unit
override fun showCategoriesState(state: ProductInfoState<List<CategoryName>>) = Unit
override fun showLabelsState(state: ProductInfoState<List<LabelName>>) = Unit
override fun showAdditivesState(state: ProductInfoState<List<AdditiveName>>) = Unit
override fun showAnalysisTags(analysisTags: List<AnalysisTagConfig>) = Unit
override suspend fun showAnalysisTags(state: ProductInfoState<List<AnalysisTagConfig>>) = Unit
}
Expand Up @@ -40,7 +40,7 @@ interface ISummaryProductPresenter {
}

interface View {
fun showProductQuestion(question: Question)
suspend fun showProductQuestion(question: Question)
fun showAnnotatedInsightToast(annotationResponse: AnnotationResponse)

fun showAllergens(allergens: List<AllergenName>)
Expand All @@ -49,6 +49,6 @@ interface ISummaryProductPresenter {
fun showLabelsState(state: ProductInfoState<List<LabelName>>)
fun showAdditivesState(state: ProductInfoState<List<AdditiveName>>)

fun showAnalysisTags(analysisTags: List<AnalysisTagConfig>)
suspend fun showAnalysisTags(state: ProductInfoState<List<AnalysisTagConfig>>)
}
}
Expand Up @@ -47,6 +47,7 @@ import com.google.android.material.snackbar.Snackbar
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -585,40 +586,60 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View {
}
}

override fun showAnalysisTags(analysisTags: List<AnalysisTagConfig>) {
requireActivity().runOnUiThread {
binding.analysisContainer.visibility = View.VISIBLE
val adapter = IngredientAnalysisTagsAdapter(requireContext(), analysisTags, picasso, sharedPreferences)
adapter.setOnItemClickListener { view, _ ->
val fragment = IngredientsWithTagDialogFragment
.newInstance(product, view.getTag(R.id.analysis_tag_config) as AnalysisTagConfig)
fragment.show(childFragmentManager, "fragment_ingredients_with_tag")
fragment.onDismissListener = { adapter.filterVisibleTags() }
override suspend fun showAnalysisTags(state: ProductInfoState<List<AnalysisTagConfig>>) {
withContext(Main) {
when (state) {
is ProductInfoState.Data -> {
val analysisTags = state.data

binding.analysisContainer.visibility = View.VISIBLE

binding.analysisTags.adapter = IngredientAnalysisTagsAdapter(
requireContext(),
analysisTags,
picasso,
sharedPreferences
).apply adapter@{
setOnItemClickListener { view, _ ->
IngredientsWithTagDialogFragment.newInstance(
product,
view.getTag(R.id.analysis_tag_config) as AnalysisTagConfig
).run {
onDismissListener = { filterVisibleTags() }
show(childFragmentManager, "fragment_ingredients_with_tag")
}
}
}
}
ProductInfoState.Empty -> {
// TODO:
}
ProductInfoState.Loading -> {
// TODO:
}
}
binding.analysisTags.adapter = adapter

}
}

override fun showAllergens(allergens: List<AllergenName>) {
val data = AllergenHelper.computeUserAllergen(product, allergens)
if (data.isEmpty()) {
return
}
if (data.isEmpty()) return

if (data.incomplete) {
binding.productAllergenAlertText.setText(R.string.product_incomplete_message)
binding.productAllergenAlertLayout.visibility = View.VISIBLE
return
}
binding.productAllergenAlertText.text = StringBuilder(resources.getString(R.string.product_allergen_prompt))
binding.productAllergenAlertText.text = SpannableStringBuilder(getString(R.string.product_allergen_prompt))
.append("\n")
.append(data.allergens.joinToString(", "))

binding.productAllergenAlertLayout.visibility = View.VISIBLE
}


override fun showProductQuestion(question: Question) {
if (isRemoving) return
override suspend fun showProductQuestion(question: Question) = withContext(Main) {

if (!question.isEmpty()) {
productQuestion = question
Expand Down Expand Up @@ -706,45 +727,60 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View {
override fun showLabelsState(state: ProductInfoState<List<LabelName>>) {
requireActivity().runOnUiThread {
when (state) {
is ProductInfoState.Loading -> binding.labelsText.append(getString(R.string.txtLoading))
is ProductInfoState.Empty -> {
binding.labelsText.visibility = View.GONE
binding.labelsIcon.visibility = View.GONE
}
is ProductInfoState.Data -> {
binding.labelsText.isClickable = true
binding.labelsText.movementMethod = LinkMovementMethod.getInstance()

binding.labelsText.text = SpannableStringBuilder()
.bold { append(getString(R.string.txtLabels)) }
.append(" ")
.append(state.data.joinToString { getLabelTag(it) })
.apply {
state.data.map(::getLabelTag).forEachIndexed { i, el ->
append(el)
if (i == state.data.size) append(", ")
}
}
}
is ProductInfoState.Loading -> {
binding.labelsText.text = SpannableStringBuilder()
.bold { append(getString(R.string.txtLabels)) }
.append(getString(R.string.txtLoading))
}

is ProductInfoState.Empty -> {
binding.labelsText.visibility = View.GONE
binding.labelsIcon.visibility = View.GONE
}
}
}
}

override fun showCategoriesState(state: ProductInfoState<List<CategoryName>>) = requireActivity().runOnUiThread {
when (state) {
is ProductInfoState.Loading -> if (context != null) {
binding.categoriesText.append(getString(R.string.txtLoading))
}
is ProductInfoState.Empty -> {
binding.categoriesText.visibility = View.GONE
binding.categoriesIcon.visibility = View.GONE
}
is ProductInfoState.Data -> {
val categories = state.data
if (categories.isEmpty()) {
binding.categoriesLayout.visibility = View.GONE
return@runOnUiThread
override fun showCategoriesState(state: ProductInfoState<List<CategoryName>>) {
requireActivity().runOnUiThread {
when (state) {
is ProductInfoState.Loading -> {
binding.categoriesText.text = SpannableStringBuilder()
.bold { append(getString(R.string.txtCategories)) }
.append(getString(R.string.txtLoading))
}
is ProductInfoState.Empty -> {
binding.categoriesText.visibility = View.GONE
binding.categoriesIcon.visibility = View.GONE
}
is ProductInfoState.Data -> {
val categories = state.data
if (categories.isEmpty()) {
binding.categoriesLayout.visibility = View.GONE
return@runOnUiThread
}
CategoryProductHelper.showCategories(
this,
binding.categoriesText,
binding.textCategoryAlcoholAlert,
categories,
wikidataClient,
)
}
CategoryProductHelper.showCategories(
this,
binding.categoriesText,
binding.textCategoryAlcoholAlert,
categories,
wikidataClient,
)
}
}
}
Expand Down
Expand Up @@ -123,39 +123,35 @@ class SummaryProductPresenter(
override suspend fun loadAnalysisTags() {
if (!isFlavors(OFF, OBF, OPFF)) return

val analysisTags = product.ingredientsAnalysisTags
val knownTags = product.ingredientsAnalysisTags

if (analysisTags.isNotEmpty()) {
view.showLabelsState(ProductInfoState.Loading)
val analysisTagConfigs = try {
analysisTags.mapNotNull {
productRepository.getAnalysisTagConfigByTagAndLanguageCode(it, languageCode).awaitSingleOrNull()
view.showAnalysisTags(ProductInfoState.Loading)

if (knownTags.isNotEmpty()) {
val configs = try {
knownTags.mapNotNull {
productRepository.getAnalysisTagConfigByTagAndLanguageCode(it, languageCode)
}
} catch (err: Exception) {
Log.e(SummaryProductPresenter::class.java.simpleName, "loadAnalysisTags", err)
view.showLabelsState(ProductInfoState.Empty)
Log.e(SummaryProductPresenter::class.simpleName, "loadAnalysisTags", err)
view.showAnalysisTags(ProductInfoState.Empty)
return
}
if (analysisTagConfigs.isEmpty()) {
view.showLabelsState(ProductInfoState.Empty)
} else {
view.showAnalysisTags(analysisTagConfigs)
}

if (configs.isEmpty()) view.showAnalysisTags(ProductInfoState.Empty)
else view.showAnalysisTags(ProductInfoState.Data(configs))

} else {
view.showLabelsState(ProductInfoState.Loading)
val analysisTagConfigs = try {
val configs = try {
productRepository.getUnknownAnalysisTagConfigsByLanguageCode(languageCode).await()
} catch (err: Exception) {
Log.e(SummaryProductPresenter::class.java.simpleName, "loadAnalysisTags", err)
Log.e(SummaryProductPresenter::class.simpleName, "loadAnalysisTags", err)
view.showLabelsState(ProductInfoState.Empty)
return
}
if (analysisTagConfigs.isEmpty()) {
view.showLabelsState(ProductInfoState.Empty)
} else {
view.showAnalysisTags(analysisTagConfigs)
}

if (configs.isEmpty()) view.showAnalysisTags(ProductInfoState.Empty)
else view.showAnalysisTags(ProductInfoState.Data(configs))

}
}
Expand Down
Expand Up @@ -55,7 +55,6 @@ import io.reactivex.Completable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import kotlinx.coroutines.*
import kotlinx.coroutines.rx2.await
import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF
import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors
import openfoodfacts.github.scrachx.openfood.BuildConfig
Expand Down Expand Up @@ -242,7 +241,7 @@ class ContinuousScanActivity : BaseActivity(), IProductView {
this@ContinuousScanActivity.product = product

// Add product to scan history
productDisp = lifecycleScope.launch { client.addToHistory(product).await() }
productDisp = lifecycleScope.launch { client.addToHistory(product) }

// If we're here from comparison -> add product, return to comparison activity
if (intent.getBooleanExtra(ProductCompareActivity.KEY_COMPARE_PRODUCT, false)) {
Expand Down Expand Up @@ -364,25 +363,39 @@ class ContinuousScanActivity : BaseActivity(), IProductView {
}
}

override fun showAnalysisTags(analysisTags: List<AnalysisTagConfig>) {
super.showAnalysisTags(analysisTags)
if (analysisTags.isEmpty()) {
binding.quickViewTags.visibility = View.GONE
analysisTagsEmpty = true
return
}
binding.quickViewTags.visibility = View.VISIBLE
analysisTagsEmpty = false
val adapter = IngredientAnalysisTagsAdapter(this@ContinuousScanActivity, analysisTags, picasso, sharedPreferences)
adapter.setOnItemClickListener { view: View?, _ ->
if (view == null) return@setOnItemClickListener
IngredientsWithTagDialogFragment.newInstance(product, view.getTag(R.id.analysis_tag_config) as AnalysisTagConfig).run {
show(supportFragmentManager, "fragment_ingredients_with_tag")
onDismissListener = { adapter.filterVisibleTags() }
override suspend fun showAnalysisTags(state: ProductInfoState<List<AnalysisTagConfig>>) = withContext(Dispatchers.Main) {
when (state) {
is ProductInfoState.Data -> {
binding.quickViewTags.visibility = View.VISIBLE
analysisTagsEmpty = false
val adapter = IngredientAnalysisTagsAdapter(
this@ContinuousScanActivity,
state.data,
picasso,
sharedPreferences
).apply adapter@{
setOnItemClickListener { view: View, _ ->
IngredientsWithTagDialogFragment.newInstance(
product,
view.getTag(R.id.analysis_tag_config) as AnalysisTagConfig
).run {
onDismissListener = { this@adapter.filterVisibleTags() }
show(supportFragmentManager, "fragment_ingredients_with_tag")
}
}
}

binding.quickViewTags.adapter = adapter
}
is ProductInfoState.Empty -> {
binding.quickViewTags.visibility = View.GONE
analysisTagsEmpty = true
}
ProductInfoState.Loading -> {
// TODO
}
}

binding.quickViewTags.adapter = adapter
}
}, productRepository).also {
lifecycleScope.launch {
Expand Down
Expand Up @@ -12,7 +12,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.Single
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx2.await
import kotlinx.coroutines.rx2.rxCompletable
import kotlinx.coroutines.rx2.rxSingle
Expand Down Expand Up @@ -152,7 +151,9 @@ class OpenFoodAPIClient @Inject constructor(
.setNegativeButton(R.string.txtNo) { _, _ -> activity.onBackPressed() }
.show()
} else {
launch { addToHistory(state.product!!) }
addToHistory(state.product!!)

// After this the lifecycleScope is cleared because we're switching activities
startProductViewActivity(activity, state)
}
}
Expand Down Expand Up @@ -226,7 +227,7 @@ class OpenFoodAPIClient @Inject constructor(
/**
* Add a product to ScanHistory asynchronously
*/
fun addToHistory(product: Product) = rxCompletable(IO) {
suspend fun addToHistory(product: Product) = withContext(IO) {
daoSession.historyProductDao.addToHistory(product, localeManager.getLanguage())
}

Expand Down

0 comments on commit c4a5314

Please sign in to comment.