mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-29 05:43:55 +01:00
Use JSON SPARQL query for fetching nearby places (#2398)
* Use JSON response for nearby places * Move okhttp calls to a different class * wip * Fetch picture of the day using JSON API * Search images using JSON APIs * tests * Fix injection based on code review comments
This commit is contained in:
parent
323527b3be
commit
f12837650a
44 changed files with 1472 additions and 418 deletions
|
|
@ -112,7 +112,7 @@ public class NearbyController {
|
|||
* @param placeList list of nearby places in Place data type
|
||||
* @return Place list that holds nearby places
|
||||
*/
|
||||
public static List<Place> loadAttractionsFromLocationToPlaces(
|
||||
static List<Place> loadAttractionsFromLocationToPlaces(
|
||||
LatLng curLatLng,
|
||||
List<Place> placeList) {
|
||||
placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS));
|
||||
|
|
|
|||
|
|
@ -1,49 +1,37 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import fr.free.nrw.commons.Utils;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Handles the Wikidata query to obtain Places around search location
|
||||
*/
|
||||
@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 Uri WIKIDATA_QUERY_URL = Uri.parse("https://query.wikidata.org/sparql");
|
||||
private static final Uri WIKIDATA_QUERY_UI_URL = Uri.parse("https://query.wikidata.org/");
|
||||
private final String wikidataQuery;
|
||||
public double radius = INITIAL_RADIUS;
|
||||
|
||||
private final OkHttpJsonApiClient okHttpJsonApiClient;
|
||||
|
||||
/**
|
||||
* Reads Wikidata query to check nearby wikidata items which needs picture, with a circular
|
||||
* search. As a point is center of a circle with a radius will be set later.
|
||||
* @param okHttpJsonApiClient
|
||||
*/
|
||||
public NearbyPlaces() {
|
||||
try {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
||||
Timber.v(wikidataQuery);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@Inject
|
||||
public NearbyPlaces(OkHttpJsonApiClient okHttpJsonApiClient) {
|
||||
this.okHttpJsonApiClient = okHttpJsonApiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -104,81 +92,6 @@ public class NearbyPlaces {
|
|||
* @throws IOException if query fails
|
||||
*/
|
||||
private List<Place> getFromWikidataQuery(LatLng cur, String lang, double radius) throws IOException {
|
||||
List<Place> places = new ArrayList<>();
|
||||
|
||||
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}", lang);
|
||||
|
||||
Timber.v("# Wikidata query: \n" + query);
|
||||
|
||||
// format as a URL
|
||||
Timber.d(WIKIDATA_QUERY_UI_URL.buildUpon().fragment(query).build().toString());
|
||||
String url = WIKIDATA_QUERY_URL.buildUpon().appendQueryParameter("query", query).build().toString();
|
||||
URLConnection conn = new URL(url).openConnection();
|
||||
conn.setRequestProperty("Accept", "text/tab-separated-values");
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
|
||||
String line;
|
||||
Timber.d("Reading from query result...");
|
||||
while ((line = in.readLine()) != null) {
|
||||
Timber.v(line);
|
||||
line = line + "\n"; // to pad columns and make fields a fixed size
|
||||
if (!line.startsWith("\"Point")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] fields = line.split("\t");
|
||||
Timber.v("Fields: " + Arrays.toString(fields));
|
||||
String point = fields[0];
|
||||
String wikiDataLink = Utils.stripLocalizedString(fields[1]);
|
||||
String name = Utils.stripLocalizedString(fields[2]);
|
||||
|
||||
//getting icon link here
|
||||
String identifier = Utils.stripLocalizedString(fields[3]);
|
||||
//getting the ID which is at the end of link
|
||||
identifier = identifier.split("/")[Utils.stripLocalizedString(fields[3]).split("/").length-1];
|
||||
//replaced the extra > char from fields
|
||||
identifier = identifier.replace(">","");
|
||||
|
||||
String type = Utils.stripLocalizedString(fields[4]);
|
||||
String icon = fields[5];
|
||||
String wikipediaSitelink = Utils.stripLocalizedString(fields[7]);
|
||||
String commonsSitelink = Utils.stripLocalizedString(fields[8]);
|
||||
String category = Utils.stripLocalizedString(fields[9]);
|
||||
Timber.v("Name: " + name + ", type: " + type + ", category: " + category + ", wikipediaSitelink: " + wikipediaSitelink + ", commonsSitelink: " + commonsSitelink);
|
||||
|
||||
double latitude;
|
||||
double longitude;
|
||||
Matcher matcher = Pattern.compile("Point\\(([^ ]+) ([^ ]+)\\)").matcher(point);
|
||||
if (!matcher.find()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
longitude = Double.parseDouble(matcher.group(1));
|
||||
latitude = Double.parseDouble(matcher.group(2));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("LatLng parse error: " + point);
|
||||
}
|
||||
|
||||
places.add(new Place(
|
||||
name,
|
||||
Label.fromText(identifier), // list
|
||||
type, // details
|
||||
Uri.parse(icon),
|
||||
new LatLng(latitude, longitude, 0),
|
||||
category,
|
||||
new Sitelinks.Builder()
|
||||
.setWikipediaLink(wikipediaSitelink)
|
||||
.setCommonsLink(commonsSitelink)
|
||||
.setWikidataLink(wikiDataLink)
|
||||
.build()
|
||||
));
|
||||
}
|
||||
in.close();
|
||||
|
||||
return places;
|
||||
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius).blockingSingle();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ import android.os.Parcelable;
|
|||
import android.support.annotation.Nullable;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.nearby.model.NearbyResultItem;
|
||||
import fr.free.nrw.commons.utils.PlaceUtils;
|
||||
import fr.free.nrw.commons.utils.StringUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
|
|
@ -48,6 +51,26 @@ public class Place implements Parcelable {
|
|||
this.siteLinks = in.readParcelable(Sitelinks.class.getClassLoader());
|
||||
}
|
||||
|
||||
public static Place from(NearbyResultItem item) {
|
||||
String itemClass = item.getClassName().getValue();
|
||||
String classEntityId = "";
|
||||
if(!StringUtils.isNullOrWhiteSpace(itemClass)) {
|
||||
classEntityId = itemClass.replace("http://www.wikidata.org/entity/", "");
|
||||
}
|
||||
return new Place(
|
||||
item.getLabel().getValue(),
|
||||
Label.fromText(classEntityId), // list
|
||||
item.getClassLabel().getValue(), // details
|
||||
Uri.parse(item.getIcon().getValue()),
|
||||
PlaceUtils.latLngFromPointString(item.getLocation().getValue()),
|
||||
item.getCommonsCategory().getValue(),
|
||||
new Sitelinks.Builder()
|
||||
.setWikipediaLink(item.getWikipediaArticle().getValue())
|
||||
.setCommonsLink(item.getCommonsArticle().getValue())
|
||||
.setWikidataLink(item.getItem().getValue())
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the place
|
||||
* @return name
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import android.widget.ImageView;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.pedrogomez.renderers.Renderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -43,7 +44,7 @@ public class PlaceRenderer extends Renderer<Place> {
|
|||
@BindView(R.id.tvName) TextView tvName;
|
||||
@BindView(R.id.tvDesc) TextView tvDesc;
|
||||
@BindView(R.id.distance) TextView distance;
|
||||
@BindView(R.id.icon) ImageView icon;
|
||||
@BindView(R.id.icon) SimpleDraweeView icon;
|
||||
@BindView(R.id.buttonLayout) LinearLayout buttonLayout;
|
||||
@BindView(R.id.cameraButton) LinearLayout cameraButton;
|
||||
|
||||
|
|
@ -215,7 +216,9 @@ public class PlaceRenderer extends Renderer<Place> {
|
|||
}
|
||||
tvDesc.setText(descriptionText);
|
||||
distance.setText(place.distance);
|
||||
icon.setImageResource(place.getLabel().getIcon());
|
||||
|
||||
|
||||
icon.setImageURI(place.getSecondaryImageUrl());
|
||||
|
||||
directionsButton.setOnClickListener(view -> {
|
||||
//Open map app at given position
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package fr.free.nrw.commons.nearby.model;
|
||||
|
||||
public class NearbyResponse {
|
||||
private final NearbyResults results;
|
||||
|
||||
public NearbyResponse(NearbyResults results) {
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public NearbyResults getResults() {
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package fr.free.nrw.commons.nearby.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class NearbyResultItem {
|
||||
private final ResultTuple item;
|
||||
private final ResultTuple wikipediaArticle;
|
||||
private final ResultTuple commonsArticle;
|
||||
private final ResultTuple location;
|
||||
private final ResultTuple label;
|
||||
private final ResultTuple icon;
|
||||
@SerializedName("class") private final ResultTuple className;
|
||||
@SerializedName("class_label") private final ResultTuple classLabel;
|
||||
@SerializedName("Commons_category") private final ResultTuple commonsCategory;
|
||||
|
||||
public NearbyResultItem(ResultTuple item,
|
||||
ResultTuple wikipediaArticle,
|
||||
ResultTuple commonsArticle,
|
||||
ResultTuple location,
|
||||
ResultTuple label,
|
||||
ResultTuple icon, ResultTuple className,
|
||||
ResultTuple classLabel,
|
||||
ResultTuple commonsCategory) {
|
||||
this.item = item;
|
||||
this.wikipediaArticle = wikipediaArticle;
|
||||
this.commonsArticle = commonsArticle;
|
||||
this.location = location;
|
||||
this.label = label;
|
||||
this.icon = icon;
|
||||
this.className = className;
|
||||
this.classLabel = classLabel;
|
||||
this.commonsCategory = commonsCategory;
|
||||
}
|
||||
|
||||
public ResultTuple getItem() {
|
||||
return item == null ? new ResultTuple(): item;
|
||||
}
|
||||
|
||||
public ResultTuple getWikipediaArticle() {
|
||||
return wikipediaArticle == null ? new ResultTuple():wikipediaArticle;
|
||||
}
|
||||
|
||||
public ResultTuple getCommonsArticle() {
|
||||
return commonsArticle == null ? new ResultTuple():commonsArticle;
|
||||
}
|
||||
|
||||
public ResultTuple getLocation() {
|
||||
return location == null ? new ResultTuple():location;
|
||||
}
|
||||
|
||||
public ResultTuple getLabel() {
|
||||
return label == null ? new ResultTuple():label;
|
||||
}
|
||||
|
||||
public ResultTuple getIcon() {
|
||||
return icon == null ? new ResultTuple():icon;
|
||||
}
|
||||
|
||||
public ResultTuple getClassName() {
|
||||
return className == null ? new ResultTuple():className;
|
||||
}
|
||||
|
||||
public ResultTuple getClassLabel() {
|
||||
return classLabel == null ? new ResultTuple():classLabel;
|
||||
}
|
||||
|
||||
public ResultTuple getCommonsCategory() {
|
||||
return commonsCategory == null ? new ResultTuple():commonsCategory;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.nearby.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NearbyResults {
|
||||
private final List<NearbyResultItem> bindings;
|
||||
|
||||
public NearbyResults(List<NearbyResultItem> bindings) {
|
||||
this.bindings = bindings;
|
||||
}
|
||||
|
||||
public List<NearbyResultItem> getBindings() {
|
||||
return bindings;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package fr.free.nrw.commons.nearby.model;
|
||||
|
||||
public class ResultTuple {
|
||||
private final String type;
|
||||
private final String value;
|
||||
|
||||
public ResultTuple(String type, String value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public ResultTuple() {
|
||||
this.type = "";
|
||||
this.value = "";
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue