mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +01:00
Added progress updater in UploadService to show upload progress in no… (#3156)
* added progress updater in UploadService to show upload progress in notification * formatting changes
This commit is contained in:
parent
41789980c7
commit
f13a4d4da7
3 changed files with 116 additions and 43 deletions
|
|
@ -0,0 +1,86 @@
|
||||||
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okio.Buffer;
|
||||||
|
import okio.BufferedSink;
|
||||||
|
import okio.ForwardingSink;
|
||||||
|
import okio.Okio;
|
||||||
|
import okio.Sink;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates an OkHttp request body to count the number of bytes written when writing it. Can
|
||||||
|
* decorate any request body, but is most useful for tracking the upload progress of large multipart
|
||||||
|
* requests.
|
||||||
|
*
|
||||||
|
* @author Ashish Kumar
|
||||||
|
*/
|
||||||
|
public class CountingRequestBody extends RequestBody {
|
||||||
|
|
||||||
|
protected RequestBody delegate;
|
||||||
|
protected Listener listener;
|
||||||
|
|
||||||
|
protected CountingSink countingSink;
|
||||||
|
|
||||||
|
public CountingRequestBody(RequestBody delegate, Listener listener) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaType contentType() {
|
||||||
|
return delegate.contentType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long contentLength() {
|
||||||
|
try {
|
||||||
|
return delegate.contentLength();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(BufferedSink sink) throws IOException {
|
||||||
|
|
||||||
|
countingSink = new CountingSink(sink);
|
||||||
|
BufferedSink bufferedSink = Okio.buffer(countingSink);
|
||||||
|
|
||||||
|
delegate.writeTo(bufferedSink);
|
||||||
|
|
||||||
|
bufferedSink.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final class CountingSink extends ForwardingSink {
|
||||||
|
|
||||||
|
private long bytesWritten = 0;
|
||||||
|
|
||||||
|
public CountingSink(Sink delegate) {
|
||||||
|
super(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Buffer source, long byteCount) throws IOException {
|
||||||
|
super.write(source, byteCount);
|
||||||
|
|
||||||
|
bytesWritten += byteCount;
|
||||||
|
listener.onRequestProgress(bytesWritten, contentLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be triggered when write progresses
|
||||||
|
* @param bytesWritten
|
||||||
|
* @param contentLength
|
||||||
|
*/
|
||||||
|
void onRequestProgress(long bytesWritten, long contentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,20 @@
|
||||||
package fr.free.nrw.commons.upload;
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import org.wikipedia.csrf.CsrfTokenClient;
|
import fr.free.nrw.commons.upload.UploadService.NotificationUpdateProgressListener;
|
||||||
|
import io.reactivex.Observable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.MultipartBody;
|
import okhttp3.MultipartBody;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
|
import org.wikipedia.csrf.CsrfTokenClient;
|
||||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UploadClient {
|
public class UploadClient {
|
||||||
|
|
@ -31,11 +28,16 @@ public class UploadClient {
|
||||||
this.csrfTokenClient = csrfTokenClient;
|
this.csrfTokenClient = csrfTokenClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file) {
|
Observable<UploadResult> uploadFileToStash(Context context, String filename, File file,
|
||||||
RequestBody requestFile = RequestBody
|
NotificationUpdateProgressListener notificationUpdater) {
|
||||||
|
RequestBody requestBody = RequestBody
|
||||||
.create(MediaType.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath()))), file);
|
.create(MediaType.parse(FileUtils.getMimeType(context, Uri.parse(file.getPath()))), file);
|
||||||
|
|
||||||
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, requestFile);
|
CountingRequestBody countingRequestBody = new CountingRequestBody(requestBody,
|
||||||
|
(bytesWritten, contentLength) -> notificationUpdater
|
||||||
|
.onProgress(bytesWritten, contentLength));
|
||||||
|
|
||||||
|
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", filename, countingRequestBody);
|
||||||
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
|
RequestBody fileNameRequestBody = RequestBody.create(okhttp3.MultipartBody.FORM, filename);
|
||||||
RequestBody tokenRequestBody;
|
RequestBody tokenRequestBody;
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,8 @@ import android.content.Intent;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.HandlerService;
|
import fr.free.nrw.commons.HandlerService;
|
||||||
|
|
@ -40,6 +25,13 @@ import fr.free.nrw.commons.utils.CommonsDateUtil;
|
||||||
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import javax.inject.Inject;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class UploadService extends HandlerService<Contribution> {
|
public class UploadService extends HandlerService<Contribution> {
|
||||||
|
|
@ -80,7 +72,7 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
super("UploadService");
|
super("UploadService");
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
|
protected class NotificationUpdateProgressListener implements MediaWikiApi.ProgressListener {
|
||||||
|
|
||||||
String notificationTag;
|
String notificationTag;
|
||||||
boolean notificationTitleChanged;
|
boolean notificationTitleChanged;
|
||||||
|
|
@ -202,29 +194,20 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private void uploadContribution(Contribution contribution) {
|
private void uploadContribution(Contribution contribution) {
|
||||||
InputStream fileInputStream;
|
|
||||||
Uri localUri = contribution.getLocalUri();
|
Uri localUri = contribution.getLocalUri();
|
||||||
if (localUri == null || localUri.getPath() == null) {
|
if (localUri == null || localUri.getPath() == null) {
|
||||||
Timber.d("localUri/path is null");
|
Timber.d("localUri/path is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String notificationTag = localUri.toString();
|
String notificationTag = localUri.toString();
|
||||||
File file1;
|
File localFile = new File(localUri.getPath());
|
||||||
try {
|
|
||||||
file1 = new File(localUri.getPath());
|
|
||||||
fileInputStream = new FileInputStream(file1);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Timber.d("File not found");
|
|
||||||
Toast fileNotFound = Toast.makeText(this, R.string.upload_failed, Toast.LENGTH_LONG);
|
|
||||||
fileNotFound.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Timber.d("Before execution!");
|
Timber.d("Before execution!");
|
||||||
curNotification.setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle()))
|
curNotification.setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle()))
|
||||||
.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload))
|
.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload))
|
||||||
.setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
|
.setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
|
||||||
notificationManager.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
|
notificationManager
|
||||||
|
.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
|
||||||
|
|
||||||
String filename = contribution.getFilename();
|
String filename = contribution.getFilename();
|
||||||
|
|
||||||
|
|
@ -235,7 +218,9 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Observable.fromCallable(() -> "Temp_" + contribution.hashCode() + filename)
|
Observable.fromCallable(() -> "Temp_" + contribution.hashCode() + filename)
|
||||||
.flatMap(stashFilename -> uploadClient.uploadFileToStash(getApplicationContext(), stashFilename, file1))
|
.flatMap(stashFilename -> uploadClient
|
||||||
|
.uploadFileToStash(getApplicationContext(), stashFilename, localFile,
|
||||||
|
notificationUpdater))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.doFinally(() -> {
|
.doFinally(() -> {
|
||||||
|
|
@ -250,7 +235,7 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatMap(uploadStash -> {
|
.flatMap(uploadStash -> {
|
||||||
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
|
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||||
|
|
||||||
Timber.d("Stash upload response 1 is %s", uploadStash.toString());
|
Timber.d("Stash upload response 1 is %s", uploadStash.toString());
|
||||||
|
|
||||||
|
|
@ -293,7 +278,7 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
}
|
}
|
||||||
}, throwable -> {
|
}, throwable -> {
|
||||||
Timber.w(throwable, "Exception during upload");
|
Timber.w(throwable, "Exception during upload");
|
||||||
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
|
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||||
showFailedNotification(contribution);
|
showFailedNotification(contribution);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue