Skip to content

Commit

Permalink
fix: filter before mapping in ImageNameParser.kt
Browse files Browse the repository at this point in the history
refactor: rename TimestampedKey to ValueAndTimestamp
  • Loading branch information
VaiTon committed Aug 21, 2022
1 parent be4fb31 commit 9d43faa
Show file tree
Hide file tree
Showing 6 changed files with 630 additions and 47 deletions.
Expand Up @@ -32,7 +32,10 @@ import dagger.hilt.android.AndroidEntryPoint
import openfoodfacts.github.scrachx.openfood.databinding.ActivityProductImagesListBinding
import openfoodfacts.github.scrachx.openfood.features.adapters.ProductImagesSelectionAdapter
import openfoodfacts.github.scrachx.openfood.features.shared.BaseActivity
import openfoodfacts.github.scrachx.openfood.images.*
import openfoodfacts.github.scrachx.openfood.images.IMAGE_FILE
import openfoodfacts.github.scrachx.openfood.images.IMG_ID
import openfoodfacts.github.scrachx.openfood.images.ImageNameParser
import openfoodfacts.github.scrachx.openfood.images.PRODUCT_BARCODE
import openfoodfacts.github.scrachx.openfood.network.services.ProductsAPI
import openfoodfacts.github.scrachx.openfood.utils.*
import pl.aprilapps.easyphotopicker.EasyImage
Expand Down Expand Up @@ -79,9 +82,8 @@ class ImagesSelectActivity : BaseActivity() {
private fun loadProductImages(code: String) {
supportActionBar?.setDisplayHomeAsUpEnabled(true)
lifecycleScope.launchWhenCreated {
val imageNames = ImageNamesParser.extractImageNames(productsApi.getProductImages(code))
.sortedByTimestampDescending()
.map { it.key }
val imageNames = ImageNameParser.extractImageNames(productsApi.getProductImages(code))
.map { it.value }

// Check if user is logged in
adapter = ProductImagesSelectionAdapter(picasso, imageNames, code) {
Expand Down
Expand Up @@ -10,8 +10,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity
import openfoodfacts.github.scrachx.openfood.images.ImageNamesParser
import openfoodfacts.github.scrachx.openfood.images.sortedByTimestampDescending
import openfoodfacts.github.scrachx.openfood.images.ImageNameParser
import openfoodfacts.github.scrachx.openfood.models.ProductState
import openfoodfacts.github.scrachx.openfood.network.services.ProductsAPI
import javax.inject.Inject
Expand All @@ -28,9 +27,8 @@ class ProductPhotosViewModel @Inject constructor(
.map { it.product }
.filterNotNull()
.map { product ->
ImageNamesParser.extractImageNames(productsAPI.getProductImages(product.code))
.sortedByTimestampDescending()
.map { it.key }
ImageNameParser.extractImageNames(productsAPI.getProductImages(product.code))
.map { it.value }
}.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(),
Expand Down
@@ -1,31 +1,38 @@
package openfoodfacts.github.scrachx.openfood.images

import com.fasterxml.jackson.databind.JsonNode
import openfoodfacts.github.scrachx.openfood.models.ValueAndTimestamp


object ImageNamesParser {
internal fun extractImageNames(jsonNode: JsonNode): List<TimestampedKey<String>> {
object ImageNameParser {
/**
* @return a sorted by timestamp [List] of [ValueAndTimestamp] that have the
* image name as key.
*
* The list is sorted in descending order (first newer images).
*/
internal fun extractImageNames(jsonNode: JsonNode): List<ValueAndTimestamp<String>> {
return jsonNode["product"]["images"]?.fields()
?.asSequence()
?.toList().orEmpty()
.map { TimestampedKey(it.value["uploaded_t"].asLong(), it.key) }
.filter {
// do not include images with contain nutrients, ingredients or other in their names
// as they are duplicate and do not load as well
isNameOk(it.key)
// Do not include images with contain nutrients,
// ingredients or other in their names. They are duplicates and
// sometimes they do not have the `uploaded_t` field and make
// the mapping throw a NPE
isValidImageName(it.key)
}
.map { ValueAndTimestamp(it.value["uploaded_t"].asLong(), it.key) }
.sortedByTimestampDescending()

}

fun isNameOk(name: String) =
internal fun isValidImageName(name: String) =
name.isNotBlank() && !Regex("[nfio]").containsMatchIn(name)
}

internal data class TimestampedKey<T>(
val timestamp: Long,
val key: T,
)
private fun <T> List<ValueAndTimestamp<T>>.sortedByTimestampDescending() =
sortedByDescending { it.timestamp }
}


internal fun <T> List<TimestampedKey<T>>.sortedByTimestampDescending() =
sortedByDescending { it.timestamp }

@@ -0,0 +1,6 @@
package openfoodfacts.github.scrachx.openfood.models

internal data class ValueAndTimestamp<V>(
val timestamp: Long,
val value: V,
)

0 comments on commit 9d43faa

Please sign in to comment.