Skip to content

Commit d7adc2e

Browse files
authored
Merge pull request #2 from commons-app/main
Update 2
2 parents 4db8589 + 86cdf96 commit d7adc2e

File tree

56 files changed

+2185
-2148
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2185
-2148
lines changed

app/src/main/java/fr/free/nrw/commons/contributions/Contribution.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ data class Contribution constructor(
6363
Media(
6464
formatCaptions(item.uploadMediaDetails),
6565
categories,
66-
item.fileName,
66+
item.filename,
6767
formatDescriptions(item.uploadMediaDetails),
6868
sessionManager.userName,
6969
sessionManager.userName,
7070
),
7171
localUri = item.mediaUri,
72-
decimalCoords = item.gpsCoords.decimalCoords,
72+
decimalCoords = item.gpsCoords?.decimalCoords,
7373
dateCreatedSource = "",
7474
depictedItems = depictedItems,
7575
wikidataPlace = from(item.place),

app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import android.graphics.drawable.Drawable;
1818
import android.location.Location;
1919
import android.location.LocationManager;
20+
import android.os.Build;
2021
import android.os.Bundle;
2122
import android.preference.PreferenceManager;
2223
import android.text.Html;
@@ -167,7 +168,11 @@ public View onCreateView(
167168
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
168169
super.onViewCreated(view, savedInstanceState);
169170
setSearchThisAreaButtonVisibility(false);
170-
binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
171+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
172+
binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution), Html.FROM_HTML_MODE_LEGACY));
173+
} else {
174+
binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
175+
}
171176
initNetworkBroadCastReceiver();
172177
locationPermissionsHelper = new LocationPermissionsHelper(getActivity(),locationManager,this);
173178
if (presenter == null) {

app/src/main/java/fr/free/nrw/commons/feedback/FeedbackDialog.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fr.free.nrw.commons.feedback
22

33
import android.app.Dialog
44
import android.content.Context
5+
import android.os.Build
56
import android.os.Bundle
67
import android.text.Html
78
import android.text.Spanned
@@ -26,11 +27,13 @@ class FeedbackDialog(
2627
private val onFeedbackSubmitCallback: OnFeedbackSubmitCallback) : Dialog(context) {
2728
private var _binding: DialogFeedbackBinding? = null
2829
private val binding get() = _binding!!
29-
// TODO("Remove Deprecation") Issue : #6002
30-
// 'fromHtml(String!): Spanned!' is deprecated. Deprecated in Java
31-
@Suppress("DEPRECATION")
32-
private var feedbackDestinationHtml: Spanned = Html.fromHtml(
33-
context.getString(R.string.feedback_destination_note))
30+
// Refactored to handle deprecation for Html.fromHtml()
31+
private var feedbackDestinationHtml: Spanned = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
32+
Html.fromHtml(context.getString(R.string.feedback_destination_note), Html.FROM_HTML_MODE_LEGACY)
33+
} else {
34+
@Suppress("DEPRECATION")
35+
Html.fromHtml(context.getString(R.string.feedback_destination_note))
36+
}
3437

3538

3639
public override fun onCreate(savedInstanceState: Bundle?) {

app/src/main/java/fr/free/nrw/commons/filepicker/MimeTypeMapWrapper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class MimeTypeMapWrapper {
1313
)
1414

1515
@JvmStatic
16-
fun getExtensionFromMimeType(mimeType: String): String? {
16+
fun getExtensionFromMimeType(mimeType: String?): String? {
1717
val result = sMimeTypeToExtensionMap[mimeType]
1818
if (result != null) {
1919
return result

app/src/main/java/fr/free/nrw/commons/mwapi/OkHttpJsonApiClient.kt

Lines changed: 115 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fr.free.nrw.commons.mwapi
22

33
import android.text.TextUtils
44
import com.google.gson.Gson
5+
import com.google.gson.JsonParser
56
import fr.free.nrw.commons.BuildConfig
67
import fr.free.nrw.commons.campaigns.CampaignResponseDTO
78
import fr.free.nrw.commons.explore.depictions.DepictsClient
@@ -10,6 +11,7 @@ import fr.free.nrw.commons.fileusages.GlobalFileUsagesResponse
1011
import fr.free.nrw.commons.location.LatLng
1112
import fr.free.nrw.commons.nearby.Place
1213
import fr.free.nrw.commons.nearby.model.ItemsClass
14+
import fr.free.nrw.commons.nearby.model.NearbyQueryParams
1315
import fr.free.nrw.commons.nearby.model.NearbyResponse
1416
import fr.free.nrw.commons.nearby.model.PlaceBindings
1517
import fr.free.nrw.commons.profile.achievements.FeaturedImages
@@ -330,36 +332,130 @@ class OkHttpJsonApiClient @Inject constructor(
330332
throw Exception(response.message)
331333
}
332334

335+
/**
336+
* Returns the count of items in the specified area by querying Wikidata.
337+
*
338+
* @param queryParams: a `NearbyQueryParam` specifying the geographical area.
339+
* @return The count of items in the specified area.
340+
*/
341+
@Throws(Exception::class)
342+
fun getNearbyItemCount(
343+
queryParams: NearbyQueryParams
344+
): Int {
345+
val wikidataQuery: String = when (queryParams) {
346+
is NearbyQueryParams.Rectangular -> {
347+
val westCornerLat = queryParams.screenTopRight.latitude
348+
val westCornerLong = queryParams.screenTopRight.longitude
349+
val eastCornerLat = queryParams.screenBottomLeft.latitude
350+
val eastCornerLong = queryParams.screenBottomLeft.longitude
351+
FileUtils.readFromResource("/queries/rectangle_query_for_item_count.rq")
352+
.replace("\${LAT_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLat))
353+
.replace("\${LONG_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLong))
354+
.replace("\${LAT_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLat))
355+
.replace("\${LONG_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLong))
356+
}
357+
358+
is NearbyQueryParams.Radial -> {
359+
FileUtils.readFromResource("/queries/radius_query_for_item_count.rq")
360+
.replace(
361+
"\${LAT}",
362+
String.format(Locale.ROOT, "%.4f", queryParams.center.latitude)
363+
)
364+
.replace(
365+
"\${LONG}",
366+
String.format(Locale.ROOT, "%.4f", queryParams.center.longitude)
367+
)
368+
.replace("\${RAD}", String.format(Locale.ROOT, "%.2f", queryParams.radiusInKm))
369+
}
370+
}
371+
372+
val urlBuilder: HttpUrl.Builder = sparqlQueryUrl.toHttpUrlOrNull()!!
373+
.newBuilder()
374+
.addQueryParameter("query", wikidataQuery)
375+
.addQueryParameter("format", "json")
376+
377+
val request: Request = Request.Builder()
378+
.url(urlBuilder.build())
379+
.build()
380+
381+
val response = okHttpClient.newCall(request).execute()
382+
if (response.body != null && response.isSuccessful) {
383+
val json = response.body!!.string()
384+
return JsonParser.parseString(json).getAsJsonObject().getAsJsonObject("results")
385+
.getAsJsonArray("bindings").get(0).getAsJsonObject().getAsJsonObject("itemCount")
386+
.get("value").asInt
387+
}
388+
throw Exception(response.message)
389+
}
390+
333391
@Throws(Exception::class)
334392
fun getNearbyPlaces(
335-
screenTopRight: LatLng,
336-
screenBottomLeft: LatLng, language: String,
393+
queryParams: NearbyQueryParams, language: String,
337394
shouldQueryForMonuments: Boolean, customQuery: String?
338395
): List<Place>? {
339396
Timber.d("CUSTOM_SPARQL: %s", (customQuery != null).toString())
340397

398+
val locale = Locale.ROOT;
341399
val wikidataQuery: String = if (customQuery != null) {
342-
customQuery
343-
} else if (!shouldQueryForMonuments) {
344-
FileUtils.readFromResource("/queries/rectangle_query_for_nearby.rq")
345-
} else {
346-
FileUtils.readFromResource("/queries/rectangle_query_for_nearby_monuments.rq")
347-
}
400+
when (queryParams) {
401+
is NearbyQueryParams.Rectangular -> {
402+
val westCornerLat = queryParams.screenTopRight.latitude
403+
val westCornerLong = queryParams.screenTopRight.longitude
404+
val eastCornerLat = queryParams.screenBottomLeft.latitude
405+
val eastCornerLong = queryParams.screenBottomLeft.longitude
406+
customQuery
407+
.replace("\${LAT_WEST}", String.format(locale, "%.4f", westCornerLat))
408+
.replace("\${LONG_WEST}", String.format(locale, "%.4f", westCornerLong))
409+
.replace("\${LAT_EAST}", String.format(locale, "%.4f", eastCornerLat))
410+
.replace("\${LONG_EAST}", String.format(locale, "%.4f", eastCornerLong))
411+
.replace("\${LANG}", language)
412+
}
413+
is NearbyQueryParams.Radial -> {
414+
Timber.e(
415+
"%s%s",
416+
"okHttpJsonApiClient.getNearbyPlaces invoked with custom query",
417+
"and radial coordinates. This is currently not supported."
418+
)
419+
""
420+
}
421+
}
422+
} else when (queryParams) {
423+
is NearbyQueryParams.Radial -> {
424+
val placeHolderQuery: String = if (!shouldQueryForMonuments) {
425+
FileUtils.readFromResource("/queries/radius_query_for_nearby.rq")
426+
} else {
427+
FileUtils.readFromResource("/queries/radius_query_for_nearby_monuments.rq")
428+
}
429+
placeHolderQuery.replace(
430+
"\${LAT}", String.format(locale, "%.4f", queryParams.center.latitude)
431+
).replace(
432+
"\${LONG}", String.format(locale, "%.4f", queryParams.center.longitude)
433+
)
434+
.replace("\${RAD}", String.format(locale, "%.2f", queryParams.radiusInKm))
435+
}
348436

349-
val westCornerLat = screenTopRight.latitude
350-
val westCornerLong = screenTopRight.longitude
351-
val eastCornerLat = screenBottomLeft.latitude
352-
val eastCornerLong = screenBottomLeft.longitude
437+
is NearbyQueryParams.Rectangular -> {
438+
val placeHolderQuery: String = if (!shouldQueryForMonuments) {
439+
FileUtils.readFromResource("/queries/rectangle_query_for_nearby.rq")
440+
} else {
441+
FileUtils.readFromResource("/queries/rectangle_query_for_nearby_monuments.rq")
442+
}
443+
val westCornerLat = queryParams.screenTopRight.latitude
444+
val westCornerLong = queryParams.screenTopRight.longitude
445+
val eastCornerLat = queryParams.screenBottomLeft.latitude
446+
val eastCornerLong = queryParams.screenBottomLeft.longitude
447+
placeHolderQuery
448+
.replace("\${LAT_WEST}", String.format(locale, "%.4f", westCornerLat))
449+
.replace("\${LONG_WEST}", String.format(locale, "%.4f", westCornerLong))
450+
.replace("\${LAT_EAST}", String.format(locale, "%.4f", eastCornerLat))
451+
.replace("\${LONG_EAST}", String.format(locale, "%.4f", eastCornerLong))
452+
.replace("\${LANG}", language)
453+
}
454+
}
353455

354-
val query = wikidataQuery
355-
.replace("\${LAT_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLat))
356-
.replace("\${LONG_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLong))
357-
.replace("\${LAT_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLat))
358-
.replace("\${LONG_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLong))
359-
.replace("\${LANG}", language)
360456
val urlBuilder: HttpUrl.Builder = sparqlQueryUrl.toHttpUrlOrNull()!!
361457
.newBuilder()
362-
.addQueryParameter("query", query)
458+
.addQueryParameter("query", wikidataQuery)
363459
.addQueryParameter("format", "json")
364460

365461
val request: Request = Request.Builder()

app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,9 @@ public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng currentLatLng,
205205
return null;
206206
}
207207

208-
List<Place> places = nearbyPlaces.getFromWikidataQuery(screenTopRight, screenBottomLeft,
209-
Locale.getDefault().getLanguage(), shouldQueryForMonuments, customQuery);
208+
List<Place> places = nearbyPlaces.getFromWikidataQuery(currentLatLng, screenTopRight,
209+
screenBottomLeft, Locale.getDefault().getLanguage(), shouldQueryForMonuments,
210+
customQuery);
210211

211212
if (null != places && places.size() > 0) {
212213
LatLng[] boundaryCoordinates = {

app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package fr.free.nrw.commons.nearby;
22

3+
import android.location.Location;
34
import androidx.annotation.Nullable;
5+
import fr.free.nrw.commons.nearby.model.NearbyQueryParams;
46
import java.io.IOException;
57
import java.util.Collections;
68
import java.util.List;
@@ -101,6 +103,7 @@ public List<Place> getFromWikidataQuery(final LatLng cur, final String lang,
101103
* Retrieves a list of places from a Wikidata query based on screen coordinates and optional
102104
* parameters.
103105
*
106+
* @param centerPoint The center of the map, used for radius queries if required.
104107
* @param screenTopRight The top right corner of the screen (latitude, longitude).
105108
* @param screenBottomLeft The bottom left corner of the screen (latitude, longitude).
106109
* @param lang The language for the query.
@@ -111,13 +114,70 @@ public List<Place> getFromWikidataQuery(final LatLng cur, final String lang,
111114
* @throws Exception If an error occurs during the retrieval process.
112115
*/
113116
public List<Place> getFromWikidataQuery(
117+
final fr.free.nrw.commons.location.LatLng centerPoint,
114118
final fr.free.nrw.commons.location.LatLng screenTopRight,
115119
final fr.free.nrw.commons.location.LatLng screenBottomLeft, final String lang,
116120
final boolean shouldQueryForMonuments,
117121
@Nullable final String customQuery) throws Exception {
118-
return okHttpJsonApiClient
119-
.getNearbyPlaces(screenTopRight, screenBottomLeft, lang, shouldQueryForMonuments,
120-
customQuery);
122+
if (customQuery != null) {
123+
return okHttpJsonApiClient
124+
.getNearbyPlaces(
125+
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang,
126+
shouldQueryForMonuments,
127+
customQuery);
128+
}
129+
130+
final int lowerLimit = 1000, upperLimit = 1500;
131+
132+
final float[] results = new float[1];
133+
Location.distanceBetween(centerPoint.getLatitude(), screenTopRight.getLongitude(),
134+
centerPoint.getLatitude(), screenBottomLeft.getLongitude(), results);
135+
final float longGap = results[0] / 1000f;
136+
Location.distanceBetween(screenTopRight.getLatitude(), centerPoint.getLongitude(),
137+
screenBottomLeft.getLatitude(), centerPoint.getLongitude(), results);
138+
final float latGap = results[0] / 1000f;
139+
140+
if (Math.max(longGap, latGap) < 100f) {
141+
final int itemCount = okHttpJsonApiClient.getNearbyItemCount(
142+
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft));
143+
if (itemCount < upperLimit) {
144+
return okHttpJsonApiClient.getNearbyPlaces(
145+
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang,
146+
shouldQueryForMonuments, null);
147+
}
148+
}
149+
150+
// minRadius, targetRadius and maxRadius are radii in decameters
151+
// unlike other radii here, which are in kilometers, to avoid looping over
152+
// floating point values
153+
int minRadius = 0, maxRadius = Math.round(Math.min(300f, Math.min(longGap, latGap))) * 100;
154+
int targetRadius = maxRadius / 2;
155+
while (minRadius < maxRadius) {
156+
targetRadius = minRadius + (maxRadius - minRadius + 1) / 2;
157+
final int itemCount = okHttpJsonApiClient.getNearbyItemCount(
158+
new NearbyQueryParams.Radial(centerPoint, targetRadius / 100f));
159+
if (itemCount >= lowerLimit && itemCount < upperLimit) {
160+
break;
161+
}
162+
if (targetRadius > maxRadius / 2 && itemCount < lowerLimit / 5) { // fast forward
163+
minRadius = targetRadius;
164+
targetRadius = minRadius + (maxRadius - minRadius + 1) / 2;
165+
minRadius = targetRadius;
166+
if (itemCount < lowerLimit / 10 && minRadius < maxRadius) { // fast forward again
167+
targetRadius = minRadius + (maxRadius - minRadius + 1) / 2;
168+
minRadius = targetRadius;
169+
}
170+
continue;
171+
}
172+
if (itemCount < upperLimit) {
173+
minRadius = targetRadius;
174+
} else {
175+
maxRadius = targetRadius - 1;
176+
}
177+
}
178+
return okHttpJsonApiClient.getNearbyPlaces(
179+
new NearbyQueryParams.Radial(centerPoint, targetRadius / 100f), lang, shouldQueryForMonuments,
180+
null);
121181
}
122182

123183
/**

0 commit comments

Comments
 (0)