mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Moved auto-retry from the Main Activity to UploadProgressActivity
This commit is contained in:
parent
28ac25fdb0
commit
0b5fb6d7b0
11 changed files with 99 additions and 123 deletions
|
|
@ -19,8 +19,5 @@ public class ContributionsContract {
|
||||||
|
|
||||||
Contribution getContributionsWithTitle(String uri);
|
Contribution getContributionsWithTitle(String uri);
|
||||||
|
|
||||||
void deleteUpload(Contribution contribution);
|
|
||||||
|
|
||||||
void saveContribution(Contribution contribution);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue