Improved UX for Nearby Export (#5654)

* 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

* Improved UX for Nearby Export

* Delete app/src/main/res/values-yue-hant directory

* Fixed internationalization issue
This commit is contained in:
Kanahia 2024-03-28 19:42:54 +05:30 committed by GitHub
parent c5c5a52a09
commit 6d4ba12775
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 90 additions and 48 deletions

View file

@ -9,6 +9,8 @@ import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
import android.Manifest; import android.Manifest;
import android.Manifest.permission; import android.Manifest.permission;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -45,6 +47,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
@ -168,6 +171,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
private Place selectedPlace; private Place selectedPlace;
private Place clickedMarkerPlace; private Place clickedMarkerPlace;
private boolean isClickedMarkerBookmarked; private boolean isClickedMarkerBookmarked;
private ProgressDialog progressDialog;
private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005; private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005;
private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004;
private boolean isPermissionDenied; private boolean isPermissionDenied;
@ -257,6 +261,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
initNetworkBroadCastReceiver(); initNetworkBroadCastReceiver();
presenter = new NearbyParentFragmentPresenter(bookmarkLocationDao); presenter = new NearbyParentFragmentPresenter(bookmarkLocationDao);
progressDialog = new ProgressDialog(getActivity());
progressDialog.setCancelable(false);
progressDialog.setMessage("Saving in progress...");
setHasOptionsMenu(true); setHasOptionsMenu(true);
// Inflate the layout for this fragment // Inflate the layout for this fragment
return view; return view;
@ -288,8 +295,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0); screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0);
fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng( fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(
screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0); screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0);
setProgressBarVisibility(true); progressDialog.setTitle(getString(R.string.saving_gpx_file));
savePlacesAsGPX(screenTopRightLatLng,screenBottomLeftLatLng); progressDialog.show();
savePlacesAsGPX(screenTopRightLatLng, screenBottomLeftLatLng);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -307,8 +315,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0); screenBottomLeft.getLatitude(), screenBottomLeft.getLongitude(), 0);
fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng( fr.free.nrw.commons.location.LatLng screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(
screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0); screenTopRight.getLatitude(), screenTopRight.getLongitude(), 0);
setProgressBarVisibility(true); progressDialog.setTitle(getString(R.string.saving_kml_file));
savePlacesAsKML(screenTopRightLatLng,screenBottomLeftLatLng); progressDialog.show();
savePlacesAsKML(screenTopRightLatLng, screenBottomLeftLatLng);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -367,10 +376,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
binding.map.getOverlays().add(new MapEventsOverlay(new MapEventsReceiver() { binding.map.getOverlays().add(new MapEventsOverlay(new MapEventsReceiver() {
@Override @Override
public boolean singleTapConfirmedHelper(GeoPoint p) { public boolean singleTapConfirmedHelper(GeoPoint p) {
if (clickedMarkerPlace != null){ if (clickedMarkerPlace != null) {
removeMarker(clickedMarkerPlace); removeMarker(clickedMarkerPlace);
addMarkerToMap(clickedMarkerPlace,isClickedMarkerBookmarked); addMarkerToMap(clickedMarkerPlace, isClickedMarkerBookmarked);
}else { } else {
Timber.e("CLICKED MARKER IS NULL"); Timber.e("CLICKED MARKER IS NULL");
} }
if (isListBottomSheetExpanded()) { if (isListBottomSheetExpanded()) {
@ -441,7 +450,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
final AdvanceQueryFragment fragment = new AdvanceQueryFragment(); final AdvanceQueryFragment fragment = new AdvanceQueryFragment();
final Bundle bundle = new Bundle(); final Bundle bundle = new Bundle();
try { try {
bundle.putString("query", FileUtils.readFromResource("/queries/radius_query_for_upload_wizard.rq")); bundle.putString("query",
FileUtils.readFromResource("/queries/radius_query_for_upload_wizard.rq"));
} catch (IOException e) { } catch (IOException e) {
Timber.e(e); Timber.e(e);
} }
@ -507,7 +517,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
binding.bottomSheetNearby.rvNearbyList.setLayoutManager(new LinearLayoutManager(getContext())); binding.bottomSheetNearby.rvNearbyList.setLayoutManager(new LinearLayoutManager(getContext()));
adapter = new PlaceAdapter(bookmarkLocationDao, adapter = new PlaceAdapter(bookmarkLocationDao,
place -> { place -> {
moveCameraToPosition(new GeoPoint(place.location.getLatitude(),place.location.getLongitude())); moveCameraToPosition(
new GeoPoint(place.location.getLatitude(), place.location.getLongitude()));
return Unit.INSTANCE; return Unit.INSTANCE;
}, },
(place, isBookmarked) -> { (place, isBookmarked) -> {
@ -1166,13 +1177,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
String fileName = String fileName =
"KML_" + timeStamp + "_" + System.currentTimeMillis() + ".kml"; "KML_" + timeStamp + "_" + System.currentTimeMillis() + ".kml";
boolean saved = saveFile(kmlString, fileName); boolean saved = saveFile(kmlString, fileName);
setProgressBarVisibility(false); progressDialog.hide();
if (saved) { if (saved) {
Toast.makeText(this.getContext(), showOpenFileDialog(getContext(), fileName, false);
"KML file saved successfully at /Downloads/" + fileName,
Toast.LENGTH_SHORT).show();
} else { } else {
Toast.makeText(this.getContext(), "Failed to save KML file.", Toast.makeText(this.getContext(),
getString(R.string.failed_to_save_kml_file),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
} }
@ -1201,13 +1211,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
String fileName = String fileName =
"GPX_" + timeStamp + "_" + System.currentTimeMillis() + ".gpx"; "GPX_" + timeStamp + "_" + System.currentTimeMillis() + ".gpx";
boolean saved = saveFile(gpxString, fileName); boolean saved = saveFile(gpxString, fileName);
setProgressBarVisibility(false); progressDialog.hide();
if (saved) { if (saved) {
Toast.makeText(this.getContext(), showOpenFileDialog(getContext(), fileName, true);
"GPX file saved successfully at /Downloads/" + fileName,
Toast.LENGTH_SHORT).show();
} else { } else {
Toast.makeText(this.getContext(), "Failed to save KML file.", Toast.makeText(this.getContext(),
getString(R.string.failed_to_save_gpx_file),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
} }
} }
@ -1243,6 +1252,38 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
} }
} }
private void showOpenFileDialog(Context context, String fileName, Boolean isGPX) {
String title = getString(R.string.file_saved_successfully);
String message =
(isGPX) ? getString(R.string.do_you_want_to_open_gpx_file)
: getString(R.string.do_you_want_to_open_kml_file);
Runnable runnable = () -> openFile(context, fileName, isGPX);
DialogUtil.showAlertDialog(getActivity(), title, message, runnable,() -> {});
}
private void openFile(Context context, String fileName, Boolean isGPX) {
File file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
fileName);
Uri uri = FileProvider.getUriForFile(context,
context.getApplicationContext().getPackageName() + ".provider", file);
Intent intent = new Intent(Intent.ACTION_VIEW);
if (isGPX) {
intent.setDataAndType(uri, "application/gpx");
} else {
intent.setDataAndType(uri, "application/kml");
}
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(context, R.string.no_application_available_to_open_gpx_files,
Toast.LENGTH_SHORT).show();
}
}
private static boolean isExternalStorageWritable() { private static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState(); String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state); return Environment.MEDIA_MOUNTED.equals(state);
@ -1486,7 +1527,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
.setMessage(R.string.login_alert_message) .setMessage(R.string.login_alert_message)
.setPositiveButton(R.string.login, (dialog, which) -> { .setPositiveButton(R.string.login, (dialog, which) -> {
// logout of the app // logout of the app
BaseLogoutListener logoutListener = new BaseLogoutListener(getActivity()); CommonsApplication app = (CommonsApplication) getActivity().getApplication(); BaseLogoutListener logoutListener = new BaseLogoutListener(getActivity());
CommonsApplication app = (CommonsApplication) getActivity().getApplication();
app.clearApplicationData(getContext(), logoutListener); app.clearApplicationData(getContext(), logoutListener);
}) })
.show(); .show();
@ -1557,14 +1599,15 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
* Adds a marker for the user's current position. Adds a circle which uses the accuracy * 2, to * Adds a marker for the user's current position. Adds a circle which uses the accuracy * 2, to
* draw a circle which represents the user's position with an accuracy of 95%. * draw a circle which represents the user's position with an accuracy of 95%.
* <p> * <p>
* Should be called only on creation of Map, there is other method to update markers * Should be called only on creation of Map, there is other method to update markers location
* location with users move. * with users move.
* *
* @param currentLatLng current location * @param currentLatLng current location
*/ */
@Override @Override
public void addCurrentLocationMarker(final fr.free.nrw.commons.location.LatLng currentLatLng) { public void addCurrentLocationMarker(final fr.free.nrw.commons.location.LatLng currentLatLng) {
if (null != currentLatLng && !isPermissionDenied && locationManager.isGPSProviderEnabled()) { if (null != currentLatLng && !isPermissionDenied
&& locationManager.isGPSProviderEnabled()) {
ExecutorUtils.get().submit(() -> { ExecutorUtils.get().submit(() -> {
Timber.d("Adds current location marker"); Timber.d("Adds current location marker");
recenterMarkerToPosition( recenterMarkerToPosition(
@ -1696,12 +1739,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
* @return returns the drawable of marker according to the place information * @return returns the drawable of marker according to the place information
*/ */
private @DrawableRes int getIconFor(Place place, Boolean isBookmarked) { private @DrawableRes int getIconFor(Place place, Boolean isBookmarked) {
if(nearestPlace!=null) { if (nearestPlace != null) {
if(place.name.equals(nearestPlace.name)) { if (place.name.equals(nearestPlace.name)) {
// Highlight nearest place only when user clicks on the home nearby banner // Highlight nearest place only when user clicks on the home nearby banner
highlightNearestPlace(place); highlightNearestPlace(place);
return (isBookmarked? return (isBookmarked ?
R.drawable.ic_custom_map_marker_purple_bookmarked: R.drawable.ic_custom_map_marker_purple_bookmarked :
R.drawable.ic_custom_map_marker_purple); R.drawable.ic_custom_map_marker_purple);
} }
} }
@ -1743,10 +1786,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
hideBottomSheet(); hideBottomSheet();
if (clickedMarkerPlace != null) { if (clickedMarkerPlace != null) {
removeMarker(clickedMarkerPlace); removeMarker(clickedMarkerPlace);
addMarkerToMap(clickedMarkerPlace,isClickedMarkerBookmarked); addMarkerToMap(clickedMarkerPlace, isClickedMarkerBookmarked);
} }
clickedMarkerPlace = place; clickedMarkerPlace = place;
isClickedMarkerBookmarked = isBookMarked ; isClickedMarkerBookmarked = isBookMarked;
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
return true; return true;
} }
@ -1789,10 +1832,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
hideBottomSheet(); hideBottomSheet();
if (clickedMarkerPlace != null) { if (clickedMarkerPlace != null) {
removeMarker(clickedMarkerPlace); removeMarker(clickedMarkerPlace);
addMarkerToMap(clickedMarkerPlace,isClickedMarkerBookmarked); addMarkerToMap(clickedMarkerPlace, isClickedMarkerBookmarked);
} }
clickedMarkerPlace = place ; clickedMarkerPlace = place;
isClickedMarkerBookmarked = false ; isClickedMarkerBookmarked = false;
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
return true; return true;
} }
@ -2134,10 +2177,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
binding.map.getOverlays().add(new MapEventsOverlay(new MapEventsReceiver() { binding.map.getOverlays().add(new MapEventsOverlay(new MapEventsReceiver() {
@Override @Override
public boolean singleTapConfirmedHelper(GeoPoint p) { public boolean singleTapConfirmedHelper(GeoPoint p) {
if (clickedMarkerPlace != null){ if (clickedMarkerPlace != null) {
removeMarker(clickedMarkerPlace); removeMarker(clickedMarkerPlace);
addMarkerToMap(clickedMarkerPlace,isClickedMarkerBookmarked); addMarkerToMap(clickedMarkerPlace, isClickedMarkerBookmarked);
}else { } else {
Timber.e("CLICKED MARKER IS NULL"); Timber.e("CLICKED MARKER IS NULL");
} }
if (isListBottomSheetExpanded()) { if (isListBottomSheetExpanded()) {

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Winston Sung
-->
<resources>
<string name="crash_dialog_title">同享壞咗</string>
<string name="crash_dialog_text">哎呀。出咗錯!</string>
<string name="crash_dialog_ok_toast">多謝你!</string>
</resources>

View file

@ -793,6 +793,14 @@ Upload your first media by tapping on the add button.</string>
<string name="send_thanks_to_author">Thank the author</string> <string name="send_thanks_to_author">Thank the author</string>
<string name="error_sending_thanks">Error sending thanks to author.</string> <string name="error_sending_thanks">Error sending thanks to author.</string>
<string name="invalid_login_message">Your log-in has expired. Please log in again.</string> <string name="invalid_login_message">Your log-in has expired. Please log in again.</string>
<string name="no_application_available_to_open_gpx_files">No application available to open GPX files</string>
<string name="file_saved_successfully">File Saved Successfully</string>
<string name="do_you_want_to_open_gpx_file">Do you want to open GPX file?</string>
<string name="do_you_want_to_open_kml_file">Do you want to open KML file?</string>
<string name="failed_to_save_kml_file">Failed to save KML file.</string>
<string name="failed_to_save_gpx_file">Failed to save GPX file.</string>
<string name="saving_kml_file">Saving KML File</string>
<string name="saving_gpx_file">Saving GPX File</string>
<plurals name="custom_picker_images_selected_title_appendix"> <plurals name="custom_picker_images_selected_title_appendix">
<item quantity="one">%d image selected</item> <item quantity="one">%d image selected</item>
<item quantity="other">%d images selected</item> <item quantity="other">%d images selected</item>