Search this area (#2051)

* Recognize user is moving on the map and show a button

* Use variable from strings xml instead of hardcoded string

* Change search this area button location in xml file

* Add location util file to convert mapbox LatLng to commons Latlng and viceversa

* Populate places around searched area

* Update narby map according to new points came from searched area

* Add searchThisAreaMode boolean to stop nearby map updated when we try to search nearby areas.

* Lock auto nearby operations during serch this area mode, with a more modular method and decrease code repetition

* Add an if clausse to prevent multiple refresh view calls, while map is moving

* Disable map gestures during search this area operation, re-eable them on operation is done

* Add progress bar during search this area operation

* Make sure you locked the map during search nearby map process

* Implement recenter map view button

* Fix logic problem and make sure you refreshed the view on coming back to previous position

* Use custom refresh method instead

* Use latest updated location from location manager isntead

* Update ListFragment accordingly too

* Do not update camera target according to bottom sheet status or do not follow users location with camera, if search this area mode is on

* Add javadocs, sorry forgotten previously

* Remove unused method

* Threat both or search this area and regular search in same way

* Make sure distances are correct

* Seperate cutom location updates and current location updates from each other to continue other operations

* Remove all logs, and make sure search this are button is not visible for no reason while around of current location is already loaded

* Notify load attractions from location method about search status, current location of custom location

* Make sure we calculate searched area and display search this area button when we are out of 3/4 of total searched area
This commit is contained in:
neslihanturan 2018-12-05 19:06:50 +02:00 committed by Josephine Lim
parent b907a0a8f1
commit 677e0099af
9 changed files with 283 additions and 32 deletions

View file

@ -622,7 +622,7 @@ public class ContributionsFragment
curLatLng = locationManager.getLastLocation(); curLatLng = locationManager.getLastLocation();
placesDisposable = Observable.fromCallable(() -> nearbyController placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLng, true)) // thanks to boolean, it will only return closest result .loadAttractionsFromLocation(curLatLng, curLatLng, true, false)) // thanks to boolean, it will only return closest result
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateNearbyNotification, .subscribe(this::updateNearbyNotification,

View file

@ -5,6 +5,7 @@ import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.support.graphics.drawable.VectorDrawableCompat; import android.support.graphics.drawable.VectorDrawableCompat;
import android.util.Log;
import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.IconFactory;
@ -31,6 +32,8 @@ public class NearbyController {
private static final int MAX_RESULTS = 1000; private static final int MAX_RESULTS = 1000;
private final NearbyPlaces nearbyPlaces; private final NearbyPlaces nearbyPlaces;
private final SharedPreferences prefs; private final SharedPreferences prefs;
public static double searchedRadius = 10.0; //in kilometers
public static LatLng currentLocation;
@Inject @Inject
public NearbyController(NearbyPlaces nearbyPlaces, public NearbyController(NearbyPlaces nearbyPlaces,
@ -44,18 +47,21 @@ public class NearbyController {
* Prepares Place list to make their distance information update later. * Prepares Place list to make their distance information update later.
* *
* @param curLatLng current location for user * @param curLatLng current location for user
* @param latLangToSearchAround the location user wants to search around
* @param returnClosestResult if this search is done to find closest result or all results
* @return NearbyPlacesInfo a variable holds Place list without distance information * @return NearbyPlacesInfo a variable holds Place list without distance information
* and boundary coordinates of current Place List * and boundary coordinates of current Place List
*/ */
public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng, boolean returnClosestResult) throws IOException { public NearbyPlacesInfo loadAttractionsFromLocation(LatLng curLatLng, LatLng latLangToSearchAround, boolean returnClosestResult, boolean checkingAroundCurrentLocation) throws IOException {
Timber.d("Loading attractions near %s", curLatLng);
Timber.d("Loading attractions near %s", latLangToSearchAround);
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo(); NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
if (curLatLng == null) { if (latLangToSearchAround == null) {
Timber.d("Loading attractions neari, but curLatLng is null"); Timber.d("Loading attractions neari, but curLatLng is null");
return null; return null;
} }
List<Place> places = nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage(), returnClosestResult); List<Place> places = nearbyPlaces.getFromWikidataQuery(latLangToSearchAround, Locale.getDefault().getLanguage(), returnClosestResult);
if (null != places && places.size() > 0) { if (null != places && places.size() > 0) {
LatLng[] boundaryCoordinates = {places.get(0).location, // south LatLng[] boundaryCoordinates = {places.get(0).location, // south
@ -93,6 +99,11 @@ public class NearbyController {
} }
nearbyPlacesInfo.placeList = places; nearbyPlacesInfo.placeList = places;
nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates; nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates;
if (!returnClosestResult && checkingAroundCurrentLocation) {
// Do not update searched radius, if controller is used for nearby card notification
searchedRadius = nearbyPlaces.radius;
currentLocation = curLatLng;
}
return nearbyPlacesInfo; return nearbyPlacesInfo;
} }
else { else {

View file

@ -14,6 +14,7 @@ import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.Snackbar; import android.support.design.widget.Snackbar;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -64,8 +65,6 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
LinearLayout bottomSheetDetails; LinearLayout bottomSheetDetails;
@BindView(R.id.transparentView) @BindView(R.id.transparentView)
View transparentView; View transparentView;
@BindView(R.id.fab_recenter)
View fabRecenter;
@Inject @Inject
LocationServiceManager locationManager; LocationServiceManager locationManager;
@ -87,16 +86,19 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
private LatLng curLatLng; private LatLng curLatLng;
private Disposable placesDisposable; private Disposable placesDisposable;
private Disposable placesDisposableCustom;
private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed private boolean lockNearbyView; //Determines if the nearby places needs to be refreshed
public View view; public View view;
private Snackbar snackbar; private Snackbar snackbar;
private LatLng lastKnownLocation; private LatLng lastKnownLocation;
private LatLng customLatLng;
private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
private BroadcastReceiver broadcastReceiver; private BroadcastReceiver broadcastReceiver;
private boolean onOrientationChanged = false; private boolean onOrientationChanged = false;
private boolean populateForCurrentLocation = false;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -216,24 +218,27 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
@Override @Override
public void onLocationChangedSignificantly(LatLng latLng) { public void onLocationChangedSignificantly(LatLng latLng) {
refreshView(LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} }
@Override @Override
public void onLocationChangedSlightly(LatLng latLng) { public void onLocationChangedSlightly(LatLng latLng) {
refreshView(LOCATION_SLIGHTLY_CHANGED); refreshView(LOCATION_SLIGHTLY_CHANGED);
} }
@Override @Override
public void onLocationChangedMedium(LatLng latLng) { public void onLocationChangedMedium(LatLng latLng) {
// For nearby map actions, there are no differences between 500 meter location change (aka medium change) and slight change // For nearby map actions, there are no differences between 500 meter location change (aka medium change) and slight change
refreshView(LOCATION_SLIGHTLY_CHANGED); refreshView(LOCATION_SLIGHTLY_CHANGED);
} }
@Override @Override
public void onWikidataEditSuccessful() { public void onWikidataEditSuccessful() {
refreshView(MAP_UPDATED); // Do not refresh nearby map if we are checking other areas with search this area button
if (!nearbyMapFragment.searchThisAreaModeOn) {
refreshView(MAP_UPDATED);
}
} }
/** /**
@ -241,7 +246,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
* *
* @param locationChangeType defines if location shanged significantly or slightly * @param locationChangeType defines if location shanged significantly or slightly
*/ */
private void refreshView(LocationServiceManager.LocationChangeType locationChangeType) { public void refreshView(LocationServiceManager.LocationChangeType locationChangeType) {
Timber.d("Refreshing nearby places"); Timber.d("Refreshing nearby places");
if (lockNearbyView) { if (lockNearbyView) {
return; return;
@ -257,9 +262,11 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
if (curLatLng != null && curLatLng.equals(lastLocation) if (curLatLng != null && curLatLng.equals(lastLocation)
&& !locationChangeType.equals(MAP_UPDATED)) { //refresh view only if location has changed && !locationChangeType.equals(MAP_UPDATED)) { //refresh view only if location has changed
// Two exceptional cases to refresh nearby map manually.
if (!onOrientationChanged) { if (!onOrientationChanged) {
return; return;
} }
} }
curLatLng = lastLocation; curLatLng = lastLocation;
@ -292,7 +299,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("CurLatLng", gsonCurLatLng);
placesDisposable = Observable.fromCallable(() -> nearbyController placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLng, false)) .loadAttractionsFromLocation(curLatLng, curLatLng, false, true))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlaces, .subscribe(this::populatePlaces,
@ -301,6 +308,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
showErrorMessage(getString(R.string.error_fetching_nearby_places)); showErrorMessage(getString(R.string.error_fetching_nearby_places));
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
}); });
} else if (locationChangeType } else if (locationChangeType
.equals(LOCATION_SLIGHTLY_CHANGED)) { .equals(LOCATION_SLIGHTLY_CHANGED)) {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
@ -308,7 +316,62 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
.create(); .create();
String gsonCurLatLng = gson.toJson(curLatLng); String gsonCurLatLng = gson.toJson(curLatLng);
bundle.putString("CurLatLng", gsonCurLatLng); bundle.putString("CurLatLng", gsonCurLatLng);
updateMapFragment(true); updateMapFragment(false,true, null, null);
}
if (nearbyMapFragment != null) {
nearbyMapFragment.searchThisAreaButton.setVisibility(View.GONE);
}
}
/**
* This method should be used with "Search this are button". This method will search nearby
* points around any custom location (target location when user clicked on search this area)
* button. It populates places for custom location.
* @param customLatLng Custom area which we will search around
*/
public void refreshViewForCustomLocation(LatLng customLatLng, boolean refreshForCurrentLocation) {
if (customLatLng == null) {
// If null, return
return;
}
populateForCurrentLocation = refreshForCurrentLocation;
this.customLatLng = customLatLng;
placesDisposableCustom = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLng, customLatLng, false, populateForCurrentLocation))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlacesFromCustomLocation,
throwable -> {
Timber.d(throwable);
showErrorMessage(getString(R.string.error_fetching_nearby_places));
});
if (nearbyMapFragment != null) {
nearbyMapFragment.searchThisAreaButton.setVisibility(View.GONE);
}
}
/**
* Populates places for custom location, should be used for finding nearby places around a
* location where you are not at.
* @param nearbyPlacesInfo This variable has place list information and distances.
*/
private void populatePlacesFromCustomLocation(NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
//NearbyMapFragment nearbyMapFragment = getMapFragment();
if (nearbyMapFragment != null) {
nearbyMapFragment.searchThisAreaButtonProgressBar.setVisibility(View.GONE);
}
if (nearbyMapFragment != null && curLatLng != null) {
if (!populateForCurrentLocation) {
nearbyMapFragment.updateMapSignificantlyForCustomLocation(customLatLng, nearbyPlacesInfo.placeList);
} else {
updateMapFragment(true,true, customLatLng, nearbyPlacesInfo);
}
updateListFragmentForCustomLocation(nearbyPlacesInfo.placeList);
} }
} }
@ -342,7 +405,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
} else { } else {
// There are fragments, just update the map and list // There are fragments, just update the map and list
Timber.d("Map fragment already exists, just update the map and list"); Timber.d("Map fragment already exists, just update the map and list");
updateMapFragment(false); updateMapFragment(false,false, null, null);
updateListFragment(); updateListFragment();
} }
} }
@ -364,7 +427,11 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
} }
} }
private void updateMapFragment(boolean isSlightUpdate) { private void updateMapFragment(boolean updateViaButton, boolean isSlightUpdate, @Nullable LatLng customLatLng, @Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
if (nearbyMapFragment.searchThisAreaModeOn) {
return;
}
/* /*
Significant update means updating nearby place markers. Slightly update means only Significant update means updating nearby place markers. Slightly update means only
updating current location marker and camera target. updating current location marker and camera target.
@ -380,14 +447,14 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
* If we are close to nearby places boundaries, we need a significant update to * If we are close to nearby places boundaries, we need a significant update to
* get new nearby places. Check order is south, north, west, east * get new nearby places. Check order is south, north, west, east
* */ * */
if (nearbyMapFragment.boundaryCoordinates != null if (nearbyMapFragment.boundaryCoordinates != null && !nearbyMapFragment.searchThisAreaModeOn
&& (curLatLng.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude() && (curLatLng.getLatitude() <= nearbyMapFragment.boundaryCoordinates[0].getLatitude()
|| curLatLng.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude() || curLatLng.getLatitude() >= nearbyMapFragment.boundaryCoordinates[1].getLatitude()
|| curLatLng.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude() || curLatLng.getLongitude() <= nearbyMapFragment.boundaryCoordinates[2].getLongitude()
|| curLatLng.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) { || curLatLng.getLongitude() >= nearbyMapFragment.boundaryCoordinates[3].getLongitude())) {
// populate places // populate places
placesDisposable = Observable.fromCallable(() -> nearbyController placesDisposable = Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLng, false)) .loadAttractionsFromLocation(curLatLng, curLatLng, false, updateViaButton))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(this::populatePlaces, .subscribe(this::populatePlaces,
@ -397,11 +464,16 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
}); });
nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.setBundleForUpdtes(bundle);
nearbyMapFragment.updateMapSignificantly(); nearbyMapFragment.updateMapSignificantlyForCurrentLocation();
updateListFragment(); updateListFragment();
return; return;
} }
if (updateViaButton) {
nearbyMapFragment.updateMapSignificantlyForCustomLocation(customLatLng, nearbyPlacesInfo.placeList);
return;
}
/* /*
If this is the map update just after orientation change, then it is not a slight update If this is the map update just after orientation change, then it is not a slight update
anymore. We want to significantly update map after each orientation change anymore. We want to significantly update map after each orientation change
@ -416,7 +488,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
nearbyMapFragment.updateMapSlightly(); nearbyMapFragment.updateMapSlightly();
} else { } else {
nearbyMapFragment.setBundleForUpdtes(bundle); nearbyMapFragment.setBundleForUpdtes(bundle);
nearbyMapFragment.updateMapSignificantly(); nearbyMapFragment.updateMapSignificantlyForCurrentLocation();
updateListFragment(); updateListFragment();
} }
} else { } else {
@ -433,6 +505,15 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
nearbyListFragment.updateNearbyListSignificantly(); nearbyListFragment.updateNearbyListSignificantly();
} }
/**
* Updates nearby list for custom location, will be used with search this area method. When you
* want to search for a place where you are not at.
* @param placeList List of places around your manually chosen target location from map.
*/
private void updateListFragmentForCustomLocation(List<Place> placeList) {
nearbyListFragment.updateNearbyListSignificantlyForCustomLocation(placeList);
}
/** /**
* Calls fragment for map view. * Calls fragment for map view.
*/ */
@ -650,6 +731,9 @@ public class NearbyFragment extends CommonsDaggerSupportFragment
if (placesDisposable != null) { if (placesDisposable != null) {
placesDisposable.dispose(); placesDisposable.dispose();
} }
if (placesDisposableCustom != null) {
placesDisposableCustom.dispose();
}
} }
@Override @Override

View file

@ -98,6 +98,19 @@ public class NearbyListFragment extends DaggerFragment {
} }
} }
/**
* While nearby updates for current location held with bundle, automatically, custom updates are
* done by calling this methods, triddered by search this are button input from user.
* @param placeList
*/
public void updateNearbyListSignificantlyForCustomLocation(List<Place> placeList) {
try {
adapterFactory.updateAdapterData(placeList, (RVRendererAdapter<Place>) recyclerView.getAdapter());
} catch (NullPointerException e) {
Timber.e("Null pointer exception from calling recyclerView.getAdapter()");
}
}
private List<Place> getPlaceListFromBundle(Bundle bundle) { private List<Place> getPlaceListFromBundle(Bundle bundle) {
List<Place> placeList = Collections.emptyList(); List<Place> placeList = Collections.emptyList();

View file

@ -23,8 +23,10 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import com.google.gson.Gson; import com.google.gson.Gson;
@ -60,10 +62,11 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.LoginActivity; import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.ContributionController; import fr.free.nrw.commons.contributions.ContributionController;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.utils.UriDeserializer; import fr.free.nrw.commons.utils.UriDeserializer;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber; import timber.log.Timber;
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
import static android.app.Activity.RESULT_OK; import static android.app.Activity.RESULT_OK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@ -115,16 +118,21 @@ public class NearbyMapFragment extends DaggerFragment {
private Place place; private Place place;
private Marker selected; private Marker selected;
private Marker currentLocationMarker; private Marker currentLocationMarker;
private MapboxMap mapboxMap; public MapboxMap mapboxMap;
private PolygonOptions currentLocationPolygonOptions; private PolygonOptions currentLocationPolygonOptions;
public Button searchThisAreaButton;
public ProgressBar searchThisAreaButtonProgressBar;
private boolean isBottomListSheetExpanded; private boolean isBottomListSheetExpanded;
private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06; private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06;
private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04; private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04;
private boolean isMapReady; private boolean isMapReady;
public boolean searchThisAreaModeOn = false;
private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location
private boolean searchedAroundCurrentLocation = true;
@Inject @Inject
@Named("prefs") @Named("prefs")
@ -246,8 +254,8 @@ public class NearbyMapFragment extends DaggerFragment {
* called when user is out of boundaries (south, north, east or west) of markers drawn by * called when user is out of boundaries (south, north, east or west) of markers drawn by
* previous nearby call. * previous nearby call.
*/ */
public void updateMapSignificantly() { public void updateMapSignificantlyForCurrentLocation() {
Timber.d("updateMapSignificantly called, bundle is:"+bundleForUpdtes); Timber.d("updateMapSignificantlyForCurrentLocation called, bundle is:"+bundleForUpdtes);
if (mapboxMap != null) { if (mapboxMap != null) {
if (bundleForUpdtes != null) { if (bundleForUpdtes != null) {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
@ -271,10 +279,32 @@ public class NearbyMapFragment extends DaggerFragment {
mapboxMap.clear(); mapboxMap.clear();
addCurrentLocationMarker(mapboxMap); addCurrentLocationMarker(mapboxMap);
updateMapToTrackPosition(); updateMapToTrackPosition();
addNearbyMarkerstoMapBoxMap(); // We are trying to find nearby places around our current location, thus custom parameter is nullified
addNearbyMarkerstoMapBoxMap(null);
} }
} }
/**
* Will be used for map vew updates for custom locations (ie. with search this area method).
* Clears the map, adds current location marker, adds nearby markers around custom location,
* re-enables map gestures which was locked during place load, remove progress bar.
* @param customLatLng custom location that we will search around
* @param placeList places around of custom location
*/
public void updateMapSignificantlyForCustomLocation(fr.free.nrw.commons.location.LatLng customLatLng, List<Place> placeList) {
List<NearbyBaseMarker> customBaseMarkerOptions = NearbyController
.loadAttractionsFromLocationToBaseMarkerOptions(curLatLng, // Curlatlang will be used to calculate distances
placeList,
getActivity());
mapboxMap.clear();
// We are trying to find nearby places around our custom searched area, thus custom parameter is nonnull
addNearbyMarkerstoMapBoxMap(customBaseMarkerOptions);
addCurrentLocationMarker(mapboxMap);
// Re-enable mapbox gestures on custom location markers load
mapboxMap.getUiSettings().setAllGesturesEnabled(true);
searchThisAreaButtonProgressBar.setVisibility(View.GONE);
}
// Only update current position marker and camera view // Only update current position marker and camera view
private void updateMapToTrackPosition() { private void updateMapToTrackPosition() {
@ -299,6 +329,9 @@ public class NearbyMapFragment extends DaggerFragment {
// Make camera to follow user on location change // Make camera to follow user on location change
CameraPosition position ; CameraPosition position ;
// Do not update camera position is search this area mode on
if (!searchThisAreaModeOn) {
if (ViewUtil.isPortrait(getActivity())){ if (ViewUtil.isPortrait(getActivity())){
position = new CameraPosition.Builder() position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ? .target(isBottomListSheetExpanded ?
@ -323,10 +356,10 @@ public class NearbyMapFragment extends DaggerFragment {
mapboxMap.animateCamera(CameraUpdateFactory mapboxMap.animateCamera(CameraUpdateFactory
.newCameraPosition(position), 1000); .newCameraPosition(position), 1000);
}
} }
} }
private void initViews() { private void initViews() {
Timber.d("initViews called"); Timber.d("initViews called");
bottomSheetList = ((NearbyFragment)getParentFragment()).view.findViewById(R.id.bottom_sheet); bottomSheetList = ((NearbyFragment)getParentFragment()).view.findViewById(R.id.bottom_sheet);
@ -366,6 +399,9 @@ public class NearbyMapFragment extends DaggerFragment {
bookmarkButton = getActivity().findViewById(R.id.bookmarkButton); bookmarkButton = getActivity().findViewById(R.id.bookmarkButton);
bookmarkButtonImage = getActivity().findViewById(R.id.bookmarkButtonImage); bookmarkButtonImage = getActivity().findViewById(R.id.bookmarkButtonImage);
searchThisAreaButton = ((NearbyFragment)getParentFragment()).view.findViewById(R.id.search_this_area_button);
searchThisAreaButtonProgressBar = ((NearbyFragment)getParentFragment()).view.findViewById(R.id.search_this_area_button_progres_bar);
} }
private void setListeners() { private void setListeners() {
@ -495,13 +531,77 @@ public class NearbyMapFragment extends DaggerFragment {
@Override @Override
public void onMapReady(MapboxMap mapboxMap) { public void onMapReady(MapboxMap mapboxMap) {
NearbyMapFragment.this.mapboxMap = mapboxMap; NearbyMapFragment.this.mapboxMap = mapboxMap;
updateMapSignificantly(); addMapMovementListeners();
updateMapSignificantlyForCurrentLocation();
} }
}); });
mapView.setStyleUrl("asset://mapstyle.json"); mapView.setStyleUrl("asset://mapstyle.json");
} }
} }
private void addMapMovementListeners() {
mapboxMap.addOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
if (NearbyController.currentLocation != null) { // If our nearby markers are calculated at least once
if (searchThisAreaButton.getVisibility() == View.GONE) {
searchThisAreaButton.setVisibility(View.VISIBLE);
}
double distance = mapboxMap.getCameraPosition().target
.distanceTo(new LatLng(NearbyController.currentLocation.getLatitude()
, NearbyController.currentLocation.getLongitude()));
if (distance > NearbyController.searchedRadius*1000*3/4) { //Convert to meter, and compare if our distance is bigger than 3/4 or our searched area
if (!searchThisAreaModeOn) { // If we are changing mode, then change click action
searchThisAreaModeOn = true;
searchThisAreaButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
searchThisAreaModeOn = true;
// Lock map operations during search this area operation
mapboxMap.getUiSettings().setAllGesturesEnabled(false);
searchThisAreaButtonProgressBar.setVisibility(View.VISIBLE);
searchThisAreaButton.setVisibility(View.GONE);
searchedAroundCurrentLocation = false;
((NearbyFragment)getParentFragment())
.refreshViewForCustomLocation(LocationUtils
.mapBoxLatLngToCommonsLatLng(mapboxMap.getCameraPosition().target), false);
}
});
}
} else {
if (searchThisAreaModeOn) {
searchThisAreaModeOn = false; // This flag will help us to understand should we folor users location or not
searchThisAreaButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
searchThisAreaModeOn = true;
// Lock map operations during search this area operation
mapboxMap.getUiSettings().setAllGesturesEnabled(false);
searchThisAreaButtonProgressBar.setVisibility(View.VISIBLE);
fabRecenter.callOnClick();
searchThisAreaButton.setVisibility(View.GONE);
searchedAroundCurrentLocation = true;
((NearbyFragment)getParentFragment())
.refreshViewForCustomLocation(LocationUtils
.mapBoxLatLngToCommonsLatLng(mapboxMap.getCameraPosition().target), true);
}
});
}
if (searchedAroundCurrentLocation) {
searchThisAreaButton.setVisibility(View.GONE);
}
}
}
}
});
}
/** /**
* onLogoutComplete is called after shared preferences and data stored in local database are cleared. * onLogoutComplete is called after shared preferences and data stored in local database are cleared.
*/ */
@ -554,10 +654,17 @@ public class NearbyMapFragment extends DaggerFragment {
/** /**
* Adds markers for nearby places to mapbox map * Adds markers for nearby places to mapbox map
*/ */
private void addNearbyMarkerstoMapBoxMap() { private void addNearbyMarkerstoMapBoxMap(@Nullable List<NearbyBaseMarker> customNearbyBaseMarker) {
List<NearbyBaseMarker> baseMarkerOptions;
Timber.d("addNearbyMarkerstoMapBoxMap is called"); Timber.d("addNearbyMarkerstoMapBoxMap is called");
if (customNearbyBaseMarker != null) {
// If we try to update nearby points for a custom location choosen from map (we are not there)
baseMarkerOptions = customNearbyBaseMarker;
} else {
// If we try to display nearby markers around our curret location
baseMarkerOptions = this.baseMarkerOptions;
}
mapboxMap.addMarkers(baseMarkerOptions); mapboxMap.addMarkers(baseMarkerOptions);
mapboxMap.setOnInfoWindowCloseListener(marker -> { mapboxMap.setOnInfoWindowCloseListener(marker -> {
if (marker == selected) { if (marker == selected) {
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);

View file

@ -30,7 +30,7 @@ public class NearbyPlaces {
private static final Uri WIKIDATA_QUERY_URL = Uri.parse("https://query.wikidata.org/sparql"); private static final Uri WIKIDATA_QUERY_URL = Uri.parse("https://query.wikidata.org/sparql");
private static final Uri WIKIDATA_QUERY_UI_URL = Uri.parse("https://query.wikidata.org/"); private static final Uri WIKIDATA_QUERY_UI_URL = Uri.parse("https://query.wikidata.org/");
private final String wikidataQuery; private final String wikidataQuery;
private double radius = INITIAL_RADIUS; public double radius = INITIAL_RADIUS;
public NearbyPlaces() { public NearbyPlaces() {
try { try {
@ -55,6 +55,7 @@ public class NearbyPlaces {
} else { } else {
MIN_RESULTS = 40; MIN_RESULTS = 40;
MAX_RADIUS = 300.0; // in kilometers MAX_RADIUS = 300.0; // in kilometers
radius = INITIAL_RADIUS;
} }
// increase the radius gradually to find a satisfactory number of nearby places // increase the radius gradually to find a satisfactory number of nearby places

View file

@ -0,0 +1,13 @@
package fr.free.nrw.commons.utils;
import fr.free.nrw.commons.location.LatLng;
public class LocationUtils {
public static LatLng mapBoxLatLngToCommonsLatLng(com.mapbox.mapboxsdk.geometry.LatLng mapBoxLatLng) {
return new LatLng(mapBoxLatLng.getLatitude(), mapBoxLatLng.getLongitude(), 0);
}
public static com.mapbox.mapboxsdk.geometry.LatLng comonsLatLngToMapBoxLatLng(LatLng commonsLatLng) {
return new com.mapbox.mapboxsdk.geometry.LatLng(commonsLatLng.getLatitude(), commonsLatLng.getLongitude());
}
}

View file

@ -19,7 +19,6 @@
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -70,6 +69,28 @@
android:id="@+id/bottom_sheet_details" android:id="@+id/bottom_sheet_details"
layout="@layout/bottom_sheet_details" /> layout="@layout/bottom_sheet_details" />
<Button
android:id="@+id/search_this_area_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:background="@color/white"
android:singleLine="true"
android:visibility="gone"
app:elevation="6dp"
android:layout_margin="8dp"
android:padding="8dp"
android:textColor="@color/status_bar_blue"
android:text="@string/search_this_area" />
<ProgressBar
android:id="@+id/search_this_area_button_progres_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
/>
<android.support.design.widget.FloatingActionButton <android.support.design.widget.FloatingActionButton
android:id="@+id/fab_plus" android:id="@+id/fab_plus"

View file

@ -425,6 +425,7 @@ Upload your first media by touching the camera or gallery icon above.</string>
<string name="no_go_back">No, Go Back</string> <string name="no_go_back">No, Go Back</string>
<string name="upload_flow_all_images_in_set">(For all images in set)</string> <string name="upload_flow_all_images_in_set">(For all images in set)</string>
<string name="search_this_area">Search this area</string>
<string name="nearby_card_permission_title">Permission Request</string> <string name="nearby_card_permission_title">Permission Request</string>
<string name="nearby_card_permission_explanation">Would you like us to use your current location to display the nearest place that needs pictures?</string> <string name="nearby_card_permission_explanation">Would you like us to use your current location to display the nearest place that needs pictures?</string>
<string name="unable_to_display_nearest_place">Unable to display nearest place that needs pictures without location permissions</string> <string name="unable_to_display_nearest_place">Unable to display nearest place that needs pictures without location permissions</string>