Skip to content

Commit 21edcb7

Browse files
authored
Retry failed uploads - commons-app#1556 Allow users to easily re-upload failed uploads... (commons-app#2112)
* Add cancel and retry buttons on layout contribution * Make sure your retry logic works * Add cancel method too * Add javadocs and remove debug logs * Remove two unused methods * Remove old and unused retry buttons as we do for their functions * Check internet connection before button function, since function requires internet connection * Remove unused variable * Display possible solution for badtoken error * Fix string
2 parents d960c14 + 47f10cb commit 21edcb7

File tree

19 files changed

+169
-85
lines changed

19 files changed

+169
-85
lines changed

app/src/main/java/fr/free/nrw/commons/contributions/ContributionViewHolder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package fr.free.nrw.commons.contributions;
22

33
import android.view.View;
4+
import android.widget.Button;
5+
import android.widget.ImageButton;
46
import android.widget.ProgressBar;
57
import android.widget.TextView;
68

@@ -13,12 +15,18 @@ class ContributionViewHolder {
1315
final TextView stateView;
1416
final TextView seqNumView;
1517
final ProgressBar progressView;
18+
final ImageButton retryButton;
19+
final ImageButton cancelButton;
20+
int position;
1621

1722
ContributionViewHolder(View parent) {
1823
imageView = parent.findViewById(R.id.contributionImage);
1924
titleView = parent.findViewById(R.id.contributionTitle);
2025
stateView = parent.findViewById(R.id.contributionState);
2126
seqNumView = parent.findViewById(R.id.contributionSequenceNumber);
2227
progressView = parent.findViewById(R.id.contributionProgress);
28+
retryButton = parent.findViewById(R.id.retryButton);
29+
cancelButton = parent.findViewById(R.id.cancelButton);
30+
position = 0;
2331
}
2432
}

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
332332

333333
contributionsListFragment.clearSyncMessage();
334334
notifyAndMigrateDataSetObservers();
335+
336+
((ContributionsListAdapter)contributionsListFragment.getAdapter()).setUploadService(uploadService);
335337
}
336338
}
337339

@@ -421,36 +423,6 @@ private void showDetail(int i) {
421423
mediaDetailPagerFragment.showImage(i);
422424
}
423425

424-
/**
425-
* Retry upload when it is failed
426-
* @param i position of upload which will be retried
427-
*/
428-
public void retryUpload(int i) {
429-
allContributions.moveToPosition(i);
430-
Contribution c = contributionDao.fromCursor(allContributions);
431-
if (c.getState() == STATE_FAILED) {
432-
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, c);
433-
Timber.d("Restarting for %s", c.toString());
434-
} else {
435-
Timber.d("Skipping re-upload for non-failed %s", c.toString());
436-
}
437-
}
438-
439-
/**
440-
* Delete a failed upload attempt
441-
* @param i position of upload attempt which will be deteled
442-
*/
443-
public void deleteUpload(int i) {
444-
allContributions.moveToPosition(i);
445-
Contribution c = contributionDao.fromCursor(allContributions);
446-
if (c.getState() == STATE_FAILED) {
447-
Timber.d("Deleting failed contrib %s", c.toString());
448-
contributionDao.delete(c);
449-
} else {
450-
Timber.d("Skipping deletion for non-failed contrib %s", c.toString());
451-
}
452-
}
453-
454426
@Override
455427
public void refreshSource() {
456428
getActivity().getSupportLoaderManager().restartLoader(0, null, this);

app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListAdapter.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,33 @@
33
import android.content.Context;
44
import android.database.Cursor;
55
import android.support.v4.widget.CursorAdapter;
6+
import android.util.Log;
67
import android.view.LayoutInflater;
78
import android.view.View;
89
import android.view.ViewGroup;
910

1011
import fr.free.nrw.commons.R;
12+
import fr.free.nrw.commons.upload.UploadService;
13+
import fr.free.nrw.commons.utils.NetworkUtils;
14+
import fr.free.nrw.commons.utils.ViewUtil;
15+
import timber.log.Timber;
16+
17+
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
1118

1219
class ContributionsListAdapter extends CursorAdapter {
1320

1421
private final ContributionDao contributionDao;
22+
private UploadService uploadService;
1523

1624
public ContributionsListAdapter(Context context, Cursor c, int flags, ContributionDao contributionDao) {
1725
super(context, c, flags);
1826
this.contributionDao = contributionDao;
1927
}
2028

29+
public void setUploadService( UploadService uploadService) {
30+
this.uploadService = uploadService;
31+
}
32+
2133
@Override
2234
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
2335
View parent = LayoutInflater.from(context)
@@ -36,21 +48,29 @@ public void bindView(View view, Context context, Cursor cursor) {
3648

3749
views.seqNumView.setText(String.valueOf(cursor.getPosition() + 1));
3850
views.seqNumView.setVisibility(View.VISIBLE);
51+
views.position = cursor.getPosition();
52+
3953

4054
switch (contribution.getState()) {
4155
case Contribution.STATE_COMPLETED:
4256
views.stateView.setVisibility(View.GONE);
4357
views.progressView.setVisibility(View.GONE);
58+
views.retryButton.setVisibility(View.GONE);
59+
views.cancelButton.setVisibility(View.GONE);
4460
views.stateView.setText("");
4561
break;
4662
case Contribution.STATE_QUEUED:
4763
views.stateView.setVisibility(View.VISIBLE);
4864
views.progressView.setVisibility(View.GONE);
4965
views.stateView.setText(R.string.contribution_state_queued);
66+
views.retryButton.setVisibility(View.GONE);
67+
views.cancelButton.setVisibility(View.GONE);
5068
break;
5169
case Contribution.STATE_IN_PROGRESS:
5270
views.stateView.setVisibility(View.GONE);
5371
views.progressView.setVisibility(View.VISIBLE);
72+
views.retryButton.setVisibility(View.GONE);
73+
views.cancelButton.setVisibility(View.GONE);
5474
long total = contribution.getDataLength();
5575
long transferred = contribution.getTransferred();
5676
if (transferred == 0 || transferred >= total) {
@@ -63,7 +83,63 @@ public void bindView(View view, Context context, Cursor cursor) {
6383
views.stateView.setVisibility(View.VISIBLE);
6484
views.stateView.setText(R.string.contribution_state_failed);
6585
views.progressView.setVisibility(View.GONE);
86+
views.retryButton.setVisibility(View.VISIBLE);
87+
views.cancelButton.setVisibility(View.VISIBLE);
88+
89+
views.retryButton.setOnClickListener(new View.OnClickListener() {
90+
@Override
91+
public void onClick(View view) {
92+
retryUpload(cursor);
93+
}
94+
});
95+
96+
views.cancelButton.setOnClickListener(new View.OnClickListener() {
97+
@Override
98+
public void onClick(View view) {
99+
deleteUpload(cursor);
100+
}
101+
});
102+
103+
66104
break;
67105
}
68106
}
107+
108+
/**
109+
* Retry upload when it is failed
110+
* @param cursor cursor will be retried
111+
*/
112+
public void retryUpload(Cursor cursor) {
113+
if (NetworkUtils.isInternetConnectionEstablished(mContext)) {
114+
Contribution c = contributionDao.fromCursor(cursor);
115+
if (c.getState() == STATE_FAILED) {
116+
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, c);
117+
Timber.d("Restarting for %s", c.toString());
118+
} else {
119+
Timber.d("Skipping re-upload for non-failed %s", c.toString());
120+
}
121+
} else {
122+
ViewUtil.showLongToast(mContext,R.string.this_function_needs_network_connection);
123+
}
124+
125+
}
126+
127+
/**
128+
* Delete a failed upload attempt
129+
* @param cursor cursor which will be deleted
130+
*/
131+
public void deleteUpload(Cursor cursor) {
132+
if (NetworkUtils.isInternetConnectionEstablished(mContext)) {
133+
Contribution c = contributionDao.fromCursor(cursor);
134+
if (c.getState() == STATE_FAILED) {
135+
Timber.d("Deleting failed contrib %s", c.toString());
136+
contributionDao.delete(c);
137+
} else {
138+
Timber.d("Skipping deletion for non-failed contrib %s", c.toString());
139+
}
140+
} else {
141+
ViewUtil.showLongToast(mContext,R.string.this_function_needs_network_connection);
142+
}
143+
144+
}
69145
}

app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
189189
// Set wallpaper
190190
setWallpaper(m);
191191
return true;
192-
case R.id.menu_retry_current_image:
193-
// Retry
194-
//((MainActivity) getActivity()).retryUpload(pager.getCurrentItem());
195-
getActivity().getSupportFragmentManager().popBackStack();
196-
return true;
197-
case R.id.menu_cancel_current_image:
198-
// todo: delete image
199-
//((MainActivity) getActivity()).deleteUpload(pager.getCurrentItem());
200-
getActivity().getSupportFragmentManager().popBackStack();
201-
return true;
202192
default:
203193
return super.onOptionsItemSelected(item);
204194
}
@@ -279,8 +269,6 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
279269
Media m = provider.getMediaAtPosition(pager.getCurrentItem());
280270
if (m != null) {
281271
// Enable default set of actions, then re-enable different set of actions only if it is a failed contrib
282-
menu.findItem(R.id.menu_retry_current_image).setEnabled(false).setVisible(false);
283-
menu.findItem(R.id.menu_cancel_current_image).setEnabled(false).setVisible(false);
284272
menu.findItem(R.id.menu_browser_current_image).setEnabled(true).setVisible(true);
285273
menu.findItem(R.id.menu_share_current_image).setEnabled(true).setVisible(true);
286274
menu.findItem(R.id.menu_download_current_image).setEnabled(true).setVisible(true);
@@ -297,17 +285,13 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
297285
Contribution c = (Contribution) m;
298286
switch (c.getState()) {
299287
case Contribution.STATE_FAILED:
300-
menu.findItem(R.id.menu_retry_current_image).setEnabled(true).setVisible(true);
301-
menu.findItem(R.id.menu_cancel_current_image).setEnabled(true).setVisible(true);
302288
menu.findItem(R.id.menu_browser_current_image).setEnabled(false).setVisible(false);
303289
menu.findItem(R.id.menu_share_current_image).setEnabled(false).setVisible(false);
304290
menu.findItem(R.id.menu_download_current_image).setEnabled(false).setVisible(false);
305291
menu.findItem(R.id.menu_bookmark_current_image).setEnabled(false).setVisible(false);
306292
break;
307293
case Contribution.STATE_IN_PROGRESS:
308294
case Contribution.STATE_QUEUED:
309-
menu.findItem(R.id.menu_retry_current_image).setEnabled(false).setVisible(false);
310-
menu.findItem(R.id.menu_cancel_current_image).setEnabled(false).setVisible(false);
311295
menu.findItem(R.id.menu_browser_current_image).setEnabled(false).setVisible(false);
312296
menu.findItem(R.id.menu_share_current_image).setEnabled(false).setVisible(false);
313297
menu.findItem(R.id.menu_download_current_image).setEnabled(false).setVisible(false);

app/src/main/java/fr/free/nrw/commons/mwapi/ApacheHttpClientMediaWikiApi.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import android.support.annotation.Nullable;
99
import android.support.annotation.VisibleForTesting;
1010
import android.text.TextUtils;
11+
import android.util.Log;
1112

1213
import com.google.gson.Gson;
1314

@@ -44,6 +45,7 @@
4445
import fr.free.nrw.commons.BuildConfig;
4546
import fr.free.nrw.commons.Media;
4647
import fr.free.nrw.commons.PageTitle;
48+
import fr.free.nrw.commons.R;
4749
import fr.free.nrw.commons.achievements.FeedbackResponse;
4850
import fr.free.nrw.commons.auth.AccountUtil;
4951
import fr.free.nrw.commons.category.CategoryImageUtils;
@@ -52,6 +54,7 @@
5254
import fr.free.nrw.commons.notification.NotificationUtils;
5355
import fr.free.nrw.commons.utils.ContributionUtils;
5456
import fr.free.nrw.commons.utils.DateUtils;
57+
import fr.free.nrw.commons.utils.ViewUtil;
5558
import in.yuvi.http.fluent.Http;
5659
import io.reactivex.Observable;
5760
import io.reactivex.Single;
@@ -81,6 +84,8 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
8184
private final String WIKIMEDIA_CAMPAIGNS_BASE_URL =
8285
"https://raw.githubusercontent.com/commons-app/campaigns/master/campaigns.json";
8386

87+
private final String ERROR_CODE_BAD_TOKEN = "badtoken";
88+
8489
public ApacheHttpClientMediaWikiApi(Context context,
8590
String apiURL,
8691
String wikidatApiURL,
@@ -901,6 +906,10 @@ public UploadResult uploadFile(String filename,
901906
if (!resultStatus.equals("Success")) {
902907
String errorCode = result.getString("/api/error/@code");
903908
Timber.e(errorCode);
909+
910+
if (errorCode.equals(ERROR_CODE_BAD_TOKEN)) {
911+
ViewUtil.showLongToast(context, R.string.bad_token_error_proposed_solution);
912+
}
904913
return new UploadResult(resultStatus, errorCode);
905914
} else {
906915
// If success we have to remove file from temp directory

app/src/main/java/fr/free/nrw/commons/upload/UploadService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.graphics.BitmapFactory;
1111
import android.os.Bundle;
1212
import android.support.v4.app.NotificationCompat;
13+
import android.util.Log;
1314
import android.webkit.MimeTypeMap;
1415
import android.widget.Toast;
1516

351 Bytes
Loading
449 Bytes
Loading
256 Bytes
Loading
279 Bytes
Loading

0 commit comments

Comments
 (0)