diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java index b8a2488b2..439780332 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContract.java @@ -19,8 +19,5 @@ public class ContributionsContract { Contribution getContributionsWithTitle(String uri); - void deleteUpload(Contribution contribution); - - void saveContribution(Contribution contribution); } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 76c9ed1ef..a36aa5b87 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -114,7 +114,6 @@ public class ContributionsFragment private static final String CONTRIBUTION_LIST_FRAGMENT_TAG = "ContributionListFragmentTag"; private MediaDetailPagerFragment mediaDetailPagerFragment; static final String MEDIA_DETAIL_PAGER_FRAGMENT_TAG = "MediaDetailFragmentTag"; - private static final int MAX_RETRIES = 10; public FragmentContributionsBinding binding; @@ -676,53 +675,6 @@ public class ContributionsFragment } } - /** - * Restarts the upload process for a contribution - * - * @param contribution - */ - public void restartUpload(Contribution contribution) { - contribution.setState(Contribution.STATE_QUEUED); - contributionsPresenter.saveContribution(contribution); - Timber.d("Restarting for %s", contribution.toString()); - } - - /** - * Retry upload when it is failed - * - * @param contribution contribution to be retried - */ - @Override - public void retryUpload(Contribution contribution) { - if (NetworkUtils.isInternetConnectionEstablished(getContext())) { - if (contribution.getState() == STATE_PAUSED - || contribution.getState() == Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE) { - restartUpload(contribution); - } else if (contribution.getState() == STATE_FAILED) { - int retries = contribution.getRetries(); - // TODO: Improve UX. Additional details: https://github.com/commons-app/apps-android-commons/pull/5257#discussion_r1304662562 - /* Limit the number of retries for a failed upload - to handle cases like invalid filename as such uploads - will never be successful */ - if (retries < MAX_RETRIES) { - contribution.setRetries(retries + 1); - Timber.d("Retried uploading %s %d times", contribution.getMedia().getFilename(), - retries + 1); - restartUpload(contribution); - } else { - // TODO: Show the exact reason for failure - Toast.makeText(getContext(), - R.string.retry_limit_reached, Toast.LENGTH_SHORT).show(); - } - } else { - Timber.d("Skipping re-upload for non-failed %s", contribution.toString()); - } - } else { - ViewUtil.showLongToast(getContext(), R.string.this_function_needs_network_connection); - } - - } - /** * Notify the viewpager that number of items have changed. */ diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java index ba4317baf..3f9e8d541 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java @@ -70,8 +70,6 @@ public class ContributionsListAdapter extends public interface Callback { - void retryUpload(Contribution contribution); - void openMediaDetail(int contribution, boolean isWikipediaPageExists); void addImageToWikipedia(Contribution contribution); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index c86ecf190..1cca24c98 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -435,13 +435,6 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl } } - @Override - public void retryUpload(final Contribution contribution) { - if (null != callback) {//Just being safe, ideally they won't be called when detached - callback.retryUpload(contribution); - } - } - @Override public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) { if (null != callback) {//Just being safe, ideally they won't be called when detached @@ -517,8 +510,6 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl void notifyDataSetChanged(); - void retryUpload(Contribution contribution); - void showDetail(int position, boolean isWikipediaButtonDisplayed); // Notify the viewpager that number of items have changed. diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java index f676f193a..c77514756 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsPresenter.java @@ -47,30 +47,4 @@ public class ContributionsPresenter implements UserActionListener { return repository.getContributionWithFileName(title); } - /** - * Delete a failed contribution from the local db - * @param contribution - */ - @Override - public void deleteUpload(Contribution contribution) { - compositeDisposable.add(repository - .deleteContributionFromDB(contribution) - .subscribeOn(ioThreadScheduler) - .subscribe()); - } - - /** - * Update the contribution's state in the databse, upon completion, trigger the workmanager to - * process this contribution - * - * @param contribution - */ - @Override - public void saveContribution(Contribution contribution) { - compositeDisposable.add(repository - .save(contribution) - .subscribeOn(ioThreadScheduler) - .subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest( - view.getContext().getApplicationContext(), ExistingWorkPolicy.KEEP))); - } } diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java index 96b97971c..ba792c332 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java @@ -399,21 +399,6 @@ public class MainActivity extends BaseActivity } } - /** - * Retry all failed uploads as soon as the user returns to the app - */ - @SuppressLint("CheckResult") - private void retryAllFailedUploads() { - contributionDao. - getContribution(Collections.singletonList(Contribution.STATE_FAILED)) - .subscribeOn(Schedulers.io()) - .subscribe(failedUploads -> { - for (Contribution contribution: failedUploads) { - contributionsFragment.retryUpload(contribution); - } - }); - } - public void toggleLimitedConnectionMode() { defaultKvStore.putBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED, !defaultKvStore @@ -456,8 +441,6 @@ public class MainActivity extends BaseActivity defaultKvStore.putBoolean("inAppCameraFirstRun", true); WelcomeActivity.startYourself(this); } - - retryAllFailedUploads(); } @Override diff --git a/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsFragment.kt b/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsFragment.kt index 89e57ea2e..c42486d67 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsFragment.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager import fr.free.nrw.commons.CommonsApplication @@ -18,8 +19,10 @@ import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.profile.ProfileActivity import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog +import fr.free.nrw.commons.utils.NetworkUtils import fr.free.nrw.commons.utils.ViewUtil import org.apache.commons.lang3.StringUtils +import timber.log.Timber import java.util.Locale import javax.inject.Inject @@ -35,6 +38,7 @@ class PendingUploadsFragment : CommonsDaggerSupportFragment(), PendingUploadsCon private var param2: String? = null private val ARG_PARAM1 = "param1" private val ARG_PARAM2 = "param2" + private val MAX_RETRIES = 10 @Inject lateinit var pendingUploadsPresenter: PendingUploadsPresenter @@ -244,6 +248,56 @@ class PendingUploadsFragment : CommonsDaggerSupportFragment(), PendingUploadsCon } } + /** + * Restarts the upload process for a contribution + * + * @param contribution + */ + fun restartUpload(contribution: Contribution) { + contribution.state = Contribution.STATE_QUEUED + pendingUploadsPresenter.saveContribution(contribution, this.requireContext().applicationContext) + Timber.d("Restarting for %s", contribution.toString()) + } + + /** + * Retry upload when it is failed + * + * @param contribution contribution to be retried + */ + fun retryUpload(contribution: Contribution) { + if (NetworkUtils.isInternetConnectionEstablished(context)) { + if (contribution.state == Contribution.STATE_PAUSED + || contribution.state == Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE + ) { + restartUpload(contribution) + } else if (contribution.state == Contribution.STATE_FAILED) { + val retries = contribution.retries + // TODO: Improve UX. Additional details: https://github.com/commons-app/apps-android-commons/pull/5257#discussion_r1304662562 + /* Limit the number of retries for a failed upload + to handle cases like invalid filename as such uploads + will never be successful */ + if (retries < MAX_RETRIES) { + contribution.retries = retries + 1 + Timber.d( + "Retried uploading %s %d times", contribution.media.filename, + retries + 1 + ) + restartUpload(contribution) + } else { + // TODO: Show the exact reason for failure + Toast.makeText( + context, + R.string.retry_limit_reached, Toast.LENGTH_SHORT + ).show() + } + } else { + Timber.d("Skipping re-upload for non-failed %s", contribution.toString()) + } + } else { + ViewUtil.showLongToast(context, R.string.this_function_needs_network_connection) + } + } + fun resetProgressBar() { totalUploads = 0 } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsPresenter.java b/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsPresenter.java index 3d0c7f953..3c5fa9689 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/PendingUploadsPresenter.java @@ -193,4 +193,18 @@ public class PendingUploadsPresenter implements UserActionListener { )); } + /** + * Update the contribution's state in the databse, upon completion, trigger the workmanager to + * process this contribution + * + * @param contribution + */ + public void saveContribution(Contribution contribution, Context context) { + compositeDisposable.add(repository + .save(contribution) + .subscribeOn(ioThreadScheduler) + .subscribe(() -> WorkRequestHelper.Companion.makeOneTimeWorkRequest( + context, ExistingWorkPolicy.KEEP))); + } + } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt index cc112c2f7..a44b619ef 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadProgressActivity.kt @@ -1,5 +1,6 @@ package fr.free.nrw.commons.upload +import android.annotation.SuppressLint import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -7,8 +8,14 @@ import androidx.fragment.app.Fragment import androidx.viewpager.widget.ViewPager import fr.free.nrw.commons.R import fr.free.nrw.commons.ViewPagerAdapter +import fr.free.nrw.commons.contributions.Contribution +import fr.free.nrw.commons.contributions.ContributionDao import fr.free.nrw.commons.databinding.ActivityUploadProgressBinding import fr.free.nrw.commons.theme.BaseActivity +import io.reactivex.functions.Consumer +import io.reactivex.schedulers.Schedulers +import timber.log.Timber +import javax.inject.Inject class UploadProgressActivity : BaseActivity() { @@ -18,6 +25,10 @@ class UploadProgressActivity : BaseActivity() { private var failedUploadsFragment: FailedUploadsFragment? = null var viewPagerAdapter: ViewPagerAdapter? = null var menu: Menu? = null + + @Inject + lateinit var contributionDao: ContributionDao + val fragmentList: MutableList = ArrayList() val titleList: MutableList = ArrayList() var isPaused = true @@ -158,5 +169,25 @@ class UploadProgressActivity : BaseActivity() { pendingUploadsFragment!!.resetProgressBar() } + override fun onResume() { + super.onResume() + retryAllFailedUploads() + } + + /** + * Retry all failed uploads as soon as the user returns to the app + */ + @SuppressLint("CheckResult") + private fun retryAllFailedUploads() { + contributionDao.getContribution(listOf(Contribution.STATE_FAILED)) + .subscribeOn(Schedulers.io()) + .subscribe { failedUploads: List -> + for (contribution in failedUploads) { + if (contribution != null) { + pendingUploadsFragment!!.retryUpload(contribution) + } + } + } + } } diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsListFragmentUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsListFragmentUnitTests.kt index 74a68e63c..00c0b12dc 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsListFragmentUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsListFragmentUnitTests.kt @@ -151,13 +151,6 @@ class ContributionsListFragmentUnitTests { fragment.openMediaDetail(0, true) } - @Test - @Throws(Exception::class) - fun testRetryUpload() { - Shadows.shadowOf(Looper.getMainLooper()).idle() - fragment.retryUpload(contribution) - } - @Test @Throws(Exception::class) fun testOnViewStateRestored() { diff --git a/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsPresenterTest.kt b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsPresenterTest.kt index 45c7d89d2..9c673720c 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsPresenterTest.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/contributions/ContributionsPresenterTest.kt @@ -57,17 +57,6 @@ class ContributionsPresenterTest { liveData=MutableLiveData() } - /** - * Test presenter actions onDeleteContribution - */ - @Test - fun testDeleteContribution() { - whenever(repository.deleteContributionFromDB(ArgumentMatchers.any())) - .thenReturn(Completable.complete()) - contributionsPresenter.deleteUpload(contribution) - verify(repository).deleteContributionFromDB(contribution) - } - /** * Test fetch contribution with filename */