mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-29 13:53:54 +01:00
Added functionality to export location of nearby missing pictures to GPX file and KML file (#5645)
* Fixed Grey empty screen at Upload wizard caption step after denying files permission * Empty commit * Fixed loop issue * Created docs for earlier commits * Fixed javadoc * Fixed spaces * Added added basic features to OSM Maps * Added search location feature * Added filter to Open Street Maps * Fixed chipGroup in Open Street Maps * Removed mapBox code * Removed mapBox's code * Reformat code * Reformatted code * Removed rotation feature to map * Removed rotation files and Fixed Marker click problem * Ignored failing tests * Added voice input feature * Fixed test cases * Changed caption and description text * Replaced mapbox to osmdroid in upload activity * Fixed Unit Tests * Made selected marker to be fixed on map * Changed color of map marker * Fixes #5439 by capitalizing first letter of voice input * Removed mapbox code1 * Removed mapbox code2 * Fixed failing tests * Fixed failing due to merging * Added feature to save nearby places as GPX and KML * Fixed error caused by null
This commit is contained in:
parent
dae1f2557e
commit
c41940241b
7 changed files with 443 additions and 0 deletions
|
|
@ -118,6 +118,14 @@ public class NearbyController extends MapController {
|
|||
return nearbyPlacesInfo;
|
||||
}
|
||||
|
||||
public String getPlacesAsKML(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
|
||||
return nearbyPlaces.getPlacesAsKML(leftLatLng, rightLatLng);
|
||||
}
|
||||
|
||||
public String getPlacesAsGPX(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
|
||||
return nearbyPlaces.getPlacesAsGPX(leftLatLng, rightLatLng);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares Place list to make their distance information update later.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -119,4 +119,27 @@ public class NearbyPlaces {
|
|||
.getNearbyPlaces(screenTopRight, screenBottomLeft, lang, shouldQueryForMonuments,
|
||||
customQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Wikidata query to retrieve the KML String
|
||||
*
|
||||
* @param leftLatLng coordinates of Left Most position
|
||||
* @param rightLatLng coordinates of Right Most position
|
||||
* @throws IOException if query fails
|
||||
*/
|
||||
public String getPlacesAsKML(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
|
||||
return okHttpJsonApiClient.getPlacesAsKML(leftLatLng, rightLatLng);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Wikidata query to retrieve the GPX String
|
||||
*
|
||||
* @param leftLatLng coordinates of Left Most position
|
||||
* @param rightLatLng coordinates of Right Most position
|
||||
* @throws IOException if query fails
|
||||
*/
|
||||
public String getPlacesAsGPX(LatLng leftLatLng, LatLng rightLatLng) throws Exception {
|
||||
return okHttpJsonApiClient.getPlacesAsGPX(leftLatLng, rightLatLng);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import android.location.Location;
|
|||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.text.Html;
|
||||
|
|
@ -80,6 +81,7 @@ import fr.free.nrw.commons.contributions.MainActivity;
|
|||
import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment;
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.location.LocationUpdateListener;
|
||||
import fr.free.nrw.commons.nearby.CheckBoxTriStates;
|
||||
|
|
@ -105,11 +107,15 @@ import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
|||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
|
|
@ -357,6 +363,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
@NonNull final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.nearby_fragment_menu, menu);
|
||||
MenuItem listMenu = menu.findItem(R.id.list_sheet);
|
||||
MenuItem saveAsGPXButton = menu.findItem(R.id.list_item_gpx);
|
||||
MenuItem saveAsKMLButton = menu.findItem(R.id.list_item_kml);
|
||||
listMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
|
|
@ -364,6 +372,44 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
return false;
|
||||
}
|
||||
});
|
||||
saveAsGPXButton.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(@NonNull MenuItem item) {
|
||||
try {
|
||||
IGeoPoint screenTopRight = mapView.getProjection().fromPixels(mapView.getWidth(), 0);
|
||||
IGeoPoint screenBottomLeft = mapView.getProjection().fromPixels(0, mapView.getHeight());
|
||||
fr.free.nrw.commons.location.LatLng screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng(
|
||||
screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0);
|
||||
fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(
|
||||
screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0);
|
||||
setProgressBarVisibility(true);
|
||||
savePlacesAsGPX(screenTopRightLatLng,screenBottomLeftLatLng);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
saveAsKMLButton.setOnMenuItemClickListener(new OnMenuItemClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(@NonNull MenuItem item) {
|
||||
try {
|
||||
IGeoPoint screenTopRight = mapView.getProjection().fromPixels(mapView.getWidth(), 0);
|
||||
IGeoPoint screenBottomLeft = mapView.getProjection().fromPixels(0, mapView.getHeight());
|
||||
fr.free.nrw.commons.location.LatLng screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng(
|
||||
screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0);
|
||||
fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(
|
||||
screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0);
|
||||
setProgressBarVisibility(true);
|
||||
savePlacesAsKML(screenTopRightLatLng,screenBottomLeftLatLng);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1198,6 +1244,102 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}
|
||||
}
|
||||
|
||||
private void savePlacesAsKML(LatLng latLng, LatLng nextlatLng) {
|
||||
final Observable<String> savePlacesObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.getPlacesAsKML(latLng, nextlatLng));
|
||||
compositeDisposable.add(savePlacesObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(kmlString -> {
|
||||
if (kmlString != null) {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
|
||||
Locale.getDefault()).format(new Date());
|
||||
String fileName =
|
||||
"KML_" + timeStamp + "_" + System.currentTimeMillis() + ".kml";
|
||||
boolean saved = saveFile(kmlString, fileName);
|
||||
setProgressBarVisibility(false);
|
||||
if (saved) {
|
||||
Toast.makeText(this.getContext(),
|
||||
"KML file saved successfully at /Downloads/" + fileName,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this.getContext(), "Failed to save KML file.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
},
|
||||
throwable -> {
|
||||
Timber.d(throwable);
|
||||
showErrorMessage(getString(R.string.error_fetching_nearby_places)
|
||||
+ throwable.getLocalizedMessage());
|
||||
setProgressBarVisibility(false);
|
||||
presenter.lockUnlockNearby(false);
|
||||
setFilterState();
|
||||
}));
|
||||
}
|
||||
|
||||
private void savePlacesAsGPX(LatLng latLng, LatLng nextlatLng) {
|
||||
final Observable<String> savePlacesObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.getPlacesAsGPX(latLng, nextlatLng));
|
||||
compositeDisposable.add(savePlacesObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(gpxString -> {
|
||||
if (gpxString != null) {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
|
||||
Locale.getDefault()).format(new Date());
|
||||
String fileName =
|
||||
"GPX_" + timeStamp + "_" + System.currentTimeMillis() + ".gpx";
|
||||
boolean saved = saveFile(gpxString, fileName);
|
||||
setProgressBarVisibility(false);
|
||||
if (saved) {
|
||||
Toast.makeText(this.getContext(),
|
||||
"GPX file saved successfully at /Downloads/" + fileName,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this.getContext(), "Failed to save KML file.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
},
|
||||
throwable -> {
|
||||
Timber.d(throwable);
|
||||
showErrorMessage(getString(R.string.error_fetching_nearby_places)
|
||||
+ throwable.getLocalizedMessage());
|
||||
setProgressBarVisibility(false);
|
||||
presenter.lockUnlockNearby(false);
|
||||
setFilterState();
|
||||
}));
|
||||
}
|
||||
|
||||
public static boolean saveFile(String string, String fileName) {
|
||||
|
||||
if (!isExternalStorageWritable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File downloadsDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS);
|
||||
File kmlFile = new File(downloadsDir, fileName);
|
||||
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(kmlFile);
|
||||
fos.write(string.getBytes());
|
||||
fos.close();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExternalStorageWritable() {
|
||||
String state = Environment.getExternalStorageState();
|
||||
return Environment.MEDIA_MOUNTED.equals(state);
|
||||
}
|
||||
|
||||
private void populatePlacesForCurrentLocation(
|
||||
final fr.free.nrw.commons.location.LatLng currentLatLng,
|
||||
final fr.free.nrw.commons.location.LatLng screenTopRight,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
package fr.free.nrw.commons.nearby.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class PlaceBindings(
|
||||
@SerializedName("item") val item: Item,
|
||||
@SerializedName("label") val label: Label,
|
||||
@SerializedName("location") val location: Location,
|
||||
@SerializedName("class") val clas: Clas
|
||||
)
|
||||
|
||||
data class ItemsClass(
|
||||
@SerializedName("head") val head: Head,
|
||||
@SerializedName("results") val results: Results
|
||||
)
|
||||
|
||||
data class Label(
|
||||
@SerializedName("xml:lang") val xml: String,
|
||||
@SerializedName("type") val type: String,
|
||||
@SerializedName("value") val value: String
|
||||
)
|
||||
|
||||
data class Location(
|
||||
@SerializedName("datatype") val datatype: String,
|
||||
@SerializedName("type") val type: String,
|
||||
@SerializedName("value") val value: String
|
||||
)
|
||||
|
||||
data class Results(
|
||||
@SerializedName("bindings") val bindings: List<PlaceBindings>
|
||||
)
|
||||
|
||||
data class Item(
|
||||
@SerializedName("type") val type: String,
|
||||
@SerializedName("value") val value: String
|
||||
)
|
||||
|
||||
data class Head(
|
||||
@SerializedName("vars") val vars: List<String>
|
||||
)
|
||||
|
||||
|
||||
data class Clas(
|
||||
@SerializedName("type") val type: String,
|
||||
@SerializedName("value") val value: String
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue