Made Nearby show all pins that could be presented on the screen, rather than a circle (#5553)

* Changed nearby from circle to rectangle

* Fixed bug

* Removed MAPBOX Token

* Fixed minor issues

* Fixed minor issues

* Changed query files

* Changed monuments query file

* Fixed Unit Tests

* Fixed failing tests

* Fixed errors due to merging
This commit is contained in:
Kanahia 2024-03-24 19:54:39 +05:30 committed by GitHub
parent f404ac9b47
commit 724e4db0fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 576 additions and 219 deletions

View file

@ -83,19 +83,27 @@ import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
public class ContributionsFragment
extends CommonsDaggerSupportFragment
implements
OnBackStackChangedListener,
LocationUpdateListener,
extends CommonsDaggerSupportFragment
implements
OnBackStackChangedListener,
LocationUpdateListener,
MediaDetailProvider,
SensorEventListener,
ICampaignsView, ContributionsContract.View, Callback{
@Inject @Named("default_preferences") JsonKvStore store;
@Inject NearbyController nearbyController;
@Inject OkHttpJsonApiClient okHttpJsonApiClient;
@Inject CampaignsPresenter presenter;
@Inject LocationServiceManager locationManager;
@Inject NotificationController notificationController;
ICampaignsView, ContributionsContract.View, Callback {
@Inject
@Named("default_preferences")
JsonKvStore store;
@Inject
NearbyController nearbyController;
@Inject
OkHttpJsonApiClient okHttpJsonApiClient;
@Inject
CampaignsPresenter presenter;
@Inject
LocationServiceManager locationManager;
@Inject
NotificationController notificationController;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
@ -129,29 +137,31 @@ public class ContributionsFragment
private SensorManager mSensorManager;
private Sensor mLight;
private float direction;
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
@Override
public void onActivityResult(Map<String, Boolean> result) {
boolean areAllGranted = true;
for (final boolean b : result.values()) {
areAllGranted = areAllGranted && b;
}
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
new ActivityResultCallback<Map<String, Boolean>>() {
@Override
public void onActivityResult(Map<String, Boolean> result) {
boolean areAllGranted = true;
for (final boolean b : result.values()) {
areAllGranted = areAllGranted && b;
}
if (areAllGranted) {
onLocationPermissionGranted();
} else {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
&& store.getBoolean("displayLocationPermissionForCardView", true)
&& !store.getBoolean("doNotAskForLocationPermission", false)
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION;
showNearbyCardPermissionRationale();
if (areAllGranted) {
onLocationPermissionGranted();
} else {
displayYouWontSeeNearbyMessage();
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
&& store.getBoolean("displayLocationPermissionForCardView", true)
&& !store.getBoolean("doNotAskForLocationPermission", false)
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION;
showNearbyCardPermissionRationale();
} else {
displayYouWontSeeNearbyMessage();
}
}
}
}
});
});
@NonNull
public static ContributionsFragment newInstance() {
@ -175,7 +185,8 @@ public class ContributionsFragment
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentContributionsBinding.inflate(inflater, container, false);
@ -192,6 +203,7 @@ public class ContributionsFragment
}
});
if (savedInstanceState != null) {
mediaDetailPagerFragment = (MediaDetailPagerFragment) getChildFragmentManager()
.findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
@ -206,9 +218,9 @@ public class ContributionsFragment
}else {
upDateUploadCount();
}
if(shouldShowMediaDetailsFragment){
if (shouldShowMediaDetailsFragment) {
showMediaDetailPagerFragment();
}else{
} else {
if (mediaDetailPagerFragment != null) {
removeFragment(mediaDetailPagerFragment);
}
@ -234,10 +246,13 @@ public class ContributionsFragment
}
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
public void onCreateOptionsMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) {
// Removing contributions menu items for ProfileActivity
if (getActivity() instanceof ProfileActivity) { return; }
if (getActivity() instanceof ProfileActivity) {
return;
}
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
@ -259,7 +274,7 @@ public class ContributionsFragment
throwable -> Timber.e(throwable, "Error occurred while loading notifications")));
}
public void scrollToTop( ){
public void scrollToTop() {
if (contributionsListFragment != null) {
contributionsListFragment.scrollToTop();
}
@ -329,13 +344,15 @@ public class ContributionsFragment
binding.cardViewNearby.setVisibility(View.GONE);
}
}
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG, mediaDetailPagerFragment);
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG,
mediaDetailPagerFragment);
}
private void showMediaDetailPagerFragment() {
// hide nearby card view on media detail is visible
setupViewForMediaDetails();
showFragment(mediaDetailPagerFragment, MEDIA_DETAIL_PAGER_FRAGMENT_TAG, contributionsListFragment);
showFragment(mediaDetailPagerFragment, MEDIA_DETAIL_PAGER_FRAGMENT_TAG,
contributionsListFragment);
}
private void setupViewForMediaDetails() {
@ -363,7 +380,8 @@ public class ContributionsFragment
showContributionsListFragment();
}
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG, mediaDetailPagerFragment);
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG,
mediaDetailPagerFragment);
}
/**
@ -386,7 +404,7 @@ public class ContributionsFragment
transaction.addToBackStack(tag);
transaction.commit();
getChildFragmentManager().executePendingTransactions();
}else if (!fragment.isAdded() && otherFragment != null ) {
} else if (!fragment.isAdded() && otherFragment != null) {
transaction.hide(otherFragment);
transaction.add(R.id.root_frame, fragment, tag);
transaction.addToBackStack(tag);
@ -411,21 +429,21 @@ public class ContributionsFragment
@SuppressWarnings("ConstantConditions")
private void setUploadCount() {
compositeDisposable.add(okHttpJsonApiClient
.getUploadCount(((MainActivity)getActivity()).sessionManager.getCurrentAccount().name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::displayUploadCount,
t -> Timber.e(t, "Fetching upload count failed")
));
.getUploadCount(((MainActivity) getActivity()).sessionManager.getCurrentAccount().name)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::displayUploadCount,
t -> Timber.e(t, "Fetching upload count failed")
));
}
private void displayUploadCount(Integer uploadCount) {
if (getActivity().isFinishing()
|| getResources() == null) {
|| getResources() == null) {
return;
}
((MainActivity)getActivity()).setNumOfUploads(uploadCount);
((MainActivity) getActivity()).setNumOfUploads(uploadCount);
}
@ -489,9 +507,9 @@ public class ContributionsFragment
if (PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
onLocationPermissionGranted();
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
&& store.getBoolean("displayLocationPermissionForCardView", true)
&& !store.getBoolean("doNotAskForLocationPermission", false)
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
&& store.getBoolean("displayLocationPermissionForCardView", true)
&& !store.getBoolean("doNotAskForLocationPermission", false)
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION;
showNearbyCardPermissionRationale();
}
@ -508,16 +526,17 @@ public class ContributionsFragment
private void showNearbyCardPermissionRationale() {
DialogUtil.showAlertDialog(getActivity(),
getString(R.string.nearby_card_permission_title),
getString(R.string.nearby_card_permission_explanation),
this::requestLocationPermission,
this::displayYouWontSeeNearbyMessage,
checkBoxView,
false);
getString(R.string.nearby_card_permission_title),
getString(R.string.nearby_card_permission_explanation),
this::requestLocationPermission,
this::displayYouWontSeeNearbyMessage,
checkBoxView,
false);
}
private void displayYouWontSeeNearbyMessage() {
ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.unable_to_display_nearest_place));
ViewUtil.showLongToast(getActivity(),
getResources().getString(R.string.unable_to_display_nearest_place));
store.putBoolean("doNotAskForLocationPermission", true);
}
@ -525,18 +544,21 @@ public class ContributionsFragment
private void updateClosestNearbyCardViewInfo() {
curLatLng = locationManager.getLastLocation();
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curLatLng, curLatLng, true, false, false)) // thanks to boolean, it will only return closest result
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateNearbyNotification,
throwable -> {
Timber.d(throwable);
updateNearbyNotification(null);
}));
.loadAttractionsFromLocation(curLatLng, curLatLng, true,
false)) // thanks to boolean, it will only return closest result
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateNearbyNotification,
throwable -> {
Timber.d(throwable);
updateNearbyNotification(null);
}));
}
private void updateNearbyNotification(@Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
if (nearbyPlacesInfo != null && nearbyPlacesInfo.placeList != null && nearbyPlacesInfo.placeList.size() > 0) {
private void updateNearbyNotification(
@Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
if (nearbyPlacesInfo != null && nearbyPlacesInfo.placeList != null
&& nearbyPlacesInfo.placeList.size() > 0) {
Place closestNearbyPlace = null;
// Find the first nearby place that has no image and exists
for (Place place : nearbyPlacesInfo.placeList) {
@ -546,9 +568,9 @@ public class ContributionsFragment
}
}
if(closestNearbyPlace == null) {
if (closestNearbyPlace == null) {
binding.cardViewNearby.setVisibility(View.GONE);
}else{
} else {
String distance = formatDistanceBetween(curLatLng, closestNearbyPlace.location);
closestNearbyPlace.setDistance(distance);
direction = (float) computeBearing(curLatLng, closestNearbyPlace.location);
@ -567,7 +589,7 @@ public class ContributionsFragment
@Override
public void onDestroy() {
try{
try {
compositeDisposable.clear();
getChildFragmentManager().removeOnBackStackChangedListener(this);
locationManager.unregisterLocationManager();
@ -587,7 +609,7 @@ public class ContributionsFragment
@Override
public void onLocationChangedSlightly(LatLng latLng) {
/* Update closest nearby notification card onLocationChangedSlightly
*/
*/
try {
updateClosestNearbyCardViewInfo();
} catch (Exception e) {
@ -601,7 +623,8 @@ public class ContributionsFragment
updateClosestNearbyCardViewInfo();
}
@Override public void onViewCreated(@NonNull View view,
@Override
public void onViewCreated(@NonNull View view,
@Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@ -626,11 +649,13 @@ public class ContributionsFragment
}
}
@Override public void showMessage(String message) {
@Override
public void showMessage(String message) {
Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show();
}
@Override public void showCampaigns(Campaign campaign) {
@Override
public void showCampaigns(Campaign campaign) {
if (campaign != null && !isUserProfile) {
if (binding!=null) {
binding.campaignsView.setCampaign(campaign);
@ -638,7 +663,8 @@ public class ContributionsFragment
}
}
@Override public void onDestroyView() {
@Override
public void onDestroyView() {
super.onDestroyView();
presenter.onDetachView();
}
@ -652,6 +678,7 @@ public class ContributionsFragment
/**
* Restarts the upload process for a contribution
*
* @param contribution
*/
public void restartUpload(Contribution contribution) {
@ -659,6 +686,7 @@ public class ContributionsFragment
contributionsPresenter.saveContribution(contribution);
Timber.d("Restarting for %s", contribution.toString());
}
/**
* Retry upload when it is failed
*
@ -667,7 +695,8 @@ public class ContributionsFragment
@Override
public void retryUpload(Contribution contribution) {
if (NetworkUtils.isInternetConnectionEstablished(getContext())) {
if (contribution.getState() == STATE_PAUSED || contribution.getState()==Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE) {
if (contribution.getState() == STATE_PAUSED
|| contribution.getState() == Contribution.STATE_QUEUED_LIMITED_CONNECTION_MODE) {
restartUpload(contribution);
} else if (contribution.getState() == STATE_FAILED) {
int retries = contribution.getRetries();
@ -675,9 +704,10 @@ public class ContributionsFragment
/* Limit the number of retries for a failed upload
to handle cases like invalid filename as such uploads
will never be successful */
if(retries < MAX_RETRIES) {
if (retries < MAX_RETRIES) {
contribution.setRetries(retries + 1);
Timber.d("Retried uploading %s %d times", contribution.getMedia().getFilename(), retries + 1);
Timber.d("Retried uploading %s %d times", contribution.getMedia().getFilename(),
retries + 1);
restartUpload(contribution);
} else {
// TODO: Show the exact reason for failure
@ -695,6 +725,7 @@ public class ContributionsFragment
/**
* Pauses the upload
*
* @param contribution
*/
@Override
@ -718,15 +749,15 @@ public class ContributionsFragment
/**
* Replace whatever is in the current contributionsFragmentContainer view with
* mediaDetailPagerFragment, and preserve previous state in back stack. Called when user selects a
* contribution.
* mediaDetailPagerFragment, and preserve previous state in back stack. Called when user selects
* a contribution.
*/
@Override
public void showDetail(int position, boolean isWikipediaButtonDisplayed) {
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
if(isUserProfile) {
((ProfileActivity)getActivity()).setScroll(false);
if (isUserProfile) {
((ProfileActivity) getActivity()).setScroll(false);
}
showMediaDetailPagerFragment();
}
@ -758,17 +789,19 @@ public class ContributionsFragment
binding.cardViewNearby.setVisibility(View.GONE);
}
removeFragment(mediaDetailPagerFragment);
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG, mediaDetailPagerFragment);
if(isUserProfile) {
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG,
mediaDetailPagerFragment);
if (isUserProfile) {
// Fragment is associated with ProfileActivity
// Enable ParentViewPager Scroll
((ProfileActivity)getActivity()).setScroll(true);
}else {
((ProfileActivity) getActivity()).setScroll(true);
} else {
fetchCampaigns();
}
if (getActivity() instanceof MainActivity) {
// Fragment is associated with MainActivity
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
((BaseActivity) getActivity()).getSupportActionBar()
.setDisplayHomeAsUpEnabled(false);
((MainActivity) getActivity()).showTabs();
}
return true;
@ -788,11 +821,11 @@ public class ContributionsFragment
void upDateUploadCount() {
WorkManager.getInstance(getContext())
.getWorkInfosForUniqueWorkLiveData(UploadWorker.class.getSimpleName()).observe(
getViewLifecycleOwner(), workInfos -> {
if (workInfos.size() > 0) {
setUploadCount();
}
});
getViewLifecycleOwner(), workInfos -> {
if (workInfos.size() > 0) {
setUploadCount();
}
});
}
@ -803,7 +836,7 @@ public class ContributionsFragment
*/
@Override
public void refreshNominatedMedia(int index) {
if(mediaDetailPagerFragment != null && !contributionsListFragment.isVisible()) {
if (mediaDetailPagerFragment != null && !contributionsListFragment.isVisible()) {
removeFragment(mediaDetailPagerFragment);
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
mediaDetailPagerFragment.showImage(index);
@ -811,20 +844,20 @@ public class ContributionsFragment
}
}
// click listener to toggle description that means uses can press the limited connection
// banner and description will hide. Tap again to show description.
private View.OnClickListener toggleDescriptionListener = new View.OnClickListener() {
// click listener to toggle description that means uses can press the limited connection
// banner and description will hide. Tap again to show description.
private View.OnClickListener toggleDescriptionListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
View view2 = binding.limitedConnectionDescriptionTextView;
if (view2.getVisibility() == View.GONE) {
view2.setVisibility(View.VISIBLE);
} else {
view2.setVisibility(View.GONE);
}
}
};
@Override
public void onClick(View view) {
View view2 = binding.limitedConnectionDescriptionTextView;
if (view2.getVisibility() == View.GONE) {
view2.setVisibility(View.VISIBLE);
} else {
view2.setVisibility(View.GONE);
}
}
};
/**
* When the device rotates, rotate the Nearby banner's compass arrow in tandem.

View file

@ -269,16 +269,15 @@ public class OkHttpJsonApiClient {
/**
* Make API Call to get Nearby Places
*
* @param cur Search lat long
* @param language Language
* @param radius Search Radius
* @param shouldQueryForMonuments : Should we query for monuments
* @param cur Search lat long
* @param language Language
* @param radius Search Radius
* @return
* @throws Exception
*/
@Nullable
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
final boolean shouldQueryForMonuments, final String customQuery)
final String customQuery)
throws Exception {
Timber.d("Fetching nearby items at radius %s", radius);
@ -286,10 +285,9 @@ public class OkHttpJsonApiClient {
final String wikidataQuery;
if (customQuery != null) {
wikidataQuery = customQuery;
} else if (!shouldQueryForMonuments) {
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
} else {
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
wikidataQuery = FileUtils.readFromResource(
"/queries/radius_query_for_upload_wizard.rq");
}
final String query = wikidataQuery
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
@ -307,6 +305,74 @@ public class OkHttpJsonApiClient {
.url(urlBuilder.build())
.build();
final Response response = okHttpClient.newCall(request).execute();
if (response.body() != null && response.isSuccessful()) {
final String json = response.body().string();
final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
final List<Place> places = new ArrayList<>();
for (final NearbyResultItem item : bindings) {
final Place placeFromNearbyItem = Place.from(item);
placeFromNearbyItem.setMonument(false);
places.add(placeFromNearbyItem);
}
return places;
}
throw new Exception(response.message());
}
/**
* Retrieves nearby places based on screen coordinates and optional query parameters.
*
* @param screenTopRight The top right corner of the screen (latitude, longitude).
* @param screenBottomLeft The bottom left corner of the screen (latitude, longitude).
* @param language The language for the query.
* @param shouldQueryForMonuments Flag indicating whether to include monuments in the query.
* @param customQuery Optional custom SPARQL query to use instead of default
* queries.
* @return A list of nearby places.
* @throws Exception If an error occurs during the retrieval process.
*/
@Nullable
public List<Place> getNearbyPlaces(
final fr.free.nrw.commons.location.LatLng screenTopRight,
final fr.free.nrw.commons.location.LatLng screenBottomLeft, final String language,
final boolean shouldQueryForMonuments, final String customQuery)
throws Exception {
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
final String wikidataQuery;
if (customQuery != null) {
wikidataQuery = customQuery;
} else if (!shouldQueryForMonuments) {
wikidataQuery = FileUtils.readFromResource("/queries/rectangle_query_for_nearby.rq");
} else {
wikidataQuery = FileUtils.readFromResource(
"/queries/rectangle_query_for_nearby_monuments.rq");
}
final double westCornerLat = screenTopRight.getLatitude();
final double westCornerLong = screenTopRight.getLongitude();
final double eastCornerLat = screenBottomLeft.getLatitude();
final double eastCornerLong = screenBottomLeft.getLongitude();
final String query = wikidataQuery
.replace("${LAT_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLat))
.replace("${LONG_WEST}", String.format(Locale.ROOT, "%.4f", westCornerLong))
.replace("${LAT_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLat))
.replace("${LONG_EAST}", String.format(Locale.ROOT, "%.4f", eastCornerLong))
.replace("${LANG}", language);
final HttpUrl.Builder urlBuilder = HttpUrl
.parse(sparqlQueryUrl)
.newBuilder()
.addQueryParameter("query", query)
.addQueryParameter("format", "json");
final Request request = new Request.Builder()
.url(urlBuilder.build())
.build();
final Response response = okHttpClient.newCall(request).execute();
if (response.body() != null && response.isSuccessful()) {
final String json = response.body().string();
@ -330,18 +396,16 @@ public class OkHttpJsonApiClient {
/**
* Make API Call to get Nearby Places Implementation does not expects a custom query
*
* @param cur Search lat long
* @param language Language
* @param radius Search Radius
* @param shouldQueryForMonuments : Should we query for monuments
* @param cur Search lat long
* @param language Language
* @param radius Search Radius
* @return
* @throws Exception
*/
@Nullable
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
final boolean shouldQueryForMonuments)
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius)
throws Exception {
return getNearbyPlaces(cur, language, radius, shouldQueryForMonuments, null);
return getNearbyPlaces(cur, language, radius, null);
}
/**

View file

@ -39,34 +39,34 @@ public class NearbyController extends MapController {
/**
* Prepares Place list to make their distance information update later.
*
* @param curLatLng current location for user
* @param searchLatLng the location user wants to search around
* @param curLatLng current location for user
* @param searchLatLng the location user wants to search around
* @param returnClosestResult if this search is done to find closest result or all results
* @param customQuery if this search is done via an advanced query
* @return NearbyPlacesInfo a variable holds Place list without distance information
* and boundary coordinates of current Place List
* @param customQuery if this search is done via an advanced query
* @return NearbyPlacesInfo a variable holds Place list without distance information and
* boundary coordinates of current Place List
*/
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng, final LatLng searchLatLng,
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng,
final LatLng searchLatLng,
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
@Nullable final String customQuery) throws Exception {
Timber.d("Loading attractions near %s", searchLatLng);
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
if (searchLatLng == null) {
Timber.d("Loading attractions nearby, but curLatLng is null");
return null;
}
List<Place> places = nearbyPlaces
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
shouldQueryForMonuments, customQuery);
customQuery);
if (null != places && places.size() > 0) {
LatLng[] boundaryCoordinates = {places.get(0).location, // south
places.get(0).location, // north
places.get(0).location, // west
places.get(0).location};// east, init with a random location
LatLng[] boundaryCoordinates = {
places.get(0).location, // south
places.get(0).location, // north
places.get(0).location, // west
places.get(0).location};// east, init with a random location
if (curLatLng != null) {
Timber.d("Sorting places by distance...");
@ -88,11 +88,11 @@ public class NearbyController extends MapController {
}
}
Collections.sort(places,
(lhs, rhs) -> {
double lhsDistance = distances.get(lhs);
double rhsDistance = distances.get(rhs);
return (int) (lhsDistance - rhsDistance);
}
(lhs, rhs) -> {
double lhsDistance = distances.get(lhs);
double rhsDistance = distances.get(rhs);
return (int) (lhsDistance - rhsDistance);
}
);
}
nearbyPlacesInfo.curLatLng = curLatLng;
@ -104,11 +104,11 @@ public class NearbyController extends MapController {
if (!returnClosestResult) {
// To remember latest search either around user or any point on map
latestSearchLocation = searchLatLng;
latestSearchRadius = nearbyPlaces.radius*1000; // to meter
latestSearchRadius = nearbyPlaces.radius * 1000; // to meter
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
if (checkingAroundCurrentLocation) {
currentLocationSearchRadius = nearbyPlaces.radius*1000; // to meter
currentLocationSearchRadius = nearbyPlaces.radius * 1000; // to meter
currentLocation = curLatLng;
}
}
@ -118,6 +118,98 @@ public class NearbyController extends MapController {
return nearbyPlacesInfo;
}
/**
* Prepares Place list to make their distance information update later.
*
* @param curLatLng The current latitude and longitude.
* @param screenTopRight The top right corner of the screen (latitude,
* longitude).
* @param screenBottomLeft The bottom left corner of the screen (latitude,
* longitude).
* @param searchLatLng The latitude and longitude of the search location.
* @param returnClosestResult Flag indicating whether to return the closest result.
* @param checkingAroundCurrentLocation Flag indicating whether to check around the current
* location.
* @param shouldQueryForMonuments Flag indicating whether to include monuments in the
* query.
* @param customQuery Optional custom SPARQL query to use instead of default
* queries.
* @return An object containing information about nearby places.
* @throws Exception If an error occurs during the retrieval process.
*/
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng,
final fr.free.nrw.commons.location.LatLng screenTopRight,
final fr.free.nrw.commons.location.LatLng screenBottomLeft, final LatLng searchLatLng,
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
final boolean shouldQueryForMonuments, @Nullable final String customQuery)
throws Exception {
Timber.d("Loading attractions near %s", searchLatLng);
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
if (searchLatLng == null) {
Timber.d("Loading attractions nearby, but curLatLng is null");
return null;
}
List<Place> places = nearbyPlaces.getFromWikidataQuery(screenTopRight, screenBottomLeft,
Locale.getDefault().getLanguage(), shouldQueryForMonuments, customQuery);
if (null != places && places.size() > 0) {
LatLng[] boundaryCoordinates = {
places.get(0).location, // south
places.get(0).location, // north
places.get(0).location, // west
places.get(0).location};// east, init with a random location
if (curLatLng != null) {
Timber.d("Sorting places by distance...");
final Map<Place, Double> distances = new HashMap<>();
for (Place place : places) {
distances.put(place, computeDistanceBetween(place.location, curLatLng));
// Find boundaries with basic find max approach
if (place.location.getLatitude() < boundaryCoordinates[0].getLatitude()) {
boundaryCoordinates[0] = place.location;
}
if (place.location.getLatitude() > boundaryCoordinates[1].getLatitude()) {
boundaryCoordinates[1] = place.location;
}
if (place.location.getLongitude() < boundaryCoordinates[2].getLongitude()) {
boundaryCoordinates[2] = place.location;
}
if (place.location.getLongitude() > boundaryCoordinates[3].getLongitude()) {
boundaryCoordinates[3] = place.location;
}
}
Collections.sort(places,
(lhs, rhs) -> {
double lhsDistance = distances.get(lhs);
double rhsDistance = distances.get(rhs);
return (int) (lhsDistance - rhsDistance);
}
);
}
nearbyPlacesInfo.curLatLng = curLatLng;
nearbyPlacesInfo.searchLatLng = searchLatLng;
nearbyPlacesInfo.placeList = places;
nearbyPlacesInfo.boundaryCoordinates = boundaryCoordinates;
// Returning closes result means we use the controller for nearby card. So no need to set search this area flags
if (!returnClosestResult) {
// To remember latest search either around user or any point on map
latestSearchLocation = searchLatLng;
latestSearchRadius = nearbyPlaces.radius * 1000; // to meter
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
if (checkingAroundCurrentLocation) {
currentLocationSearchRadius = nearbyPlaces.radius * 1000; // to meter
currentLocation = curLatLng;
}
}
}
return nearbyPlacesInfo;
}
/**
* Prepares Place list to make their distance information update later.
*
@ -129,10 +221,10 @@ public class NearbyController extends MapController {
*/
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng,
final LatLng searchLatLng,
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
final boolean shouldQueryForMonuments) throws Exception {
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation)
throws Exception {
return loadAttractionsFromLocation(curLatLng, searchLatLng, returnClosestResult,
checkingAroundCurrentLocation, shouldQueryForMonuments, null);
checkingAroundCurrentLocation, null);
}
/**
@ -171,12 +263,14 @@ public class NearbyController extends MapController {
/**
* Updates makerLabelList item isBookmarked value
* @param place place which is bookmarked
*
* @param place place which is bookmarked
* @param isBookmarked true is bookmarked, false if bookmark removed
*/
@MainThread
public static void updateMarkerLabelListBookmark(Place place, boolean isBookmarked) {
for (ListIterator<MarkerPlaceGroup> iter = markerLabelList.listIterator(); iter.hasNext();) {
for (ListIterator<MarkerPlaceGroup> iter = markerLabelList.listIterator();
iter.hasNext(); ) {
MarkerPlaceGroup markerPlaceGroup = iter.next();
if (markerPlaceGroup.getPlace().getWikiDataEntityId().equals(place.getWikiDataEntityId())) {
iter.set(new MarkerPlaceGroup(isBookmarked, place));

View file

@ -27,6 +27,7 @@ public class NearbyPlaces {
/**
* Reads Wikidata query to check nearby wikidata items which needs picture, with a circular
* search. As a point is center of a circle with a radius will be set later.
*
* @param okHttpJsonApiClient
*/
@Inject
@ -36,15 +37,15 @@ public class NearbyPlaces {
/**
* Expands the radius as needed for the Wikidata query
* @param curLatLng coordinates of search location
* @param lang user's language
*
* @param curLatLng coordinates of search location
* @param lang user's language
* @param returnClosestResult true if only the nearest point is desired
* @param customQuery
* @return list of places obtained
*/
List<Place> radiusExpander(final LatLng curLatLng, final String lang,
final boolean returnClosestResult
, final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
final boolean returnClosestResult, @Nullable final String customQuery) throws Exception {
final int minResults;
final double maxRadius;
@ -63,15 +64,15 @@ public class NearbyPlaces {
radius = INITIAL_RADIUS;
}
// Increase the radius gradually to find a satisfactory number of nearby places
while (radius <= maxRadius) {
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments, customQuery);
Timber.d("%d results at radius: %f", places.size(), radius);
if (places.size() >= minResults) {
break;
}
radius *= RADIUS_MULTIPLIER;
// Increase the radius gradually to find a satisfactory number of nearby places
while (radius <= maxRadius) {
places = getFromWikidataQuery(curLatLng, lang, radius, customQuery);
Timber.d("%d results at radius: %f", places.size(), radius);
if (places.size() >= minResults) {
break;
}
radius *= RADIUS_MULTIPLIER;
}
// make sure we will be able to send at least one request next time
if (radius > maxRadius) {
radius = maxRadius;
@ -81,18 +82,41 @@ public class NearbyPlaces {
/**
* Runs the Wikidata query to populate the Places around search location
* @param cur coordinates of search location
* @param lang user's language
* @param radius radius for search, as determined by radiusExpander()
* @param shouldQueryForMonuments should the query include properites for monuments
*
* @param cur coordinates of search location
* @param lang user's language
* @param radius radius for search, as determined by radiusExpander()
* @param customQuery
* @return list of places obtained
* @throws IOException if query fails
*/
public List<Place> getFromWikidataQuery(final LatLng cur, final String lang,
final double radius, final boolean shouldQueryForMonuments,
final double radius,
@Nullable final String customQuery) throws Exception {
return okHttpJsonApiClient
.getNearbyPlaces(cur, lang, radius, shouldQueryForMonuments, customQuery);
.getNearbyPlaces(cur, lang, radius, customQuery);
}
/**
* Retrieves a list of places from a Wikidata query based on screen coordinates and optional
* parameters.
*
* @param screenTopRight The top right corner of the screen (latitude, longitude).
* @param screenBottomLeft The bottom left corner of the screen (latitude, longitude).
* @param lang The language for the query.
* @param shouldQueryForMonuments Flag indicating whether to include monuments in the query.
* @param customQuery Optional custom SPARQL query to use instead of default
* queries.
* @return A list of places obtained from the Wikidata query.
* @throws Exception If an error occurs during the retrieval process.
*/
public List<Place> getFromWikidataQuery(
final fr.free.nrw.commons.location.LatLng screenTopRight,
final fr.free.nrw.commons.location.LatLng screenBottomLeft, final String lang,
final boolean shouldQueryForMonuments,
@Nullable final String customQuery) throws Exception {
return okHttpJsonApiClient
.getNearbyPlaces(screenTopRight, screenBottomLeft, lang, shouldQueryForMonuments,
customQuery);
}
}

View file

@ -116,6 +116,7 @@ import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.events.MapEventsReceiver;
import org.osmdroid.events.MapListener;
import org.osmdroid.events.ScrollEvent;
@ -489,7 +490,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
final AdvanceQueryFragment fragment = new AdvanceQueryFragment();
final Bundle bundle = new Bundle();
try {
bundle.putString("query", FileUtils.readFromResource("/queries/nearby_query.rq"));
bundle.putString("query", FileUtils.readFromResource("/queries/radius_query_for_upload_wizard.rq"));
} catch (IOException e) {
Timber.e(e);
}
@ -1119,11 +1120,52 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
@Override
public void populatePlaces(final fr.free.nrw.commons.location.LatLng curlatLng) {
if (curlatLng.equals(getLastMapFocus())) { // Means we are checking around current location
populatePlacesForCurrentLocation(getLastMapFocus(), curlatLng, null);
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);
// When the nearby fragment is opened immediately upon app launch, the {screenTopRightLatLng}
// and {screenBottomLeftLatLng} variables return {LatLng(0.0,0.0)} as output.
// To address this issue, A small delta value {delta = 0.02} is used to adjust the latitude
// and longitude values for {ZOOM_LEVEL = 14f}.
// This adjustment helps in calculating the east and west corner LatLng accurately.
// Note: This only happens when the nearby fragment is opened immediately upon app launch,
// otherwise {screenTopRightLatLng} and {screenBottomLeftLatLng} are used to determine
// the east and west corner LatLng.
if (screenTopRightLatLng.getLatitude() == 0.0 && screenTopRightLatLng.getLongitude() == 0.0
&& screenBottomLeftLatLng.getLatitude() == 0.0
&& screenBottomLeftLatLng.getLongitude() == 0.0) {
final double delta = 0.02;
final double westCornerLat = curlatLng.getLatitude() - delta;
final double westCornerLong = curlatLng.getLongitude() - delta;
final double eastCornerLat = curlatLng.getLatitude() + delta;
final double eastCornerLong = curlatLng.getLongitude() + delta;
screenTopRightLatLng = new fr.free.nrw.commons.location.LatLng(westCornerLat,
westCornerLong, 0);
screenBottomLeftLatLng = new fr.free.nrw.commons.location.LatLng(eastCornerLat,
eastCornerLong, 0);
if (curlatLng.equals(
getLastMapFocus())) { // Means we are checking around current location
populatePlacesForCurrentLocation(getLastMapFocus(), screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, null);
} else {
populatePlacesForAnotherLocation(getLastMapFocus(), screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, null);
}
} else {
populatePlacesForAnotherLocation(getLastMapFocus(), curlatLng, null);
if (curlatLng.equals(
getLastMapFocus())) { // Means we are checking around current location
populatePlacesForCurrentLocation(getLastMapFocus(), screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, null);
} else {
populatePlacesForAnotherLocation(getLastMapFocus(), screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, null);
}
}
if (recenterToUserLocation) {
recenterToUserLocation = false;
}
@ -1136,12 +1178,20 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
populatePlaces(curlatLng);
return;
}
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);
if (curlatLng.equals(lastFocusLocation) || lastFocusLocation == null
|| recenterToUserLocation) { // Means we are checking around current location
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng, customQuery);
populatePlacesForCurrentLocation(lastKnownLocation, screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, customQuery);
} else {
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng, customQuery);
populatePlacesForAnotherLocation(lastKnownLocation, screenTopRightLatLng,
screenBottomLeftLatLng, curlatLng, customQuery);
}
if (recenterToUserLocation) {
recenterToUserLocation = false;
@ -1150,11 +1200,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
private void populatePlacesForCurrentLocation(
final fr.free.nrw.commons.location.LatLng curlatLng,
final fr.free.nrw.commons.location.LatLng screenTopRight,
final fr.free.nrw.commons.location.LatLng screenBottomLeft,
final fr.free.nrw.commons.location.LatLng searchLatLng,
@Nullable final String customQuery) {
final Observable<NearbyController.NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng,
.loadAttractionsFromLocation(curlatLng, screenTopRight, screenBottomLeft,
searchLatLng,
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
compositeDisposable.add(nearbyPlacesInfoObservable
@ -1182,11 +1235,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
private void populatePlacesForAnotherLocation(
final fr.free.nrw.commons.location.LatLng curlatLng,
final fr.free.nrw.commons.location.LatLng screenTopRight,
final fr.free.nrw.commons.location.LatLng screenBottomLeft,
final fr.free.nrw.commons.location.LatLng searchLatLng,
@Nullable final String customQuery) {
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng,
.loadAttractionsFromLocation(curlatLng, screenTopRight, screenBottomLeft,
searchLatLng,
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
compositeDisposable.add(nearbyPlacesInfoObservable

View file

@ -345,6 +345,7 @@ public class UploadRepository {
/**
* Returns nearest place matching the passed latitude and longitude
*
* @param decLatitude
* @param decLongitude
* @return
@ -354,11 +355,11 @@ public class UploadRepository {
try {
final List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
decLatitude, decLongitude, 0.0f),
Locale.getDefault().getLanguage(),
NEARBY_RADIUS_IN_KILO_METERS, false, null);
Locale.getDefault().getLanguage(),
NEARBY_RADIUS_IN_KILO_METERS, null);
return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery
.get(0) : null;
}catch (final Exception e) {
} catch (final Exception e) {
Timber.e("Error fetching nearby places: %s", e.getMessage());
return null;
}

View file

@ -49,8 +49,10 @@ class FileProcessor @Inject constructor(
/**
* Processes filePath coordinates, either from EXIF data or user location
*/
fun processFileCoordinates(similarImageInterface: SimilarImageInterface,
filePath: String?, inAppPictureLocation: LatLng?)
fun processFileCoordinates(
similarImageInterface: SimilarImageInterface,
filePath: String?, inAppPictureLocation: LatLng?
)
: ImageCoordinates {
val exifInterface: ExifInterface? = try {
ExifInterface(filePath!!)
@ -207,8 +209,7 @@ class FileProcessor @Inject constructor(
okHttpJsonApiClient.getNearbyPlaces(
imageCoordinates.latLng,
Locale.getDefault().language,
it,
false
it
)
}
}

View file

@ -85,7 +85,7 @@ public class FileUtils {
/**
* Read and return the content of a resource filePath as string.
*
* @param fileName asset filePath's path (e.g. "/queries/nearby_query.rq")
* @param fileName asset filePath's path (e.g. "/queries/radius_query_for_upload_wizard.rq")
* @return the content of the filePath
*/
public static String readFromResource(String fileName) throws IOException {

View file

@ -0,0 +1,56 @@
SELECT
?item
(SAMPLE(?location) as ?location)
(SAMPLE(?label) AS ?label)
(SAMPLE(?description) AS ?description)
(SAMPLE(?class) AS ?class)
(SAMPLE(?classLabel) AS ?classLabel)
(SAMPLE(?pic) AS ?pic)
(SAMPLE(?destroyed) AS ?destroyed)
(SAMPLE(?endTime) AS ?endTime)
(SAMPLE(?wikipediaArticle) AS ?wikipediaArticle)
(SAMPLE(?commonsArticle) AS ?commonsArticle)
(SAMPLE(?commonsCategory) AS ?commonsCategory)
WHERE {
# Around given location
SERVICE wikibase:box {
?item wdt:P625 ?location.
bd:serviceParam wikibase:cornerWest "Point(${LONG_WEST} ${LAT_WEST})"^^geo:wktLiteral.
bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral.
}
OPTIONAL {
?item p:P31/ps:P31 ?class.
}
# Get picture
OPTIONAL {?item wdt:P18 ?pic}
# Get existence
OPTIONAL {?item wdt:P576 ?destroyed}
OPTIONAL {?item wdt:P582 ?endTime}
# Get Commons category
OPTIONAL {?item wdt:P373 ?commonsCategory}
# Get Wikipedia article
OPTIONAL {
?wikipediaArticle schema:about ?item.
?wikipediaArticle schema:isPartOf <https://${LANG}.wikipedia.org/>.
}
# Get Commons article
OPTIONAL {
?commonsArticle schema:about ?item.
?commonsArticle schema:isPartOf <https://commons.wikimedia.org/>.
}
# Labels and descriptions
SERVICE wikibase:label {
bd:serviceParam wikibase:language "${LANG},en,fr,de,es,ja,ru,it,zh,pt,ar,fa,pl,nl,id,uk,he,sv,cs,ko,vi,ca,no,fi,hu,tr,th,hi,bn,ceb,ro,sw,kk,da,eo,sr,lt,sk,bg,sl,eu,et,hr,ms,el,arz,ur,ta,te,nn,gl,az,af,bs,be,ml,ka,is,sq,uz,la,br,mk,lv,azb,mr,sh,tl,cy,ckb,ast,be-tarask,zh-yue,hy,pa,as,my,kn,ne,si,tt,ha,war,zh-min-nan,vo,min,lmo,ht,lb,gu,tg,sco,ku,new,bpy,nds,io,pms,su,oc,jv,nap,ba,scn,wa,bar,an,ksh,szl,fy,frr,als,ia,ga,yi,mg,gd,vec,ce,sa,mai,xmf,sd,wuu,mrj,mhr,km,roa-tara,am,roa-rup,map-bms,bh,mnw,shn,bcl,co,cv,dv,nds-nl,fo,hif,fur,gan,glk,hak,ilo,pam,csb,avk,lij,li,gv,mi,mt,nah,nrm,se,nov,qu,os,pi,pag,ps,pdc,rm,bat-smg,sc,to,tk,hsb,fiu-vro,vls,yo,diq,zh-classical,frp,lad,kw,mn,haw,ang,ln,ie,wo,tpi,ty,crh,nv,jbo,ay,pcd,zea,eml,ky,ig,or,cbk-zam,kg,arc,rmy,ab,gn,so,kab,ug,stq,udm,ext,mzn,pap,cu,sah,tet,sn,lo,pnb,iu,na,got,bo,dsb,chr,cdo,om,sm,ee,ti,av,bm,zu,pnt,cr,pih,ss,ve,bi,rw,ch,xh,kl,ik,bug,dz,ts,tn,kv,tum,xal,st,tw,bxr,ak,ny,fj,lbe,za,ks,ff,lg,sg,rn,chy,mwl,lez,bjn,gom,tyv,vep,nso,kbd,ltg,rue,pfl,gag,koi,krc,ace,olo,kaa,mdf,myv,srn,ady,jam,tcy,dty,atj,kbp,din,lfn,gor,inh,sat,hyw,nqo,ban,szy,awa,ary,lld,smn,skr,mad,dag,shi,nia,ki,gcr".
?item rdfs:label ?label.
?item schema:description ?description.
?class rdfs:label ?classLabel.
}
}
GROUP BY ?item

View file

@ -14,10 +14,10 @@ SELECT
(SAMPLE(?monument) AS ?monument)
WHERE {
# Around given location
SERVICE wikibase:around {
?item wdt:P625 ?location.
bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. # Longitude latitude
bd:serviceParam wikibase:radius "${RAD}". # Radius in kilometers.
SERVICE wikibase:box {
?item wdt:P625 ?location.
bd:serviceParam wikibase:cornerWest "Point(${LONG_WEST} ${LAT_WEST})"^^geo:wktLiteral.
bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral.
}
OPTIONAL {

View file

@ -62,7 +62,8 @@ class OkHttpJsonApiClientTests {
fun testGetNearbyPlacesCustomQuery() {
Mockito.`when`(response.message).thenReturn("test")
try {
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true, "test")
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, "test")
okHttpJsonApiClient.getNearbyPlaces(latLng, latLng, "test", true, "test")
} catch (e: Exception) {
assert(e.message.equals("test"))
}
@ -75,7 +76,8 @@ class OkHttpJsonApiClientTests {
fun testGetNearbyPlaces() {
Mockito.`when`(response.message).thenReturn("test")
try {
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true)
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, null)
okHttpJsonApiClient.getNearbyPlaces(latLng, latLng, "test", true, null)
} catch (e: Exception) {
assert(e.message.equals("test"))
}

View file

@ -35,6 +35,12 @@ class NearbyControllerTest {
@Mock
private lateinit var nearbyPlaces: NearbyPlaces
@Mock
private lateinit var screenTopRight: LatLng
@Mock
private lateinit var screenBottomLeft: LatLng
@Mock
private lateinit var searchLatLong: LatLng
@ -56,41 +62,48 @@ class NearbyControllerTest {
@Test
fun testLoadAttractionsForLocationTest() {
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), any()))
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any()))
.thenReturn(Collections.emptyList())
nearbyController.loadAttractionsFromLocation(
searchLatLong,
currentLatLng,
false,
searchLatLong,
false,
true,
customQuery
)
nearbyController.loadAttractionsFromLocation(
currentLatLng,
screenTopRight,
screenBottomLeft,
searchLatLong,
false,
true,
false,
customQuery
)
Mockito.verify(nearbyPlaces).radiusExpander(
eq(currentLatLng),
eq(searchLatLong),
any(String::class.java),
eq(false),
eq(true),
eq(customQuery)
)
}
@Test
fun testLoadAttractionsForLocationTestNoQuery() {
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), anyOrNull()))
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), anyOrNull()))
.thenReturn(Collections.emptyList())
nearbyController.loadAttractionsFromLocation(
searchLatLong,
currentLatLng,
searchLatLong,
false,
false,
true
true,
null
)
Mockito.verify(nearbyPlaces).radiusExpander(
eq(currentLatLng),
eq(searchLatLong),
any(String::class.java),
eq(false),
eq(true),
eq(null)
)
}
@ -102,8 +115,7 @@ class NearbyControllerTest {
currentLatLng,
null,
false,
false,
false,
true,
customQuery
), null
)
@ -136,7 +148,7 @@ class NearbyControllerTest {
`when`(
nearbyPlaces.radiusExpander(
searchLatLong, Locale.getDefault().language, false,
false, customQuery
customQuery
)
).thenReturn(mutableListOf(place1, place2))
val result = nearbyController.loadAttractionsFromLocation(
@ -144,6 +156,15 @@ class NearbyControllerTest {
searchLatLong,
false,
true,
customQuery
)
nearbyController.loadAttractionsFromLocation(
currentLatLng,
screenTopRight,
screenBottomLeft,
searchLatLong,
false,
true,
false,
customQuery
)
@ -178,7 +199,7 @@ class NearbyControllerTest {
`when`(
nearbyPlaces.radiusExpander(
searchLatLong, Locale.getDefault().language, false,
false, customQuery
customQuery
)
).thenReturn(mutableListOf(place1, place2))
val result = nearbyController.loadAttractionsFromLocation(
@ -186,7 +207,6 @@ class NearbyControllerTest {
searchLatLong,
false,
true,
false,
customQuery
)
assertEquals(result.curLatLng, currentLatLng)
@ -220,7 +240,7 @@ class NearbyControllerTest {
`when`(
nearbyPlaces.radiusExpander(
searchLatLong, Locale.getDefault().language, false,
false, customQuery
customQuery
)
).thenReturn(mutableListOf(place1, place2))
val result = nearbyController.loadAttractionsFromLocation(
@ -228,7 +248,6 @@ class NearbyControllerTest {
searchLatLong,
false,
true,
false,
customQuery
)
assertEquals(result.curLatLng, currentLatLng)

View file

@ -28,12 +28,11 @@ class NearbyPlacesTest {
@Test
fun testRadiusExpander() {
nearbyPlaces.radiusExpander(currentLatLong, "test", true, true, "test")
nearbyPlaces.radiusExpander(currentLatLong, "test", true, "test")
verify(okHttpJsonApiClient, times(5)).getNearbyPlaces(
eq(currentLatLong),
eq("test"),
any(),
eq(true),
eq("test")
)
}

View file

@ -217,8 +217,10 @@ class UploadRepositoryUnitTest {
@Test
fun testSetSelectedExistingDepictions() {
assertEquals(repository.setSelectedExistingDepictions(listOf("")),
uploadModel.setSelectedExistingDepictions(listOf("")))
assertEquals(
repository.setSelectedExistingDepictions(listOf("")),
uploadModel.setSelectedExistingDepictions(listOf(""))
)
}
@Test
@ -264,7 +266,7 @@ class UploadRepositoryUnitTest {
nearbyPlaces.getFromWikidataQuery(
LatLng(0.0, 0.0, 0.0f),
java.util.Locale.getDefault().language, 0.1,
false, null
null
)
).thenReturn(listOf(place))
assertEquals(
@ -287,7 +289,7 @@ class UploadRepositoryUnitTest {
nearbyPlaces.getFromWikidataQuery(
LatLng(0.0, 0.0, 0.0f),
java.util.Locale.getDefault().language, 0.1,
false, null
null
)
).thenThrow(Exception())
assertEquals(
@ -348,19 +350,25 @@ class UploadRepositoryUnitTest {
@Test
fun testGetSelectedExistingCategories() {
assertEquals(repository.selectedExistingCategories,
categoriesModel.getSelectedExistingCategories())
assertEquals(
repository.selectedExistingCategories,
categoriesModel.getSelectedExistingCategories()
)
}
@Test
fun testSetSelectedExistingCategories() {
assertEquals(repository.setSelectedExistingCategories(listOf("Test")),
categoriesModel.setSelectedExistingCategories(mutableListOf("Test")))
assertEquals(
repository.setSelectedExistingCategories(listOf("Test")),
categoriesModel.setSelectedExistingCategories(mutableListOf("Test"))
)
}
@Test
fun testGetCategories() {
assertEquals(repository.getCategories(listOf("Test")),
categoriesModel.getCategoriesByName(mutableListOf("Test")))
assertEquals(
repository.getCategories(listOf("Test")),
categoriesModel.getCategoriesByName(mutableListOf("Test"))
)
}
}