Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit foci boundary enhancements #339

Merged
merged 12 commits into from
Jul 22, 2020
20 changes: 20 additions & 0 deletions library/src/main/java/io/ona/kujaku/interfaces/IKujakuMapView.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.ona.kujaku.listeners.BoundsChangeListener;
import io.ona.kujaku.listeners.LocationClientStartedCallback;
import io.ona.kujaku.listeners.OnFeatureClickListener;
import io.ona.kujaku.listeners.OnFeatureLongClickListener;
import io.ona.kujaku.listeners.TrackingServiceListener;
import io.ona.kujaku.location.KujakuLocation;
import io.ona.kujaku.services.configurations.TrackingServiceUIConfiguration;
Expand Down Expand Up @@ -188,6 +189,25 @@ public interface IKujakuMapView extends IKujakuMapViewLowLevel {
*/
void setOnFeatureClickListener(@NonNull OnFeatureClickListener onFeatureClickListener, @Nullable Expression expressionFilter, @Nullable String... layerIds);

/**
* Sets an {@link OnFeatureClickListener} which will be fired when a feature on the map in either of the {@code layerIds}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change documentation here to link to OnFeatureLongClickListener

* is long touched/clicked
*
* @param onFeatureLongClickListener
* @param layerIds
*/
void setOnFeatureLongClickListener(@NonNull OnFeatureLongClickListener onFeatureLongClickListener, @Nullable String... layerIds);

/**
* Sets an {@link OnFeatureClickListener} which will be fired when a feature on the map in either of the {@code layerIds}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change documentation here to link to OnFeatureLongClickListener

* is long touched/clicked and/or fulfilling the filter defined in {@code filter}
*
* @param onFeatureLongClickListener
* @param expressionFilter
* @param layerIds
*/
void setOnFeatureLongClickListener(@NonNull OnFeatureLongClickListener onFeatureLongClickListener, @Nullable Expression expressionFilter, @Nullable String... layerIds);

/**
* Checks if the map warms GPS(this just means the location service that is going to be used).
* Warming the GPS in this case means that it starts the location services as soon as you open
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.ona.kujaku.listeners;

import com.mapbox.geojson.Feature;

import java.util.List;

/**
* Created by Richard Kareko on 5/18/20.
*/

public interface OnFeatureLongClickListener {

/**
* Called when a features(s) is long clicked on the map and adheres to params passed in
* {@link io.ona.kujaku.views.KujakuMapView#setOnFeatureClickListener(OnFeatureClickListener, String...)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change documentation here to link to setOnFeatureLongClickListener

* or {@link io.ona.kujaku.views.KujakuMapView#setOnFeatureClickListener(OnFeatureClickListener, com.mapbox.mapboxsdk.style.expressions.Expression, String...)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change documentation here to link to setOnFeatureLongClickListener

*
* @param features
*/
void onFeatureLongClick(List<Feature> features);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annotate List<Feature> features to indicate that it does not provide nonNull i.e. add @NonNull annotation

}
11 changes: 11 additions & 0 deletions library/src/main/java/io/ona/kujaku/manager/DrawingManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Geometry;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.geometry.LatLng;
Expand Down Expand Up @@ -217,6 +218,16 @@ public boolean startDrawing(@Nullable FillBoundaryLayer fillBoundaryLayer) {
List<Point> points = polygon.coordinates().get(0);
this.startDrawingPoints(points);
return true;
} else if (geometry instanceof MultiPolygon) {
// hide layer
fillBoundaryLayer.disableLayerOnMap(mapboxMap);

MultiPolygon multiPolygon = (MultiPolygon) geometry;
for (List<List<Point>> polygonCoordinates : multiPolygon.coordinates()) {
List<Point> points = polygonCoordinates.get(0);
this.startDrawingPoints(points);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an issue to improve this later? A multipolygon contains holes or can show a feature that is made of of multiple scattered polygons. In case you want to edit the boundary of Mombasa which is part of the Kenya boundary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the link #340

}
return true;
}
}

Expand Down
23 changes: 23 additions & 0 deletions library/src/main/java/io/ona/kujaku/views/KujakuMapView.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import io.ona.kujaku.listeners.BoundsChangeListener;
import io.ona.kujaku.listeners.LocationClientStartedCallback;
import io.ona.kujaku.listeners.OnFeatureClickListener;
import io.ona.kujaku.listeners.OnFeatureLongClickListener;
import io.ona.kujaku.listeners.OnKujakuLayerClickListener;
import io.ona.kujaku.listeners.OnKujakuLayerLongClickListener;
import io.ona.kujaku.listeners.OnLocationChanged;
Expand Down Expand Up @@ -164,6 +165,7 @@ public class KujakuMapView extends MapView implements IKujakuMapView, MapboxMap.
private BoundsChangeListener boundsChangeListener;

private OnFeatureClickListener onFeatureClickListener;
private OnFeatureLongClickListener onFeatureLongClickListener;
private String[] featureClickLayerIdFilters;
private Expression featureClickExpressionFilter;

Expand Down Expand Up @@ -829,6 +831,18 @@ public void setOnFeatureClickListener(@NonNull OnFeatureClickListener onFeatureC
this.featureClickExpressionFilter = expressionFilter;
}

@Override
public void setOnFeatureLongClickListener(@NonNull OnFeatureLongClickListener onFeatureLongClickListener, @Nullable String... layerIds) {
this.setOnFeatureLongClickListener(onFeatureLongClickListener, null, layerIds);
}

@Override
public void setOnFeatureLongClickListener(@NonNull OnFeatureLongClickListener onFeatureLongClickListener, @Nullable Expression expressionFilter, @Nullable String... layerIds) {
this.onFeatureLongClickListener = onFeatureLongClickListener;
this.featureClickLayerIdFilters = layerIds;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting layerIds to this.featureClickLayerIdFilters will override the layerIds passed for the OnClickListener
This will also override the featureClickExpressionFilter. Add separate variables to holds this and update the #onMapLongClick to use the new variables

this.featureClickExpressionFilter = expressionFilter;
}

/**
* Set listener when pressing a KujakuLayer
*
Expand Down Expand Up @@ -1124,6 +1138,15 @@ public boolean onMapClick(@NonNull LatLng point) {
public boolean onMapLongClick(@NonNull LatLng point) {
PointF pixel = mapboxMap.getProjection().toScreenLocation(point);

if (onFeatureLongClickListener != null) {
List<com.mapbox.geojson.Feature> features = mapboxMap.queryRenderedFeatures(pixel, featureClickExpressionFilter, featureClickLayerIdFilters);

if (features.size() > 0) {
onFeatureLongClickListener.onFeatureLongClick(features);
}
}


if (onKujakuLayerLongClickListener != null) {
KujakuLayer layer = KujakuLayer.getKujakuLayerSelected(pixel, kujakuLayers, mapboxMap);
if (layer != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.MultiPolygon;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.geometry.LatLng;
Expand Down Expand Up @@ -78,7 +79,26 @@ public void startDrawingWithPoints() {

@Test
public void startDrawingWithExistingLayer() {
manager.startDrawing(getFillBoundaryLayer());
manager.startDrawing(getFillBoundaryLayer(true));

Assert.assertTrue(manager.isDrawingEnabled());
Assert.assertNull(manager.getCurrentKujakuCircle());
// Middle Circles created between each point
Assert.assertEquals(8, manager.getKujakuCircles().size());

Assert.assertFalse(manager.getKujakuCircles().get(0).isMiddleCircle());
Assert.assertTrue(manager.getKujakuCircles().get(1).isMiddleCircle());
Assert.assertFalse(manager.getKujakuCircles().get(2).isMiddleCircle());
Assert.assertTrue(manager.getKujakuCircles().get(3).isMiddleCircle());
Assert.assertFalse(manager.getKujakuCircles().get(4).isMiddleCircle());
Assert.assertTrue(manager.getKujakuCircles().get(5).isMiddleCircle());
Assert.assertFalse(manager.getKujakuCircles().get(6).isMiddleCircle());
Assert.assertTrue(manager.getKujakuCircles().get(7).isMiddleCircle());
}

@Test
public void startDrawingWithExistingMultipolygonLayer() {
manager.startDrawing(getFillBoundaryLayer(false));

Assert.assertTrue(manager.isDrawingEnabled());
Assert.assertNull(manager.getCurrentKujakuCircle());
Expand Down Expand Up @@ -206,18 +226,24 @@ public void areMiddleCircles() {
Assert.assertTrue(manager.getKujakuCircles().get(7).isMiddleCircle());
}

private FillBoundaryLayer getFillBoundaryLayer() {
private FillBoundaryLayer getFillBoundaryLayer(boolean isPolygon) {
List<Feature> features = new ArrayList<Feature>();
List<List<Point>> lists = new ArrayList<>();
List<Point> points = new ArrayList<>();
Polygon polygon = null;

points.add(Point.fromLngLat(-11,15));
points.add(Point.fromLngLat(-5,15));
points.add(Point.fromLngLat(-5,11));
points.add(Point.fromLngLat(-11,11));
lists.add(points);

features.add(Feature.fromGeometry(Polygon.fromLngLats(lists)));
polygon = Polygon.fromLngLats(lists);
if (!isPolygon) {
features.add(Feature.fromGeometry(polygon));
} else {
features.add(Feature.fromGeometry(MultiPolygon.fromPolygon(polygon)));
}

FeatureCollection featureCollection = FeatureCollection.fromFeatures(features);
FillBoundaryLayer.Builder builder = new FillBoundaryLayer.Builder(featureCollection);
Expand Down
14 changes: 14 additions & 0 deletions library/src/test/java/io/ona/kujaku/views/KujakuMapViewTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
import io.ona.kujaku.BaseTest;
import io.ona.kujaku.interfaces.ILocationClient;
import io.ona.kujaku.listeners.LocationClientStartedCallback;
import io.ona.kujaku.listeners.OnFeatureLongClickListener;
import io.ona.kujaku.location.clients.GoogleLocationClient;
import io.ona.kujaku.test.shadows.ShadowKujakuMapView;
import io.ona.kujaku.test.shadows.ShadowMapView;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

/**
Expand Down Expand Up @@ -186,4 +188,16 @@ public void getLocationClientShouldCallCallbackWhenLocationClientIsNullAndWarmLo
.onStarted(Mockito.any(ILocationClient.class));
assertEquals(0, callbacks.size());
}

@Test
public void setOnFeatureLongClickListener() {
assertNull(ReflectionHelpers.getField(kujakuMapView,"onFeatureLongClickListener"));
assertNull(ReflectionHelpers.getField(kujakuMapView,"featureClickLayerIdFilters"));
OnFeatureLongClickListener onFeatureLongClickListenerMock = Mockito.mock(OnFeatureLongClickListener.class);
String[] layerIds = {"id1"};

kujakuMapView.setOnFeatureLongClickListener(onFeatureLongClickListenerMock, layerIds);
assertEquals(onFeatureLongClickListenerMock, ReflectionHelpers.getField(kujakuMapView,"onFeatureLongClickListener"));
assertEquals(layerIds, ReflectionHelpers.getField(kujakuMapView,"featureClickLayerIdFilters"));
}
}