Merge branch 'master' into set_upload_limit
|
|
@ -84,9 +84,9 @@ public class SettingsActivityTest {
|
||||||
.atPosition(0)
|
.atPosition(0)
|
||||||
.perform(ViewActions.click());
|
.perform(ViewActions.click());
|
||||||
|
|
||||||
// click "CC BY-4.0"
|
// click "Attribution 4.0"
|
||||||
Espresso.onView(
|
Espresso.onView(
|
||||||
ViewMatchers.withText(R.string.license_name_cc_by_4_0)
|
ViewMatchers.withText(R.string.license_name_cc_by_four)
|
||||||
).perform(ViewActions.click());
|
).perform(ViewActions.click());
|
||||||
|
|
||||||
// click "License" (the first item)
|
// click "License" (the first item)
|
||||||
|
|
@ -95,10 +95,10 @@ public class SettingsActivityTest {
|
||||||
.atPosition(0)
|
.atPosition(0)
|
||||||
.perform(ViewActions.click());
|
.perform(ViewActions.click());
|
||||||
|
|
||||||
// test the value remains "CC BY-4.0"
|
// test the value remains "Attribution 4.0"
|
||||||
Espresso.onView(ViewMatchers.isChecked())
|
Espresso.onView(ViewMatchers.isChecked())
|
||||||
.check(ViewAssertions.matches(
|
.check(ViewAssertions.matches(
|
||||||
ViewMatchers.withText(R.string.license_name_cc_by_4_0)
|
ViewMatchers.withText(R.string.license_name_cc_by_four)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
43
app/src/main/assets/queries/nearby_query.txt
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
SELECT
|
||||||
|
(SAMPLE(?location) as ?location)
|
||||||
|
?item
|
||||||
|
(SAMPLE(COALESCE(?item_label_preferred_language, ?item_label_any_language)) as ?label)
|
||||||
|
(SAMPLE(?classId) as ?class)
|
||||||
|
(SAMPLE(COALESCE(?class_label_preferred_language, ?class_label_any_language, "?")) as ?class_label)
|
||||||
|
(SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon)
|
||||||
|
(SAMPLE(COALESCE(?emoji0, ?emoji1)) as ?emoji)
|
||||||
|
(SAMPLE(?sitelink) as ?sitelink)
|
||||||
|
WHERE {
|
||||||
|
# Around given location...
|
||||||
|
SERVICE wikibase:around {
|
||||||
|
?item wdt:P625 ?location.
|
||||||
|
bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral.
|
||||||
|
bd:serviceParam wikibase:radius "${RADIUS}" . # Radius in kilometers.
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... and without an image.
|
||||||
|
MINUS {?item wdt:P18 []}
|
||||||
|
|
||||||
|
# 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 ?item_label_preferred_language. FILTER (lang(?item_label_preferred_language) = "${LANG}")}
|
||||||
|
OPTIONAL {?item rdfs:label ?item_label_any_language}
|
||||||
|
|
||||||
|
# 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 ?class_label_preferred_language. FILTER (lang(?class_label_preferred_language) = "${LANG}")}
|
||||||
|
OPTIONAL {?classId rdfs:label ?class_label_any_language}
|
||||||
|
|
||||||
|
# Get icon
|
||||||
|
OPTIONAL { ?classId wdt:P2910 ?icon0. }
|
||||||
|
OPTIONAL { ?classId wdt:P279*/wdt:P2910 ?icon1. }
|
||||||
|
# Get emoji
|
||||||
|
OPTIONAL { ?classId wdt:P487 ?emoji0. }
|
||||||
|
OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. }
|
||||||
|
OPTIONAL {
|
||||||
|
?sitelink schema:about ?item .
|
||||||
|
?sitelink schema:inLanguage "en"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GROUP BY ?item
|
||||||
|
|
@ -144,6 +144,14 @@ public class Media implements Parcelable {
|
||||||
this.license = license;
|
this.license = license;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCoordinates() {
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCoordinates(String coordinates) {
|
||||||
|
this.coordinates = coordinates;
|
||||||
|
}
|
||||||
|
|
||||||
// Primary metadata fields
|
// Primary metadata fields
|
||||||
protected Uri localUri;
|
protected Uri localUri;
|
||||||
protected String imageUrl;
|
protected String imageUrl;
|
||||||
|
|
@ -155,6 +163,7 @@ public class Media implements Parcelable {
|
||||||
protected int width;
|
protected int width;
|
||||||
protected int height;
|
protected int height;
|
||||||
protected String license;
|
protected String license;
|
||||||
|
private String coordinates;
|
||||||
protected String creator;
|
protected String creator;
|
||||||
protected ArrayList<String> categories; // as loaded at runtime?
|
protected ArrayList<String> categories; // as loaded at runtime?
|
||||||
protected Map<String, String> descriptions; // multilingual descriptions as loaded
|
protected Map<String, String> descriptions; // multilingual descriptions as loaded
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
|
||||||
import org.mediawiki.api.ApiResult;
|
import org.mediawiki.api.ApiResult;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
@ -38,6 +40,7 @@ public class MediaDataExtractor {
|
||||||
private String author;
|
private String author;
|
||||||
private Date date;
|
private Date date;
|
||||||
private String license;
|
private String license;
|
||||||
|
private String coordinates;
|
||||||
private LicenseList licenseList;
|
private LicenseList licenseList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -122,6 +125,14 @@ public class MediaDataExtractor {
|
||||||
author = getFlatText(authorNode);
|
author = getFlatText(authorNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node coordinateTemplateNode = findTemplate(doc.getDocumentElement(), "location");
|
||||||
|
|
||||||
|
if (coordinateTemplateNode != null) {
|
||||||
|
coordinates = getCoordinates(coordinateTemplateNode);
|
||||||
|
} else {
|
||||||
|
coordinates = "No coordinates found";
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pull up the license data list...
|
Pull up the license data list...
|
||||||
look for the templates in two ways:
|
look for the templates in two ways:
|
||||||
|
|
@ -242,6 +253,25 @@ public class MediaDataExtractor {
|
||||||
return parentNode.getTextContent();
|
return parentNode.getTextContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the coordinates from the template and returns them as pretty formatted string.
|
||||||
|
* Loops over the children of the coordinate template:
|
||||||
|
* {{Location|47.50111007666667|19.055700301944444}}
|
||||||
|
* and extracts the latitude and longitude as a pretty string.
|
||||||
|
*
|
||||||
|
* @param parentNode The node of the coordinates template.
|
||||||
|
* @return Pretty formatted coordinates.
|
||||||
|
* @throws IOException Parsing failed.
|
||||||
|
*/
|
||||||
|
private String getCoordinates(Node parentNode) throws IOException {
|
||||||
|
NodeList childNodes = parentNode.getChildNodes();
|
||||||
|
double latitudeText = Double.parseDouble(childNodes.item(1).getTextContent());
|
||||||
|
double longitudeText = Double.parseDouble(childNodes.item(2).getTextContent());
|
||||||
|
LatLng coordinates = new LatLng(latitudeText, longitudeText);
|
||||||
|
|
||||||
|
return coordinates.getPrettyCoordinateString();
|
||||||
|
}
|
||||||
|
|
||||||
// Extract a dictionary of multilingual texts from a subset of the parse tree.
|
// Extract a dictionary of multilingual texts from a subset of the parse tree.
|
||||||
// Texts are wrapped in things like {{en|foo} or {{en|1=foo bar}}.
|
// Texts are wrapped in things like {{en|foo} or {{en|1=foo bar}}.
|
||||||
// Text outside those wrappers is stuffed into a 'default' faux language key if present.
|
// Text outside those wrappers is stuffed into a 'default' faux language key if present.
|
||||||
|
|
@ -287,6 +317,7 @@ public class MediaDataExtractor {
|
||||||
|
|
||||||
media.setCategories(categories);
|
media.setCategories(categories);
|
||||||
media.setDescriptions(descriptions);
|
media.setDescriptions(descriptions);
|
||||||
|
media.setCoordinates(coordinates);
|
||||||
if (license != null) {
|
if (license != null) {
|
||||||
media.setLicense(license);
|
media.setLicense(license);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
package fr.free.nrw.commons;
|
package fr.free.nrw.commons;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||||
|
|
@ -306,4 +308,12 @@ public class Utils {
|
||||||
public static boolean isNullOrWhiteSpace(String value) {
|
public static boolean isNullOrWhiteSpace(String value) {
|
||||||
return value == null || value.trim().isEmpty();
|
return value == null || value.trim().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDarkTheme(Context context) {
|
||||||
|
if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme",true)) {
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,4 +42,52 @@ public class LatLng {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "lat/lng: (" + this.latitude + "," + this.longitude + ")";
|
return "lat/lng: (" + this.latitude + "," + this.longitude + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds the float to 4 digits.
|
||||||
|
*
|
||||||
|
* @param coordinate A coordinate value as string.
|
||||||
|
* @return String of the rounded number.
|
||||||
|
*/
|
||||||
|
private String formatCoordinate(double coordinate) {
|
||||||
|
double roundedNumber = Math.round(coordinate * 10000d) / 10000d;
|
||||||
|
return String.valueOf(roundedNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns "N" or "S" depending on the latitude.
|
||||||
|
*
|
||||||
|
* @return "N" or "S".
|
||||||
|
*/
|
||||||
|
private String getNorthSouth() {
|
||||||
|
if (this.latitude < 0) {
|
||||||
|
return "S";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "N";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns "E" or "W" depending on the longitude.
|
||||||
|
*
|
||||||
|
* @return "E" or "W".
|
||||||
|
*/
|
||||||
|
private String getEastWest() {
|
||||||
|
if (this.longitude < 180) {
|
||||||
|
return "E";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "W";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a nicely formatted coordinate string. Used e.g. in
|
||||||
|
* the detail view.
|
||||||
|
*
|
||||||
|
* @return The formatted string.
|
||||||
|
*/
|
||||||
|
public String getPrettyCoordinateString() {
|
||||||
|
return formatCoordinate(this.latitude) + " " + this.getNorthSouth() + ", "
|
||||||
|
+ formatCoordinate(this.longitude) + " " + this.getEastWest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ public class MediaDetailFragment extends Fragment {
|
||||||
private TextView title;
|
private TextView title;
|
||||||
private TextView desc;
|
private TextView desc;
|
||||||
private TextView license;
|
private TextView license;
|
||||||
|
private TextView coordinates;
|
||||||
private LinearLayout categoryContainer;
|
private LinearLayout categoryContainer;
|
||||||
private ScrollView scrollView;
|
private ScrollView scrollView;
|
||||||
private ArrayList<String> categoryNames;
|
private ArrayList<String> categoryNames;
|
||||||
|
|
@ -123,6 +124,7 @@ public class MediaDetailFragment extends Fragment {
|
||||||
title = (TextView) view.findViewById(R.id.mediaDetailTitle);
|
title = (TextView) view.findViewById(R.id.mediaDetailTitle);
|
||||||
desc = (TextView) view.findViewById(R.id.mediaDetailDesc);
|
desc = (TextView) view.findViewById(R.id.mediaDetailDesc);
|
||||||
license = (TextView) view.findViewById(R.id.mediaDetailLicense);
|
license = (TextView) view.findViewById(R.id.mediaDetailLicense);
|
||||||
|
coordinates = (TextView) view.findViewById(R.id.mediaDetailCoordinates);
|
||||||
categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer);
|
categoryContainer = (LinearLayout) view.findViewById(R.id.mediaDetailCategoryContainer);
|
||||||
|
|
||||||
licenseList = new LicenseList(getActivity());
|
licenseList = new LicenseList(getActivity());
|
||||||
|
|
@ -226,6 +228,7 @@ public class MediaDetailFragment extends Fragment {
|
||||||
// Set text of desc, license, and categories
|
// Set text of desc, license, and categories
|
||||||
desc.setText(prettyDescription(media));
|
desc.setText(prettyDescription(media));
|
||||||
license.setText(prettyLicense(media));
|
license.setText(prettyLicense(media));
|
||||||
|
coordinates.setText(prettyCoordinates(media));
|
||||||
|
|
||||||
categoryNames.removeAll(categoryNames);
|
categoryNames.removeAll(categoryNames);
|
||||||
categoryNames.addAll(media.getCategories());
|
categoryNames.addAll(media.getCategories());
|
||||||
|
|
@ -388,4 +391,15 @@ public class MediaDetailFragment extends Fragment {
|
||||||
return licenseObj.getName();
|
return licenseObj.getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the coordinates nicely formatted.
|
||||||
|
*
|
||||||
|
* @return Coordinates as text.
|
||||||
|
*/
|
||||||
|
private String prettyCoordinates(Media media) {
|
||||||
|
String coordinates = media.getCoordinates();
|
||||||
|
|
||||||
|
return coordinates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
|
|
@ -71,6 +72,11 @@ public class NearbyActivity extends BaseActivity {
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_map:
|
case R.id.action_map:
|
||||||
showMapView();
|
showMapView();
|
||||||
|
if (isMapViewActive) {
|
||||||
|
item.setIcon(R.drawable.ic_list_white_24dp);
|
||||||
|
} else {
|
||||||
|
item.setIcon(R.drawable.ic_map_white_24dp);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
|
@ -83,6 +89,12 @@ public class NearbyActivity extends BaseActivity {
|
||||||
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
|
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
|
||||||
setMapFragment();
|
setMapFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
isMapViewActive = false;
|
||||||
|
if (nearbyAsyncTask.getStatus() == AsyncTask.Status.FINISHED) {
|
||||||
|
setListFragment();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,22 +172,21 @@ public class NearbyActivity extends BaseActivity {
|
||||||
* Calls fragment for map view.
|
* Calls fragment for map view.
|
||||||
*/
|
*/
|
||||||
public void setMapFragment() {
|
public void setMapFragment() {
|
||||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||||
NearbyMapFragment fragment = new NearbyMapFragment();
|
Fragment fragment = new NearbyMapFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
ft.add(R.id.container, fragment);
|
fragmentTransaction.replace(R.id.container, fragment);
|
||||||
ft.commit();
|
fragmentTransaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls fragment for list view.
|
* Calls fragment for list view.
|
||||||
*/
|
*/
|
||||||
public void setListFragment() {
|
public void setListFragment() {
|
||||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||||
NearbyListFragment fragment = new NearbyListFragment();
|
Fragment fragment = new NearbyListFragment();
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
ft.add(R.id.container, fragment);
|
fragmentTransaction.replace(R.id.container, fragment);
|
||||||
ft.commit();
|
fragmentTransaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
|
||||||
|
import com.mapbox.mapboxsdk.annotations.Icon;
|
||||||
|
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||||
|
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||||
|
import fr.free.nrw.commons.utils.UriSerializer;
|
||||||
|
|
||||||
|
public class NearbyBaseMarker extends BaseMarkerOptions<NearbyMarker, NearbyBaseMarker> {
|
||||||
|
private Place place;
|
||||||
|
public NearbyBaseMarker() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public NearbyBaseMarker place(Place place) {
|
||||||
|
this.place = place;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NearbyBaseMarker(Parcel in) {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Uri.class, new UriDeserializer())
|
||||||
|
.create();
|
||||||
|
|
||||||
|
position((LatLng) in.readParcelable(LatLng.class.getClassLoader()));
|
||||||
|
snippet(in.readString());
|
||||||
|
String iconId = in.readString();
|
||||||
|
Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader());
|
||||||
|
Icon icon = IconFactory.recreate(iconId, iconBitmap);
|
||||||
|
icon(icon);
|
||||||
|
title(in.readString());
|
||||||
|
String gsonString = in.readString();
|
||||||
|
place(gson.fromJson(gsonString, Place.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NearbyBaseMarker getThis() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NearbyMarker getMarker() {
|
||||||
|
return new NearbyMarker(this, place);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(Uri.class, new UriSerializer())
|
||||||
|
.create();
|
||||||
|
|
||||||
|
dest.writeParcelable(position, flags);
|
||||||
|
dest.writeString(snippet);
|
||||||
|
dest.writeString(icon.getId());
|
||||||
|
dest.writeParcelable(icon.getBitmap(), flags);
|
||||||
|
dest.writeString(title);
|
||||||
|
dest.writeString(gson.toJson(place));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Place getPlace() {
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<NearbyBaseMarker> CREATOR
|
||||||
|
= new Parcelable.Creator<NearbyBaseMarker>() {
|
||||||
|
public NearbyBaseMarker createFromParcel(Parcel in) {
|
||||||
|
return new NearbyBaseMarker(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NearbyBaseMarker[] newArray(int size) {
|
||||||
|
return new NearbyBaseMarker[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween;
|
|
||||||
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.drawable.Icon;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
|
|
||||||
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
@ -20,8 +13,12 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween;
|
||||||
|
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
|
||||||
|
|
||||||
|
|
||||||
public class NearbyController {
|
public class NearbyController {
|
||||||
private static final int MAX_RESULTS = 1000;
|
private static final int MAX_RESULTS = 1000;
|
||||||
|
|
@ -40,7 +37,9 @@ public class NearbyController {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
List<Place> places = prefs.getBoolean("useWikidata", true)
|
List<Place> places = prefs.getBoolean("useWikidata", true)
|
||||||
? NearbyPlaces.getInstance().getFromWikidataQuery(
|
? NearbyPlaces.getInstance().getFromWikidataQuery(
|
||||||
curLatLng, Locale.getDefault().getLanguage())
|
context,
|
||||||
|
curLatLng,
|
||||||
|
Locale.getDefault().getLanguage())
|
||||||
: NearbyPlaces.getInstance().getFromWikiNeedsPictures();
|
: NearbyPlaces.getInstance().getFromWikiNeedsPictures();
|
||||||
if (curLatLng != null) {
|
if (curLatLng != null) {
|
||||||
Timber.d("Sorting places by distance...");
|
Timber.d("Sorting places by distance...");
|
||||||
|
|
@ -85,19 +84,24 @@ public class NearbyController {
|
||||||
* @param placeList list of nearby places in Place data type
|
* @param placeList list of nearby places in Place data type
|
||||||
* @return BaseMarkerOprions list that holds nearby places
|
* @return BaseMarkerOprions list that holds nearby places
|
||||||
*/
|
*/
|
||||||
public static List<BaseMarkerOptions> loadAttractionsFromLocationToBaseMarkerOptions(
|
public static List<NearbyBaseMarker> loadAttractionsFromLocationToBaseMarkerOptions(
|
||||||
LatLng curLatLng,
|
LatLng curLatLng,
|
||||||
List<Place> placeList) {
|
List<Place> placeList) {
|
||||||
List<BaseMarkerOptions> baseMarkerOptionses = new ArrayList<>();
|
List<NearbyBaseMarker> baseMarkerOptionses = new ArrayList<>();
|
||||||
placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS));
|
placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS));
|
||||||
for (Place place: placeList) {
|
for (Place place: placeList) {
|
||||||
String distance = formatDistanceBetween(curLatLng, place.location);
|
String distance = formatDistanceBetween(curLatLng, place.location);
|
||||||
place.setDistance(distance);
|
place.setDistance(distance);
|
||||||
baseMarkerOptionses.add(new MarkerOptions()
|
|
||||||
.position(new com.mapbox.mapboxsdk.geometry
|
NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker();
|
||||||
.LatLng(place.location.latitude,place.location.longitude))
|
nearbyBaseMarker.title(place.name);
|
||||||
.title(place.name)
|
nearbyBaseMarker.position(
|
||||||
.snippet(place.description));
|
new com.mapbox.mapboxsdk.geometry.LatLng(
|
||||||
|
place.location.latitude,
|
||||||
|
place.location.longitude));
|
||||||
|
nearbyBaseMarker.place(place);
|
||||||
|
|
||||||
|
baseMarkerOptionses.add(nearbyBaseMarker);
|
||||||
}
|
}
|
||||||
return baseMarkerOptionses;
|
return baseMarkerOptionses;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import butterknife.OnClick;
|
||||||
|
import butterknife.Unbinder;
|
||||||
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.Utils;
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
import fr.free.nrw.commons.ui.widget.OverlayDialog;
|
||||||
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
|
|
||||||
|
public class NearbyInfoDialog extends OverlayDialog {
|
||||||
|
|
||||||
|
private final static String ARG_TITLE = "placeTitle";
|
||||||
|
private final static String ARG_DESC = "placeDesc";
|
||||||
|
private final static String ARG_LATITUDE = "latitude";
|
||||||
|
private final static String ARG_LONGITUDE = "longitude";
|
||||||
|
private final static String ARG_ARTICLE_LINK = "articleLink";
|
||||||
|
private final static String ARG_WIKI_DATA_LINK = "wikiDataLink";
|
||||||
|
|
||||||
|
@BindView(R.id.link_preview_title)
|
||||||
|
TextView placeTitle;
|
||||||
|
@BindView(R.id.link_preview_extract)
|
||||||
|
TextView placeDescription;
|
||||||
|
|
||||||
|
@BindView(R.id.link_preview_go_button)
|
||||||
|
TextView goToButton;
|
||||||
|
|
||||||
|
private Unbinder unbinder;
|
||||||
|
|
||||||
|
private LatLng location;
|
||||||
|
private Uri articleLink;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.dialog_nearby_info, container, false);
|
||||||
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
initUi();
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initUi() {
|
||||||
|
Bundle bundle = getArguments();
|
||||||
|
placeTitle.setText(bundle.getString(ARG_TITLE));
|
||||||
|
placeDescription.setText(bundle.getString(ARG_DESC));
|
||||||
|
location = new LatLng(bundle.getDouble(ARG_LATITUDE), bundle.getDouble(ARG_LONGITUDE));
|
||||||
|
getArticleLink(bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getArticleLink(Bundle bundle) {
|
||||||
|
String articleLink = bundle.getString(ARG_ARTICLE_LINK);
|
||||||
|
articleLink = articleLink.replace("<", "").replace(">", "");
|
||||||
|
|
||||||
|
if (Utils.isNullOrWhiteSpace(articleLink) || articleLink == "\n") {
|
||||||
|
articleLink = bundle.getString(ARG_WIKI_DATA_LINK).replace("<", "").replace(">", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils.isNullOrWhiteSpace(articleLink) && articleLink != "\n") {
|
||||||
|
this.articleLink = Uri.parse(articleLink);
|
||||||
|
} else {
|
||||||
|
goToButton.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showYourself(FragmentActivity fragmentActivity, Place place) {
|
||||||
|
NearbyInfoDialog mDialog = new NearbyInfoDialog();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(ARG_TITLE, place.name);
|
||||||
|
bundle.putString(ARG_DESC, place.description);
|
||||||
|
bundle.putDouble(ARG_LATITUDE, place.location.latitude);
|
||||||
|
bundle.putDouble(ARG_LONGITUDE, place.location.longitude);
|
||||||
|
bundle.putString(ARG_ARTICLE_LINK, place.siteLink.toString());
|
||||||
|
bundle.putString(ARG_WIKI_DATA_LINK, place.wikiDataLink.toString());
|
||||||
|
mDialog.setArguments(bundle);
|
||||||
|
DialogUtil.showSafely(fragmentActivity, mDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
unbinder.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.link_preview_directions_button)
|
||||||
|
void onDirectionsClick() {
|
||||||
|
//Open map app at given position
|
||||||
|
Uri gmmIntentUri = Uri.parse("geo:0,0?q=" + location.latitude + "," + location.longitude);
|
||||||
|
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
||||||
|
|
||||||
|
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
|
||||||
|
startActivity(mapIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.link_preview_go_button)
|
||||||
|
void onReadArticleClick() {
|
||||||
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, articleLink);
|
||||||
|
startActivity(browserIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClick(R.id.emptyLayout)
|
||||||
|
void onCloseClicked() {
|
||||||
|
dismissAllowingStateLoss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,8 +28,6 @@ import java.util.List;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class NearbyListFragment extends ListFragment {
|
public class NearbyListFragment extends ListFragment {
|
||||||
|
|
||||||
//private NearbyAsyncTask nearbyAsyncTask;
|
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private List<Place> placeList;
|
private List<Place> placeList;
|
||||||
private LatLng curLatLng;
|
private LatLng curLatLng;
|
||||||
|
|
@ -98,12 +96,6 @@ public class NearbyListFragment extends ListFragment {
|
||||||
|
|
||||||
Timber.d("Item at position %d has coords: Lat: %f Long: %f", position, latitude, longitude);
|
Timber.d("Item at position %d has coords: Lat: %f Long: %f", position, latitude, longitude);
|
||||||
|
|
||||||
//Open map app at given position
|
NearbyInfoDialog.showYourself(getActivity(), place);
|
||||||
Uri gmmIntentUri = Uri.parse("geo:0,0?q=" + latitude + "," + longitude);
|
|
||||||
Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri);
|
|
||||||
|
|
||||||
if (mapIntent.resolveActivity(getActivity().getPackageManager()) != null) {
|
|
||||||
startActivity(mapIntent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
@ -11,7 +13,7 @@ import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.mapbox.mapboxsdk.Mapbox;
|
import com.mapbox.mapboxsdk.Mapbox;
|
||||||
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
|
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||||
import com.mapbox.mapboxsdk.constants.Style;
|
import com.mapbox.mapboxsdk.constants.Style;
|
||||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||||
|
|
@ -21,18 +23,17 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
|
||||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||||
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
|
||||||
import fr.free.nrw.commons.utils.UriDeserializer;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||||
|
|
||||||
public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
//private NearbyAsyncTask nearbyAsyncTask;
|
|
||||||
private MapView mapView;
|
private MapView mapView;
|
||||||
private Gson gson;
|
private Gson gson;
|
||||||
private List<Place> placeList;
|
private List<Place> placeList;
|
||||||
private List<BaseMarkerOptions> baseMarkerOptionses;
|
private List<NearbyBaseMarker> baseMarkerOptionses;
|
||||||
private fr.free.nrw.commons.location.LatLng curLatLng;
|
private fr.free.nrw.commons.location.LatLng curLatLng;
|
||||||
|
|
||||||
public NearbyMapFragment() {
|
public NearbyMapFragment() {
|
||||||
|
|
@ -65,6 +66,17 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
if (curLatLng != null) {
|
||||||
|
setupMapView(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
setHasOptionsMenu(false);
|
||||||
|
|
||||||
|
return mapView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMapView(Bundle savedInstanceState) {
|
||||||
MapboxMapOptions options = new MapboxMapOptions()
|
MapboxMapOptions options = new MapboxMapOptions()
|
||||||
.styleUrl(Style.OUTDOORS)
|
.styleUrl(Style.OUTDOORS)
|
||||||
.camera(new CameraPosition.Builder()
|
.camera(new CameraPosition.Builder()
|
||||||
|
|
@ -79,10 +91,25 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
@Override
|
@Override
|
||||||
public void onMapReady(MapboxMap mapboxMap) {
|
public void onMapReady(MapboxMap mapboxMap) {
|
||||||
mapboxMap.addMarkers(baseMarkerOptionses);
|
mapboxMap.addMarkers(baseMarkerOptionses);
|
||||||
|
|
||||||
|
mapboxMap.setOnMarkerClickListener(new MapboxMap.OnMarkerClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onMarkerClick(@NonNull Marker marker) {
|
||||||
|
if (marker instanceof NearbyMarker) {
|
||||||
|
NearbyMarker nearbyMarker = (NearbyMarker) marker;
|
||||||
|
Place place = nearbyMarker.getNearbyBaseMarker().getPlace();
|
||||||
|
NearbyInfoDialog.showYourself(getActivity(), place);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setHasOptionsMenu(false);
|
if (PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean("theme",true)) {
|
||||||
return mapView;
|
mapView.setStyleUrl(getResources().getString(R.string.map_theme_dark));
|
||||||
|
} else {
|
||||||
|
mapView.setStyleUrl(getResources().getString(R.string.map_theme_light));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -92,31 +119,41 @@ public class NearbyMapFragment extends android.support.v4.app.Fragment {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
mapView.onStart();
|
if (mapView != null) {
|
||||||
|
mapView.onStart();
|
||||||
|
}
|
||||||
super.onStart();
|
super.onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
mapView.onPause();
|
if (mapView != null) {
|
||||||
|
mapView.onPause();
|
||||||
|
}
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
mapView.onResume();
|
if (mapView != null) {
|
||||||
|
mapView.onResume();
|
||||||
|
}
|
||||||
super.onResume();
|
super.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
mapView.onStop();
|
if (mapView != null) {
|
||||||
|
mapView.onStop();
|
||||||
|
}
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
mapView.onDestroy();
|
if (mapView != null) {
|
||||||
|
mapView.onDestroy();
|
||||||
|
}
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||||
|
|
||||||
|
public class NearbyMarker extends Marker {
|
||||||
|
private Place place;
|
||||||
|
private NearbyBaseMarker nearbyBaseMarker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a instance of {@link Marker} using the builder of Marker.
|
||||||
|
*
|
||||||
|
* @param baseMarkerOptions The builder used to construct the Marker.
|
||||||
|
*/
|
||||||
|
public NearbyMarker(NearbyBaseMarker baseMarkerOptions, Place place) {
|
||||||
|
super(baseMarkerOptions);
|
||||||
|
this.place = place;
|
||||||
|
this.nearbyBaseMarker = baseMarkerOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NearbyBaseMarker getNearbyBaseMarker() {
|
||||||
|
return nearbyBaseMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Place getPlace() {
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNearbyBaseMarker(NearbyBaseMarker nearbyBaseMarker) {
|
||||||
|
this.nearbyBaseMarker = nearbyBaseMarker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
|
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
@ -19,6 +17,9 @@ import java.util.Locale;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.Utils;
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
import fr.free.nrw.commons.utils.FileUtils;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class NearbyPlaces {
|
public class NearbyPlaces {
|
||||||
|
|
@ -28,44 +29,6 @@ public class NearbyPlaces {
|
||||||
private static final double MAX_RADIUS = 300.0;
|
private static final double MAX_RADIUS = 300.0;
|
||||||
private static final double RADIUS_MULTIPLIER = 1.618;
|
private static final double RADIUS_MULTIPLIER = 1.618;
|
||||||
private static final String WIKIDATA_QUERY_URL = "https://query.wikidata.org/sparql?query=${QUERY}";
|
private static final String WIKIDATA_QUERY_URL = "https://query.wikidata.org/sparql?query=${QUERY}";
|
||||||
private static final String WIKIDATA_QUERY_TEMPLATE = "SELECT\n" +
|
|
||||||
" (SAMPLE(?location) as ?location)\n" +
|
|
||||||
" ?item\n" +
|
|
||||||
" (SAMPLE(COALESCE(?item_label_preferred_language, ?item_label_any_language)) as ?label)\n" +
|
|
||||||
" (SAMPLE(?classId) as ?class)\n" +
|
|
||||||
" (SAMPLE(COALESCE(?class_label_preferred_language, ?class_label_any_language, \"?\")) as ?class_label)\n" +
|
|
||||||
" (SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon)\n" +
|
|
||||||
" (SAMPLE(COALESCE(?emoji0, ?emoji1)) as ?emoji)\n" +
|
|
||||||
"WHERE {\n" +
|
|
||||||
" # Around given location...\n" +
|
|
||||||
" SERVICE wikibase:around {\n" +
|
|
||||||
" ?item wdt:P625 ?location.\n" +
|
|
||||||
" bd:serviceParam wikibase:center \"Point(${LONG} ${LAT})\"^^geo:wktLiteral. \n" +
|
|
||||||
" bd:serviceParam wikibase:radius \"${RADIUS}\" . # Radius in kilometers.\n" +
|
|
||||||
" }\n" +
|
|
||||||
" \n" +
|
|
||||||
" # ... and without an image.\n" +
|
|
||||||
" MINUS {?item wdt:P18 []}\n" +
|
|
||||||
" \n" +
|
|
||||||
" # Get the label in the preferred language of the user, or any other language if no label is available in that language.\n" +
|
|
||||||
" OPTIONAL {?item rdfs:label ?item_label_preferred_language. FILTER (lang(?item_label_preferred_language) = \"${LANG}\")}\n" +
|
|
||||||
" OPTIONAL {?item rdfs:label ?item_label_any_language}\n" +
|
|
||||||
" \n" +
|
|
||||||
" # Get the class label in the preferred language of the user, or any other language if no label is available in that language.\n" +
|
|
||||||
" OPTIONAL {\n" +
|
|
||||||
" ?item p:P31/ps:P31 ?classId.\n" +
|
|
||||||
" OPTIONAL {?classId rdfs:label ?class_label_preferred_language. FILTER (lang(?class_label_preferred_language) = \"${LANG}\")}\n" +
|
|
||||||
" OPTIONAL {?classId rdfs:label ?class_label_any_language}\n" +
|
|
||||||
"\n" +
|
|
||||||
" # Get icon\n" +
|
|
||||||
" OPTIONAL { ?classId wdt:P2910 ?icon0. }\n" +
|
|
||||||
" OPTIONAL { ?classId wdt:P279*/wdt:P2910 ?icon1. }\n" +
|
|
||||||
" # Get emoji\n" +
|
|
||||||
" OPTIONAL { ?classId wdt:P487 ?emoji0. }\n" +
|
|
||||||
" OPTIONAL { ?classId wdt:P279*/wdt:P487 ?emoji1. }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n" +
|
|
||||||
"GROUP BY ?item\n";
|
|
||||||
private static NearbyPlaces singleton;
|
private static NearbyPlaces singleton;
|
||||||
private double radius = INITIAL_RADIUS;
|
private double radius = INITIAL_RADIUS;
|
||||||
private List<Place> places;
|
private List<Place> places;
|
||||||
|
|
@ -73,13 +36,15 @@ public class NearbyPlaces {
|
||||||
private NearbyPlaces(){
|
private NearbyPlaces(){
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Place> getFromWikidataQuery(LatLng curLatLng, String lang) {
|
List<Place> getFromWikidataQuery(Context context,
|
||||||
|
LatLng curLatLng,
|
||||||
|
String lang) {
|
||||||
List<Place> places = Collections.emptyList();
|
List<Place> places = Collections.emptyList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// increase the radius gradually to find a satisfactory number of nearby places
|
// increase the radius gradually to find a satisfactory number of nearby places
|
||||||
while (radius < MAX_RADIUS) {
|
while (radius < MAX_RADIUS) {
|
||||||
places = getFromWikidataQuery(curLatLng, lang, radius);
|
places = getFromWikidataQuery(context, curLatLng, lang, radius);
|
||||||
Timber.d("%d results at radius: %f", places.size(), radius);
|
Timber.d("%d results at radius: %f", places.size(), radius);
|
||||||
if (places.size() >= MIN_RESULTS) {
|
if (places.size() >= MIN_RESULTS) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -97,10 +62,18 @@ public class NearbyPlaces {
|
||||||
return places;
|
return places;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Place> getFromWikidataQuery(LatLng cur, String lang, double radius)
|
private List<Place> getFromWikidataQuery(Context context,
|
||||||
|
LatLng cur,
|
||||||
|
String lang,
|
||||||
|
double radius)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
List<Place> places = new ArrayList<>();
|
List<Place> places = new ArrayList<>();
|
||||||
String query = WIKIDATA_QUERY_TEMPLATE.replace("${RADIUS}", "" + radius)
|
|
||||||
|
String query = FileUtils.readFromFile(context, "queries/nearby_query.txt");
|
||||||
|
|
||||||
|
Timber.d(query);
|
||||||
|
|
||||||
|
query = query.replace("${RADIUS}", "" + radius)
|
||||||
.replace("${LAT}", "" + String.format(Locale.ROOT, "%.3f", cur.latitude))
|
.replace("${LAT}", "" + String.format(Locale.ROOT, "%.3f", cur.latitude))
|
||||||
.replace("${LONG}", "" + String.format(Locale.ROOT, "%.3f", cur.longitude))
|
.replace("${LONG}", "" + String.format(Locale.ROOT, "%.3f", cur.longitude))
|
||||||
.replace("${LANG}", "" + lang);
|
.replace("${LANG}", "" + lang);
|
||||||
|
|
@ -124,6 +97,8 @@ public class NearbyPlaces {
|
||||||
String point = fields[0];
|
String point = fields[0];
|
||||||
String name = Utils.stripLocalizedString(fields[2]);
|
String name = Utils.stripLocalizedString(fields[2]);
|
||||||
String type = Utils.stripLocalizedString(fields[4]);
|
String type = Utils.stripLocalizedString(fields[4]);
|
||||||
|
String sitelink = Utils.stripLocalizedString(fields[7]);
|
||||||
|
String wikiDataLink = Utils.stripLocalizedString(fields[3]);
|
||||||
String icon = fields[5];
|
String icon = fields[5];
|
||||||
|
|
||||||
double latitude = 0;
|
double latitude = 0;
|
||||||
|
|
@ -145,7 +120,9 @@ public class NearbyPlaces {
|
||||||
type, // list
|
type, // list
|
||||||
type, // details
|
type, // details
|
||||||
Uri.parse(icon),
|
Uri.parse(icon),
|
||||||
new LatLng(latitude, longitude)
|
new LatLng(latitude, longitude),
|
||||||
|
Uri.parse(sitelink),
|
||||||
|
Uri.parse(wikiDataLink)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
|
|
@ -202,7 +179,9 @@ public class NearbyPlaces {
|
||||||
type, // list
|
type, // list
|
||||||
type, // details
|
type, // details
|
||||||
null,
|
null,
|
||||||
new LatLng(latitude, longitude)
|
new LatLng(latitude, longitude),
|
||||||
|
null,
|
||||||
|
null
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,19 @@ public class Place {
|
||||||
public Bitmap image;
|
public Bitmap image;
|
||||||
public Bitmap secondaryImage;
|
public Bitmap secondaryImage;
|
||||||
public String distance;
|
public String distance;
|
||||||
|
public Uri siteLink;
|
||||||
|
public Uri wikiDataLink;
|
||||||
|
|
||||||
|
|
||||||
public Place(String name, String description, String longDescription,
|
public Place(String name, String description, String longDescription,
|
||||||
Uri secondaryImageUrl, LatLng location) {
|
Uri secondaryImageUrl, LatLng location, Uri siteLink, Uri wikiDataLink) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.longDescription = longDescription;
|
this.longDescription = longDescription;
|
||||||
this.secondaryImageUrl = secondaryImageUrl;
|
this.secondaryImageUrl = secondaryImageUrl;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
|
this.siteLink = siteLink;
|
||||||
|
this.wikiDataLink = wikiDataLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDistance(String distance) {
|
public void setDistance(String distance) {
|
||||||
|
|
|
||||||
|
|
@ -24,30 +24,15 @@ public class SettingsFragment extends PreferenceFragment {
|
||||||
|
|
||||||
// Update spinner to show selected value as summary
|
// Update spinner to show selected value as summary
|
||||||
ListPreference licensePreference = (ListPreference) findPreference(Prefs.DEFAULT_LICENSE);
|
ListPreference licensePreference = (ListPreference) findPreference(Prefs.DEFAULT_LICENSE);
|
||||||
// WARNING: ORDERING NEEDS TO MATCH FOR THE LICENSE NAMES AND DISPLAY VALUES
|
|
||||||
licensePreference.setEntries(new String[]{
|
|
||||||
getString(R.string.license_name_cc0),
|
|
||||||
getString(R.string.license_name_cc_by_3_0),
|
|
||||||
getString(R.string.license_name_cc_by_4_0),
|
|
||||||
getString(R.string.license_name_cc_by_sa_3_0),
|
|
||||||
getString(R.string.license_name_cc_by_sa_4_0)
|
|
||||||
});
|
|
||||||
licensePreference.setEntryValues(new String[]{
|
|
||||||
Prefs.Licenses.CC0,
|
|
||||||
Prefs.Licenses.CC_BY_3,
|
|
||||||
Prefs.Licenses.CC_BY_4,
|
|
||||||
Prefs.Licenses.CC_BY_SA_3,
|
|
||||||
Prefs.Licenses.CC_BY_SA_4
|
|
||||||
});
|
|
||||||
|
|
||||||
licensePreference.setSummary(getString(Utils.licenseNameFor(licensePreference.getValue())));
|
licensePreference.setSummary(getString(Utils.licenseNameFor(licensePreference.getValue())));
|
||||||
licensePreference
|
|
||||||
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
// Keep summary updated when changing value
|
||||||
@Override
|
licensePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
@Override
|
||||||
preference.setSummary(getString(Utils.licenseNameFor((String) newValue)));
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
return true;
|
preference.setSummary(getString(Utils.licenseNameFor((String) newValue)));
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CheckBoxPreference themePreference = (CheckBoxPreference) findPreference("theme");
|
CheckBoxPreference themePreference = (CheckBoxPreference) findPreference("theme");
|
||||||
|
|
@ -99,4 +84,4 @@ public class SettingsFragment extends PreferenceFragment {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,17 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.Utils;
|
||||||
|
|
||||||
public class BaseActivity extends AppCompatActivity {
|
public class BaseActivity extends AppCompatActivity {
|
||||||
boolean currentTheme;
|
boolean currentTheme;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("theme",true)) {
|
if(Utils.isDarkTheme(this)){
|
||||||
currentTheme = true;
|
currentTheme = true;
|
||||||
setTheme(R.style.DarkAppTheme);
|
setTheme(R.style.DarkAppTheme);
|
||||||
}else {
|
} else {
|
||||||
currentTheme = false;
|
currentTheme = false;
|
||||||
setTheme(R.style.LightAppTheme); // default
|
setTheme(R.style.LightAppTheme); // default
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package fr.free.nrw.commons.ui.widget;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
public abstract class OverlayDialog extends DialogFragment {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
|
setDialogLayoutToFullScreen();
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDialogLayoutToFullScreen() {
|
||||||
|
Window window = getDialog().getWindow();
|
||||||
|
WindowManager.LayoutParams wlp = window.getAttributes();
|
||||||
|
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
wlp.gravity = Gravity.BOTTOM;
|
||||||
|
wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
|
||||||
|
wlp.height = WindowManager.LayoutParams.MATCH_PARENT;
|
||||||
|
window.setAttributes(wlp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||||
|
Window window = dialog.getWindow();
|
||||||
|
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -115,6 +115,13 @@ public class SingleUploadFragment extends Fragment {
|
||||||
licenseSpinner.setAdapter(adapter);
|
licenseSpinner.setAdapter(adapter);
|
||||||
|
|
||||||
int position = licenseItems.indexOf(getString(Utils.licenseNameFor(license)));
|
int position = licenseItems.indexOf(getString(Utils.licenseNameFor(license)));
|
||||||
|
|
||||||
|
// Check position is valid
|
||||||
|
if (position < 0) {
|
||||||
|
Timber.d("Invalid position: %d. Using default license", position);
|
||||||
|
position = 4;
|
||||||
|
}
|
||||||
|
|
||||||
Timber.d("Position: %d %s", position, getString(Utils.licenseNameFor(license)));
|
Timber.d("Position: %d %s", position, getString(Utils.licenseNameFor(license)));
|
||||||
licenseSpinner.setSelection(position);
|
licenseSpinner.setSelection(position);
|
||||||
|
|
||||||
|
|
|
||||||
80
app/src/main/java/fr/free/nrw/commons/utils/DialogUtil.java
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package fr.free.nrw.commons.utils;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.DialogFragment;
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class DialogUtil {
|
||||||
|
|
||||||
|
public static void dismissSafely(@Nullable Activity activity, @Nullable DialogFragment dialog) {
|
||||||
|
boolean isActivityDestroyed = false;
|
||||||
|
|
||||||
|
if (activity == null || dialog == null) {
|
||||||
|
Timber.d("dismiss called with null activity / dialog. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||||
|
isActivityDestroyed = activity.isDestroyed();
|
||||||
|
}
|
||||||
|
if (activity.isFinishing() || isActivityDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dialog.dismiss();
|
||||||
|
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Timber.e(e, "Could not dismiss dialog.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showSafely(Activity activity, Dialog dialog) {
|
||||||
|
if (activity == null || dialog == null) {
|
||||||
|
Timber.d("Show called with null activity / dialog. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isActivityDestroyed = false;
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||||
|
isActivityDestroyed = activity.isDestroyed();
|
||||||
|
}
|
||||||
|
if (activity.isFinishing() || isActivityDestroyed) {
|
||||||
|
Timber.e("Activity is not running. Could not show dialog. ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dialog.show();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Timber.e(e, "Could not show dialog.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showSafely(FragmentActivity activity, DialogFragment dialog) {
|
||||||
|
boolean isActivityDestroyed = false;
|
||||||
|
|
||||||
|
if (activity == null || dialog == null) {
|
||||||
|
Timber.d("show called with null activity / dialog. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||||
|
isActivityDestroyed = activity.isDestroyed();
|
||||||
|
}
|
||||||
|
if (activity.isFinishing() || isActivityDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (dialog.getDialog() == null || !dialog.getDialog().isShowing()) {
|
||||||
|
dialog.show(activity.getSupportFragmentManager(), dialog.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Timber.e(e, "Could not show dialog.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package fr.free.nrw.commons.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
public class FileUtils {
|
||||||
|
public static String readFromFile(Context context, String fileName) {
|
||||||
|
String stringBuilder = "";
|
||||||
|
BufferedReader reader = null;
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(
|
||||||
|
new InputStreamReader(context.getAssets().open(fileName), "UTF-8"));
|
||||||
|
String mLine;
|
||||||
|
while ((mLine = reader.readLine()) != null) {
|
||||||
|
stringBuilder += mLine + "\n";
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
//log the exception
|
||||||
|
} finally {
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
//log the exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringBuilder;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
app/src/main/res/drawable-hdpi/ic_list_white_24dp.png
Normal file
|
After Width: | Height: | Size: 116 B |
|
Before Width: | Height: | Size: 310 B |
BIN
app/src/main/res/drawable-mdpi/ic_list_white_24dp.png
Normal file
|
After Width: | Height: | Size: 86 B |
|
Before Width: | Height: | Size: 222 B |
BIN
app/src/main/res/drawable-xhdpi/ic_list_white_24dp.png
Normal file
|
After Width: | Height: | Size: 95 B |
|
Before Width: | Height: | Size: 363 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_list_white_24dp.png
Normal file
|
After Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 513 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_list_white_24dp.png
Normal file
|
After Width: | Height: | Size: 100 B |
|
Before Width: | Height: | Size: 667 B |
115
app/src/main/res/layout/dialog_nearby_info.xml
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:behavior_peekHeight="@dimen/bottom_peak_height">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:id="@+id/emptyLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:weightSum="1" />
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
|
android:background="@android:color/white">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/dialogInfoLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:minHeight="@dimen/bottom_peak_height"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/link_preview_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:clickable="true"
|
||||||
|
android:minHeight="64dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/link_preview_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:fontFamily="serif"
|
||||||
|
android:lineSpacingMultiplier="0.9"
|
||||||
|
android:maxLines="3"
|
||||||
|
android:paddingBottom="4dp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="20sp"
|
||||||
|
tools:text="Lorem ipsum" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0.5dp"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:background="@android:color/black" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/link_preview_extract"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:lineSpacingMultiplier="1.3"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
tools:text="Lorem ipsum" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/link_preview_bottom_padding"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="70dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/dialogButtonsLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@id/dialogInfoLayout"
|
||||||
|
android:layout_gravity="bottom">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/link_preview_directions_button"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:text="GET DIRECTIONS"
|
||||||
|
android:textColor="@android:color/black" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/link_preview_go_button"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:text="READ ARTICLE"
|
||||||
|
android:textColor="@android:color/black" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
@ -159,6 +159,35 @@
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/subBackground"
|
||||||
|
android:padding="16dp"
|
||||||
|
>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:text="Coordinates"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="License link"
|
||||||
|
android:id="@+id/mediaDetailCoordinates"
|
||||||
|
android:layout_gravity="left|start"
|
||||||
|
android:background="?attr/subBackground"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:padding="12dp"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<fr.free.nrw.commons.media.MediaDetailSpacer
|
<fr.free.nrw.commons.media.MediaDetailSpacer
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="8dp"
|
android:layout_height="8dp"
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@
|
||||||
<item>@string/license_name_cc_by_sa_four</item>
|
<item>@string/license_name_cc_by_sa_four</item>
|
||||||
</array>
|
</array>
|
||||||
<array name="pref_defaultLicense_values">
|
<array name="pref_defaultLicense_values">
|
||||||
<item>@string/license_name_cc0</item>
|
<item>@string/license_pref_cc0</item>
|
||||||
<item>@string/license_name_cc_by_3_0</item>
|
<item>@string/license_pref_cc_by_3_0</item>
|
||||||
<item>@string/license_name_cc_by_4_0</item>
|
<item>@string/license_pref_cc_by_4_0</item>
|
||||||
<item>@string/license_name_cc_by_sa_3_0</item>
|
<item>@string/license_pref_cc_by_sa_3_0</item>
|
||||||
<item>@string/license_name_cc_by_sa_4_0</item>
|
<item>@string/license_pref_cc_by_sa_4_0</item>
|
||||||
</array>
|
</array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
<dimen name="icon_size">120dp</dimen>
|
<dimen name="icon_size">120dp</dimen>
|
||||||
<dimen name="tiny_margin">4dp</dimen>
|
<dimen name="tiny_margin">4dp</dimen>
|
||||||
<dimen name="small_margin">8dp</dimen>
|
<dimen name="small_margin">8dp</dimen>
|
||||||
|
<dimen name="bottom_peak_height">240dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
8
app/src/main/res/values/keys.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="license_pref_cc0" translatable="false">CC0</string>
|
||||||
|
<string name="license_pref_cc_by_3_0" translatable="false">CC BY 3.0</string>
|
||||||
|
<string name="license_pref_cc_by_sa_3_0" translatable="false">CC BY-SA 3.0</string>
|
||||||
|
<string name="license_pref_cc_by_4_0" translatable="false">CC BY 4.0</string>
|
||||||
|
<string name="license_pref_cc_by_sa_4_0" translatable="false">CC BY-SA 4.0</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -170,6 +170,8 @@ Tap this message (or hit back) to skip this step.</string>
|
||||||
<string name="beta_opt_in_link">https://play.google.com/apps/testing/fr.free.nrw.commons</string>
|
<string name="beta_opt_in_link">https://play.google.com/apps/testing/fr.free.nrw.commons</string>
|
||||||
<string name="use_wikidata">Use Wikidata</string>
|
<string name="use_wikidata">Use Wikidata</string>
|
||||||
<string name="use_wikidata_summary">(Warning: disabling this may cause large mobile data consumption)</string>
|
<string name="use_wikidata_summary">(Warning: disabling this may cause large mobile data consumption)</string>
|
||||||
|
<string name="map_theme_light">mapbox://styles/mapbox/traffic-day-v2</string>
|
||||||
|
<string name="map_theme_dark">mapbox://styles/mapbox/traffic-night-v2</string>
|
||||||
<string name="mapbox_commons_app_token">pk.eyJ1IjoibWFza2FyYXZpdmVrIiwiYSI6ImNqMmxvdzFjMTAwMHYzM283ZWM3eW5tcDAifQ.ib5SZ9EVjwJe6GSKve0bcg</string>
|
<string name="mapbox_commons_app_token">pk.eyJ1IjoibWFza2FyYXZpdmVrIiwiYSI6ImNqMmxvdzFjMTAwMHYzM283ZWM3eW5tcDAifQ.ib5SZ9EVjwJe6GSKve0bcg</string>
|
||||||
<string name="number_of_uploads">My Recent Upload Limit</string>
|
<string name="number_of_uploads">My Recent Upload Limit</string>
|
||||||
<string name="maximum_limit">Maximum Limit</string>
|
<string name="maximum_limit">Maximum Limit</string>
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,10 @@
|
||||||
|
|
||||||
<style name="ProgressBar" parent="Widget.AppCompat.ProgressBar.Horizontal" />
|
<style name="ProgressBar" parent="Widget.AppCompat.ProgressBar.Horizontal" />
|
||||||
|
|
||||||
|
<style name="borderless_dialog">
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowIsFloating">true</item>
|
||||||
|
<item name="android:background">@android:color/transparent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
android:title="@string/preference_license"
|
android:title="@string/preference_license"
|
||||||
android:entries="@array/pref_defaultLicense_entries"
|
android:entries="@array/pref_defaultLicense_entries"
|
||||||
android:entryValues="@array/pref_defaultLicense_values"
|
android:entryValues="@array/pref_defaultLicense_values"
|
||||||
android:defaultValue="@string/license_name_cc_by_sa_4_0"
|
android:defaultValue="@string/license_pref_cc_by_sa_4_0"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
|
|
|
||||||