mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Merge remote-tracking branch 'upstream/master' into refactorNearbyClassesMVP
This commit is contained in:
commit
c43b4949ed
33 changed files with 352 additions and 30 deletions
|
|
@ -54,3 +54,6 @@ before_install:
|
||||||
- if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then
|
- if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||||
openssl aes-256-cbc -K $encrypted_38ac1a5053f6_key -iv $encrypted_38ac1a5053f6_iv -in play.p12.enc -out play.p12 -d;
|
openssl aes-256-cbc -K $encrypted_38ac1a5053f6_key -iv $encrypted_38ac1a5053f6_iv -in play.p12.enc -out play.p12 -d;
|
||||||
fi
|
fi
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
- https://wiki-commons.zulipchat.com/api/v1/external/travis?api_key=kn4a8YKNqHCBYp7EW2k463txMj35vReq&stream=travis-ci
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ dependencies {
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
|
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$KOTLIN_VERSION"
|
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$KOTLIN_VERSION"
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation 'org.robolectric:robolectric:3.7.1'
|
testImplementation 'org.robolectric:robolectric:4.3'
|
||||||
|
testImplementation 'androidx.test:core:1.2.0'
|
||||||
testImplementation 'com.nhaarman:mockito-kotlin:1.5.0'
|
testImplementation 'com.nhaarman:mockito-kotlin:1.5.0'
|
||||||
testImplementation 'com.squareup.okhttp3:mockwebserver:3.10.0'
|
testImplementation 'com.squareup.okhttp3:mockwebserver:3.10.0'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ public class NetworkingModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
public OkHttpJsonApiClient provideOkHttpJsonApiClient(OkHttpClient okHttpClient,
|
public OkHttpJsonApiClient provideOkHttpJsonApiClient(OkHttpClient okHttpClient,
|
||||||
@Named("tools_force") HttpUrl toolsForgeUrl,
|
@Named("tools_forge") HttpUrl toolsForgeUrl,
|
||||||
@Named("default_preferences") JsonKvStore defaultKvStore,
|
@Named("default_preferences") JsonKvStore defaultKvStore,
|
||||||
Gson gson) {
|
Gson gson) {
|
||||||
return new OkHttpJsonApiClient(okHttpClient,
|
return new OkHttpJsonApiClient(okHttpClient,
|
||||||
|
|
@ -91,7 +91,7 @@ public class NetworkingModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Named("tools_force")
|
@Named("tools_forge")
|
||||||
@NonNull
|
@NonNull
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
public HttpUrl provideToolsForgeUrl() {
|
public HttpUrl provideToolsForgeUrl() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
package fr.free.nrw.commons.mwapi;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
|
@ -10,6 +12,7 @@ import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||||
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
|
||||||
import org.wikipedia.dataclient.mwapi.RecentChange;
|
import org.wikipedia.dataclient.mwapi.RecentChange;
|
||||||
import org.wikipedia.util.DateUtil;
|
import org.wikipedia.util.DateUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -33,6 +36,7 @@ import fr.free.nrw.commons.nearby.model.NearbyResponse;
|
||||||
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
||||||
import fr.free.nrw.commons.upload.FileUtils;
|
import fr.free.nrw.commons.upload.FileUtils;
|
||||||
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
||||||
|
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||||
import fr.free.nrw.commons.wikidata.model.GetWikidataEditCountResponse;
|
import fr.free.nrw.commons.wikidata.model.GetWikidataEditCountResponse;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
|
|
@ -84,6 +88,11 @@ public class OkHttpJsonApiClient {
|
||||||
urlBuilder
|
urlBuilder
|
||||||
.addPathSegments("/uploadsbyuser.py")
|
.addPathSegments("/uploadsbyuser.py")
|
||||||
.addQueryParameter("user", userName);
|
.addQueryParameter("user", userName);
|
||||||
|
|
||||||
|
if (ConfigUtils.isBetaFlavour()) {
|
||||||
|
urlBuilder.addQueryParameter("labs", "commonswiki");
|
||||||
|
}
|
||||||
|
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(urlBuilder.build())
|
.url(urlBuilder.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -91,7 +100,9 @@ public class OkHttpJsonApiClient {
|
||||||
return Single.fromCallable(() -> {
|
return Single.fromCallable(() -> {
|
||||||
Response response = okHttpClient.newCall(request).execute();
|
Response response = okHttpClient.newCall(request).execute();
|
||||||
if (response != null && response.isSuccessful()) {
|
if (response != null && response.isSuccessful()) {
|
||||||
return Integer.parseInt(response.body().string().trim());
|
if(!TextUtils.isEmpty(response.body().string().trim())){
|
||||||
|
return Integer.parseInt(response.body().string().trim());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
@ -103,6 +114,11 @@ public class OkHttpJsonApiClient {
|
||||||
urlBuilder
|
urlBuilder
|
||||||
.addPathSegments("/wikidataedits.py")
|
.addPathSegments("/wikidataedits.py")
|
||||||
.addQueryParameter("user", userName);
|
.addQueryParameter("user", userName);
|
||||||
|
|
||||||
|
if (ConfigUtils.isBetaFlavour()) {
|
||||||
|
urlBuilder.addQueryParameter("labs", "commonswiki");
|
||||||
|
}
|
||||||
|
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(urlBuilder.build())
|
.url(urlBuilder.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -131,7 +147,7 @@ public class OkHttpJsonApiClient {
|
||||||
*/
|
*/
|
||||||
public Single<FeedbackResponse> getAchievements(String userName) {
|
public Single<FeedbackResponse> getAchievements(String userName) {
|
||||||
final String fetchAchievementUrlTemplate =
|
final String fetchAchievementUrlTemplate =
|
||||||
wikiMediaToolforgeUrl + "/feedback.py";
|
wikiMediaToolforgeUrl + (ConfigUtils.isBetaFlavour() ? "/feedback.py?labs=commonswiki" : "/feedback.py");
|
||||||
return Single.fromCallable(() -> {
|
return Single.fromCallable(() -> {
|
||||||
String url = String.format(
|
String url = String.format(
|
||||||
Locale.ENGLISH,
|
Locale.ENGLISH,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ public class Prefs {
|
||||||
public static final String DEFAULT_LICENSE = "defaultLicense";
|
public static final String DEFAULT_LICENSE = "defaultLicense";
|
||||||
public static final String UPLOADS_SHOWING = "uploadsshowing";
|
public static final String UPLOADS_SHOWING = "uploadsshowing";
|
||||||
public static final String IS_CONTRIBUTION_COUNT_CHANGED = "ccontributionCountChanged";
|
public static final String IS_CONTRIBUTION_COUNT_CHANGED = "ccontributionCountChanged";
|
||||||
|
public static final String MANAGED_EXIF_TAGS = "managedExifTags";
|
||||||
|
|
||||||
public static class Licenses {
|
public static class Licenses {
|
||||||
public static final String CC_BY_SA_3 = "CC BY-SA 3.0";
|
public static final String CC_BY_SA_3 = "CC BY-SA 3.0";
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.Manifest;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.EditTextPreference;
|
import android.preference.EditTextPreference;
|
||||||
|
import android.preference.MultiSelectListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
|
|
@ -14,6 +15,11 @@ import com.karumi.dexter.Dexter;
|
||||||
import com.karumi.dexter.listener.PermissionGrantedResponse;
|
import com.karumi.dexter.listener.PermissionGrantedResponse;
|
||||||
import com.karumi.dexter.listener.single.BasePermissionListener;
|
import com.karumi.dexter.listener.single.BasePermissionListener;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
|
@ -59,6 +65,14 @@ public class SettingsFragment extends PreferenceFragment {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MultiSelectListPreference multiSelectListPref = (MultiSelectListPreference) findPreference("manageExifTags");
|
||||||
|
if (multiSelectListPref != null) {
|
||||||
|
multiSelectListPref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
defaultKvStore.putJson(Prefs.MANAGED_EXIF_TAGS, newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
final EditTextPreference uploadLimit = (EditTextPreference) findPreference("uploads");
|
final EditTextPreference uploadLimit = (EditTextPreference) findPreference("uploads");
|
||||||
int currentUploadLimit = defaultKvStore.getInt(Prefs.UPLOADS_SHOWING, 100);
|
int currentUploadLimit = defaultKvStore.getInt(Prefs.UPLOADS_SHOWING, 100);
|
||||||
uploadLimit.setText(Integer.toString(currentUploadLimit));
|
uploadLimit.setText(Integer.toString(currentUploadLimit));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package fr.free.nrw.commons.ui.LongTitlePreferences;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.preference.MultiSelectListPreference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
public class LongTitleMultiSelectListPreference extends MultiSelectListPreference {
|
||||||
|
/*
|
||||||
|
public LongTitleMultiSelectListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongTitleMultiSelectListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
public LongTitleMultiSelectListPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LongTitleMultiSelectListPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onBindView(View view)
|
||||||
|
{
|
||||||
|
super.onBindView(view);
|
||||||
|
|
||||||
|
TextView title= view.findViewById(android.R.id.title);
|
||||||
|
if (title != null) {
|
||||||
|
title.setSingleLine(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static androidx.exifinterface.media.ExifInterface.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support utils for EXIF metadata handling
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FileMetadataUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes EXIF label from sharedPreferences as input and returns relevant EXIF tags
|
||||||
|
*
|
||||||
|
* @param pref EXIF sharedPreference label
|
||||||
|
* @return EXIF tags
|
||||||
|
*/
|
||||||
|
public static String[] getTagsFromPref(String pref) {
|
||||||
|
Timber.d("Retuning tags for pref:%s", pref);
|
||||||
|
switch (pref) {
|
||||||
|
case "Author":
|
||||||
|
return new String[]{TAG_ARTIST, TAG_CAMARA_OWNER_NAME};
|
||||||
|
case "Copyright":
|
||||||
|
return new String[]{TAG_COPYRIGHT};
|
||||||
|
case "Location":
|
||||||
|
return new String[]{TAG_GPS_LATITUDE, TAG_GPS_LATITUDE_REF,
|
||||||
|
TAG_GPS_LONGITUDE, TAG_GPS_LONGITUDE_REF,
|
||||||
|
TAG_GPS_ALTITUDE, TAG_GPS_ALTITUDE_REF};
|
||||||
|
case "Camera Model":
|
||||||
|
return new String[]{TAG_MAKE, TAG_MODEL};
|
||||||
|
case "Lens Model":
|
||||||
|
return new String[]{TAG_LENS_MAKE, TAG_LENS_MODEL, TAG_LENS_SPECIFICATION};
|
||||||
|
case "Serial Numbers":
|
||||||
|
return new String[]{TAG_BODY_SERIAL_NUMBER, TAG_LENS_SERIAL_NUMBER};
|
||||||
|
case "Software":
|
||||||
|
return new String[]{TAG_SOFTWARE};
|
||||||
|
default:
|
||||||
|
return new String[]{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -2,22 +2,34 @@ package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
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 androidx.exifinterface.media.ExifInterface;
|
import androidx.exifinterface.media.ExifInterface;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.caching.CacheController;
|
import fr.free.nrw.commons.caching.CacheController;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.mwapi.CategoryApi;
|
import fr.free.nrw.commons.mwapi.CategoryApi;
|
||||||
|
import fr.free.nrw.commons.settings.Prefs;
|
||||||
|
import io.reactivex.Observable;
|
||||||
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 timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
@ -66,7 +78,10 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
|
||||||
/**
|
/**
|
||||||
* Processes filePath coordinates, either from EXIF data or user location
|
* Processes filePath coordinates, either from EXIF data or user location
|
||||||
*/
|
*/
|
||||||
GPSExtractor processFileCoordinates(SimilarImageInterface similarImageInterface) {
|
GPSExtractor processFileCoordinates(SimilarImageInterface similarImageInterface, Context context) {
|
||||||
|
// Redact EXIF data as indicated in preferences.
|
||||||
|
redactExifTags(exifInterface, getExifTagsToRedact(context));
|
||||||
|
|
||||||
Timber.d("Calling GPSExtractor");
|
Timber.d("Calling GPSExtractor");
|
||||||
imageObj = new GPSExtractor(exifInterface);
|
imageObj = new GPSExtractor(exifInterface);
|
||||||
decimalCoords = imageObj.getCoords();
|
decimalCoords = imageObj.getCoords();
|
||||||
|
|
@ -81,6 +96,55 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
|
||||||
return imageObj;
|
return imageObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets EXIF Tags from preferences to be redacted.
|
||||||
|
*
|
||||||
|
* @param context application context
|
||||||
|
* @return tags to be redacted
|
||||||
|
*/
|
||||||
|
private Set<String> getExifTagsToRedact(Context context) {
|
||||||
|
Type setType = new TypeToken<Set<String>>() {}.getType();
|
||||||
|
Set<String> prefManageEXIFTags = defaultKvStore.getJson(Prefs.MANAGED_EXIF_TAGS, setType);
|
||||||
|
|
||||||
|
Set<String> redactTags = new HashSet<>(Arrays.asList(
|
||||||
|
context.getResources().getStringArray(R.array.pref_exifTag_values)));
|
||||||
|
Timber.d(redactTags.toString());
|
||||||
|
|
||||||
|
if (prefManageEXIFTags != null) redactTags.removeAll(prefManageEXIFTags);
|
||||||
|
|
||||||
|
return redactTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redacts EXIF metadata as indicated in preferences.
|
||||||
|
*
|
||||||
|
* @param exifInterface ExifInterface object
|
||||||
|
* @param redactTags tags to be redacted
|
||||||
|
*/
|
||||||
|
public static void redactExifTags(ExifInterface exifInterface, Set<String> redactTags) {
|
||||||
|
if(redactTags.isEmpty()) return;
|
||||||
|
|
||||||
|
Disposable disposable = Observable.fromIterable(redactTags)
|
||||||
|
.flatMap(tag -> Observable.fromArray(FileMetadataUtils.getTagsFromPref(tag)))
|
||||||
|
.forEach(tag -> {
|
||||||
|
Timber.d("Checking for tag: %s", tag);
|
||||||
|
String oldValue = exifInterface.getAttribute(tag);
|
||||||
|
if (oldValue != null && !oldValue.isEmpty()) {
|
||||||
|
Timber.d("Exif tag %s with value %s redacted.", tag, oldValue);
|
||||||
|
exifInterface.setAttribute(tag, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
disposables.add(disposable);
|
||||||
|
disposables.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
exifInterface.saveAttributes();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Timber.w("EXIF redaction failed: %s", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find other images around the same location that were taken within the last 20 sec
|
* Find other images around the same location that were taken within the last 20 sec
|
||||||
* @param similarImageInterface
|
* @param similarImageInterface
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ 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);
|
||||||
GPSExtractor gpsExtractor = fileProcessor.processFileCoordinates(similarImageInterface);
|
GPSExtractor gpsExtractor = fileProcessor.processFileCoordinates(similarImageInterface, context);
|
||||||
return new UploadItem(uploadableFile.getContentUri(), Uri.parse(uploadableFile.getFilePath()), uploadableFile.getMimeType(context), source, gpsExtractor, place, fileCreatedDate, createdTimestampSource);
|
return new UploadItem(uploadableFile.getContentUri(), Uri.parse(uploadableFile.getFilePath()), uploadableFile.getMimeType(context), source, gpsExtractor, place, fileCreatedDate, createdTimestampSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Authors:
|
<!-- Authors:
|
||||||
|
* 4nn1l2
|
||||||
* Abijeet Patro
|
* Abijeet Patro
|
||||||
* Amirsara
|
* Amirsara
|
||||||
* Arash.pt
|
* Arash.pt
|
||||||
|
|
@ -175,13 +176,15 @@
|
||||||
<string name="detail_discussion_empty">بدون بحث</string>
|
<string name="detail_discussion_empty">بدون بحث</string>
|
||||||
<string name="detail_license_empty">مجوز ناشناخته</string>
|
<string name="detail_license_empty">مجوز ناشناخته</string>
|
||||||
<string name="menu_refresh">تازهکردن</string>
|
<string name="menu_refresh">تازهکردن</string>
|
||||||
|
<string name="storage_permission_title">درخواست اجازهٔ ذخیرهسازی</string>
|
||||||
<string name="read_storage_permission_rationale">اجازههای مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمیتواند کار کند.</string>
|
<string name="read_storage_permission_rationale">اجازههای مورد نیاز: مطالعهٔ حافظهٔ خارجی. اپلیکیشن بدون آن نمیتواند کار کند.</string>
|
||||||
<string name="write_storage_permission_rationale" fuzzy="true">اجازههای مورد نیاز: نوشتن در حافظهٔ خارجی. اپلیکیشن نمیتواند به دبین دسترسی داشته باشد.</string>
|
<string name="write_storage_permission_rationale">اجازههای مورد نیاز: نوشتن در حافظهٔ خارجی. اپلیکیشن نمیتواند به دوربین/گالری دسترسی داشته باشد.</string>
|
||||||
<string name="location_permission_rationale">اجازههای اختیاری: دریافت موقعیت برای پیشنهاد رده</string>
|
<string name="location_permission_rationale">اجازههای اختیاری: دریافت موقعیت برای پیشنهاد رده</string>
|
||||||
<string name="ok">تأیید</string>
|
<string name="ok">تأیید</string>
|
||||||
<string name="title_activity_nearby">مکانهای اطراف</string>
|
<string name="title_activity_nearby">مکانهای اطراف</string>
|
||||||
<string name="no_nearby">مکانی در نزدیکی یافت نشد</string>
|
<string name="no_nearby">مکانی در نزدیکی یافت نشد</string>
|
||||||
<string name="warning">هشدار</string>
|
<string name="warning">هشدار</string>
|
||||||
|
<string name="upload_image_duplicate">پرونده در ویکیانبار موجود است. آیا مطمئنید که میخواهید ادامه دهید؟</string>
|
||||||
<string name="yes">بله</string>
|
<string name="yes">بله</string>
|
||||||
<string name="no">خیر</string>
|
<string name="no">خیر</string>
|
||||||
<string name="media_detail_title">عنوان</string>
|
<string name="media_detail_title">عنوان</string>
|
||||||
|
|
@ -201,7 +204,8 @@
|
||||||
<string name="invalid_input">ورودی نامعتبر</string>
|
<string name="invalid_input">ورودی نامعتبر</string>
|
||||||
<string name="maximum_limit_alert">عدم توانایی در نمایش بیش از ۵۰۰ مورد</string>
|
<string name="maximum_limit_alert">عدم توانایی در نمایش بیش از ۵۰۰ مورد</string>
|
||||||
<string name="enter_valid">عدد معتبر را وارد کنید</string>
|
<string name="enter_valid">عدد معتبر را وارد کنید</string>
|
||||||
<string name="set_limit" fuzzy="true">تنظیم محدودیت بارگذاریهای اخیر</string>
|
<string name="cannot_be_zero">حد بارگذاری نمیتواند ۰ باشد</string>
|
||||||
|
<string name="set_limit">محدودیت بارگذاری اخیر</string>
|
||||||
<string name="login_failed_2fa_not_supported">تأیید دومرحلهای الان پشتیبانی نمیشود.</string>
|
<string name="login_failed_2fa_not_supported">تأیید دومرحلهای الان پشتیبانی نمیشود.</string>
|
||||||
<string name="logout_verification">آیا واقعاً قصد خروج از سامانه را دارید؟</string>
|
<string name="logout_verification">آیا واقعاً قصد خروج از سامانه را دارید؟</string>
|
||||||
<string name="commons_logo">نشان ویکیانبار</string>
|
<string name="commons_logo">نشان ویکیانبار</string>
|
||||||
|
|
@ -245,11 +249,16 @@
|
||||||
<string name="error_while_cache">خطا در زمان دریافت تصاویر</string>
|
<string name="error_while_cache">خطا در زمان دریافت تصاویر</string>
|
||||||
<string name="title_info">عنوانی توصیفی و یکتا برای پرونده که به عنوان نام پرونده در نظر گرفته خواهد شد. ترجیحاً به زبان ساده باشد، میتوانید فاصله هم به کار ببرید. پسوند پرونده را ننویسید.</string>
|
<string name="title_info">عنوانی توصیفی و یکتا برای پرونده که به عنوان نام پرونده در نظر گرفته خواهد شد. ترجیحاً به زبان ساده باشد، میتوانید فاصله هم به کار ببرید. پسوند پرونده را ننویسید.</string>
|
||||||
<string name="description_info">لطفاً تصویر را تا حد توان شرح دهید. کجا گرفته شدهاست؟ شامل چه چیزی میشود؟ لطفاً اشیا یا افراد را شرح دهید. اطلاعاتی که به راحتی قابل مشاهده هستند را صرفهنظر کنید. اگر چیزی در تصویر غیر طبیعی به نظر میرسد آن را شرح دهید.</string>
|
<string name="description_info">لطفاً تصویر را تا حد توان شرح دهید. کجا گرفته شدهاست؟ شامل چه چیزی میشود؟ لطفاً اشیا یا افراد را شرح دهید. اطلاعاتی که به راحتی قابل مشاهده هستند را صرفهنظر کنید. اگر چیزی در تصویر غیر طبیعی به نظر میرسد آن را شرح دهید.</string>
|
||||||
|
<string name="upload_image_too_dark">این تصویر خیلی تار است. آیا مطمئنید که میخواهید آن را بارگذاری کنید؟ ویکیانبار فقط برای نگهداری از تصاویری است که ارزش دانشنامهای داشته باشند.</string>
|
||||||
|
<string name="upload_image_blurry">این تصویر خیلی محو است. آیا مطمئنید که میخواهید آن را بارگذاری کنید؟ ویکیانبار فقط برای نگهداری از تصاویری است که ارزش دانشنامهای داشته باشند.</string>
|
||||||
|
<string name="upload_problem_exist">مشکلات احتمالی با این تصویر :</string>
|
||||||
<string name="upload_problem_image_dark">تصویر بیش از حد تاریک است.</string>
|
<string name="upload_problem_image_dark">تصویر بیش از حد تاریک است.</string>
|
||||||
<string name="upload_problem_image_blurry">تصویر تار است.</string>
|
<string name="upload_problem_image_blurry">تصویر تار است.</string>
|
||||||
<string name="upload_problem_image_duplicate">تصویر اکنون در انبار موجود است.</string>
|
<string name="upload_problem_image_duplicate">تصویر اکنون در انبار موجود است.</string>
|
||||||
<string name="upload_problem_different_geolocation">این تصویر در مکان متفاوتی گرفته شده است.</string>
|
<string name="upload_problem_different_geolocation">این تصویر در مکان متفاوتی گرفته شده است.</string>
|
||||||
|
<string name="upload_problem_fbmd">لطفاً فقط تصاویری را بارگذاری کنید که خودتان گرفتهاید. تصاویری را که در فیسبوک دیگران پیدا کردهاید بارگذاری نکنید.</string>
|
||||||
<string name="upload_problem_do_you_continue">هنوزم می خوای این عکس رو آپلود کنی؟</string>
|
<string name="upload_problem_do_you_continue">هنوزم می خوای این عکس رو آپلود کنی؟</string>
|
||||||
|
<string name="internet_downloaded">لطفاً فقط تصاویری را بارگذاری کنید که خودتان گرفتهاید. تصاویری را که از اینترنت بارگیری کردهاید بارگذاری نکنید.</string>
|
||||||
<string name="give_permission">اجازه بده</string>
|
<string name="give_permission">اجازه بده</string>
|
||||||
<string name="use_external_storage">استفاده از حافظهٔ خارجی</string>
|
<string name="use_external_storage">استفاده از حافظهٔ خارجی</string>
|
||||||
<string name="use_external_storage_summary">ذخیرهٔ تصویرهای گرفته شده توسط دوربین درونکار اپلیکیشن بر روی دستگاه شما</string>
|
<string name="use_external_storage_summary">ذخیرهٔ تصویرهای گرفته شده توسط دوربین درونکار اپلیکیشن بر روی دستگاه شما</string>
|
||||||
|
|
@ -261,6 +270,8 @@
|
||||||
<string name="nominate_deletion">نامزد شده برای حذف</string>
|
<string name="nominate_deletion">نامزد شده برای حذف</string>
|
||||||
<string name="nominated_for_deletion">این تصویر برای حذف شدن علامت گذاری شده.</string>
|
<string name="nominated_for_deletion">این تصویر برای حذف شدن علامت گذاری شده.</string>
|
||||||
<string name="nominated_see_more"> .</string>
|
<string name="nominated_see_more"> .</string>
|
||||||
|
<string name="nominating_file_for_deletion">نامزد حذف کردن %1$s.</string>
|
||||||
|
<string name="nominating_for_deletion_status">نامزد حذف کردن: %1$s</string>
|
||||||
<string name="view_browser">مشاهده در مرورگر</string>
|
<string name="view_browser">مشاهده در مرورگر</string>
|
||||||
<string name="skip_login">رها کردن</string>
|
<string name="skip_login">رها کردن</string>
|
||||||
<string name="navigation_item_login">ورود به سامانه</string>
|
<string name="navigation_item_login">ورود به سامانه</string>
|
||||||
|
|
@ -268,6 +279,7 @@
|
||||||
<string name="skip_login_message">برای بارگذاری تصاویر در آینده شما باید وارد حساب کاربری خود شوید.</string>
|
<string name="skip_login_message">برای بارگذاری تصاویر در آینده شما باید وارد حساب کاربری خود شوید.</string>
|
||||||
<string name="login_alert_message">لطفا برای استفاده از این ویژگی وارد شوید</string>
|
<string name="login_alert_message">لطفا برای استفاده از این ویژگی وارد شوید</string>
|
||||||
<string name="copy_wikicode">از ویکی واژه به کلیپ برد کپی کنید.</string>
|
<string name="copy_wikicode">از ویکی واژه به کلیپ برد کپی کنید.</string>
|
||||||
|
<string name="wikicode_copied">ویکیمتن در کلیپبورد کپی شد</string>
|
||||||
<string name="nearby_location_has_not_changed">مکان تغییر نکردهاست.</string>
|
<string name="nearby_location_has_not_changed">مکان تغییر نکردهاست.</string>
|
||||||
<string name="nearby_location_not_available">مکان موجود نیست.</string>
|
<string name="nearby_location_not_available">مکان موجود نیست.</string>
|
||||||
<string name="location_permission_rationale_nearby">برای نمایش مکانّای اطراف نیاز به اجازه است.</string>
|
<string name="location_permission_rationale_nearby">برای نمایش مکانّای اطراف نیاز به اجازه است.</string>
|
||||||
|
|
@ -404,4 +416,5 @@
|
||||||
<string name="menu_option_unread">مشاهده خوانده نشده ها</string>
|
<string name="menu_option_unread">مشاهده خوانده نشده ها</string>
|
||||||
<string name="image_chooser_title">انتخاب تصویر برای بارگذاری</string>
|
<string name="image_chooser_title">انتخاب تصویر برای بارگذاری</string>
|
||||||
<string name="please_wait">لطفاً صبر کنید...</string>
|
<string name="please_wait">لطفاً صبر کنید...</string>
|
||||||
|
<string name="image_info">اطلاعات عکس</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
<string name="provider_categories">حالیہ ورتیاں ڳیاں ونکیاں</string>
|
<string name="provider_categories">حالیہ ورتیاں ڳیاں ونکیاں</string>
|
||||||
<string name="menu_retry_upload">ولدا کوشش کرو</string>
|
<string name="menu_retry_upload">ولدا کوشش کرو</string>
|
||||||
<string name="menu_cancel_upload">منسوخ</string>
|
<string name="menu_cancel_upload">منسوخ</string>
|
||||||
<string name="menu_download">ڈاؤن لوڈ ، لہاوݨ</string>
|
<string name="menu_download">ڈاؤن لوڈ کرو ، لہاؤ</string>
|
||||||
<string name="preference_license">پہلے طے تھیا لائسنس</string>
|
<string name="preference_license">پہلے طے تھیا لائسنس</string>
|
||||||
<string name="preference_theme">رات آلا مزاج</string>
|
<string name="preference_theme">رات آلا مزاج</string>
|
||||||
<string name="preference_theme_summary">گھاٹا تھیم ورتو</string>
|
<string name="preference_theme_summary">گھاٹا تھیم ورتو</string>
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,25 @@
|
||||||
<item>@string/license_pref_cc_by_sa_3_0</item>
|
<item>@string/license_pref_cc_by_sa_3_0</item>
|
||||||
<item>@string/license_pref_cc_by_sa_4_0</item>
|
<item>@string/license_pref_cc_by_sa_4_0</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<!--TODO add more EXIF tags-->
|
||||||
|
<array name="pref_exifTag_entries">
|
||||||
|
<item>@string/exif_tag_name_author</item>
|
||||||
|
<item>@string/exif_tag_name_copyright</item>
|
||||||
|
<item>@string/exif_tag_name_location</item>
|
||||||
|
<item>@string/exif_tag_name_cameraModel</item>
|
||||||
|
<item>@string/exif_tag_name_lensModel</item>
|
||||||
|
<item>@string/exif_tag_name_serialNumbers</item>
|
||||||
|
<item>@string/exif_tag_name_software</item>
|
||||||
|
</array>
|
||||||
|
<array name="pref_exifTag_values">
|
||||||
|
<item>@string/exif_tag_author</item>
|
||||||
|
<item>@string/exif_tag_copyright</item>
|
||||||
|
<item>@string/exif_tag_location</item>
|
||||||
|
<item>@string/exif_tag_cameraModel</item>
|
||||||
|
<item>@string/exif_tag_lensModel</item>
|
||||||
|
<item>@string/exif_tag_serialNumbers</item>
|
||||||
|
<item>@string/exif_tag_software</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -5,4 +5,13 @@
|
||||||
<string name="license_pref_cc_by_sa_3_0" translatable="false">CC BY-SA 3.0</string>
|
<string name="license_pref_cc_by_sa_3_0" translatable="false">CC BY-SA 3.0</string>
|
||||||
<string name="license_pref_cc_by_4_0" translatable="false">CC BY 4.0</string>
|
<string name="license_pref_cc_by_4_0" translatable="false">CC BY 4.0</string>
|
||||||
<string name="license_pref_cc_by_sa_4_0" translatable="false">CC BY-SA 4.0</string>
|
<string name="license_pref_cc_by_sa_4_0" translatable="false">CC BY-SA 4.0</string>
|
||||||
|
|
||||||
|
<string name="exif_tag_author" translatable="false">Author</string>
|
||||||
|
<string name="exif_tag_copyright" translatable="false">Copyright</string>
|
||||||
|
<string name="exif_tag_location" translatable="false">Location</string>
|
||||||
|
<string name="exif_tag_cameraModel" translatable="false">Camera Model</string>
|
||||||
|
<string name="exif_tag_lensModel" translatable="false">Lens Model</string>
|
||||||
|
<string name="exif_tag_serialNumbers" translatable="false">Serial Numbers</string>
|
||||||
|
<string name="exif_tag_software" translatable="false">Software</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<string name="preference_category_appearance">Appearance</string>
|
<string name="preference_category_appearance">Appearance</string>
|
||||||
<string name="preference_category_general">General</string>
|
<string name="preference_category_general">General</string>
|
||||||
<string name="preference_category_feedback">Feedback</string>
|
<string name="preference_category_feedback">Feedback</string>
|
||||||
|
<string name="preference_category_privacy">Privacy</string>
|
||||||
<string name="preference_category_location">Location</string>
|
<string name="preference_category_location">Location</string>
|
||||||
<string name="app_name">Commons</string>
|
<string name="app_name">Commons</string>
|
||||||
<string name="bullet">• </string>
|
<string name="bullet">• </string>
|
||||||
|
|
@ -537,6 +538,18 @@ Upload your first media by tapping on the add button.</string>
|
||||||
<string name="welcome_dont_upload_content_description">Examples of images not to upload</string>
|
<string name="welcome_dont_upload_content_description">Examples of images not to upload</string>
|
||||||
<string name="skip_image">SKIP THIS IMAGE</string>
|
<string name="skip_image">SKIP THIS IMAGE</string>
|
||||||
<string name="download_failed_we_cannot_download_the_file_without_storage_permission">Download Failed!!. We cannot download the file without external storage permission.</string>
|
<string name="download_failed_we_cannot_download_the_file_without_storage_permission">Download Failed!!. We cannot download the file without external storage permission.</string>
|
||||||
|
|
||||||
|
<string name="manage_exif_tags">Manage EXIF Tags</string>
|
||||||
|
<string name="manage_exif_tags_summary">Select which EXIF tags to keep in uploads</string>
|
||||||
|
|
||||||
|
<string name="exif_tag_name_author">Author</string>
|
||||||
|
<string name="exif_tag_name_copyright">Copyright</string>
|
||||||
|
<string name="exif_tag_name_location">Location</string>
|
||||||
|
<string name="exif_tag_name_cameraModel">Camera Model</string>
|
||||||
|
<string name="exif_tag_name_lensModel">Lens Model</string>
|
||||||
|
<string name="exif_tag_name_serialNumbers">Serial Numbers</string>
|
||||||
|
<string name="exif_tag_name_software">Software</string>
|
||||||
|
|
||||||
<string name="share_text">Upload photos to Wikimedia Commons on your phone Download the Commons app: %1$s</string>
|
<string name="share_text">Upload photos to Wikimedia Commons on your phone Download the Commons app: %1$s</string>
|
||||||
<string name="share_via">Share app via...</string>
|
<string name="share_via">Share app via...</string>
|
||||||
<string name="image_info">Image Info</string>
|
<string name="image_info">Image Info</string>
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,18 @@
|
||||||
|
|
||||||
</fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory>
|
</fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory>
|
||||||
|
|
||||||
|
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory
|
||||||
|
android:title="@string/preference_category_privacy">
|
||||||
|
|
||||||
|
<fr.free.nrw.commons.ui.LongTitlePreferences.LongTitleMultiSelectListPreference
|
||||||
|
android:entries="@array/pref_exifTag_entries"
|
||||||
|
android:entryValues="@array/pref_exifTag_values"
|
||||||
|
android:key="manageExifTags"
|
||||||
|
android:title="@string/manage_exif_tags"
|
||||||
|
android:summary="@string/manage_exif_tags_summary"/>
|
||||||
|
|
||||||
|
</fr.free.nrw.commons.ui.LongTitlePreferences.LongTitlePreferenceCategory>
|
||||||
|
|
||||||
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.
|
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.
|
||||||
Do not reuse this key unless you revive the same feature with the changes mentioned at #1599.-->
|
Do not reuse this key unless you revive the same feature with the changes mentioned at #1599.-->
|
||||||
|
|
||||||
|
|
|
||||||
BIN
app/src/test/data/exif_redact_sample.jpg
Normal file
BIN
app/src/test/data/exif_redact_sample.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
|
|
@ -4,7 +4,7 @@ import fr.free.nrw.commons.mwapi.MediaResult
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import junit.framework.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class MediaTest {
|
class MediaTest {
|
||||||
@Test
|
@Test
|
||||||
fun displayTitleShouldStripExtension() {
|
fun displayTitleShouldStripExtension() {
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@ package fr.free.nrw.commons
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng
|
import fr.free.nrw.commons.location.LatLng
|
||||||
import fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions
|
import fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class NearbyControllerTest {
|
class NearbyControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -18,7 +18,7 @@ class NearbyControllerTest {
|
||||||
val location = LatLng(0.0, 0.0, 0f)
|
val location = LatLng(0.0, 0.0, 0f)
|
||||||
|
|
||||||
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
||||||
location, null, RuntimeEnvironment.application, null)
|
location, null, ApplicationProvider.getApplicationContext(), null)
|
||||||
|
|
||||||
assertEquals(0, options.size.toLong())
|
assertEquals(0, options.size.toLong())
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ class NearbyControllerTest {
|
||||||
val location = LatLng(0.0, 0.0, 0f)
|
val location = LatLng(0.0, 0.0, 0f)
|
||||||
|
|
||||||
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
||||||
location, emptyList(), RuntimeEnvironment.application, emptyList())
|
location, emptyList(), ApplicationProvider.getApplicationContext(), emptyList())
|
||||||
|
|
||||||
assertEquals(0, options.size.toLong())
|
assertEquals(0, options.size.toLong())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class BookMarkLocationDaoTest {
|
class BookMarkLocationDaoTest {
|
||||||
private val columns = arrayOf(COLUMN_NAME,
|
private val columns = arrayOf(COLUMN_NAME,
|
||||||
COLUMN_DESCRIPTION,
|
COLUMN_DESCRIPTION,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class BookmarkPictureDaoTest {
|
class BookmarkPictureDaoTest {
|
||||||
|
|
||||||
private val columns = arrayOf(COLUMN_MEDIA_NAME, COLUMN_CREATOR)
|
private val columns = arrayOf(COLUMN_MEDIA_NAME, COLUMN_CREATOR)
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import org.robolectric.annotation.Config
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class CategoryDaoTest {
|
class CategoryDaoTest {
|
||||||
|
|
||||||
private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED, COLUMN_TIMES_USED)
|
private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED, COLUMN_TIMES_USED)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import org.robolectric.annotation.Config
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class ContributionDaoTest {
|
class ContributionDaoTest {
|
||||||
private val localUri = "http://example.com/"
|
private val localUri = "http://example.com/"
|
||||||
private val client: ContentProviderClient = mock()
|
private val client: ContentProviderClient = mock()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import fr.free.nrw.commons.auth.SessionManager
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||||
import fr.free.nrw.commons.notification.NotificationHelper
|
import fr.free.nrw.commons.notification.NotificationHelper
|
||||||
import fr.free.nrw.commons.utils.ViewUtilWrapper
|
import fr.free.nrw.commons.utils.ViewUtilWrapper
|
||||||
import junit.framework.Assert.*
|
import org.junit.Assert.*
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.InjectMocks
|
import org.mockito.InjectMocks
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import org.robolectric.annotation.Config
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class RecentSearchesDaoTest {
|
class RecentSearchesDaoTest {
|
||||||
|
|
||||||
private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED)
|
private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class ModifierSequenceDaoTest {
|
class ModifierSequenceDaoTest {
|
||||||
|
|
||||||
private val mediaUrl = "http://example.com/"
|
private val mediaUrl = "http://example.com/"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package fr.free.nrw.commons.mwapi
|
package fr.free.nrw.commons.mwapi
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import fr.free.nrw.commons.BuildConfig
|
|
||||||
import fr.free.nrw.commons.TestCommonsApplication
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
import fr.free.nrw.commons.utils.ConfigUtils
|
import fr.free.nrw.commons.utils.ConfigUtils
|
||||||
|
|
@ -17,14 +17,13 @@ import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mockito.mock
|
import org.mockito.Mockito.mock
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
import org.robolectric.annotation.Config
|
import org.robolectric.annotation.Config
|
||||||
import org.wikipedia.util.DateUtil
|
import org.wikipedia.util.DateUtil
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
class ApacheHttpClientMediaWikiApiTest {
|
class ApacheHttpClientMediaWikiApiTest {
|
||||||
|
|
||||||
private lateinit var testObject: ApacheHttpClientMediaWikiApi
|
private lateinit var testObject: ApacheHttpClientMediaWikiApi
|
||||||
|
|
@ -39,7 +38,7 @@ class ApacheHttpClientMediaWikiApiTest {
|
||||||
wikidataServer = MockWebServer()
|
wikidataServer = MockWebServer()
|
||||||
okHttpClient = OkHttpClient()
|
okHttpClient = OkHttpClient()
|
||||||
sharedPreferences = mock(JsonKvStore::class.java)
|
sharedPreferences = mock(JsonKvStore::class.java)
|
||||||
testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", "http://" + wikidataServer.hostName + ":" + wikidataServer.port + "/", sharedPreferences, Gson())
|
testObject = ApacheHttpClientMediaWikiApi(ApplicationProvider.getApplicationContext(), "http://" + server.hostName + ":" + server.port + "/", "http://" + wikidataServer.hostName + ":" + wikidataServer.port + "/", sharedPreferences, Gson())
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
@ -319,7 +318,7 @@ class ApacheHttpClientMediaWikiApiTest {
|
||||||
private fun assertBasicRequestParameters(server: MockWebServer, method: String): RecordedRequest = server.takeRequest().let {
|
private fun assertBasicRequestParameters(server: MockWebServer, method: String): RecordedRequest = server.takeRequest().let {
|
||||||
assertEquals("/", it.requestUrl.encodedPath())
|
assertEquals("/", it.requestUrl.encodedPath())
|
||||||
assertEquals(method, it.method)
|
assertEquals(method, it.method)
|
||||||
assertEquals("Commons/${ConfigUtils.getVersionNameWithSha(RuntimeEnvironment.application)} (https://mediawiki.org/wiki/Apps/Commons) Android/${Build.VERSION.RELEASE}",
|
assertEquals("Commons/${ConfigUtils.getVersionNameWithSha(ApplicationProvider.getApplicationContext())} (https://mediawiki.org/wiki/Apps/Commons) Android/${Build.VERSION.RELEASE}",
|
||||||
it.getHeader("User-Agent"))
|
it.getHeader("User-Agent"))
|
||||||
if ("POST" == method) {
|
if ("POST" == method) {
|
||||||
assertEquals("application/x-www-form-urlencoded", it.getHeader("Content-Type"))
|
assertEquals("application/x-www-form-urlencoded", it.getHeader("Content-Type"))
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import kotlin.random.Random
|
||||||
* Mock web server based tests for ok http json api client
|
* Mock web server based tests for ok http json api client
|
||||||
*/
|
*/
|
||||||
@RunWith(RobolectricTestRunner::class)
|
@RunWith(RobolectricTestRunner::class)
|
||||||
@Config(constants = BuildConfig::class, sdk = [23], application = TestCommonsApplication::class)
|
@Config(sdk = [23], application = TestCommonsApplication::class)
|
||||||
class OkHttpJsonApiClientTest {
|
class OkHttpJsonApiClientTest {
|
||||||
|
|
||||||
private lateinit var testObject: OkHttpJsonApiClient
|
private lateinit var testObject: OkHttpJsonApiClient
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import fr.free.nrw.commons.Media
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import junit.framework.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentMatchers
|
import org.mockito.ArgumentMatchers
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package fr.free.nrw.commons.upload
|
||||||
|
|
||||||
|
import androidx.exifinterface.media.ExifInterface.*
|
||||||
|
import junit.framework.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test cases for FileMetadataUtils
|
||||||
|
*/
|
||||||
|
class FileMetadataUtilsTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method to verify EXIF tags
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun getTagsFromPref() {
|
||||||
|
val author = FileMetadataUtils.getTagsFromPref("Author")
|
||||||
|
val authorRef = arrayOf(TAG_ARTIST, TAG_CAMARA_OWNER_NAME);
|
||||||
|
|
||||||
|
assertTrue(Arrays.deepEquals(author, authorRef))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package fr.free.nrw.commons.upload
|
package fr.free.nrw.commons.upload
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import fr.free.nrw.commons.caching.CacheController
|
import fr.free.nrw.commons.caching.CacheController
|
||||||
import fr.free.nrw.commons.mwapi.CategoryApi
|
import fr.free.nrw.commons.mwapi.CategoryApi
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
|
@ -11,6 +12,9 @@ import org.mockito.MockitoAnnotations
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
|
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
class FileProcessorTest {
|
class FileProcessorTest {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
|
|
@ -35,4 +39,51 @@ class FileProcessorTest {
|
||||||
fun processFileCoordinates() {
|
fun processFileCoordinates() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method to verify redaction Exif metadata
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun redactExifTags() {
|
||||||
|
/*
|
||||||
|
val filePathRef: String? = "src/test/data/exif_redact_sample.jpg"
|
||||||
|
val filePathTmp: String? = "" + System.getProperty("java.io.tmpdir") + "exif_redact_sample_tmp.jpg"
|
||||||
|
|
||||||
|
val inStream = FileInputStream(filePathRef)
|
||||||
|
val outStream = FileOutputStream(filePathTmp)
|
||||||
|
val inChannel = inStream.getChannel()
|
||||||
|
val outChannel = outStream.getChannel()
|
||||||
|
inChannel.transferTo(0, inChannel.size(), outChannel)
|
||||||
|
inStream.close()
|
||||||
|
outStream.close()
|
||||||
|
|
||||||
|
val redactTags = mutableSetOf("Author", "Copyright", "Location", "Camera Model",
|
||||||
|
"Lens Model", "Serial Numbers", "Software")
|
||||||
|
|
||||||
|
val exifInterface : ExifInterface? = ExifInterface(filePathTmp.toString())
|
||||||
|
|
||||||
|
var nonEmptyTag = false
|
||||||
|
for (redactTag in redactTags) {
|
||||||
|
for (tag in FileMetadataUtils.getTagsFromPref(redactTag)) {
|
||||||
|
val tagValue = exifInterface?.getAttribute(tag)
|
||||||
|
if(tagValue != null) {
|
||||||
|
nonEmptyTag = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nonEmptyTag) break
|
||||||
|
}
|
||||||
|
// all tags are empty, can't test redaction
|
||||||
|
assert(nonEmptyTag)
|
||||||
|
|
||||||
|
FileProcessor.redactExifTags(exifInterface, redactTags)
|
||||||
|
|
||||||
|
for (redactTag in redactTags) {
|
||||||
|
for (tag in FileMetadataUtils.getTagsFromPref(redactTag)) {
|
||||||
|
val oldValue = exifInterface?.getAttribute(tag)
|
||||||
|
assert(oldValue == null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#Thu Mar 01 15:28:48 IST 2018
|
#Thu Mar 01 15:28:48 IST 2018
|
||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
android.enableBuildCache=true
|
android.enableBuildCache=true
|
||||||
|
android.enableUnitTestBinaryResources=true
|
||||||
|
|
||||||
KOTLIN_VERSION=1.3.21
|
KOTLIN_VERSION=1.3.21
|
||||||
BUTTERKNIFE_VERSION=10.1.0
|
BUTTERKNIFE_VERSION=10.1.0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue