From 7476b0a24d1dd14683ee2d775ad7d5a2b8968683 Mon Sep 17 00:00:00 2001 From: Ashish Date: Thu, 16 Sep 2021 18:39:29 +0530 Subject: [PATCH] Merge changes from 3.1-release (#4629) * Cherry-Picked NPE fix from master (#4569) * Fix notification bug #4547 (#4570) * Make Single Query for Nearby and WLM pins (#4573) * Merge nearby and monument queries * Bug Fix- query resource path change on shouldQueryForMonuments * Bug Fixes 1. Propagate exceptions for nearby API calls to caller 2. Fix too much work on main thread exception in NearbyParentFragment * Modify parameters for Nearby query * Bug fix- current location marker (#4580) * Move WLM template below geolocation template (#4582) * Modify string for WLM upload notice * Fix bug #4583 (#4591) * Fix bug #4585 by updating kotlin and acra version (#4592) * Fixes #4554 - only use WLM2021 template for countries that are included in it (#4574) * Fixes #4554 1. For WLM uploads reverse geo code and see if the country code is supported -only then is the WLM upload flow triggered, otherwise usual nearby uploads happen 2. Bug Fix - Current Location marker and area * Fixed compile error added after rebasing * Bug fix for country code in reverse geo code * Update WLM camaign dates [Do not merge now, merge only after alpha release] (#4584) * Updates dates for WML campaign * Bug fix- campaign dates * Fixed logic for WLM enablement - stick to the month of September * Add countries supported by WLM2021 template, except Italy * Versioning for v3.1.0 * Update changelog.md * Fix empty default lang bug (#4608) * Fix bug #4583 * Fix empty default lang bug * Fixes #4595 - Updated nearby query (#4622) * Fixes #4595 - Updated nearby query * Removed logic to replace local language in nearby query - that might acccidentally replace other strings * Fetch property location in usual nearby query * Remove duplicate line (#4626) * Change "learn more" link to new wiki * Add Sweden's P3426 to property filter * Fixes #4601 - 1. Handle possible exceptions in upload file from stash 2. Modify MWException, as error is nullable, update getTitle and getMessage to rever that (#4627) * Versioning for v3.1.1 * Update changelog.md * Updated DB version to rever integrity Co-authored-by: Madhur Gupta <30932899+madhurgupta10@users.noreply.github.com> Co-authored-by: Josephine Lim --- CHANGELOG.md | 9 ++ app/build.gradle | 10 +- .../main/java/fr/free/nrw/commons/Media.kt | 20 ++-- .../main/java/fr/free/nrw/commons/Utils.java | 9 +- .../nrw/commons/campaigns/CampaignView.java | 5 +- .../nrw/commons/contributions/Contribution.kt | 3 +- .../contributions/ContributionsFragment.java | 4 +- .../free/nrw/commons/data/DBOpenHelper.java | 2 +- .../fr/free/nrw/commons/db/AppDatabase.kt | 2 +- .../commons/media/MediaDetailFragment.java | 2 - .../commons/mwapi/OkHttpJsonApiClient.java | 110 +++++------------- .../nrw/commons/nearby/NearbyController.java | 13 +-- .../free/nrw/commons/nearby/NearbyPlaces.java | 35 ++---- .../fragments/NearbyParentFragment.java | 85 +++----------- .../commons/nearby/model/NearbyResultItem.kt | 7 +- .../commons/repository/UploadRepository.java | 13 ++- .../fr/free/nrw/commons/settings/Prefs.java | 2 +- .../commons/settings/SettingsFragment.java | 5 +- .../free/nrw/commons/upload/FileProcessor.kt | 13 ++- .../commons/upload/PageContentsCreator.java | 14 +-- .../free/nrw/commons/upload/UploadClient.java | 8 +- .../free/nrw/commons/upload/UploadItem.java | 19 +++ .../free/nrw/commons/upload/UploadModel.java | 9 ++ .../free/nrw/commons/upload/UploadResponse.kt | 2 +- .../free/nrw/commons/upload/WikidataPlace.kt | 2 +- .../upload/license/MediaLicenseContract.java | 2 + .../upload/license/MediaLicenseFragment.java | 25 ++-- .../upload/license/MediaLicensePresenter.java | 5 + .../mediaDetails/UploadMediaPresenter.java | 51 +++++++- .../nrw/commons/upload/worker/UploadWorker.kt | 45 ++----- app/src/main/res/values/strings.xml | 2 +- .../main/resources/queries/monuments_query.rq | 60 ---------- .../main/resources/queries/nearby_query.rq | 106 ++++++++--------- .../queries/nearby_query_monuments.rq | 68 +++++++++++ data-client/build.gradle | 2 +- .../dataclient/mwapi/MwException.java | 17 ++- gradle.properties | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 38 files changed, 383 insertions(+), 409 deletions(-) delete mode 100644 app/src/main/resources/queries/monuments_query.rq create mode 100644 app/src/main/resources/queries/nearby_query_monuments.rq diff --git a/CHANGELOG.md b/CHANGELOG.md index ba83aa025..405b7d9de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Wikimedia Commons for Android +## v3.1.1 +- Optimized Nearby query +- Added Sweden's property for WLM 2021 +- Added link to wiki explaining how to contribute to WLM through app +- Fixed various bugs and crashes + +## v3.1.0 +- Added Wiki Loves Monuments integration for WLM 2021 + ## v3.0.2 - Fixed crash when uploading high res image - Fixed crash when viewing images in Explore diff --git a/app/build.gradle b/app/build.gradle index 0ccc38f60..65170e1de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,8 +58,8 @@ dependencies { implementation "com.squareup.okhttp3:okhttp-ws:$OKHTTP_VERSION" // Logging - implementation 'ch.acra:acra-dialog:5.8.1-beta11' - implementation 'ch.acra:acra-mail:5.8.1-beta11' + implementation 'ch.acra:acra-dialog:5.8.4' + implementation 'ch.acra:acra-mail:5.8.4' implementation 'org.slf4j:slf4j-api:1.7.25' api('com.github.tony19:logback-android-classic:1.1.1-6') { exclude group: 'com.google.android', module: 'android' @@ -155,8 +155,8 @@ android { defaultConfig { //applicationId 'fr.free.nrw.commons' - versionCode 1021 - versionName '3.0.2' + versionCode 1025 + versionName '3.1.1' setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) minSdkVersion 19 @@ -226,7 +226,7 @@ android { } configurations.all { - resolutionStrategy.force 'androidx.annotation:annotation:1.0.2' + resolutionStrategy.force 'androidx.annotation:annotation:1.1.0' exclude module: 'okhttp-ws' } flavorDimensions 'tier' diff --git a/app/src/main/java/fr/free/nrw/commons/Media.kt b/app/src/main/java/fr/free/nrw/commons/Media.kt index 3987acb37..1a5531e85 100644 --- a/app/src/main/java/fr/free/nrw/commons/Media.kt +++ b/app/src/main/java/fr/free/nrw/commons/Media.kt @@ -12,19 +12,19 @@ class Media constructor( * @return pageId for the current media object * Wikibase Identifier associated with media files */ - val pageId: String = UUID.randomUUID().toString(), - val thumbUrl: String? = null, + var pageId: String = UUID.randomUUID().toString(), + var thumbUrl: String? = null, /** * Gets image URL * @return Image URL */ - val imageUrl: String? = null, + var imageUrl: String? = null, /** * Gets the name of the file. * @return file name as a string */ - val filename: String? = null, + var filename: String? = null, /** * Gets the file description. * @return file description as a string @@ -41,7 +41,7 @@ class Media constructor( * Can be null. * @return upload date as a Date */ - val dateUploaded: Date? = null, + var dateUploaded: Date? = null, /** * Gets the license name of the file. * @return license as a String @@ -52,7 +52,7 @@ class Media constructor( * @param license license name as a String */ var license: String? = null, - val licenseUrl: String? = null, + var licenseUrl: String? = null, /** * Gets the name of the creator of the file. * @return author name as a String @@ -69,15 +69,15 @@ class Media constructor( * Gets the categories the file falls under. * @return file categories as an ArrayList of Strings */ - val categories: List? = null, + var categories: List? = null, /** * Gets the coordinates of where the file was created. * @return file coordinates as a LatLng */ var coordinates: LatLng? = null, - val captions: Map = emptyMap(), - val descriptions: Map = emptyMap(), - val depictionIds: List = emptyList() + var captions: Map = emptyMap(), + var descriptions: Map = emptyMap(), + var depictionIds: List = emptyList() ) : Parcelable { constructor( diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 0abd8d603..70c032d80 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -218,12 +218,11 @@ public class Utils { * @param date * @return */ - public static boolean isMonumentsEnabled(final Date date, final JsonKvStore store){ - if(date.getDay()>=1 && date.getMonth()>=9 && date.getDay()<=31 && date.getMonth()<=10 ){ + public static boolean isMonumentsEnabled(final Date date) { + if (date.getMonth() == 8) { return true; } - - return store.getBoolean(CAMPAIGNS_DEFAULT_PREFERENCE) || true ; + return false; } /** @@ -241,7 +240,7 @@ public class Utils { * @return */ public static String getWLMEndDate() { - return "31 Oct"; + return "30 Sep"; } } diff --git a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java index b641dabd6..b772f19c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java +++ b/app/src/main/java/fr/free/nrw/commons/campaigns/CampaignView.java @@ -117,9 +117,8 @@ public class CampaignView extends SwipableCardView { .parse(campaign.getStartDate()); final Date endDate = CommonsDateUtil.getIso8601DateFormatShort() .parse(campaign.getEndDate()); - tvDates.setText( - String.format("%1s - %2s", startDate, - endDate)); + tvDates.setText(String.format("%1s - %2s", DateUtil.getExtraShortDateString(startDate), + DateUtil.getExtraShortDateString(endDate))); } } catch (final ParseException e) { e.printStackTrace(); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt index 6b895232f..ccb9fd640 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt +++ b/app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt @@ -40,7 +40,8 @@ data class Contribution constructor( var dateCreated: Date? = null, var dateModified: Date? = null, var hasInvalidLocation : Int = 0, - var contentUri: Uri? = null + var contentUri: Uri? = null, + var countryCode : String? = null ) : Parcelable { fun completeWith(media: Media): Contribution { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index 1f5a86a9c..ca1f6d0df 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -454,7 +454,7 @@ public class ContributionsFragment private void updateClosestNearbyCardViewInfo() { curLatLng = locationManager.getLastLocation(); compositeDisposable.add(Observable.fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curLatLng, curLatLng, true, false)) // thanks to boolean, it will only return closest result + .loadAttractionsFromLocation(curLatLng, curLatLng, true, false, false)) // thanks to boolean, it will only return closest result .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::updateNearbyNotification, @@ -528,7 +528,7 @@ public class ContributionsFragment * of campaigns on the campaigns card */ private void fetchCampaigns() { - if (Utils.isMonumentsEnabled(new Date(), store)) { + if (Utils.isMonumentsEnabled(new Date())) { campaignView.setCampaign(wlmCampaign); campaignView.setVisibility(View.VISIBLE); } else if (store.getBoolean(CampaignView.CAMPAIGNS_DEFAULT_PREFERENCE, true)) { diff --git a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java index f9ba4a5ae..2183e6730 100644 --- a/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java +++ b/app/src/main/java/fr/free/nrw/commons/data/DBOpenHelper.java @@ -13,7 +13,7 @@ import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao; public class DBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "commons.db"; - private static final int DATABASE_VERSION = 18; + private static final int DATABASE_VERSION = 19; public static final String CONTRIBUTIONS_TABLE = "contributions"; private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s"; diff --git a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt index 1085865df..57a35ce70 100644 --- a/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt +++ b/app/src/main/java/fr/free/nrw/commons/db/AppDatabase.kt @@ -14,7 +14,7 @@ import fr.free.nrw.commons.upload.depicts.DepictsDao * The database for accessing the respective DAOs * */ -@Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class], version = 9, exportSchema = false) +@Database(entities = [Contribution::class, Depicts::class, UploadedStatus::class], version = 10, exportSchema = false) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun contributionDao(): ContributionDao diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index f7db4574e..ed28960b2 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -373,8 +373,6 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment implements media = getArguments().getParcelable("media"); } - media = detailProvider.getMediaAtPosition(index); - if(media != null && applicationKvStore.getBoolean(String.format(NOMINATING_FOR_DELETION_MEDIA, media.getImageUrl()), false)) { enableProgressBar(); } diff --git a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java index 3f272a41a..3c7bd1f97 100644 --- a/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java +++ b/app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.java @@ -5,6 +5,7 @@ import static fr.free.nrw.commons.profile.leaderboard.LeaderboardConstants.UPDAT import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.gson.Gson; import fr.free.nrw.commons.campaigns.CampaignResponseDTO; import fr.free.nrw.commons.explore.depictions.DepictsClient; @@ -264,107 +265,54 @@ public class OkHttpJsonApiClient { }); } - public Observable> getNearbyPlaces(LatLng cur, String language, double radius) + @Nullable + public List getNearbyPlaces(final LatLng cur, final String language, final double radius, + final boolean shouldQueryForMonuments) throws Exception { Timber.d("Fetching nearby items at radius %s", radius); - String wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq"); - String query = wikidataQuery + final String wikidataQuery; + if (!shouldQueryForMonuments) { + wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq"); + } else { + wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq"); + } + final String query = wikidataQuery .replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius)) .replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude())) .replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude())) .replace("${LANG}", language); - HttpUrl.Builder urlBuilder = HttpUrl + final HttpUrl.Builder urlBuilder = HttpUrl .parse(sparqlQueryUrl) .newBuilder() .addQueryParameter("query", query) .addQueryParameter("format", "json"); - Request request = new Request.Builder() + final Request request = new Request.Builder() .url(urlBuilder.build()) .build(); - return Observable.fromCallable(() -> { - Response response = okHttpClient.newCall(request).execute(); - if (response != null && response.body() != null && response.isSuccessful()) { - String json = response.body().string(); - if (json == null) { - return new ArrayList<>(); + final Response response = okHttpClient.newCall(request).execute(); + if (response.body() != null && response.isSuccessful()) { + final String json = response.body().string(); + final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class); + final List bindings = nearbyResponse.getResults().getBindings(); + final List places = new ArrayList<>(); + for (final NearbyResultItem item : bindings) { + final Place placeFromNearbyItem = Place.from(item); + if (shouldQueryForMonuments && item.getMonument() != null) { + placeFromNearbyItem.setMonument(true); + } else { + placeFromNearbyItem.setMonument(false); } - NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class); - List bindings = nearbyResponse.getResults().getBindings(); - List places = new ArrayList<>(); - for (NearbyResultItem item : bindings) { - places.add(Place.from(item)); - } - return places; + places.add(placeFromNearbyItem); } - return new ArrayList<>(); - }); + return places; + } + throw new Exception(response.message()); } - /** - * Wikidata query to fetch monuments - * - * @param cur : The current location coordinates - * @param language : The language - * @param radius : The radius around the current location within which we expect the results - * @return - * @throws IOException - */ - public Observable> getNearbyMonuments(LatLng cur, String language, final double radius){ - Timber.d("Fetching monuments at radius %s", radius); - final String wikidataQuery; - try { - wikidataQuery = FileUtils.readFromResource("/queries/monuments_query.rq"); - if (TextUtils.isEmpty(language)) { - language = "en"; - } - String query = wikidataQuery - .replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius)) - .replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude())) - .replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude())) - .replace("${LANG}", language); - - HttpUrl.Builder urlBuilder = HttpUrl - .parse(sparqlQueryUrl) - .newBuilder() - .addQueryParameter("query", query) - .addQueryParameter("format", "json"); - - Request request = new Request.Builder() - .url(urlBuilder.build()) - .build(); - - Timber.d("Monuments URL: %s", request.url().toString()); - - return Observable.fromCallable(() -> { - final Response response = okHttpClient.newCall(request).execute(); - if (response != null && response.body() != null && response.isSuccessful()) { - final String json = response.body().string(); - if (json == null) { - return new ArrayList<>(); - } - - final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class); - final List bindings = nearbyResponse.getResults().getBindings(); - final List places = new ArrayList<>(); - for (final NearbyResultItem item : bindings) { - final Place place = Place.from(item); - place.setMonument(true); - places.add(place); - } - return places; - } - return new ArrayList<>(); - }); - } catch (final IOException e) { - e.printStackTrace(); - return Observable.error(e); - } - } - /** * Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example: * bridge -> suspended bridge, aqueduct, etc diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index bd7a61d24..a534273e4 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -57,7 +57,9 @@ public class NearbyController { * @return NearbyPlacesInfo a variable holds Place list without distance information * and boundary coordinates of current Place List */ - public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng, LatLng searchLatLng, boolean returnClosestResult, boolean checkingAroundCurrentLocation) throws IOException { + public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng, final LatLng searchLatLng, + final boolean returnClosestResult, final boolean checkingAroundCurrentLocation, + final boolean shouldQueryForMonuments) throws Exception { Timber.d("Loading attractions near %s", searchLatLng); NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo(); @@ -66,7 +68,9 @@ public class NearbyController { Timber.d("Loading attractions nearby, but curLatLng is null"); return null; } - List places = nearbyPlaces.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult); + List places = nearbyPlaces + .radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult, + shouldQueryForMonuments); if (null != places && places.size() > 0) { LatLng[] boundaryCoordinates = {places.get(0).location, // south @@ -128,11 +132,6 @@ public class NearbyController { } } - public Observable> queryWikiDataForMonuments( - final LatLng latLng, final String language) { - return nearbyPlaces.queryWikiDataForMonuments(latLng, language); - } - /** * Loads attractions from location for list view, we need to return Place data type. * diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java index 1ba3219b1..c7a3dc0fb 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java @@ -1,8 +1,6 @@ package fr.free.nrw.commons.nearby; -import io.reactivex.Observable; import java.io.IOException; -import java.io.InterruptedIOException; import java.util.Collections; import java.util.List; @@ -19,8 +17,8 @@ import timber.log.Timber; @Singleton public class NearbyPlaces { - private static final double INITIAL_RADIUS = 1.0; // in kilometers - private static final double RADIUS_MULTIPLIER = 1.618; + private static final double INITIAL_RADIUS = 0.3; // in kilometers + private static final double RADIUS_MULTIPLIER = 2.0; public double radius = INITIAL_RADIUS; private final OkHttpJsonApiClient okHttpJsonApiClient; @@ -41,12 +39,12 @@ public class NearbyPlaces { * @param lang user's language * @param returnClosestResult true if only the nearest point is desired * @return list of places obtained - * @throws IOException if query fails */ - List radiusExpander(LatLng curLatLng, String lang, boolean returnClosestResult) throws IOException { + List radiusExpander(final LatLng curLatLng, final String lang, final boolean returnClosestResult + , final boolean shouldQueryForMonuments) throws Exception { - int minResults; - double maxRadius; + final int minResults; + final double maxRadius; List places = Collections.emptyList(); @@ -57,19 +55,14 @@ public class NearbyPlaces { maxRadius = 5; // Return places only in 5 km area radius = INITIAL_RADIUS; // refresh radius again, otherwise increased radius is grater than MAX_RADIUS, thus returns null } else { - minResults = 40; + minResults = 20; maxRadius = 300.0; // in kilometers radius = INITIAL_RADIUS; } // Increase the radius gradually to find a satisfactory number of nearby places while (radius <= maxRadius) { - try { - places = getFromWikidataQuery(curLatLng, lang, radius); - } catch (final Exception e) { - Timber.e(e, "Exception in fetching nearby places"); - break; - } + places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments); Timber.d("%d results at radius: %f", places.size(), radius); if (places.size() >= minResults) { break; @@ -89,16 +82,12 @@ public class NearbyPlaces { * @param cur coordinates of search location * @param lang user's language * @param radius radius for search, as determined by radiusExpander() + * @param shouldQueryForMonuments should the query include properites for monuments * @return list of places obtained * @throws IOException if query fails */ - public List getFromWikidataQuery(LatLng cur, String lang, double radius) throws Exception { - return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius).blockingSingle(); - } - - public Observable> queryWikiDataForMonuments( - LatLng latLng, String language) { - return okHttpJsonApiClient - .getNearbyMonuments(latLng, language, radius); + public List getFromWikidataQuery(final LatLng cur, final String lang, + final double radius, final boolean shouldQueryForMonuments) throws Exception { + return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius, shouldQueryForMonuments); } } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java index b007b5f5d..15cd1a997 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java @@ -245,7 +245,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment /** * WLM URL */ - public static final String WLM_URL = "https://www.wikilovesmonuments.org/"; + public static final String WLM_URL = "https://commons.wikimedia.org/wiki/Commons:Mobile_app/Contributing_to_WLM_using_the_app"; @NonNull public static NearbyParentFragment newInstance() { @@ -284,7 +284,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); isDarkTheme = systemThemeUtils.isDeviceInNightMode(); - if (Utils.isMonumentsEnabled(new Date(), applicationKvStore)) { + if (Utils.isMonumentsEnabled(new Date())) { rlContainerWLMMonthMessage.setVisibility(View.VISIBLE); } else { rlContainerWLMMonthMessage.setVisibility(View.GONE); @@ -513,7 +513,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment setBottomSheetCallbacks(); decideButtonVisibilities(); addActionToTitle(); - if(!Utils.isMonumentsEnabled(new Date(), applicationKvStore)){ + if (!Utils.isMonumentsEnabled(new Date())) { chipWlm.setVisibility(View.GONE); } } @@ -883,29 +883,11 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment final Observable nearbyPlacesInfoObservable = Observable .fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curlatLng, searchLatLng, false, true)); + .loadAttractionsFromLocation(curlatLng, searchLatLng, + false, true, Utils.isMonumentsEnabled(new Date()))); - Observable> observableWikidataMonuments = Observable.empty(); - if(Utils.isMonumentsEnabled(new Date(), applicationKvStore)){ - observableWikidataMonuments = - nearbyController - .queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage()); - - } - - compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable - , observableWikidataMonuments.onErrorReturn(throwable -> { - showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable - .getLocalizedMessage()); - return new ArrayList<>(); - }), - (nearbyPlacesInfo, monuments) -> { - final List places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList, - monuments); - nearbyPlacesInfo.placeList.clear(); - nearbyPlacesInfo.placeList.addAll(places); - return nearbyPlacesInfo; - }).subscribeOn(Schedulers.io()) + compositeDisposable.add(nearbyPlacesInfoObservable + .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(nearbyPlacesInfo -> { updateMapMarkers(nearbyPlacesInfo, true); @@ -925,28 +907,11 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment final Observable nearbyPlacesInfoObservable = Observable .fromCallable(() -> nearbyController - .loadAttractionsFromLocation(curlatLng, searchLatLng, false, false)); + .loadAttractionsFromLocation(curlatLng, searchLatLng, + false, true, Utils.isMonumentsEnabled(new Date()))); - Observable> observableWikidataMonuments = Observable.empty(); - if (Utils.isMonumentsEnabled(new Date(), applicationKvStore)) { - observableWikidataMonuments = nearbyController - .queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage()); - - } - - compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable - , observableWikidataMonuments.onErrorReturn(throwable -> { - showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable - .getLocalizedMessage()); - return new ArrayList<>(); - }), - (nearbyPlacesInfo, monuments) -> { - final List places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList, - monuments); - nearbyPlacesInfo.placeList.clear(); - nearbyPlacesInfo.placeList.addAll(places); - return nearbyPlacesInfo; - }).subscribeOn(Schedulers.io()) + compositeDisposable.add(nearbyPlacesInfoObservable + .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(nearbyPlacesInfo -> { updateMapMarkers(nearbyPlacesInfo, false); @@ -961,25 +926,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment })); } - /** - * If a nearby place happens to be a monument as well, don't make the Pin's overlap, instead - * show it as a monument - * - * @param nearbyPlaces - * @param monuments - * @return - */ - private List mergeNearbyPlacesAndMonuments(List nearbyPlaces, List monuments){ - List allPlaces= new ArrayList<>(); - allPlaces.addAll(monuments); - for (Place place : nearbyPlaces){ - if(!allPlaces.contains(place)){ - allPlaces.add(place); - } - } - return allPlaces; - } - /** * Populates places for your location, should be used for finding nearby places around a * location where you are. @@ -1248,8 +1194,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment .position(new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude())); currentLocationMarkerOptions.setIcon(icon); // Set custom icon - mapView.post(() -> currentLocationMarker = mapBox.addMarker(currentLocationMarkerOptions)); - + mapView.post( + () -> currentLocationMarker = mapBox.addMarker(currentLocationMarkerOptions)); final List circle = UiUtils .createCircleArray(curLatLng.getLatitude(), curLatLng.getLongitude(), @@ -1259,8 +1205,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment .addAll(circle) .strokeColor(getResources().getColor(R.color.current_marker_stroke)) .fillColor(getResources().getColor(R.color.current_marker_fill)); - mapView.post(() -> currentLocationPolygon = mapBox.addPolygon(currentLocationPolygonOptions)); - + mapView.post( + () -> currentLocationPolygon = mapBox + .addPolygon(currentLocationPolygonOptions)); }); } else { Timber.d("not adding current location marker..current location is null"); diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/model/NearbyResultItem.kt b/app/src/main/java/fr/free/nrw/commons/nearby/model/NearbyResultItem.kt index fcb6a013b..4da8740cc 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/model/NearbyResultItem.kt +++ b/app/src/main/java/fr/free/nrw/commons/nearby/model/NearbyResultItem.kt @@ -14,7 +14,8 @@ class NearbyResultItem(private val item: ResultTuple?, @field:SerializedName("pic") private val pic: ResultTuple?, @field:SerializedName("destroyed") private val destroyed: ResultTuple?, @field:SerializedName("description") private val description: ResultTuple?, - @field:SerializedName("endTime") private val endTime: ResultTuple?) { + @field:SerializedName("endTime") private val endTime: ResultTuple?, + @field:SerializedName("monument") private val monument: ResultTuple?) { fun getItem(): ResultTuple { return item ?: ResultTuple() @@ -71,4 +72,8 @@ class NearbyResultItem(private val item: ResultTuple?, fun getAddress(): String { return address?.value?:"" } + + fun getMonument():ResultTuple?{ + return monument + } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java index 98a1e9535..843542de6 100644 --- a/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java +++ b/app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java @@ -283,13 +283,14 @@ public class UploadRepository { * @return */ @Nullable - public Place checkNearbyPlaces(double decLatitude, double decLongitude) { + public Place checkNearbyPlaces(final double decLatitude, final double decLongitude) { try { - List fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng( + final List fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng( decLatitude, decLongitude, 0.0f), Locale.getDefault().getLanguage(), - NEARBY_RADIUS_IN_KILO_METERS); - return fromWikidataQuery.size() > 0 ? fromWikidataQuery.get(0) : null; + NEARBY_RADIUS_IN_KILO_METERS, false); + return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery + .get(0) : null; }catch (final Exception e) { Timber.e("Error fetching nearby places: %s", e.getMessage()); return null; @@ -299,4 +300,8 @@ public class UploadRepository { public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) { uploadModel.useSimilarPictureCoordinates(imageCoordinates, uploadItemIndex); } + + public boolean isWMLSupportedForThisPlace() { + return uploadModel.getItems().get(0).isWLMUpload(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java b/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java index f1bc5a8a4..0867aebbc 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/Prefs.java @@ -7,7 +7,7 @@ public class Prefs { public static final String DEFAULT_LICENSE = "defaultLicense"; public static final String UPLOADS_SHOWING = "uploadsshowing"; public static final String MANAGED_EXIF_TAGS = "managed_exif_tags"; - public static final String DESCRIPTION_LANGUAGE = "descriptionLanguage"; + public static final String DESCRIPTION_LANGUAGE = "languageDescription"; public static final String APP_UI_LANGUAGE = "appUiLanguage"; public static final String KEY_THEME_VALUE = "appThemePref"; public static final String TELEMETRY_PREFERENCE = "telemetryPref"; diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index fcc6dc3dd..b0e02cb7b 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -229,7 +229,10 @@ public class SettingsFragment extends PreferenceFragmentCompat { /** * Changing the default app language with selected one and save it to SharedPreferences */ - public void setLocale(final Activity activity, final String userSelectedValue) { + public void setLocale(final Activity activity, String userSelectedValue) { + if (userSelectedValue.equals("")) { + userSelectedValue = Locale.getDefault().getLanguage(); + } final Locale locale = new Locale(userSelectedValue); Locale.setDefault(locale); final Configuration configuration = new Configuration(); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt b/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt index 5ad6952ee..f8744809d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/FileProcessor.kt @@ -199,11 +199,14 @@ class FileProcessor @Inject constructor( private fun suggestNearbyDepictions(imageCoordinates: ImageCoordinates): Disposable { return Observable.fromIterable(radiiProgressionInMetres.map { it / 1000.0 }) .concatMap { - okHttpJsonApiClient.getNearbyPlaces( - imageCoordinates.latLng, - Locale.getDefault().language, - it - ) + Observable.fromCallable { + okHttpJsonApiClient.getNearbyPlaces( + imageCoordinates.latLng, + Locale.getDefault().language, + it, + false + ) + } } .subscribeOn(Schedulers.io()) .filter { it.size >= MIN_NEARBY_RESULTS } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/PageContentsCreator.java b/app/src/main/java/fr/free/nrw/commons/upload/PageContentsCreator.java index dc26b939d..4bf2de027 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/PageContentsCreator.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/PageContentsCreator.java @@ -30,7 +30,7 @@ class PageContentsCreator { this.context = context; } - public String createFrom(final Contribution contribution, final String countryCode) { + public String createFrom(final Contribution contribution) { StringBuilder buffer = new StringBuilder(); final Media media = contribution.getMedia(); buffer @@ -55,18 +55,18 @@ class PageContentsCreator { buffer.append("}}").append("\n"); - if (contribution.getWikidataPlace()!=null && contribution.getWikidataPlace().isMonumentUpload()) { - buffer.append("{{Wiki Loves Monuments 2021|1= ") - .append(countryCode) - .append("}}").append("\n"); - } - //Only add Location template (e.g. {{Location|37.51136|-77.602615}} ) if coords is not null final String decimalCoords = contribution.getDecimalCoords(); if (decimalCoords != null) { buffer.append("{{Location|").append(decimalCoords).append("}}").append("\n"); } + if (contribution.getWikidataPlace()!=null && contribution.getWikidataPlace().isMonumentUpload()) { + buffer.append("{{Wiki Loves Monuments 2021|1= ") + .append(contribution.getCountryCode()) + .append("}}").append("\n"); + } + buffer.append("== {{int:license-header}} ==\n") .append(licenseTemplateFor(media.getLicense())).append("\n\n") .append("{{Uploaded from Mobile|platform=Android|version=") diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java index b717ff276..0577ee39d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadClient.java @@ -210,21 +210,21 @@ public class UploadClient { public Observable uploadFileFromStash( final Contribution contribution, final String uniqueFileName, - final String fileKey, @Nullable String countryCode) { + final String fileKey) { try { return uploadInterface .uploadFileFromStash(csrfTokenClient.getTokenBlocking(), - pageContentsCreator.createFrom(contribution, countryCode), + pageContentsCreator.createFrom(contribution), CommonsApplication.DEFAULT_EDIT_SUMMARY, uniqueFileName, fileKey).map(uploadResponse -> { - UploadResponse uploadResult = gson + final UploadResponse uploadResult = gson .fromJson(uploadResponse, UploadResponse.class); if (uploadResult.getUpload() == null) { final MwException exception = gson .fromJson(uploadResponse, MwException.class); Timber.e(exception, "Error in uploading file from stash"); - throw new RuntimeException(exception.getErrorCode()); + throw new Exception(exception.getErrorCode()); } return uploadResult.getUpload(); }); diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java index 1b482717f..3d0f2066b 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadItem.java @@ -23,6 +23,8 @@ public class UploadItem { private final String createdTimestampSource; private final BehaviorSubject imageQuality; private boolean hasInvalidLocation; + private boolean isWLMUpload = false; + private String countryCode; /** * Uri of uploadItem @@ -102,6 +104,14 @@ public class UploadItem { this.uploadMediaDetails = uploadMediaDetails; } + public void setWLMUpload(final boolean WLMUpload) { + isWLMUpload = WLMUpload; + } + + public boolean isWLMUpload() { + return isWLMUpload; + } + @Override public boolean equals(@Nullable final Object obj) { if (!(obj instanceof UploadItem)) { @@ -136,4 +146,13 @@ public class UploadItem { public boolean hasInvalidLocation() { return hasInvalidLocation; } + + public void setCountryCode(final String countryCode) { + this.countryCode = countryCode; + } + + @Nullable + public String getCountryCode() { + return countryCode; + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java index 1d1b7117f..48da67394 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java @@ -155,6 +155,15 @@ public class UploadModel { contribution.setDateCreatedSource(item.getCreatedTimestampSource()); //Set the date only if you have it, else the upload service is gonna try it the other way } + + if (contribution.getWikidataPlace() != null) { + if (item.isWLMUpload()) { + contribution.getWikidataPlace().setMonumentUpload(true); + } else { + contribution.getWikidataPlace().setMonumentUpload(false); + } + } + contribution.setCountryCode(item.getCountryCode()); return contribution; }); } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadResponse.kt b/app/src/main/java/fr/free/nrw/commons/upload/UploadResponse.kt index 28f83b669..ff9dcc5b7 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadResponse.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadResponse.kt @@ -1,3 +1,3 @@ package fr.free.nrw.commons.upload -class UploadResponse(val upload: UploadResult) \ No newline at end of file +class UploadResponse(val upload: UploadResult?) \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/upload/WikidataPlace.kt b/app/src/main/java/fr/free/nrw/commons/upload/WikidataPlace.kt index 2425d4395..575dffc6d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/WikidataPlace.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/WikidataPlace.kt @@ -12,7 +12,7 @@ data class WikidataPlace( val imageValue: String?, val wikipediaArticle: String?, val location: LatLng? = null, - val isMonumentUpload : Boolean =false + var isMonumentUpload : Boolean =false ) : WikidataItem, Parcelable { constructor(place: Place) : this( diff --git a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseContract.java b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseContract.java index 800888b4e..bdc09ca13 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseContract.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseContract.java @@ -21,6 +21,8 @@ public interface MediaLicenseContract { void getLicenses(); void selectLicense(String licenseName); + + boolean isWLMSupportedForThisPlace(); } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseFragment.java index faaaf2988..9c1f3da48 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicenseFragment.java @@ -90,16 +90,11 @@ public class MediaLicenseFragment extends UploadBaseFragment implements MediaLic initPresenter(); initLicenseSpinner(); presenter.getLicenses(); + } - /** - * Show the wlm info message if the upload is a WLM upload - */ - if(callback.isWLMUpload()){ - //TODO : Update the info message logo - llInfoMonumentUpload.setVisibility(View.VISIBLE); - }else{ - llInfoMonumentUpload.setVisibility(View.GONE); - } + @Override + public void onResume() { + super.onResume(); } /** @@ -229,4 +224,16 @@ public class MediaLicenseFragment extends UploadBaseFragment implements MediaLic callback.onNextButtonClicked(callback.getIndexInViewFlipper(this)); } + @Override + protected void onBecameVisible() { + super.onBecameVisible(); + /** + * Show the wlm info message if the upload is a WLM upload + */ + if(callback.isWLMUpload() && presenter.isWLMSupportedForThisPlace()){ + llInfoMonumentUpload.setVisibility(View.VISIBLE); + }else{ + llInfoMonumentUpload.setVisibility(View.GONE); + } + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicensePresenter.java b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicensePresenter.java index ca6cd4f04..79fdf812a 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicensePresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/license/MediaLicensePresenter.java @@ -74,4 +74,9 @@ public class MediaLicensePresenter implements MediaLicenseContract.UserActionLis repository.setSelectedLicense(licenseName); view.updateLicenseSummary(repository.getSelectedLicense(), repository.getCount()); } + + @Override + public boolean isWLMSupportedForThisPlace() { + return repository.isWMLSupportedForThisPlace(); + } } diff --git a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java index e0e410171..de59a625d 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java @@ -7,9 +7,14 @@ import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS; import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_KEEP; import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK; +import android.location.Address; +import android.location.Geocoder; +import androidx.annotation.Nullable; +import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; import fr.free.nrw.commons.filepicker.UploadableFile; import fr.free.nrw.commons.kvstore.JsonKvStore; +import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.nearby.Place; import fr.free.nrw.commons.repository.UploadRepository; import fr.free.nrw.commons.upload.ImageCoordinates; @@ -22,10 +27,13 @@ import io.reactivex.Maybe; import io.reactivex.Scheduler; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; +import java.io.IOException; import java.lang.reflect.Proxy; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import javax.inject.Inject; import javax.inject.Named; import org.jetbrains.annotations.NotNull; @@ -48,6 +56,8 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt private Scheduler ioScheduler; private Scheduler mainThreadScheduler; + private final List WLM_SUPPORTED_COUNTRIES= Arrays.asList("am","at","az","br","hr","sv","fi","fr","de","gh","in","ie","il","mk","my","mt","pk","pe","pl","ru","rw","si","es","se","tw","ug","ua","us"); + @Inject public UploadMediaPresenter(UploadRepository uploadRepository, @Named("default_preferences") JsonKvStore defaultKVStore, @@ -77,18 +87,31 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt * @param place */ @Override - public void receiveImage(UploadableFile uploadableFile, Place place) { + public void receiveImage(final UploadableFile uploadableFile, final Place place) { view.showProgress(true); compositeDisposable.add( repository .preProcessImage(uploadableFile, place, this) + .map(uploadItem -> { + if(place!=null && place.isMonument()){ + if (place.location != null) { + final String countryCode = reverseGeoCode(place.location); + if (countryCode != null && WLM_SUPPORTED_COUNTRIES + .contains(countryCode.toLowerCase())) { + uploadItem.setWLMUpload(true); + uploadItem.setCountryCode(countryCode.toLowerCase()); + } + } + } + return uploadItem; + }) .subscribeOn(ioScheduler) .observeOn(mainThreadScheduler) .subscribe(uploadItem -> { view.onImageProcessed(uploadItem, place); view.updateMediaDetails(uploadItem.getUploadMediaDetails()); - ImageCoordinates gpsCoords = uploadItem.getGpsCoords(); + final ImageCoordinates gpsCoords = uploadItem.getGpsCoords(); final boolean hasImageCoordinates = gpsCoords != null && gpsCoords.getImageCoordsExists(); view.showMapWithImageCoordinates(hasImageCoordinates); @@ -100,12 +123,32 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt throwable -> Timber.e(throwable, "Error occurred in processing images"))); } + @Nullable + private String reverseGeoCode(final LatLng latLng){ + final Geocoder geocoder = new Geocoder( + CommonsApplication.getInstance().getApplicationContext(), Locale + .getDefault()); + try { + final List
addresses = geocoder + .getFromLocation(latLng.getLatitude(), latLng.getLongitude(), 1); + for (final Address address : addresses) { + if (address != null && address.getCountryCode() != null) { + String countryCode = address.getCountryCode(); + return countryCode; + } + } + } catch (final IOException e) { + Timber.e(e); + } + return null; + } + /** * This method checks for the nearest location that needs images and suggests it to the user. * @param uploadItem */ - private void checkNearbyPlaces(UploadItem uploadItem) { - Disposable checkNearbyPlaces = Maybe.fromCallable(() -> repository + private void checkNearbyPlaces(final UploadItem uploadItem) { + final Disposable checkNearbyPlaces = Maybe.fromCallable(() -> repository .checkNearbyPlaces(uploadItem.getGpsCoords().getDecLatitude(), uploadItem.getGpsCoords().getDecLongitude())) .subscribeOn(ioScheduler) diff --git a/app/src/main/java/fr/free/nrw/commons/upload/worker/UploadWorker.kt b/app/src/main/java/fr/free/nrw/commons/upload/worker/UploadWorker.kt index cec598eaa..c4c5ab89c 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/worker/UploadWorker.kt +++ b/app/src/main/java/fr/free/nrw/commons/upload/worker/UploadWorker.kt @@ -23,6 +23,7 @@ import fr.free.nrw.commons.customselector.database.UploadedStatusDao import fr.free.nrw.commons.di.ApplicationlessInjection import fr.free.nrw.commons.location.LatLng import fr.free.nrw.commons.media.MediaClient +import fr.free.nrw.commons.upload.StashUploadResult import fr.free.nrw.commons.upload.FileUtilsWrapper import fr.free.nrw.commons.upload.StashUploadState import fr.free.nrw.commons.upload.UploadClient @@ -276,7 +277,9 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) : //Upload the file to stash val stashUploadResult = uploadClient.uploadFileToStash( appContext, filename, contribution, notificationProgressUpdater - ).blockingSingle() + ).onErrorReturn{ + return@onErrorReturn StashUploadResult(StashUploadState.FAILED,fileKey = null) + }.blockingSingle() when (stashUploadResult.state) { StashUploadState.SUCCESS -> { @@ -285,22 +288,15 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) : Timber.d("Ensure uniqueness of filename"); val uniqueFileName = findUniqueFileName(filename!!) - try { //Upload the file from stash - var countryCode: String? =null - with(contribution.wikidataPlace?.location){ - if (contribution.wikidataPlace?.isMonumentUpload == true) { - countryCode = - reverseGeoCode(contribution.wikidataPlace?.location!!)?.toLowerCase() - } - - } val uploadResult = uploadClient.uploadFileFromStash( - contribution, uniqueFileName, stashUploadResult.fileKey, countryCode - ).blockingSingle() + contribution, uniqueFileName, stashUploadResult.fileKey + ).onErrorReturn { + return@onErrorReturn null + }.blockingSingle() - if (uploadResult.isSuccessful()) { + if (null != uploadResult && uploadResult.isSuccessful()) { Timber.d( "Stash Upload success..proceeding to make wikidata edit" ) @@ -312,13 +308,13 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) : "WikiDataEdit not required, upload success" ) saveCompletedContribution(contribution,uploadResult) - showSuccessNotification(contribution) }else{ Timber.d( "WikiDataEdit not required, making wikidata edit" ) makeWikiDataEdit(uploadResult, contribution) } + showSuccessNotification(contribution) } else { Timber.e("Stash Upload failed") @@ -333,6 +329,7 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) : Timber.e("Upload from stash failed for contribution : $filename") showFailedNotification(contribution) contribution.state=Contribution.STATE_FAILED + contributionDao.saveSynchronous(contribution) if (STASH_ERROR_CODES.contains(exception.message)) { clearChunks(contribution) } @@ -360,26 +357,6 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) : } } - private fun reverseGeoCode(latLng: LatLng): String? { - - val geocoder = Geocoder( - CommonsApplication.getInstance().applicationContext, Locale - .getDefault() - ) - try { - val addresses = - geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1) - for (address in addresses) { - if (address != null && address.locale.isO3Country != null) { - return address.locale.country - } - } - } catch (e: IOException) { - Timber.e(e) - } - return null - } - private fun clearChunks(contribution: Contribution) { contribution.chunkInfo=null contributionDao.saveSynchronous(contribution) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 599a2a294..2acf08b8f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -650,7 +650,7 @@ Upload your first media by tapping on the add button. Awesome This image has already been uploaded to Commons. WLM - You are contributing to Wiki Loves Monuments Campaign. Related templates will be added accordingly. + This image will be entered into the Wiki Loves Monuments 2021 contest Display monuments It\'s Wiki Loves Monuments month! LEARN MORE diff --git a/app/src/main/resources/queries/monuments_query.rq b/app/src/main/resources/queries/monuments_query.rq deleted file mode 100644 index f7b7621fa..000000000 --- a/app/src/main/resources/queries/monuments_query.rq +++ /dev/null @@ -1,60 +0,0 @@ -SELECT - (SAMPLE(?location) as ?location) - ?item - (SAMPLE(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage)) as ?label) - (SAMPLE(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?")) as ?description) - (SAMPLE(?classId) as ?class) - (SAMPLE(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?")) as ?classLabel) - (SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon) - ?wikipediaArticle - ?commonsArticle - (SAMPLE(?commonsCategory) as ?commonsCategory) - (SAMPLE(?pic) as ?pic) - WHERE { - # Around given location... - SERVICE wikibase:around { - ?item wdt:P625 ?location. - bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. - bd:serviceParam wikibase:radius "${RAD}" . # Radius in kilometers. - } - - { ?item p:P1435 ?monument } UNION { ?item p:P2186 ?monument } UNION { ?item p:P1459 ?monument } UNION { ?item p:P1460 ?monument } UNION { ?item p:P1216 ?monument } UNION { ?item p:P709 ?monument } UNION { ?item p:P718 ?monument } UNION { ?item p:P5694 ?monument } - - # Get Commons category (P373) - OPTIONAL { ?item wdt:P373 ?commonsCategory. } - - # Get (P18) - OPTIONAL { ?item wdt:P18 ?pic. } - - # Get the label in the preferred language of the user, or any other language if no label is available in that language. - OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")} - OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage} - - # Get the description in the preferred language of the user, or any other language if no description is available in that language. - OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")} - OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage } - - # Get the class label in the preferred language of the user, or any other language if no label is available in that language. - OPTIONAL { - ?item p:P31/ps:P31 ?classId. - OPTIONAL {?classId rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "")} - OPTIONAL {?classId rdfs:label ?classLabelAnyLanguage} - - OPTIONAL { - ?wikipediaArticle schema:about ?item ; - schema:isPartOf . - } - OPTIONAL { - ?wikipediaArticle schema:about ?item ; - schema:isPartOf . - SERVICE wikibase:label { bd:serviceParam wikibase:language "en" } - } - - OPTIONAL { - ?commonsArticle schema:about ?item ; - schema:isPartOf . - SERVICE wikibase:label { bd:serviceParam wikibase:language "en" } - } - } - } - GROUP BY ?item ?wikipediaArticle ?commonsArticle \ No newline at end of file diff --git a/app/src/main/resources/queries/nearby_query.rq b/app/src/main/resources/queries/nearby_query.rq index e9648d20e..36da97374 100644 --- a/app/src/main/resources/queries/nearby_query.rq +++ b/app/src/main/resources/queries/nearby_query.rq @@ -1,66 +1,56 @@ SELECT - (SAMPLE(?location) as ?location) - ?item - (SAMPLE(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage)) as ?label) - (SAMPLE(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?")) as ?description) - (SAMPLE(?classId) as ?class) - (SAMPLE(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?")) as ?classLabel) - (SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon) - ?wikipediaArticle - ?commonsArticle - (SAMPLE(?commonsCategory) as ?commonsCategory) - (SAMPLE(?pic) as ?pic) - (SAMPLE(?destroyed) as ?destroyed) - (SAMPLE(?endTime) as ?endTime) - WHERE { - # Around given location... - SERVICE wikibase:around { - ?item wdt:P625 ?location. - bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. - bd:serviceParam wikibase:radius "${RAD}" . # Radius in kilometers. - } + ?item + (SAMPLE(?location) as ?location) + (SAMPLE(?label) AS ?label) + (SAMPLE(?description) AS ?description) + (SAMPLE(?class) AS ?class) + (SAMPLE(?classLabel) AS ?classLabel) + (SAMPLE(?pic) AS ?pic) + (SAMPLE(?destroyed) AS ?destroyed) + (SAMPLE(?endTime) AS ?endTime) + (SAMPLE(?wikipediaArticle) AS ?wikipediaArticle) + (SAMPLE(?commonsArticle) AS ?commonsArticle) + (SAMPLE(?commonsCategory) AS ?commonsCategory) +WHERE { + # Around given location + SERVICE wikibase:around { + ?item wdt:P625 ?location. + bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. # Longitude latitude + bd:serviceParam wikibase:radius "${RAD}". # Radius in kilometers. + } - # Get the label in the preferred language of the user, or any other language if no label is available in that language. - OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")} - OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage} + OPTIONAL { + ?item p:P31/ps:P31 ?class. + } - # Get the description in the preferred language of the user, or any other language if no description is available in that language. - OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")} - OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage } + # Get picture + OPTIONAL {?item wdt:P18 ?pic} - # Get Commons category (P373) - OPTIONAL { ?item wdt:P373 ?commonsCategory. } + # Get existence + OPTIONAL {?item wdt:P576 ?destroyed} + OPTIONAL {?item wdt:P582 ?endTime} - # Get (P18) - OPTIONAL { ?item wdt:P18 ?pic. } + # Get Commons category + OPTIONAL {?item wdt:P373 ?commonsCategory} - # Get (P576) - OPTIONAL { ?item wdt:P576 ?destroyed. } + # Get Wikipedia article + OPTIONAL { + ?wikipediaArticle schema:about ?item. + ?wikipediaArticle schema:isPartOf . + } - # Get (P582) - OPTIONAL { ?item wdt:P582 ?endTime. } + # Get Commons article + OPTIONAL { + ?commonsArticle schema:about ?item. + ?commonsArticle schema:isPartOf . + } - # Get the class label in the preferred language of the user, or any other language if no label is available in that language. - OPTIONAL { - ?item p:P31/ps:P31 ?classId. - OPTIONAL {?classId rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "${LANG}")} - OPTIONAL {?classId rdfs:label ?classLabelAnyLanguage} - - OPTIONAL { - ?wikipediaArticle schema:about ?item ; - schema:isPartOf . - } - OPTIONAL { - ?wikipediaArticle schema:about ?item ; - schema:isPartOf . - SERVICE wikibase:label { bd:serviceParam wikibase:language "en" } - } - - OPTIONAL { - ?commonsArticle schema:about ?item ; - schema:isPartOf . - SERVICE wikibase:label { bd:serviceParam wikibase:language "en" } - } - } - } - GROUP BY ?item ?wikipediaArticle ?commonsArticle \ No newline at end of file + # Labels and descriptions + SERVICE wikibase:label { + bd:serviceParam wikibase:language "${LANG},en,fr,de,es,ja,ru,it,zh,pt,ar,fa,pl,nl,id,uk,he,sv,cs,ko,vi,ca,no,fi,hu,tr,th,hi,bn,ceb,ro,sw,kk,da,eo,sr,lt,sk,bg,sl,eu,et,hr,ms,el,arz,ur,ta,te,nn,gl,az,af,bs,be,ml,ka,is,sq,uz,la,br,mk,lv,azb,mr,sh,tl,cy,ckb,ast,be-tarask,zh-yue,hy,pa,as,my,kn,ne,si,tt,ha,war,zh-min-nan,vo,min,lmo,ht,lb,gu,tg,sco,ku,new,bpy,nds,io,pms,su,oc,jv,nap,ba,scn,wa,bar,an,ksh,szl,fy,frr,als,ia,ga,yi,mg,gd,vec,ce,sa,mai,xmf,sd,wuu,mrj,mhr,km,roa-tara,am,roa-rup,map-bms,bh,mnw,shn,bcl,co,cv,dv,nds-nl,fo,hif,fur,gan,glk,hak,ilo,pam,csb,avk,lij,li,gv,mi,mt,nah,nrm,se,nov,qu,os,pi,pag,ps,pdc,rm,bat-smg,sc,to,tk,hsb,fiu-vro,vls,yo,diq,zh-classical,frp,lad,kw,mn,haw,ang,ln,ie,wo,tpi,ty,crh,nv,jbo,ay,pcd,zea,eml,ky,ig,or,cbk-zam,kg,arc,rmy,ab,gn,so,kab,ug,stq,udm,ext,mzn,pap,cu,sah,tet,sn,lo,pnb,iu,na,got,bo,dsb,chr,cdo,om,sm,ee,ti,av,bm,zu,pnt,cr,pih,ss,ve,bi,rw,ch,xh,kl,ik,bug,dz,ts,tn,kv,tum,xal,st,tw,bxr,ak,ny,fj,lbe,za,ks,ff,lg,sg,rn,chy,mwl,lez,bjn,gom,tyv,vep,nso,kbd,ltg,rue,pfl,gag,koi,krc,ace,olo,kaa,mdf,myv,srn,ady,jam,tcy,dty,atj,kbp,din,lfn,gor,inh,sat,hyw,nqo,ban,szy,awa,ary,lld,smn,skr,mad,dag,shi,nia,ki,gcr". + ?item rdfs:label ?label. + ?item schema:description ?description. + ?class rdfs:label ?classLabel. + } +} +GROUP BY ?item \ No newline at end of file diff --git a/app/src/main/resources/queries/nearby_query_monuments.rq b/app/src/main/resources/queries/nearby_query_monuments.rq new file mode 100644 index 000000000..cd74b4d98 --- /dev/null +++ b/app/src/main/resources/queries/nearby_query_monuments.rq @@ -0,0 +1,68 @@ +SELECT + ?item + (SAMPLE(?location) as ?location) + (SAMPLE(?label) AS ?label) + (SAMPLE(?description) AS ?description) + (SAMPLE(?class) AS ?class) + (SAMPLE(?classLabel) AS ?classLabel) + (SAMPLE(?pic) AS ?pic) + (SAMPLE(?destroyed) AS ?destroyed) + (SAMPLE(?endTime) AS ?endTime) + (SAMPLE(?wikipediaArticle) AS ?wikipediaArticle) + (SAMPLE(?commonsArticle) AS ?commonsArticle) + (SAMPLE(?commonsCategory) AS ?commonsCategory) + (SAMPLE(?monument) AS ?monument) +WHERE { + # Around given location + SERVICE wikibase:around { + ?item wdt:P625 ?location. + bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. # Longitude latitude + bd:serviceParam wikibase:radius "${RAD}". # Radius in kilometers. + } + + OPTIONAL { + ?item p:P31/ps:P31 ?class. + } + + # Get picture + OPTIONAL {?item wdt:P18 ?pic} + + # Get existence + OPTIONAL {?item wdt:P576 ?destroyed} + OPTIONAL {?item wdt:P582 ?endTime} + + # Get Commons category + OPTIONAL {?item wdt:P373 ?commonsCategory} + + # Get Wikipedia article + OPTIONAL { + ?wikipediaArticle schema:about ?item. + ?wikipediaArticle schema:isPartOf . + } + + # Get Commons article + OPTIONAL { + ?commonsArticle schema:about ?item. + ?commonsArticle schema:isPartOf . + } + + # Wiki Loves Monuments + OPTIONAL {?item p:P1435 ?monument} + OPTIONAL {?item p:P2186 ?monument} + OPTIONAL {?item p:P1459 ?monument} + OPTIONAL {?item p:P1460 ?monument} + OPTIONAL {?item p:P1216 ?monument} + OPTIONAL {?item p:P709 ?monument} + OPTIONAL {?item p:P718 ?monument} + OPTIONAL {?item p:P5694 ?monument} + OPTIONAL {?item p:P3426 ?monument} + + # Labels and descriptions + SERVICE wikibase:label { + bd:serviceParam wikibase:language "${LANG},en,fr,de,es,ja,ru,it,zh,pt,ar,fa,pl,nl,id,uk,he,sv,cs,ko,vi,ca,no,fi,hu,tr,th,hi,bn,ceb,ro,sw,kk,da,eo,sr,lt,sk,bg,sl,eu,et,hr,ms,el,arz,ur,ta,te,nn,gl,az,af,bs,be,ml,ka,is,sq,uz,la,br,mk,lv,azb,mr,sh,tl,cy,ckb,ast,be-tarask,zh-yue,hy,pa,as,my,kn,ne,si,tt,ha,war,zh-min-nan,vo,min,lmo,ht,lb,gu,tg,sco,ku,new,bpy,nds,io,pms,su,oc,jv,nap,ba,scn,wa,bar,an,ksh,szl,fy,frr,als,ia,ga,yi,mg,gd,vec,ce,sa,mai,xmf,sd,wuu,mrj,mhr,km,roa-tara,am,roa-rup,map-bms,bh,mnw,shn,bcl,co,cv,dv,nds-nl,fo,hif,fur,gan,glk,hak,ilo,pam,csb,avk,lij,li,gv,mi,mt,nah,nrm,se,nov,qu,os,pi,pag,ps,pdc,rm,bat-smg,sc,to,tk,hsb,fiu-vro,vls,yo,diq,zh-classical,frp,lad,kw,mn,haw,ang,ln,ie,wo,tpi,ty,crh,nv,jbo,ay,pcd,zea,eml,ky,ig,or,cbk-zam,kg,arc,rmy,ab,gn,so,kab,ug,stq,udm,ext,mzn,pap,cu,sah,tet,sn,lo,pnb,iu,na,got,bo,dsb,chr,cdo,om,sm,ee,ti,av,bm,zu,pnt,cr,pih,ss,ve,bi,rw,ch,xh,kl,ik,bug,dz,ts,tn,kv,tum,xal,st,tw,bxr,ak,ny,fj,lbe,za,ks,ff,lg,sg,rn,chy,mwl,lez,bjn,gom,tyv,vep,nso,kbd,ltg,rue,pfl,gag,koi,krc,ace,olo,kaa,mdf,myv,srn,ady,jam,tcy,dty,atj,kbp,din,lfn,gor,inh,sat,hyw,nqo,ban,szy,awa,ary,lld,smn,skr,mad,dag,shi,nia,ki,gcr". + ?item rdfs:label ?label. + ?item schema:description ?description. + ?class rdfs:label ?classLabel. + } +} +GROUP BY ?item \ No newline at end of file diff --git a/data-client/build.gradle b/data-client/build.gradle index 6ec984498..382c1a651 100644 --- a/data-client/build.gradle +++ b/data-client/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.31' + ext.kotlin_version = '1.5.10' repositories { jcenter() google() diff --git a/data-client/src/main/java/org/wikipedia/dataclient/mwapi/MwException.java b/data-client/src/main/java/org/wikipedia/dataclient/mwapi/MwException.java index 51af36196..146b3cdba 100644 --- a/data-client/src/main/java/org/wikipedia/dataclient/mwapi/MwException.java +++ b/data-client/src/main/java/org/wikipedia/dataclient/mwapi/MwException.java @@ -31,11 +31,20 @@ public class MwException extends RuntimeException { return error; } - @Nullable public String getTitle() { - return error.getTitle(); + @Nullable + public String getTitle() { + if (error != null) { + return error.getTitle(); + } + return errors != null ? errors.get(0).getTitle() : null; } - @Override @Nullable public String getMessage() { - return error.getDetails(); + @Override + @Nullable + public String getMessage() { + if (error != null) { + return error.getDetails(); + } + return errors != null ? errors.get(0).getDetails() : null; } } diff --git a/gradle.properties b/gradle.properties index 3a2d71a08..eeac9bd46 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,11 +16,11 @@ org.gradle.jvmargs=-Xmx1536M android.enableBuildCache=true -KOTLIN_VERSION=1.3.72 +KOTLIN_VERSION=1.5.10 BUTTERKNIFE_VERSION=10.1.0 LEAK_CANARY_VERSION=1.6.2 DAGGER_VERSION=2.23 -ROOM_VERSION=2.2.3 +ROOM_VERSION=2.3.0 PREFERENCE_VERSION=1.1.0 CORE_KTX_VERSION=1.2.0 ADAPTER_DELEGATES_VERSION=4.3.0 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cdd4b5409..0a47110a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip +distributionUrl=https://services.gradle.org/distributions/gradle-6.9-all.zip