diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/app/OFFApplication.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/app/OFFApplication.kt index 3a36c2aacc05..4db11c8d40af 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/app/OFFApplication.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/app/OFFApplication.kt @@ -82,12 +82,6 @@ class OFFApplication : MultiDexApplication(), Configuration.Provider { private const val DEBUG = false val LOG_TAG = OFFApplication::class.simpleName!! - @JvmStatic - @Deprecated("Use hilt.") - lateinit var _daoSession: DaoSession - @Synchronized - private set - @Deprecated("Use hilt.") lateinit var _instance: OFFApplication @Synchronized diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/FragmentScope.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/FragmentScope.kt deleted file mode 100644 index bfb47d84327f..000000000000 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/FragmentScope.kt +++ /dev/null @@ -1,6 +0,0 @@ -package openfoodfacts.github.scrachx.openfood.dagger - -import javax.inject.Scope - -@Scope -annotation class FragmentScope \ No newline at end of file diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/Qualifiers.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/Qualifiers.kt deleted file mode 100644 index de8249395d57..000000000000 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/Qualifiers.kt +++ /dev/null @@ -1,11 +0,0 @@ -package openfoodfacts.github.scrachx.openfood.dagger - -import javax.inject.Qualifier - -class Qualifiers { - @Qualifier - annotation class ForApplication - - @Qualifier - annotation class ForActivity -} \ No newline at end of file diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/PreferencesFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/PreferencesFragment.kt index b0558eec442a..09b947a35207 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/PreferencesFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/PreferencesFragment.kt @@ -35,12 +35,14 @@ import androidx.appcompat.app.AppCompatDelegate import androidx.browser.customtabs.CustomTabsIntent import androidx.core.content.edit import androidx.core.content.pm.PackageInfoCompat +import androidx.core.net.toUri import androidx.preference.* import androidx.preference.Preference.OnPreferenceClickListener import androidx.work.OneTimeWorkRequest import androidx.work.WorkInfo import androidx.work.WorkManager import com.afollestad.materialdialogs.MaterialDialog +import dagger.hilt.android.AndroidEntryPoint import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable @@ -52,7 +54,6 @@ import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF import openfoodfacts.github.scrachx.openfood.AppFlavors.OPFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.R -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback import openfoodfacts.github.scrachx.openfood.features.scan.ContinuousScanActivity @@ -75,11 +76,15 @@ import org.greenrobot.greendao.async.AsyncOperation import org.greenrobot.greendao.async.AsyncOperationListener import org.greenrobot.greendao.query.WhereCondition.StringCondition import java.util.* +import javax.inject.Inject - +@AndroidEntryPoint class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnSharedPreferenceChangeListener { private val disp = CompositeDisposable() + @Inject + lateinit var daoSession: DaoSession + override val navigationDrawerListener: NavigationDrawerListener? by lazy { if (activity is NavigationDrawerListener) activity as NavigationDrawerListener else null @@ -154,7 +159,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare requirePreference(getString(R.string.pref_scanner_type_key)).let { it.isVisible = ContinuousScanActivity.showSelectScannerPref it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - if(newValue == true){ + if (newValue == true) { MaterialDialog.Builder(requireActivity()).run { title(R.string.preference_choose_scanner_dialog_title) content(R.string.preference_choose_scanner_dialog_body) @@ -165,15 +170,14 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare Toast.makeText(requireActivity(), getString(R.string.changes_saved), Toast.LENGTH_SHORT).show() } negativeText(R.string.dialog_cancel) - onNegative { - dialog, _ -> dialog.dismiss() + onNegative { dialog, _ -> + dialog.dismiss() it.isChecked = false settings.edit { putBoolean(getString(R.string.pref_scanner_type_key), false) } } show() } - } - else{ + } else { it.isChecked = false settings.edit { putBoolean(getString(R.string.pref_scanner_type_key), newValue as Boolean) } Toast.makeText(requireActivity(), getString(R.string.changes_saved), Toast.LENGTH_SHORT).show() @@ -182,23 +186,17 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare } } - val countryLabels = mutableListOf() - val countryTags = mutableListOf() val countryPreference = requirePreference(getString(R.string.pref_country_key)) - val asyncSessionCountries = OFFApplication._daoSession.startAsyncSession() - val countryNameDao = OFFApplication._daoSession.countryNameDao + val asyncSessionCountries = daoSession.startAsyncSession() + val countryNameDao = daoSession.countryNameDao // Set query finish listener asyncSessionCountries.listenerMainThread = AsyncOperationListener { operation: AsyncOperation -> val countryNames = operation.result as List - countryNames.forEach { - countryLabels.add(it.name) - countryTags.add(it.countyTag) - } - countryPreference.entries = countryLabels.toTypedArray() - countryPreference.entryValues = countryTags.toTypedArray() + countryPreference.entries = countryNames.map { it.name }.toTypedArray() + countryPreference.entryValues = countryNames.map { it.countyTag }.toTypedArray() } // Execute query asyncSessionCountries.queryList(countryNameDao.queryBuilder() @@ -213,11 +211,11 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare } requirePreference(getString(R.string.pref_contact_us_key)).setOnPreferenceChangeListener { _, _ -> - val contactIntent = Intent(Intent.ACTION_SENDTO) - contactIntent.data = Uri.parse(getString(R.string.off_mail)) - contactIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK try { - startActivity(contactIntent) + startActivity(Intent(Intent.ACTION_SENDTO).apply { + data = Uri.parse(getString(R.string.off_mail)) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + }) } catch (e: ActivityNotFoundException) { Toast.makeText(requireActivity(), R.string.email_not_found, Toast.LENGTH_SHORT).show() } @@ -225,7 +223,8 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare } requirePreference(getString(R.string.pref_rate_us_key)).setOnPreferenceChangeListener { _, _ -> try { - startActivity(Intent(ACTION_VIEW, Uri.parse("market://details?id=${requireActivity().packageName}"))) + startActivity(Intent(ACTION_VIEW, + Uri.parse("market://details?id=${requireActivity().packageName}"))) } catch (e: ActivityNotFoundException) { startActivity(Intent(ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=${requireActivity().packageName}"))) } @@ -287,14 +286,14 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare } if (isFlavors(OFF, OBF, OPFF)) { - getAnalysisTagConfigs(OFFApplication._daoSession) + getAnalysisTagConfigs(daoSession) } else { preferenceScreen.removePreference(preferenceScreen.requirePreference(getString(R.string.pref_key_display))) } } } - private fun buildDisplayCategory(configs: List?) { + private fun buildDisplayCategory(configs: List) { if (!isAdded) return val displayCategory = preferenceScreen.requirePreference(getString(R.string.pref_key_display)) @@ -302,33 +301,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare preferenceScreen.addPreference(displayCategory) // If analysis tag is empty show "Load ingredient detection data" option in order to manually reload taxonomies - if (configs == null || configs.isEmpty()) { - val preference = Preference(preferenceScreen.context) - preference.setTitle(R.string.load_ingredient_detection_data) - preference.setSummary(R.string.load_ingredient_detection_data_summary) - preference.onPreferenceClickListener = OnPreferenceClickListener { pref: Preference -> - pref.onPreferenceClickListener = null - val manager = WorkManager.getInstance(requireContext()) - val request = OneTimeWorkRequest.from(LoadTaxonomiesWorker::class.java) - - // The service will load server resources only if newer than already downloaded... - manager.enqueue(request) - manager.getWorkInfoByIdLiveData(request.id).observe(this, { workInfo: WorkInfo? -> - if (workInfo != null) { - if (workInfo.state == WorkInfo.State.RUNNING) { - preference.setTitle(R.string.please_wait) - preference.setIcon(R.drawable.ic_cloud_download_black_24dp) - preference.summary = null - preference.widgetLayoutResource = R.layout.loading - } else if (workInfo.state == WorkInfo.State.SUCCEEDED) { - getAnalysisTagConfigs(OFFApplication._daoSession) - } - } - }) - true - } - displayCategory.addPreference(preference) - } else { + if (configs.isNotEmpty()) { configs.forEach { config -> displayCategory.addPreference(CheckBoxPreference(this.context).apply { key = config.type @@ -339,14 +312,43 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare title = getString(R.string.display_analysis_tag_status, config.typeName.toLowerCase(Locale.getDefault())) }) } + } else { + val preference = Preference(preferenceScreen.context).apply { + setTitle(R.string.load_ingredient_detection_data) + setSummary(R.string.load_ingredient_detection_data_summary) + onPreferenceClickListener = OnPreferenceClickListener { pref -> + pref.onPreferenceClickListener = null + val request = OneTimeWorkRequest.from(LoadTaxonomiesWorker::class.java) + + // The service will load server resources only if newer than already downloaded... + WorkManager.getInstance(requireContext()).let { manager -> + manager.enqueue(request) + manager.getWorkInfoByIdLiveData(request.id).observe(this@PreferencesFragment, { workInfo: WorkInfo? -> + if (workInfo != null) { + if (workInfo.state == WorkInfo.State.RUNNING) { + pref.setTitle(R.string.please_wait) + pref.setIcon(R.drawable.ic_cloud_download_black_24dp) + pref.summary = null + pref.widgetLayoutResource = R.layout.loading + } else if (workInfo.state == WorkInfo.State.SUCCEEDED) { + getAnalysisTagConfigs(daoSession) + } + } + }) + } + true + } + } + displayCategory.addPreference(preference) } displayCategory.isVisible = true } private fun openWebCustomTab(@StringRes resId: Int): Boolean { - val customTabsIntent = CustomTabsIntent.Builder().build() - customTabsIntent.intent.putExtra("android.intent.extra.REFERRER", Uri.parse("android-app://${requireContext().packageName}")) - CustomTabActivityHelper.openCustomTab(requireActivity(), customTabsIntent, Uri.parse(getString(resId)), WebViewFallback()) + val customTabsIntent = CustomTabsIntent.Builder().build().apply { + intent.putExtra("android.intent.extra.REFERRER", "android-app://${requireContext().packageName}".toUri()) + } + CustomTabActivityHelper.openCustomTab(requireActivity(), customTabsIntent, getString(resId).toUri(), WebViewFallback()) return true } @@ -404,7 +406,7 @@ class PreferencesFragment : PreferenceFragmentCompat(), INavigationItem, OnShare analysisTagConfigs }.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe { configs -> buildDisplayCategory(configs) } + .subscribe { configs: List -> buildDisplayCategory(configs) } .addTo(disp) } diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/additives/AdditiveListActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/additives/AdditiveListActivity.kt index b5c8f455f973..713d582d6003 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/additives/AdditiveListActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/additives/AdditiveListActivity.kt @@ -8,25 +8,35 @@ import android.view.Menu import android.widget.SearchView import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager +import dagger.hilt.android.AndroidEntryPoint import openfoodfacts.github.scrachx.openfood.R import openfoodfacts.github.scrachx.openfood.databinding.ActivityAdditivesExplorerBinding import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.installBottomNavigation import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.selectNavigationItem import openfoodfacts.github.scrachx.openfood.features.search.ProductSearchActivity import openfoodfacts.github.scrachx.openfood.features.shared.BaseActivity +import openfoodfacts.github.scrachx.openfood.models.DaoSession import openfoodfacts.github.scrachx.openfood.models.entities.additive.AdditiveName import openfoodfacts.github.scrachx.openfood.models.entities.additive.AdditiveNameDao import openfoodfacts.github.scrachx.openfood.utils.LocaleHelper import openfoodfacts.github.scrachx.openfood.utils.SearchType -import openfoodfacts.github.scrachx.openfood.utils.Utils import org.greenrobot.greendao.async.AsyncOperation import org.greenrobot.greendao.async.AsyncOperationListener import java.util.* +import javax.inject.Inject +@AndroidEntryPoint class AdditiveListActivity : BaseActivity() { private var _binding: ActivityAdditivesExplorerBinding? = null private val binding get() = _binding!! + + @Inject + lateinit var daoSession: DaoSession + + private var additives = mutableListOf() + + override fun onDestroy() { super.onDestroy() _binding = null @@ -39,7 +49,6 @@ class AdditiveListActivity : BaseActivity() { setSupportActionBar(binding.toolbarInclude.toolbar) supportActionBar!!.setDisplayHomeAsUpEnabled(true) supportActionBar!!.setTitle(R.string.additives) - val daoSession = Utils.daoSession val asyncSessionAdditives = daoSession.startAsyncSession() val additiveNameDao = daoSession.additiveNameDao val languageCode = LocaleHelper.getLanguage(this) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditActivity.kt index a66e676c0f35..7a7dfb00d81c 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditActivity.kt @@ -43,13 +43,13 @@ import openfoodfacts.github.scrachx.openfood.AppFlavors.OPF import openfoodfacts.github.scrachx.openfood.AppFlavors.OPFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.R -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.databinding.ActivityEditProductBinding import openfoodfacts.github.scrachx.openfood.features.product.ProductFragmentPagerAdapter import openfoodfacts.github.scrachx.openfood.features.product.edit.overview.ProductEditOverviewFragment import openfoodfacts.github.scrachx.openfood.images.IMG_ID import openfoodfacts.github.scrachx.openfood.images.ProductImage import openfoodfacts.github.scrachx.openfood.jobs.OfflineProductWorker.Companion.scheduleSync +import openfoodfacts.github.scrachx.openfood.models.DaoSession import openfoodfacts.github.scrachx.openfood.models.Product import openfoodfacts.github.scrachx.openfood.models.ProductImageField import openfoodfacts.github.scrachx.openfood.models.entities.OfflineSavedProduct @@ -59,7 +59,6 @@ import openfoodfacts.github.scrachx.openfood.network.CommonApiManager.productsAp import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient.Companion.addToHistorySync import openfoodfacts.github.scrachx.openfood.utils.OfflineProductService -import openfoodfacts.github.scrachx.openfood.utils.Utils.daoSession import openfoodfacts.github.scrachx.openfood.utils.Utils.hideKeyboard import openfoodfacts.github.scrachx.openfood.utils.Utils.isExternalStorageWritable import openfoodfacts.github.scrachx.openfood.utils.getLoginPreferences @@ -80,6 +79,12 @@ class ProductEditActivity : AppCompatActivity() { @Inject lateinit var offlineService: OfflineProductService + @Inject + lateinit var daoSession: DaoSession + + @Inject + lateinit var client: OpenFoodAPIClient + private val addProductPhotosFragment = ProductEditPhotosFragment() private val nutritionFactsFragment = ProductEditNutritionFactsFragment() private val ingredientsFragment = ProductEditIngredientsFragment() @@ -258,7 +263,7 @@ class ProductEditActivity : AppCompatActivity() { imgMap[ApiFields.Keys.USER_ID] = createTextPlain(login) imgMap[ApiFields.Keys.USER_PASS] = createTextPlain(password) } - imgMap[ApiFields.Keys.USER_COMMENT] = createTextPlain(OpenFoodAPIClient.getCommentToUpload(login)) + imgMap[ApiFields.Keys.USER_COMMENT] = createTextPlain(client.getCommentToUpload(login)) } private fun saveProduct() { @@ -392,7 +397,7 @@ class ProductEditActivity : AppCompatActivity() { } else { hideImageProgress(position, true, it.message ?: "Empty error.") Log.i(this::class.simpleName, it.message ?: "Empty error.") - Toast.makeText(OFFApplication._instance, it.message, Toast.LENGTH_SHORT).show() + Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show() } } .subscribe { jsonNode -> diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditIngredientsFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditIngredientsFragment.kt index bc71cc4117a1..52cef138efcf 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditIngredientsFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/ProductEditIngredientsFragment.kt @@ -63,6 +63,9 @@ class ProductEditIngredientsFragment : ProductEditFragment() { private var _binding: FragmentAddProductIngredientsBinding? = null private val binding get() = _binding!! + @Inject + lateinit var daoSession: DaoSession + private var photoReceiverHandler: PhotoReceiverHandler? = null private var mAllergenNameDao: AllergenNameDao? = null private var photoFile: File? = null @@ -110,7 +113,7 @@ class ProductEditIngredientsFragment : ProductEditFragment() { val bundle = arguments if (bundle != null) { - mAllergenNameDao = Utils.daoSession.allergenNameDao + mAllergenNameDao = daoSession.allergenNameDao product = getProductFromArgs() mOfflineSavedProduct = getEditOfflineProductFromArgs() if (product != null) { @@ -273,8 +276,6 @@ class ProductEditIngredientsFragment : ProductEditFragment() { /** * Automatically load suggestions for allergen names */ - @Inject - lateinit var daoSession: DaoSession private fun loadAutoSuggestions() { val asyncSessionAllergens = daoSession.startAsyncSession() val allergenNameDao = daoSession.allergenNameDao diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/ProductEditOverviewFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/ProductEditOverviewFragment.kt index 984742a5f2e7..88771457df26 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/ProductEditOverviewFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/ProductEditOverviewFragment.kt @@ -363,7 +363,7 @@ class ProductEditOverviewFragment : ProductEditFragment() { * @return returns the name of the country if found in the db or else returns the tag itself. */ private fun getCountryName(languageCode: String?, tag: String) = - Utils.daoSession.countryNameDao.queryBuilder() + daoSession.countryNameDao.queryBuilder() .where( CountryNameDao.Properties.CountyTag.eq(tag), CountryNameDao.Properties.LanguageCode.eq(languageCode) @@ -376,7 +376,7 @@ class ProductEditOverviewFragment : ProductEditFragment() { * @return returns the name of the label if found in the db or else returns the tag itself. */ private fun getLabelName(languageCode: String?, tag: String) = - Utils.daoSession.labelNameDao.queryBuilder() + daoSession.labelNameDao.queryBuilder() .where( LabelNameDao.Properties.LabelTag.eq(tag), LabelNameDao.Properties.LanguageCode.eq(languageCode) @@ -389,7 +389,7 @@ class ProductEditOverviewFragment : ProductEditFragment() { * @return returns the name of the category (example Plant-based foods and beverages) if found in the db or else returns the tag itself. */ private fun getCategoryName(languageCode: String?, tag: String): String { - return Utils.daoSession.categoryNameDao + return daoSession.categoryNameDao .queryBuilder() .where( CategoryNameDao.Properties.CategoryTag.eq(tag), @@ -399,7 +399,7 @@ class ProductEditOverviewFragment : ProductEditFragment() { } private fun getEmbCode(embTag: String) = - Utils.daoSession.tagDao.queryBuilder() + daoSession.tagDao.queryBuilder() .where(TagDao.Properties.Id.eq(embTag)) .unique() ?.name ?: embTag diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductFragment.kt index c24e86d0c10c..e225afc4adf6 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductFragment.kt @@ -150,7 +150,7 @@ class IngredientsProductFragment : BaseFragment(), IIngredientsProductPresenter. if (arguments != null) mSendProduct = getSendProduct() val product = this.productState.product!! - presenter = IngredientsProductPresenter(product, this, productRepository).apply { addTo(disp) } + presenter = IngredientsProductPresenter(requireContext(), this, productRepository, product).apply { addTo(disp) } val vitaminTagsList = product.vitaminTags val aminoAcidTagsList = product.aminoAcidTags val mineralTags = product.mineralTags diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductPresenter.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductPresenter.kt index 3886033650a1..4b06a7c06ce8 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductPresenter.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/ingredients/IngredientsProductPresenter.kt @@ -15,6 +15,7 @@ */ package openfoodfacts.github.scrachx.openfood.features.product.view.ingredients +import android.content.Context import android.util.Log import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers @@ -22,7 +23,6 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.toObservable import io.reactivex.schedulers.Schedulers -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.models.Product import openfoodfacts.github.scrachx.openfood.models.entities.additive.AdditiveName import openfoodfacts.github.scrachx.openfood.models.entities.allergen.AllergenName @@ -34,9 +34,10 @@ import openfoodfacts.github.scrachx.openfood.utils.ProductInfoState * Created by Lobster on 17.03.18. */ class IngredientsProductPresenter( - private val product: Product, + private val context: Context, private val view: IIngredientsProductPresenter.View, - private val productRepository: ProductRepository + private val productRepository: ProductRepository, + private val product: Product ) : IIngredientsProductPresenter.Actions { private val disp = CompositeDisposable() @@ -46,7 +47,7 @@ class IngredientsProductPresenter( view.showAdditivesState(ProductInfoState.EMPTY) return } - val languageCode = LocaleHelper.getLanguage(OFFApplication._instance) + val languageCode = LocaleHelper.getLanguage(context) additivesTags.toObservable() .flatMapSingle { tag: String? -> productRepository.getAdditiveByTagAndLanguageCode(tag, languageCode).flatMap { categoryName: AdditiveName -> @@ -82,7 +83,7 @@ class IngredientsProductPresenter( view.showAllergensState(ProductInfoState.EMPTY) return } - val languageCode = LocaleHelper.getLanguage(OFFApplication._instance) + val languageCode = LocaleHelper.getLanguage(context) allergenTags.toObservable() .flatMapSingle { tag: String? -> productRepository.getAllergenByTagAndLanguageCode(tag, languageCode).flatMap { allergenName: AllergenName -> diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/DialogAddToListAdapter.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/DialogAddToListAdapter.kt index 9972fe9d44db..33b31fae366d 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/DialogAddToListAdapter.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/summary/DialogAddToListAdapter.kt @@ -9,9 +9,9 @@ import androidx.recyclerview.widget.RecyclerView import openfoodfacts.github.scrachx.openfood.R import openfoodfacts.github.scrachx.openfood.features.product.view.summary.DialogAddToListAdapter.ListViewHolder import openfoodfacts.github.scrachx.openfood.features.productlist.ProductListActivity +import openfoodfacts.github.scrachx.openfood.models.DaoSession import openfoodfacts.github.scrachx.openfood.models.entities.ProductLists import openfoodfacts.github.scrachx.openfood.models.entities.YourListedProduct -import openfoodfacts.github.scrachx.openfood.utils.Utils.daoSession //recyclerview adapter to display product lists in a dialog class DialogAddToListAdapter( @@ -20,7 +20,8 @@ class DialogAddToListAdapter( private val barcode: String, private val productName: String, private val productDetails: String, - private val imageUrl: String + private val imageUrl: String, + private val daoSession: DaoSession ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder { val view = LayoutInflater.from(context).inflate(R.layout.dialog_add_to_list_recycler_item, parent, false) 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 65ee2b673cbf..d9006c571125 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 @@ -48,7 +48,6 @@ import io.reactivex.rxkotlin.addTo import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.R -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabsHelper import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback @@ -206,11 +205,7 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View { private fun onImageListenerError(error: Throwable) { binding.uploadingImageProgress.visibility = View.GONE binding.uploadingImageProgressText.visibility = View.GONE - var context = context - if (context == null) { - context = OFFApplication._instance - } - Toast.makeText(context, error.message, Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), error.message, Toast.LENGTH_SHORT).show() } @@ -819,7 +814,8 @@ class SummaryProductFragment : BaseFragment(), ISummaryProductPresenter.View { productBarcode, productName.orEmpty(), productDetails, - imageUrl.orEmpty() + imageUrl.orEmpty(), + daoSession ) addToListRecyclerView.layoutManager = LinearLayoutManager(activity) addToListRecyclerView.adapter = addToListAdapter 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 29db3dc0c7d5..ee9d3ba09e14 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 @@ -32,6 +32,7 @@ import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomList import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.selectNavigationItem import openfoodfacts.github.scrachx.openfood.features.scan.ContinuousScanActivity import openfoodfacts.github.scrachx.openfood.features.shared.BaseActivity +import openfoodfacts.github.scrachx.openfood.models.DaoSession import openfoodfacts.github.scrachx.openfood.models.HistoryProduct import openfoodfacts.github.scrachx.openfood.models.HistoryProductDao import openfoodfacts.github.scrachx.openfood.models.Product @@ -41,7 +42,6 @@ import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient import openfoodfacts.github.scrachx.openfood.utils.* import openfoodfacts.github.scrachx.openfood.utils.LocaleHelper.getLanguage import openfoodfacts.github.scrachx.openfood.utils.SortType.* -import openfoodfacts.github.scrachx.openfood.utils.Utils.daoSession import java.io.File import java.text.SimpleDateFormat import java.util.* @@ -56,6 +56,9 @@ class ProductListActivity : BaseActivity(), SwipeController.Actions { @Inject lateinit var client: OpenFoodAPIClient + @Inject + lateinit var daoSession: DaoSession + private var listID by Delegates.notNull() private lateinit var productList: ProductLists private lateinit var adapter: ProductListAdapter @@ -312,7 +315,7 @@ class ProductListActivity : BaseActivity(), SwipeController.Actions { @RequiresApi(Build.VERSION_CODES.KITKAT) val fileWriterLauncher = registerForActivityResult(CreateCSVContract()) { - writeListToFile(this, productList, it,contentResolver.openOutputStream(it) ?: error("File path must not be null.")) + writeListToFile(this, productList, it, contentResolver.openOutputStream(it) ?: error("File path must not be null.")) } private fun exportAsCSV() { @@ -330,7 +333,7 @@ class ProductListActivity : BaseActivity(), SwipeController.Actions { val baseDir = File(Environment.getExternalStorageDirectory(), getCsvFolderName()) if (!baseDir.exists()) baseDir.mkdirs() val file = File(baseDir, fileName) - writeListToFile(this, productList,Uri.fromFile(file), file.outputStream()) + writeListToFile(this, productList, Uri.fromFile(file), file.outputStream()) } } 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 a722b7f3ef30..8de425ab0392 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 @@ -53,7 +53,6 @@ import openfoodfacts.github.scrachx.openfood.models.entities.ProductListsDao import openfoodfacts.github.scrachx.openfood.models.entities.YourListedProduct import openfoodfacts.github.scrachx.openfood.models.entities.YourListedProductDao import openfoodfacts.github.scrachx.openfood.utils.SwipeController -import openfoodfacts.github.scrachx.openfood.utils.Utils import org.apache.commons.csv.CSVFormat import org.apache.commons.csv.CSVParser import java.io.InputStream @@ -230,7 +229,7 @@ class ProductListsActivity : BaseActivity(), SwipeController.Actions { progressDialog.show() Observable.create { emitter: ObservableEmitter -> Single.fromCallable { - val yourListedProductDao = Utils.daoSession.yourListedProductDao + val yourListedProductDao = daoSession.yourListedProductDao val list = ArrayList() try { CSVParser(InputStreamReader(inputStream), CSVFormat.DEFAULT.withFirstRecordAsHeader()).use { csvParser -> diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/viewmodel/category/CategoryFragmentViewModel.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/viewmodel/category/CategoryFragmentViewModel.kt index cffb74968f00..9577cb294a3b 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/viewmodel/category/CategoryFragmentViewModel.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/viewmodel/category/CategoryFragmentViewModel.kt @@ -27,7 +27,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.addTo import io.reactivex.schedulers.Schedulers -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.models.entities.category.Category import openfoodfacts.github.scrachx.openfood.models.entities.category.CategoryName import openfoodfacts.github.scrachx.openfood.repositories.ProductRepository @@ -64,7 +63,7 @@ class CategoryFragmentViewModel @Inject constructor( * Generates a network call for showing categories in CategoryFragment */ fun refreshCategories() { - productRepository.getAllCategoriesByLanguageCode(getLanguage(OFFApplication._instance)) + productRepository.getAllCategoriesByLanguageCode(getLanguage(app)) .doOnSubscribe { showOffline.set(View.GONE) showProgress.set(View.VISIBLE) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/ActivityModule.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/ActivityModule.kt similarity index 65% rename from app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/ActivityModule.kt rename to app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/ActivityModule.kt index 39ab3f7a3849..6829428c1816 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/ActivityModule.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/ActivityModule.kt @@ -1,4 +1,4 @@ -package openfoodfacts.github.scrachx.openfood.dagger.module +package openfoodfacts.github.scrachx.openfood.hilt import dagger.Module import dagger.hilt.InstallIn diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/AppModule.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/AppModule.kt similarity index 97% rename from app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/AppModule.kt rename to app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/AppModule.kt index 279e33ecbdf2..b78de2e462e0 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/AppModule.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/AppModule.kt @@ -1,4 +1,4 @@ -package openfoodfacts.github.scrachx.openfood.dagger.module +package openfoodfacts.github.scrachx.openfood.hilt import android.content.Context import dagger.Module diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/FragmentModule.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/FragmentModule.kt similarity index 65% rename from app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/FragmentModule.kt rename to app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/FragmentModule.kt index ab50ab9745aa..de9f287bbde6 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/dagger/module/FragmentModule.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/hilt/FragmentModule.kt @@ -1,4 +1,4 @@ -package openfoodfacts.github.scrachx.openfood.dagger.module +package openfoodfacts.github.scrachx.openfood.hilt import dagger.Module import dagger.hilt.InstallIn diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt index db56175b67b9..96b95d762dfd 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt @@ -24,7 +24,6 @@ import openfoodfacts.github.scrachx.openfood.AppFlavors.OPFF import openfoodfacts.github.scrachx.openfood.BuildConfig import openfoodfacts.github.scrachx.openfood.R import openfoodfacts.github.scrachx.openfood.app.AnalyticsService -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.Companion.KEY_EDIT_PRODUCT import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewActivity @@ -36,7 +35,6 @@ import openfoodfacts.github.scrachx.openfood.models.entities.ToUploadProductDao import openfoodfacts.github.scrachx.openfood.network.CommonApiManager.productsApi import openfoodfacts.github.scrachx.openfood.utils.* import openfoodfacts.github.scrachx.openfood.utils.LocaleHelper.getLanguage -import openfoodfacts.github.scrachx.openfood.utils.Utils.daoSession import java.io.File import java.io.IOException import java.util.* @@ -49,7 +47,8 @@ import openfoodfacts.github.scrachx.openfood.features.product.view.ProductViewAc */ @Singleton class OpenFoodAPIClient @Inject constructor( - @ApplicationContext val context: Context + @ApplicationContext private val context: Context, + private val daoSession: DaoSession ) { private var historySyncDisp = CompositeDisposable() @@ -197,7 +196,7 @@ class OpenFoodAPIClient @Inject constructor( /** * Add a product to ScanHistory asynchronously */ - fun addToHistory(product: Product) = Completable.fromAction { daoSession.historyProductDao.addToHistorySync(product) } + fun addToHistory(product: Product) = Completable.fromAction { daoSession.historyProductDao.addToHistorySync(product, this) } fun getProductsByContributor(contributor: String, page: Int) = productsApi.getProductsByContributor(contributor, page).subscribeOn(Schedulers.io()) @@ -374,41 +373,34 @@ class OpenFoodAPIClient @Inject constructor( companion object { const val MIME_TEXT = "text/plain" const val PNG_EXT = ".png\"" - - - /** - * Uploads comment by users - * - * @param login the username - */ - fun getCommentToUpload(login: String? = null): String { - val comment = when (BuildConfig.FLAVOR) { - OBF -> StringBuilder("Official Open Beauty Facts Android app") - OPFF -> StringBuilder("Official Open Pet Food Facts Android app") - OPF -> StringBuilder("Official Open Products Facts Android app") - OFF -> StringBuilder("Official Open Food Facts Android app") - else -> StringBuilder("Official Open Food Facts Android app") - } - comment.append(" ").append(getVersionName(OFFApplication._instance)) - if (login.isNullOrEmpty()) { - comment.append(" (Added by ").append(InstallationUtils.id(OFFApplication._instance)).append(")") - } - return comment.toString() + fun HistoryProductDao.addToHistorySync(product: OfflineSavedProduct) { + val historyProducts = queryBuilder().where(HistoryProductDao.Properties.Barcode.eq(product.barcode)).list() + val productDetails = product.productDetails + val hp = HistoryProduct( + product.name, + productDetails[ApiFields.Keys.ADD_BRANDS], + product.imageFrontLocalUrl, + product.barcode, + productDetails[ApiFields.Keys.QUANTITY], + null, + null, + null + ) + if (historyProducts.isNotEmpty()) hp.id = historyProducts[0].id + insertOrReplace(hp) } - fun getLocaleProductNameField() = "product_name_${getLanguage(OFFApplication._instance)}" - /** * Add a product to ScanHistory synchronously */ - fun HistoryProductDao.addToHistorySync(product: Product) { + fun HistoryProductDao.addToHistorySync(product: Product, client: OpenFoodAPIClient) { val historyProducts = queryBuilder() .where(HistoryProductDao.Properties.Barcode.eq(product.code)) .list() val hp = HistoryProduct( product.productName, product.brands, - product.getImageSmallUrl(getLanguage(OFFApplication._instance)), + product.getImageSmallUrl(getLanguage(client.context)), product.code, product.quantity, product.nutritionGradeFr, @@ -418,54 +410,59 @@ class OpenFoodAPIClient @Inject constructor( if (historyProducts.isNotEmpty()) hp.id = historyProducts[0].id insertOrReplace(hp) } + } - fun HistoryProductDao.addToHistorySync(product: OfflineSavedProduct) { - val historyProducts = queryBuilder().where(HistoryProductDao.Properties.Barcode.eq(product.barcode)).list() - val productDetails = product.productDetails - val hp = HistoryProduct( - product.name, - productDetails[ApiFields.Keys.ADD_BRANDS], - product.imageFrontLocalUrl, - product.barcode, - productDetails[ApiFields.Keys.QUANTITY], - null, - null, - null - ) - if (historyProducts.isNotEmpty()) hp.id = historyProducts[0].id - insertOrReplace(hp) - } + /** + * Fill the given [Map] with user info (username, password, comment) + * + * @param imgMap The map to fill + */ + private fun addUserInfo(imgMap: MutableMap = mutableMapOf()): Map { + val settings = context.getLoginPreferences() - /** - * Fill the given [Map] with user info (username, password, comment) - * - * @param imgMap The map to fill - */ - fun addUserInfo(imgMap: MutableMap = mutableMapOf()): Map { - val settings = OFFApplication._instance.getLoginPreferences() + settings.getString("user", null)?.let { + imgMap[ApiFields.Keys.USER_COMMENT] = getCommentToUpload(it) + if (it.isNotBlank()) imgMap[ApiFields.Keys.USER_ID] = it + } - settings.getString("user", null)?.let { - imgMap[ApiFields.Keys.USER_COMMENT] = getCommentToUpload(it) - if (it.isNotBlank()) imgMap[ApiFields.Keys.USER_ID] = it - } + settings.getString("pass", null)?.let { + if (it.isNotBlank()) imgMap[ApiFields.Keys.USER_PASS] = it + } - settings.getString("pass", null)?.let { - if (it.isNotBlank()) imgMap[ApiFields.Keys.USER_PASS] = it - } + return imgMap + } - return imgMap + /** + * Uploads comment by users + * + * @param login the username + */ + fun getCommentToUpload(login: String? = null): String { + val comment = when (BuildConfig.FLAVOR) { + OBF -> StringBuilder("Official Open Beauty Facts Android app") + OPFF -> StringBuilder("Official Open Pet Food Facts Android app") + OPF -> StringBuilder("Official Open Products Facts Android app") + OFF -> StringBuilder("Official Open Food Facts Android app") + else -> StringBuilder("Official Open Food Facts Android app") } - - private fun getFieldsToFetchFacets() = listOf( - ApiFields.Keys.BRANDS, - ApiFields.Keys.PRODUCT_NAME, - ApiFields.Keys.IMAGE_SMALL_URL, - ApiFields.Keys.QUANTITY, - ApiFields.Keys.NUTRITION_GRADE_FR, - ApiFields.Keys.BARCODE, - ApiFields.Keys.ECOSCORE, - ApiFields.Keys.NOVA_GROUPS, - getLocaleProductNameField() - ).joinToString(",") + comment.append(" ").append(context.getVersionName()) + if (login.isNullOrEmpty()) { + comment.append(" (Added by ").append(InstallationUtils.id(context)).append(")") + } + return comment.toString() } + + private fun getLocaleProductNameField() = "product_name_${getLanguage(context)}" + + private fun getFieldsToFetchFacets() = listOf( + ApiFields.Keys.BRANDS, + ApiFields.Keys.PRODUCT_NAME, + ApiFields.Keys.IMAGE_SMALL_URL, + ApiFields.Keys.QUANTITY, + ApiFields.Keys.NUTRITION_GRADE_FR, + ApiFields.Keys.BARCODE, + ApiFields.Keys.ECOSCORE, + ApiFields.Keys.NOVA_GROUPS, + getLocaleProductNameField() + ).joinToString(",") } diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/WikiDataApiClient.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/WikiDataApiClient.kt index 9ddffda565f7..e09ba416037d 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/WikiDataApiClient.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/WikiDataApiClient.kt @@ -11,16 +11,13 @@ import javax.inject.Singleton * @since 14.03.18 */ @Singleton -class WikiDataApiClient @Inject constructor() { - - @Inject - lateinit var wikidataAPI: WikidataAPI - +class WikiDataApiClient @Inject constructor( + private val wikidataAPI: WikidataAPI +) { /** * Get json response of the WikiData for additive/ingredient/category/label using their WikiDataID * * @param code WikiData ID of additive/ingredient/category/label */ fun doSomeThing(code: String) = wikidataAPI.getWikiCategory(code).map { it["entities"][code] } - } \ No newline at end of file diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/ProductRepository.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/ProductRepository.kt index 3fb5376e8ab8..0284692df167 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/ProductRepository.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/ProductRepository.kt @@ -15,14 +15,15 @@ */ package openfoodfacts.github.scrachx.openfood.repositories +import android.content.Context import android.util.Log import androidx.core.content.edit import com.squareup.picasso.Picasso +import dagger.hilt.android.qualifiers.ApplicationContext import io.reactivex.Maybe import io.reactivex.Single import io.reactivex.schedulers.Schedulers import okhttp3.Credentials -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.models.* import openfoodfacts.github.scrachx.openfood.models.entities.additive.* import openfoodfacts.github.scrachx.openfood.models.entities.allergen.* @@ -57,6 +58,7 @@ import javax.inject.Singleton */ @Singleton class ProductRepository @Inject constructor( + @ApplicationContext private val context: Context, private val daoSession: DaoSession ) { @@ -66,7 +68,7 @@ class ProductRepository @Inject constructor( * @return The list of Labels. */ fun reloadLabelsFromServer() = - getTaxonomyData(Taxonomy.LABEL, this, true, daoSession.labelDao) + getTaxonomyData(Taxonomy.LABEL, this, true, daoSession.labelDao, context) fun loadLabels(lastModifiedDate: Long) = analysisDataApi.getLabels() .map { it.map() } @@ -81,7 +83,7 @@ class ProductRepository @Inject constructor( * @return The list of Tags. */ fun reloadTagsFromServer() = - getTaxonomyData(Taxonomy.TAGS, this, true, daoSession.tagDao) + getTaxonomyData(Taxonomy.TAGS, this, true, daoSession.tagDao, context) fun loadTags(lastModifiedDate: Long) = analysisDataApi.getTags() .map { it.tags } @@ -91,7 +93,7 @@ class ProductRepository @Inject constructor( } fun reloadInvalidBarcodesFromServer() = - getTaxonomyData(Taxonomy.INVALID_BARCODES, this, true, daoSession.invalidBarcodeDao) + getTaxonomyData(Taxonomy.INVALID_BARCODES, this, true, daoSession.invalidBarcodeDao, context) fun loadInvalidBarcodes(lastModifiedDate: Long) = analysisDataApi.getInvalidBarcodes() .map { strings -> strings.map { InvalidBarcode(it) } } @@ -107,10 +109,10 @@ class ProductRepository @Inject constructor( */ fun reloadAllergensFromServer(): Single> = // FIXME: this returns 404 - getTaxonomyData(Taxonomy.ALLERGEN, this, true, daoSession.allergenDao) + getTaxonomyData(Taxonomy.ALLERGEN, this, true, daoSession.allergenDao, context) fun getAllergens(): Single> = - getTaxonomyData(Taxonomy.ALLERGEN, this, false, daoSession.allergenDao) + getTaxonomyData(Taxonomy.ALLERGEN, this, false, daoSession.allergenDao, context) fun loadAllergens(lastModifiedDate: Long): Single> = analysisDataApi.getAllergens() .map { it.map() } @@ -125,7 +127,7 @@ class ProductRepository @Inject constructor( * @return The list of countries. */ fun reloadCountriesFromServer(): Single> = - getTaxonomyData(Taxonomy.COUNTRY, this, true, daoSession.countryDao) + getTaxonomyData(Taxonomy.COUNTRY, this, true, daoSession.countryDao, context) fun loadCountries(lastModifiedDate: Long): Single> = analysisDataApi.getCountries() .map { it.map() } @@ -140,9 +142,9 @@ class ProductRepository @Inject constructor( * @return The list of categories. */ fun reloadCategoriesFromServer() = - getTaxonomyData(Taxonomy.CATEGORY, this, true, daoSession.categoryDao) + getTaxonomyData(Taxonomy.CATEGORY, this, true, daoSession.categoryDao, context) - fun getCategories() = getTaxonomyData(Taxonomy.CATEGORY, this, false, daoSession.categoryDao) + fun getCategories() = getTaxonomyData(Taxonomy.CATEGORY, this, false, daoSession.categoryDao, context) fun loadCategories(lastModifiedDate: Long) = analysisDataApi.getCategories() .map { it.map() } @@ -167,7 +169,7 @@ class ProductRepository @Inject constructor( * @return The list of additives. */ fun reloadAdditivesFromServer() = - getTaxonomyData(Taxonomy.ADDITIVE, this, true, daoSession.additiveDao) + getTaxonomyData(Taxonomy.ADDITIVE, this, true, daoSession.additiveDao, context) fun loadAdditives(lastModifiedDate: Long) = analysisDataApi.getAdditives() .map { it.map() } @@ -187,7 +189,7 @@ class ProductRepository @Inject constructor( * @return The ingredients in the product. */ fun reloadIngredientsFromServer(): Single> = - getTaxonomyData(Taxonomy.INGREDIENT, this, true, daoSession.ingredientDao) + getTaxonomyData(Taxonomy.INGREDIENT, this, true, daoSession.ingredientDao, context) fun loadIngredients(lastModifiedDate: Long): Single> = analysisDataApi.getIngredients() .map { it.map() } @@ -202,7 +204,7 @@ class ProductRepository @Inject constructor( * @return The list of states. */ fun reloadStatesFromServer(): Single> = - getTaxonomyData(Taxonomy.STATES, this, true, daoSession.statesDao) + getTaxonomyData(Taxonomy.STATES, this, true, daoSession.statesDao, context) fun loadStates(lastModifiedDate: Long): Single> = analysisDataApi.getStates() .map { it.map() } @@ -217,7 +219,7 @@ class ProductRepository @Inject constructor( * @return The list of stores. */ fun reloadStoresFromServer(): Single> = - getTaxonomyData(Taxonomy.STORES, this, true, daoSession.storeDao) + getTaxonomyData(Taxonomy.STORES, this, true, daoSession.storeDao, context) fun loadStores(lastModifiedDate: Long): Single> = analysisDataApi.getStores() .map { it.map() } @@ -227,13 +229,13 @@ class ProductRepository @Inject constructor( } fun reloadBrandsFromServer(): Single> = - getTaxonomyData(Taxonomy.BRANDS, this, true, daoSession.brandDao) + getTaxonomyData(Taxonomy.BRANDS, this, true, daoSession.brandDao, context) fun loadBrands(lastModifiedDate: Long): Single> = analysisDataApi.getBrands() .map { it.map() } - .doOnSuccess{ + .doOnSuccess { saveBrands(it) - updateLastDownloadDateInSettings(Taxonomy.BRANDS,lastModifiedDate) + updateLastDownloadDateInSettings(Taxonomy.BRANDS, lastModifiedDate) } /** @@ -243,7 +245,7 @@ class ProductRepository @Inject constructor( * @param lastDownload Date of last update on Long format */ private fun updateLastDownloadDateInSettings(taxonomy: Taxonomy, lastDownload: Long) { - OFFApplication._instance.getSharedPreferences("prefs", 0) + context.getSharedPreferences("prefs", 0) .edit { putLong(taxonomy.lastDownloadTimeStampPreferenceId, lastDownload) } Log.i(LOG_TAG, "Set lastDownload of $taxonomy to $lastDownload") } @@ -582,7 +584,8 @@ class ProductRepository @Inject constructor( Taxonomy.COUNTRY, this, false, - daoSession.countryDao + daoSession.countryDao, + context ) fun getCountryByCC2OrWorld(cc2: String?) = getCountries().flatMapMaybe { countries -> @@ -727,8 +730,8 @@ class ProductRepository @Inject constructor( */ fun annotateInsight(insightId: String, annotation: AnnotationAnswer): Single { // if the user is logged in, send the auth, otherwise make it anonymous - val user = OFFApplication._instance.getLoginPreferences().getString("user", "")?.trim { it <= ' ' } ?: "" - val pass = OFFApplication._instance.getLoginPreferences().getString("pass", "")?.trim { it <= ' ' } ?: "" + val user = context.getLoginPreferences().getString("user", "")?.trim { it <= ' ' } ?: "" + val pass = context.getLoginPreferences().getString("pass", "")?.trim { it <= ' ' } ?: "" return if (user.isBlank() || pass.isBlank()) { robotoffApi.annotateInsight(insightId, annotation.result) @@ -743,7 +746,7 @@ class ProductRepository @Inject constructor( * @return The analysis tags in the product. */ fun reloadAnalysisTagsFromServer() = - getTaxonomyData(Taxonomy.ANALYSIS_TAGS, this, true, daoSession.analysisTagDao) + getTaxonomyData(Taxonomy.ANALYSIS_TAGS, this, true, daoSession.analysisTagDao, context) fun loadAnalysisTags(lastModifiedDate: Long) = analysisDataApi.getAnalysisTags() .map { it.map() } @@ -778,7 +781,7 @@ class ProductRepository @Inject constructor( } fun reloadAnalysisTagConfigsFromServer(): Single> = - getTaxonomyData(Taxonomy.ANALYSIS_TAG_CONFIG, this, true, daoSession.analysisTagConfigDao) + getTaxonomyData(Taxonomy.ANALYSIS_TAG_CONFIG, this, true, daoSession.analysisTagConfigDao, context) fun loadAnalysisTagConfigs(lastModifiedDate: Long): Single> = analysisDataApi.getAnalysisTagConfigs() .map { it.map() } diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt index fd8c891c34cc..c358875911a3 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt @@ -1,9 +1,9 @@ package openfoodfacts.github.scrachx.openfood.repositories +import android.content.Context import android.util.Log import io.reactivex.Single import openfoodfacts.github.scrachx.openfood.BuildConfig -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.utils.Utils import openfoodfacts.github.scrachx.openfood.utils.isEmpty import openfoodfacts.github.scrachx.openfood.utils.logDownload @@ -58,10 +58,11 @@ object TaxonomiesManager { taxonomy: Taxonomy, repository: ProductRepository, checkUpdate: Boolean, - dao: AbstractDao + dao: AbstractDao, + context: Context ): Single> { // WARNING: Before "return" all code is executed on MAIN THREAD - val mSettings = OFFApplication._instance.getSharedPreferences("prefs", 0) + val mSettings = context.getSharedPreferences("prefs", 0) // First check if this taxonomy is to be loaded for this flavor, else return empty list val isTaxonomyActivated = mSettings.getBoolean(taxonomy.downloadActivatePreferencesId, false) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/InstallationUtils.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/InstallationUtils.kt index cae29e0eabc5..4170e305f6e4 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/InstallationUtils.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/InstallationUtils.kt @@ -2,68 +2,45 @@ package openfoodfacts.github.scrachx.openfood.utils import android.content.Context import android.util.Log -import org.jetbrains.annotations.Contract import java.io.File -import java.io.FileOutputStream import java.io.IOException -import java.io.RandomAccessFile import java.security.MessageDigest import java.security.NoSuchAlgorithmException import java.util.* object InstallationUtils { private const val KEY_INSTALLATION = "INSTALLATION" - private var sID: String? = null + private var id: String? = null @Synchronized - fun id(context: Context?): String? { + fun id(context: Context?): String { if (context == null) return "(no id)" - if (sID.isNullOrEmpty()) { - val installation = File(context.filesDir, KEY_INSTALLATION) - try { - if (!installation.exists()) { - writeInstallationFile(installation) - } - sID = readInstallationFile(installation) - } catch (e: Exception) { - throw RuntimeException(e) + if (id.isNullOrEmpty()) { + val installFile = File(context.filesDir, KEY_INSTALLATION) + if (!installFile.exists()) { + writeInstallationFile(installFile) } + id = installFile.readText() } - return sID - } - - @Contract("_ -> new") - @Throws(IOException::class) - private fun readInstallationFile(installation: File): String { - RandomAccessFile(installation, "r").use { file -> - val bytes = ByteArray(file.length().toInt()) - file.readFully(bytes) - return String(bytes) - } + return id as String } @Throws(IOException::class) private fun writeInstallationFile(installation: File) { - FileOutputStream(installation).use { out -> - var id = UUID.randomUUID().toString() - val random = Random() //NO-SONAR ok here - random.setSeed(1000) - id += random.nextInt() - id = getHashedString(id) - out.write(id.toByteArray()) - } + var id = UUID.randomUUID().toString() + id += Random().apply { setSeed(1000) }.nextInt() + id = getHashedString(id) + installation.writeText(id) } private fun getHashedString(str: String) = try { // Create MD5 Hash - val messageDigest = MessageDigest.getInstance("MD5").apply { - update(str.toByteArray()) - }.digest() + val digest = MessageDigest.getInstance("MD5").digest(str.toByteArray()) // Create Hex String StringBuilder().also { - messageDigest.forEach { b -> it.append(Integer.toHexString(0xFF and b.toInt())) } + digest.forEach { b -> it.append(Integer.toHexString(0xFF and b.toInt())) } }.toString() } catch (e: NoSuchAlgorithmException) { Log.e(InstallationUtils::class.simpleName, "getHashedString $str", e) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PhotoReceiverHandler.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PhotoReceiverHandler.kt index 9b9fcba61cfa..0278facfafbd 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PhotoReceiverHandler.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PhotoReceiverHandler.kt @@ -19,7 +19,9 @@ import java.io.File /** * A class for handling photo receiver */ -class PhotoReceiverHandler(private val photoReceiver: (File) -> Unit) { +class PhotoReceiverHandler( + private val photoReceiver: (File) -> Unit +) { fun onActivityResult(fragment: Fragment?, requestCode: Int, resultCode: Int, data: Intent?) = onActivityResult(null, fragment, requestCode, resultCode, data) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/Utils.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/Utils.kt index 76fe66d6ceb5..02732f70cd92 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/Utils.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/Utils.kt @@ -54,7 +54,6 @@ import okhttp3.* import okhttp3.logging.HttpLoggingInterceptor import openfoodfacts.github.scrachx.openfood.BuildConfig import openfoodfacts.github.scrachx.openfood.R -import openfoodfacts.github.scrachx.openfood.app.OFFApplication import openfoodfacts.github.scrachx.openfood.features.LoginActivity import openfoodfacts.github.scrachx.openfood.features.scan.ContinuousScanActivity import openfoodfacts.github.scrachx.openfood.features.search.ProductSearchActivity.Companion.start @@ -157,9 +156,6 @@ object Utils { fun getRoundNumber(value: Float, locale: Locale = Locale.getDefault()) = getRoundNumber(value.toString(), locale) fun getRoundNumber(value: Double, locale: Locale = Locale.getDefault()) = getRoundNumber(value.toString(), locale) - @Deprecated("Use hilt.") - val daoSession get() = OFFApplication._daoSession - /** * Schedules job to download when network is available */ @@ -409,12 +405,10 @@ fun getModifierNonDefault(modifier: String) = if (modifier != DEFAULT_MODIFIER) private val LOG_TAG = Utils::class.simpleName!! /** - * @param context The context * @return Returns the version name of the app */ -fun getVersionName(context: Context): String = try { - val pInfo = context.packageManager.getPackageInfo(context.packageName, 0) - pInfo.versionName +fun Context.getVersionName(): String = try { + packageManager.getPackageInfo(packageName, 0).versionName } catch (e: PackageManager.NameNotFoundException) { Log.e(LOG_TAG, "getVersionName", e) "(version unknown)" @@ -425,12 +419,12 @@ fun getVersionName(context: Context): String = try { fun ViewGroup.getViewsByType(typeClass: Class): List { val result = mutableListOf() - children.forEach { child -> - if (child is ViewGroup) { - result.addAll(child.getViewsByType(typeClass)) + children.forEach { view -> + if (view is ViewGroup) { + result += view.getViewsByType(typeClass) } - if (typeClass.isInstance(child)) { - result += typeClass.cast(child) + if (typeClass.isInstance(view)) { + result += typeClass.cast(view) } } return result diff --git a/app/src/playstore/java/openfoodfacts/github/scrachx/openfood/features/scan/ContinuousScanActivity.kt b/app/src/playstore/java/openfoodfacts/github/scrachx/openfood/features/scan/ContinuousScanActivity.kt index 458712b5582a..468716f9406e 100644 --- a/app/src/playstore/java/openfoodfacts/github/scrachx/openfood/features/scan/ContinuousScanActivity.kt +++ b/app/src/playstore/java/openfoodfacts/github/scrachx/openfood/features/scan/ContinuousScanActivity.kt @@ -78,6 +78,7 @@ import openfoodfacts.github.scrachx.openfood.features.product.view.ingredients_a import openfoodfacts.github.scrachx.openfood.features.product.view.summary.AbstractSummaryProductPresenter import openfoodfacts.github.scrachx.openfood.features.product.view.summary.IngredientAnalysisTagsAdapter import openfoodfacts.github.scrachx.openfood.features.product.view.summary.SummaryProductPresenter +import openfoodfacts.github.scrachx.openfood.models.DaoSession import openfoodfacts.github.scrachx.openfood.models.InvalidBarcodeDao import openfoodfacts.github.scrachx.openfood.models.Product import openfoodfacts.github.scrachx.openfood.models.entities.OfflineSavedProduct @@ -91,7 +92,6 @@ import openfoodfacts.github.scrachx.openfood.network.OpenFoodAPIClient import openfoodfacts.github.scrachx.openfood.repositories.ProductRepository import openfoodfacts.github.scrachx.openfood.scanner.BarcodeProcessor import openfoodfacts.github.scrachx.openfood.utils.* -import openfoodfacts.github.scrachx.openfood.utils.Utils.daoSession import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import java.io.IOException @@ -115,6 +115,9 @@ class ContinuousScanActivity : AppCompatActivity() { @Inject lateinit var client: OpenFoodAPIClient + @Inject + lateinit var daoSession: DaoSession + @Inject lateinit var offlineProductService: OfflineProductService