mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Added advanced query support in Nearby (#4714)
* Added feature for advanced query options in Nearby * Fix unit-tests coverage * wip-tests * Added log to identify if the nearby request is via an advanced query * Rolledback test-dependency updates * Fix tests * build fix * Added basic tests for relevant method in OkHttpJsonApiClient & NearbyController * Added NearbyParentFragmentPresenter Tests * Added AdvancedQueryFragment Unit Tests * Added more tests for NearbyParentFragmentPresenter * Reset ContributionsFragment with Upstream * Overload method loadNearbyPlaces for CustomQuery * Added more tests * Added more tests * Fixed tests for NearbyParentFragmentPresenter
This commit is contained in:
parent
bd00ce2071
commit
a0ff15cdc2
19 changed files with 823 additions and 47 deletions
|
|
@ -268,6 +268,7 @@ public class LocationServiceManager implements LocationListener {
|
|||
LOCATION_NOT_CHANGED,
|
||||
PERMISSION_JUST_GRANTED,
|
||||
MAP_UPDATED,
|
||||
SEARCH_CUSTOM_AREA
|
||||
SEARCH_CUSTOM_AREA,
|
||||
CUSTOM_QUERY
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.text.TextUtils;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.gson.Gson;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
||||
import fr.free.nrw.commons.explore.depictions.DepictsClient;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
|
|
@ -265,14 +266,27 @@ 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
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Nullable
|
||||
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
||||
final boolean shouldQueryForMonuments)
|
||||
final boolean shouldQueryForMonuments, final String customQuery)
|
||||
throws Exception {
|
||||
|
||||
Timber.d("Fetching nearby items at radius %s", radius);
|
||||
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
|
||||
final String wikidataQuery;
|
||||
if (!shouldQueryForMonuments) {
|
||||
if (customQuery != null) {
|
||||
wikidataQuery = customQuery;
|
||||
} else if (!shouldQueryForMonuments) {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
||||
} else {
|
||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
|
||||
|
|
@ -313,6 +327,23 @@ public class OkHttpJsonApiClient {
|
|||
throw new Exception(response.message());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Nullable
|
||||
public List<Place> getNearbyPlaces(final LatLng cur, final String language, final double radius,
|
||||
final boolean shouldQueryForMonuments)
|
||||
throws Exception {
|
||||
return getNearbyPlaces(cur, language, radius, shouldQueryForMonuments, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example:
|
||||
* bridge -> suspended bridge, aqueduct, etc
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.res.Resources;
|
|||
import android.graphics.Bitmap;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||
|
|
@ -54,12 +55,13 @@ public class NearbyController {
|
|||
* @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
|
||||
*/
|
||||
public NearbyPlacesInfo loadAttractionsFromLocation(final LatLng curLatLng, final LatLng searchLatLng,
|
||||
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
|
||||
final boolean shouldQueryForMonuments) throws Exception {
|
||||
final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
|
||||
|
||||
Timber.d("Loading attractions near %s", searchLatLng);
|
||||
NearbyPlacesInfo nearbyPlacesInfo = new NearbyPlacesInfo();
|
||||
|
|
@ -70,7 +72,7 @@ public class NearbyController {
|
|||
}
|
||||
List<Place> places = nearbyPlaces
|
||||
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
||||
shouldQueryForMonuments);
|
||||
shouldQueryForMonuments, customQuery);
|
||||
|
||||
if (null != places && places.size() > 0) {
|
||||
LatLng[] boundaryCoordinates = {places.get(0).location, // south
|
||||
|
|
@ -128,10 +130,27 @@ public class NearbyController {
|
|||
return nearbyPlacesInfo;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
return nearbyPlacesInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 returnClosestResult if this search is done to find closest result or all results
|
||||
* @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,
|
||||
final boolean returnClosestResult, final boolean checkingAroundCurrentLocation,
|
||||
final boolean shouldQueryForMonuments) throws Exception {
|
||||
return loadAttractionsFromLocation(curLatLng, searchLatLng, returnClosestResult,
|
||||
checkingAroundCurrentLocation, shouldQueryForMonuments, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads attractions from location for list view, we need to return Place data type.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -38,10 +39,12 @@ public class NearbyPlaces {
|
|||
* @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) throws Exception {
|
||||
List<Place> radiusExpander(final LatLng curLatLng, final String lang,
|
||||
final boolean returnClosestResult
|
||||
, final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
|
||||
|
||||
final int minResults;
|
||||
final double maxRadius;
|
||||
|
|
@ -62,13 +65,12 @@ public class NearbyPlaces {
|
|||
|
||||
// Increase the radius gradually to find a satisfactory number of nearby places
|
||||
while (radius <= maxRadius) {
|
||||
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments);
|
||||
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments, customQuery);
|
||||
Timber.d("%d results at radius: %f", places.size(), radius);
|
||||
if (places.size() >= minResults) {
|
||||
break;
|
||||
} else {
|
||||
radius *= RADIUS_MULTIPLIER;
|
||||
}
|
||||
radius *= RADIUS_MULTIPLIER;
|
||||
}
|
||||
// make sure we will be able to send at least one request next time
|
||||
if (radius > maxRadius) {
|
||||
|
|
@ -83,11 +85,14 @@ public class NearbyPlaces {
|
|||
* @param lang user's language
|
||||
* @param radius radius for search, as determined by radiusExpander()
|
||||
* @param shouldQueryForMonuments should the query include properites for monuments
|
||||
* @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) throws Exception {
|
||||
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius, shouldQueryForMonuments);
|
||||
final double radius, final boolean shouldQueryForMonuments,
|
||||
@Nullable final String customQuery) throws Exception {
|
||||
return okHttpJsonApiClient
|
||||
.getNearbyPlaces(cur, lang, radius, shouldQueryForMonuments, customQuery);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package fr.free.nrw.commons.nearby.contract;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
|
||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
||||
import java.util.List;
|
||||
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
|
|
@ -19,6 +20,7 @@ public interface NearbyParentFragmentContract {
|
|||
boolean isNetworkConnectionEstablished();
|
||||
void listOptionMenuItemClicked();
|
||||
void populatePlaces(LatLng curlatLng);
|
||||
void populatePlaces(LatLng curlatLng, String customQuery);
|
||||
boolean isListBottomSheetExpanded();
|
||||
void checkPermissionsAndPerformAction();
|
||||
void displayLoginSkippedWarning();
|
||||
|
|
@ -62,7 +64,7 @@ public interface NearbyParentFragmentContract {
|
|||
|
||||
LatLng getCameraTarget();
|
||||
|
||||
void centerMapToPlace(Place placeToCenter);
|
||||
void centerMapToPlace(@Nullable Place placeToCenter);
|
||||
|
||||
void updateListFragment(List<Place> placeList);
|
||||
|
||||
|
|
@ -72,6 +74,12 @@ public interface NearbyParentFragmentContract {
|
|||
|
||||
boolean isCurrentLocationMarkerVisible();
|
||||
void setProjectorLatLngBounds();
|
||||
|
||||
boolean isAdvancedQueryFragmentVisible();
|
||||
|
||||
void showHideAdvancedQueryFragment(boolean shouldShow);
|
||||
|
||||
void centerMapToPosition(@Nullable LatLng searchLatLng);
|
||||
}
|
||||
|
||||
interface NearbyListView {
|
||||
|
|
@ -79,7 +87,7 @@ public interface NearbyParentFragmentContract {
|
|||
}
|
||||
|
||||
interface UserActions {
|
||||
void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType);
|
||||
void updateMapAndList(LocationChangeType locationChangeType);
|
||||
void lockUnlockNearby(boolean isNearbyLocked);
|
||||
|
||||
void attachView(View view);
|
||||
|
|
@ -96,5 +104,7 @@ public interface NearbyParentFragmentContract {
|
|||
|
||||
void searchViewGainedFocus();
|
||||
void setCheckboxUnknown();
|
||||
|
||||
void setAdvancedQuery(String query);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package fr.free.nrw.commons.nearby.fragments
|
||||
|
||||
import android.content.Context.INPUT_METHOD_SERVICE
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.fragment.app.Fragment
|
||||
import fr.free.nrw.commons.R
|
||||
import kotlinx.android.synthetic.main.fragment_advance_query.*
|
||||
|
||||
class AdvanceQueryFragment : Fragment() {
|
||||
|
||||
lateinit var originalQuery: String
|
||||
lateinit var callback: Callback
|
||||
lateinit var etQuery: AppCompatEditText
|
||||
lateinit var btnApply: AppCompatButton
|
||||
lateinit var btnReset: AppCompatButton
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_advance_query, container, false)
|
||||
originalQuery = arguments?.getString("query")!!
|
||||
setHasOptionsMenu(false)
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
etQuery = view.findViewById(R.id.et_query)
|
||||
btnApply = view.findViewById(R.id.btn_apply)
|
||||
btnReset = view.findViewById(R.id.btn_reset)
|
||||
|
||||
etQuery.setText(originalQuery)
|
||||
btnReset.setOnClickListener {
|
||||
btnReset.post {
|
||||
etQuery.setText(originalQuery)
|
||||
etQuery.clearFocus()
|
||||
hideKeyBoard()
|
||||
callback.reset()
|
||||
}
|
||||
}
|
||||
|
||||
btnApply.setOnClickListener {
|
||||
btnApply.post {
|
||||
etQuery.clearFocus()
|
||||
hideKeyBoard()
|
||||
callback.apply(etQuery.text.toString())
|
||||
callback.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideKeyBoard() {
|
||||
val inputMethodManager =
|
||||
context?.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager?
|
||||
inputMethodManager?.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun reset()
|
||||
fun apply(query: String)
|
||||
fun close()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package fr.free.nrw.commons.nearby.fragments;
|
||||
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.CUSTOM_QUERY;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
||||
|
|
@ -34,6 +35,7 @@ import android.view.ViewGroup;
|
|||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
|
|
@ -44,6 +46,7 @@ import androidx.annotation.DrawableRes;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.AppCompatButton;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
|
|
@ -100,7 +103,9 @@ import fr.free.nrw.commons.nearby.NearbyFilterState;
|
|||
import fr.free.nrw.commons.nearby.NearbyMarker;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
|
||||
import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment.Callback;
|
||||
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
|
||||
import fr.free.nrw.commons.upload.FileUtils;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
import fr.free.nrw.commons.utils.ExecutorUtils;
|
||||
import fr.free.nrw.commons.utils.LayoutUtils;
|
||||
|
|
@ -114,14 +119,12 @@ import fr.free.nrw.commons.utils.ViewUtil;
|
|||
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
|
@ -180,6 +183,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
AppCompatImageView ivToggleChips;
|
||||
@BindView(R.id.chip_view)
|
||||
View llContainerChips;
|
||||
@BindView(R.id.btn_advanced_options)
|
||||
AppCompatButton btnAdvancedOptions;
|
||||
@BindView(R.id.fl_container_nearby_children)
|
||||
FrameLayout flConainerNearbyChildren;
|
||||
|
||||
@Inject LocationServiceManager locationManager;
|
||||
@Inject NearbyController nearbyController;
|
||||
|
|
@ -233,6 +240,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
private LatLngBounds latLngBounds;
|
||||
private PlaceAdapter adapter;
|
||||
private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback;
|
||||
private boolean isAdvancedQueryFragmentVisible = false;
|
||||
|
||||
/**
|
||||
* Holds filtered markers that are to be shown
|
||||
|
|
@ -342,6 +350,42 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
|
||||
tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
|
||||
tvAttribution.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
btnAdvancedOptions.setOnClickListener(v -> {
|
||||
searchView.clearFocus();
|
||||
showHideAdvancedQueryFragment(true);
|
||||
final AdvanceQueryFragment fragment = new AdvanceQueryFragment();
|
||||
final Bundle bundle=new Bundle();
|
||||
try {
|
||||
bundle.putString("query", FileUtils.readFromResource("/queries/nearby_query.rq"));
|
||||
} catch (IOException e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
fragment.setArguments(bundle);
|
||||
fragment.callback = new Callback() {
|
||||
@Override
|
||||
public void close() {
|
||||
showHideAdvancedQueryFragment(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
presenter.setAdvancedQuery(null);
|
||||
presenter.updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED);
|
||||
showHideAdvancedQueryFragment(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull final String query) {
|
||||
presenter.setAdvancedQuery(query);
|
||||
presenter.updateMapAndList(CUSTOM_QUERY);
|
||||
showHideAdvancedQueryFragment(false);
|
||||
}
|
||||
};
|
||||
getChildFragmentManager().beginTransaction()
|
||||
.replace(R.id.fl_container_nearby_children, fragment)
|
||||
.commit();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -600,7 +644,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
});
|
||||
nearbyFilterList.getLayoutParams().width = (int) LayoutUtils.getScreenWidth(getActivity(), 0.75);
|
||||
recyclerView.setAdapter(nearbyFilterSearchRecyclerViewAdapter);
|
||||
LayoutUtils.setLayoutHeightAllignedToWidth(1, nearbyFilterList);
|
||||
LayoutUtils.setLayoutHeightAllignedToWidth(1.25, nearbyFilterList);
|
||||
|
||||
compositeDisposable.add(RxSearchView.queryTextChanges(searchView)
|
||||
.takeUntil(RxView.detaches(searchView))
|
||||
|
|
@ -821,7 +865,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
* @param place is new center of the map
|
||||
*/
|
||||
@Override
|
||||
public void centerMapToPlace(final Place place) {
|
||||
public void centerMapToPlace(@Nullable final Place place) {
|
||||
Timber.d("Map is centered to place");
|
||||
final double cameraShift;
|
||||
if(null!=place){
|
||||
|
|
@ -846,6 +890,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateListFragment(final List<Place> placeList) {
|
||||
places = placeList;
|
||||
|
|
@ -879,6 +924,32 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
latLngBounds = mapBox.getProjection().getVisibleRegion().latLngBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdvancedQueryFragmentVisible() {
|
||||
return isAdvancedQueryFragmentVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showHideAdvancedQueryFragment(final boolean shouldShow) {
|
||||
setHasOptionsMenu(!shouldShow);
|
||||
flConainerNearbyChildren.setVisibility(shouldShow ? View.VISIBLE : View.GONE);
|
||||
isAdvancedQueryFragmentVisible = shouldShow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void centerMapToPosition(fr.free.nrw.commons.location.LatLng searchLatLng) {
|
||||
final CameraPosition cameraPosition = mapBox.getCameraPosition();
|
||||
if (null != searchLatLng && !(
|
||||
cameraPosition.target.getLatitude() == searchLatLng.getLatitude()
|
||||
&& cameraPosition.target.getLongitude() == searchLatLng.getLongitude())) {
|
||||
final CameraPosition position = new CameraPosition.Builder()
|
||||
.target(LocationUtils.commonsLatLngToMapBoxLatLng(searchLatLng))
|
||||
.zoom(ZOOM_LEVEL) // Same zoom level
|
||||
.build();
|
||||
mapBox.setCameraPosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkConnectionEstablished() {
|
||||
return NetworkUtils.isInternetConnectionEstablished(getActivity());
|
||||
|
|
@ -933,29 +1004,53 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
@Override
|
||||
public void populatePlaces(final fr.free.nrw.commons.location.LatLng curlatLng) {
|
||||
if (curlatLng.equals(lastFocusLocation) || lastFocusLocation == null || recenterToUserLocation) { // Means we are checking around current location
|
||||
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng);
|
||||
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng, null);
|
||||
} else {
|
||||
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng);
|
||||
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng, null);
|
||||
}
|
||||
if(recenterToUserLocation) {
|
||||
recenterToUserLocation = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void populatePlacesForCurrentLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
|
||||
final fr.free.nrw.commons.location.LatLng searchLatLng){
|
||||
@Override
|
||||
public void populatePlaces(final fr.free.nrw.commons.location.LatLng curlatLng,
|
||||
@Nullable final String customQuery) {
|
||||
if (customQuery == null || customQuery.isEmpty()) {
|
||||
populatePlaces(curlatLng);
|
||||
return;
|
||||
}
|
||||
|
||||
if (curlatLng.equals(lastFocusLocation) || lastFocusLocation == null
|
||||
|| recenterToUserLocation) { // Means we are checking around current location
|
||||
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng, customQuery);
|
||||
} else {
|
||||
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng, customQuery);
|
||||
}
|
||||
if (recenterToUserLocation) {
|
||||
recenterToUserLocation = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void populatePlacesForCurrentLocation(
|
||||
final fr.free.nrw.commons.location.LatLng curlatLng,
|
||||
final fr.free.nrw.commons.location.LatLng searchLatLng, @Nullable final String customQuery){
|
||||
|
||||
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||
false, true, Utils.isMonumentsEnabled(new Date())));
|
||||
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||
|
||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(nearbyPlacesInfo -> {
|
||||
if (nearbyPlacesInfo.placeList == null || nearbyPlacesInfo.placeList.isEmpty()) {
|
||||
showErrorMessage(getString(R.string.no_nearby_places_around));
|
||||
} else {
|
||||
updateMapMarkers(nearbyPlacesInfo, true);
|
||||
lastFocusLocation = searchLatLng;
|
||||
}
|
||||
},
|
||||
throwable -> {
|
||||
Timber.d(throwable);
|
||||
|
|
@ -966,20 +1061,24 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
}));
|
||||
}
|
||||
|
||||
private void populatePlacesForAnotherLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
|
||||
final fr.free.nrw.commons.location.LatLng searchLatLng){
|
||||
|
||||
private void populatePlacesForAnotherLocation(
|
||||
final fr.free.nrw.commons.location.LatLng curlatLng,
|
||||
final fr.free.nrw.commons.location.LatLng searchLatLng, @Nullable final String customQuery){
|
||||
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||
.fromCallable(() -> nearbyController
|
||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||
false, true, Utils.isMonumentsEnabled(new Date())));
|
||||
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||
|
||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(nearbyPlacesInfo -> {
|
||||
if (nearbyPlacesInfo.placeList == null || nearbyPlacesInfo.placeList.isEmpty()) {
|
||||
showErrorMessage(getString(R.string.no_nearby_places_around));
|
||||
} else {
|
||||
updateMapMarkers(nearbyPlacesInfo, false);
|
||||
lastFocusLocation = searchLatLng;
|
||||
}
|
||||
},
|
||||
throwable -> {
|
||||
Timber.e(throwable);
|
||||
|
|
@ -1617,10 +1716,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
if (!fabPlus.isShown()) {
|
||||
showFABs();
|
||||
}
|
||||
getView().requestFocus();
|
||||
break;
|
||||
case (BottomSheetBehavior.STATE_EXPANDED):
|
||||
getView().requestFocus();
|
||||
break;
|
||||
case (BottomSheetBehavior.STATE_HIDDEN):
|
||||
if (null != mapBox) {
|
||||
|
|
@ -1630,9 +1725,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
|||
transparentView.setAlpha(0);
|
||||
collapseFABs(isFABsExpanded);
|
||||
hideFABs();
|
||||
if (getView() != null) {
|
||||
getView().requestFocus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ package fr.free.nrw.commons.nearby.presenter;
|
|||
import android.view.View;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||
|
||||
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -12,7 +14,6 @@ import java.util.List;
|
|||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||
import fr.free.nrw.commons.location.LocationUpdateListener;
|
||||
import fr.free.nrw.commons.nearby.CheckBoxTriStates;
|
||||
import fr.free.nrw.commons.nearby.Label;
|
||||
|
|
@ -25,6 +26,7 @@ import fr.free.nrw.commons.utils.LocationUtils;
|
|||
import fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.CUSTOM_QUERY;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
||||
|
|
@ -46,6 +48,8 @@ public class NearbyParentFragmentPresenter
|
|||
|
||||
BookmarkLocationsDao bookmarkLocationDao;
|
||||
|
||||
private @Nullable String customQuery;
|
||||
|
||||
private static final NearbyParentFragmentContract.View DUMMY = (NearbyParentFragmentContract.View) Proxy.newProxyInstance(
|
||||
NearbyParentFragmentContract.View.class.getClassLoader(),
|
||||
new Class[]{NearbyParentFragmentContract.View.class}, (proxy, method, args) -> {
|
||||
|
|
@ -118,7 +122,11 @@ public class NearbyParentFragmentPresenter
|
|||
|
||||
@Override
|
||||
public boolean backButtonClicked() {
|
||||
if(nearbyParentFragmentView.isListBottomSheetExpanded()) {
|
||||
if (nearbyParentFragmentView.isAdvancedQueryFragmentVisible()) {
|
||||
nearbyParentFragmentView.showHideAdvancedQueryFragment(false);
|
||||
return true;
|
||||
}
|
||||
else if(nearbyParentFragmentView.isListBottomSheetExpanded()) {
|
||||
// Back should first hide the bottom sheet if it is expanded
|
||||
nearbyParentFragmentView.listOptionMenuItemClicked();
|
||||
return true;
|
||||
|
|
@ -160,7 +168,7 @@ public class NearbyParentFragmentPresenter
|
|||
* @param locationChangeType defines if location changed significantly or slightly
|
||||
*/
|
||||
@Override
|
||||
public void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType) {
|
||||
public void updateMapAndList(LocationChangeType locationChangeType) {
|
||||
Timber.d("Presenter updates map and list");
|
||||
if (isNearbyLocked) {
|
||||
Timber.d("Nearby is locked, so updateMapAndList returns");
|
||||
|
|
@ -184,7 +192,17 @@ public class NearbyParentFragmentPresenter
|
|||
* Significant changed - Markers and current location will be updated together
|
||||
* Slightly changed - Only current position marker will be updated
|
||||
*/
|
||||
if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED)
|
||||
if(locationChangeType.equals(CUSTOM_QUERY)){
|
||||
Timber.d("ADVANCED_QUERY_SEARCH");
|
||||
lockUnlockNearby(true);
|
||||
nearbyParentFragmentView.setProgressBarVisibility(true);
|
||||
LatLng updatedLocationByUser = deriveUpdatedLocationFromSearchQuery(customQuery);
|
||||
if (updatedLocationByUser == null) {
|
||||
updatedLocationByUser = lastLocation;
|
||||
}
|
||||
nearbyParentFragmentView.populatePlaces(updatedLocationByUser, customQuery);
|
||||
}
|
||||
else if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED)
|
||||
|| locationChangeType.equals(MAP_UPDATED)) {
|
||||
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED");
|
||||
lockUnlockNearby(true);
|
||||
|
|
@ -204,6 +222,38 @@ public class NearbyParentFragmentPresenter
|
|||
}
|
||||
}
|
||||
|
||||
private LatLng deriveUpdatedLocationFromSearchQuery(String customQuery) {
|
||||
LatLng latLng = null;
|
||||
final int indexOfPrefix = customQuery.indexOf("Point(");
|
||||
if (indexOfPrefix == -1) {
|
||||
Timber.e("Invalid prefix index - Seems like user has entered an invalid query");
|
||||
return latLng;
|
||||
}
|
||||
final int indexOfSuffix = customQuery.indexOf(")\"", indexOfPrefix);
|
||||
if (indexOfSuffix == -1) {
|
||||
Timber.e("Invalid suffix index - Seems like user has entered an invalid query");
|
||||
return latLng;
|
||||
}
|
||||
String latLngString = customQuery.substring(indexOfPrefix+"Point(".length(), indexOfSuffix);
|
||||
if (latLngString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String latLngArray[] = latLngString.split(" ");
|
||||
if (latLngArray.length != 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
latLng = new LatLng(Double.parseDouble(latLngArray[1].trim()),
|
||||
Double.parseDouble(latLngArray[0].trim()), 1f);
|
||||
}catch (Exception e){
|
||||
Timber.e("Error while parsing user entered lat long: %s", e);
|
||||
}
|
||||
|
||||
return latLng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates places for custom location, should be used for finding nearby places around a
|
||||
* location where you are not at.
|
||||
|
|
@ -225,6 +275,7 @@ public class NearbyParentFragmentPresenter
|
|||
nearbyParentFragmentView.setProgressBarVisibility(false);
|
||||
nearbyParentFragmentView.updateListFragment(nearbyPlacesInfo.placeList);
|
||||
handleCenteringTaskIfAny();
|
||||
nearbyParentFragmentView.centerMapToPosition(nearbyPlacesInfo.searchLatLng);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +382,11 @@ public class NearbyParentFragmentPresenter
|
|||
nearbyParentFragmentView.setCheckBoxState(CheckBoxTriStates.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdvancedQuery(String query) {
|
||||
this.customQuery = query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void searchViewGainedFocus() {
|
||||
if(nearbyParentFragmentView.isListBottomSheetExpanded()) {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
|||
import io.reactivex.Flowable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Single;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
|
@ -288,7 +287,7 @@ public class UploadRepository {
|
|||
final List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
|
||||
decLatitude, decLongitude, 0.0f),
|
||||
Locale.getDefault().getLanguage(),
|
||||
NEARBY_RADIUS_IN_KILO_METERS, false);
|
||||
NEARBY_RADIUS_IN_KILO_METERS, false, null);
|
||||
return (fromWikidataQuery != null && fromWikidataQuery.size() > 0) ? fromWikidataQuery
|
||||
.get(0) : null;
|
||||
}catch (final Exception e) {
|
||||
|
|
|
|||
7
app/src/main/res/drawable/advanced_query_border.xml
Normal file
7
app/src/main/res/drawable/advanced_query_border.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/divider_grey" />
|
||||
</shape>
|
||||
54
app/src/main/res/layout/fragment_advance_query.xml
Normal file
54
app/src/main/res/layout/fragment_advance_query.xml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white"
|
||||
android:padding="10dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/tv_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/advanced_query_info_text"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
android:textStyle="bold"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/et_query"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/advanced_query_border"
|
||||
android:padding="5dp"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/btn_apply"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_apply"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/apply"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_reset"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset"
|
||||
android:textColor="@color/mapbox_blue"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@id/btn_apply" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -6,6 +6,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
@ -129,6 +132,11 @@
|
|||
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
||||
app:useCompatPadding="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_container_nearby_children"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<include layout="@layout/bottom_sheet_nearby" />
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:elevation="@dimen/activity_margin_horizontal"
|
||||
android:background="@color/white">
|
||||
|
||||
|
|
@ -26,6 +26,15 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="@dimen/dimen_10"
|
||||
android:paddingBottom="48dp"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btn_advanced_options"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/status_bar_blue"
|
||||
android:text="@string/advanced_options"
|
||||
android:textColor="@color/white"
|
||||
android:layout_marginTop="-48dp"
|
||||
android:layout_height="48dp"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -326,6 +326,7 @@
|
|||
<string name="share_app_title">Share App</string>
|
||||
|
||||
<string name="error_fetching_nearby_places">Error fetching nearby places.</string>
|
||||
<string name="no_nearby_places_around">No nearby places around</string>
|
||||
<string name="error_fetching_nearby_monuments">Error fetching nearby monuments.</string>
|
||||
<string name="no_recent_searches">No recent searches</string>
|
||||
<string name="delete_recent_searches_dialog">Are you sure you want to clear your search history?</string>
|
||||
|
|
@ -673,4 +674,8 @@ Upload your first media by tapping on the add button.</string>
|
|||
<string name="contributions_of_user">Contributions of User: %s</string>
|
||||
<string name="achievements_of_user">Achievements of User: %s</string>
|
||||
<string name="menu_view_user_page">View user page</string>
|
||||
<string name="advanced_options">Advanced Options</string>
|
||||
<string name="advanced_query_info_text">You can customize the Nearby query. If you get errors, reset and apply.</string>
|
||||
<string name="apply">Apply</string>
|
||||
<string name="reset">Reset</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
package fr.free.nrw.commons
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import fr.free.nrw.commons.explore.depictions.DepictsClient
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
||||
import okhttp3.Call
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.lang.Exception
|
||||
|
||||
class OkHttpJsonApiClientTests {
|
||||
@Mock
|
||||
lateinit var okhttpClient: OkHttpClient
|
||||
|
||||
@Mock
|
||||
lateinit var depictsClient: DepictsClient
|
||||
|
||||
@Mock
|
||||
lateinit var wikiMediaToolforgeUrl: HttpUrl
|
||||
|
||||
@Mock
|
||||
lateinit var wikiMediaTestToolforgeUrl: HttpUrl
|
||||
var sparqlQueryUrl: String = "https://www.testqparql.com"
|
||||
var campaignsUrl: String = "https://www.testcampaignsurl.com"
|
||||
|
||||
@Mock
|
||||
lateinit var gson: Gson
|
||||
|
||||
@Mock
|
||||
lateinit var latLng: LatLng
|
||||
private lateinit var okHttpJsonApiClient: OkHttpJsonApiClient
|
||||
|
||||
@Mock
|
||||
lateinit var call: Call
|
||||
|
||||
@Mock
|
||||
lateinit var response: Response
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
okHttpJsonApiClient = OkHttpJsonApiClient(
|
||||
okhttpClient,
|
||||
depictsClient,
|
||||
wikiMediaToolforgeUrl,
|
||||
wikiMediaTestToolforgeUrl,
|
||||
sparqlQueryUrl,
|
||||
campaignsUrl,
|
||||
gson
|
||||
)
|
||||
Mockito.`when`(okhttpClient.newCall(any())).thenReturn(call)
|
||||
Mockito.`when`(call.execute()).thenReturn(response)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetNearbyPlacesCustomQuery() {
|
||||
Mockito.`when`(response.message()).thenReturn("test")
|
||||
try {
|
||||
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true, "test")
|
||||
} catch (e: Exception) {
|
||||
assert(e.message.equals("test"))
|
||||
}
|
||||
verify(okhttpClient).newCall(any())
|
||||
verify(call).execute()
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetNearbyPlaces() {
|
||||
Mockito.`when`(response.message()).thenReturn("test")
|
||||
try {
|
||||
okHttpJsonApiClient.getNearbyPlaces(latLng, "test", 10.0, true)
|
||||
} catch (e: Exception) {
|
||||
assert(e.message.equals("test"))
|
||||
}
|
||||
verify(okhttpClient).newCall(any())
|
||||
verify(call).execute()
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package fr.free.nrw.commons.nearby
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.TestAppAdapter
|
||||
import fr.free.nrw.commons.TestCommonsApplication
|
||||
import fr.free.nrw.commons.contributions.MainActivity
|
||||
import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.Shadows
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.LooperMode
|
||||
import org.wikipedia.AppAdapter
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||
@LooperMode(LooperMode.Mode.PAUSED)
|
||||
class AdvanceQueryFragmentUnitTests {
|
||||
private lateinit var context: Context
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var fragment: AdvanceQueryFragment
|
||||
|
||||
private lateinit var viewGroup: ViewGroup
|
||||
|
||||
@Mock
|
||||
private lateinit var layoutInflater: LayoutInflater
|
||||
|
||||
@Mock
|
||||
private lateinit var callback: AdvanceQueryFragment.Callback
|
||||
|
||||
@Mock
|
||||
private lateinit var view: View
|
||||
|
||||
@Mock
|
||||
private lateinit var etQuery: AppCompatEditText
|
||||
|
||||
@Mock
|
||||
private lateinit var btnReset: AppCompatButton
|
||||
|
||||
@Mock
|
||||
private lateinit var btnApply: AppCompatButton
|
||||
|
||||
@Mock
|
||||
private lateinit var bundle: Bundle
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
|
||||
AppAdapter.set(TestAppAdapter())
|
||||
context = RuntimeEnvironment.application.applicationContext
|
||||
activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
|
||||
viewGroup = FrameLayout(context)
|
||||
|
||||
Mockito.`when`(bundle.getString("query")).thenReturn("test")
|
||||
|
||||
fragment = AdvanceQueryFragment()
|
||||
fragment.callback = callback
|
||||
fragment.arguments = bundle
|
||||
|
||||
val fragmentManager: FragmentManager = activity.supportFragmentManager
|
||||
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
|
||||
fragmentTransaction.add(fragment, null)
|
||||
fragmentTransaction.commit()
|
||||
|
||||
Mockito.`when`(layoutInflater.inflate(R.layout.fragment_advance_query, viewGroup, false))
|
||||
.thenReturn(view)
|
||||
Mockito.`when`(view.findViewById<AppCompatEditText>(R.id.et_query)).thenReturn(etQuery)
|
||||
Mockito.`when`(view.findViewById<AppCompatButton>(R.id.btn_apply)).thenReturn(btnApply)
|
||||
Mockito.`when`(view.findViewById<AppCompatButton>(R.id.btn_reset)).thenReturn(btnReset)
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun checkFragmentNotNull() {
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
Assert.assertNotNull(fragment)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnCreateView() {
|
||||
Shadows.shadowOf(Looper.getMainLooper()).idle()
|
||||
fragment.onCreateView(layoutInflater, viewGroup, bundle)
|
||||
verify(layoutInflater).inflate(R.layout.fragment_advance_query, viewGroup, false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnViewCreated() {
|
||||
fragment.onCreateView(layoutInflater, viewGroup, bundle)
|
||||
fragment.onViewCreated(view, bundle)
|
||||
verify(etQuery).setText("test")
|
||||
|
||||
Mockito.`when`(btnReset.post(any())).thenAnswer {
|
||||
it.getArgument(0, Runnable::class.java).run()
|
||||
}
|
||||
|
||||
Mockito.`when`(btnApply.post(any())).thenAnswer {
|
||||
it.getArgument(0, Runnable::class.java).run()
|
||||
}
|
||||
btnReset.performClick()
|
||||
btnApply.performClick()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHideKeyboard() {
|
||||
fragment.hideKeyBoard()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
package fr.free.nrw.commons.nearby
|
||||
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.anyOrNull
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.*
|
||||
|
||||
class NearbyControllerTest {
|
||||
@Mock
|
||||
private lateinit var nearbyPlaces: NearbyPlaces
|
||||
|
||||
@Mock
|
||||
lateinit var searchLatLong: LatLng
|
||||
|
||||
@Mock
|
||||
lateinit var currentLatLng: LatLng
|
||||
var customQuery: String = "test"
|
||||
private lateinit var nearbyController: NearbyController
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
nearbyController = NearbyController(nearbyPlaces)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoadAttractionsForLocationTest() {
|
||||
Mockito.`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), any()))
|
||||
.thenReturn(Collections.emptyList())
|
||||
nearbyController.loadAttractionsFromLocation(
|
||||
searchLatLong,
|
||||
currentLatLng,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
customQuery
|
||||
)
|
||||
Mockito.verify(nearbyPlaces).radiusExpander(
|
||||
eq(currentLatLng),
|
||||
any(String::class.java),
|
||||
eq(false),
|
||||
eq(true),
|
||||
eq(customQuery)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoadAttractionsForLocationTestNoQuery() {
|
||||
Mockito.`when`(nearbyPlaces.radiusExpander(any(), any(), any(), any(), anyOrNull()))
|
||||
.thenReturn(Collections.emptyList())
|
||||
nearbyController.loadAttractionsFromLocation(
|
||||
searchLatLong,
|
||||
currentLatLng,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
)
|
||||
Mockito.verify(nearbyPlaces).radiusExpander(
|
||||
eq(currentLatLng),
|
||||
any(String::class.java),
|
||||
eq(false),
|
||||
eq(true),
|
||||
eq(null)
|
||||
)
|
||||
}
|
||||
|
||||
fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import org.mockito.ArgumentMatchers
|
|||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.MockitoAnnotations
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* The unit test class for NearbyParentFragmentPresenter
|
||||
|
|
@ -32,6 +33,8 @@ class NearbyParentFragmentPresenterTest {
|
|||
internal lateinit var selectedLabels: List<Label>
|
||||
@Mock
|
||||
internal lateinit var marker: Marker
|
||||
@Mock
|
||||
internal lateinit var nearbyPlaces: NearbyPlaces
|
||||
|
||||
private lateinit var nearbyPresenter: NearbyParentFragmentPresenter
|
||||
private lateinit var mapboxCameraTarget: com.mapbox.mapboxsdk.geometry.LatLng
|
||||
|
|
@ -392,6 +395,14 @@ class NearbyParentFragmentPresenterTest {
|
|||
assertFalse(hasNearbyHandledBackPress)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBackButtonClickedWhenAdvancedFragmentIsVisible() {
|
||||
whenever(nearbyParentFragmentView.isAdvancedQueryFragmentVisible()).thenReturn(true)
|
||||
val hasNearbyHandledBackPress = nearbyPresenter.backButtonClicked()
|
||||
verify(nearbyParentFragmentView).showHideAdvancedQueryFragment(false)
|
||||
assertTrue(hasNearbyHandledBackPress)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMarkerUnselected() {
|
||||
nearbyPresenter.markerUnselected()
|
||||
|
|
@ -429,6 +440,50 @@ class NearbyParentFragmentPresenterTest {
|
|||
verify(nearbyParentFragmentView).recenterMap(latestLocation)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnLocationChangeTypeCustomQuery() {
|
||||
nearbyPresenter.setAdvancedQuery("Point(17.865 82.343)\"")
|
||||
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished()).thenReturn(true)
|
||||
whenever(nearbyParentFragmentView.getLastLocation()).thenReturn(latestLocation)
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
verify(nearbyParentFragmentView).setProgressBarVisibility(true)
|
||||
verify(nearbyParentFragmentView).populatePlaces(any(), any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnLocationChangeTypeCustomQueryInvalidQuery() {
|
||||
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished).thenReturn(true)
|
||||
whenever(nearbyParentFragmentView.lastLocation).thenReturn(latestLocation)
|
||||
nearbyPresenter.setAdvancedQuery("")
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
nearbyPresenter.setAdvancedQuery("Point(")
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnLocationChangeTypeCustomQueryUnParsableQuery() {
|
||||
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished).thenReturn(true)
|
||||
whenever(nearbyParentFragmentView.lastLocation).thenReturn(latestLocation)
|
||||
nearbyPresenter.setAdvancedQuery("Point()\"")
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
|
||||
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished).thenReturn(true)
|
||||
whenever(nearbyParentFragmentView.lastLocation).thenReturn(latestLocation)
|
||||
nearbyPresenter.setAdvancedQuery("Point(ab)\"")
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
|
||||
whenever(nearbyParentFragmentView.isNetworkConnectionEstablished).thenReturn(true)
|
||||
whenever(nearbyParentFragmentView.lastLocation).thenReturn(latestLocation)
|
||||
nearbyPresenter.setAdvancedQuery("Point(ab ab)\"")
|
||||
nearbyPresenter.updateMapAndList(LocationChangeType.CUSTOM_QUERY)
|
||||
expectMapAndListUpdate()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnCameraMoveWhenSearchLocationNull() {
|
||||
NearbyController.latestSearchLocation = null
|
||||
|
|
@ -456,4 +511,27 @@ class NearbyParentFragmentPresenterTest {
|
|||
verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
|
||||
verifyZeroInteractions(nearbyParentFragmentView)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSetAdvancedQuery(){
|
||||
nearbyPresenter.setAdvancedQuery("test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateMapMarkers(){
|
||||
var nearbyPlacesInfo = NearbyController(nearbyPlaces).NearbyPlacesInfo()
|
||||
nearbyPlacesInfo.boundaryCoordinates= arrayOf()
|
||||
nearbyPlacesInfo.curLatLng=latestLocation
|
||||
nearbyPlacesInfo.searchLatLng=latestLocation
|
||||
nearbyPlacesInfo.placeList = null
|
||||
|
||||
whenever(bookmarkLocationsDao.allBookmarksLocations).thenReturn(Collections.emptyList())
|
||||
nearbyPresenter.updateMapMarkers(nearbyPlacesInfo, marker, true)
|
||||
Mockito.verify(nearbyParentFragmentView).updateMapMarkers(any(), eq(marker))
|
||||
Mockito.verify(nearbyParentFragmentView).addCurrentLocationMarker(latestLocation)
|
||||
Mockito.verify(nearbyParentFragmentView).updateMapToTrackPosition(latestLocation)
|
||||
Mockito.verify(nearbyParentFragmentView).setProgressBarVisibility(false)
|
||||
Mockito.verify(nearbyParentFragmentView).centerMapToPosition(latestLocation)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package fr.free.nrw.commons.nearby
|
||||
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import fr.free.nrw.commons.location.LatLng
|
||||
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
class NearbyPlacesTest {
|
||||
@Mock
|
||||
private lateinit var okHttpJsonApiClient: OkHttpJsonApiClient
|
||||
|
||||
@Mock
|
||||
private lateinit var currentLatLong: LatLng
|
||||
|
||||
private lateinit var nearbyPlaces: NearbyPlaces
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
nearbyPlaces = NearbyPlaces(okHttpJsonApiClient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRadiusExpander() {
|
||||
nearbyPlaces.radiusExpander(currentLatLong, "test", true, true, "test")
|
||||
verify(okHttpJsonApiClient, times(5)).getNearbyPlaces(
|
||||
eq(currentLatLong),
|
||||
eq("test"),
|
||||
any(),
|
||||
eq(true),
|
||||
eq("test")
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue