mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +01:00
* #3529 Captions/depictions are not saved to Commons - make copy of list of depictionEntityIds - uncomment editBaseDepictsProperty - refactor upload related classes * #3529 Captions/depictions are not saved to Commons - fix wrong ArrayList usage * #3529 Captions/depictions are not saved to Commons - fix test
This commit is contained in:
parent
587d97716a
commit
23b8c2e659
12 changed files with 360 additions and 504 deletions
|
|
@ -3,18 +3,12 @@ package fr.free.nrw.commons;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.PrimaryKey;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import fr.free.nrw.commons.utils.MediaDataExtractorUtil;
|
||||||
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
|
||||||
import org.wikipedia.gallery.ExtMetadata;
|
|
||||||
import org.wikipedia.gallery.ImageInfo;
|
|
||||||
import org.wikipedia.page.PageTitle;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -23,10 +17,11 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||||
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
import org.wikipedia.gallery.ExtMetadata;
|
||||||
import fr.free.nrw.commons.utils.MediaDataExtractorUtil;
|
import org.wikipedia.gallery.ImageInfo;
|
||||||
|
import org.wikipedia.page.PageTitle;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class Media implements Parcelable {
|
public class Media implements Parcelable {
|
||||||
|
|
@ -90,7 +85,7 @@ public class Media implements Parcelable {
|
||||||
* Ex: key = "en", value: "<caption in short in English>"
|
* Ex: key = "en", value: "<caption in short in English>"
|
||||||
* key = "de" , value: "<caption in german>"
|
* key = "de" , value: "<caption in german>"
|
||||||
*/
|
*/
|
||||||
public HashMap<String, String> captions;
|
public Map<String, String> captions;
|
||||||
public HashMap<String, String> tags = new HashMap<>();
|
public HashMap<String, String> tags = new HashMap<>();
|
||||||
@Nullable public LatLng coordinates;
|
@Nullable public LatLng coordinates;
|
||||||
|
|
||||||
|
|
@ -126,7 +121,7 @@ public class Media implements Parcelable {
|
||||||
* @param dateUploaded Media date uploaded
|
* @param dateUploaded Media date uploaded
|
||||||
* @param creator Media creator
|
* @param creator Media creator
|
||||||
*/
|
*/
|
||||||
public Media(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description,
|
public Media(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description,
|
||||||
long dataLength, Date dateCreated, Date dateUploaded, String creator) {
|
long dataLength, Date dateCreated, Date dateUploaded, String creator) {
|
||||||
this();
|
this();
|
||||||
this.localUri = localUri;
|
this.localUri = localUri;
|
||||||
|
|
@ -395,7 +390,7 @@ public class Media implements Parcelable {
|
||||||
*
|
*
|
||||||
* returns list of captions stored in hashmap
|
* returns list of captions stored in hashmap
|
||||||
*/
|
*/
|
||||||
public HashMap<String, String> getCaptions() {
|
public Map<String, String> getCaptions() {
|
||||||
return captions;
|
return captions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,25 @@
|
||||||
package fr.free.nrw.commons.contributions;
|
package fr.free.nrw.commons.contributions;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringDef;
|
import androidx.annotation.StringDef;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.Media;
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@Entity(tableName = "contribution")
|
@Entity(tableName = "contribution")
|
||||||
public class Contribution extends Media {
|
public class Contribution extends Media {
|
||||||
|
|
@ -83,7 +79,7 @@ public class Contribution extends Media {
|
||||||
|
|
||||||
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated,
|
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated,
|
||||||
int state, long dataLength, Date dateUploaded, long transferred,
|
int state, long dataLength, Date dateUploaded, long transferred,
|
||||||
String source, HashMap<String, String> captions, String description, String creator, boolean isMultiple,
|
String source, Map<String, String> captions, String description, String creator, boolean isMultiple,
|
||||||
int width, int height, String license) {
|
int width, int height, String license) {
|
||||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||||
this.contentUri = contentUri;
|
this.contentUri = contentUri;
|
||||||
|
|
@ -97,7 +93,7 @@ public class Contribution extends Media {
|
||||||
this.dateCreatedSource = "";
|
this.dateCreatedSource = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contribution(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description, long dataLength,
|
public Contribution(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description, long dataLength,
|
||||||
Date dateCreated, Date dateUploaded, String creator, String editSummary, ArrayList<String> depictionsEntityIds, String decimalCoords) {
|
Date dateCreated, Date dateUploaded, String creator, String editSummary, ArrayList<String> depictionsEntityIds, String decimalCoords) {
|
||||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||||
this.decimalCoords = decimalCoords;
|
this.decimalCoords = decimalCoords;
|
||||||
|
|
@ -106,7 +102,7 @@ public class Contribution extends Media {
|
||||||
this.depictionsEntityIds = depictionsEntityIds;
|
this.depictionsEntityIds = depictionsEntityIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contribution(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description, long dataLength,
|
public Contribution(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description, long dataLength,
|
||||||
Date dateCreated, Date dateUploaded, String creator, String editSummary, String decimalCoords, int state) {
|
Date dateCreated, Date dateUploaded, String creator, String editSummary, String decimalCoords, int state) {
|
||||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||||
this.decimalCoords = decimalCoords;
|
this.decimalCoords = decimalCoords;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,8 @@
|
||||||
package fr.free.nrw.commons.di;
|
package fr.free.nrw.commons.di;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
import org.wikipedia.csrf.CsrfTokenClient;
|
|
||||||
import org.wikipedia.dataclient.Service;
|
|
||||||
import org.wikipedia.dataclient.ServiceFactory;
|
|
||||||
import org.wikipedia.dataclient.WikiSite;
|
|
||||||
import org.wikipedia.json.GsonUtil;
|
|
||||||
import org.wikipedia.login.LoginClient;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
|
|
@ -32,14 +16,25 @@ import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||||
import fr.free.nrw.commons.mwapi.UserInterface;
|
import fr.free.nrw.commons.mwapi.UserInterface;
|
||||||
import fr.free.nrw.commons.review.ReviewInterface;
|
import fr.free.nrw.commons.review.ReviewInterface;
|
||||||
import fr.free.nrw.commons.upload.UploadInterface;
|
import fr.free.nrw.commons.upload.UploadInterface;
|
||||||
import fr.free.nrw.commons.wikidata.WikidataInterface;
|
|
||||||
import fr.free.nrw.commons.upload.WikiBaseInterface;
|
import fr.free.nrw.commons.upload.WikiBaseInterface;
|
||||||
import fr.free.nrw.commons.upload.depicts.DepictsInterface;
|
import fr.free.nrw.commons.upload.depicts.DepictsInterface;
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
||||||
|
import fr.free.nrw.commons.wikidata.WikidataInterface;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
import okhttp3.Cache;
|
import okhttp3.Cache;
|
||||||
import okhttp3.HttpUrl;
|
import okhttp3.HttpUrl;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||||
|
import org.wikipedia.csrf.CsrfTokenClient;
|
||||||
|
import org.wikipedia.dataclient.Service;
|
||||||
|
import org.wikipedia.dataclient.ServiceFactory;
|
||||||
|
import org.wikipedia.dataclient.WikiSite;
|
||||||
|
import org.wikipedia.json.GsonUtil;
|
||||||
|
import org.wikipedia.login.LoginClient;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
|
@ -76,7 +71,7 @@ public class NetworkingModule {
|
||||||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(message -> {
|
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(message -> {
|
||||||
Timber.tag("OkHttp").v(message);
|
Timber.tag("OkHttp").v(message);
|
||||||
});
|
});
|
||||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
httpLoggingInterceptor.level(BuildConfig.DEBUG ? Level.BODY: HttpLoggingInterceptor.Level.BASIC);
|
||||||
return httpLoggingInterceptor;
|
return httpLoggingInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,8 @@ import android.net.Uri;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.HandlerService;
|
import fr.free.nrw.commons.HandlerService;
|
||||||
|
import fr.free.nrw.commons.Media;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
|
|
@ -34,23 +25,26 @@ import io.reactivex.Single;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UploadController {
|
public class UploadController {
|
||||||
private UploadService uploadService;
|
private UploadService uploadService;
|
||||||
private SessionManager sessionManager;
|
private final SessionManager sessionManager;
|
||||||
private Context context;
|
private final Context context;
|
||||||
private JsonKvStore store;
|
private final JsonKvStore store;
|
||||||
|
|
||||||
public interface ContributionUploadProgress {
|
|
||||||
void onUploadStarted(Contribution contribution);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UploadController(SessionManager sessionManager,
|
public UploadController(final SessionManager sessionManager,
|
||||||
Context context,
|
final Context context,
|
||||||
JsonKvStore store) {
|
final JsonKvStore store) {
|
||||||
this.sessionManager = sessionManager;
|
this.sessionManager = sessionManager;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
|
@ -59,13 +53,13 @@ public class UploadController {
|
||||||
private boolean isUploadServiceConnected;
|
private boolean isUploadServiceConnected;
|
||||||
public ServiceConnection uploadServiceConnection = new ServiceConnection() {
|
public ServiceConnection uploadServiceConnection = new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(ComponentName componentName, IBinder binder) {
|
public void onServiceConnected(final ComponentName componentName, final IBinder binder) {
|
||||||
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder).getService();
|
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder).getService();
|
||||||
isUploadServiceConnected = true;
|
isUploadServiceConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected(ComponentName componentName) {
|
public void onServiceDisconnected(final ComponentName componentName) {
|
||||||
// this should never happen
|
// this should never happen
|
||||||
isUploadServiceConnected = false;
|
isUploadServiceConnected = false;
|
||||||
Timber.e(new RuntimeException("UploadService died but the rest of the process did not!"));
|
Timber.e(new RuntimeException("UploadService died but the rest of the process did not!"));
|
||||||
|
|
@ -76,7 +70,7 @@ public class UploadController {
|
||||||
* Prepares the upload service.
|
* Prepares the upload service.
|
||||||
*/
|
*/
|
||||||
public void prepareService() {
|
public void prepareService() {
|
||||||
Intent uploadServiceIntent = new Intent(context, UploadService.class);
|
final Intent uploadServiceIntent = new Intent(context, UploadService.class);
|
||||||
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
|
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
|
||||||
context.startService(uploadServiceIntent);
|
context.startService(uploadServiceIntent);
|
||||||
context.bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE);
|
context.bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
@ -96,28 +90,18 @@ public class UploadController {
|
||||||
*
|
*
|
||||||
* @param contribution the contribution object
|
* @param contribution the contribution object
|
||||||
*/
|
*/
|
||||||
public void startUpload(Contribution contribution) {
|
|
||||||
startUpload(contribution, c -> {});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new upload task.
|
|
||||||
*
|
|
||||||
* @param contribution the contribution object
|
|
||||||
* @param onComplete the progress tracker
|
|
||||||
*/
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) {
|
public void startUpload(final Contribution contribution) {
|
||||||
//Set creator, desc, and license
|
//Set creator, desc, and license
|
||||||
|
|
||||||
// If author name is enabled and set, use it
|
// If author name is enabled and set, use it
|
||||||
if (store.getBoolean("useAuthorName", false)) {
|
if (store.getBoolean("useAuthorName", false)) {
|
||||||
String authorName = store.getString("authorName", "");
|
final String authorName = store.getString("authorName", "");
|
||||||
contribution.setCreator(authorName);
|
contribution.setCreator(authorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextUtils.isEmpty(contribution.getCreator())) {
|
if (TextUtils.isEmpty(contribution.getCreator())) {
|
||||||
Account currentAccount = sessionManager.getCurrentAccount();
|
final Account currentAccount = sessionManager.getCurrentAccount();
|
||||||
if (currentAccount == null) {
|
if (currentAccount == null) {
|
||||||
Timber.d("Current account is null");
|
Timber.d("Current account is null");
|
||||||
ViewUtil.showLongToast(context, context.getString(R.string.user_not_logged_in));
|
ViewUtil.showLongToast(context, context.getString(R.string.user_not_logged_in));
|
||||||
|
|
@ -135,23 +119,23 @@ public class UploadController {
|
||||||
contribution.setCaption("");
|
contribution.setCaption("");
|
||||||
}
|
}
|
||||||
|
|
||||||
String license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
final String license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||||
contribution.setLicense(license);
|
contribution.setLicense(license);
|
||||||
|
|
||||||
uploadTask(contribution, onComplete);
|
uploadTask(contribution);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates the upload task
|
* Initiates the upload task
|
||||||
* @param contribution
|
* @param contribution
|
||||||
* @param onComplete
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Disposable uploadTask(Contribution contribution, ContributionUploadProgress onComplete) {
|
private Disposable uploadTask(final Contribution contribution) {
|
||||||
return Single.fromCallable(() -> makeUpload(contribution))
|
return Single.just(contribution)
|
||||||
|
.map(this::buildUpload)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(finalContribution -> onUploadCompleted(finalContribution, onComplete));
|
.subscribe(this::upload);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -159,71 +143,76 @@ public class UploadController {
|
||||||
* @param contribution
|
* @param contribution
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Contribution makeUpload(Contribution contribution) {
|
private Contribution buildUpload(final Contribution contribution) {
|
||||||
long length;
|
final ContentResolver contentResolver = context.getContentResolver();
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
|
contribution.setDataLength(resolveDataLength(contentResolver, contribution));
|
||||||
|
|
||||||
|
final String mimeType = resolveMimeType(contentResolver, contribution);
|
||||||
|
|
||||||
|
if (mimeType != null) {
|
||||||
|
Timber.d("MimeType is: %s", mimeType);
|
||||||
|
contribution.setTag("mimeType", mimeType);
|
||||||
|
if(mimeType.startsWith("image/") && contribution.getDateCreated() == null){
|
||||||
|
contribution.setDateCreated(resolveDateTakenOrNow(contentResolver, contribution));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contribution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveMimeType(final ContentResolver contentResolver, final Contribution contribution) {
|
||||||
|
final String mimeType = (String) contribution.getTag("mimeType");
|
||||||
|
if (mimeType == null || TextUtils.isEmpty(mimeType) || mimeType.endsWith("*")) {
|
||||||
|
return contentResolver.getType(contribution.getLocalUri());
|
||||||
|
}
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long resolveDataLength(final ContentResolver contentResolver, final Media contribution) {
|
||||||
try {
|
try {
|
||||||
if (contribution.getDataLength() <= 0) {
|
if (contribution.getDataLength() <= 0) {
|
||||||
Timber.d("UploadController/doInBackground, contribution.getLocalUri():%s", contribution.getLocalUri());
|
Timber.d("UploadController/doInBackground, contribution.getLocalUri():%s", contribution.getLocalUri());
|
||||||
AssetFileDescriptor assetFileDescriptor = contentResolver
|
final AssetFileDescriptor assetFileDescriptor = contentResolver
|
||||||
.openAssetFileDescriptor(Uri.fromFile(new File(contribution.getLocalUri().getPath())), "r");
|
.openAssetFileDescriptor(Uri.fromFile(new File(contribution.getLocalUri().getPath())), "r");
|
||||||
if (assetFileDescriptor != null) {
|
if (assetFileDescriptor != null) {
|
||||||
length = assetFileDescriptor.getLength();
|
final long length = assetFileDescriptor.getLength();
|
||||||
if (length == -1) {
|
return length != -1 ? length
|
||||||
// Let us find out the long way!
|
: countBytes(contentResolver.openInputStream(contribution.getLocalUri()));
|
||||||
length = countBytes(contentResolver
|
|
||||||
.openInputStream(contribution.getLocalUri()));
|
|
||||||
}
|
|
||||||
contribution.setDataLength(length);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException | NullPointerException | SecurityException e) {
|
} catch (final IOException | NullPointerException | SecurityException e) {
|
||||||
Timber.e(e, "Exception occurred while uploading image");
|
Timber.e(e, "Exception occurred while uploading image");
|
||||||
}
|
}
|
||||||
|
return contribution.getDataLength();
|
||||||
|
}
|
||||||
|
|
||||||
String mimeType = (String) contribution.getTag("mimeType");
|
private Date resolveDateTakenOrNow(final ContentResolver contentResolver, final Media contribution) {
|
||||||
boolean imagePrefix = false;
|
Timber.d("local uri %s", contribution.getLocalUri());
|
||||||
|
try(final Cursor cursor = dateTakenCursor(contentResolver, contribution)) {
|
||||||
if (mimeType == null || TextUtils.isEmpty(mimeType) || mimeType.endsWith("*")) {
|
|
||||||
mimeType = contentResolver.getType(contribution.getLocalUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mimeType != null) {
|
|
||||||
contribution.setTag("mimeType", mimeType);
|
|
||||||
imagePrefix = mimeType.startsWith("image/");
|
|
||||||
Timber.d("MimeType is: %s", mimeType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imagePrefix && contribution.getDateCreated() == null) {
|
|
||||||
Timber.d("local uri %s", contribution.getLocalUri());
|
|
||||||
Cursor cursor = contentResolver.query(contribution.getLocalUri(),
|
|
||||||
new String[]{MediaStore.Images.ImageColumns.DATE_TAKEN}, null, null, null);
|
|
||||||
if (cursor != null && cursor.getCount() != 0 && cursor.getColumnCount() != 0) {
|
if (cursor != null && cursor.getCount() != 0 && cursor.getColumnCount() != 0) {
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
Date dateCreated = new Date(cursor.getLong(0));
|
final Date dateCreated = new Date(cursor.getLong(0));
|
||||||
Date epochStart = new Date(0);
|
if (dateCreated.after(new Date(0))) {
|
||||||
if (dateCreated.equals(epochStart) || dateCreated.before(epochStart)) {
|
return dateCreated;
|
||||||
// If date is incorrect (1st second of unix time) then set it to the current date
|
|
||||||
dateCreated = new Date();
|
|
||||||
}
|
}
|
||||||
contribution.setDateCreated(dateCreated);
|
|
||||||
cursor.close();
|
|
||||||
} else {
|
|
||||||
contribution.setDateCreated(new Date());
|
|
||||||
}
|
}
|
||||||
|
return new Date();
|
||||||
}
|
}
|
||||||
return contribution;
|
}
|
||||||
|
|
||||||
|
private Cursor dateTakenCursor(final ContentResolver contentResolver, final Media contribution) {
|
||||||
|
return contentResolver.query(contribution.getLocalUri(),
|
||||||
|
new String[]{MediaStore.Images.ImageColumns.DATE_TAKEN}, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the contribution object is completely formed, the item is queued to the upload service
|
* When the contribution object is completely formed, the item is queued to the upload service
|
||||||
* @param contribution
|
* @param contribution
|
||||||
* @param onComplete
|
|
||||||
*/
|
*/
|
||||||
private void onUploadCompleted(Contribution contribution, ContributionUploadProgress onComplete) {
|
private void upload(final Contribution contribution) {
|
||||||
//Starts the upload. If commented out, user can proceed to next Fragment but upload doesn't happen
|
//Starts the upload. If commented out, user can proceed to next Fragment but upload doesn't happen
|
||||||
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, contribution);
|
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, contribution);
|
||||||
onComplete.onUploadStarted(contribution);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -234,9 +223,9 @@ public class UploadController {
|
||||||
* @return the number of bytes in {@code stream}
|
* @return the number of bytes in {@code stream}
|
||||||
* @throws IOException if an I/O error occurs
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
private long countBytes(InputStream stream) throws IOException {
|
private long countBytes(final InputStream stream) throws IOException {
|
||||||
long count = 0;
|
long count = 0;
|
||||||
BufferedInputStream bis = new BufferedInputStream(stream);
|
final BufferedInputStream bis = new BufferedInputStream(stream);
|
||||||
while (bis.read() != -1) {
|
while (bis.read() != -1) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
package fr.free.nrw.commons.upload;
|
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds a description of an item being uploaded by {@link UploadActivity}
|
|
||||||
*/
|
|
||||||
public class UploadMediaDetail {
|
|
||||||
|
|
||||||
private String languageCode;
|
|
||||||
private String descriptionText;
|
|
||||||
public String captionText;
|
|
||||||
private int selectedLanguageIndex = -1;
|
|
||||||
private boolean isManuallyAdded=false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formatting captions to the Wikibase format for sending labels
|
|
||||||
* @param uploadMediaDetails list of media Details
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static HashMap<String, String> formatCaptions(List<UploadMediaDetail> uploadMediaDetails) {
|
|
||||||
HashMap<String, String> caption = new HashMap<>();
|
|
||||||
for (UploadMediaDetail uploadMediaDetail : uploadMediaDetails) {
|
|
||||||
caption.put(uploadMediaDetail.getLanguageCode(),uploadMediaDetail.getCaptionText());
|
|
||||||
}
|
|
||||||
return caption;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCaptionText() {
|
|
||||||
return captionText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCaptionText(String captionText) {
|
|
||||||
this.captionText = captionText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The language code ie. "en" or "fr"
|
|
||||||
*/
|
|
||||||
String getLanguageCode() {
|
|
||||||
return languageCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param languageCode The language code ie. "en" or "fr"
|
|
||||||
*/
|
|
||||||
public void setLanguageCode(String languageCode) {
|
|
||||||
this.languageCode = languageCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getDescriptionText() {
|
|
||||||
return descriptionText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDescriptionText(String descriptionText) {
|
|
||||||
this.descriptionText = descriptionText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the index of the language selected in a spinner with {@link SpinnerLanguagesAdapter}
|
|
||||||
*/
|
|
||||||
int getSelectedLanguageIndex() {
|
|
||||||
return selectedLanguageIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param selectedLanguageIndex the index of the language selected in a spinner with {@link SpinnerLanguagesAdapter}
|
|
||||||
*/
|
|
||||||
void setSelectedLanguageIndex(int selectedLanguageIndex) {
|
|
||||||
this.selectedLanguageIndex = selectedLanguageIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* returns if the description was added manually (by the user, or we have added it programaticallly)
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isManuallyAdded() {
|
|
||||||
return isManuallyAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sets to true if the description was manually added by the user
|
|
||||||
* @param manuallyAdded
|
|
||||||
*/
|
|
||||||
public void setManuallyAdded(boolean manuallyAdded) {
|
|
||||||
isManuallyAdded = manuallyAdded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats the list of descriptions into the format Commons requires for uploads.
|
|
||||||
*
|
|
||||||
* @param descriptions the list of descriptions, description is ignored if text is null.
|
|
||||||
* @return a string with the pattern of {{en|1=descriptionText}}
|
|
||||||
*/
|
|
||||||
static String formatList(List<UploadMediaDetail> descriptions) {
|
|
||||||
StringBuilder descListString = new StringBuilder();
|
|
||||||
for (UploadMediaDetail description : descriptions) {
|
|
||||||
if (!description.isEmpty()) {
|
|
||||||
String individualDescription = String.format("{{%s|1=%s}}", description.getLanguageCode(),
|
|
||||||
description.getDescriptionText());
|
|
||||||
descListString.append(individualDescription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return descListString.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return descriptionText == null || descriptionText.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package fr.free.nrw.commons.upload
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.nearby.Place
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds a description of an item being uploaded by [UploadActivity]
|
||||||
|
*/
|
||||||
|
data class UploadMediaDetail constructor(
|
||||||
|
/**
|
||||||
|
* @return The language code ie. "en" or "fr"
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param languageCode The language code ie. "en" or "fr"
|
||||||
|
*/
|
||||||
|
var languageCode: String? = null,
|
||||||
|
var descriptionText: String = "",
|
||||||
|
var captionText: String = ""
|
||||||
|
) {
|
||||||
|
constructor(place: Place) : this(
|
||||||
|
Locale.getDefault().language,
|
||||||
|
place.longDescription,
|
||||||
|
place.name
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* @return the index of the language selected in a spinner with [SpinnerLanguagesAdapter]
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @param selectedLanguageIndex the index of the language selected in a spinner with [SpinnerLanguagesAdapter]
|
||||||
|
*/
|
||||||
|
var selectedLanguageIndex: Int = -1
|
||||||
|
/**
|
||||||
|
* returns if the description was added manually (by the user, or we have added it programaticallly)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* sets to true if the description was manually added by the user
|
||||||
|
* @param manuallyAdded
|
||||||
|
*/
|
||||||
|
var isManuallyAdded: Boolean = false
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Formatting captions to the Wikibase format for sending labels
|
||||||
|
* @param uploadMediaDetails list of media Details
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun formatCaptions(uploadMediaDetails: List<UploadMediaDetail>) =
|
||||||
|
uploadMediaDetails.associate { it.languageCode to it.captionText }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the list of descriptions into the format Commons requires for uploads.
|
||||||
|
*
|
||||||
|
* @param descriptions the list of descriptions, description is ignored if text is null.
|
||||||
|
* @return a string with the pattern of {{en|1=descriptionText}}
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun formatList(descriptions: List<UploadMediaDetail>) =
|
||||||
|
descriptions.joinToString {
|
||||||
|
if (it.descriptionText.isNotEmpty())
|
||||||
|
"{{${it.languageCode}|1=${it.descriptionText}}}"
|
||||||
|
else
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,7 @@ package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.Editable;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
@ -107,36 +105,11 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
public void init(int position) {
|
public void init(int position) {
|
||||||
UploadMediaDetail uploadMediaDetail = uploadMediaDetails.get(position);
|
UploadMediaDetail uploadMediaDetail = uploadMediaDetails.get(position);
|
||||||
Timber.d("UploadMediaDetail is " + uploadMediaDetail);
|
Timber.d("UploadMediaDetail is " + uploadMediaDetail);
|
||||||
if (!TextUtils.isEmpty(uploadMediaDetail.getCaptionText())) {
|
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
||||||
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
||||||
} else {
|
|
||||||
captionItemEditText.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(uploadMediaDetail.getDescriptionText())) {
|
captionItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||||
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
value -> eventListener.onEvent(value.length() != 0)) );
|
||||||
} else {
|
|
||||||
descItemEditText.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
captionItemEditText.addTextChangedListener(new TextWatcher() {
|
|
||||||
@Override
|
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterTextChanged(Editable s) {
|
|
||||||
if (s.length() != 0) {
|
|
||||||
eventListener.onEvent(true);
|
|
||||||
} else eventListener.onEvent(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
captionItemEditText.setCompoundDrawablesWithIntrinsicBounds(null, null, getInfoIcon(),
|
captionItemEditText.setCompoundDrawablesWithIntrinsicBounds(null, null, getInfoIcon(),
|
||||||
|
|
@ -174,13 +147,11 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
||||||
}
|
}
|
||||||
|
|
||||||
captionItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
captionItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||||
captionText -> uploadMediaDetails.get(position)
|
captionText -> uploadMediaDetails.get(position).setCaptionText(captionText)));
|
||||||
.setCaptionText(captionText)));
|
|
||||||
initLanguageSpinner(position, uploadMediaDetail);
|
initLanguageSpinner(position, uploadMediaDetail);
|
||||||
|
|
||||||
descItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
descItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||||
descriptionText -> uploadMediaDetails.get(position)
|
descriptionText -> uploadMediaDetails.get(position).setDescriptionText(descriptionText)));
|
||||||
.setDescriptionText(descriptionText)));
|
|
||||||
initLanguageSpinner(position, uploadMediaDetail);
|
initLanguageSpinner(position, uploadMediaDetail);
|
||||||
|
|
||||||
//If the description was manually added by the user, it deserves focus, if not, let the user decide
|
//If the description was manually added by the user, it deserves focus, if not, let the user decide
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import androidx.annotation.Nullable;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
import fr.free.nrw.commons.contributions.Contribution;
|
import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper;
|
|
||||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
|
|
@ -18,15 +17,17 @@ import io.reactivex.Single;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.subjects.BehaviorSubject;
|
import io.reactivex.subjects.BehaviorSubject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
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 org.jetbrains.annotations.NotNull;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
|
|
@ -37,23 +38,23 @@ public class UploadModel {
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private String license;
|
private String license;
|
||||||
private final Map<String, String> licensesByName;
|
private final Map<String, String> licensesByName;
|
||||||
private List<UploadItem> items = new ArrayList<>();
|
private final List<UploadItem> items = new ArrayList<>();
|
||||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
private SessionManager sessionManager;
|
private final SessionManager sessionManager;
|
||||||
private FileProcessor fileProcessor;
|
private final FileProcessor fileProcessor;
|
||||||
private final ImageProcessingService imageProcessingService;
|
private final ImageProcessingService imageProcessingService;
|
||||||
private List<String> selectedCategories;
|
private List<String> selectedCategories;
|
||||||
private ArrayList<String> selectedDepictions;
|
private ArrayList<String> selectedDepictions;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
UploadModel(@Named("licenses") List<String> licenses,
|
UploadModel(@Named("licenses") final List<String> licenses,
|
||||||
@Named("default_preferences") JsonKvStore store,
|
@Named("default_preferences") final JsonKvStore store,
|
||||||
@Named("licenses_by_name") Map<String, String> licensesByName,
|
@Named("licenses_by_name") final Map<String, String> licensesByName,
|
||||||
Context context,
|
final Context context,
|
||||||
SessionManager sessionManager,
|
final SessionManager sessionManager,
|
||||||
FileProcessor fileProcessor,
|
final FileProcessor fileProcessor,
|
||||||
ImageProcessingService imageProcessingService) {
|
final ImageProcessingService imageProcessingService) {
|
||||||
this.licenses = licenses;
|
this.licenses = licenses;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
this.license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||||
|
|
@ -80,31 +81,29 @@ public class UploadModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedCategories(List<String> selectedCategories) {
|
public void setSelectedCategories(List<String> selectedCategories) {
|
||||||
if (null == selectedCategories) {
|
this.selectedCategories = newListOf(selectedCategories);
|
||||||
selectedCategories = new ArrayList<>();
|
|
||||||
}
|
|
||||||
this.selectedCategories = selectedCategories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pre process a one item at a time
|
* pre process a one item at a time
|
||||||
*/
|
*/
|
||||||
public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile,
|
public Observable<UploadItem> preProcessImage(final UploadableFile uploadableFile,
|
||||||
Place place,
|
final Place place,
|
||||||
String source,
|
final String source,
|
||||||
SimilarImageInterface similarImageInterface) {
|
final SimilarImageInterface similarImageInterface) {
|
||||||
return Observable.just(getUploadItem(uploadableFile, place, source, similarImageInterface));
|
return Observable.just(
|
||||||
|
createAndAddUploadItem(uploadableFile, place, source, similarImageInterface));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Single<Integer> getImageQuality(UploadItem uploadItem) {
|
public Single<Integer> getImageQuality(final UploadItem uploadItem) {
|
||||||
return imageProcessingService.validateImage(uploadItem);
|
return imageProcessingService.validateImage(uploadItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UploadItem getUploadItem(UploadableFile uploadableFile,
|
private UploadItem createAndAddUploadItem(final UploadableFile uploadableFile,
|
||||||
Place place,
|
final Place place,
|
||||||
String source,
|
final String source,
|
||||||
SimilarImageInterface similarImageInterface) {
|
final SimilarImageInterface similarImageInterface) {
|
||||||
UploadableFile.DateTimeWithSource dateTimeWithSource = uploadableFile
|
final UploadableFile.DateTimeWithSource dateTimeWithSource = uploadableFile
|
||||||
.getFileCreatedDate(context);
|
.getFileCreatedDate(context);
|
||||||
long fileCreatedDate = -1;
|
long fileCreatedDate = -1;
|
||||||
String createdTimestampSource = "";
|
String createdTimestampSource = "";
|
||||||
|
|
@ -113,23 +112,15 @@ public class UploadModel {
|
||||||
createdTimestampSource = dateTimeWithSource.getSource();
|
createdTimestampSource = dateTimeWithSource.getSource();
|
||||||
}
|
}
|
||||||
Timber.d("File created date is %d", fileCreatedDate);
|
Timber.d("File created date is %d", fileCreatedDate);
|
||||||
ImageCoordinates imageCoordinates = fileProcessor
|
final ImageCoordinates imageCoordinates = fileProcessor
|
||||||
.processFileCoordinates(similarImageInterface, uploadableFile.getFilePath());
|
.processFileCoordinates(similarImageInterface, uploadableFile.getFilePath());
|
||||||
UploadItem uploadItem = new UploadItem(uploadableFile.getContentUri(),
|
final UploadItem uploadItem = new UploadItem(uploadableFile.getContentUri(),
|
||||||
Uri.parse(uploadableFile.getFilePath()),
|
Uri.parse(uploadableFile.getFilePath()),
|
||||||
uploadableFile.getMimeType(context), source, imageCoordinates, place, fileCreatedDate,
|
uploadableFile.getMimeType(context), source, imageCoordinates, place, fileCreatedDate,
|
||||||
createdTimestampSource);
|
createdTimestampSource);
|
||||||
if (place != null) {
|
if (place != null) {
|
||||||
uploadItem.title.setTitleText(place.name);
|
uploadItem.title.setTitleText(place.name);
|
||||||
if(uploadItem.uploadMediaDetails.isEmpty()) {
|
uploadItem.getUploadMediaDetails().set(0, new UploadMediaDetail(place));
|
||||||
uploadItem.uploadMediaDetails.add(new UploadMediaDetail());
|
|
||||||
}
|
|
||||||
uploadItem.uploadMediaDetails.get(0).setDescriptionText(place.getLongDescription());
|
|
||||||
uploadItem.uploadMediaDetails.get(0).setLanguageCode("en");
|
|
||||||
String languageCode = Locale.getDefault().getLanguage();
|
|
||||||
uploadItem.uploadMediaDetails.get(0).setDescriptionText(place.getLongDescription());
|
|
||||||
uploadItem.uploadMediaDetails.get(0).setLanguageCode(languageCode);
|
|
||||||
uploadItem.uploadMediaDetails.get(0).setCaptionText(place.name);
|
|
||||||
}
|
}
|
||||||
if (!items.contains(uploadItem)) {
|
if (!items.contains(uploadItem)) {
|
||||||
items.add(uploadItem);
|
items.add(uploadItem);
|
||||||
|
|
@ -153,7 +144,7 @@ public class UploadModel {
|
||||||
return license;
|
return license;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedLicense(String licenseName) {
|
public void setSelectedLicense(final String licenseName) {
|
||||||
this.license = licensesByName.get(licenseName);
|
this.license = licensesByName.get(licenseName);
|
||||||
store.putString(Prefs.DEFAULT_LICENSE, license);
|
store.putString(Prefs.DEFAULT_LICENSE, license);
|
||||||
}
|
}
|
||||||
|
|
@ -161,11 +152,11 @@ public class UploadModel {
|
||||||
public Observable<Contribution> buildContributions() {
|
public Observable<Contribution> buildContributions() {
|
||||||
return Observable.fromIterable(items).map(item ->
|
return Observable.fromIterable(items).map(item ->
|
||||||
{
|
{
|
||||||
Contribution contribution = new Contribution(item.mediaUri, null,
|
final Contribution contribution = new Contribution(item.mediaUri, null,
|
||||||
item.getFileName(), item.uploadMediaDetails.size()!=0? UploadMediaDetail.formatCaptions(item.uploadMediaDetails):new HashMap<>(),
|
item.getFileName(), item.uploadMediaDetails.size()!=0? UploadMediaDetail.formatCaptions(item.uploadMediaDetails):new HashMap<>(),
|
||||||
UploadMediaDetail.formatList(item.uploadMediaDetails), -1,
|
UploadMediaDetail.formatList(item.uploadMediaDetails), -1,
|
||||||
null, null, sessionManager.getAuthorName(),
|
null, null, sessionManager.getAuthorName(),
|
||||||
CommonsApplication.DEFAULT_EDIT_SUMMARY, selectedDepictions, item.gpsCoords.getDecimalCoords());
|
CommonsApplication.DEFAULT_EDIT_SUMMARY, new ArrayList<>(selectedDepictions), item.gpsCoords.getDecimalCoords());
|
||||||
if (item.place != null) {
|
if (item.place != null) {
|
||||||
contribution.setWikiDataEntityId(item.place.getWikiDataEntityId());
|
contribution.setWikiDataEntityId(item.place.getWikiDataEntityId());
|
||||||
contribution.setWikiItemName(item.place.getName());
|
contribution.setWikiItemName(item.place.getName());
|
||||||
|
|
@ -196,8 +187,8 @@ public class UploadModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deletePicture(String filePath) {
|
public void deletePicture(final String filePath) {
|
||||||
Iterator<UploadItem> iterator = items.iterator();
|
final Iterator<UploadItem> iterator = items.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
if (iterator.next().mediaUri.toString().contains(filePath)) {
|
if (iterator.next().mediaUri.toString().contains(filePath)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
|
|
@ -213,20 +204,22 @@ public class UploadModel {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateUploadItem(int index, UploadItem uploadItem) {
|
public void updateUploadItem(final int index, final UploadItem uploadItem) {
|
||||||
UploadItem uploadItem1 = items.get(index);
|
final UploadItem uploadItem1 = items.get(index);
|
||||||
uploadItem1.setMediaDetails(uploadItem.uploadMediaDetails);
|
uploadItem1.setMediaDetails(uploadItem.uploadMediaDetails);
|
||||||
uploadItem1.setTitle(uploadItem.title);
|
uploadItem1.setTitle(uploadItem.title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelectedDepictions(List<String> selectedDepictions) {
|
public void setSelectedDepictions(final List<String> selectedDepictions) {
|
||||||
if (null == selectedDepictions) {
|
this.selectedDepictions = newListOf(selectedDepictions);
|
||||||
selectedDepictions = new ArrayList<>();
|
|
||||||
}
|
|
||||||
this.selectedDepictions = (ArrayList<String>) selectedDepictions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) {
|
@NotNull
|
||||||
|
private <T> ArrayList<T> newListOf(final List<T> items) {
|
||||||
|
return items != null ? new ArrayList<>(items) : new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useSimilarPictureCoordinates(final ImageCoordinates imageCoordinates, final int uploadItemIndex) {
|
||||||
fileProcessor.useImageCoords(imageCoordinates);
|
fileProcessor.useImageCoords(imageCoordinates);
|
||||||
items.get(uploadItemIndex).setGpsCoords(imageCoordinates);
|
items.get(uploadItemIndex).setGpsCoords(imageCoordinates);
|
||||||
}
|
}
|
||||||
|
|
@ -239,29 +232,23 @@ public class UploadModel {
|
||||||
private final String mimeType;
|
private final String mimeType;
|
||||||
private final String source;
|
private final String source;
|
||||||
private ImageCoordinates gpsCoords;
|
private ImageCoordinates gpsCoords;
|
||||||
|
|
||||||
public void setGpsCoords(ImageCoordinates gpsCoords) {
|
|
||||||
this.gpsCoords = gpsCoords;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Title title;
|
private Title title;
|
||||||
private List<UploadMediaDetail> uploadMediaDetails;
|
private List<UploadMediaDetail> uploadMediaDetails;
|
||||||
private Place place;
|
private final Place place;
|
||||||
private long createdTimestamp;
|
private final long createdTimestamp;
|
||||||
private String createdTimestampSource;
|
private final String createdTimestampSource;
|
||||||
private BehaviorSubject<Integer> imageQuality;
|
private final BehaviorSubject<Integer> imageQuality;
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
UploadItem(Uri originalContentUri,
|
UploadItem(final Uri originalContentUri,
|
||||||
Uri mediaUri, String mimeType, String source, ImageCoordinates gpsCoords,
|
final Uri mediaUri, final String mimeType, final String source, final ImageCoordinates gpsCoords,
|
||||||
Place place,
|
final Place place,
|
||||||
long createdTimestamp,
|
final long createdTimestamp,
|
||||||
String createdTimestampSource) {
|
final String createdTimestampSource) {
|
||||||
this.originalContentUri = originalContentUri;
|
this.originalContentUri = originalContentUri;
|
||||||
this.createdTimestampSource = createdTimestampSource;
|
this.createdTimestampSource = createdTimestampSource;
|
||||||
title = new Title();
|
title = new Title();
|
||||||
uploadMediaDetails = new ArrayList<>();
|
uploadMediaDetails = Collections.singletonList(new UploadMediaDetail());
|
||||||
uploadMediaDetails.add(new UploadMediaDetail());
|
uploadMediaDetails = new ArrayList<>(Arrays.asList(new UploadMediaDetail()));
|
||||||
this.place = place;
|
this.place = place;
|
||||||
this.mediaUri = mediaUri;
|
this.mediaUri = mediaUri;
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
|
|
@ -303,7 +290,7 @@ public class UploadModel {
|
||||||
return this.imageQuality.getValue();
|
return this.imageQuality.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setImageQuality(int imageQuality) {
|
public void setImageQuality(final int imageQuality) {
|
||||||
this.imageQuality.onNext(imageQuality);
|
this.imageQuality.onNext(imageQuality);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,12 +298,12 @@ public class UploadModel {
|
||||||
return place;
|
return place;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(Title title) {
|
public void setTitle(final Title title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setMediaDetails(List<UploadMediaDetail> uploadMediaDetails) {
|
public void setMediaDetails(final List<UploadMediaDetail> uploadMediaDetails) {
|
||||||
this.uploadMediaDetails = uploadMediaDetails;
|
this.uploadMediaDetails = uploadMediaDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,7 +312,7 @@ public class UploadModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object obj) {
|
public boolean equals(@Nullable final Object obj) {
|
||||||
if (!(obj instanceof UploadItem)) {
|
if (!(obj instanceof UploadItem)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -345,6 +332,10 @@ public class UploadModel {
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
return uploadMediaDetails.get(0).getCaptionText();
|
return uploadMediaDetails.get(0).getCaptionText();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public void setGpsCoords(final ImageCoordinates gpsCoords) {
|
||||||
|
this.gpsCoords = gpsCoords;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
@ -35,18 +36,8 @@ 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.Scheduler;
|
import io.reactivex.Scheduler;
|
||||||
import io.reactivex.SingleObserver;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
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.Map;
|
|
||||||
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> {
|
||||||
|
|
@ -275,55 +266,59 @@ public class UploadService extends HandlerService<Contribution> {
|
||||||
uploadStash.getFilekey());
|
uploadStash.getFilekey());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(uploadResult -> {
|
.subscribe(
|
||||||
Timber.d("Stash upload response 2 is %s", uploadResult.toString());
|
uploadResult -> onUpload(contribution, notificationTag, uploadResult),
|
||||||
|
throwable -> {
|
||||||
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
|
||||||
|
|
||||||
String resultStatus = uploadResult.getResult();
|
|
||||||
if (!resultStatus.equals("Success")) {
|
|
||||||
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
|
|
||||||
showFailedNotification(contribution);
|
|
||||||
} else {
|
|
||||||
String canonicalFilename = "File:" + uploadResult.getFilename();
|
|
||||||
final String wikiDataEntityId = contribution.getWikiDataEntityId();
|
|
||||||
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s",
|
|
||||||
wikiDataEntityId);
|
|
||||||
// to perform upload of depictions we pass on depiction entityId of the selected depictions to the wikidataEditService
|
|
||||||
final String p18Value = contribution.getP18Value();
|
|
||||||
final String wikiItemName = contribution.getWikiItemName();
|
|
||||||
if (contribution.getDepictionsEntityIds() != null) {
|
|
||||||
for (String depictionEntityId : contribution.getDepictionsEntityIds()) {
|
|
||||||
wikidataEditService.createClaimWithLogging(depictionEntityId,
|
|
||||||
wikiItemName, canonicalFilename, p18Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Timber.d("Contribution upload success. Initiating Wikidata edit for"
|
|
||||||
+ " entity id %s if necessary (if P18 is null). P18 value is %s",
|
|
||||||
wikiDataEntityId, p18Value);
|
|
||||||
wikidataEditService.createClaimWithLogging(
|
|
||||||
wikiDataEntityId, wikiItemName, canonicalFilename,p18Value);
|
|
||||||
|
|
||||||
wikidataEditService.createLabelforWikidataEntity(
|
|
||||||
wikiDataEntityId, canonicalFilename, contribution.getCaptions());
|
|
||||||
contribution.setFilename(canonicalFilename);
|
|
||||||
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
|
|
||||||
contribution.setState(Contribution.STATE_COMPLETED);
|
|
||||||
contribution.setDateUploaded(CommonsDateUtil.getIso8601DateFormatShort()
|
|
||||||
.parse(uploadResult.getImageinfo().getTimestamp()));
|
|
||||||
compositeDisposable.add(contributionDao
|
|
||||||
.save(contribution)
|
|
||||||
.subscribeOn(ioThreadScheduler)
|
|
||||||
.observeOn(mainThreadScheduler)
|
|
||||||
.subscribe());
|
|
||||||
}
|
|
||||||
}, throwable -> {
|
|
||||||
Timber.w(throwable, "Exception during upload");
|
Timber.w(throwable, "Exception during upload");
|
||||||
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||||
showFailedNotification(contribution);
|
showFailedNotification(contribution);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onUpload(Contribution contribution, String notificationTag,
|
||||||
|
UploadResult uploadResult) throws ParseException {
|
||||||
|
Timber.d("Stash upload response 2 is %s", uploadResult.toString());
|
||||||
|
|
||||||
|
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||||
|
|
||||||
|
String resultStatus = uploadResult.getResult();
|
||||||
|
if (!resultStatus.equals("Success")) {
|
||||||
|
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
|
||||||
|
showFailedNotification(contribution);
|
||||||
|
} else {
|
||||||
|
String canonicalFilename = "File:" + uploadResult.getFilename();
|
||||||
|
final String wikiDataEntityId = contribution.getWikiDataEntityId();
|
||||||
|
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s",
|
||||||
|
wikiDataEntityId);
|
||||||
|
// to perform upload of depictions we pass on depiction entityId of the selected depictions to the wikidataEditService
|
||||||
|
final String p18Value = contribution.getP18Value();
|
||||||
|
final String wikiItemName = contribution.getWikiItemName();
|
||||||
|
if (contribution.getDepictionsEntityIds() != null) {
|
||||||
|
for (String depictionEntityId : contribution.getDepictionsEntityIds()) {
|
||||||
|
wikidataEditService.createClaimWithLogging(depictionEntityId,
|
||||||
|
wikiItemName, canonicalFilename, p18Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Timber.d("Contribution upload success. Initiating Wikidata edit for"
|
||||||
|
+ " entity id %s if necessary (if P18 is null). P18 value is %s",
|
||||||
|
wikiDataEntityId, p18Value);
|
||||||
|
wikidataEditService.createClaimWithLogging(
|
||||||
|
wikiDataEntityId, wikiItemName, canonicalFilename,p18Value);
|
||||||
|
|
||||||
|
wikidataEditService.createLabelforWikidataEntity(canonicalFilename, contribution.getCaptions());
|
||||||
|
contribution.setFilename(canonicalFilename);
|
||||||
|
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
|
||||||
|
contribution.setState(Contribution.STATE_COMPLETED);
|
||||||
|
contribution.setDateUploaded(CommonsDateUtil.getIso8601DateFormatShort()
|
||||||
|
.parse(uploadResult.getImageinfo().getTimestamp()));
|
||||||
|
compositeDisposable.add(contributionDao
|
||||||
|
.save(contribution)
|
||||||
|
.subscribeOn(ioThreadScheduler)
|
||||||
|
.observeOn(mainThreadScheduler)
|
||||||
|
.subscribe());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("StringFormatInvalid")
|
@SuppressLint("StringFormatInvalid")
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void showFailedNotification(Contribution contribution) {
|
private void showFailedNotification(Contribution contribution) {
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.settings.Prefs;
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
import fr.free.nrw.commons.upload.Description;
|
|
||||||
//import fr.free.nrw.commons.upload.DescriptionsAdapter;
|
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
|
||||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
|
||||||
import fr.free.nrw.commons.upload.ImageCoordinates;
|
import fr.free.nrw.commons.upload.ImageCoordinates;
|
||||||
import fr.free.nrw.commons.upload.SimilarImageDialogFragment;
|
import fr.free.nrw.commons.upload.SimilarImageDialogFragment;
|
||||||
import fr.free.nrw.commons.upload.Title;
|
import fr.free.nrw.commons.upload.Title;
|
||||||
import fr.free.nrw.commons.upload.UploadBaseFragment;
|
import fr.free.nrw.commons.upload.UploadBaseFragment;
|
||||||
|
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||||
|
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
||||||
import fr.free.nrw.commons.upload.UploadModel;
|
import fr.free.nrw.commons.upload.UploadModel;
|
||||||
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
|
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
|
|
@ -55,6 +53,8 @@ import javax.inject.Named;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
//import fr.free.nrw.commons.upload.DescriptionsAdapter;
|
||||||
|
|
||||||
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
||||||
|
|
||||||
|
|
@ -282,10 +282,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
@Override
|
@Override
|
||||||
public void onImageProcessed(UploadItem uploadItem, Place place) {
|
public void onImageProcessed(UploadItem uploadItem, Place place) {
|
||||||
this.uploadItem = uploadItem;
|
this.uploadItem = uploadItem;
|
||||||
if (uploadItem.getFileName() != null) {
|
|
||||||
setDescriptionsInAdapter(uploadItem.getUploadMediaDetails());
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptions = uploadItem.getUploadMediaDetails();
|
descriptions = uploadItem.getUploadMediaDetails();
|
||||||
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
|
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
|
||||||
setDescriptionsInAdapter(descriptions);
|
setDescriptionsInAdapter(descriptions);
|
||||||
|
|
@ -306,10 +302,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
place.getName()),
|
place.getName()),
|
||||||
() -> {
|
() -> {
|
||||||
etTitle.setText(place.getName());
|
etTitle.setText(place.getName());
|
||||||
UploadMediaDetail description = new UploadMediaDetail();
|
descriptions = new ArrayList<>(Arrays.asList(new UploadMediaDetail()));
|
||||||
description.setLanguageCode("en");
|
|
||||||
description.setDescriptionText(place.getLongDescription());
|
|
||||||
descriptions = Arrays.asList(description);
|
|
||||||
setDescriptionsInAdapter(descriptions);
|
setDescriptionsInAdapter(descriptions);
|
||||||
},
|
},
|
||||||
() -> {
|
() -> {
|
||||||
|
|
@ -431,13 +424,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDescriptionsInAdapter(List<UploadMediaDetail> uploadMediaDetails){
|
private void setDescriptionsInAdapter(List<UploadMediaDetail> uploadMediaDetails){
|
||||||
if(uploadMediaDetails==null){
|
|
||||||
uploadMediaDetails=new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(uploadMediaDetails.size()==0){
|
|
||||||
uploadMediaDetails.add(new UploadMediaDetail());
|
|
||||||
}
|
|
||||||
uploadMediaDetailAdapter.setItems(uploadMediaDetails);
|
uploadMediaDetailAdapter.setItems(uploadMediaDetails);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import com.google.gson.JsonObject;
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
|
||||||
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
|
|
@ -26,7 +25,6 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import org.wikipedia.csrf.CsrfTokenClient;
|
import org.wikipedia.csrf.CsrfTokenClient;
|
||||||
import org.wikipedia.dataclient.Service;
|
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -46,42 +44,31 @@ public class WikidataEditService {
|
||||||
private final CaptionInterface captionInterface;
|
private final CaptionInterface captionInterface;
|
||||||
private final WikiBaseClient wikiBaseClient;
|
private final WikiBaseClient wikiBaseClient;
|
||||||
private final WikidataClient wikidataClient;
|
private final WikidataClient wikidataClient;
|
||||||
private final MediaClient mediaClient;
|
|
||||||
private final CsrfTokenClient csrfTokenClient;
|
private final CsrfTokenClient csrfTokenClient;
|
||||||
private final Service service;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public WikidataEditService(Context context,
|
public WikidataEditService(final Context context,
|
||||||
WikidataEditListener wikidataEditListener,
|
final WikidataEditListener wikidataEditListener,
|
||||||
MediaClient mediaClient,
|
@Named("default_preferences") final JsonKvStore directKvStore,
|
||||||
@Named("default_preferences") JsonKvStore directKvStore,
|
final WikiBaseClient wikiBaseClient,
|
||||||
WikiBaseClient wikiBaseClient,
|
final CaptionInterface captionInterface,
|
||||||
CaptionInterface captionInterface,
|
final WikidataClient wikidataClient,
|
||||||
WikidataClient wikidataClient,
|
@Named("commons-csrf") final CsrfTokenClient csrfTokenClient) {
|
||||||
@Named("commons-csrf") CsrfTokenClient csrfTokenClient,
|
|
||||||
@Named("commons-service") Service service) {
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.wikidataEditListener = wikidataEditListener;
|
this.wikidataEditListener = wikidataEditListener;
|
||||||
this.directKvStore = directKvStore;
|
this.directKvStore = directKvStore;
|
||||||
this.captionInterface = captionInterface;
|
this.captionInterface = captionInterface;
|
||||||
this.wikiBaseClient = wikiBaseClient;
|
this.wikiBaseClient = wikiBaseClient;
|
||||||
this.mediaClient = mediaClient;
|
|
||||||
this.wikidataClient = wikidataClient;
|
this.wikidataClient = wikidataClient;
|
||||||
this.csrfTokenClient = csrfTokenClient;
|
this.csrfTokenClient = csrfTokenClient;
|
||||||
this.service = service;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a P18 claim and log the edit with custom tag
|
* Create a P18 claim and log the edit with custom tag
|
||||||
<<<<<<< HEAD
|
|
||||||
*
|
*
|
||||||
* @param wikidataEntityId
|
|
||||||
* @param fileName
|
|
||||||
=======
|
|
||||||
* @param wikidataEntityId a unique id of each Wikidata items
|
* @param wikidataEntityId a unique id of each Wikidata items
|
||||||
* @param fileName name of the file we will upload
|
* @param fileName name of the file we will upload
|
||||||
* @param p18Value pic attribute of Wikidata item
|
* @param p18Value pic attribute of Wikidata item
|
||||||
>>>>>>> origin/master
|
|
||||||
*/
|
*/
|
||||||
public void createClaimWithLogging(String wikidataEntityId, String wikiItemName, String fileName, String p18Value) {
|
public void createClaimWithLogging(String wikidataEntityId, String wikiItemName, String fileName, String p18Value) {
|
||||||
if (wikidataEntityId == null) {
|
if (wikidataEntityId == null) {
|
||||||
|
|
@ -104,8 +91,8 @@ public class WikidataEditService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editWikidataProperty(wikidataEntityId, wikiItemName, fileName);
|
editWikidataProperty(wikidataEntityId, wikiItemName, fileName);;
|
||||||
//editWikiBaseDepictsProperty(wikidataEntityId, fileName);
|
editWikiBaseDepictsProperty(wikidataEntityId, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -122,7 +109,7 @@ public class WikidataEditService {
|
||||||
Timber.d("Upload successful with wiki data entity id as %s", wikidataEntityId);
|
Timber.d("Upload successful with wiki data entity id as %s", wikidataEntityId);
|
||||||
Timber.d("Attempting to edit Wikidata property %s", wikidataEntityId);
|
Timber.d("Attempting to edit Wikidata property %s", wikidataEntityId);
|
||||||
|
|
||||||
String propertyValue = getFileName(fileName);
|
final String propertyValue = getFileName(fileName);
|
||||||
|
|
||||||
Timber.d("Entity id is %s and property value is %s", wikidataEntityId, propertyValue);
|
Timber.d("Entity id is %s and property value is %s", wikidataEntityId, propertyValue);
|
||||||
wikidataClient.createClaim(wikidataEntityId, propertyValue)
|
wikidataClient.createClaim(wikidataEntityId, propertyValue)
|
||||||
|
|
@ -148,7 +135,7 @@ public class WikidataEditService {
|
||||||
* @param fileName
|
* @param fileName
|
||||||
*/
|
*/
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private void editWikiBaseDepictsProperty(String wikidataEntityId, String fileName) {
|
private void editWikiBaseDepictsProperty(final String wikidataEntityId, final String fileName) {
|
||||||
wikiBaseClient.getFileEntityId(fileName)
|
wikiBaseClient.getFileEntityId(fileName)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
|
@ -166,37 +153,37 @@ public class WikidataEditService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private void addDepictsProperty(String entityId, String fileEntityId) {
|
private void addDepictsProperty(String entityId, final String fileEntityId) {
|
||||||
if (ConfigUtils.isBetaFlavour()) {
|
if (ConfigUtils.isBetaFlavour()) {
|
||||||
entityId = "Q10"; // Wikipedia:Sandbox (Q10)
|
entityId = "Q10"; // Wikipedia:Sandbox (Q10)
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject value = new JsonObject();
|
final JsonObject value = new JsonObject();
|
||||||
value.addProperty("entity-type", "item");
|
value.addProperty("entity-type", "item");
|
||||||
value.addProperty("numeric-id", entityId.replace("Q", ""));
|
value.addProperty("numeric-id", entityId.replace("Q", ""));
|
||||||
value.addProperty("id", entityId);
|
value.addProperty("id", entityId);
|
||||||
|
|
||||||
JsonObject dataValue = new JsonObject();
|
final JsonObject dataValue = new JsonObject();
|
||||||
dataValue.add("value", value);
|
dataValue.add("value", value);
|
||||||
dataValue.addProperty("type", "wikibase-entityid");
|
dataValue.addProperty("type", "wikibase-entityid");
|
||||||
|
|
||||||
JsonObject mainSnak = new JsonObject();
|
final JsonObject mainSnak = new JsonObject();
|
||||||
mainSnak.addProperty("snaktype", "value");
|
mainSnak.addProperty("snaktype", "value");
|
||||||
mainSnak.addProperty("property", BuildConfig.DEPICTS_PROPERTY);
|
mainSnak.addProperty("property", BuildConfig.DEPICTS_PROPERTY);
|
||||||
mainSnak.add("datavalue", dataValue);
|
mainSnak.add("datavalue", dataValue);
|
||||||
|
|
||||||
JsonObject claim = new JsonObject();
|
final JsonObject claim = new JsonObject();
|
||||||
claim.add("mainsnak", mainSnak);
|
claim.add("mainsnak", mainSnak);
|
||||||
claim.addProperty("type", "statement");
|
claim.addProperty("type", "statement");
|
||||||
claim.addProperty("rank", "preferred");
|
claim.addProperty("rank", "preferred");
|
||||||
|
|
||||||
JsonArray claims = new JsonArray();
|
final JsonArray claims = new JsonArray();
|
||||||
claims.add(claim);
|
claims.add(claim);
|
||||||
|
|
||||||
JsonObject jsonData = new JsonObject();
|
final JsonObject jsonData = new JsonObject();
|
||||||
jsonData.add("claims", claims);
|
jsonData.add("claims", claims);
|
||||||
|
|
||||||
String data = jsonData.toString();
|
final String data = jsonData.toString();
|
||||||
|
|
||||||
Observable.defer((Callable<ObservableSource<Boolean>>) () ->
|
Observable.defer((Callable<ObservableSource<Boolean>>) () ->
|
||||||
wikiBaseClient.postEditEntity(PAGE_ID_PREFIX + fileEntityId, data))
|
wikiBaseClient.postEditEntity(PAGE_ID_PREFIX + fileEntityId, data))
|
||||||
|
|
@ -253,18 +240,19 @@ public class WikidataEditService {
|
||||||
* Adding captions as labels after image is successfully uploaded
|
* Adding captions as labels after image is successfully uploaded
|
||||||
*/
|
*/
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
public void createLabelforWikidataEntity(String wikiDataEntityId, String fileName, Map<String, String> captions) {
|
public void createLabelforWikidataEntity(final String fileName,
|
||||||
|
final Map<String, String> captions) {
|
||||||
Observable.fromCallable(() -> wikiBaseClient.getFileEntityId(fileName))
|
Observable.fromCallable(() -> wikiBaseClient.getFileEntityId(fileName))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(fileEntityId -> {
|
.subscribe(fileEntityId -> {
|
||||||
if (fileEntityId != null) {
|
if (fileEntityId != null) {
|
||||||
for (Map.Entry<String, String> entry : captions.entrySet()) {
|
for (final Map.Entry<String, String> entry : captions.entrySet()) {
|
||||||
Map<String, String> caption = new HashMap<>();
|
final Map<String, String> caption = new HashMap<>();
|
||||||
caption.put(entry.getKey(), entry.getValue());
|
caption.put(entry.getKey(), entry.getValue());
|
||||||
try {
|
try {
|
||||||
wikidataAddLabels(wikiDataEntityId, fileEntityId.toString(), caption);
|
wikidataAddLabels(fileEntityId.toString(), caption);
|
||||||
} catch (Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
throwable.printStackTrace();
|
throwable.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -280,13 +268,12 @@ public class WikidataEditService {
|
||||||
/**
|
/**
|
||||||
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from csrfTokenClient
|
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from csrfTokenClient
|
||||||
*
|
*
|
||||||
* @param wikiDataEntityId entityId for the current contribution
|
|
||||||
* @param fileEntityId
|
* @param fileEntityId
|
||||||
* @param caption
|
* @param caption
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
private void wikidataAddLabels(String wikiDataEntityId, String fileEntityId, Map<String, String> caption) throws Throwable {
|
private void wikidataAddLabels(final String fileEntityId, final Map<String, String> caption) {
|
||||||
Observable.fromCallable(() -> {
|
Observable.fromCallable(() -> {
|
||||||
try {
|
try {
|
||||||
return csrfTokenClient.getTokenBlocking();
|
return csrfTokenClient.getTokenBlocking();
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||||
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
|
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers.any
|
||||||
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.InjectMocks
|
import org.mockito.InjectMocks
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.*
|
import org.mockito.Mockito.*
|
||||||
|
|
@ -15,19 +17,19 @@ import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
class WikidataEditServiceTest {
|
class WikidataEditServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
internal var context: Context? = null
|
internal lateinit var context: Context
|
||||||
@Mock
|
|
||||||
internal var wikidataEditListener: WikidataEditListener? = null
|
|
||||||
@Mock
|
|
||||||
internal var directKvStore: JsonKvStore? = null
|
|
||||||
@Mock
|
|
||||||
internal var wikidataClient: WikidataClient? = null
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
internal var wikibaseClient: WikiBaseClient? = null
|
internal lateinit var directKvStore: JsonKvStore
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
internal lateinit var wikidataClient: WikidataClient
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
internal lateinit var wikibaseClient: WikiBaseClient
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
var wikidataEditService: WikidataEditService? = null
|
lateinit var wikidataEditService: WikidataEditService
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
|
|
@ -37,40 +39,40 @@ class WikidataEditServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noClaimsWhenEntityIdIsNull() {
|
fun noClaimsWhenEntityIdIsNull() {
|
||||||
wikidataEditService!!.createClaimWithLogging(null, null,"Test.jpg","")
|
wikidataEditService.createClaimWithLogging(null, null,"Test.jpg","")
|
||||||
verifyZeroInteractions(wikidataClient!!)
|
verifyZeroInteractions(wikidataClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noClaimsWhenFileNameIsNull() {
|
fun noClaimsWhenFileNameIsNull() {
|
||||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test", null,"")
|
wikidataEditService.createClaimWithLogging("Q1", "Test", null,"")
|
||||||
verifyZeroInteractions(wikidataClient!!)
|
verifyZeroInteractions(wikidataClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noClaimsWhenP18IsNotEmpty() {
|
fun noClaimsWhenP18IsNotEmpty() {
|
||||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test","Test.jpg","Previous.jpg")
|
wikidataEditService.createClaimWithLogging("Q1", "Test","Test.jpg","Previous.jpg")
|
||||||
verifyZeroInteractions(wikidataClient!!)
|
verifyZeroInteractions(wikidataClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noClaimsWhenLocationIsNotCorrect() {
|
fun noClaimsWhenLocationIsNotCorrect() {
|
||||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||||
.thenReturn(false)
|
.thenReturn(false)
|
||||||
wikidataEditService!!.createClaimWithLogging("Q1", "","Test.jpg","")
|
wikidataEditService.createClaimWithLogging("Q1", "", "Test.jpg", "")
|
||||||
verifyZeroInteractions(wikidataClient!!)
|
verifyZeroInteractions(wikidataClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun createClaimWithLogging() {
|
fun createClaimWithLogging() {
|
||||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||||
.thenReturn(true)
|
.thenReturn(true)
|
||||||
`when`(wikidataClient!!.createClaim(ArgumentMatchers.anyString(), ArgumentMatchers.anyString()))
|
whenever(wikidataClient.createClaim(anyString(), anyString()))
|
||||||
.thenReturn(Observable.just(1L))
|
.thenReturn(Observable.just(1L))
|
||||||
`when`(wikidataClient!!.addEditTag(anyLong(), ArgumentMatchers.anyString(), ArgumentMatchers.anyString()))
|
whenever(wikidataClient.addEditTag(anyLong(), anyString(), anyString()))
|
||||||
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
|
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
|
||||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test","Test.jpg","")
|
whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L))
|
||||||
verify(wikidataClient!!, times(1))
|
wikidataEditService.createClaimWithLogging("Q1", "", "Test.jpg", "")
|
||||||
.createClaim(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())
|
verify(wikidataClient, times(1)).createClaim(anyString(), anyString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue