diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 780535cb7f4a..47817e9319a5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -133,7 +133,7 @@ - val htmlBody: String = try { - response.body()!!.string() - } catch (e: IOException) { - Log.e(LOG_TAG, "I/O Exception while checking user saved credentials.", e) - return@subscribe - } - if (LoginActivity.isHtmlNotValid(htmlBody)) { - Log.w(LOG_TAG, "Cannot validate login, deleting saved credentials and asking the user to log back in.") - settings.edit { - putString("user", "") - putString("pass", "") - } - MaterialDialog.Builder(requireActivity()).let { - it.title(R.string.alert_dialog_warning_title) - it.content(R.string.alert_dialog_warning_msg_user) - it.positiveText(R.string.txtOk) - it.onPositive { _, _ -> loginLauncher.launch(Unit) } - it.show() - } - + lifecycleScope.launch(Dispatchers.IO) { + val response = try { + productsApi.signIn(login, password, "Sign-in") + } catch (err: Throwable) { + Log.e(LOG_TAG, "Cannot check user credentials.", err) + null + } ?: return@launch + + val htmlBody: String = try { + response.body()!!.string() + } catch (e: IOException) { + Log.e(LOG_TAG, "I/O Exception while checking user saved credentials.", e) + return@launch + } + if (LoginActivity.isHtmlNotValid(htmlBody)) { + Log.w(LOG_TAG, "Cannot validate login, deleting saved credentials and asking the user to log back in.") + settings.edit { + putString("user", "") + putString("pass", "") + } + withContext(Dispatchers.Main) { + MaterialDialog.Builder(requireActivity()).let { + it.title(R.string.alert_dialog_warning_title) + it.content(R.string.alert_dialog_warning_msg_user) + it.positiveText(R.string.txtOk) + it.onPositive { _, _ -> loginLauncher.launch(Unit) } + it.show() } - }.addTo(disp) + } + } + } } override fun onResume() { @@ -161,21 +171,21 @@ class HomeFragment : NavigationBaseFragment() { Log.d(LOG_TAG, "Refreshing total product count...") productsApi.getTotalProductCount(getUserAgent()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe { setProductCount(oldCount) } - .doOnError { - setProductCount(oldCount) - Log.e(LOG_TAG, "Could not retrieve product count from server.", it) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe { setProductCount(oldCount) } + .doOnError { + setProductCount(oldCount) + Log.e(LOG_TAG, "Could not retrieve product count from server.", it) + } + .subscribe { resp -> + val totalProductCount = resp.count.toInt() + Log.d(LOG_TAG, "Refreshed total product count. There are $totalProductCount products on the database.") + setProductCount(totalProductCount) + sharedPrefs.edit { + putInt(PRODUCT_COUNT_KEY, totalProductCount) + apply() } - .subscribe { resp -> - val totalProductCount = resp.count.toInt() - Log.d(LOG_TAG, "Refreshed total product count. There are $totalProductCount products on the database.") - setProductCount(totalProductCount) - sharedPrefs.edit { - putInt(PRODUCT_COUNT_KEY, totalProductCount) - apply() - } - }.addTo(disp) + }.addTo(disp) } /** @@ -196,28 +206,28 @@ class HomeFragment : NavigationBaseFragment() { */ private fun refreshTagLine() { productsApi.getTagline(getUserAgent()) - .subscribeOn(Schedulers.io()) // io for network - .observeOn(AndroidSchedulers.mainThread()) // Move to main thread for UI changes - .doOnError { Log.w(LOG_TAG, "Could not retrieve tag-line from server.", it) } - .subscribe { tagLines -> - val appLanguage = localeManager.getLanguage() - var isLanguageFound = false - var isExactLanguageFound = false - tagLines.forEach { tag -> - if (!isExactLanguageFound && (tag.language == appLanguage || tag.language.contains(appLanguage))) { - isExactLanguageFound = tag.language == appLanguage - taglineURL = tag.tagLine.url - binding.tvTagLine.text = tag.tagLine.message - isLanguageFound = true - } + .subscribeOn(Schedulers.io()) // io for network + .observeOn(AndroidSchedulers.mainThread()) // Move to main thread for UI changes + .doOnError { Log.w(LOG_TAG, "Could not retrieve tag-line from server.", it) } + .subscribe { tagLines -> + val appLanguage = localeManager.getLanguage() + var isLanguageFound = false + var isExactLanguageFound = false + tagLines.forEach { tag -> + if (!isExactLanguageFound && (tag.language == appLanguage || tag.language.contains(appLanguage))) { + isExactLanguageFound = tag.language == appLanguage + taglineURL = tag.tagLine.url + binding.tvTagLine.text = tag.tagLine.message + isLanguageFound = true } - if (!isLanguageFound) { - taglineURL = tagLines.last().tagLine.url - binding.tvTagLine.text = tagLines.last().tagLine.message - } - binding.tvTagLine.visibility = View.VISIBLE } - .addTo(disp) + if (!isLanguageFound) { + taglineURL = tagLines.last().tagLine.url + binding.tvTagLine.text = tagLines.last().tagLine.message + } + binding.tvTagLine.visibility = View.VISIBLE + } + .addTo(disp) } companion object { diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/ImagesManageActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/ImagesManageActivity.kt index 1ba63c08a59e..d126a2a0618c 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/ImagesManageActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/ImagesManageActivity.kt @@ -46,6 +46,7 @@ import io.reactivex.rxkotlin.addTo import openfoodfacts.github.scrachx.openfood.R import openfoodfacts.github.scrachx.openfood.databinding.ActivityFullScreenImageBinding import openfoodfacts.github.scrachx.openfood.features.adapters.LanguageDataAdapter +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity import openfoodfacts.github.scrachx.openfood.features.shared.BaseActivity import openfoodfacts.github.scrachx.openfood.images.* import openfoodfacts.github.scrachx.openfood.models.LanguageData diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/MainActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/MainActivity.kt index cb916f7e1ff9..7d8958b43340 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/MainActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/MainActivity.kt @@ -77,7 +77,6 @@ import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabActivityHelper import openfoodfacts.github.scrachx.openfood.customtabs.CustomTabsHelper import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback import openfoodfacts.github.scrachx.openfood.databinding.ActivityMainBinding -import openfoodfacts.github.scrachx.openfood.features.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.adapters.PhotosAdapter import openfoodfacts.github.scrachx.openfood.features.additives.AdditiveListActivity import openfoodfacts.github.scrachx.openfood.features.allergensalert.AllergensAlertFragment @@ -86,6 +85,8 @@ import openfoodfacts.github.scrachx.openfood.features.changelog.ChangelogDialog import openfoodfacts.github.scrachx.openfood.features.compare.ProductCompareActivity import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.installBottomNavigation import openfoodfacts.github.scrachx.openfood.features.listeners.CommonBottomListenerInstaller.selectNavigationItem +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity import openfoodfacts.github.scrachx.openfood.features.productlists.ProductListsActivity import openfoodfacts.github.scrachx.openfood.features.scan.ContinuousScanActivity diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/LoginActivity.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/login/LoginActivity.kt similarity index 59% rename from app/src/main/java/openfoodfacts/github/scrachx/openfood/features/LoginActivity.kt rename to app/src/main/java/openfoodfacts/github/scrachx/openfood/features/login/LoginActivity.kt index 91e4e4687f3f..0b209f258ed2 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/LoginActivity.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/login/LoginActivity.kt @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package openfoodfacts.github.scrachx.openfood.features +package openfoodfacts.github.scrachx.openfood.features.login import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo -import android.net.Uri import android.os.Bundle import android.util.Log import android.view.MenuItem @@ -27,14 +26,15 @@ import android.widget.Toast import androidx.activity.result.contract.ActivityResultContract import androidx.core.content.ContextCompat import androidx.core.content.edit -import com.afollestad.materialdialogs.MaterialDialog +import androidx.core.net.toUri +import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.addTo -import okhttp3.ResponseBody +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF import openfoodfacts.github.scrachx.openfood.AppFlavors.isFlavors import openfoodfacts.github.scrachx.openfood.BuildConfig @@ -49,7 +49,6 @@ import openfoodfacts.github.scrachx.openfood.features.shared.BaseActivity import openfoodfacts.github.scrachx.openfood.network.services.ProductsAPI import openfoodfacts.github.scrachx.openfood.utils.Utils import openfoodfacts.github.scrachx.openfood.utils.getLoginPreferences -import retrofit2.Response import java.io.IOException import java.net.HttpCookie import javax.inject.Inject @@ -69,12 +68,9 @@ class LoginActivity : BaseActivity() { @Inject lateinit var matomoAnalytics: MatomoAnalytics - private lateinit var customTabActivityHelper: CustomTabActivityHelper - - private val disp = CompositeDisposable() - - private var userLoginUri: Uri? = null - private var resetPasswordUri: Uri? = null + private val customTabActivityHelper: CustomTabActivityHelper by lazy { CustomTabActivityHelper() } + private val userLoginUri by lazy { "${getString(R.string.website)}cgi/user.pl".toUri() } + private val resetPasswordUri by lazy { "${getString(R.string.website)}cgi/reset_password.pl".toUri() } override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { android.R.id.home -> { @@ -107,61 +103,68 @@ class LoginActivity : BaseActivity() { // End checks val snackbar = Snackbar.make(binding.loginLinearlayout, R.string.toast_retrieving, LENGTH_LONG) - .apply { show() } + .apply { show() } binding.btnLogin.isClickable = false - productsApi.signIn(login, password, "Sign-in") - .observeOn(AndroidSchedulers.mainThread()) // We need to modify view - .doOnError { - Toast.makeText(this, this.getString(R.string.errorWeb), Toast.LENGTH_LONG).show() - Log.e(this::class.simpleName, "onFailure", it) + lifecycleScope.launch(Dispatchers.Main) { + val response = withContext(Dispatchers.IO) { + try { + productsApi.signIn(login, password, "Sign-in") + + } catch (err: Throwable) { + Toast.makeText(this@LoginActivity, this@LoginActivity.getString(R.string.errorWeb), Toast.LENGTH_LONG).show() + Log.e(this::class.simpleName, "onFailure", err) + null } - .subscribe { response: Response -> - if (!response.isSuccessful) { - Toast.makeText(this@LoginActivity, R.string.errorWeb, Toast.LENGTH_LONG).show() - return@subscribe - } - val htmlNoParsed = try { - response.body()?.string() - } catch (e: IOException) { - Log.e("LOGIN", "Unable to parse the login response page", e) - return@subscribe - } - val pref = this@LoginActivity.getSharedPreferences("login", 0) - if (isHtmlNotValid(htmlNoParsed)) { - Snackbar.make(binding.loginLinearlayout, R.string.errorLogin, LENGTH_LONG).show() - binding.passInput.setText("") - binding.txtInfoLogin.setTextColor(ContextCompat.getColor(this, R.color.red)) - binding.txtInfoLogin.setText(R.string.txtInfoLoginNo) - snackbar.dismiss() - } else { - // store the user session id (user_session and user_id) - for (httpCookie in HttpCookie.parse(response.headers()["set-cookie"])) { - // Example format of set-cookie: session=user_session&S0MeR@nD0MSECRETk3Y&user_id&testuser; domain=.openfoodfacts.org; path=/ - if (BuildConfig.HOST.contains(httpCookie.domain) && httpCookie.path == "/") { - val cookieValues = httpCookie.value.split("&") - var i = 0 - while (i < cookieValues.size) { - pref.edit { putString(cookieValues[i], cookieValues[++i]) } - i++ - } - break - } - } - Snackbar.make(binding.loginLinearlayout, R.string.connection, LENGTH_LONG).show() - pref.edit { - putString("user", login) - putString("pass", password) + } ?: return@launch + + if (!response.isSuccessful) { + Toast.makeText(this@LoginActivity, R.string.errorWeb, Toast.LENGTH_LONG).show() + return@launch + } + val htmlNoParsed = withContext(Dispatchers.IO) { + try { + response.body()?.string() + } catch (e: IOException) { + Log.e("LOGIN", "Unable to parse the login response page", e) + null + } + } ?: return@launch + val pref = this@LoginActivity.getSharedPreferences("login", 0) + if (isHtmlNotValid(htmlNoParsed)) { + Snackbar.make(binding.loginLinearlayout, R.string.errorLogin, LENGTH_LONG).show() + binding.passInput.setText("") + binding.txtInfoLogin.setTextColor(ContextCompat.getColor(this@LoginActivity, R.color.red)) + binding.txtInfoLogin.setText(R.string.txtInfoLoginNo) + snackbar.dismiss() + } else { + // store the user session id (user_session and user_id) + for (httpCookie in HttpCookie.parse(response.headers()["set-cookie"])) { + // Example format of set-cookie: session=user_session&S0MeR@nD0MSECRETk3Y&user_id&testuser; domain=.openfoodfacts.org; path=/ + if (BuildConfig.HOST.contains(httpCookie.domain) && httpCookie.path == "/") { + val cookieValues = httpCookie.value.split("&") + var i = 0 + while (i < cookieValues.size) { + pref.edit { putString(cookieValues[i], cookieValues[++i]) } + i++ } - binding.txtInfoLogin.setTextColor(ContextCompat.getColor(this, R.color.green_500)) - binding.txtInfoLogin.setText(R.string.txtInfoLoginOk) + break + } + } + Snackbar.make(binding.loginLinearlayout, R.string.connection, LENGTH_LONG).show() + pref.edit { + putString("user", login) + putString("pass", password) + } + binding.txtInfoLogin.setTextColor(ContextCompat.getColor(this@LoginActivity, R.color.green_500)) + binding.txtInfoLogin.setText(R.string.txtInfoLoginOk) - matomoAnalytics.trackEvent(AnalyticsEvent.UserLogin) + matomoAnalytics.trackEvent(AnalyticsEvent.UserLogin) - setResult(RESULT_OK) - finish() - } - }.addTo(disp) + setResult(RESULT_OK) + finish() + } + } binding.btnLogin.isClickable = true } @@ -187,38 +190,32 @@ class LoginActivity : BaseActivity() { supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.title = getString(R.string.txtSignIn) - userLoginUri = Uri.parse(getString(R.string.website) + "cgi/user.pl") - resetPasswordUri = Uri.parse(getString(R.string.website) + "cgi/reset_password.pl") - - // prefetch the uri - customTabActivityHelper = CustomTabActivityHelper() + // Prefetch the uri customTabActivityHelper.setConnectionCallback( - onConnected = { binding.btnCreateAccount.isEnabled = true }, - onDisconnected = { binding.btnCreateAccount.isEnabled = false } + onConnected = { binding.btnCreateAccount.isEnabled = true }, + onDisconnected = { binding.btnCreateAccount.isEnabled = false } ) customTabActivityHelper.mayLaunchUrl(userLoginUri, null, null) binding.btnCreateAccount.isEnabled = true val loginS = getLoginPreferences().getString(resources.getString(R.string.user), resources.getString(R.string.txt_anonymous)) if (loginS == resources.getString(R.string.user)) { - MaterialDialog.Builder(this).apply { - title(R.string.log_in) - content(R.string.login_true) - neutralText(R.string.ok_button) - onNeutral { _, _ -> finish() } - show() - } + MaterialAlertDialogBuilder(this).apply { + setTitle(R.string.log_in) + setMessage(R.string.login_true) + setNeutralButton(R.string.ok_button) { _, _ -> finish() } + }.show() } } private fun doRegister() { - val customTabsIntent = CustomTabsHelper.getCustomTabsIntent(baseContext, customTabActivityHelper.session) - CustomTabActivityHelper.openCustomTab(this, customTabsIntent, userLoginUri!!, WebViewFallback()) + val customTabsIntent = CustomTabsHelper.getCustomTabsIntent(this, customTabActivityHelper.session) + CustomTabActivityHelper.openCustomTab(this, customTabsIntent, userLoginUri, WebViewFallback()) } private fun doForgotPassword() { - val customTabsIntent = CustomTabsHelper.getCustomTabsIntent(baseContext, customTabActivityHelper.session) - CustomTabActivityHelper.openCustomTab(this, customTabsIntent, resetPasswordUri!!, WebViewFallback()) + val customTabsIntent = CustomTabsHelper.getCustomTabsIntent(this, customTabActivityHelper.session) + CustomTabActivityHelper.openCustomTab(this, customTabsIntent, resetPasswordUri, WebViewFallback()) } override fun onStart() { @@ -233,7 +230,6 @@ class LoginActivity : BaseActivity() { } override fun onDestroy() { - disp.dispose() customTabActivityHelper.connectionCallback = null _binding = null super.onDestroy() 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 3a0ba355070c..f00a508fa85b 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 @@ -26,6 +26,7 @@ import android.view.MenuItem import android.view.View import android.widget.Toast import androidx.activity.result.contract.ActivityResultContract +import androidx.lifecycle.lifecycleScope import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import com.afollestad.materialdialogs.MaterialDialog @@ -35,6 +36,10 @@ 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 okhttp3.RequestBody import openfoodfacts.github.scrachx.openfood.AppFlavors.OBF import openfoodfacts.github.scrachx.openfood.AppFlavors.OFF @@ -398,65 +403,75 @@ class ProductEditActivity : BaseActivity() { // Attribute the upload to the connected user addLoginPasswordInfo(imgMap) - savePhoto(imgMap, image, position, ocr) + + lifecycleScope.launch { savePhoto(imgMap, image, position, ocr) } + } - private fun savePhoto(imgMap: Map, image: ProductImage, position: Int, performOCR: Boolean) { - productsApi.saveImage(imgMap) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe { showImageProgress(position) } - .doOnError { - // A network error happened - if (it is IOException) { - hideImageProgress(position, false, getString(R.string.no_internet_connection)) - Log.e(LOGGER_TAG, it.message!!) - if (image.imageField === ProductImageField.OTHER) { - daoSession.toUploadProductDao.insertOrReplace( - ToUploadProduct( - image.barcode, - image.filePath, - image.imageField.toString() - ) + private suspend fun savePhoto( + imgMap: Map, + image: ProductImage, + position: Int, + performOCR: Boolean + ) = withContext(Dispatchers.IO) { + showImageProgress(position) + val jsonNode = try { + productsApi.saveImage(imgMap).await() + } catch (err: Throwable) { + // A network error happened + if (err is IOException) { + + hideImageProgress(position, getString(R.string.no_internet_connection)) + + Log.e(LOGGER_TAG, err.message!!) + if (image.imageField === ProductImageField.OTHER) { + daoSession.toUploadProductDao.insertOrReplace( + ToUploadProduct( + image.barcode, + image.filePath, + image.imageField.toString() ) - } - } else { - hideImageProgress(position, true, it.message ?: "Empty error.") - Log.i(this::class.simpleName, it.message ?: "Empty error.") - Toast.makeText(this, it.message, Toast.LENGTH_SHORT).show() + ) + } + } else { + Log.i(this::class.simpleName, err.message ?: "Empty error.") + withContext(Dispatchers.Main) { + hideImageProgress(position, err.message ?: "Empty error.", true) + Toast.makeText(this@ProductEditActivity, err.message, Toast.LENGTH_SHORT).show() } } - .subscribe { jsonNode -> - val status = jsonNode["status"].asText() - if (status == "status not ok") { - val error = jsonNode["error"].asText() - val alreadySent = error == "This picture has already been sent." - if (alreadySent && performOCR) { - hideImageProgress(position, false, getString(R.string.image_uploaded_successfully)) - performOCR(image.barcode, "ingredients_${getProductLanguageForEdition()}") - } else { - hideImageProgress(position, true, error) - } - } else { - when { - image.imageField === ProductImageField.FRONT -> { - imageFrontUploaded = true - } - image.imageField === ProductImageField.INGREDIENTS -> { - imageIngredientsUploaded = true - } - image.imageField === ProductImageField.NUTRITION -> { - imageNutritionFactsUploaded = true - } - } - hideImageProgress(position, false, getString(R.string.image_uploaded_successfully)) - val imageField = jsonNode["imagefield"].asText() - val imgId = jsonNode["image"]["imgid"].asText() - if (position != 3 && position != 4) { - // Not OTHER image - setPhoto(image, imageField, imgId, performOCR) - } + return@withContext + } + val status = jsonNode["status"].asText() + if (status == "status not ok") { + val error = jsonNode["error"].asText() + val alreadySent = error == "This picture has already been sent." + if (alreadySent && performOCR) { + hideImageProgress(position, getString(R.string.image_uploaded_successfully)) + performOCR(image.barcode, "ingredients_${getProductLanguageForEdition()}") + } else { + hideImageProgress(position, error, true) + } + } else { + when { + image.imageField === ProductImageField.FRONT -> { + imageFrontUploaded = true } - }.addTo(disp) + image.imageField === ProductImageField.INGREDIENTS -> { + imageIngredientsUploaded = true + } + image.imageField === ProductImageField.NUTRITION -> { + imageNutritionFactsUploaded = true + } + } + hideImageProgress(position, getString(R.string.image_uploaded_successfully)) + val imageField = jsonNode["imagefield"].asText() + val imgId = jsonNode["image"]["imgid"].asText() + if (position != 3 && position != 4) { + // Not OTHER image + setPhoto(image, imageField, imgId, performOCR) + } + } } private fun setPhoto(image: ProductImage, imageField: String, imgId: String, performOCR: Boolean) { @@ -514,17 +529,21 @@ class ProductEditActivity : BaseActivity() { .addTo(disp) } - private fun hideImageProgress(position: Int, errorUploading: Boolean, message: String) { + private suspend fun hideImageProgress( + position: Int, + msg: String, + error: Boolean = false + ) = withContext(Dispatchers.Main) { when (position) { - 0 -> editOverviewFragment.hideImageProgress(errorUploading, message) - 1 -> ingredientsFragment.hideImageProgress(errorUploading, message) - 2 -> nutritionFactsFragment.hideImageProgress(errorUploading, message) - 3 -> editOverviewFragment.hideOtherImageProgress(errorUploading, message) - 4 -> addProductPhotosFragment.hideImageProgress(errorUploading, message) + 0 -> editOverviewFragment.hideImageProgress(error, msg) + 1 -> ingredientsFragment.hideImageProgress(error, msg) + 2 -> nutritionFactsFragment.hideImageProgress(error, msg) + 3 -> editOverviewFragment.hideOtherImageProgress(error, msg) + 4 -> addProductPhotosFragment.hideImageProgress(error, msg) } } - private fun showImageProgress(position: Int) { + private suspend fun showImageProgress(position: Int) = withContext(Dispatchers.Main) { when (position) { 0 -> editOverviewFragment.showImageProgress() 1 -> ingredientsFragment.showImageProgress() diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt index 0875a7514f23..a41930f35330 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt @@ -894,8 +894,7 @@ class EditOverviewFragment : ProductEditFragment() { binding.imgFront.visibility = View.VISIBLE binding.btnEditImgFront.visibility = View.VISIBLE if (!errorInUploading) { - Picasso.get() - .load(photoFile!!) + picasso.load(photoFile!!) .resize(requireContext().dpsToPixel(50), requireContext().dpsToPixel(50)) .centerInside() .into(binding.imgFront) 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 6ab9a44e7fce..f425cd45e116 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 @@ -50,8 +50,8 @@ import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback import openfoodfacts.github.scrachx.openfood.databinding.FragmentIngredientsProductBinding import openfoodfacts.github.scrachx.openfood.features.FullScreenActivityOpener import openfoodfacts.github.scrachx.openfood.features.ImagesManageActivity -import openfoodfacts.github.scrachx.openfood.features.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.additives.AdditiveFragmentHelper.showAdditives +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.Companion.KEY_STATE import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.PerformOCRContract diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/nutrition/NutritionProductFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/nutrition/NutritionProductFragment.kt index 63ea24032fbc..9ba511fede9b 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/nutrition/NutritionProductFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/nutrition/NutritionProductFragment.kt @@ -57,8 +57,8 @@ import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback import openfoodfacts.github.scrachx.openfood.databinding.FragmentNutritionProductBinding import openfoodfacts.github.scrachx.openfood.features.FullScreenActivityOpener import openfoodfacts.github.scrachx.openfood.features.ImagesManageActivity -import openfoodfacts.github.scrachx.openfood.features.LoginActivity import openfoodfacts.github.scrachx.openfood.features.adapters.NutrimentsGridAdapter +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.Companion.KEY_STATE import openfoodfacts.github.scrachx.openfood.features.product.view.CalculateDetailsActivity diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosAdapter.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosAdapter.kt index ce18ddc98966..2b6e7e5da97c 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosAdapter.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosAdapter.kt @@ -23,7 +23,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.rx2.await import kotlinx.coroutines.withContext import openfoodfacts.github.scrachx.openfood.R -import openfoodfacts.github.scrachx.openfood.features.LoginActivity +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity import openfoodfacts.github.scrachx.openfood.images.* import openfoodfacts.github.scrachx.openfood.models.Product import openfoodfacts.github.scrachx.openfood.models.ProductImageField 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 aad3c07015d9..fe0a11be68e0 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 @@ -58,9 +58,9 @@ import openfoodfacts.github.scrachx.openfood.customtabs.WebViewFallback import openfoodfacts.github.scrachx.openfood.databinding.FragmentSummaryProductBinding import openfoodfacts.github.scrachx.openfood.features.FullScreenActivityOpener import openfoodfacts.github.scrachx.openfood.features.ImagesManageActivity -import openfoodfacts.github.scrachx.openfood.features.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.additives.AdditiveFragmentHelper.showAdditives import openfoodfacts.github.scrachx.openfood.features.compare.ProductCompareActivity.Companion.start +import openfoodfacts.github.scrachx.openfood.features.login.LoginActivity.Companion.LoginContract import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity import openfoodfacts.github.scrachx.openfood.features.product.edit.ProductEditActivity.Companion.KEY_STATE import openfoodfacts.github.scrachx.openfood.features.product.view.CategoryProductHelper diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt index f0f5d0a7fc84..bf540860c6e3 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt @@ -81,11 +81,11 @@ interface ProductsAPI { @FormUrlEncoded @POST("/cgi/session.pl") - fun signIn( - @Field(ApiFields.Keys.USER_ID) login: String?, - @Field(ApiFields.Keys.USER_PASS) password: String?, - @Field(".submit") submit: String? - ): Single> + suspend fun signIn( + @Field(ApiFields.Keys.USER_ID) login: String?, + @Field(ApiFields.Keys.USER_PASS) password: String?, + @Field(".submit") submit: String? + ): Response @GET("$API_P/product/{barcode}.json?fields=ingredients") fun getIngredientsByBarcode(@Path("barcode") barcode: String?): Single diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 74b843697906..2d64e71f9c67 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -11,7 +11,7 @@ android:id="@+id/login_linearlayout" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".features.LoginActivity"> + tools:context=".features.login.LoginActivity">