Skip to content

Commit

Permalink
ref: use coroutines instead of rxjava in repositories (#4363)
Browse files Browse the repository at this point in the history
ref: "services" renamed to "repositories" as per android docs recommendation
  • Loading branch information
VaiTon committed Nov 29, 2021
1 parent 3aadd43 commit 5687e34
Show file tree
Hide file tree
Showing 70 changed files with 1,942 additions and 1,914 deletions.
2 changes: 1 addition & 1 deletion .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -27,13 +27,13 @@ import javax.inject.Inject
@ExperimentalCoroutinesApi
@SmallTest
@HiltAndroidTest
class ProductRepositoryTest {
class TaxonomiesRepositoryTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)


@Inject
lateinit var productRepository: ProductRepository
lateinit var taxonomiesRepository: TaxonomiesRepository

@Inject
@ApplicationContext
Expand All @@ -46,15 +46,15 @@ class ProductRepositoryTest {
@Before
fun cleanAllergens() {
clearDatabase(daoSession)
productRepository.saveAllergens(createAllergens())
taxonomiesRepository.saveAllergens(createAllergens())
}

@Test
fun testGetAllergens() = runBlockingTest {
val appPrefs = instance.getAppPreferences()

val isDownloadActivated = appPrefs.getBoolean(Taxonomy.Allergens.getDownloadActivatePreferencesId(), false)
val allergens = productRepository.reloadAllergensFromServer()
val allergens = taxonomiesRepository.reloadAllergensFromServer()
assertNotNull(allergens)
if (!isDownloadActivated) {
assertEquals(0, allergens.size.toLong())
Expand All @@ -73,16 +73,16 @@ class ProductRepositoryTest {

@Test
fun testGetEnabledAllergens() = runBlockingTest {
val allergens = productRepository.getEnabledAllergens()
val allergens = taxonomiesRepository.getEnabledAllergens()
assertNotNull(allergens)
assertEquals(1, allergens.size.toLong())
assertEquals(TEST_ALLERGEN_TAG, allergens[0].tag)
}

@Test
fun testGetAllergensByEnabledAndLanguageCode() {
val enabledAllergenNames = productRepository.getAllergensByEnabledAndLanguageCode(true, TEST_LANGUAGE_CODE).blockingGet()
val notEnabledAllergenNames = productRepository.getAllergensByEnabledAndLanguageCode(false, TEST_LANGUAGE_CODE).blockingGet()
fun testGetAllergensByEnabledAndLanguageCode() = runBlockingTest {
val enabledAllergenNames = taxonomiesRepository.getAllergens(true, TEST_LANGUAGE_CODE)
val notEnabledAllergenNames = taxonomiesRepository.getAllergens(false, TEST_LANGUAGE_CODE)
assertNotNull(enabledAllergenNames)
assertNotNull(notEnabledAllergenNames)
assertEquals(1, enabledAllergenNames.size.toLong())
Expand All @@ -93,7 +93,7 @@ class ProductRepositoryTest {

@Test
fun testGetAllergensByLanguageCode() = runBlockingTest {
val allergenNames = productRepository.getAllergensByLanguageCode(TEST_LANGUAGE_CODE)
val allergenNames = taxonomiesRepository.getAllergens(TEST_LANGUAGE_CODE)
assertNotNull(allergenNames)
assertEquals(2, allergenNames.size.toLong())
}
Expand Down
@@ -1,8 +1,7 @@
package openfoodfacts.github.scrachx.openfood.category

import android.util.Log
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext
import openfoodfacts.github.scrachx.openfood.category.mapper.CategoryMapper
import openfoodfacts.github.scrachx.openfood.category.model.Category
import openfoodfacts.github.scrachx.openfood.category.network.CategoryNetworkService
Expand All @@ -15,22 +14,22 @@ import javax.inject.Singleton
*/
@Singleton
class CategoryRepository @Inject constructor(
private val networkService: CategoryNetworkService,
private val mapper: CategoryMapper
private val networkService: CategoryNetworkService,
private val mapper: CategoryMapper
) {
private val memoryCache = AtomicReference<List<Category>?>()

/**
* Calling this function retrieves list of all categories from NetworkService
*/
fun retrieveAll() = if (memoryCache.get() != null) {
Single.just(memoryCache.get())
} else {
networkService.getCategories()
.map { mapper.fromNetwork(it.tags) }
.doOnSuccess { memoryCache.set(it) }
.doOnError { Log.w(LOG_TAG, "Can't get categories", it) }
.subscribeOn(Schedulers.io())
suspend fun retrieveAll() = withContext(IO) {
if (memoryCache.get() != null) {
memoryCache.get()
} else {
networkService.getCategories()
.let { mapper.fromNetwork(it.tags) }
.also { memoryCache.set(it) }
}
}

companion object {
Expand Down
Expand Up @@ -12,6 +12,7 @@ class CategoryMapper @Inject constructor() {
* Returns list of Category objects using the tags
* @param tags List of CategoryResponse.Tag object
*/
fun fromNetwork(tags: List<CategoryResponse.Tag>) = tags.map { Category(it.id, it.name, it.url, it.products) }
fun fromNetwork(tags: List<CategoryResponse.Tag>) =
tags.map { Category(it.id, it.name, it.url, it.products) }
.sortedBy { it.name }
}
@@ -1,12 +1,11 @@
package openfoodfacts.github.scrachx.openfood.category.network

import io.reactivex.Single
import retrofit2.http.GET

/**
* Created by Abdelali Eramli on 27/12/2017.
*/
interface CategoryNetworkService {
@GET("categories.json")
fun getCategories(): Single<CategoryResponse>
suspend fun getCategories(): CategoryResponse
}
Expand Up @@ -9,14 +9,13 @@ import android.widget.Toast
import androidx.annotation.CheckResult
import androidx.core.app.ActivityOptionsCompat
import androidx.fragment.app.Fragment
import io.reactivex.disposables.Disposable
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.images.IMAGE_URL
import openfoodfacts.github.scrachx.openfood.images.ImageSize
import openfoodfacts.github.scrachx.openfood.images.createImageBundle
import openfoodfacts.github.scrachx.openfood.models.Product
import openfoodfacts.github.scrachx.openfood.models.ProductImageField
import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient
import openfoodfacts.github.scrachx.openfood.repositories.ProductRepository
import openfoodfacts.github.scrachx.openfood.utils.isAbsoluteUrl
import org.jetbrains.annotations.Contract

Expand All @@ -25,25 +24,24 @@ import org.jetbrains.annotations.Contract
*/
object FullScreenActivityOpener {

fun openForUrl(
fragment: Fragment,
client: OpenFoodAPIClient,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
mImageFront: View,
language: String
suspend fun openForUrl(
fragment: Fragment,
client: ProductRepository,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
mImageFront: View,
language: String
) = openForUrl(fragment.requireActivity(), client, product, imageType, mUrlImage, mImageFront, language)

@SuppressLint("CheckResult")
fun openForUrl(
activity: Activity,
client: OpenFoodAPIClient,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
mImageFront: View,
language: String
suspend fun openForUrl(
activity: Activity,
client: ProductRepository,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
mImageFront: View,
language: String
) {
// A new file added just now
if (isAbsoluteUrl(mUrlImage)) {
Expand All @@ -56,30 +54,30 @@ object FullScreenActivityOpener {
private fun startActivity(activity: Activity, mImageFront: View?, intent: Intent) {
val bundle = mImageFront?.let {
ActivityOptionsCompat.makeSceneTransitionAnimation(
activity,
mImageFront,
activity.getString(R.string.product_transition)
activity,
mImageFront,
activity.getString(R.string.product_transition)
).toBundle()
}
activity.startActivityForResult(intent, ImagesManageActivity.REQUEST_EDIT_IMAGE, bundle)
}

fun openZoom(
activity: Activity,
mUrlImage: String,
mImageFront: View?
activity: Activity,
mUrlImage: String,
mImageFront: View?
) = startActivity(activity, mImageFront, Intent(activity, ImageZoomActivity::class.java).apply {
putExtra(IMAGE_URL, mUrlImage)
})

@CheckResult
@Contract(pure = true)
private fun createIntent(
context: Context,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
language: String
context: Context,
product: Product,
imageType: ProductImageField,
mUrlImage: String,
language: String
): Intent {
var productLanguage = language
if (!product.isLanguageSupported(language) && product.lang.isNotBlank()) {
Expand All @@ -90,26 +88,21 @@ object FullScreenActivityOpener {
}
}

@CheckResult
private fun loadImageServerUrl(
activity: Activity,
client: OpenFoodAPIClient,
product: Product,
imageType: ProductImageField,
mImageFront: View,
language: String
): Disposable {
return client.getProductImages(product.code).subscribe { state ->
val newProduct = state.product
if (newProduct != null) {
val imageUrl = newProduct.getSelectedImage(language, imageType, ImageSize.DISPLAY)
if (!imageUrl.isNullOrBlank()) {
openForUrl(activity, client, newProduct, imageType, imageUrl, mImageFront, language)
} else {
Toast.makeText(activity, R.string.cant_edit_image_not_yet_uploaded, Toast.LENGTH_LONG).show()
}
private suspend fun loadImageServerUrl(
activity: Activity,
client: ProductRepository,
product: Product,
imageType: ProductImageField,
mImageFront: View,
language: String
) {
client.getProductImages(product.code).product?.let { newProduct ->
val imageUrl = newProduct.getSelectedImage(language, imageType, ImageSize.DISPLAY)
if (!imageUrl.isNullOrBlank()) {
openForUrl(activity, client, newProduct, imageType, imageUrl, mImageFront, language)
} else {
Toast.makeText(activity, R.string.cant_edit_image_not_yet_uploaded, Toast.LENGTH_LONG).show()
}
}

}
}
Expand Up @@ -41,12 +41,8 @@ import com.github.chrisbanes.photoview.PhotoViewAttacher
import com.squareup.picasso.Callback
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.rx2.await
import kotlinx.coroutines.withContext
import openfoodfacts.github.scrachx.openfood.R
import openfoodfacts.github.scrachx.openfood.databinding.ActivityFullScreenImageBinding
Expand All @@ -59,7 +55,7 @@ import openfoodfacts.github.scrachx.openfood.models.Product
import openfoodfacts.github.scrachx.openfood.models.ProductImageField
import openfoodfacts.github.scrachx.openfood.models.findByCode
import openfoodfacts.github.scrachx.openfood.network.ApiFields
import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient
import openfoodfacts.github.scrachx.openfood.repositories.ProductRepository
import openfoodfacts.github.scrachx.openfood.utils.*
import openfoodfacts.github.scrachx.openfood.utils.SwipeDetector.OnSwipeEventListener
import openfoodfacts.github.scrachx.openfood.utils.SwipeDetector.SwipeTypeEnum
Expand All @@ -79,7 +75,7 @@ class ImagesManageActivity : BaseActivity() {
private val binding get() = _binding!!

@Inject
lateinit var client: OpenFoodAPIClient
lateinit var client: ProductRepository

@Inject
lateinit var fileDownloader: FileDownloader
Expand All @@ -93,8 +89,6 @@ class ImagesManageActivity : BaseActivity() {
@Inject
lateinit var localeManager: LocaleManager

private val disp = CompositeDisposable()

private var lastViewedImage: File? = null
private lateinit var attacher: PhotoViewAttacher
private val settings by lazy { getAppPreferences() }
Expand Down Expand Up @@ -165,7 +159,6 @@ class ImagesManageActivity : BaseActivity() {
}

override fun onDestroy() {
disp.dispose()
_binding = null
super.onDestroy()
}
Expand Down Expand Up @@ -324,7 +317,7 @@ class ImagesManageActivity : BaseActivity() {
startRefresh(getString(R.string.loading_product, "${it.getProductName(localeManager.getLanguage())}..."))

lifecycleScope.launch {
val newState = client.getProductImages(it.code).observeOn(AndroidSchedulers.mainThread()).await()
val newState = client.getProductImages(it.code)
val newProduct = newState.product
var imageReloaded = false

Expand Down Expand Up @@ -358,10 +351,11 @@ class ImagesManageActivity : BaseActivity() {
*/
private fun updateProductImagesInfo(toDoAfter: () -> Unit = {}) {
getProduct()?.let { product ->
client.getProductImages(product.code).observeOn(AndroidSchedulers.mainThread()).subscribe { newState ->
lifecycleScope.launchWhenCreated {
val newState = client.getProductImages(product.code)
newState.product?.let { intent.putExtra(PRODUCT, it) }
toDoAfter()
}.addTo(disp)
}
}
}

Expand Down Expand Up @@ -565,7 +559,7 @@ class ImagesManageActivity : BaseActivity() {

private val selectImageLauncher = registerForActivityResult(ImagesSelectActivity.Companion.SelectImageContract(""))
{ (imgId, file) ->
// Photo choosed from gallery
// Photo chosen from gallery
if (file != null) {
onPhotoReturned(file)
} else if (!imgId.isNullOrBlank()) {
Expand Down Expand Up @@ -647,20 +641,27 @@ class ImagesManageActivity : BaseActivity() {
*/
private fun onPhotoReturned(newPhotoFile: File) {
startRefresh(getString(R.string.uploading_image))
val image = ProductImage(requireProduct().code, getSelectedType(), newPhotoFile, getCurrentLanguage()).apply {
val image = ProductImage(
requireProduct().code,
getSelectedType(),
newPhotoFile,
getCurrentLanguage()
).apply {
filePath = newPhotoFile.absolutePath
}
client.postImg(image, true)
.observeOn(AndroidSchedulers.mainThread())
.doOnError {
Toast.makeText(this@ImagesManageActivity, it.message, Toast.LENGTH_LONG).show()
Log.e(ImagesManageActivity::class.java.simpleName, it.message, it)

// Send image
lifecycleScope.launchWhenCreated {
try {
client.postImg(image, true)
} catch (err: Exception) {
Toast.makeText(this@ImagesManageActivity, err.message, Toast.LENGTH_LONG).show()
Log.e(ImagesManageActivity::class.simpleName, err.message, err)
stopRefresh()
}
.subscribe {
reloadProduct()
setResult(RESULTCODE_MODIFIED)
}.addTo(disp)
reloadProduct()
setResult(RESULTCODE_MODIFIED)
}
}

companion object {
Expand Down

0 comments on commit 5687e34

Please sign in to comment.