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,
|
LOCATION_NOT_CHANGED,
|
||||||
PERMISSION_JUST_GRANTED,
|
PERMISSION_JUST_GRANTED,
|
||||||
MAP_UPDATED,
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
import fr.free.nrw.commons.campaigns.CampaignResponseDTO;
|
||||||
import fr.free.nrw.commons.explore.depictions.DepictsClient;
|
import fr.free.nrw.commons.explore.depictions.DepictsClient;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
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
|
@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 boolean shouldQueryForMonuments, 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);
|
||||||
|
Timber.d("CUSTOM_SPARQL%s", String.valueOf(customQuery != null));
|
||||||
final String wikidataQuery;
|
final String wikidataQuery;
|
||||||
if (!shouldQueryForMonuments) {
|
if (customQuery != null) {
|
||||||
|
wikidataQuery = customQuery;
|
||||||
|
} else if (!shouldQueryForMonuments) {
|
||||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
|
||||||
} else {
|
} else {
|
||||||
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
|
wikidataQuery = FileUtils.readFromResource("/queries/nearby_query_monuments.rq");
|
||||||
|
|
@ -313,6 +327,23 @@ public class OkHttpJsonApiClient {
|
||||||
throw new Exception(response.message());
|
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:
|
* Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example:
|
||||||
* bridge -> suspended bridge, aqueduct, etc
|
* bridge -> suspended bridge, aqueduct, etc
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import androidx.annotation.MainThread;
|
import androidx.annotation.MainThread;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||||
|
|
||||||
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
import com.mapbox.mapboxsdk.annotations.IconFactory;
|
||||||
|
|
@ -54,12 +55,13 @@ public class NearbyController {
|
||||||
* @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
|
||||||
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
* @return NearbyPlacesInfo a variable holds Place list without distance information
|
||||||
* and boundary coordinates of current Place List
|
* and boundary coordinates of current Place List
|
||||||
*/
|
*/
|
||||||
public NearbyPlacesInfo loadAttractionsFromLocation(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) throws Exception {
|
final boolean shouldQueryForMonuments, @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();
|
||||||
|
|
@ -70,7 +72,7 @@ public class NearbyController {
|
||||||
}
|
}
|
||||||
List<Place> places = nearbyPlaces
|
List<Place> places = nearbyPlaces
|
||||||
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
.radiusExpander(searchLatLng, Locale.getDefault().getLanguage(), returnClosestResult,
|
||||||
shouldQueryForMonuments);
|
shouldQueryForMonuments, 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, // south
|
||||||
|
|
@ -128,10 +130,27 @@ public class NearbyController {
|
||||||
return nearbyPlacesInfo;
|
return nearbyPlacesInfo;
|
||||||
}
|
}
|
||||||
else {
|
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.
|
* Loads attractions from location for list view, we need to return Place data type.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package fr.free.nrw.commons.nearby;
|
package fr.free.nrw.commons.nearby;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -38,10 +39,12 @@ public class NearbyPlaces {
|
||||||
* @param curLatLng coordinates of search location
|
* @param curLatLng coordinates of search location
|
||||||
* @param lang user's language
|
* @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
|
||||||
* @return list of places obtained
|
* @return list of places obtained
|
||||||
*/
|
*/
|
||||||
List<Place> radiusExpander(final LatLng curLatLng, final String lang, final boolean returnClosestResult
|
List<Place> radiusExpander(final LatLng curLatLng, final String lang,
|
||||||
, final boolean shouldQueryForMonuments) throws Exception {
|
final boolean returnClosestResult
|
||||||
|
, final boolean shouldQueryForMonuments, @Nullable final String customQuery) throws Exception {
|
||||||
|
|
||||||
final int minResults;
|
final int minResults;
|
||||||
final double maxRadius;
|
final double maxRadius;
|
||||||
|
|
@ -62,13 +65,12 @@ public class NearbyPlaces {
|
||||||
|
|
||||||
// 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);
|
places = getFromWikidataQuery(curLatLng, lang, radius, shouldQueryForMonuments, 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;
|
||||||
} else {
|
|
||||||
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) {
|
||||||
|
|
@ -83,11 +85,14 @@ public class NearbyPlaces {
|
||||||
* @param lang user's language
|
* @param lang user's language
|
||||||
* @param radius radius for search, as determined by radiusExpander()
|
* @param radius radius for search, as determined by radiusExpander()
|
||||||
* @param shouldQueryForMonuments should the query include properites for monuments
|
* @param shouldQueryForMonuments should the query include properites for monuments
|
||||||
|
* @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) throws Exception {
|
final double radius, final boolean shouldQueryForMonuments,
|
||||||
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius, 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 android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
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.Label;
|
||||||
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
|
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
|
|
@ -19,6 +20,7 @@ public interface NearbyParentFragmentContract {
|
||||||
boolean isNetworkConnectionEstablished();
|
boolean isNetworkConnectionEstablished();
|
||||||
void listOptionMenuItemClicked();
|
void listOptionMenuItemClicked();
|
||||||
void populatePlaces(LatLng curlatLng);
|
void populatePlaces(LatLng curlatLng);
|
||||||
|
void populatePlaces(LatLng curlatLng, String customQuery);
|
||||||
boolean isListBottomSheetExpanded();
|
boolean isListBottomSheetExpanded();
|
||||||
void checkPermissionsAndPerformAction();
|
void checkPermissionsAndPerformAction();
|
||||||
void displayLoginSkippedWarning();
|
void displayLoginSkippedWarning();
|
||||||
|
|
@ -62,7 +64,7 @@ public interface NearbyParentFragmentContract {
|
||||||
|
|
||||||
LatLng getCameraTarget();
|
LatLng getCameraTarget();
|
||||||
|
|
||||||
void centerMapToPlace(Place placeToCenter);
|
void centerMapToPlace(@Nullable Place placeToCenter);
|
||||||
|
|
||||||
void updateListFragment(List<Place> placeList);
|
void updateListFragment(List<Place> placeList);
|
||||||
|
|
||||||
|
|
@ -72,6 +74,12 @@ public interface NearbyParentFragmentContract {
|
||||||
|
|
||||||
boolean isCurrentLocationMarkerVisible();
|
boolean isCurrentLocationMarkerVisible();
|
||||||
void setProjectorLatLngBounds();
|
void setProjectorLatLngBounds();
|
||||||
|
|
||||||
|
boolean isAdvancedQueryFragmentVisible();
|
||||||
|
|
||||||
|
void showHideAdvancedQueryFragment(boolean shouldShow);
|
||||||
|
|
||||||
|
void centerMapToPosition(@Nullable LatLng searchLatLng);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NearbyListView {
|
interface NearbyListView {
|
||||||
|
|
@ -79,7 +87,7 @@ public interface NearbyParentFragmentContract {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UserActions {
|
interface UserActions {
|
||||||
void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType);
|
void updateMapAndList(LocationChangeType locationChangeType);
|
||||||
void lockUnlockNearby(boolean isNearbyLocked);
|
void lockUnlockNearby(boolean isNearbyLocked);
|
||||||
|
|
||||||
void attachView(View view);
|
void attachView(View view);
|
||||||
|
|
@ -96,5 +104,7 @@ public interface NearbyParentFragmentContract {
|
||||||
|
|
||||||
void searchViewGainedFocus();
|
void searchViewGainedFocus();
|
||||||
void setCheckboxUnknown();
|
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;
|
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_SIGNIFICANTLY_CHANGED;
|
||||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
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.Animation;
|
||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
@ -44,6 +46,7 @@ import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
import androidx.appcompat.widget.AppCompatImageView;
|
||||||
import androidx.appcompat.widget.SearchView;
|
import androidx.appcompat.widget.SearchView;
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
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.NearbyMarker;
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
import fr.free.nrw.commons.nearby.Place;
|
||||||
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
|
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.nearby.presenter.NearbyParentFragmentPresenter;
|
||||||
|
import fr.free.nrw.commons.upload.FileUtils;
|
||||||
import fr.free.nrw.commons.utils.DialogUtil;
|
import fr.free.nrw.commons.utils.DialogUtil;
|
||||||
import fr.free.nrw.commons.utils.ExecutorUtils;
|
import fr.free.nrw.commons.utils.ExecutorUtils;
|
||||||
import fr.free.nrw.commons.utils.LayoutUtils;
|
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 fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.functions.Function;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
@ -180,6 +183,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
AppCompatImageView ivToggleChips;
|
AppCompatImageView ivToggleChips;
|
||||||
@BindView(R.id.chip_view)
|
@BindView(R.id.chip_view)
|
||||||
View llContainerChips;
|
View llContainerChips;
|
||||||
|
@BindView(R.id.btn_advanced_options)
|
||||||
|
AppCompatButton btnAdvancedOptions;
|
||||||
|
@BindView(R.id.fl_container_nearby_children)
|
||||||
|
FrameLayout flConainerNearbyChildren;
|
||||||
|
|
||||||
@Inject LocationServiceManager locationManager;
|
@Inject LocationServiceManager locationManager;
|
||||||
@Inject NearbyController nearbyController;
|
@Inject NearbyController nearbyController;
|
||||||
|
|
@ -233,6 +240,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
private LatLngBounds latLngBounds;
|
private LatLngBounds latLngBounds;
|
||||||
private PlaceAdapter adapter;
|
private PlaceAdapter adapter;
|
||||||
private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback;
|
private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback;
|
||||||
|
private boolean isAdvancedQueryFragmentVisible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds filtered markers that are to be shown
|
* 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.setText(Html.fromHtml(getString(R.string.map_attribution)));
|
||||||
tvAttribution.setMovementMethod(LinkMovementMethod.getInstance());
|
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);
|
nearbyFilterList.getLayoutParams().width = (int) LayoutUtils.getScreenWidth(getActivity(), 0.75);
|
||||||
recyclerView.setAdapter(nearbyFilterSearchRecyclerViewAdapter);
|
recyclerView.setAdapter(nearbyFilterSearchRecyclerViewAdapter);
|
||||||
LayoutUtils.setLayoutHeightAllignedToWidth(1, nearbyFilterList);
|
LayoutUtils.setLayoutHeightAllignedToWidth(1.25, nearbyFilterList);
|
||||||
|
|
||||||
compositeDisposable.add(RxSearchView.queryTextChanges(searchView)
|
compositeDisposable.add(RxSearchView.queryTextChanges(searchView)
|
||||||
.takeUntil(RxView.detaches(searchView))
|
.takeUntil(RxView.detaches(searchView))
|
||||||
|
|
@ -821,7 +865,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
* @param place is new center of the map
|
* @param place is new center of the map
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void centerMapToPlace(final Place place) {
|
public void centerMapToPlace(@Nullable final Place place) {
|
||||||
Timber.d("Map is centered to place");
|
Timber.d("Map is centered to place");
|
||||||
final double cameraShift;
|
final double cameraShift;
|
||||||
if(null!=place){
|
if(null!=place){
|
||||||
|
|
@ -846,6 +890,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateListFragment(final List<Place> placeList) {
|
public void updateListFragment(final List<Place> placeList) {
|
||||||
places = placeList;
|
places = placeList;
|
||||||
|
|
@ -879,6 +924,32 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
latLngBounds = mapBox.getProjection().getVisibleRegion().latLngBounds;
|
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
|
@Override
|
||||||
public boolean isNetworkConnectionEstablished() {
|
public boolean isNetworkConnectionEstablished() {
|
||||||
return NetworkUtils.isInternetConnectionEstablished(getActivity());
|
return NetworkUtils.isInternetConnectionEstablished(getActivity());
|
||||||
|
|
@ -933,29 +1004,53 @@ 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(lastFocusLocation) || lastFocusLocation == null || recenterToUserLocation) { // Means we are checking around current location
|
if (curlatLng.equals(lastFocusLocation) || lastFocusLocation == null || recenterToUserLocation) { // Means we are checking around current location
|
||||||
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng);
|
populatePlacesForCurrentLocation(lastKnownLocation, curlatLng, null);
|
||||||
} else {
|
} else {
|
||||||
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng);
|
populatePlacesForAnotherLocation(lastKnownLocation, curlatLng, null);
|
||||||
}
|
}
|
||||||
if(recenterToUserLocation) {
|
if(recenterToUserLocation) {
|
||||||
recenterToUserLocation = false;
|
recenterToUserLocation = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populatePlacesForCurrentLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
|
@Override
|
||||||
final fr.free.nrw.commons.location.LatLng searchLatLng){
|
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
|
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||||
.fromCallable(() -> nearbyController
|
.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||||
false, true, Utils.isMonumentsEnabled(new Date())));
|
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||||
|
|
||||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(nearbyPlacesInfo -> {
|
.subscribe(nearbyPlacesInfo -> {
|
||||||
updateMapMarkers(nearbyPlacesInfo, true);
|
if (nearbyPlacesInfo.placeList == null || nearbyPlacesInfo.placeList.isEmpty()) {
|
||||||
lastFocusLocation=searchLatLng;
|
showErrorMessage(getString(R.string.no_nearby_places_around));
|
||||||
|
} else {
|
||||||
|
updateMapMarkers(nearbyPlacesInfo, true);
|
||||||
|
lastFocusLocation = searchLatLng;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
throwable -> {
|
throwable -> {
|
||||||
Timber.d(throwable);
|
Timber.d(throwable);
|
||||||
|
|
@ -966,20 +1061,24 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populatePlacesForAnotherLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
|
private void populatePlacesForAnotherLocation(
|
||||||
final fr.free.nrw.commons.location.LatLng searchLatLng){
|
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
|
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
|
||||||
.fromCallable(() -> nearbyController
|
.fromCallable(() -> nearbyController
|
||||||
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
.loadAttractionsFromLocation(curlatLng, searchLatLng,
|
||||||
false, true, Utils.isMonumentsEnabled(new Date())));
|
false, true, Utils.isMonumentsEnabled(new Date()), customQuery));
|
||||||
|
|
||||||
compositeDisposable.add(nearbyPlacesInfoObservable
|
compositeDisposable.add(nearbyPlacesInfoObservable
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(nearbyPlacesInfo -> {
|
.subscribe(nearbyPlacesInfo -> {
|
||||||
updateMapMarkers(nearbyPlacesInfo, false);
|
if (nearbyPlacesInfo.placeList == null || nearbyPlacesInfo.placeList.isEmpty()) {
|
||||||
lastFocusLocation=searchLatLng;
|
showErrorMessage(getString(R.string.no_nearby_places_around));
|
||||||
|
} else {
|
||||||
|
updateMapMarkers(nearbyPlacesInfo, false);
|
||||||
|
lastFocusLocation = searchLatLng;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
throwable -> {
|
throwable -> {
|
||||||
Timber.e(throwable);
|
Timber.e(throwable);
|
||||||
|
|
@ -1617,10 +1716,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
if (!fabPlus.isShown()) {
|
if (!fabPlus.isShown()) {
|
||||||
showFABs();
|
showFABs();
|
||||||
}
|
}
|
||||||
getView().requestFocus();
|
|
||||||
break;
|
|
||||||
case (BottomSheetBehavior.STATE_EXPANDED):
|
|
||||||
getView().requestFocus();
|
|
||||||
break;
|
break;
|
||||||
case (BottomSheetBehavior.STATE_HIDDEN):
|
case (BottomSheetBehavior.STATE_HIDDEN):
|
||||||
if (null != mapBox) {
|
if (null != mapBox) {
|
||||||
|
|
@ -1630,9 +1725,6 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
|
||||||
transparentView.setAlpha(0);
|
transparentView.setAlpha(0);
|
||||||
collapseFABs(isFABsExpanded);
|
collapseFABs(isFABsExpanded);
|
||||||
hideFABs();
|
hideFABs();
|
||||||
if (getView() != null) {
|
|
||||||
getView().requestFocus();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@ package fr.free.nrw.commons.nearby.presenter;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.MainThread;
|
import androidx.annotation.MainThread;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.mapbox.mapboxsdk.annotations.Marker;
|
import com.mapbox.mapboxsdk.annotations.Marker;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
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.bookmarks.locations.BookmarkLocationsDao;
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
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.location.LocationUpdateListener;
|
||||||
import fr.free.nrw.commons.nearby.CheckBoxTriStates;
|
import fr.free.nrw.commons.nearby.CheckBoxTriStates;
|
||||||
import fr.free.nrw.commons.nearby.Label;
|
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 fr.free.nrw.commons.wikidata.WikidataEditListener;
|
||||||
import timber.log.Timber;
|
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_SIGNIFICANTLY_CHANGED;
|
||||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
|
||||||
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
|
||||||
|
|
@ -46,6 +48,8 @@ public class NearbyParentFragmentPresenter
|
||||||
|
|
||||||
BookmarkLocationsDao bookmarkLocationDao;
|
BookmarkLocationsDao bookmarkLocationDao;
|
||||||
|
|
||||||
|
private @Nullable String customQuery;
|
||||||
|
|
||||||
private static final NearbyParentFragmentContract.View DUMMY = (NearbyParentFragmentContract.View) Proxy.newProxyInstance(
|
private static final NearbyParentFragmentContract.View DUMMY = (NearbyParentFragmentContract.View) Proxy.newProxyInstance(
|
||||||
NearbyParentFragmentContract.View.class.getClassLoader(),
|
NearbyParentFragmentContract.View.class.getClassLoader(),
|
||||||
new Class[]{NearbyParentFragmentContract.View.class}, (proxy, method, args) -> {
|
new Class[]{NearbyParentFragmentContract.View.class}, (proxy, method, args) -> {
|
||||||
|
|
@ -118,7 +122,11 @@ public class NearbyParentFragmentPresenter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean backButtonClicked() {
|
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
|
// Back should first hide the bottom sheet if it is expanded
|
||||||
nearbyParentFragmentView.listOptionMenuItemClicked();
|
nearbyParentFragmentView.listOptionMenuItemClicked();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -160,7 +168,7 @@ public class NearbyParentFragmentPresenter
|
||||||
* @param locationChangeType defines if location changed significantly or slightly
|
* @param locationChangeType defines if location changed significantly or slightly
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType) {
|
public void updateMapAndList(LocationChangeType locationChangeType) {
|
||||||
Timber.d("Presenter updates map and list");
|
Timber.d("Presenter updates map and list");
|
||||||
if (isNearbyLocked) {
|
if (isNearbyLocked) {
|
||||||
Timber.d("Nearby is locked, so updateMapAndList returns");
|
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
|
* Significant changed - Markers and current location will be updated together
|
||||||
* Slightly changed - Only current position marker will be updated
|
* 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)) {
|
|| locationChangeType.equals(MAP_UPDATED)) {
|
||||||
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED");
|
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED");
|
||||||
lockUnlockNearby(true);
|
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
|
* Populates places for custom location, should be used for finding nearby places around a
|
||||||
* location where you are not at.
|
* location where you are not at.
|
||||||
|
|
@ -225,6 +275,7 @@ public class NearbyParentFragmentPresenter
|
||||||
nearbyParentFragmentView.setProgressBarVisibility(false);
|
nearbyParentFragmentView.setProgressBarVisibility(false);
|
||||||
nearbyParentFragmentView.updateListFragment(nearbyPlacesInfo.placeList);
|
nearbyParentFragmentView.updateListFragment(nearbyPlacesInfo.placeList);
|
||||||
handleCenteringTaskIfAny();
|
handleCenteringTaskIfAny();
|
||||||
|
nearbyParentFragmentView.centerMapToPosition(nearbyPlacesInfo.searchLatLng);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,6 +382,11 @@ public class NearbyParentFragmentPresenter
|
||||||
nearbyParentFragmentView.setCheckBoxState(CheckBoxTriStates.UNKNOWN);
|
nearbyParentFragmentView.setCheckBoxState(CheckBoxTriStates.UNKNOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAdvancedQuery(String query) {
|
||||||
|
this.customQuery = query;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void searchViewGainedFocus() {
|
public void searchViewGainedFocus() {
|
||||||
if(nearbyParentFragmentView.isListBottomSheetExpanded()) {
|
if(nearbyParentFragmentView.isListBottomSheetExpanded()) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -288,7 +287,7 @@ public class UploadRepository {
|
||||||
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);
|
NEARBY_RADIUS_IN_KILO_METERS, false, 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) {
|
||||||
|
|
|
||||||
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_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|
@ -129,6 +132,11 @@
|
||||||
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
app:srcCompat="@drawable/ic_my_location_black_24dp"
|
||||||
app:useCompatPadding="true" />
|
app:useCompatPadding="true" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fl_container_nearby_children"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<include layout="@layout/bottom_sheet_nearby" />
|
<include layout="@layout/bottom_sheet_nearby" />
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:elevation="@dimen/activity_margin_horizontal"
|
android:elevation="@dimen/activity_margin_horizontal"
|
||||||
android:background="@color/white">
|
android:background="@color/white">
|
||||||
|
|
||||||
|
|
@ -26,6 +26,15 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginVertical="@dimen/dimen_10"
|
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>
|
</LinearLayout>
|
||||||
|
|
@ -326,6 +326,7 @@
|
||||||
<string name="share_app_title">Share App</string>
|
<string name="share_app_title">Share App</string>
|
||||||
|
|
||||||
<string name="error_fetching_nearby_places">Error fetching nearby places.</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="error_fetching_nearby_monuments">Error fetching nearby monuments.</string>
|
||||||
<string name="no_recent_searches">No recent searches</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>
|
<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="contributions_of_user">Contributions of User: %s</string>
|
||||||
<string name="achievements_of_user">Achievements 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="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>
|
</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.Mock
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unit test class for NearbyParentFragmentPresenter
|
* The unit test class for NearbyParentFragmentPresenter
|
||||||
|
|
@ -32,6 +33,8 @@ class NearbyParentFragmentPresenterTest {
|
||||||
internal lateinit var selectedLabels: List<Label>
|
internal lateinit var selectedLabels: List<Label>
|
||||||
@Mock
|
@Mock
|
||||||
internal lateinit var marker: Marker
|
internal lateinit var marker: Marker
|
||||||
|
@Mock
|
||||||
|
internal lateinit var nearbyPlaces: NearbyPlaces
|
||||||
|
|
||||||
private lateinit var nearbyPresenter: NearbyParentFragmentPresenter
|
private lateinit var nearbyPresenter: NearbyParentFragmentPresenter
|
||||||
private lateinit var mapboxCameraTarget: com.mapbox.mapboxsdk.geometry.LatLng
|
private lateinit var mapboxCameraTarget: com.mapbox.mapboxsdk.geometry.LatLng
|
||||||
|
|
@ -392,6 +395,14 @@ class NearbyParentFragmentPresenterTest {
|
||||||
assertFalse(hasNearbyHandledBackPress)
|
assertFalse(hasNearbyHandledBackPress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBackButtonClickedWhenAdvancedFragmentIsVisible() {
|
||||||
|
whenever(nearbyParentFragmentView.isAdvancedQueryFragmentVisible()).thenReturn(true)
|
||||||
|
val hasNearbyHandledBackPress = nearbyPresenter.backButtonClicked()
|
||||||
|
verify(nearbyParentFragmentView).showHideAdvancedQueryFragment(false)
|
||||||
|
assertTrue(hasNearbyHandledBackPress)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testMarkerUnselected() {
|
fun testMarkerUnselected() {
|
||||||
nearbyPresenter.markerUnselected()
|
nearbyPresenter.markerUnselected()
|
||||||
|
|
@ -429,6 +440,50 @@ class NearbyParentFragmentPresenterTest {
|
||||||
verify(nearbyParentFragmentView).recenterMap(latestLocation)
|
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
|
@Test
|
||||||
fun testOnCameraMoveWhenSearchLocationNull() {
|
fun testOnCameraMoveWhenSearchLocationNull() {
|
||||||
NearbyController.latestSearchLocation = null
|
NearbyController.latestSearchLocation = null
|
||||||
|
|
@ -456,4 +511,27 @@ class NearbyParentFragmentPresenterTest {
|
||||||
verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
|
verify(nearbyParentFragmentView).isNetworkConnectionEstablished()
|
||||||
verifyZeroInteractions(nearbyParentFragmentView)
|
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