mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
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:
parent
f404ac9b47
commit
724e4db0fd
15 changed files with 576 additions and 219 deletions
|
|
@ -83,19 +83,27 @@ import io.reactivex.schedulers.Schedulers;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class ContributionsFragment
|
public class ContributionsFragment
|
||||||
extends CommonsDaggerSupportFragment
|
extends CommonsDaggerSupportFragment
|
||||||
implements
|
implements
|
||||||
OnBackStackChangedListener,
|
OnBackStackChangedListener,
|
||||||
LocationUpdateListener,
|
LocationUpdateListener,
|
||||||
MediaDetailProvider,
|
MediaDetailProvider,
|
||||||
SensorEventListener,
|
SensorEventListener,
|
||||||
ICampaignsView, ContributionsContract.View, Callback{
|
ICampaignsView, ContributionsContract.View, Callback {
|
||||||
@Inject @Named("default_preferences") JsonKvStore store;
|
|
||||||
@Inject NearbyController nearbyController;
|
@Inject
|
||||||
@Inject OkHttpJsonApiClient okHttpJsonApiClient;
|
@Named("default_preferences")
|
||||||
@Inject CampaignsPresenter presenter;
|
JsonKvStore store;
|
||||||
@Inject LocationServiceManager locationManager;
|
@Inject
|
||||||
@Inject NotificationController notificationController;
|
NearbyController nearbyController;
|
||||||
|
@Inject
|
||||||
|
OkHttpJsonApiClient okHttpJsonApiClient;
|
||||||
|
@Inject
|
||||||
|
CampaignsPresenter presenter;
|
||||||
|
@Inject
|
||||||
|
LocationServiceManager locationManager;
|
||||||
|
@Inject
|
||||||
|
NotificationController notificationController;
|
||||||
|
|
||||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
|
|
@ -129,29 +137,31 @@ public class ContributionsFragment
|
||||||
private SensorManager mSensorManager;
|
private SensorManager mSensorManager;
|
||||||
private Sensor mLight;
|
private Sensor mLight;
|
||||||
private float direction;
|
private float direction;
|
||||||
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() {
|
private ActivityResultLauncher<String[]> nearbyLocationPermissionLauncher = registerForActivityResult(
|
||||||
@Override
|
new ActivityResultContracts.RequestMultiplePermissions(),
|
||||||
public void onActivityResult(Map<String, Boolean> result) {
|
new ActivityResultCallback<Map<String, Boolean>>() {
|
||||||
boolean areAllGranted = true;
|
@Override
|
||||||
for (final boolean b : result.values()) {
|
public void onActivityResult(Map<String, Boolean> result) {
|
||||||
areAllGranted = areAllGranted && b;
|
boolean areAllGranted = true;
|
||||||
}
|
for (final boolean b : result.values()) {
|
||||||
|
areAllGranted = areAllGranted && b;
|
||||||
|
}
|
||||||
|
|
||||||
if (areAllGranted) {
|
if (areAllGranted) {
|
||||||
onLocationPermissionGranted();
|
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();
|
|
||||||
} else {
|
} 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
|
@NonNull
|
||||||
public static ContributionsFragment newInstance() {
|
public static ContributionsFragment newInstance() {
|
||||||
|
|
@ -175,7 +185,8 @@ public class ContributionsFragment
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@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);
|
binding = FragmentContributionsBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
|
|
@ -192,6 +203,7 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mediaDetailPagerFragment = (MediaDetailPagerFragment) getChildFragmentManager()
|
mediaDetailPagerFragment = (MediaDetailPagerFragment) getChildFragmentManager()
|
||||||
.findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
.findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG);
|
||||||
|
|
@ -206,9 +218,9 @@ public class ContributionsFragment
|
||||||
}else {
|
}else {
|
||||||
upDateUploadCount();
|
upDateUploadCount();
|
||||||
}
|
}
|
||||||
if(shouldShowMediaDetailsFragment){
|
if (shouldShowMediaDetailsFragment) {
|
||||||
showMediaDetailPagerFragment();
|
showMediaDetailPagerFragment();
|
||||||
}else{
|
} else {
|
||||||
if (mediaDetailPagerFragment != null) {
|
if (mediaDetailPagerFragment != null) {
|
||||||
removeFragment(mediaDetailPagerFragment);
|
removeFragment(mediaDetailPagerFragment);
|
||||||
}
|
}
|
||||||
|
|
@ -234,10 +246,13 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// 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);
|
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")));
|
throwable -> Timber.e(throwable, "Error occurred while loading notifications")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scrollToTop( ){
|
public void scrollToTop() {
|
||||||
if (contributionsListFragment != null) {
|
if (contributionsListFragment != null) {
|
||||||
contributionsListFragment.scrollToTop();
|
contributionsListFragment.scrollToTop();
|
||||||
}
|
}
|
||||||
|
|
@ -329,13 +344,15 @@ public class ContributionsFragment
|
||||||
binding.cardViewNearby.setVisibility(View.GONE);
|
binding.cardViewNearby.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG, mediaDetailPagerFragment);
|
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG,
|
||||||
|
mediaDetailPagerFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMediaDetailPagerFragment() {
|
private void showMediaDetailPagerFragment() {
|
||||||
// hide nearby card view on media detail is visible
|
// hide nearby card view on media detail is visible
|
||||||
setupViewForMediaDetails();
|
setupViewForMediaDetails();
|
||||||
showFragment(mediaDetailPagerFragment, MEDIA_DETAIL_PAGER_FRAGMENT_TAG, contributionsListFragment);
|
showFragment(mediaDetailPagerFragment, MEDIA_DETAIL_PAGER_FRAGMENT_TAG,
|
||||||
|
contributionsListFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupViewForMediaDetails() {
|
private void setupViewForMediaDetails() {
|
||||||
|
|
@ -363,7 +380,8 @@ public class ContributionsFragment
|
||||||
showContributionsListFragment();
|
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.addToBackStack(tag);
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
getChildFragmentManager().executePendingTransactions();
|
getChildFragmentManager().executePendingTransactions();
|
||||||
}else if (!fragment.isAdded() && otherFragment != null ) {
|
} else if (!fragment.isAdded() && otherFragment != null) {
|
||||||
transaction.hide(otherFragment);
|
transaction.hide(otherFragment);
|
||||||
transaction.add(R.id.root_frame, fragment, tag);
|
transaction.add(R.id.root_frame, fragment, tag);
|
||||||
transaction.addToBackStack(tag);
|
transaction.addToBackStack(tag);
|
||||||
|
|
@ -411,21 +429,21 @@ public class ContributionsFragment
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
private void setUploadCount() {
|
private void setUploadCount() {
|
||||||
compositeDisposable.add(okHttpJsonApiClient
|
compositeDisposable.add(okHttpJsonApiClient
|
||||||
.getUploadCount(((MainActivity)getActivity()).sessionManager.getCurrentAccount().name)
|
.getUploadCount(((MainActivity) getActivity()).sessionManager.getCurrentAccount().name)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(this::displayUploadCount,
|
.subscribe(this::displayUploadCount,
|
||||||
t -> Timber.e(t, "Fetching upload count failed")
|
t -> Timber.e(t, "Fetching upload count failed")
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayUploadCount(Integer uploadCount) {
|
private void displayUploadCount(Integer uploadCount) {
|
||||||
if (getActivity().isFinishing()
|
if (getActivity().isFinishing()
|
||||||
|| getResources() == null) {
|
|| getResources() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
((MainActivity)getActivity()).setNumOfUploads(uploadCount);
|
((MainActivity) getActivity()).setNumOfUploads(uploadCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -460,7 +478,7 @@ public class ContributionsFragment
|
||||||
if (mediaDetailPagerFragment == null && !isUserProfile) {
|
if (mediaDetailPagerFragment == null && !isUserProfile) {
|
||||||
if (store.getBoolean("displayNearbyCardView", true)) {
|
if (store.getBoolean("displayNearbyCardView", true)) {
|
||||||
checkPermissionsAndShowNearbyCardView();
|
checkPermissionsAndShowNearbyCardView();
|
||||||
|
|
||||||
// Calling nearby card to keep showing it even when user clicks on it and comes back
|
// Calling nearby card to keep showing it even when user clicks on it and comes back
|
||||||
try {
|
try {
|
||||||
updateClosestNearbyCardViewInfo();
|
updateClosestNearbyCardViewInfo();
|
||||||
|
|
@ -489,9 +507,9 @@ public class ContributionsFragment
|
||||||
if (PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
|
if (PermissionUtils.hasPermission(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION})) {
|
||||||
onLocationPermissionGranted();
|
onLocationPermissionGranted();
|
||||||
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
|
} else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
&& store.getBoolean("displayLocationPermissionForCardView", true)
|
&& store.getBoolean("displayLocationPermissionForCardView", true)
|
||||||
&& !store.getBoolean("doNotAskForLocationPermission", false)
|
&& !store.getBoolean("doNotAskForLocationPermission", false)
|
||||||
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
|
&& (((MainActivity) getActivity()).activeFragment == ActiveFragment.CONTRIBUTIONS)) {
|
||||||
binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION;
|
binding.cardViewNearby.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION;
|
||||||
showNearbyCardPermissionRationale();
|
showNearbyCardPermissionRationale();
|
||||||
}
|
}
|
||||||
|
|
@ -508,16 +526,17 @@ public class ContributionsFragment
|
||||||
|
|
||||||
private void showNearbyCardPermissionRationale() {
|
private void showNearbyCardPermissionRationale() {
|
||||||
DialogUtil.showAlertDialog(getActivity(),
|
DialogUtil.showAlertDialog(getActivity(),
|
||||||
getString(R.string.nearby_card_permission_title),
|
getString(R.string.nearby_card_permission_title),
|
||||||
getString(R.string.nearby_card_permission_explanation),
|
getString(R.string.nearby_card_permission_explanation),
|
||||||
this::requestLocationPermission,
|
this::requestLocationPermission,
|
||||||
this::displayYouWontSeeNearbyMessage,
|
this::displayYouWontSeeNearbyMessage,
|
||||||
checkBoxView,
|
checkBoxView,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayYouWontSeeNearbyMessage() {
|
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);
|
store.putBoolean("doNotAskForLocationPermission", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -525,18 +544,21 @@ public class ContributionsFragment
|
||||||
private void updateClosestNearbyCardViewInfo() {
|
private void updateClosestNearbyCardViewInfo() {
|
||||||
curLatLng = locationManager.getLastLocation();
|
curLatLng = locationManager.getLastLocation();
|
||||||
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
|
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curLatLng, curLatLng, true, false, false)) // thanks to boolean, it will only return closest result
|
.loadAttractionsFromLocation(curLatLng, curLatLng, true,
|
||||||
.subscribeOn(Schedulers.io())
|
false)) // thanks to boolean, it will only return closest result
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe(this::updateNearbyNotification,
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
throwable -> {
|
.subscribe(this::updateNearbyNotification,
|
||||||
Timber.d(throwable);
|
throwable -> {
|
||||||
updateNearbyNotification(null);
|
Timber.d(throwable);
|
||||||
}));
|
updateNearbyNotification(null);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNearbyNotification(@Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
|
private void updateNearbyNotification(
|
||||||
if (nearbyPlacesInfo != null && nearbyPlacesInfo.placeList != null && nearbyPlacesInfo.placeList.size() > 0) {
|
@Nullable NearbyController.NearbyPlacesInfo nearbyPlacesInfo) {
|
||||||
|
if (nearbyPlacesInfo != null && nearbyPlacesInfo.placeList != null
|
||||||
|
&& nearbyPlacesInfo.placeList.size() > 0) {
|
||||||
Place closestNearbyPlace = null;
|
Place closestNearbyPlace = null;
|
||||||
// Find the first nearby place that has no image and exists
|
// Find the first nearby place that has no image and exists
|
||||||
for (Place place : nearbyPlacesInfo.placeList) {
|
for (Place place : nearbyPlacesInfo.placeList) {
|
||||||
|
|
@ -546,9 +568,9 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(closestNearbyPlace == null) {
|
if (closestNearbyPlace == null) {
|
||||||
binding.cardViewNearby.setVisibility(View.GONE);
|
binding.cardViewNearby.setVisibility(View.GONE);
|
||||||
}else{
|
} else {
|
||||||
String distance = formatDistanceBetween(curLatLng, closestNearbyPlace.location);
|
String distance = formatDistanceBetween(curLatLng, closestNearbyPlace.location);
|
||||||
closestNearbyPlace.setDistance(distance);
|
closestNearbyPlace.setDistance(distance);
|
||||||
direction = (float) computeBearing(curLatLng, closestNearbyPlace.location);
|
direction = (float) computeBearing(curLatLng, closestNearbyPlace.location);
|
||||||
|
|
@ -567,7 +589,7 @@ public class ContributionsFragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
try{
|
try {
|
||||||
compositeDisposable.clear();
|
compositeDisposable.clear();
|
||||||
getChildFragmentManager().removeOnBackStackChangedListener(this);
|
getChildFragmentManager().removeOnBackStackChangedListener(this);
|
||||||
locationManager.unregisterLocationManager();
|
locationManager.unregisterLocationManager();
|
||||||
|
|
@ -587,7 +609,7 @@ public class ContributionsFragment
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChangedSlightly(LatLng latLng) {
|
public void onLocationChangedSlightly(LatLng latLng) {
|
||||||
/* Update closest nearby notification card onLocationChangedSlightly
|
/* Update closest nearby notification card onLocationChangedSlightly
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
updateClosestNearbyCardViewInfo();
|
updateClosestNearbyCardViewInfo();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
@ -601,7 +623,8 @@ public class ContributionsFragment
|
||||||
updateClosestNearbyCardViewInfo();
|
updateClosestNearbyCardViewInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onViewCreated(@NonNull View view,
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, 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();
|
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 (campaign != null && !isUserProfile) {
|
||||||
if (binding!=null) {
|
if (binding!=null) {
|
||||||
binding.campaignsView.setCampaign(campaign);
|
binding.campaignsView.setCampaign(campaign);
|
||||||
|
|
@ -638,7 +663,8 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onDestroyView() {
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
presenter.onDetachView();
|
presenter.onDetachView();
|
||||||
}
|
}
|
||||||
|
|
@ -652,6 +678,7 @@ public class ContributionsFragment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restarts the upload process for a contribution
|
* Restarts the upload process for a contribution
|
||||||
|
*
|
||||||
* @param contribution
|
* @param contribution
|
||||||
*/
|
*/
|
||||||
public void restartUpload(Contribution contribution) {
|
public void restartUpload(Contribution contribution) {
|
||||||
|
|
@ -659,6 +686,7 @@ public class ContributionsFragment
|
||||||
contributionsPresenter.saveContribution(contribution);
|
contributionsPresenter.saveContribution(contribution);
|
||||||
Timber.d("Restarting for %s", contribution.toString());
|
Timber.d("Restarting for %s", contribution.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retry upload when it is failed
|
* Retry upload when it is failed
|
||||||
*
|
*
|
||||||
|
|
@ -667,7 +695,8 @@ public class ContributionsFragment
|
||||||
@Override
|
@Override
|
||||||
public void retryUpload(Contribution contribution) {
|
public void retryUpload(Contribution contribution) {
|
||||||
if (NetworkUtils.isInternetConnectionEstablished(getContext())) {
|
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);
|
restartUpload(contribution);
|
||||||
} else if (contribution.getState() == STATE_FAILED) {
|
} else if (contribution.getState() == STATE_FAILED) {
|
||||||
int retries = contribution.getRetries();
|
int retries = contribution.getRetries();
|
||||||
|
|
@ -675,9 +704,10 @@ public class ContributionsFragment
|
||||||
/* Limit the number of retries for a failed upload
|
/* Limit the number of retries for a failed upload
|
||||||
to handle cases like invalid filename as such uploads
|
to handle cases like invalid filename as such uploads
|
||||||
will never be successful */
|
will never be successful */
|
||||||
if(retries < MAX_RETRIES) {
|
if (retries < MAX_RETRIES) {
|
||||||
contribution.setRetries(retries + 1);
|
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);
|
restartUpload(contribution);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Show the exact reason for failure
|
// TODO: Show the exact reason for failure
|
||||||
|
|
@ -695,6 +725,7 @@ public class ContributionsFragment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses the upload
|
* Pauses the upload
|
||||||
|
*
|
||||||
* @param contribution
|
* @param contribution
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -718,15 +749,15 @@ public class ContributionsFragment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace whatever is in the current contributionsFragmentContainer view with
|
* Replace whatever is in the current contributionsFragmentContainer view with
|
||||||
* mediaDetailPagerFragment, and preserve previous state in back stack. Called when user selects a
|
* mediaDetailPagerFragment, and preserve previous state in back stack. Called when user selects
|
||||||
* contribution.
|
* a contribution.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void showDetail(int position, boolean isWikipediaButtonDisplayed) {
|
public void showDetail(int position, boolean isWikipediaButtonDisplayed) {
|
||||||
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
|
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
|
||||||
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
|
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
|
||||||
if(isUserProfile) {
|
if (isUserProfile) {
|
||||||
((ProfileActivity)getActivity()).setScroll(false);
|
((ProfileActivity) getActivity()).setScroll(false);
|
||||||
}
|
}
|
||||||
showMediaDetailPagerFragment();
|
showMediaDetailPagerFragment();
|
||||||
}
|
}
|
||||||
|
|
@ -758,17 +789,19 @@ public class ContributionsFragment
|
||||||
binding.cardViewNearby.setVisibility(View.GONE);
|
binding.cardViewNearby.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
removeFragment(mediaDetailPagerFragment);
|
removeFragment(mediaDetailPagerFragment);
|
||||||
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG, mediaDetailPagerFragment);
|
showFragment(contributionsListFragment, CONTRIBUTION_LIST_FRAGMENT_TAG,
|
||||||
if(isUserProfile) {
|
mediaDetailPagerFragment);
|
||||||
|
if (isUserProfile) {
|
||||||
// Fragment is associated with ProfileActivity
|
// Fragment is associated with ProfileActivity
|
||||||
// Enable ParentViewPager Scroll
|
// Enable ParentViewPager Scroll
|
||||||
((ProfileActivity)getActivity()).setScroll(true);
|
((ProfileActivity) getActivity()).setScroll(true);
|
||||||
}else {
|
} else {
|
||||||
fetchCampaigns();
|
fetchCampaigns();
|
||||||
}
|
}
|
||||||
if (getActivity() instanceof MainActivity) {
|
if (getActivity() instanceof MainActivity) {
|
||||||
// Fragment is associated with MainActivity
|
// Fragment is associated with MainActivity
|
||||||
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
((BaseActivity) getActivity()).getSupportActionBar()
|
||||||
|
.setDisplayHomeAsUpEnabled(false);
|
||||||
((MainActivity) getActivity()).showTabs();
|
((MainActivity) getActivity()).showTabs();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -788,11 +821,11 @@ public class ContributionsFragment
|
||||||
void upDateUploadCount() {
|
void upDateUploadCount() {
|
||||||
WorkManager.getInstance(getContext())
|
WorkManager.getInstance(getContext())
|
||||||
.getWorkInfosForUniqueWorkLiveData(UploadWorker.class.getSimpleName()).observe(
|
.getWorkInfosForUniqueWorkLiveData(UploadWorker.class.getSimpleName()).observe(
|
||||||
getViewLifecycleOwner(), workInfos -> {
|
getViewLifecycleOwner(), workInfos -> {
|
||||||
if (workInfos.size() > 0) {
|
if (workInfos.size() > 0) {
|
||||||
setUploadCount();
|
setUploadCount();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -803,7 +836,7 @@ public class ContributionsFragment
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refreshNominatedMedia(int index) {
|
public void refreshNominatedMedia(int index) {
|
||||||
if(mediaDetailPagerFragment != null && !contributionsListFragment.isVisible()) {
|
if (mediaDetailPagerFragment != null && !contributionsListFragment.isVisible()) {
|
||||||
removeFragment(mediaDetailPagerFragment);
|
removeFragment(mediaDetailPagerFragment);
|
||||||
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
|
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
|
||||||
mediaDetailPagerFragment.showImage(index);
|
mediaDetailPagerFragment.showImage(index);
|
||||||
|
|
@ -811,20 +844,20 @@ public class ContributionsFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// click listener to toggle description that means uses can press the limited connection
|
// click listener to toggle description that means uses can press the limited connection
|
||||||
// banner and description will hide. Tap again to show description.
|
// banner and description will hide. Tap again to show description.
|
||||||
private View.OnClickListener toggleDescriptionListener = new View.OnClickListener() {
|
private View.OnClickListener toggleDescriptionListener = new View.OnClickListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
View view2 = binding.limitedConnectionDescriptionTextView;
|
View view2 = binding.limitedConnectionDescriptionTextView;
|
||||||
if (view2.getVisibility() == View.GONE) {
|
if (view2.getVisibility() == View.GONE) {
|
||||||
view2.setVisibility(View.VISIBLE);
|
view2.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
view2.setVisibility(View.GONE);
|
view2.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the device rotates, rotate the Nearby banner's compass arrow in tandem.
|
* When the device rotates, rotate the Nearby banner's compass arrow in tandem.
|
||||||
|
|
|
||||||
|
|
@ -269,16 +269,15 @@ public class OkHttpJsonApiClient {
|
||||||
/**
|
/**
|
||||||
* Make API Call to get Nearby Places
|
* Make API Call to get Nearby Places
|
||||||
*
|
*
|
||||||
* @param cur Search lat long
|
* @param cur Search lat long
|
||||||
* @param language Language
|
* @param language Language
|
||||||
* @param radius Search Radius
|
* @param radius Search Radius
|
||||||
* @param shouldQueryForMonuments : Should we query for monuments
|
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
||||||
final boolean shouldQueryForMonuments, final String customQuery)
|
final String customQuery)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
Timber.d("Fetching nearby items at radius %s", radius);
|
Timber.d("Fetching nearby items at radius %s", radius);
|
||||||
|
|
@ -286,10 +285,9 @@ public class OkHttpJsonApiClient {
|
||||||
final String wikidataQuery;
|
final String wikidataQuery;
|
||||||
if (customQuery != null) {
|
if (customQuery != null) {
|
||||||
wikidataQuery = customQuery;
|
wikidataQuery = customQuery;
|
||||||
} else if (!shouldQueryForMonuments) {
|
|
||||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
|
||||||
} else {
|
} else {
|
||||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
|
wikidataQuery = FileUtils.readFromResource(
|
||||||
|
"/queries/radius_query_for_upload_wizard.rq");
|
||||||
}
|
}
|
||||||
final String query = wikidataQuery
|
final String query = wikidataQuery
|
||||||
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
|
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
|
||||||
|
|
@ -307,6 +305,74 @@ public class OkHttpJsonApiClient {
|
||||||
.url(urlBuilder.build())
|
.url(urlBuilder.build())
|
||||||
.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();
|
final Response response = okHttpClient.newCall(request).execute();
|
||||||
if (response.body() != null && response.isSuccessful()) {
|
if (response.body() != null && response.isSuccessful()) {
|
||||||
final String json = response.body().string();
|
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
|
* Make API Call to get Nearby Places Implementation does not expects a custom query
|
||||||
*
|
*
|
||||||
* @param cur Search lat long
|
* @param cur Search lat long
|
||||||
* @param language Language
|
* @param language Language
|
||||||
* @param radius Search Radius
|
* @param radius Search Radius
|
||||||
* @param shouldQueryForMonuments : Should we query for monuments
|
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius)
|
||||||
final boolean shouldQueryForMonuments)
|
|
||||||
throws Exception {
|
throws Exception {
|
||||||
return getNearbyPlaces(cur, language, radius, shouldQueryForMonuments, null);
|
return getNearbyPlaces(cur, language, radius, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -39,34 +39,34 @@ public class NearbyController extends MapController {
|
||||||
/**
|
/**
|
||||||
* 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 searchLatLng the location user wants to search around
|
* @param searchLatLng the location user wants to search around
|
||||||
* @param returnClosestResult if this search is done to find closest result or all results
|
* @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
|
* @param customQuery if this search is done via an advanced query
|
||||||
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
* @return NearbyPlacesInfo a variable holds Place list without distance information and
|
||||||
* and boundary coordinates of current Place List
|
* 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 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);
|
Timber.d("Loading attractions near %s", searchLatLng);
|
||||||
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
|
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
|
||||||
|
|
||||||
if (searchLatLng == null) {
|
if (searchLatLng == null) {
|
||||||
Timber.d("Loading attractions nearby, but curLatLng is null");
|
Timber.d("Loading attractions nearby, but curLatLng is null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<Place> places = nearbyPlaces
|
List<Place> places = nearbyPlaces
|
||||||
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
||||||
shouldQueryForMonuments, customQuery);
|
customQuery);
|
||||||
|
|
||||||
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, // north
|
places.get(0).location, // south
|
||||||
places.get(0).location, // west
|
places.get(0).location, // north
|
||||||
places.get(0).location};// east, init with a random location
|
places.get(0).location, // west
|
||||||
|
places.get(0).location};// east, init with a random location
|
||||||
|
|
||||||
if (curLatLng != null) {
|
if (curLatLng != null) {
|
||||||
Timber.d("Sorting places by distance...");
|
Timber.d("Sorting places by distance...");
|
||||||
|
|
@ -88,11 +88,11 @@ public class NearbyController extends MapController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(places,
|
Collections.sort(places,
|
||||||
(lhs, rhs) -> {
|
(lhs, rhs) -> {
|
||||||
double lhsDistance = distances.get(lhs);
|
double lhsDistance = distances.get(lhs);
|
||||||
double rhsDistance = distances.get(rhs);
|
double rhsDistance = distances.get(rhs);
|
||||||
return (int) (lhsDistance - rhsDistance);
|
return (int) (lhsDistance - rhsDistance);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
nearbyPlacesInfo.curLatLng = curLatLng;
|
nearbyPlacesInfo.curLatLng = curLatLng;
|
||||||
|
|
@ -104,11 +104,11 @@ public class NearbyController extends MapController {
|
||||||
if (!returnClosestResult) {
|
if (!returnClosestResult) {
|
||||||
// To remember latest search either around user or any point on map
|
// To remember latest search either around user or any point on map
|
||||||
latestSearchLocation = searchLatLng;
|
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
|
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
|
||||||
if (checkingAroundCurrentLocation) {
|
if (checkingAroundCurrentLocation) {
|
||||||
currentLocationSearchRadius = nearbyPlaces.radius*1000; // to meter
|
currentLocationSearchRadius = nearbyPlaces.radius * 1000; // to meter
|
||||||
currentLocation = curLatLng;
|
currentLocation = curLatLng;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +118,98 @@ public class NearbyController extends MapController {
|
||||||
return nearbyPlacesInfo;
|
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.
|
* 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,
|
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng,
|
||||||
final LatLng searchLatLng,
|
final LatLng searchLatLng,
|
||||||
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
|
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation)
|
||||||
final boolean shouldQueryForMonuments) throws Exception {
|
throws Exception {
|
||||||
return loadAttractionsFromLocation(curLatLng, searchLatLng, returnClosestResult,
|
return loadAttractionsFromLocation(curLatLng, searchLatLng, returnClosestResult,
|
||||||
checkingAroundCurrentLocation, shouldQueryForMonuments, null);
|
checkingAroundCurrentLocation, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -171,12 +263,14 @@ public class NearbyController extends MapController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates makerLabelList item isBookmarked value
|
* 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
|
* @param isBookmarked true is bookmarked, false if bookmark removed
|
||||||
*/
|
*/
|
||||||
@MainThread
|
@MainThread
|
||||||
public static void updateMarkerLabelListBookmark(Place place, boolean isBookmarked) {
|
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();
|
MarkerPlaceGroup markerPlaceGroup = iter.next();
|
||||||
if (markerPlaceGroup.getPlace().getWikiDataEntityId().equals(place.getWikiDataEntityId())) {
|
if (markerPlaceGroup.getPlace().getWikiDataEntityId().equals(place.getWikiDataEntityId())) {
|
||||||
iter.set(new MarkerPlaceGroup(isBookmarked, place));
|
iter.set(new MarkerPlaceGroup(isBookmarked, place));
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public class NearbyPlaces {
|
||||||
/**
|
/**
|
||||||
* Reads Wikidata query to check nearby wikidata items which needs picture, with a circular
|
* 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.
|
* search. As a point is center of a circle with a radius will be set later.
|
||||||
|
*
|
||||||
* @param okHttpJsonApiClient
|
* @param okHttpJsonApiClient
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
|
|
@ -36,15 +37,15 @@ public class NearbyPlaces {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expands the radius as needed for the Wikidata query
|
* 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 returnClosestResult true if only the nearest point is desired
|
||||||
* @param customQuery
|
* @param customQuery
|
||||||
* @return list of places obtained
|
* @return list of places obtained
|
||||||
*/
|
*/
|
||||||
List<Place> radiusExpander(final LatLng curLatLng, final String lang,
|
List<Place> radiusExpander(final LatLng curLatLng, final String lang,
|
||||||
final boolean returnClosestResult
|
final boolean returnClosestResult, @Nullable final String customQuery) throws Exception {
|
||||||
, final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
|
|
||||||
|
|
||||||
final int minResults;
|
final int minResults;
|
||||||
final double maxRadius;
|
final double maxRadius;
|
||||||
|
|
@ -63,15 +64,15 @@ public class NearbyPlaces {
|
||||||
radius = INITIAL_RADIUS;
|
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
|
||||||
while (radius <= maxRadius) {
|
while (radius <= maxRadius) {
|
||||||
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments, customQuery);
|
places = getFromWikidataQuery(curLatLng, lang, radius, customQuery);
|
||||||
Timber.d("%d results at radius: %f", places.size(), radius);
|
Timber.d("%d results at radius: %f", places.size(), radius);
|
||||||
if (places.size() >= minResults) {
|
if (places.size() >= minResults) {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
radius *= RADIUS_MULTIPLIER;
|
|
||||||
}
|
}
|
||||||
|
radius *= RADIUS_MULTIPLIER;
|
||||||
|
}
|
||||||
// make sure we will be able to send at least one request next time
|
// make sure we will be able to send at least one request next time
|
||||||
if (radius > maxRadius) {
|
if (radius > maxRadius) {
|
||||||
radius = maxRadius;
|
radius = maxRadius;
|
||||||
|
|
@ -81,18 +82,41 @@ public class NearbyPlaces {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the Wikidata query to populate the Places around search location
|
* Runs the Wikidata query to populate the Places around search location
|
||||||
* @param cur coordinates of search location
|
*
|
||||||
* @param lang user's language
|
* @param cur coordinates of search location
|
||||||
* @param radius radius for search, as determined by radiusExpander()
|
* @param lang user's language
|
||||||
* @param shouldQueryForMonuments should the query include properites for monuments
|
* @param radius radius for search, as determined by radiusExpander()
|
||||||
* @param customQuery
|
* @param customQuery
|
||||||
* @return list of places obtained
|
* @return list of places obtained
|
||||||
* @throws IOException if query fails
|
* @throws IOException if query fails
|
||||||
*/
|
*/
|
||||||
public List<Place> getFromWikidataQuery(final LatLng cur, final String lang,
|
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 {
|
@Nullable final String customQuery) throws Exception {
|
||||||
return okHttpJsonApiClient
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.osmdroid.api.IGeoPoint;
|
||||||
import org.osmdroid.events.MapEventsReceiver;
|
import org.osmdroid.events.MapEventsReceiver;
|
||||||
import org.osmdroid.events.MapListener;
|
import org.osmdroid.events.MapListener;
|
||||||
import org.osmdroid.events.ScrollEvent;
|
import org.osmdroid.events.ScrollEvent;
|
||||||
|
|
@ -489,7 +490,7 @@ 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/nearby_query.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);
|
||||||
}
|
}
|
||||||
|
|
@ -1119,11 +1120,52 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void populatePlaces(final fr.free.nrw.commons.location.LatLng curlatLng) {
|
public void populatePlaces(final fr.free.nrw.commons.location.LatLng curlatLng) {
|
||||||
if (curlatLng.equals(getLastMapFocus())) { // Means we are checking around current location
|
IGeoPoint screenTopRight = mapView.getProjection().fromPixels(mapView.getWidth(), 0);
|
||||||
populatePlacesForCurrentLocation(getLastMapFocus(), curlatLng, null);
|
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 {
|
} 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) {
|
if (recenterToUserLocation) {
|
||||||
recenterToUserLocation = false;
|
recenterToUserLocation = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1136,12 +1178,20 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
populatePlaces(curlatLng);
|
populatePlaces(curlatLng);
|
||||||
return;
|
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
|
if (curlatLng.equals(lastFocusLocation) || lastFocusLocation == null
|
||||||
|| recenterToUserLocation) { // Means we are checking around current location
|
|| recenterToUserLocation) { // Means we are checking around current location
|
||||||
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng, customQuery);
|
populatePlacesForCurrentLocation(lastKnownLocation, screenTopRightLatLng,
|
||||||
|
screenBottomLeftLatLng, curlatLng, customQuery);
|
||||||
} else {
|
} else {
|
||||||
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng, customQuery);
|
populatePlacesForAnotherLocation(lastKnownLocation, screenTopRightLatLng,
|
||||||
|
screenBottomLeftLatLng, curlatLng, customQuery);
|
||||||
}
|
}
|
||||||
if (recenterToUserLocation) {
|
if (recenterToUserLocation) {
|
||||||
recenterToUserLocation = false;
|
recenterToUserLocation = false;
|
||||||
|
|
@ -1150,11 +1200,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
|
|
||||||
private void populatePlacesForCurrentLocation(
|
private void populatePlacesForCurrentLocation(
|
||||||
final fr.free.nrw.commons.location.LatLng curlatLng,
|
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,
|
final fr.free.nrw.commons.location.LatLng searchLatLng,
|
||||||
@Nullable final String customQuery) {
|
@Nullable final String customQuery) {
|
||||||
final Observable<NearbyController.NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
final Observable<NearbyController.NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||||
.fromCallable(() -> nearbyController
|
.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
.loadAttractionsFromLocation(curlatLng, screenTopRight, screenBottomLeft,
|
||||||
|
searchLatLng,
|
||||||
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||||
|
|
||||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||||
|
|
@ -1182,11 +1235,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
|
|
||||||
private void populatePlacesForAnotherLocation(
|
private void populatePlacesForAnotherLocation(
|
||||||
final fr.free.nrw.commons.location.LatLng curlatLng,
|
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,
|
final fr.free.nrw.commons.location.LatLng searchLatLng,
|
||||||
@Nullable final String customQuery) {
|
@Nullable final String customQuery) {
|
||||||
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||||
.fromCallable(() -> nearbyController
|
.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
.loadAttractionsFromLocation(curlatLng, screenTopRight, screenBottomLeft,
|
||||||
|
searchLatLng,
|
||||||
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||||
|
|
||||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,7 @@ public class UploadRepository {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns nearest place matching the passed latitude and longitude
|
* Returns nearest place matching the passed latitude and longitude
|
||||||
|
*
|
||||||
* @param decLatitude
|
* @param decLatitude
|
||||||
* @param decLongitude
|
* @param decLongitude
|
||||||
* @return
|
* @return
|
||||||
|
|
@ -354,11 +355,11 @@ public class UploadRepository {
|
||||||
try {
|
try {
|
||||||
final List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
|
final List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
|
||||||
decLatitude, decLongitude, 0.0f),
|
decLatitude, decLongitude, 0.0f),
|
||||||
Locale.getDefault().getLanguage(),
|
Locale.getDefault().getLanguage(),
|
||||||
NEARBY_RADIUS_IN_KILO_METERS, false, null);
|
NEARBY_RADIUS_IN_KILO_METERS, null);
|
||||||
return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery
|
return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery
|
||||||
.get(0) : null;
|
.get(0) : null;
|
||||||
}catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
Timber.e("Error fetching nearby places: %s", e.getMessage());
|
Timber.e("Error fetching nearby places: %s", e.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,10 @@ class FileProcessor @Inject constructor(
|
||||||
/**
|
/**
|
||||||
* Processes filePath coordinates, either from EXIF data or user location
|
* Processes filePath coordinates, either from EXIF data or user location
|
||||||
*/
|
*/
|
||||||
fun processFileCoordinates(similarImageInterface: SimilarImageInterface,
|
fun processFileCoordinates(
|
||||||
filePath: String?, inAppPictureLocation: LatLng?)
|
similarImageInterface: SimilarImageInterface,
|
||||||
|
filePath: String?, inAppPictureLocation: LatLng?
|
||||||
|
)
|
||||||
: ImageCoordinates {
|
: ImageCoordinates {
|
||||||
val exifInterface: ExifInterface? = try {
|
val exifInterface: ExifInterface? = try {
|
||||||
ExifInterface(filePath!!)
|
ExifInterface(filePath!!)
|
||||||
|
|
@ -207,8 +209,7 @@ class FileProcessor @Inject constructor(
|
||||||
okHttpJsonApiClient.getNearbyPlaces(
|
okHttpJsonApiClient.getNearbyPlaces(
|
||||||
imageCoordinates.latLng,
|
imageCoordinates.latLng,
|
||||||
Locale.getDefault().language,
|
Locale.getDefault().language,
|
||||||
it,
|
it
|
||||||
false
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ public class FileUtils {
|
||||||
/**
|
/**
|
||||||
* Read and return the content of a resource filePath as string.
|
* 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
|
* @return the content of the filePath
|
||||||
*/
|
*/
|
||||||
public static String readFromResource(String fileName) throws IOException {
|
public static String readFromResource(String fileName) throws IOException {
|
||||||
|
|
|
||||||
56
app/src/main/resources/queries/rectangle_query_for_nearby.rq
Normal file
56
app/src/main/resources/queries/rectangle_query_for_nearby.rq
Normal 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
|
||||||
|
|
@ -14,10 +14,10 @@ SELECT
|
||||||
(SAMPLE(?monument) AS ?monument)
|
(SAMPLE(?monument) AS ?monument)
|
||||||
WHERE {
|
WHERE {
|
||||||
# Around given location
|
# Around given location
|
||||||
SERVICE wikibase:around {
|
SERVICE wikibase:box {
|
||||||
?item wdt:P625 ?location.
|
?item wdt:P625 ?location.
|
||||||
bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral. # Longitude latitude
|
bd:serviceParam wikibase:cornerWest "Point(${LONG_WEST} ${LAT_WEST})"^^geo:wktLiteral.
|
||||||
bd:serviceParam wikibase:radius "${RAD}". # Radius in kilometers.
|
bd:serviceParam wikibase:cornerEast "Point(${LONG_EAST} ${LAT_EAST})"^^geo:wktLiteral.
|
||||||
}
|
}
|
||||||
|
|
||||||
OPTIONAL {
|
OPTIONAL {
|
||||||
|
|
@ -62,7 +62,8 @@ class OkHttpJsonApiClientTests {
|
||||||
fun testGetNearbyPlacesCustomQuery() {
|
fun testGetNearbyPlacesCustomQuery() {
|
||||||
Mockito.`when`(response.message).thenReturn("test")
|
Mockito.`when`(response.message).thenReturn("test")
|
||||||
try {
|
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) {
|
} catch (e: Exception) {
|
||||||
assert(e.message.equals("test"))
|
assert(e.message.equals("test"))
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +76,8 @@ class OkHttpJsonApiClientTests {
|
||||||
fun testGetNearbyPlaces() {
|
fun testGetNearbyPlaces() {
|
||||||
Mockito.`when`(response.message).thenReturn("test")
|
Mockito.`when`(response.message).thenReturn("test")
|
||||||
try {
|
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) {
|
} catch (e: Exception) {
|
||||||
assert(e.message.equals("test"))
|
assert(e.message.equals("test"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ class NearbyControllerTest {
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var nearbyPlaces: NearbyPlaces
|
private lateinit var nearbyPlaces: NearbyPlaces
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var screenTopRight: LatLng
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var screenBottomLeft: LatLng
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private lateinit var searchLatLong: LatLng
|
private lateinit var searchLatLong: LatLng
|
||||||
|
|
||||||
|
|
@ -56,41 +62,48 @@ class NearbyControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLoadAttractionsForLocationTest() {
|
fun testLoadAttractionsForLocationTest() {
|
||||||
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), any()))
|
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any()))
|
||||||
.thenReturn(Collections.emptyList())
|
.thenReturn(Collections.emptyList())
|
||||||
nearbyController.loadAttractionsFromLocation(
|
nearbyController.loadAttractionsFromLocation(
|
||||||
searchLatLong,
|
|
||||||
currentLatLng,
|
currentLatLng,
|
||||||
false,
|
searchLatLong,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
|
nearbyController.loadAttractionsFromLocation(
|
||||||
|
currentLatLng,
|
||||||
|
screenTopRight,
|
||||||
|
screenBottomLeft,
|
||||||
|
searchLatLong,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
customQuery
|
||||||
|
)
|
||||||
Mockito.verify(nearbyPlaces).radiusExpander(
|
Mockito.verify(nearbyPlaces).radiusExpander(
|
||||||
eq(currentLatLng),
|
eq(searchLatLong),
|
||||||
any(String::class.java),
|
any(String::class.java),
|
||||||
eq(false),
|
eq(false),
|
||||||
eq(true),
|
|
||||||
eq(customQuery)
|
eq(customQuery)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testLoadAttractionsForLocationTestNoQuery() {
|
fun testLoadAttractionsForLocationTestNoQuery() {
|
||||||
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), anyOrNull()))
|
`when`(nearbyPlaces.radiusExpander(any(), any(), any(), anyOrNull()))
|
||||||
.thenReturn(Collections.emptyList())
|
.thenReturn(Collections.emptyList())
|
||||||
nearbyController.loadAttractionsFromLocation(
|
nearbyController.loadAttractionsFromLocation(
|
||||||
searchLatLong,
|
|
||||||
currentLatLng,
|
currentLatLng,
|
||||||
|
searchLatLong,
|
||||||
false,
|
false,
|
||||||
false,
|
true,
|
||||||
true
|
null
|
||||||
)
|
)
|
||||||
Mockito.verify(nearbyPlaces).radiusExpander(
|
Mockito.verify(nearbyPlaces).radiusExpander(
|
||||||
eq(currentLatLng),
|
eq(searchLatLong),
|
||||||
any(String::class.java),
|
any(String::class.java),
|
||||||
eq(false),
|
eq(false),
|
||||||
eq(true),
|
|
||||||
eq(null)
|
eq(null)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -102,8 +115,7 @@ class NearbyControllerTest {
|
||||||
currentLatLng,
|
currentLatLng,
|
||||||
null,
|
null,
|
||||||
false,
|
false,
|
||||||
false,
|
true,
|
||||||
false,
|
|
||||||
customQuery
|
customQuery
|
||||||
), null
|
), null
|
||||||
)
|
)
|
||||||
|
|
@ -136,7 +148,7 @@ class NearbyControllerTest {
|
||||||
`when`(
|
`when`(
|
||||||
nearbyPlaces.radiusExpander(
|
nearbyPlaces.radiusExpander(
|
||||||
searchLatLong, Locale.getDefault().language, false,
|
searchLatLong, Locale.getDefault().language, false,
|
||||||
false, customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
).thenReturn(mutableListOf(place1, place2))
|
).thenReturn(mutableListOf(place1, place2))
|
||||||
val result = nearbyController.loadAttractionsFromLocation(
|
val result = nearbyController.loadAttractionsFromLocation(
|
||||||
|
|
@ -144,6 +156,15 @@ class NearbyControllerTest {
|
||||||
searchLatLong,
|
searchLatLong,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
customQuery
|
||||||
|
)
|
||||||
|
nearbyController.loadAttractionsFromLocation(
|
||||||
|
currentLatLng,
|
||||||
|
screenTopRight,
|
||||||
|
screenBottomLeft,
|
||||||
|
searchLatLong,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
false,
|
false,
|
||||||
customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
|
|
@ -178,7 +199,7 @@ class NearbyControllerTest {
|
||||||
`when`(
|
`when`(
|
||||||
nearbyPlaces.radiusExpander(
|
nearbyPlaces.radiusExpander(
|
||||||
searchLatLong, Locale.getDefault().language, false,
|
searchLatLong, Locale.getDefault().language, false,
|
||||||
false, customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
).thenReturn(mutableListOf(place1, place2))
|
).thenReturn(mutableListOf(place1, place2))
|
||||||
val result = nearbyController.loadAttractionsFromLocation(
|
val result = nearbyController.loadAttractionsFromLocation(
|
||||||
|
|
@ -186,7 +207,6 @@ class NearbyControllerTest {
|
||||||
searchLatLong,
|
searchLatLong,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
assertEquals(result.curLatLng, currentLatLng)
|
assertEquals(result.curLatLng, currentLatLng)
|
||||||
|
|
@ -220,7 +240,7 @@ class NearbyControllerTest {
|
||||||
`when`(
|
`when`(
|
||||||
nearbyPlaces.radiusExpander(
|
nearbyPlaces.radiusExpander(
|
||||||
searchLatLong, Locale.getDefault().language, false,
|
searchLatLong, Locale.getDefault().language, false,
|
||||||
false, customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
).thenReturn(mutableListOf(place1, place2))
|
).thenReturn(mutableListOf(place1, place2))
|
||||||
val result = nearbyController.loadAttractionsFromLocation(
|
val result = nearbyController.loadAttractionsFromLocation(
|
||||||
|
|
@ -228,7 +248,6 @@ class NearbyControllerTest {
|
||||||
searchLatLong,
|
searchLatLong,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
customQuery
|
customQuery
|
||||||
)
|
)
|
||||||
assertEquals(result.curLatLng, currentLatLng)
|
assertEquals(result.curLatLng, currentLatLng)
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,11 @@ class NearbyPlacesTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testRadiusExpander() {
|
fun testRadiusExpander() {
|
||||||
nearbyPlaces.radiusExpander(currentLatLong, "test", true, true, "test")
|
nearbyPlaces.radiusExpander(currentLatLong, "test", true, "test")
|
||||||
verify(okHttpJsonApiClient, times(5)).getNearbyPlaces(
|
verify(okHttpJsonApiClient, times(5)).getNearbyPlaces(
|
||||||
eq(currentLatLong),
|
eq(currentLatLong),
|
||||||
eq("test"),
|
eq("test"),
|
||||||
any(),
|
any(),
|
||||||
eq(true),
|
|
||||||
eq("test")
|
eq("test")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,8 +217,10 @@ class UploadRepositoryUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetSelectedExistingDepictions() {
|
fun testSetSelectedExistingDepictions() {
|
||||||
assertEquals(repository.setSelectedExistingDepictions(listOf("")),
|
assertEquals(
|
||||||
uploadModel.setSelectedExistingDepictions(listOf("")))
|
repository.setSelectedExistingDepictions(listOf("")),
|
||||||
|
uploadModel.setSelectedExistingDepictions(listOf(""))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -264,7 +266,7 @@ class UploadRepositoryUnitTest {
|
||||||
nearbyPlaces.getFromWikidataQuery(
|
nearbyPlaces.getFromWikidataQuery(
|
||||||
LatLng(0.0, 0.0, 0.0f),
|
LatLng(0.0, 0.0, 0.0f),
|
||||||
java.util.Locale.getDefault().language, 0.1,
|
java.util.Locale.getDefault().language, 0.1,
|
||||||
false, null
|
null
|
||||||
)
|
)
|
||||||
).thenReturn(listOf(place))
|
).thenReturn(listOf(place))
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
@ -287,7 +289,7 @@ class UploadRepositoryUnitTest {
|
||||||
nearbyPlaces.getFromWikidataQuery(
|
nearbyPlaces.getFromWikidataQuery(
|
||||||
LatLng(0.0, 0.0, 0.0f),
|
LatLng(0.0, 0.0, 0.0f),
|
||||||
java.util.Locale.getDefault().language, 0.1,
|
java.util.Locale.getDefault().language, 0.1,
|
||||||
false, null
|
null
|
||||||
)
|
)
|
||||||
).thenThrow(Exception())
|
).thenThrow(Exception())
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
|
@ -348,19 +350,25 @@ class UploadRepositoryUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetSelectedExistingCategories() {
|
fun testGetSelectedExistingCategories() {
|
||||||
assertEquals(repository.selectedExistingCategories,
|
assertEquals(
|
||||||
categoriesModel.getSelectedExistingCategories())
|
repository.selectedExistingCategories,
|
||||||
|
categoriesModel.getSelectedExistingCategories()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSetSelectedExistingCategories() {
|
fun testSetSelectedExistingCategories() {
|
||||||
assertEquals(repository.setSelectedExistingCategories(listOf("Test")),
|
assertEquals(
|
||||||
categoriesModel.setSelectedExistingCategories(mutableListOf("Test")))
|
repository.setSelectedExistingCategories(listOf("Test")),
|
||||||
|
categoriesModel.setSelectedExistingCategories(mutableListOf("Test"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testGetCategories() {
|
fun testGetCategories() {
|
||||||
assertEquals(repository.getCategories(listOf("Test")),
|
assertEquals(
|
||||||
categoriesModel.getCategoriesByName(mutableListOf("Test")))
|
repository.getCategories(listOf("Test")),
|
||||||
|
categoriesModel.getCategoriesByName(mutableListOf("Test"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue