Moved auto-retry from the Main Activity to UploadProgressActivity

This commit is contained in:
Kanahia 2024-06-25 23:49:09 +05:30
parent 28ac25fdb0
commit 0b5fb6d7b0
11 changed files with 99 additions and 123 deletions

View file

@ -19,8 +19,5 @@ public class ContributionsContract {
Contribution getContributionsWithTitle(String uri); Contribution getContributionsWithTitle(String uri);
void deleteUpload(Contribution contribution);
void saveContribution(Contribution contribution);
} }
} }

View file

@ -114,7 +114,6 @@ public class ContributionsFragment
private static final String CONTRIBUTION_LIST_FRAGMENT_TAG = "ContributionListFragmentTag"; private static final String CONTRIBUTION_LIST_FRAGMENT_TAG = "ContributionListFragmentTag";
private MediaDetailPagerFragment mediaDetailPagerFragment; private MediaDetailPagerFragment mediaDetailPagerFragment;
static final String MEDIA_DETAIL_PAGER_FRAGMENT_TAG = "MediaDetailFragmentTag"; static final String MEDIA_DETAIL_PAGER_FRAGMENT_TAG = "MediaDetailFragmentTag";
private static final int MAX_RETRIES = 10;
public FragmentContributionsBinding binding; 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. * Notify the viewpager that number of items have changed.
*/ */

View file

@ -70,8 +70,6 @@ public class ContributionsListAdapter extends
public interface Callback { public interface Callback {
void retryUpload(Contribution contribution);
void openMediaDetail(int contribution, boolean isWikipediaPageExists); void openMediaDetail(int contribution, boolean isWikipediaPageExists);
void addImageToWikipedia(Contribution contribution); void addImageToWikipedia(Contribution contribution);

View file

@ -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 @Override
public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) { public void openMediaDetail(final int position, boolean isWikipediaButtonDisplayed) {
if (null != callback) {//Just being safe, ideally they won't be called when detached 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 notifyDataSetChanged();
void retryUpload(Contribution contribution);
void showDetail(int position, boolean isWikipediaButtonDisplayed); void showDetail(int position, boolean isWikipediaButtonDisplayed);
// Notify the viewpager that number of items have changed. // Notify the viewpager that number of items have changed.

View file

@ -47,30 +47,4 @@ public class ContributionsPresenter implements UserActionListener {
return repository.getContributionWithFileName(title); 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)));
}
} }

View file

@ -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() { public void toggleLimitedConnectionMode() {
defaultKvStore.putBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED, defaultKvStore.putBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED,
!defaultKvStore !defaultKvStore
@ -456,8 +441,6 @@ public class MainActivity extends BaseActivity
defaultKvStore.putBoolean("inAppCameraFirstRun", true); defaultKvStore.putBoolean("inAppCameraFirstRun", true);
WelcomeActivity.startYourself(this); WelcomeActivity.startYourself(this);
} }
retryAllFailedUploads();
} }
@Override @Override

View file

@ -7,6 +7,7 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.paging.PagedList import androidx.paging.PagedList
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import fr.free.nrw.commons.CommonsApplication 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.media.MediaClient
import fr.free.nrw.commons.profile.ProfileActivity import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.NetworkUtils
import fr.free.nrw.commons.utils.ViewUtil import fr.free.nrw.commons.utils.ViewUtil
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import timber.log.Timber
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@ -35,6 +38,7 @@ class PendingUploadsFragment : CommonsDaggerSupportFragment(), PendingUploadsCon
private var param2: String? = null private var param2: String? = null
private val ARG_PARAM1 = "param1" private val ARG_PARAM1 = "param1"
private val ARG_PARAM2 = "param2" private val ARG_PARAM2 = "param2"
private val MAX_RETRIES = 10
@Inject @Inject
lateinit var pendingUploadsPresenter: PendingUploadsPresenter 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() { fun resetProgressBar() {
totalUploads = 0 totalUploads = 0
} }

View file

@ -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)));
}
} }

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.upload package fr.free.nrw.commons.upload
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -7,8 +8,14 @@ import androidx.fragment.app.Fragment
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.ViewPagerAdapter 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.databinding.ActivityUploadProgressBinding
import fr.free.nrw.commons.theme.BaseActivity 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() { class UploadProgressActivity : BaseActivity() {
@ -18,6 +25,10 @@ class UploadProgressActivity : BaseActivity() {
private var failedUploadsFragment: FailedUploadsFragment? = null private var failedUploadsFragment: FailedUploadsFragment? = null
var viewPagerAdapter: ViewPagerAdapter? = null var viewPagerAdapter: ViewPagerAdapter? = null
var menu: Menu? = null var menu: Menu? = null
@Inject
lateinit var contributionDao: ContributionDao
val fragmentList: MutableList<Fragment> = ArrayList() val fragmentList: MutableList<Fragment> = ArrayList()
val titleList: MutableList<String> = ArrayList() val titleList: MutableList<String> = ArrayList()
var isPaused = true var isPaused = true
@ -158,5 +169,25 @@ class UploadProgressActivity : BaseActivity() {
pendingUploadsFragment!!.resetProgressBar() 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<Contribution?> ->
for (contribution in failedUploads) {
if (contribution != null) {
pendingUploadsFragment!!.retryUpload(contribution)
}
}
}
}
} }

View file

@ -151,13 +151,6 @@ class ContributionsListFragmentUnitTests {
fragment.openMediaDetail(0, true) fragment.openMediaDetail(0, true)
} }
@Test
@Throws(Exception::class)
fun testRetryUpload() {
Shadows.shadowOf(Looper.getMainLooper()).idle()
fragment.retryUpload(contribution)
}
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testOnViewStateRestored() { fun testOnViewStateRestored() {

View file

@ -57,17 +57,6 @@ class ContributionsPresenterTest {
liveData=MutableLiveData() liveData=MutableLiveData()
} }
/**
* Test presenter actions onDeleteContribution
*/
@Test
fun testDeleteContribution() {
whenever(repository.deleteContributionFromDB(ArgumentMatchers.any<Contribution>()))
.thenReturn(Completable.complete())
contributionsPresenter.deleteUpload(contribution)
verify(repository).deleteContributionFromDB(contribution)
}
/** /**
* Test fetch contribution with filename * Test fetch contribution with filename
*/ */