Sync master with release (#3922)

* #3624 DateTimeFormat wrong - match pattern returned from servers (#3625)

* Revert "Fixes: #3179 Make category search non case-sensitive (#3326)" (#3636)

Simply lower casing the name of the category sent to the server
doesn't result in the server doing a case insensitive category
search. In fact, it reduces the category search space as only
categories that has a lower case character is searched even
if the search text contains upper case characters.

The test case did not catch this issue as the first character
of the title is case insensitive[1].

So, revert the changes done in commit afdeaae075.

See further disucssion in the issue thread of #3179 starting
from [2].

[1]: https://www.mediawiki.org/wiki/Manual:Page_title
[2]: https://github.com/commons-app/apps-android-commons/issues/3179#issuecomment-605462140

* Bugfix/security exception (#3627)

* Fixes #3626
* Check is file is actually created before writing to file, file picker android

* Handle Security exception

* Fixes #3436 and #2881: Media Detail design Overhaul (#3505)

* ic_map_dark_24dp: map icon for white background

* ic_info_outline_dark_24dp: info icon for dark background

* MediaDetailFragment: update the spacer as per image aspect ratio

* fragment_media_detail: design overhaul

* fragment_media_detail: remove redundant background color statements

* make requested changes

* add dark mode support

* minor ui tweak

* white map icon in dark mode

* make rquested changes

* make requested changes to layout

* fix misalignment of category list

* subtle amendments

* convert comments to javadocs

* minor amendments

* minor changes

* add styles for media detail

* Media detail fragment refactored

* make suggested changes

* minor name fix

* fix the delete button border

* Fixes #3639 (Fix Save State implementation of CheckBoxTriState ) (#3686)

* Add #3723 and #3721 to 2.13 release, fix conflicts

Conflicts were caused by merging #3723 before #3721 , so I just rolled both into one commit.

* Fix NullPointer when clicking on image in MediaDetailFragment (#3730)… (#3739)

* Update changelog.md

* Versioning for v2.13

* Fixes #3705 (Crash when viewing pic I just uploaded) (#3782)

* Fixes #3705
* Let the MediaDetailPager fragment know when the contributions have been updated

* Handle NPE, null check on adapter in MediaDetailPagerFragment

* Fixed BookmarkLocationsDao DB migration (#3793)

* Fixes #3725 (#3795)

* Downgraded okhttp version to support Api 19 devices

* Handled null CompoundDrawable[2] in etTitle-> UploadMediaDetailsFragment (#3828)

* DownSample Upload image to be shown in UploadMediaDetailFragment to handle OOM, Bitmap Too large exception (#3830)

* Fixes #3829
* DownSample Upload image to be shown in UploadMediaDetailFragment to handle OOM, Bitmap Too large exception

* removed unused imports, handled possible exceptions

* Let Fresco handle the downsampling of image

* invalidate in onTransformEnd

* Expose an interface TransformationListener in ZoomableDraweeView to listen to transformation change end

* removed photoView dependency

* removed unused imports in ZoomableActivity

* Bugfix, expand/collapse

* changed functio name

* Bugfix/p18 uploads (#3869)

* updated gradle plugin version

* BugFix #3856
* Do not use preference for deciding acceptable lat long for nearby uploads, instead save the corresponding location in the Contribution via UploadItem

* Marshall contribution's hasInvalidLocation

* reset un-related changes

* Fixed test cases

* Minor code formatting and docs

* Fixes #3882 (#3883)

* Make hasInvalidLocation non-null integer with default value 0

Co-authored-by: Ashish Kumar <ashish@Ashishs-MacBook-Air.local>

* Fixes #3766, Added OPENSTREET attribution (#3889)

* Fixes #3766
* Added OPENSTREET attribution in nearby

* Added custom text attribution in Nearby

* Deleted unused class CustomBorderTextView

* review suggested changes

* modified telemetry summary string

* Versioning and changelog for v2.13.1 (#3908)

* Update changelog.md

* Versioning for v2.13.1

* Fixes #3914 (#3915)

* Verify user login before setting upload count

* fixed compile-time error

* fix erros

* delete emptied files

* remove empty file CategoriesModel.java

Co-authored-by: Seán Mac Gillicuddy <seantheappdev@gmail.com>
Co-authored-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
Co-authored-by: Kshitij Bhardwaj <44129798+kbhardwaj123@users.noreply.github.com>
Co-authored-by: Vitaly V. Pinchuk <vetal.978@gmail.com>
Co-authored-by: Josephine Lim <josephinelim86@gmail.com>
Co-authored-by: Ashish Kumar <ashish@Ashishs-MacBook-Air.local>
This commit is contained in:
Ashish 2020-09-14 16:41:46 +05:30 committed by GitHub
parent abdd16c063
commit ddd3e1212a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 604 additions and 512 deletions

View file

@ -1,5 +1,17 @@
# Wikimedia Commons for Android
## v2.13.1
- Added OpenStreetMap attribution
- Fixed various crashes
- Fixed SQLite error in Nearby map
- Fixed issue with Nearby uploads not being associated with Wikidata p18
## v2.13.0
- New media details UI, ability to zoom and pan around image
- Added suggestions for a place that needs photos if user uploads a photo that is near one of them
- Modifications and fixes to Nearby filters based on user feedback
- Multiple crash and bug fixes
## v2.12.3
- Fixed issue with EXIF data, including coords, being removed from uploads

View file

@ -21,7 +21,9 @@ dependencies {
// Utils
implementation 'in.yuvi:http.fluent:1.3'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
implementation ("com.squareup.okhttp3:okhttp:$OKHTTP_VERSION"){
force = true //API 19 support
}
implementation 'com.squareup.okio:okio:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
@ -35,6 +37,7 @@ dependencies {
// UI
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar'
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
implementation 'com.github.pedrovgs:renderers:3.3.3'
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.6.2'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v8:0.11.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v9:0.4.0'
@ -51,7 +54,7 @@ dependencies {
testImplementation "androidx.paging:paging-common-ktx:$PAGING_VERSION"
implementation "androidx.paging:paging-rxjava2-ktx:$PAGING_VERSION"
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
implementation 'com.squareup.okhttp3:okhttp-ws:3.4.1'
implementation "com.squareup.okhttp3:okhttp-ws:$OKHTTP_VERSION"
// Logging
implementation 'ch.acra:acra-dialog:5.3.0'
@ -60,7 +63,7 @@ dependencies {
api('com.github.tony19:logback-android-classic:1.1.1-6') {
exclude group: 'com.google.android', module: 'android'
}
implementation "com.squareup.okhttp3:logging-interceptor:4.5.0"
implementation "com.squareup.okhttp3:logging-interceptor:$OKHTTP_VERSION"
// Dependency injector
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
@ -81,7 +84,7 @@ dependencies {
testImplementation 'junit:junit:4.13'
testImplementation 'org.robolectric:robolectric:4.3'
testImplementation 'androidx.test:core:1.2.0'
testImplementation "com.squareup.okhttp3:mockwebserver:4.8.0"
testImplementation "com.squareup.okhttp3:mockwebserver:$OKHTTP_VERSION"
testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5"
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
testImplementation 'org.mockito:mockito-core:2.23.0'
@ -139,8 +142,8 @@ android {
defaultConfig {
//applicationId 'fr.free.nrw.commons'
versionCode 561
versionName '2.12.3'
versionCode 775
versionName '2.13.1'
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
minSdkVersion 19

View file

@ -248,24 +248,44 @@ public class BookmarkLocationsDao {
public static void onUpdate(SQLiteDatabase db, int from, int to) {
Timber.d("bookmarksLocations db is updated from:"+from+", to:"+to);
switch (from) {
case 7: onCreate(db);
case 8: // No change
case 9: // No change
case 10:
try {
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;");
} catch (SQLiteException exception){
Timber.e(exception);
}
case 11: // No change
case 12:
try {
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;");
}catch (SQLiteException exception){
Timber.e(exception);
}
break;
if (from == to) {
return;
}
if (from < 7) {
// doesn't exist yet
from++;
onUpdate(db, from, to);
return;
}
if (from == 7) {
// table added in version 8
onCreate(db);
from++;
onUpdate(db, from, to);
return;
}
if (from == 8) {
from++;
onUpdate(db, from, to);
return;
}
if (from == 10) {
//This is safe, and can be called clean, as we/I do not remember the appropriate version for this
//We are anyways switching to room, these things won't be necessary then
try {
db.execSQL("ALTER TABLE bookmarksLocations ADD COLUMN location_pic STRING;");
}catch (SQLiteException exception){
Timber.e(exception);//
}
return;
}
if (from == 12) {
try {
db.execSQL(
"ALTER TABLE bookmarksLocations ADD COLUMN location_destroyed STRING;");
} catch (SQLiteException exception) {
Timber.e(exception);
}
}
}
}

View file

@ -38,7 +38,8 @@ data class Contribution constructor(
val localUri: Uri? = null,
var dataLength: Long = 0,
var dateCreated: Date? = null,
var dateModified: Date? = null
var dateModified: Date? = null,
var hasInvalidLocation : Int = 0
) : Parcelable {
fun completeWith(media: Media): Contribution {
@ -65,6 +66,18 @@ data class Contribution constructor(
wikidataPlace = from(item.place)
)
/**
* Set this true when ImageProcessor has said that the location is invalid
* @param hasInvalidLocation
*/
fun setHasInvalidLocation(hasInvalidLocation: Boolean) {
this.hasInvalidLocation = if (hasInvalidLocation) 1 else 0
}
fun hasInvalidLocation(): Boolean {
return hasInvalidLocation == 1
}
companion object {
const val STATE_COMPLETED = -1
const val STATE_FAILED = 1

View file

@ -22,6 +22,15 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
import androidx.fragment.app.FragmentTransaction;
import fr.free.nrw.commons.MediaDataExtractor;
import fr.free.nrw.commons.auth.SessionManager;
import io.reactivex.disposables.Disposable;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.Media;
@ -83,6 +92,9 @@ public class ContributionsFragment
@Inject ContributionsPresenter contributionsPresenter;
@Inject
SessionManager sessionManager;
private LatLng curLatLng;
private boolean firstLocationUpdate = true;
@ -143,7 +155,14 @@ public class ContributionsFragment
initFragments();
if (!ConfigUtils.isBetaFlavour()) {
if(shouldShowMediaDetailsFragment){
showMediaDetailPagerFragment();
}else{
showContributionsListFragment();
}
if (!ConfigUtils.isBetaFlavour() && sessionManager.isUserLoggedIn()
&& sessionManager.getCurrentAccount() != null) {
setUploadCount();
}

View file

@ -132,7 +132,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
getSpanCount(getResources().getConfiguration().orientation));
rvContributionsList.setLayoutManager(layoutManager);
contributionsListPresenter.setup();
contributionsListPresenter.contributionList.observe(this, adapter::submitList);
contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), adapter::submitList);
rvContributionsList.setAdapter(adapter);
}

View file

@ -7,6 +7,8 @@ import android.content.Context;
import android.view.inputmethod.InputMethodManager;
import androidx.collection.LruCache;
import androidx.room.Room;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.google.gson.Gson;
import dagger.Module;
import dagger.Provides;
@ -49,6 +51,15 @@ public class CommonsApplicationModule {
private Context applicationContext;
public static final String IO_THREAD="io_thread";
public static final String MAIN_THREAD="main_thread";
private AppDatabase appDatabase;
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE contribution "
+ " ADD COLUMN hasInvalidLocation INTEGER NOT NULL DEFAULT 0");
}
};
public CommonsApplicationModule(Context applicationContext) {
this.applicationContext = applicationContext;
@ -103,11 +114,6 @@ public class CommonsApplicationModule {
return context.getContentResolver().acquireContentProviderClient(BuildConfig.CATEGORY_AUTHORITY);
}
/**
* This method is used to provide instance of DepictsContentProviderClient
* @param context context
* @return DepictsContentProviderClient*/
/**
* This method is used to provide instance of RecentSearchContentProviderClient
* which provides content of Recent Searches from database
@ -224,9 +230,11 @@ public class CommonsApplicationModule {
@Provides
@Singleton
public AppDatabase provideAppDataBase() {
return Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db")
appDatabase = Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db")
.addMigrations(MIGRATION_1_2)
.fallbackToDestructiveMigration()
.build();
return appDatabase;
}
@Provides

View file

@ -76,7 +76,7 @@ public class NetworkingModule {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(message -> {
Timber.tag("OkHttp").v(message);
});
httpLoggingInterceptor.level(BuildConfig.DEBUG ? Level.BODY: Level.BASIC);
httpLoggingInterceptor.setLevel(BuildConfig.DEBUG ? Level.BODY: Level.BASIC);
return httpLoggingInterceptor;
}

View file

@ -166,7 +166,7 @@ public class FilePicker implements Constants {
public static List<UploadableFile> handleExternalImagesPicked(Intent data, Activity activity) {
try {
return getFilesFromGalleryPictures(data, activity);
} catch (IOException e) {
} catch (IOException | SecurityException e) {
e.printStackTrace();
}
return new ArrayList<>();
@ -207,7 +207,7 @@ public class FilePicker implements Constants {
}
}
private static List<UploadableFile> getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException {
private static List<UploadableFile> getFilesFromGalleryPictures(Intent data, Activity activity) throws IOException, SecurityException {
List<UploadableFile> files = new ArrayList<>();
ClipData clipData = data.getClipData();
if (clipData == null) {

View file

@ -104,12 +104,15 @@ class PickedFiles implements Constants {
});
}
static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException {
static UploadableFile pickedExistingPicture(@NonNull Context context, Uri photoUri) throws IOException, SecurityException {// SecurityException for those file providers who share URI but forget to grant necessary permissions
InputStream pictureInputStream = context.getContentResolver().openInputStream(photoUri);
File directory = tempImageDirectory(context);
File photoFile = new File(directory, UUID.randomUUID().toString() + "." + getMimeType(context, photoUri));
photoFile.createNewFile();
writeToFile(pictureInputStream, photoFile);
if (photoFile.createNewFile()) {
writeToFile(pictureInputStream, photoFile);
} else {
throw new IOException("could not create photoFile to write upon");
}
return new UploadableFile(photoUri, photoFile);
}

View file

@ -295,7 +295,9 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
* The method notify the viewpager that number of items have changed.
*/
public void notifyDataSetChanged(){
adapter.notifyDataSetChanged();
if (null != adapter) {
adapter.notifyDataSetChanged();
}
}
@Override

View file

@ -23,18 +23,11 @@ import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.interfaces.DraweeController;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.image.ImageInfo;
import com.github.chrisbanes.photoview.PhotoView;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class ZoomableActivity extends AppCompatActivity {
private Uri imageUri;

View file

@ -47,6 +47,7 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
private boolean mIsDialtoneEnabled = false;
private boolean mZoomingEnabled = true;
private TransformationListener transformationListener;
private final ControllerListener mControllerListener =
new BaseControllerListener<Object>() {
@ -73,9 +74,18 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
}
@Override
public void onTransformEnd(Matrix transform) {}
public void onTransformEnd(Matrix transform) {
if (null != transformationListener) {
transformationListener.onTransformationEnd();
}
}
};
public void setTransformationListener(
TransformationListener transformationListener) {
this.transformationListener = transformationListener;
}
private final GestureListenerWrapper mTapListenerWrapper = new GestureListenerWrapper();
public ZoomableDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
@ -397,4 +407,11 @@ public class ZoomableDraweeView extends DraweeView<GenericDraweeHierarchy>
protected ZoomableController createZoomableController() {
return AnimatedZoomableController.newInstance();
}
/**
* Use this, If someone is willing to listen to scale change
*/
public interface TransformationListener{
void onTransformationEnd();
}
}

View file

@ -1,8 +1,6 @@
package fr.free.nrw.commons.nearby;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.widget.CompoundButton;
@ -12,7 +10,6 @@ import androidx.appcompat.widget.AppCompatCheckBox;
import java.util.List;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
/**
* Base on https://stackoverflow.com/a/40939367/3950497 answer.
@ -25,7 +22,7 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
static public final int CHECKED = 1;
private int state;
private int state=UNKNOWN;
private Callback callback;
@ -64,12 +61,6 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
*/
private OnCheckedChangeListener clientListener;
/**
* This flag is needed to avoid accidentally changing the current {@link #state} when
* {@link #onRestoreInstanceState(Parcelable)} calls {@link #setChecked(boolean)}
* evoking our {@link #privateListener} and therefore changing the real state.
*/
private boolean restoring;
public CheckBoxTriStates(Context context) {
super(context);
@ -91,7 +82,7 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
}
public void setState(int state) {
if(!this.restoring && this.state != state) {
if(this.state != state) {
this.state = state;
if(this.clientListener != null) {
@ -118,27 +109,6 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
super.setOnCheckedChangeListener(privateListener);
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.state = state;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
this.restoring = true; // indicates that the ui is restoring its state
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setState(ss.state);
requestLayout();
this.restoring = false;
}
private void init() {
state = UNKNOWN;
updateBtn();
@ -164,44 +134,4 @@ public class CheckBoxTriStates extends AppCompatCheckBox {
setButtonDrawable(btnDrawable);
}
static class SavedState extends BaseSavedState {
int state;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
state = in.readInt();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue(state);
}
@Override
public String toString() {
return "CheckboxTriState.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " state=" + state + "}";
}
@SuppressWarnings("hiding")
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}

View file

@ -19,6 +19,8 @@ import android.graphics.Bitmap;
import android.graphics.drawable.VectorDrawable;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -39,6 +41,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -75,7 +78,6 @@ import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.ContributionController;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LocationServiceManager;
@ -154,6 +156,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
@BindView(R.id.rv_nearby_list)
RecyclerView rvNearbyList;
@BindView(R.id.no_results_message) TextView noResultsView;
@BindView(R.id.tv_attribution)
AppCompatTextView tvAttribution;
@Inject LocationServiceManager locationManager;
@Inject NearbyController nearbyController;
@ -235,8 +239,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
final UiSettings uiSettings = mapBoxMap.getUiSettings();
uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.LEFT);
uiSettings.setCompassMargins(12, 0, 0, 24);
uiSettings.setLogoEnabled(true);
uiSettings.setAttributionEnabled(true);
uiSettings.setLogoEnabled(false);
uiSettings.setAttributionEnabled(false);
uiSettings.setRotateGesturesEnabled(false);
isMapBoxReady =true;
performMapReadyActions();
@ -259,6 +263,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
scaleBarPlugin.create(scaleBarOptions);
});
});
tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
tvAttribution.setMovementMethod(LinkMovementMethod.getInstance());
}
/**
@ -659,7 +666,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
@Override
public boolean isCurrentLocationMarkerVisible() {
if (latLngBounds == null) {
if (latLngBounds == null || currentLocationMarker==null) {
Timber.d("Map projection bounds are null");
return false;
} else {

View file

@ -9,6 +9,7 @@ public class Prefs {
public static final String MANAGED_EXIF_TAGS = "managed_exif_tags";
public static final String KEY_LANGUAGE_VALUE = "languageDescription";
public static final String KEY_THEME_VALUE = "appThemePref";
public static final String TELEMETRY_PREFERENCE = "telemetryPref";
public static class Licenses {
public static final String CC_BY_SA_3 = "CC BY-SA 3.0";

View file

@ -14,6 +14,8 @@ import com.google.android.material.snackbar.Snackbar;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.single.BasePermissionListener;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.di.ApplicationlessInjection;
@ -85,6 +87,24 @@ public class SettingsFragment extends PreferenceFragmentCompat {
findPreference("displayLocationPermissionForCardView").setEnabled(false);
findPreference("displayCampaignsCardView").setEnabled(false);
}
findPreference("telemetryOptOut").setOnPreferenceChangeListener(
(preference, newValue) -> {
telemetryOptInOut((boolean)newValue);
defaultKvStore.putBoolean(Prefs.TELEMETRY_PREFERENCE,(boolean)newValue);
return false;
});
}
/**
* Opt in or out of MapBox telemetry
* @param shouldOptIn
*/
private void telemetryOptInOut(boolean shouldOptIn){
TelemetryDefinition telemetry = Mapbox.getTelemetry();
if (telemetry != null) {
telemetry.setUserTelemetryRequestState(shouldOptIn);
}
}
/**

View file

@ -22,6 +22,8 @@ public class UploadItem {
private final long createdTimestamp;
private final String createdTimestampSource;
private final BehaviorSubject<Integer> imageQuality;
private boolean hasInvalidLocation;
@SuppressLint("CheckResult")
UploadItem(final Uri mediaUri,
@ -103,4 +105,11 @@ public class UploadItem {
this.gpsCoords = gpsCoords;
}
public void setHasInvalidLocation(boolean hasInvalidLocation) {
this.hasInvalidLocation=hasInvalidLocation;
}
public boolean hasInvalidLocation() {
return hasInvalidLocation;
}
}

View file

@ -141,6 +141,13 @@ public class UploadModel {
{
final Contribution contribution = new Contribution(
item, sessionManager, newListOf(selectedDepictions), newListOf(selectedCategories));
contribution.setHasInvalidLocation(item.hasInvalidLocation());
Timber.d("Created timestamp while building contribution is %s, %s",
item.getCreatedTimestamp(),
new Date(item.getCreatedTimestamp()));
if (item.getCreatedTimestamp() != -1L) {
contribution.setDateCreated(new Date(item.getCreatedTimestamp()));
contribution.setDateCreatedSource(item.getCreatedTimestampSource());
@ -188,4 +195,5 @@ public class UploadModel {
public List<DepictedItem> getSelectedDepictions() {
return selectedDepictions;
}
}

View file

@ -22,6 +22,7 @@ import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.CommonsApplicationModule;
import fr.free.nrw.commons.di.CommonsDaggerService;
import fr.free.nrw.commons.media.MediaClient;
import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.wikidata.WikidataEditService;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
@ -350,8 +351,14 @@ public class UploadService extends CommonsDaggerService {
.add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution));
WikidataPlace wikidataPlace = contribution.getWikidataPlace();
if (wikidataPlace != null && wikidataPlace.getImageValue() == null) {
wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(),
contribution.getMedia().getCaptions());
if (!contribution.hasInvalidLocation()) {
wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(),
contribution.getMedia().getCaptions());
} else {
ViewUtil.showShortToast(this, getString(R.string.wikidata_edit_failure));
Timber
.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
}
}
saveCompletedContribution(contribution, uploadResult);
}

View file

@ -45,7 +45,7 @@ import org.apache.commons.lang3.StringUtils;
import timber.log.Timber;
public class UploadMediaDetailFragment extends UploadBaseFragment implements
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
@BindView(R.id.tv_title)
TextView tvTitle;
@ -98,7 +98,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_upload_media_detail_fragment, container, false);
}
@ -111,7 +111,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
private void init() {
tvTitle.setText(getString(R.string.step_count, callback.getIndexInViewFlipper(this) + 1,
callback.getTotalNumberOfSteps()));
callback.getTotalNumberOfSteps()));
initRecyclerView();
initPresenter();
presenter.receiveImage(uploadableFile, place);
@ -140,10 +140,10 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
*/
private void attachImageViewScaleChangeListener() {
photoViewBackgroundImage.setOnScaleChangeListener(
(scaleFactor, focusX, focusY) -> {
//Whenever the uses plays with the image, lets collapse the media detail container
expandCollapseLlMediaDetail(false);
});
(scaleFactor, focusX, focusY) -> {
//Whenever the uses plays with the image, lets collapse the media detail container
expandCollapseLlMediaDetail(false);
});
}
/**
@ -228,16 +228,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
@Override
public void onNearbyPlaceFound(UploadItem uploadItem, Place place) {
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.upload_nearby_place_found_title),
String.format(Locale.getDefault(),
getString(R.string.upload_nearby_place_found_description),
place.getName()),
() -> {
presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this));
},
() -> {
getString(R.string.upload_nearby_place_found_title),
String.format(Locale.getDefault(),
getString(R.string.upload_nearby_place_found_description),
place.getName()),
() -> {
presenter.onUserConfirmedUploadIsOfPlace(place, callback.getIndexInViewFlipper(this));
},
() -> {
});
});
}
@Override
@ -264,16 +264,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
public void showDuplicatePicturePopup(UploadItem uploadItem) {
String uploadTitleFormat = getString(R.string.upload_title_duplicate);
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.duplicate_image_found),
String.format(Locale.getDefault(),
uploadTitleFormat,
uploadItem.getFileName()),
getString(R.string.upload),
getString(R.string.cancel),
() -> {
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
onNextButtonClicked();
}, null);
getString(R.string.duplicate_image_found),
String.format(Locale.getDefault(),
uploadTitleFormat,
uploadItem.getFileName()),
getString(R.string.upload),
getString(R.string.cancel),
() -> {
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
onNextButtonClicked();
}, null);
}
@ -283,16 +283,16 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
String errorMessageForResult = getErrorMessageForResult(getContext(), errorCode);
if (!StringUtils.isBlank(errorMessageForResult)) {
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.upload_problem_image),
errorMessageForResult,
getString(R.string.upload),
getString(R.string.cancel),
getString(R.string.upload_problem_image),
errorMessageForResult,
getString(R.string.upload),
getString(R.string.cancel),
() -> {
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
onNextButtonClicked();
},
() -> deleteThisPicture()
);
uploadItem.setImageQuality(ImageUtils.IMAGE_KEEP);
onNextButtonClicked();
},
() -> deleteThisPicture()
);
}
//If the error message is null, we will probably not show anything
}

View file

@ -134,7 +134,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
.observeOn(mainThreadScheduler)
.subscribe(imageResult -> {
view.showProgress(false);
handleImageResult(imageResult, uploadItem);
handleImageResult(imageResult, uploadItem);
},
throwable -> {
view.showProgress(false);
@ -201,6 +201,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
UploadItem uploadItem) {
if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) {
view.onImageValidationSuccess();
uploadItem.setHasInvalidLocation(false);
} else {
handleBadImage(imageResult, uploadItem);
}
@ -212,11 +213,12 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
* @param errorCode
* @param uploadItem
*/
public void handleBadImage(Integer errorCode, UploadItem uploadItem) {
public void handleBadImage(Integer errorCode,
UploadItem uploadItem) {
Timber.d("Handle bad picture with error code %d", errorCode);
// If location of image and nearby does not match, then set shared preferences to disable wikidata edits
if (errorCode >= 8) {
defaultKVStore.putBoolean("Picture_Has_Correct_Location", false);
if (errorCode
>= 8) { // If location of image and nearby does not match
uploadItem.setHasInvalidLocation(true);
}
switch (errorCode) {

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/mainBackground"
>
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/mainBackground"
>
<LinearLayout
android:id="@+id/dummy_category_edit_container"
@ -23,53 +23,53 @@
</LinearLayout>
<ImageView
android:id="@+id/mediaDetailImageFailed"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:visibility="gone"
android:contentDescription="@string/mediaimage_failed"
/>
android:id="@+id/mediaDetailImageFailed"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:src="@android:drawable/ic_menu_close_clear_cancel"
android:visibility="gone"
android:contentDescription="@string/mediaimage_failed"
/>
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/mediaDetailImageView"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_250"
app:actualImageScaleType="none" />
android:id="@+id/mediaDetailImageView"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_250"
app:actualImageScaleType="none" />
<ScrollView
android:id="@+id/mediaDetailScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:fillViewport="true">
android:id="@+id/mediaDetailScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:cacheColorHint="@android:color/transparent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Placeholder. Height gets set at runtime based on container size; the initial value is a hack to keep
the detail info offscreen until it's placed properly. May be a better way to do this. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/mediaDetailImageViewLandscape"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_250"
app:actualImageScaleType="none"
android:visibility="gone" />
android:id="@+id/mediaDetailImageViewLandscape"
android:layout_width="match_parent"
android:layout_height="@dimen/dimen_250"
app:actualImageScaleType="none"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/mediaDetailImageViewSpacer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/mediaDetailImageViewSpacer"
>
</LinearLayout>
@ -77,32 +77,32 @@
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/mainBackground"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/mainBackground"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/primaryDarkColor"
android:orientation="horizontal"
android:padding="@dimen/quarter_standard_height">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/primaryDarkColor"
android:orientation="horizontal"
android:padding="@dimen/quarter_standard_height">
<TextView
style="@style/MediaDetailTextLabelTitle"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_title" />
style="@style/MediaDetailTextLabelTitle"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_title" />
<TextView
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailTitle"
android:layout_width="@dimen/widget_margin"
android:textColor="@android:color/white"
android:layout_height="match_parent"
tools:text="Title of the media" />
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailTitle"
android:layout_width="@dimen/widget_margin"
android:textColor="@android:color/white"
android:layout_height="match_parent"
tools:text="Title of the media" />
</LinearLayout>
<LinearLayout
@ -130,24 +130,24 @@
</LinearLayout>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/authorLinearLayout"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/authorLinearLayout"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_author" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_author" />
<TextView
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailAuthor"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
tools:text="Media author user name goes here." />
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailAuthor"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
tools:text="Media author user name goes here." />
</LinearLayout>
<LinearLayout
@ -172,88 +172,88 @@
</LinearLayout>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_description" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_description" />
<fr.free.nrw.commons.ui.widget.HtmlTextView
android:id="@+id/mediaDetailDesc"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
tools:text="Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though." />
android:id="@+id/mediaDetailDesc"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
tools:text="Description of the media goes here. This can potentially be fairly long, and will need to wrap across multiple lines. We hope it looks nice though." />
</LinearLayout>
<View
android:background="?attr/mediaDetailSpacerColor"
android:layout_width="match_parent"
android:layout_height="@dimen/tiny_gap"/>
android:background="?attr/mediaDetailSpacerColor"
android:layout_width="match_parent"
android:layout_height="@dimen/tiny_gap"/>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_license" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_license" />
<TextView
android:id="@+id/mediaDetailLicense"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
android:drawablePadding="@dimen/tiny_gap"
android:drawableStart="?attr/iconInfo24"
tools:text="License link" />
android:id="@+id/mediaDetailLicense"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
android:drawablePadding="@dimen/tiny_gap"
android:drawableStart="?attr/iconInfo24"
tools:text="License link" />
</LinearLayout>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_coordinates" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_coordinates" />
<TextView
android:id="@+id/mediaDetailCoordinates"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
android:drawablePadding="@dimen/tiny_gap"
android:drawableStart="?attr/iconMap24"
tools:text="Coordinates link" />
android:id="@+id/mediaDetailCoordinates"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:layout_gravity="start"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical"
android:padding="@dimen/small_gap"
android:textColor="?attr/mediaDetailsText"
android:textSize="@dimen/description_text_size"
android:drawablePadding="@dimen/tiny_gap"
android:drawableStart="?attr/iconMap24"
tools:text="Coordinates link" />
</LinearLayout>
<LinearLayout
@ -264,39 +264,39 @@
android:orientation="horizontal"
android:textStyle="bold">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_depiction" />
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_depiction" />
<LinearLayout
android:id="@+id/media_detail_depiction_container"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:orientation="vertical" />
<LinearLayout
android:id="@+id/media_detail_depiction_container"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:orientation="vertical" />
</LinearLayout>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:textStyle="bold">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:textStyle="bold">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/detail_panel_cats_label" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/detail_panel_cats_label" />
<LinearLayout
android:id="@+id/mediaDetailCategoryContainer"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:orientation="vertical">
android:id="@+id/mediaDetailCategoryContainer"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:layout_weight="70"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>
@ -310,90 +310,90 @@
android:background="@drawable/ic_baseline_edit_24" />
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_uploaded_date" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_uploaded_date" />
<TextView
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailuploadeddate"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
tools:text="Uploaded date" />
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailuploadeddate"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
tools:text="Uploaded date" />
</LinearLayout>
<LinearLayout
android:id="@+id/nominatedDeletionBanner"
android:background="?attr/mediaDetailNominationBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/quarter_standard_height"
android:visibility="gone">
android:id="@+id/nominatedDeletionBanner"
android:background="?attr/mediaDetailNominationBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/quarter_standard_height"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/nominated_for_deletion"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/nominated_for_deletion"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
<TextView
android:id="@+id/seeMore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="@dimen/standard_gap"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
android:id="@+id/seeMore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="@dimen/standard_gap"
android:textColor="@color/primaryTextColor"
android:textSize="@dimen/normal_text"
android:textStyle="bold"/>
</LinearLayout>
<LinearLayout
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
style="@style/MediaDetailContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_discussion" />
style="@style/MediaDetailTextLabelGeneric"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent"
android:text="@string/media_detail_discussion" />
<TextView
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailDisc"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent" />
style="@style/MediaDetailTextBody"
android:id="@+id/mediaDetailDisc"
android:layout_width="@dimen/widget_margin"
android:layout_height="match_parent" />
</LinearLayout>
<Button
android:id="@+id/copyWikicode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_gap"
android:background="@drawable/bg_copy_wikitext_button"
android:text="@string/copy_wikicode"
android:textColor="@color/primaryTextColor" />
android:id="@+id/copyWikicode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_gap"
android:background="@drawable/bg_copy_wikitext_button"
android:text="@string/copy_wikicode"
android:textColor="@color/primaryTextColor" />
<Button
android:id="@+id/nominateDeletion"
android:background="@drawable/bg_delete_button"
android:textColor="@color/primaryTextColor"
android:layout_margin="@dimen/standard_gap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/nominate_deletion"/>
android:id="@+id/nominateDeletion"
android:background="@drawable/bg_delete_button"
android:textColor="@color/primaryTextColor"
android:layout_margin="@dimen/standard_gap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/nominate_deletion"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -25,7 +25,7 @@
<!-- I have done this intentionally, the mapview because of some elevation or something,
sometimes hangs over the drawer layout and sometimes draws its onPaused state over the contributions, this seems to be the probable fix -->
<FrameLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/nearby_filter">
@ -40,7 +40,19 @@
android:layout_height="match_parent"
android:background="@android:color/transparent" />
</FrameLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_attribution"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="@string/map_attribution"
android:textAlignment="center"
android:textSize="10sp" />
</RelativeLayout>
<Button

View file

@ -1,139 +1,139 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/backgroundImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:actualImageScaleType="fitXY" />
android:id="@+id/backgroundImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:actualImageScaleType="fitXY" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="@dimen/dimen_10"
android:elevation="@dimen/cardview_default_elevation">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="@dimen/dimen_10"
android:elevation="@dimen/cardview_default_elevation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dimen_10"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_container_title"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="@dimen/half_standard_height"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:gravity="center_vertical"
android:textSize="@dimen/normal_text"
android:textStyle="bold"
tools:text="Step 1 of 15" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/ib_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:layout_toLeftOf="@id/ib_expand_collapse"
android:visibility="gone"
app:srcCompat="@drawable/ic_map_white_24dp"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/ib_expand_collapse"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/half_standard_height"
android:layout_height="@dimen/half_standard_height"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="@dimen/small_gap"
android:layout_marginEnd="@dimen/small_gap"
android:layout_marginBottom="@dimen/small_gap"
android:clickable="false"
android:focusable="false"
android:padding="@dimen/medium_height"
app:srcCompat="@drawable/ic_expand_less_black_24dp" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dimen_10"
android:orientation="vertical">
android:id="@+id/ll_container_media_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_gap"
android:orientation="vertical">
<fr.free.nrw.commons.widget.HeightLimitedRecyclerView
android:id="@+id/rv_descriptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin_horizontal"
android:layout_marginBottom="@dimen/activity_margin_horizontal"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_copy_prev_title_desc"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/previous_image_caption_description"
android:padding="@dimen/miniscule_margin"
android:textAlignment="textEnd"
android:textColor="@color/button_blue"
android:visibility="gone"
tools:visibility="visible" />
<RelativeLayout
android:id="@+id/rl_container_title"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="@dimen/half_standard_height"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:gravity="center_vertical"
android:textSize="@dimen/normal_text"
android:textStyle="bold"
tools:text="Step 1 of 15" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/ib_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:layout_toLeftOf="@id/ib_expand_collapse"
android:visibility="gone"
app:srcCompat="@drawable/ic_map_white_24dp"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/ib_expand_collapse"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="@dimen/half_standard_height"
android:layout_height="@dimen/half_standard_height"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="@dimen/small_gap"
android:layout_marginEnd="@dimen/small_gap"
android:layout_marginBottom="@dimen/small_gap"
android:clickable="false"
android:focusable="false"
android:padding="@dimen/medium_height"
app:srcCompat="@drawable/ic_expand_less_black_24dp" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_container_media_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_gap"
android:orientation="vertical">
<fr.free.nrw.commons.widget.HeightLimitedRecyclerView
android:id="@+id/rv_descriptions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin_horizontal"
android:layout_marginBottom="@dimen/activity_margin_horizontal"
tools:visibility="visible" />
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_copy_prev_title_desc"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/previous_image_caption_description"
android:padding="@dimen/miniscule_margin"
android:textAlignment="textEnd"
android:textColor="@color/button_blue"
android:visibility="gone"
tools:visibility="visible" />
android:id="@+id/btn_add_description"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="@dimen/fragment_height"
android:text="+" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:enabled="false"
android:alpha=".5"
android:text="@string/next"
android:textColor="@android:color/white" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_add_description"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="@dimen/fragment_height"
android:text="+" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_previous"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:layout_toLeftOf="@+id/btn_next"
android:text="@string/previous" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:enabled="false"
android:alpha=".5"
android:text="@string/next"
android:textColor="@android:color/white" />
</RelativeLayout>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_previous"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/standard_gap"
android:layout_marginRight="@dimen/standard_gap"
android:layout_toLeftOf="@+id/btn_next"
android:text="@string/previous" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>

View file

@ -689,4 +689,7 @@ Upload your first media by tapping on the add button.</string>
<string name="leaderboard_nearby">Nearby</string>
<string name="leaderboard_used">Used</string>
<string name="leaderboard_my_rank_button_text">My Rank</string>
<string name="mapbox_telemetry">Telemetry Opt Out</string>
<string name="telemetry_opt_out_summary">Send anonymized location and usage data to Mapbox when using Nearby feature</string>
<string name="map_attribution" translatable="false"><![CDATA[&#169; <a href="https://www.mapbox.com/about/maps/">Mapbox</a> &#169; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> <a href="https://www.mapbox.com/map-feedback/">Improve this map</a>]]></string>
</resources>

View file

@ -78,6 +78,13 @@
android:summary="@string/manage_exif_tags_summary"
android:title="@string/manage_exif_tags" />
<SwitchPreference
android:defaultValue="true"
android:key="telemetryOptOut"
app:singleLineTitle="false"
android:summary="@string/telemetry_opt_out_summary"
android:title="@string/mapbox_telemetry" />
</PreferenceCategory>
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.

View file

@ -52,7 +52,6 @@ class CategoryClientTest {
.test()
.assertValues(emptyList())
}
@Test
fun searchCategoriesForPrefixFound() {
val mockResponse = withMockResponse("Category:Test")
@ -78,7 +77,6 @@ class CategoryClientTest {
.test()
.assertValues(emptyList())
}
@Test
fun getParentCategoryListFound() {
val mockResponse = withMockResponse("Category:Test")

View file

@ -194,7 +194,6 @@ class UploadMediaPresenterTest {
@Test
fun handleBadImageBaseTestInvalidLocation() {
uploadMediaPresenter.handleBadImage(8, uploadItem)
verify(jsonKvStore).putBoolean(ArgumentMatchers.anyString(), eq(false))
verify(view).showBadImagePopup(8, uploadItem)
}

View file

@ -43,9 +43,7 @@ class WikidataEditServiceTest {
}
@Test
fun noClaimsWhenLocationIsNotCorrect() {
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
.thenReturn(false)
fun noClaimsWhenEntityIdIsNull() {
wikidataEditService.createClaim(mock(), "Test.jpg", hashMapOf())
verifyZeroInteractions(wikidataClient)
}

View file

@ -26,6 +26,7 @@ CORE_KTX_VERSION=1.2.0
ADAPTER_DELEGATES_VERSION=4.3.0
PAGING_VERSION=2.1.2
MULTIDEX_VERSION=2.0.1
OKHTTP_VERSION=3.12.1
systemProp.http.proxyPort=0
systemProp.http.proxyHost=