From 53c47c22c004a85684757aec386ec6f02c392ed5 Mon Sep 17 00:00:00 2001 From: tobrun Date: Sat, 9 Feb 2019 16:21:51 +0100 Subject: [PATCH] [flutter] [android] - add symbol api, add android integration of Annotation plugin --- android/.gitignore | 2 + android/build.gradle | 9 +- .../java/com/mapbox/mapboxgl/Convert.java | 189 +++++++--- .../com/mapbox/mapboxgl/MapboxMapBuilder.java | 9 +- .../mapbox/mapboxgl/MapboxMapController.java | 339 +++++++++--------- .../com/mapbox/mapboxgl/MapboxMapFactory.java | 1 + .../mapbox/mapboxgl/MapboxMapOptionsSink.java | 8 +- .../com/mapbox/mapboxgl/MapboxMapsPlugin.java | 11 +- .../com/mapbox/mapboxgl/MarkerBuilder.java | 87 ----- .../com/mapbox/mapboxgl/MarkerController.java | 95 ----- .../mapbox/mapboxgl/MarkerOptionsSink.java | 35 -- ...tener.java => OnSymbolTappedListener.java} | 6 +- .../com/mapbox/mapboxgl/SymbolBuilder.java | 162 +++++++++ .../com/mapbox/mapboxgl/SymbolController.java | 180 ++++++++++ .../mapbox/mapboxgl/SymbolOptionsSink.java | 69 ++++ example/android/app/build.gradle | 4 + example/lib/main.dart | 4 +- example/lib/place_marker.dart | 271 -------------- example/lib/place_symbol.dart | 264 ++++++++++++++ example/lib/scrolling_map.dart | 6 +- lib/mapbox_gl.dart | 2 +- lib/src/controller.dart | 125 ++++--- lib/src/marker.dart | 216 ----------- lib/src/symbol.dart | 182 ++++++++++ 24 files changed, 1262 insertions(+), 1014 deletions(-) delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/MarkerBuilder.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/MarkerController.java delete mode 100644 android/src/main/java/com/mapbox/mapboxgl/MarkerOptionsSink.java rename android/src/main/java/com/mapbox/mapboxgl/{OnMarkerTappedListener.java => OnSymbolTappedListener.java} (60%) create mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java create mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolController.java create mode 100644 android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java delete mode 100644 example/lib/place_marker.dart create mode 100644 example/lib/place_symbol.dart delete mode 100644 lib/src/marker.dart create mode 100644 lib/src/symbol.dart diff --git a/android/.gitignore b/android/.gitignore index c6cbe562a..090919ca2 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -6,3 +6,5 @@ .DS_Store /build /captures +gradlew +gradlew.bat \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 4867e9653..8e12e8bc4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -23,7 +23,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { minSdkVersion 16 @@ -37,6 +37,11 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } dependencies { - implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:7.1.1" + implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:7.1.2" + implementation "com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v7:0.5.0" + } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 } } diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java index 64c3f4555..05dc1bcf5 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java +++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java @@ -6,11 +6,14 @@ import android.graphics.Point; +import android.util.Log; + import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.maps.MapboxMap; import java.util.Arrays; @@ -18,8 +21,13 @@ import java.util.List; import java.util.Map; -/** Conversions between JSON-like values and MapboxMaps data types. */ +/** + * Conversions between JSON-like values and MapboxMaps data types. + */ class Convert { + + private final static String TAG = "Convert"; + // private static BitmapDescriptor toBitmapDescriptor(Object o) { // final List data = toList(o); // switch (toString(data.get(0))) { @@ -56,7 +64,7 @@ static CameraPosition toCameraPosition(Object o) { return builder.build(); } - static boolean isScrollByCameraUpdate(Object o){ + static boolean isScrollByCameraUpdate(Object o) { return toString(toList(o).get(0)).equals("scrollBy"); } @@ -141,7 +149,7 @@ private static LatLngBounds toLatLngBounds(Object o) { return null; } final List data = toList(o); - LatLng[] boundsArray = new LatLng[]{toLatLng(data.get(0)), toLatLng(data.get(1))}; + LatLng[] boundsArray = new LatLng[] {toLatLng(data.get(0)), toLatLng(data.get(1))}; List bounds = Arrays.asList(boundsArray); LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.includes(bounds); @@ -229,58 +237,125 @@ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink) { } } -// static void interpretMarkerOptions(Object o, MarkerOptionsSink sink) { -// final Map data = toMap(o); -// final Object alpha = data.get("alpha"); -// if (alpha != null) { -// sink.setAlpha(toFloat(alpha)); -// } -// final Object anchor = data.get("anchor"); -// if (anchor != null) { -// final List anchorData = toList(anchor); -// sink.setAnchor(toFloat(anchorData.get(0)), toFloat(anchorData.get(1))); -// } -// final Object consumesTapEvents = data.get("consumesTapEvents"); -// if (consumesTapEvents != null) { -// sink.setConsumeTapEvents(toBoolean(consumesTapEvents)); -// } -// final Object draggable = data.get("draggable"); -// if (draggable != null) { -// sink.setDraggable(toBoolean(draggable)); -// } -// final Object flat = data.get("flat"); -// if (flat != null) { -// sink.setFlat(toBoolean(flat)); -// } -// final Object icon = data.get("icon"); -// if (icon != null) { -// sink.setIcon(toBitmapDescriptor(icon)); -// } -// final Object infoWindowAnchor = data.get("infoWindowAnchor"); -// if (infoWindowAnchor != null) { -// final List anchorData = toList(infoWindowAnchor); -// sink.setInfoWindowAnchor(toFloat(anchorData.get(0)), toFloat(anchorData.get(1))); -// } -// final Object infoWindowText = data.get("infoWindowText"); -// if (infoWindowText != null) { -// final List textData = toList(infoWindowText); -// sink.setInfoWindowText(toString(textData.get(0)), toString(textData.get(1))); -// } -// final Object position = data.get("position"); -// if (position != null) { -// sink.setPosition(toLatLng(position)); -// } -// final Object rotation = data.get("rotation"); -// if (rotation != null) { -// sink.setRotation(toFloat(rotation)); -// } -// final Object visible = data.get("visible"); -// if (visible != null) { -// sink.setVisible(toBoolean(visible)); -// } -// final Object zIndex = data.get("zIndex"); -// if (zIndex != null) { -// sink.setZIndex(toFloat(zIndex)); -// } -// } + static void interpretSymbolOptions(Object o, SymbolOptionsSink sink) { + final Map data = toMap(o); + final Object iconSize = data.get("iconSize"); + if (iconSize != null) { + Logger.e(TAG, "setIconSize" + iconSize); + sink.setIconSize(toFloat(iconSize)); + } + final Object iconImage = data.get("iconImage"); + if (iconImage != null) { + Logger.e(TAG, "setIconImage" + iconImage); + sink.setIconImage(toString(iconImage)); + } + final Object iconRotate = data.get("iconRotate"); + if (iconRotate != null) { + Logger.e(TAG, "SetIconRotate" + iconRotate); + sink.setIconRotate(toFloat(iconRotate)); + } + final Object iconOffset = data.get("iconOffset"); + if (iconOffset != null) { + Logger.e(TAG, "SetIconOffset" + iconOffset); + sink.setIconOffset(new float[] {toFloat(toList(iconOffset).get(0)), toFloat(toList(iconOffset).get(1))}); + } + final Object iconAnchor = data.get("iconAnchor"); + if (iconAnchor != null) { + Logger.e(TAG, "SetIconAnchor" + iconAnchor); + sink.setIconAnchor(toString(iconAnchor)); + } + final Object textField = data.get("textField"); + if (textField != null) { + Logger.e(TAG, "SetTextField" + textField); + sink.setTextField(toString(textField)); + } + final Object textSize = data.get("textSize"); + if (textSize != null) { + sink.setTextSize(toFloat(textSize)); + } + final Object textMaxWidth = data.get("textMaxWidth"); + if (textMaxWidth != null) { + sink.setTextMaxWidth(toFloat(textMaxWidth)); + } + final Object textLetterSpacing = data.get("textLetterSpacing"); + if (textLetterSpacing != null) { + sink.setTextLetterSpacing(toFloat(textLetterSpacing)); + } + final Object textJustify = data.get("textJustify"); + if (textJustify != null) { + sink.setTextJustify(toString(textJustify)); + } + final Object textAnchor = data.get("textAnchor"); + if (textAnchor != null) { + sink.setTextAnchor(toString(textAnchor)); + } + final Object textRotate = data.get("textRotate"); + if (textRotate != null) { + sink.setTextRotate(toFloat(textRotate)); + } + final Object textTransform = data.get("textTransform"); + if (textTransform != null) { + sink.setTextTransform(toString(textTransform)); + } + final Object textOffset = data.get("textOffset"); + if (textOffset != null) { + sink.setTextOffset(new float[] {toFloat(toList(textOffset).get(0)), toFloat(toList(textOffset).get(1))}); + } + final Object iconOpacity = data.get("iconOpacity"); + if (iconOpacity != null) { + Logger.e(TAG, "SetIconOpactiy" + iconOpacity); + sink.setIconOpacity(toFloat(iconOpacity)); + } + final Object iconColor = data.get("iconColor"); + if (iconColor != null) { + sink.setIconColor(toString(iconColor)); + } + final Object iconHaloColor = data.get("iconHaloColor"); + if (iconHaloColor != null) { + sink.setIconHaloColor(toString(iconHaloColor)); + } + final Object iconHaloWidth = data.get("iconHaloWidth"); + if (iconHaloWidth != null) { + sink.setIconHaloWidth(toFloat(iconHaloWidth)); + } + final Object iconHaloBlur = data.get("iconHaloBlur"); + if (iconHaloBlur != null) { + sink.setIconHaloBlur(toFloat(iconHaloBlur)); + } + final Object textOpacity = data.get("textOpacity"); + if (textOpacity != null) { + sink.setTextOpacity(toFloat(textOpacity)); + } + final Object textColor = data.get("textColor"); + if (textColor != null) { + sink.setTextColor(toString(textColor)); + } + final Object textHaloColor = data.get("textHaloColor"); + if (textHaloColor != null) { + sink.setTextHaloColor(toString(textHaloColor)); + } + final Object textHaloWidth = data.get("textHaloWidth"); + if (textHaloWidth != null) { + sink.setTextHaloWidth(toFloat(textHaloWidth)); + } + final Object textHaloBlur = data.get("textHaloBlur"); + if (textHaloBlur != null) { + sink.setTextHaloBlur(toFloat(textHaloBlur)); + } + final Object geometry = data.get("geometry"); + if (geometry != null) { + Logger.e(TAG, "SetGeometry"); + sink.setGeometry(toLatLng(geometry)); + } + final Object zIndex = data.get("zIndex"); + if (zIndex != null) { + Logger.e(TAG, "SetZIndex"); + sink.setZIndex(toInt(zIndex)); + } + final Object draggable = data.get("draggable"); + if (draggable != null) { + Logger.e(TAG, "SetDraggable"); + sink.setDraggable(toBoolean(draggable)); + } + } } \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java index a671b5061..0784c6737 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java @@ -13,6 +13,7 @@ import com.mapbox.mapboxsdk.maps.Style; import io.flutter.plugin.common.PluginRegistry; + import java.util.concurrent.atomic.AtomicInteger; @@ -27,9 +28,9 @@ class MapboxMapBuilder implements MapboxMapOptionsSink { private String styleString = Style.MAPBOX_STREETS; MapboxMapController build( - int id, Context context, AtomicInteger state, PluginRegistry.Registrar registrar) { + int id, Context context, AtomicInteger state, PluginRegistry.Registrar registrar) { final MapboxMapController controller = - new MapboxMapController(id, context, state, registrar, options, styleString); + new MapboxMapController(id, context, state, registrar, options, styleString); controller.init(); controller.setMyLocationEnabled(myLocationEnabled); controller.setMyLocationTrackingMode(myLocationTrackingMode); @@ -48,7 +49,7 @@ public void setCompassEnabled(boolean compassEnabled) { @Override public void setCameraTargetBounds(LatLngBounds bounds) { - Log.e(TAG,"setCameraTargetBounds is supported only after map initiated."); + Log.e(TAG, "setCameraTargetBounds is supported only after map initiated."); //throw new UnsupportedOperationException("setCameraTargetBounds is supported only after map initiated."); //options.latLngBoundsForCameraTarget(bounds); } @@ -103,5 +104,5 @@ public void setMyLocationEnabled(boolean myLocationEnabled) { public void setMyLocationTrackingMode(int myLocationTrackingMode) { this.myLocationTrackingMode = myLocationTrackingMode; } - + } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java index 4b15a2043..0c268cda3 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java @@ -25,7 +25,6 @@ import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; @@ -36,6 +35,8 @@ import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.geojson.Feature; +import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolClickListener; +import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -49,6 +50,7 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.platform.PlatformView; + import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -56,31 +58,35 @@ import java.util.List; import java.util.ArrayList; +import com.mapbox.mapboxsdk.plugins.annotation.Symbol; + import android.graphics.RectF; -/** Controller of a single MapboxMaps MapView instance. */ +/** + * Controller of a single MapboxMaps MapView instance. + */ final class MapboxMapController - implements Application.ActivityLifecycleCallbacks, - MapboxMap.OnCameraIdleListener, - MapboxMap.OnCameraMoveListener, - MapboxMap.OnCameraMoveStartedListener, - MapboxMap.OnInfoWindowClickListener, - // MapboxMap.OnMarkerClickListener,//todo: deprecated in 7 - MapboxMap.OnMapClickListener, - MapboxMapOptionsSink, - MethodChannel.MethodCallHandler, - com.mapbox.mapboxsdk.maps.OnMapReadyCallback, - OnCameraTrackingChangedListener, - //OnMarkerTappedListener, - PlatformView { + implements Application.ActivityLifecycleCallbacks, + MapboxMap.OnCameraIdleListener, + MapboxMap.OnCameraMoveListener, + MapboxMap.OnCameraMoveStartedListener, + OnSymbolClickListener, + MapboxMap.OnMapClickListener, + MapboxMapOptionsSink, + MethodChannel.MethodCallHandler, + com.mapbox.mapboxsdk.maps.OnMapReadyCallback, + OnCameraTrackingChangedListener, + OnSymbolTappedListener, + PlatformView { private static final String TAG = "MapboxMapController"; private final int id; private final AtomicInteger activityState; private final MethodChannel methodChannel; private final PluginRegistry.Registrar registrar; private final MapView mapView; - //private final Map markers; + private final Map symbols; private MapboxMap mapboxMap; + private SymbolManager symbolManager; private boolean trackCameraPosition = false; private boolean myLocationEnabled = false; private int myLocationTrackingMode = 0; @@ -90,15 +96,15 @@ final class MapboxMapController private final int registrarActivityHashCode; private final Context context; private final String styleStringInitial; - LocationComponent locationComponent = null; + private LocationComponent locationComponent = null; MapboxMapController( - int id, - Context context, - AtomicInteger activityState, - PluginRegistry.Registrar registrar, - MapboxMapOptions options, - String styleStringInitial) { + int id, + Context context, + AtomicInteger activityState, + PluginRegistry.Registrar registrar, + MapboxMapOptions options, + String styleStringInitial) { Mapbox.getInstance(context, getAccessToken(context)); this.id = id; this.context = context; @@ -106,15 +112,15 @@ final class MapboxMapController this.registrar = registrar; this.styleStringInitial = styleStringInitial; this.mapView = new MapView(context, options); - // this.markers = new HashMap<>(); + this.symbols = new HashMap<>(); this.density = context.getResources().getDisplayMetrics().density; methodChannel = - new MethodChannel(registrar.messenger(), "plugins.flutter.io/mapbox_maps_" + id); + new MethodChannel(registrar.messenger(), "plugins.flutter.io/mapbox_maps_" + id); methodChannel.setMethodCallHandler(this); this.registrarActivityHashCode = registrar.activity().hashCode(); } - private static String getAccessToken(@NonNull Context context){ + private static String getAccessToken(@NonNull Context context) { try { ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); Bundle bundle = ai.metaData; @@ -167,7 +173,7 @@ void init() { break; default: throw new IllegalArgumentException( - "Cannot interpret " + activityState.get() + " as an activity state"); + "Cannot interpret " + activityState.get() + " as an activity state"); } registrar.activity().getApplication().registerActivityLifecycleCallbacks(this); mapView.getMapAsync(this); @@ -185,36 +191,28 @@ private CameraPosition getCameraPosition() { return trackCameraPosition ? mapboxMap.getCameraPosition() : null; } -// private MarkerBuilder newMarkerBuilder() { -// return new MarkerBuilder(this); -// } - -// Marker addMarker(MarkerOptions markerOptions, boolean consumesTapEvents) { -// final Marker marker = mapboxMap.addMarker(markerOptions); -// markers.put(marker.getId(), new MarkerController(marker, consumesTapEvents, this)); -// return marker; -// } -// -// private void removeMarker(String markerId) { -// final MarkerController markerController = markers.remove(markerId); -// if (markerController != null) { -// markerController.remove(); -// } -// } -// -// private MarkerController marker(String markerId) { -// final MarkerController marker = markers.get(markerId); -// if (marker == null) { -// throw new IllegalArgumentException("Unknown marker: " + markerId); -// } -// return marker; -// } + private SymbolBuilder newSymbolBuilder() { + return new SymbolBuilder(symbolManager); + } + + private void removeSymbol(String symbolId) { + final SymbolController symbolController = symbols.remove(symbolId); + if (symbolController != null) { + symbolController.remove(symbolManager); + } + } + + private SymbolController symbol(String symbolId) { + final SymbolController symbol = symbols.get(symbolId); + if (symbol == null) { + throw new IllegalArgumentException("Unknown symbol: " + symbolId); + } + return symbol; + } @Override public void onMapReady(MapboxMap mapboxMap) { this.mapboxMap = mapboxMap; - // mapboxMap.setStyle(Style.MAPBOX_STREETS); - mapboxMap.setOnInfoWindowClickListener(this); if (mapReadyResult != null) { mapReadyResult.success(null); mapReadyResult = null; @@ -222,8 +220,6 @@ public void onMapReady(MapboxMap mapboxMap) { mapboxMap.addOnCameraMoveStartedListener(this); mapboxMap.addOnCameraMoveListener(this); mapboxMap.addOnCameraIdleListener(this); - //mapboxMap.setOnMarkerClickListener(this); - mapboxMap.addOnMapClickListener(this); setStyleString(styleStringInitial); // updateMyLocationEnabled(); } @@ -231,30 +227,34 @@ public void onMapReady(MapboxMap mapboxMap) { @Override public void setStyleString(String styleString) { //check if json, url or plain string: - if (styleString==null || styleString.isEmpty()) { - Log.e(TAG,"setStyleString - string empty or null"); - } else if (styleString.startsWith("{") || styleString.startsWith("[")){ + if (styleString == null || styleString.isEmpty()) { + Log.e(TAG, "setStyleString - string empty or null"); + } else if (styleString.startsWith("{") || styleString.startsWith("[")) { mapboxMap.setStyle(new Style.Builder().fromJson(styleString), onStyleLoadedCallback); } else { mapboxMap.setStyle(new Style.Builder().fromUrl(styleString), onStyleLoadedCallback); } } - + Style.OnStyleLoaded onStyleLoadedCallback = new Style.OnStyleLoaded() { @Override public void onStyleLoaded(@NonNull Style style) { - enableLocationComponent(); + enableSymbolManager(style); + enableLocationComponent(style); + // needs to be placed after SymbolManager#addClickListener, + // is fixed with 0.6.0 of annotations plugin + mapboxMap.addOnMapClickListener(MapboxMapController.this); } }; @SuppressWarnings( {"MissingPermission"}) - private void enableLocationComponent() { + private void enableLocationComponent(@NonNull Style style) { if (hasLocationPermission()) { LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context) .trackingGesturesManagement(true) .build(); locationComponent = mapboxMap.getLocationComponent(); - locationComponent.activateLocationComponent(context, mapboxMap.getStyle(), locationComponentOptions); + locationComponent.activateLocationComponent(context, style, locationComponentOptions); locationComponent.setLocationComponentEnabled(true); locationComponent.setRenderMode(RenderMode.COMPASS); updateMyLocationTrackingMode(); @@ -265,6 +265,17 @@ private void enableLocationComponent() { } } + private void enableSymbolManager(@NonNull Style style) { + if (symbolManager == null) { + symbolManager = new SymbolManager(mapView, mapboxMap, style); + symbolManager.setIconAllowOverlap(true); + symbolManager.setIconIgnorePlacement(true); + symbolManager.setTextAllowOverlap(true); + symbolManager.setTextIgnorePlacement(true); + symbolManager.addClickListener(this); + } + } + @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { switch (call.method) { @@ -275,86 +286,82 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { } mapReadyResult = result; break; - case "map#update": - { - Convert.interpretMapboxMapOptions(call.argument("options"), this); - result.success(Convert.toJson(getCameraPosition())); - break; + case "map#update": { + Convert.interpretMapboxMapOptions(call.argument("options"), this); + result.success(Convert.toJson(getCameraPosition())); + break; + } + case "camera#move": { + final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density); + if (cameraUpdate != null) { + // camera transformation not handled yet + moveCamera(cameraUpdate); } - case "camera#move": - { - final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density); - if(cameraUpdate!=null){ - // camera transformation not handled yet - moveCamera(cameraUpdate); - } - result.success(null); - break; + result.success(null); + break; + } + case "camera#animate": { + final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density); + if (cameraUpdate != null) { + // camera transformation not handled yet + animateCamera(cameraUpdate); } - case "camera#animate": - { - final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density); - if(cameraUpdate!=null) { - // camera transformation not handled yet - animateCamera(cameraUpdate); - } - result.success(null); - break; + result.success(null); + break; + } + case "map#queryRenderedFeatures": { + Map reply = new HashMap<>(); + List features; + + String[] layerIds = ((List) call.argument("layerIds")).toArray(new String[0]); + + String filter = (String) call.argument("filter"); + + Expression filterExpression = filter == null ? null : new Expression(filter); + if (call.hasArgument("x")) { + Double x = call.argument("x"); + Double y = call.argument("y"); + PointF pixel = new PointF(x.floatValue(), y.floatValue()); + features = mapboxMap.queryRenderedFeatures(pixel, filterExpression, layerIds); + } else { + Double left = call.argument("left"); + Double top = call.argument("top"); + Double right = call.argument("right"); + Double bottom = call.argument("bottom"); + RectF rectF = new RectF(left.floatValue(), top.floatValue(), right.floatValue(), bottom.floatValue()); + features = mapboxMap.queryRenderedFeatures(rectF, filterExpression, layerIds); } - case "map#queryRenderedFeatures": - { - Map reply = new HashMap<>(); - List features; - - String[] layerIds = ((List) call.argument("layerIds")).toArray(new String[0]); - - String filter = (String) call.argument("filter"); - - Expression filterExpression = filter == null ? null : new Expression(filter); - if (call.hasArgument("x")) { - Double x = call.argument("x"); - Double y = call.argument("y"); - PointF pixel = new PointF(x.floatValue(), y.floatValue()); - features = mapboxMap.queryRenderedFeatures(pixel, filterExpression, layerIds); - } else { - Double left = call.argument("left"); - Double top = call.argument("top"); - Double right = call.argument("right"); - Double bottom = call.argument("bottom"); - RectF rectF = new RectF(left.floatValue(), top.floatValue(), right.floatValue(), bottom.floatValue()); - features = mapboxMap.queryRenderedFeatures(rectF, filterExpression, layerIds); - } - List featuresJson = new ArrayList<>(); - for (Feature feature : features) { - featuresJson.add(feature.toJson()); - } - reply.put("features", featuresJson); - result.success(reply); - break; + List featuresJson = new ArrayList<>(); + for (Feature feature : features) { + featuresJson.add(feature.toJson()); } -// case "marker#add": -// { -// final MarkerBuilder markerBuilder = newMarkerBuilder(); -// Convert.interpretMarkerOptions(call.argument("options"), markerBuilder); -// final String markerId = markerBuilder.build(); -// result.success(markerId); -// break; -// } -// case "marker#remove": -// { -// final String markerId = call.argument("marker"); -// removeMarker(markerId); -// result.success(null); -// break; -// } -// case "marker#update": -// { -// final String markerId = call.argument("marker"); -// final MarkerController marker = marker(markerId); -// Convert.interpretMarkerOptions(call.argument("options"), marker); -// result.success(null); -// break; -// } + reply.put("features", featuresJson); + result.success(reply); + break; + } + case "symbol#add": { + final SymbolBuilder symbolBuilder = newSymbolBuilder(); + Convert.interpretSymbolOptions(call.argument("options"), symbolBuilder); + final Symbol symbol = symbolBuilder.build(); + final String symbolId = String.valueOf(symbol.getId()); + symbols.put(symbolId, new SymbolController(symbol, true, this)); + result.success(symbolId); + break; + } + case "symbol#remove": { + final String symbolId = call.argument("symbol"); + removeSymbol(symbolId); + result.success(null); + break; + } + case "symbol#update": { + final String symbolId = call.argument("symbol"); + final SymbolController symbol = symbol(symbolId); + Convert.interpretSymbolOptions(call.argument("options"), symbol); + symbol.update(symbolManager); + result.success(null); + break; + } default: result.notImplemented(); } @@ -368,14 +375,6 @@ public void onCameraMoveStarted(int reason) { methodChannel.invokeMethod("camera#onMoveStarted", arguments); } - @Override - public boolean onInfoWindowClick(Marker marker) { - final Map arguments = new HashMap<>(2); - arguments.put("marker", marker.getId()); - methodChannel.invokeMethod("infoWindow#onTap", arguments); - return false;//todo: need to know if consumed the event or not - } - @Override public void onCameraMove() { if (!trackCameraPosition) { @@ -397,21 +396,23 @@ public void onCameraTrackingChanged(int currentMode) { @Override public void onCameraTrackingDismissed() { - methodChannel.invokeMethod("map#onCameraTrackingDismissed",new HashMap<>()); - } - -// @Override -// public void onMarkerTapped(Marker marker) { -// final Map arguments = new HashMap<>(2); -// arguments.put("marker", marker.getId()); -// methodChannel.invokeMethod("marker#onTap", arguments); -// } -// -// @Override -// public boolean onMarkerClick(Marker marker) { -// final MarkerController markerController = markers.get(marker.getId()); -// return (markerController != null && markerController.onTap()); -// } + methodChannel.invokeMethod("map#onCameraTrackingDismissed", new HashMap<>()); + } + + @Override + public void onAnnotationClick(Symbol symbol) { + final SymbolController symbolController = symbols.get(String.valueOf(symbol.getId())); + if (symbolController != null) { + symbolController.onTap(); + } + } + + @Override + public void onSymbolTapped(Symbol symbol) { + final Map arguments = new HashMap<>(2); + arguments.put("symbol", String.valueOf(symbol.getId())); + methodChannel.invokeMethod("symbol#onTap", arguments); + } @Override public boolean onMapClick(@NonNull LatLng point) { @@ -434,6 +435,9 @@ public void dispose() { if (locationComponent != null) { locationComponent.setLocationComponentEnabled(false); } + if (symbolManager != null) { + symbolManager.onDestroy(); + } mapView.onDestroy(); registrar.activity().getApplication().unregisterActivityLifecycleCallbacks(this); } @@ -570,15 +574,15 @@ private void updateMyLocationEnabled() { } private void updateMyLocationTrackingMode() { - int[] mapboxTrackingModes = new int[]{ CameraMode.NONE, CameraMode.TRACKING, CameraMode.TRACKING_COMPASS, CameraMode.TRACKING_GPS }; + int[] mapboxTrackingModes = new int[] {CameraMode.NONE, CameraMode.TRACKING, CameraMode.TRACKING_COMPASS, CameraMode.TRACKING_GPS}; locationComponent.setCameraMode(mapboxTrackingModes[this.myLocationTrackingMode]); } - + private boolean hasLocationPermission() { return checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED - || checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) - == PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED + || checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) + == PackageManager.PERMISSION_GRANTED; } private int checkSelfPermission(String permission) { @@ -586,8 +590,7 @@ private int checkSelfPermission(String permission) { throw new IllegalArgumentException("permission is null"); } return context.checkPermission( - permission, android.os.Process.myPid(), android.os.Process.myUid()); + permission, android.os.Process.myPid(), android.os.Process.myUid()); } - } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java index 5247b20b4..bc8299eca 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapFactory.java @@ -9,6 +9,7 @@ import io.flutter.plugin.common.StandardMessageCodec; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugin.platform.PlatformViewFactory; + import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java index 9159de7fd..0099220d1 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapOptionsSink.java @@ -6,14 +6,16 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds; -/** Receiver of MapboxMap configuration options. */ +/** + * Receiver of MapboxMap configuration options. + */ interface MapboxMapOptionsSink { void setCameraTargetBounds(LatLngBounds bounds); //todo: dddd replace with CameraPosition.Builder target void setCompassEnabled(boolean compassEnabled); // TODO: styleString is not actually a part of options. consider moving - void setStyleString(String styleString); + void setStyleString(String styleString); void setMinMaxZoomPreference(Float min, Float max); @@ -28,6 +30,6 @@ interface MapboxMapOptionsSink { void setZoomGesturesEnabled(boolean zoomGesturesEnabled); void setMyLocationEnabled(boolean myLocationEnabled); - + void setMyLocationTrackingMode(int myLocationTrackingMode); } diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapsPlugin.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapsPlugin.java index 0e7877bda..db9b09db7 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapsPlugin.java +++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapsPlugin.java @@ -7,7 +7,9 @@ import android.app.Activity; import android.app.Application; import android.os.Bundle; + import io.flutter.plugin.common.PluginRegistry.Registrar; + import java.util.concurrent.atomic.AtomicInteger; /** @@ -30,9 +32,9 @@ public static void registerWith(Registrar registrar) { final MapboxMapsPlugin plugin = new MapboxMapsPlugin(registrar); registrar.activity().getApplication().registerActivityLifecycleCallbacks(plugin); registrar - .platformViewRegistry() - .registerViewFactory( - "plugins.flutter.io/mapbox_gl", new MapboxMapFactory(plugin.state, registrar)); + .platformViewRegistry() + .registerViewFactory( + "plugins.flutter.io/mapbox_gl", new MapboxMapFactory(plugin.state, registrar)); } @Override @@ -76,7 +78,8 @@ public void onActivityStopped(Activity activity) { } @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) {} + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + } @Override public void onActivityDestroyed(Activity activity) { diff --git a/android/src/main/java/com/mapbox/mapboxgl/MarkerBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/MarkerBuilder.java deleted file mode 100644 index ce628aa4d..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/MarkerBuilder.java +++ /dev/null @@ -1,87 +0,0 @@ -//// Copyright 2018 The Chromium Authors. All rights reserved. -//// Use of this source code is governed by a BSD-style license that can be -//// found in the LICENSE file. -// -//package com.mapbox.mapboxgl; -// -//import com.google.android.gms.maps.model.BitmapDescriptor; -//import com.google.android.gms.maps.model.LatLng; -//import com.google.android.gms.maps.model.Marker; -//import com.google.android.gms.maps.model.MarkerOptions; -// -//class MarkerBuilder implements MarkerOptionsSink { -// private final MapboxMapController mapController; -// private final MarkerOptions markerOptions; -// private boolean consumesTapEvents; -// -// MarkerBuilder(MapboxMapController mapController) { -// this.mapController = mapController; -// this.markerOptions = new MarkerOptions(); -// } -// -// String build() { -// final Marker marker = mapController.addMarker(markerOptions, consumesTapEvents); -// return marker.getId(); -// } -// -// @Override -// public void setAlpha(float alpha) { -// markerOptions.alpha(alpha); -// } -// -// @Override -// public void setAnchor(float u, float v) { -// markerOptions.anchor(u, v); -// } -// -// @Override -// public void setConsumeTapEvents(boolean consumesTapEvents) { -// this.consumesTapEvents = consumesTapEvents; -// } -// -// @Override -// public void setDraggable(boolean draggable) { -// markerOptions.draggable(draggable); -// } -// -// @Override -// public void setFlat(boolean flat) { -// markerOptions.flat(flat); -// } -// -// @Override -// public void setIcon(BitmapDescriptor bitmapDescriptor) { -// markerOptions.icon(bitmapDescriptor); -// } -// -// @Override -// public void setInfoWindowAnchor(float u, float v) { -// markerOptions.infoWindowAnchor(u, v); -// } -// -// @Override -// public void setInfoWindowText(String title, String snippet) { -// markerOptions.title(title); -// markerOptions.snippet(snippet); -// } -// -// @Override -// public void setPosition(LatLng position) { -// markerOptions.position(position); -// } -// -// @Override -// public void setRotation(float rotation) { -// markerOptions.rotation(rotation); -// } -// -// @Override -// public void setVisible(boolean visible) { -// markerOptions.visible(visible); -// } -// -// @Override -// public void setZIndex(float zIndex) { -// markerOptions.zIndex(zIndex); -// } -//} diff --git a/android/src/main/java/com/mapbox/mapboxgl/MarkerController.java b/android/src/main/java/com/mapbox/mapboxgl/MarkerController.java deleted file mode 100644 index f7612d19a..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/MarkerController.java +++ /dev/null @@ -1,95 +0,0 @@ -//// Copyright 2018 The Chromium Authors. All rights reserved. -//// Use of this source code is governed by a BSD-style license that can be -//// found in the LICENSE file. -// -//package com.mapbox.mapboxgl; -// -//import com.google.android.gms.maps.model.BitmapDescriptor; -//import com.google.android.gms.maps.model.LatLng; -//import com.google.android.gms.maps.model.Marker; -// -///** Controller of a single Marker on the map. */ -//class MarkerController implements MarkerOptionsSink { -// private final Marker marker; -// private final OnMarkerTappedListener onTappedListener; -// private boolean consumeTapEvents; -// -// MarkerController( -// Marker marker, boolean consumeTapEvents, OnMarkerTappedListener onTappedListener) { -// this.marker = marker; -// this.consumeTapEvents = consumeTapEvents; -// this.onTappedListener = onTappedListener; -// } -// -// boolean onTap() { -// if (onTappedListener != null) { -// onTappedListener.onMarkerTapped(marker); -// } -// return consumeTapEvents; -// } -// -// void remove() { -// marker.remove(); -// } -// -// @Override -// public void setAlpha(float alpha) { -// marker.setAlpha(alpha); -// } -// -// @Override -// public void setAnchor(float u, float v) { -// marker.setAnchor(u, v); -// } -// -// @Override -// public void setConsumeTapEvents(boolean consumeTapEvents) { -// this.consumeTapEvents = consumeTapEvents; -// } -// -// @Override -// public void setDraggable(boolean draggable) { -// marker.setDraggable(draggable); -// } -// -// @Override -// public void setFlat(boolean flat) { -// marker.setFlat(flat); -// } -// -// @Override -// public void setIcon(BitmapDescriptor bitmapDescriptor) { -// marker.setIcon(bitmapDescriptor); -// } -// -// @Override -// public void setInfoWindowAnchor(float u, float v) { -// marker.setInfoWindowAnchor(u, v); -// } -// -// @Override -// public void setInfoWindowText(String title, String snippet) { -// marker.setTitle(title); -// marker.setSnippet(snippet); -// } -// -// @Override -// public void setPosition(LatLng position) { -// marker.setPosition(position); -// } -// -// @Override -// public void setRotation(float rotation) { -// marker.setRotation(rotation); -// } -// -// @Override -// public void setVisible(boolean visible) { -// marker.setVisible(visible); -// } -// -// @Override -// public void setZIndex(float zIndex) { -// marker.setZIndex(zIndex); -// } -//} diff --git a/android/src/main/java/com/mapbox/mapboxgl/MarkerOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/MarkerOptionsSink.java deleted file mode 100644 index 31a162aa0..000000000 --- a/android/src/main/java/com/mapbox/mapboxgl/MarkerOptionsSink.java +++ /dev/null @@ -1,35 +0,0 @@ -//// Copyright 2018 The Chromium Authors. All rights reserved. -//// Use of this source code is governed by a BSD-style license that can be -//// found in the LICENSE file. -// -//package com.mapbox.mapboxgl; -// -//import com.google.android.gms.maps.model.BitmapDescriptor; -//import com.google.android.gms.maps.model.LatLng; -// -///** Receiver of Marker configuration options. */ -//interface MarkerOptionsSink { -// void setAlpha(float alpha); -// -// void setAnchor(float u, float v); -// -// void setConsumeTapEvents(boolean consumesTapEvents); -// -// void setDraggable(boolean draggable); -// -// void setFlat(boolean flat); -// -// void setIcon(BitmapDescriptor bitmapDescriptor); -// -// void setInfoWindowAnchor(float u, float v); -// -// void setInfoWindowText(String title, String snippet); -// -// void setPosition(LatLng position); -// -// void setRotation(float rotation); -// -// void setVisible(boolean visible); -// -// void setZIndex(float zIndex); -//} diff --git a/android/src/main/java/com/mapbox/mapboxgl/OnMarkerTappedListener.java b/android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java similarity index 60% rename from android/src/main/java/com/mapbox/mapboxgl/OnMarkerTappedListener.java rename to android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java index 18b55f104..9e567e74a 100644 --- a/android/src/main/java/com/mapbox/mapboxgl/OnMarkerTappedListener.java +++ b/android/src/main/java/com/mapbox/mapboxgl/OnSymbolTappedListener.java @@ -4,8 +4,8 @@ package com.mapbox.mapboxgl; -import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.plugins.annotation.Symbol; -interface OnMarkerTappedListener { - void onMarkerTapped(Marker marker); +interface OnSymbolTappedListener { + void onSymbolTapped(Symbol symbol); } diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java new file mode 100644 index 000000000..c7378821c --- /dev/null +++ b/android/src/main/java/com/mapbox/mapboxgl/SymbolBuilder.java @@ -0,0 +1,162 @@ +// This file is generated. + +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.mapbox.mapboxgl; + +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.plugins.annotation.Symbol; +import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; +import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions; + +class SymbolBuilder implements SymbolOptionsSink { + private final SymbolManager symbolManager; + private final SymbolOptions symbolOptions; + + SymbolBuilder(SymbolManager symbolManager) { + this.symbolManager = symbolManager; + this.symbolOptions = new SymbolOptions(); + } + + Symbol build() { + return symbolManager.create(symbolOptions); + } + + @Override + public void setIconSize(float iconSize) { + symbolOptions.withIconSize(iconSize); + } + + @Override + public void setIconImage(String iconImage) { + symbolOptions.withIconImage(iconImage); + } + + @Override + public void setIconRotate(float iconRotate) { + symbolOptions.withIconRotate(iconRotate); + } + + @Override + public void setIconOffset(float[] iconOffset) { + symbolOptions.withIconOffset(new Float[] {iconOffset[0], iconOffset[1]}); + } + + @Override + public void setIconAnchor(String iconAnchor) { + symbolOptions.withIconAnchor(iconAnchor); + } + + @Override + public void setTextField(String textField) { + symbolOptions.withTextField(textField); + } + + @Override + public void setTextSize(float textSize) { + symbolOptions.withTextSize(textSize); + } + + @Override + public void setTextMaxWidth(float textMaxWidth) { + symbolOptions.withTextMaxWidth(textMaxWidth); + } + + @Override + public void setTextLetterSpacing(float textLetterSpacing) { + symbolOptions.withTextLetterSpacing(textLetterSpacing); + } + + @Override + public void setTextJustify(String textJustify) { + symbolOptions.withTextJustify(textJustify); + } + + @Override + public void setTextAnchor(String textAnchor) { + symbolOptions.withTextAnchor(textAnchor); + } + + @Override + public void setTextRotate(float textRotate) { + symbolOptions.withTextRotate(textRotate); + } + + @Override + public void setTextTransform(String textTransform) { + symbolOptions.withTextTransform(textTransform); + } + + @Override + public void setTextOffset(float[] textOffset) { + symbolOptions.withTextOffset(new Float[] {textOffset[0], textOffset[1]}); + } + + @Override + public void setIconOpacity(float iconOpacity) { + symbolOptions.withIconOpacity(iconOpacity); + } + + @Override + public void setIconColor(String iconColor) { + symbolOptions.withIconColor(iconColor); + } + + @Override + public void setIconHaloColor(String iconHaloColor) { + symbolOptions.withIconHaloColor(iconHaloColor); + } + + @Override + public void setIconHaloWidth(float iconHaloWidth) { + symbolOptions.withIconHaloWidth(iconHaloWidth); + } + + @Override + public void setIconHaloBlur(float iconHaloBlur) { + symbolOptions.withIconHaloBlur(iconHaloBlur); + } + + @Override + public void setTextOpacity(float textOpacity) { + symbolOptions.withTextOpacity(textOpacity); + } + + @Override + public void setTextColor(String textColor) { + symbolOptions.withTextColor(textColor); + } + + @Override + public void setTextHaloColor(String textHaloColor) { + symbolOptions.withTextHaloColor(textHaloColor); + } + + @Override + public void setTextHaloWidth(float textHaloWidth) { + symbolOptions.withTextHaloWidth(textHaloWidth); + } + + @Override + public void setTextHaloBlur(float textHaloBlur) { + symbolOptions.withTextHaloBlur(textHaloBlur); + } + + @Override + public void setGeometry(LatLng geometry) { + symbolOptions.withGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); + } + + @Override + public void setZIndex(int zIndex) { + symbolOptions.withZIndex(zIndex); + } + + @Override + public void setDraggable(boolean draggable) { + symbolOptions.setDraggable(draggable); + } +} \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolController.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolController.java new file mode 100644 index 000000000..1fe30cf79 --- /dev/null +++ b/android/src/main/java/com/mapbox/mapboxgl/SymbolController.java @@ -0,0 +1,180 @@ +// This file is generated. + +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.mapbox.mapboxgl; + +import android.graphics.PointF; + +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.plugins.annotation.Symbol; +import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager; +import com.mapbox.mapboxsdk.utils.ColorUtils; + +/** + * Controller of a single Symbol on the map. + */ +class SymbolController implements SymbolOptionsSink { + private final Symbol symbol; + private final OnSymbolTappedListener onTappedListener; + private boolean consumeTapEvents; + + SymbolController(Symbol symbol, boolean consumeTapEvents, OnSymbolTappedListener onTappedListener) { + this.symbol = symbol; + this.consumeTapEvents = consumeTapEvents; + this.onTappedListener = onTappedListener; + } + + boolean onTap() { + if (onTappedListener != null) { + onTappedListener.onSymbolTapped(symbol); + } + return consumeTapEvents; + } + + void remove(SymbolManager symbolManager) { + symbolManager.delete(symbol); + } + + @Override + public void setIconSize(float iconSize) { + symbol.setIconSize(iconSize); + } + + @Override + public void setIconImage(String iconImage) { + symbol.setIconImage(iconImage); + } + + @Override + public void setIconRotate(float iconRotate) { + symbol.setIconRotate(iconRotate); + } + + @Override + public void setIconOffset(float[] iconOffset) { + symbol.setIconOffset(new PointF(iconOffset[0], iconOffset[1])); + } + + @Override + public void setIconAnchor(String iconAnchor) { + symbol.setIconAnchor(iconAnchor); + } + + @Override + public void setTextField(String textField) { + symbol.setTextField(textField); + } + + @Override + public void setTextSize(float textSize) { + symbol.setTextSize(textSize); + } + + @Override + public void setTextMaxWidth(float textMaxWidth) { + symbol.setTextMaxWidth(textMaxWidth); + } + + @Override + public void setTextLetterSpacing(float textLetterSpacing) { + symbol.setTextLetterSpacing(textLetterSpacing); + } + + @Override + public void setTextJustify(String textJustify) { + symbol.setTextJustify(textJustify); + } + + @Override + public void setTextAnchor(String textAnchor) { + symbol.setTextAnchor(textAnchor); + } + + @Override + public void setTextRotate(float textRotate) { + symbol.setTextRotate(textRotate); + } + + @Override + public void setTextTransform(String textTransform) { + symbol.setTextTransform(textTransform); + } + + @Override + public void setTextOffset(float[] textOffset) { + symbol.setTextOffset(new PointF(textOffset[0], textOffset[1])); + } + + @Override + public void setIconOpacity(float iconOpacity) { + symbol.setIconOpacity(iconOpacity); + } + + @Override + public void setIconColor(String iconColor) { + symbol.setIconColor(ColorUtils.rgbaToColor(iconColor)); + } + + @Override + public void setIconHaloColor(String iconHaloColor) { + symbol.setIconHaloColor(ColorUtils.rgbaToColor(iconHaloColor)); + } + + @Override + public void setIconHaloWidth(float iconHaloWidth) { + symbol.setIconHaloWidth(iconHaloWidth); + } + + @Override + public void setIconHaloBlur(float iconHaloBlur) { + symbol.setIconHaloBlur(iconHaloBlur); + } + + @Override + public void setTextOpacity(float textOpacity) { + symbol.setTextOpacity(textOpacity); + } + + @Override + public void setTextColor(String textColor) { + symbol.setTextColor(ColorUtils.rgbaToColor((textColor))); + } + + @Override + public void setTextHaloColor(String textHaloColor) { + symbol.setTextHaloColor(ColorUtils.rgbaToColor(textHaloColor)); + } + + @Override + public void setTextHaloWidth(float textHaloWidth) { + symbol.setTextHaloWidth(textHaloWidth); + } + + @Override + public void setTextHaloBlur(float textHaloBlur) { + symbol.setTextHaloBlur(textHaloBlur); + } + + @Override + public void setZIndex(int zIndex) { + symbol.setZIndex(zIndex); + } + + @Override + public void setGeometry(LatLng geometry) { + symbol.setGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude())); + } + + @Override + public void setDraggable(boolean draggable) { + symbol.setDraggable(draggable); + } + + public void update(SymbolManager symbolManager) { + symbolManager.update(symbol); + } +} diff --git a/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java new file mode 100644 index 000000000..af46756dc --- /dev/null +++ b/android/src/main/java/com/mapbox/mapboxgl/SymbolOptionsSink.java @@ -0,0 +1,69 @@ +// This file is generated. + +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package com.mapbox.mapboxgl; + +import com.mapbox.mapboxsdk.geometry.LatLng; + +/** + * Receiver of Symbol configuration options. + */ +interface SymbolOptionsSink { + + void setIconSize(float iconSize); + + void setIconImage(String iconImage); + + void setIconRotate(float iconRotate); + + void setIconOffset(float[] iconOffset); + + void setIconAnchor(String iconAnchor); + + void setTextField(String textField); + + void setTextSize(float textSize); + + void setTextMaxWidth(float textMaxWidth); + + void setTextLetterSpacing(float textLetterSpacing); + + void setTextJustify(String textJustify); + + void setTextAnchor(String textAnchor); + + void setTextRotate(float textRotate); + + void setTextTransform(String textTransform); + + void setTextOffset(float[] textOffset); + + void setIconOpacity(float iconOpacity); + + void setIconColor(String iconColor); + + void setIconHaloColor(String iconHaloColor); + + void setIconHaloWidth(float iconHaloWidth); + + void setIconHaloBlur(float iconHaloBlur); + + void setTextOpacity(float textOpacity); + + void setTextColor(String textColor); + + void setTextHaloColor(String textHaloColor); + + void setTextHaloWidth(float textHaloWidth); + + void setTextHaloBlur(float textHaloBlur); + + void setGeometry(LatLng geometry); + + void setZIndex(int index); + + void setDraggable(boolean draggable); +} diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index fe8da1189..d9229a9e4 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -49,6 +49,10 @@ android { signingConfig signingConfigs.debug } } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } } flutter { diff --git a/example/lib/main.dart b/example/lib/main.dart index 616ab4e2f..2153061d2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -7,14 +7,14 @@ import 'animate_camera.dart'; import 'map_ui.dart'; import 'move_camera.dart'; import 'page.dart'; -import 'place_marker.dart'; +import 'place_symbol.dart'; import 'scrolling_map.dart'; final List _allPages = [ MapUiPage(), AnimateCameraPage(), MoveCameraPage(), - PlaceMarkerPage(), + PlaceSymbolPage(), ScrollingMapPage(), ]; diff --git a/example/lib/place_marker.dart b/example/lib/place_marker.dart deleted file mode 100644 index 32dff8f97..000000000 --- a/example/lib/place_marker.dart +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:mapbox_gl/mapbox_gl.dart'; - -import 'page.dart'; - -class PlaceMarkerPage extends Page { - PlaceMarkerPage() : super(const Icon(Icons.place), 'Place marker'); - - @override - Widget build(BuildContext context) { - return const PlaceMarkerBody(); - } -} - -class PlaceMarkerBody extends StatefulWidget { - const PlaceMarkerBody(); - - @override - State createState() => PlaceMarkerBodyState(); -} - -class PlaceMarkerBodyState extends State { - PlaceMarkerBodyState(); - - static final LatLng center = const LatLng(-33.86711, 151.1947171); - - MapboxMapController controller; - int _markerCount = 0; - Marker _selectedMarker; - - void _onMapCreated(MapboxMapController controller) { - this.controller = controller; - controller.onMarkerTapped.add(_onMarkerTapped); - } - - @override - void dispose() { - controller?.onMarkerTapped?.remove(_onMarkerTapped); - super.dispose(); - } - - void _onMarkerTapped(Marker marker) { - if (_selectedMarker != null) { - _updateSelectedMarker( - const MarkerOptions(icon: BitmapDescriptor.defaultMarker), - ); - } - setState(() { - _selectedMarker = marker; - }); - _updateSelectedMarker( - MarkerOptions( - icon: BitmapDescriptor.defaultMarkerWithHue( - BitmapDescriptor.hueGreen, - ), - ), - ); - } - - void _updateSelectedMarker(MarkerOptions changes) { - controller.updateMarker(_selectedMarker, changes); - } - - void _add() { - controller.addMarker(MarkerOptions( - position: LatLng( - center.latitude + sin(_markerCount * pi / 6.0) / 20.0, - center.longitude + cos(_markerCount * pi / 6.0) / 20.0, - ), - infoWindowText: InfoWindowText('Marker #${_markerCount + 1}', '*'), - )); - setState(() { - _markerCount += 1; - }); - } - - void _remove() { - controller.removeMarker(_selectedMarker); - setState(() { - _selectedMarker = null; - _markerCount -= 1; - }); - } - - void _changePosition() { - final LatLng current = _selectedMarker.options.position; - final Offset offset = Offset( - center.latitude - current.latitude, - center.longitude - current.longitude, - ); - _updateSelectedMarker( - MarkerOptions( - position: LatLng( - center.latitude + offset.dy, - center.longitude + offset.dx, - ), - ), - ); - } - - void _changeAnchor() { - final Offset currentAnchor = _selectedMarker.options.anchor; - final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); - _updateSelectedMarker(MarkerOptions(anchor: newAnchor)); - } - - Future _changeInfoAnchor() async { - final Offset currentAnchor = _selectedMarker.options.infoWindowAnchor; - final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); - _updateSelectedMarker(MarkerOptions(infoWindowAnchor: newAnchor)); - } - - Future _toggleDraggable() async { - _updateSelectedMarker( - MarkerOptions(draggable: !_selectedMarker.options.draggable), - ); - } - - Future _toggleFlat() async { - _updateSelectedMarker(MarkerOptions(flat: !_selectedMarker.options.flat)); - } - - Future _changeInfo() async { - final InfoWindowText currentInfo = _selectedMarker.options.infoWindowText; - _updateSelectedMarker(MarkerOptions( - infoWindowText: InfoWindowText( - currentInfo.title, - currentInfo.snippet + '*', - ), - )); - } - - Future _changeAlpha() async { - final double current = _selectedMarker.options.alpha; - _updateSelectedMarker( - MarkerOptions(alpha: current < 0.1 ? 1.0 : current * 0.75), - ); - } - - Future _changeRotation() async { - final double current = _selectedMarker.options.rotation; - _updateSelectedMarker( - MarkerOptions(rotation: current == 330.0 ? 0.0 : current + 30.0), - ); - } - - Future _toggleVisible() async { - _updateSelectedMarker( - MarkerOptions(visible: !_selectedMarker.options.visible), - ); - } - - Future _changeZIndex() async { - final double current = _selectedMarker.options.zIndex; - _updateSelectedMarker( - MarkerOptions(zIndex: current == 12.0 ? 0.0 : current + 1.0), - ); - } - - @override - Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Center( - child: SizedBox( - width: 300.0, - height: 200.0, - child: MapboxMap( - onMapCreated: _onMapCreated, - initialCameraPosition: const CameraPosition( - target: LatLng(-33.852, 151.211), - zoom: 11.0, - ), - ), - ), - ), - Expanded( - child: SingleChildScrollView( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Row( - children: [ - Column( - children: [ - FlatButton( - child: const Text('add'), - onPressed: (_markerCount == 12) ? null : _add, - ), - FlatButton( - child: const Text('remove'), - onPressed: (_selectedMarker == null) ? null : _remove, - ), - FlatButton( - child: const Text('change info'), - onPressed: - (_selectedMarker == null) ? null : _changeInfo, - ), - FlatButton( - child: const Text('change info anchor'), - onPressed: (_selectedMarker == null) - ? null - : _changeInfoAnchor, - ), - ], - ), - Column( - children: [ - FlatButton( - child: const Text('change alpha'), - onPressed: - (_selectedMarker == null) ? null : _changeAlpha, - ), - FlatButton( - child: const Text('change anchor'), - onPressed: - (_selectedMarker == null) ? null : _changeAnchor, - ), - FlatButton( - child: const Text('toggle draggable'), - onPressed: (_selectedMarker == null) - ? null - : _toggleDraggable, - ), - FlatButton( - child: const Text('toggle flat'), - onPressed: - (_selectedMarker == null) ? null : _toggleFlat, - ), - FlatButton( - child: const Text('change position'), - onPressed: (_selectedMarker == null) - ? null - : _changePosition, - ), - FlatButton( - child: const Text('change rotation'), - onPressed: (_selectedMarker == null) - ? null - : _changeRotation, - ), - FlatButton( - child: const Text('toggle visible'), - onPressed: - (_selectedMarker == null) ? null : _toggleVisible, - ), - FlatButton( - child: const Text('change zIndex'), - onPressed: - (_selectedMarker == null) ? null : _changeZIndex, - ), - ], - ), - ], - ) - ], - ), - ), - ), - ], - ); - } -} diff --git a/example/lib/place_symbol.dart b/example/lib/place_symbol.dart new file mode 100644 index 000000000..6f2a0bc4c --- /dev/null +++ b/example/lib/place_symbol.dart @@ -0,0 +1,264 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:mapbox_gl/mapbox_gl.dart'; + +import 'page.dart'; + +class PlaceSymbolPage extends Page { + PlaceSymbolPage() : super(const Icon(Icons.place), 'Place symbol'); + + @override + Widget build(BuildContext context) { + return const PlaceSymbolBody(); + } +} + +class PlaceSymbolBody extends StatefulWidget { + const PlaceSymbolBody(); + + @override + State createState() => PlaceSymbolBodyState(); +} + +class PlaceSymbolBodyState extends State { + PlaceSymbolBodyState(); + + static final LatLng center = const LatLng(-33.86711, 151.1947171); + + MapboxMapController controller; + int _symbolCount = 0; + Symbol _selectedSymbol; + + void _onMapCreated(MapboxMapController controller) { + this.controller = controller; + controller.onSymbolTapped.add(_onSymbolTapped); + } + + @override + void dispose() { + controller?.onSymbolTapped?.remove(_onSymbolTapped); + super.dispose(); + } + + void _onSymbolTapped(Symbol symbol) { + if (_selectedSymbol != null) { + _updateSelectedSymbol( + const SymbolOptions(iconSize: 1.0), + ); + } + setState(() { + _selectedSymbol = symbol; + }); + _updateSelectedSymbol( + SymbolOptions( + iconSize: 1.4, + ), + ); + } + + void _updateSelectedSymbol(SymbolOptions changes) { + controller.updateSymbol(_selectedSymbol, changes); + } + + void _add() { + controller.addSymbol( + SymbolOptions( + geometry: LatLng( + center.latitude + sin(_symbolCount * pi / 6.0) / 20.0, + center.longitude + cos(_symbolCount * pi / 6.0) / 20.0, + ), + iconImage: "airport-15"), + ); + setState(() { + _symbolCount += 1; + }); + } + + void _remove() { + controller.removeSymbol(_selectedSymbol); + setState(() { + _selectedSymbol = null; + _symbolCount -= 1; + }); + } + + void _changePosition() { + final LatLng current = _selectedSymbol.options.geometry; + final Offset offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); + _updateSelectedSymbol( + SymbolOptions( + geometry: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), + ), + ); + } + + void _changeAnchor() { + Offset currentAnchor = _selectedSymbol.options.iconOffset; + if (currentAnchor == null) { + // default value + currentAnchor = Offset(0.0, 0.0); + } + final Offset newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + _updateSelectedSymbol(SymbolOptions(iconOffset: newAnchor)); + } + + Future _toggleDraggable() async { + bool draggable = _selectedSymbol.options.draggable; + if (draggable == null) { + // default value + draggable = false; + } + + _updateSelectedSymbol( + SymbolOptions(draggable: !draggable), + ); + } + + Future _changeAlpha() async { + double current = _selectedSymbol.options.iconOpacity; + if (current == null) { + // default value + current = 1.0; + } + + _updateSelectedSymbol( + SymbolOptions(iconOpacity: current < 0.1 ? 1.0 : current * 0.75), + ); + } + + Future _changeRotation() async { + double current = _selectedSymbol.options.iconRotate; + if (current == null) { + // default value + current = 0; + } + _updateSelectedSymbol( + SymbolOptions(iconRotate: current == 330.0 ? 0.0 : current + 30.0), + ); + } + + Future _toggleVisible() async { + double current = _selectedSymbol.options.iconOpacity; + if (current == null) { + // default value + current = 1.0; + } + + _updateSelectedSymbol( + SymbolOptions( + iconOpacity: current == 0.0 ? 1.0 : 0.0), + ); + } + + Future _changeZIndex() async { + int current = _selectedSymbol.options.zIndex; + if (current == null) { + // default value + current = 0; + } + _updateSelectedSymbol( + SymbolOptions(zIndex: current == 12 ? 0 : current + 1), + ); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: MapboxMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ), + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + FlatButton( + child: const Text('add'), + onPressed: (_symbolCount == 12) ? null : _add, + ), + FlatButton( + child: const Text('remove'), + onPressed: (_selectedSymbol == null) ? null : _remove, + ), + ], + ), + Column( + children: [ + FlatButton( + child: const Text('change alpha'), + onPressed: + (_selectedSymbol == null) ? null : _changeAlpha, + ), + FlatButton( + child: const Text('change anchor'), + onPressed: + (_selectedSymbol == null) ? null : _changeAnchor, + ), + FlatButton( + child: const Text('toggle draggable'), + onPressed: (_selectedSymbol == null) + ? null + : _toggleDraggable, + ), + FlatButton( + child: const Text('change position'), + onPressed: (_selectedSymbol == null) + ? null + : _changePosition, + ), + FlatButton( + child: const Text('change rotation'), + onPressed: (_selectedSymbol == null) + ? null + : _changeRotation, + ), + FlatButton( + child: const Text('toggle visible'), + onPressed: + (_selectedSymbol == null) ? null : _toggleVisible, + ), + FlatButton( + child: const Text('change zIndex'), + onPressed: + (_selectedSymbol == null) ? null : _changeZIndex, + ), + ], + ), + ], + ) + ], + ), + ), + ), + ], + ); + } +} diff --git a/example/lib/scrolling_map.dart b/example/lib/scrolling_map.dart index 8e6187cf5..ce950a675 100644 --- a/example/lib/scrolling_map.dart +++ b/example/lib/scrolling_map.dart @@ -99,12 +99,12 @@ class ScrollingMapBody extends StatelessWidget { } void onMapCreated(MapboxMapController controller) { - controller.addMarker(MarkerOptions( - position: LatLng( + controller.addSymbol(SymbolOptions( + geometry: LatLng( center.latitude, center.longitude, ), - infoWindowText: const InfoWindowText('An interesting location', '*'), + iconImage: "airport-15" )); } } diff --git a/lib/mapbox_gl.dart b/lib/mapbox_gl.dart index bfc09518d..fedc3e4e7 100644 --- a/lib/mapbox_gl.dart +++ b/lib/mapbox_gl.dart @@ -18,6 +18,6 @@ part 'src/callbacks.dart'; part 'src/camera.dart'; part 'src/controller.dart'; part 'src/mapbox_map.dart'; -part 'src/marker.dart'; part 'src/location.dart'; +part 'src/symbol.dart'; part 'src/ui.dart'; diff --git a/lib/src/controller.dart b/lib/src/controller.dart index f7b14ade2..21a8c0b93 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -13,13 +13,13 @@ typedef void OnCameraTrackingDismissedCallback(); /// Change listeners are notified upon changes to any of /// /// * the [options] property -/// * the collection of [Marker]s added to this map +/// * the collection of [Symbol]s added to this map /// * the [isCameraMoving] property /// * the [cameraPosition] property /// /// Listeners are notified after changes have been applied on the platform side. /// -/// Marker tap events can be received by adding callbacks to [onMarkerTapped]. +/// Symbol tap events can be received by adding callbacks to [onSymbolTapped]. class MapboxMapController extends ChangeNotifier { MapboxMapController._( this._id, MethodChannel channel, CameraPosition initialCameraPosition, @@ -50,18 +50,18 @@ class MapboxMapController extends ChangeNotifier { final OnCameraTrackingDismissedCallback onCameraTrackingDismissed; - /// Callbacks to receive tap events for markers placed on this map. - final ArgumentCallbacks onMarkerTapped = ArgumentCallbacks(); + /// Callbacks to receive tap events for symbols placed on this map. + final ArgumentCallbacks onSymbolTapped = ArgumentCallbacks(); - /// Callbacks to receive tap events for info windows on markers - final ArgumentCallbacks onInfoWindowTapped = - ArgumentCallbacks(); + /// Callbacks to receive tap events for info windows on symbols + final ArgumentCallbacks onInfoWindowTapped = + ArgumentCallbacks(); - /// The current set of markers on this map. + /// The current set of symbols on this map. /// - /// The returned set will be a detached snapshot of the markers collection. - Set get markers => Set.from(_markers.values); - final Map _markers = {}; + /// The returned set will be a detached snapshot of the symbols collection. + Set get symbols => Set.from(_symbols.values); + final Map _symbols = {}; /// True if the map camera is currently moving. bool get isCameraMoving => _isCameraMoving; @@ -77,18 +77,17 @@ class MapboxMapController extends ChangeNotifier { Future _handleMethodCall(MethodCall call) async { switch (call.method) { case 'infoWindow#onTap': - final String markerId = call.arguments['marker']; - final Marker marker = _markers[markerId]; - if (marker != null) { - onInfoWindowTapped(marker); + final String symbolId = call.arguments['symbol']; + final Symbol symbol = _symbols[symbolId]; + if (symbol != null) { + onInfoWindowTapped(symbol); } break; - - case 'marker#onTap': - final String markerId = call.arguments['marker']; - final Marker marker = _markers[markerId]; - if (marker != null) { - onMarkerTapped(marker); + case 'symbol#onTap': + final String symbolId = call.arguments['symbol']; + final Symbol symbol = _symbols[symbolId]; + if (symbol != null) { + onSymbolTapped(symbol); } break; case 'camera#onMoveStarted': @@ -160,86 +159,86 @@ class MapboxMapController extends ChangeNotifier { }); } - /// Adds a marker to the map, configured using the specified custom [options]. + /// Adds a symbol to the map, configured using the specified custom [options]. /// - /// Change listeners are notified once the marker has been added on the + /// Change listeners are notified once the symbol has been added on the /// platform side. /// - /// The returned [Future] completes with the added marker once listeners have + /// The returned [Future] completes with the added symbol once listeners have /// been notified. - Future addMarker(MarkerOptions options) async { - final MarkerOptions effectiveOptions = - MarkerOptions.defaultOptions.copyWith(options); - final String markerId = await _channel.invokeMethod( - 'marker#add', + Future addSymbol(SymbolOptions options) async { + final SymbolOptions effectiveOptions = + SymbolOptions.defaultOptions.copyWith(options); + final String symbolId = await _channel.invokeMethod( + 'symbol#add', { 'options': effectiveOptions._toJson(), }, ); - final Marker marker = Marker(markerId, effectiveOptions); - _markers[markerId] = marker; + final Symbol symbol = Symbol(symbolId, effectiveOptions); + _symbols[symbolId] = symbol; notifyListeners(); - return marker; + return symbol; } - /// Updates the specified [marker] with the given [changes]. The marker must - /// be a current member of the [markers] set. + /// Updates the specified [symbol] with the given [changes]. The symbol must + /// be a current member of the [symbols] set. /// - /// Change listeners are notified once the marker has been updated on the + /// Change listeners are notified once the symbol has been updated on the /// platform side. /// /// The returned [Future] completes once listeners have been notified. - Future updateMarker(Marker marker, MarkerOptions changes) async { - assert(marker != null); - assert(_markers[marker._id] == marker); + Future updateSymbol(Symbol symbol, SymbolOptions changes) async { + assert(symbol != null); + assert(_symbols[symbol._id] == symbol); assert(changes != null); - await _channel.invokeMethod('marker#update', { - 'marker': marker._id, + await _channel.invokeMethod('symbol#update', { + 'symbol': symbol._id, 'options': changes._toJson(), }); - marker._options = marker._options.copyWith(changes); + symbol._options = symbol._options.copyWith(changes); notifyListeners(); } - /// Removes the specified [marker] from the map. The marker must be a current - /// member of the [markers] set. + /// Removes the specified [symbol] from the map. The symbol must be a current + /// member of the [symbols] set. /// - /// Change listeners are notified once the marker has been removed on the + /// Change listeners are notified once the symbol has been removed on the /// platform side. /// /// The returned [Future] completes once listeners have been notified. - Future removeMarker(Marker marker) async { - assert(marker != null); - assert(_markers[marker._id] == marker); - await _removeMarker(marker._id); + Future removeSymbol(Symbol symbol) async { + assert(symbol != null); + assert(_symbols[symbol._id] == symbol); + await _removeSymbol(symbol._id); notifyListeners(); } - /// Removes all [markers] from the map. + /// Removes all [symbols] from the map. /// - /// Change listeners are notified once all markers have been removed on the + /// Change listeners are notified once all symbols have been removed on the /// platform side. /// /// The returned [Future] completes once listeners have been notified. - Future clearMarkers() async { - assert(_markers != null); - final List markerIds = List.from(_markers.keys); - for (String id in markerIds) { - await _removeMarker(id); + Future clearSymbols() async { + assert(_symbols != null); + final List symbolIds = List.from(_symbols.keys); + for (String id in symbolIds) { + await _removeSymbol(id); } notifyListeners(); } - /// Helper method to remove a single marker from the map. Consumed by - /// [removeMarker] and [clearMarkers]. + /// Helper method to remove a single symbol from the map. Consumed by + /// [removeSymbol] and [clearSymbols]. /// - /// The returned [Future] completes once the marker has been removed from - /// [_markers]. - Future _removeMarker(String id) async { - await _channel.invokeMethod('marker#remove', { - 'marker': id, + /// The returned [Future] completes once the symbol has been removed from + /// [_symbols]. + Future _removeSymbol(String id) async { + await _channel.invokeMethod('symbol#remove', { + 'symbol': id, }); - _markers.remove(id); + _symbols.remove(id); } Future queryRenderedFeatures( diff --git a/lib/src/marker.dart b/lib/src/marker.dart deleted file mode 100644 index 5e0b1ab58..000000000 --- a/lib/src/marker.dart +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -part of mapbox_gl; - -/// An icon placed at a particular geographical location on the map's surface. -/// A marker icon is drawn oriented against the device's screen rather than the -/// map's surface; that is, it will not necessarily change orientation due to -/// map rotations, tilting, or zooming. -/// -/// Markers are owned by a single [MapboxMapController] which fires events -/// as markers are added, updated, tapped, and removed. -class Marker { - @visibleForTesting - Marker(this._id, this._options); - - /// A unique identifier for this marker. - /// - /// The identirifer is an arbitrary unique string. - final String _id; - String get id => _id; - - MarkerOptions _options; - - /// The marker configuration options most recently applied programmatically - /// via the map controller. - /// - /// The returned value does not reflect any changes made to the marker through - /// touch events. Add listeners to the owning map controller to track those. - MarkerOptions get options => _options; -} - -dynamic _offsetToJson(Offset offset) { - if (offset == null) { - return null; - } - return [offset.dx, offset.dy]; -} - -/// Text labels for a [Marker] info window. -class InfoWindowText { - const InfoWindowText(this.title, this.snippet); - - /// Text labels specifying that no text is to be displayed. - static const InfoWindowText noText = InfoWindowText(null, null); - - /// Text displayed in an info window when the user taps the marker. - /// - /// A null value means no title. - final String title; - - /// Additional text displayed below the [title]. - /// - /// A null value means no additional text. - final String snippet; - - dynamic _toJson() => [title, snippet]; -} - -/// Configuration options for [Marker] instances. -/// -/// When used to change configuration, null values will be interpreted as -/// "do not change this configuration option". -class MarkerOptions { - /// Creates a set of marker configuration options. - /// - /// By default, every non-specified field is null, meaning no desire to change - /// marker defaults or current configuration. - const MarkerOptions({ - this.alpha, - this.anchor, - this.consumeTapEvents, - this.draggable, - this.flat, - this.icon, - this.infoWindowAnchor, - this.infoWindowText, - this.position, - this.rotation, - this.visible, - this.zIndex, - }) : assert(alpha == null || (0.0 <= alpha && alpha <= 1.0)); - - /// The opacity of the marker, between 0.0 and 1.0 inclusive. - /// - /// 0.0 means fully transparent, 1.0 means fully opaque. - final double alpha; - - /// The icon image point that will be placed at the [position] of the marker. - /// - /// The image point is specified in normalized coordinates: An anchor of - /// (0.0, 0.0) means the top left corner of the image. An anchor - /// of (1.0, 1.0) means the bottom right corner of the image. - final Offset anchor; - - /// True if the marker icon consumes tap events. If not, the map will perform - /// default tap handling by centering the map on the marker and displaying its - /// info window. - final bool consumeTapEvents; - - /// True if the marker is draggable by user touch events. - final bool draggable; - - /// True if the marker is rendered flatly against the surface of the Earth, so - /// that it will rotate and tilt along with map camera movements. - final bool flat; - - /// A description of the bitmap used to draw the marker icon. - final BitmapDescriptor icon; - - /// The icon image point that will be the anchor of the info window when - /// displayed. - /// - /// The image point is specified in normalized coordinates: An anchor of - /// (0.0, 0.0) means the top left corner of the image. An anchor - /// of (1.0, 1.0) means the bottom right corner of the image. - final Offset infoWindowAnchor; - - /// Text content for the info window. - final InfoWindowText infoWindowText; - - /// Geographical location of the marker. - final LatLng position; - - /// Rotation of the marker image in degrees clockwise from the [anchor] point. - final double rotation; - - /// True if the marker is visible. - final bool visible; - - /// The z-index of the marker, used to determine relative drawing order of - /// map overlays. - /// - /// Overlays are drawn in order of z-index, so that lower values means drawn - /// earlier, and thus appearing to be closer to the surface of the Earth. - final double zIndex; - - /// Default marker options. - /// - /// Specifies a marker that - /// * is fully opaque; [alpha] is 1.0 - /// * uses icon bottom center to indicate map position; [anchor] is (0.5, 1.0) - /// * has default tap handling; [consumeTapEvents] is false - /// * is stationary; [draggable] is false - /// * is drawn against the screen, not the map; [flat] is false - /// * has a default icon; [icon] is `BitmapDescriptor.defaultMarker` - /// * anchors the info window at top center; [infoWindowAnchor] is (0.5, 0.0) - /// * has no info window text; [infoWindowText] is `InfoWindowText.noText` - /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)` - /// * has an axis-aligned icon; [rotation] is 0.0 - /// * is visible; [visible] is true - /// * is placed at the base of the drawing order; [zIndex] is 0.0 - static const MarkerOptions defaultOptions = MarkerOptions( - alpha: 1.0, - anchor: Offset(0.5, 1.0), - consumeTapEvents: false, - draggable: false, - flat: false, - icon: BitmapDescriptor.defaultMarker, - infoWindowAnchor: Offset(0.5, 0.0), - infoWindowText: InfoWindowText.noText, - position: LatLng(0.0, 0.0), - rotation: 0.0, - visible: true, - zIndex: 0.0, - ); - - /// Creates a new options object whose values are the same as this instance, - /// unless overwritten by the specified [changes]. - /// - /// Returns this instance, if [changes] is null. - MarkerOptions copyWith(MarkerOptions changes) { - if (changes == null) { - return this; - } - return MarkerOptions( - alpha: changes.alpha ?? alpha, - anchor: changes.anchor ?? anchor, - consumeTapEvents: changes.consumeTapEvents ?? consumeTapEvents, - draggable: changes.draggable ?? draggable, - flat: changes.flat ?? flat, - icon: changes.icon ?? icon, - infoWindowAnchor: changes.infoWindowAnchor ?? infoWindowAnchor, - infoWindowText: changes.infoWindowText ?? infoWindowText, - position: changes.position ?? position, - rotation: changes.rotation ?? rotation, - visible: changes.visible ?? visible, - zIndex: changes.zIndex ?? zIndex, - ); - } - - dynamic _toJson() { - final Map json = {}; - - void addIfPresent(String fieldName, dynamic value) { - if (value != null) { - json[fieldName] = value; - } - } - - addIfPresent('alpha', alpha); - addIfPresent('anchor', _offsetToJson(anchor)); - addIfPresent('consumeTapEvents', consumeTapEvents); - addIfPresent('draggable', draggable); - addIfPresent('flat', flat); - addIfPresent('icon', icon?._toJson()); - addIfPresent('infoWindowAnchor', _offsetToJson(infoWindowAnchor)); - addIfPresent('infoWindowText', infoWindowText?._toJson()); - addIfPresent('position', position?._toJson()); - addIfPresent('rotation', rotation); - addIfPresent('visible', visible); - addIfPresent('zIndex', zIndex); - return json; - } -} diff --git a/lib/src/symbol.dart b/lib/src/symbol.dart new file mode 100644 index 000000000..54cffaca5 --- /dev/null +++ b/lib/src/symbol.dart @@ -0,0 +1,182 @@ +// This file is generated. + +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +part of mapbox_gl; + +class Symbol { + @visibleForTesting + Symbol(this._id, this._options); + + /// A unique identifier for this symbol. + /// + /// The identifier is an arbitrary unique string. + final String _id; + + String get id => _id; + + SymbolOptions _options; + + /// The symbol configuration options most recently applied programmatically + /// via the map controller. + /// + /// The returned value does not reflect any changes made to the symbol through + /// touch events. Add listeners to the owning map controller to track those. + SymbolOptions get options => _options; +} + +dynamic _offsetToJson(Offset offset) { + if (offset == null) { + return null; + } + return [offset.dx, offset.dy]; +} + +/// Configuration options for [Symbol] instances. +/// +/// When used to change configuration, null values will be interpreted as +/// "do not change this configuration option". +class SymbolOptions { + /// Creates a set of symbol configuration options. + /// + /// By default, every non-specified field is null, meaning no desire to change + /// symbol defaults or current configuration. + const SymbolOptions({ + this.iconSize, + this.iconImage, + this.iconRotate, + this.iconOffset, + this.iconAnchor, + this.textField, + this.textSize, + this.textMaxWidth, + this.textLetterSpacing, + this.textJustify, + this.textAnchor, + this.textRotate, + this.textTransform, + this.textOffset, + this.iconOpacity, + this.iconColor, + this.iconHaloColor, + this.iconHaloWidth, + this.iconHaloBlur, + this.textOpacity, + this.textColor, + this.textHaloColor, + this.textHaloWidth, + this.textHaloBlur, + this.geometry, + this.zIndex, + this.draggable, + }); + + final double iconSize; + final String iconImage; + final double iconRotate; + final Offset iconOffset; + final String iconAnchor; + final String textField; + final double textSize; + final double textMaxWidth; + final double textLetterSpacing; + final String textJustify; + final String textAnchor; + final double textRotate; + final String textTransform; + final Offset textOffset; + final double iconOpacity; + final String iconColor; + final String iconHaloColor; + final double iconHaloWidth; + final double iconHaloBlur; + final double textOpacity; + final String textColor; + final String textHaloColor; + final double textHaloWidth; + final double textHaloBlur; + final LatLng geometry; + final int zIndex; + final bool draggable; + + static const SymbolOptions defaultOptions = SymbolOptions( + + ); + + SymbolOptions copyWith(SymbolOptions changes) { + if (changes == null) { + return this; + } + return SymbolOptions( + iconSize: changes.iconSize ?? iconSize, + iconImage: changes.iconImage ?? iconImage, + iconRotate: changes.iconRotate ?? iconRotate, + iconOffset: changes.iconOffset ?? iconOffset, + iconAnchor: changes.iconAnchor ?? iconAnchor, + textField: changes.textField ?? textField, + textSize: changes.textSize ?? textSize, + textMaxWidth: changes.textMaxWidth ?? textMaxWidth, + textLetterSpacing: changes.textLetterSpacing ?? textLetterSpacing, + textJustify: changes.textJustify ?? textJustify, + textAnchor: changes.textAnchor ?? textAnchor, + textRotate: changes.textRotate ?? textRotate, + textTransform: changes.textTransform ?? textTransform, + textOffset: changes.textOffset ?? textOffset, + iconOpacity: changes.iconOpacity ?? iconOpacity, + iconColor: changes.iconColor ?? iconColor, + iconHaloColor: changes.iconHaloColor ?? iconHaloColor, + iconHaloWidth: changes.iconHaloWidth ?? iconHaloWidth, + iconHaloBlur: changes.iconHaloBlur ?? iconHaloBlur, + textOpacity: changes.textOpacity ?? textOpacity, + textColor: changes.textColor ?? textColor, + textHaloColor: changes.textHaloColor ?? textHaloColor, + textHaloWidth: changes.textHaloWidth ?? textHaloWidth, + textHaloBlur: changes.textHaloBlur ?? textHaloBlur, + geometry: changes.geometry ?? geometry, + zIndex: changes.zIndex ?? zIndex, + draggable: changes.draggable ?? draggable, + ); + } + + dynamic _toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('iconSize', iconSize); + addIfPresent('iconImage', iconImage); + addIfPresent('iconRotate', iconRotate); + addIfPresent('iconOffset', _offsetToJson(iconOffset)); + addIfPresent('iconAnchor', iconAnchor); + addIfPresent('textField', textField); + addIfPresent('textSize', textSize); + addIfPresent('textMaxWidth', textMaxWidth); + addIfPresent('textLetterSpacing', textLetterSpacing); + addIfPresent('textJustify', textJustify); + addIfPresent('textAnchor', textAnchor); + addIfPresent('textRotate', textRotate); + addIfPresent('textTransform', textTransform); + addIfPresent('textOffset', _offsetToJson(textOffset)); + addIfPresent('iconOpacity', iconOpacity); + addIfPresent('iconColor', iconColor); + addIfPresent('iconHaloColor', iconHaloColor); + addIfPresent('iconHaloWidth', iconHaloWidth); + addIfPresent('iconHaloBlur', iconHaloBlur); + addIfPresent('textOpacity', textOpacity); + addIfPresent('textColor', textColor); + addIfPresent('textHaloColor', textHaloColor); + addIfPresent('textHaloWidth', textHaloWidth); + addIfPresent('textHaloBlur', textHaloBlur); + addIfPresent('geometry', geometry?._toJson()); + addIfPresent('zIndex', zIndex); + addIfPresent('draggable', draggable); + return json; + } + +} \ No newline at end of file