diff --git a/.github/label-actions.yml b/.github/label-actions.yml index df3e2350c..67e655920 100644 --- a/.github/label-actions.yml +++ b/.github/label-actions.yml @@ -19,4 +19,8 @@ :thinking: @{issue-author}, closing the issue for lack of activity, if the issue still persist, pls open a new one with steps to reproduce on recent versions # Close the issue close: true +"Needs: Project setup instructions": + comment: > + @{issue-author}, sorry for us to look into project setup issues, we require steps to reproduce from `react-native init ...`. If you cannot reproduce starting with a blank project, then compare your setup with a blank working one. + close: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 18850c8d7..d0facd61f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,19 +5,22 @@ Please add unreleased changes in the following style: PR Title ([#123](link to my pr)) ``` -Implement clustering properties to ShapeSource ([#1745](https://github.com/react-native-mapbox-gl/maps/pull/1745)) - -### UNRELEASED/10.0.0-beta.0 +### UNRELEASED/10.0.0-beta.10 #### Breaking changes: The setup was changed - see install instructions for more details. In a nuthsell: * On both android/ios to select mapbox implementation use `RNMapboxMapsImpl`/`$RNMapboxMapsImpl` variable which can be one of (`maplibre`,`mapbox`(aka v10),`mapbox-gl`) +* Default implementation is `maplibre` as it requires not further setup. *WARNING* using mapbox styles from `maplibre` has different pricing than mapbox native sdk-s. * On Podfile `$RNMBGL.(pre|post)_install` was changed `$RNMapboxMaps.(pre|post)_install` * Package name was changed from `@react-native-mapbox-gl/maps` to `@rnmapbox/maps`. If you just testing with the v10 version you can use something like [babel-plugin-transform-rename-import](https://www.npmjs.com/package/babel-plugin-transform-rename-import) to keep using the old imports for a while. +* `MapboxGL.setAccessToken` now requires `MapboxGL.setWellKnownTileServer` on maplibre. + + #### Changes: +- Implement clustering properties to ShapeSource ([#1745](https://github.com/react-native-mapbox-gl/maps/pull/1745)) - Initial Mapbox V10 support ([#1750](https://github.com/rnmapbox/maps/pull/1750)) - Updated MapLibre on Android to 9.5.2 ([#1780](https://github.com/rnmapbox/maps/pull/1780)) diff --git a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java index bac7bbfff..6019a22fe 100644 --- a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java +++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java @@ -751,6 +751,7 @@ public void onDidFinishRenderingMap(boolean fully) { for (Pair preRenderMethod : mPreRenderMethods) { Integer methodID = preRenderMethod.first; ReadableArray args = preRenderMethod.second; + mManager.receiveCommand(this, methodID, args); } mPreRenderMethods.clear(); diff --git a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java index 3e90d253e..32ed74561 100644 --- a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java +++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java @@ -246,6 +246,7 @@ public Map getCommandsMap() { @Override public void receiveCommand(RCTMGLMapView mapView, int commandID, @Nullable ReadableArray args) { + String callbackID = args.getString(0); // allows method calls to work with componentDidMount MapboxMap mapboxMap = mapView.getMapboxMap(); if (mapboxMap == null) { @@ -256,41 +257,42 @@ public void receiveCommand(RCTMGLMapView mapView, int commandID, @Nullable Reada switch (commandID) { case METHOD_QUERY_FEATURES_POINT: mapView.queryRenderedFeaturesAtPoint( - args.getString(0), + callbackID, ConvertUtils.toPointF(args.getArray(1)), ExpressionParser.from(args.getArray(2)), ConvertUtils.toStringList(args.getArray(3))); break; case METHOD_QUERY_FEATURES_RECT: mapView.queryRenderedFeaturesInRect( - args.getString(0), + callbackID, ConvertUtils.toRectF(args.getArray(1)), ExpressionParser.from(args.getArray(2)), ConvertUtils.toStringList(args.getArray(3))); break; case METHOD_VISIBLE_BOUNDS: - mapView.getVisibleBounds(args.getString(0)); + mapView.getVisibleBounds(callbackID); break; case METHOD_GET_POINT_IN_VIEW: - mapView.getPointInView(args.getString(0), GeoJSONUtils.toLatLng(args.getArray(1))); + mapView.getPointInView(callbackID, GeoJSONUtils.toLatLng(args.getArray(1))); break; case METHOD_GET_COORDINATE_FROM_VIEW: - mapView.getCoordinateFromView(args.getString(0), ConvertUtils.toPointF(args.getArray(1))); + mapView.getCoordinateFromView(callbackID, ConvertUtils.toPointF(args.getArray(1))); break; case METHOD_TAKE_SNAP: - mapView.takeSnap(args.getString(0), args.getBoolean(1)); + mapView.takeSnap(callbackID, args.getBoolean(1)); break; case METHOD_GET_ZOOM: - mapView.getZoom(args.getString(0)); + mapView.getZoom(callbackID); break; case METHOD_GET_CENTER: - mapView.getCenter(args.getString(0)); + mapView.getCenter(callbackID); break; case METHOD_SET_HANDLED_MAP_EVENTS: if(args != null) { + ReadableArray events = args.getArray(1); ArrayList eventsArray = new ArrayList<>(); - for (int i = 1; i < args.size(); i++) { - eventsArray.add(args.getString(i)); + for (int i = 0; i < events.size(); i++) { + eventsArray.add(events.getString(i)); } mapView.setHandledMapChangedEvents(eventsArray); } diff --git a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java index 4fa6d9393..348d45b1a 100644 --- a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java +++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java @@ -249,7 +249,16 @@ public Map getConstants() { Map locationModuleCallbackNames = new HashMap<>(); locationModuleCallbackNames.put("Update", RCTMGLLocationModule.LOCATION_UPDATE); + // tileServer + Map tileServers = InstanceManagerImpl.getTileServers(); + + // implementation + Map implementation = new HashMap<>(); + implementation.put("Library", InstanceManagerImpl.getLibraryName()); + return MapBuilder.builder() + .put("TileServers", tileServers) + .put("Implementation", implementation) .put("StyleURL", styleURLS) .put("EventTypes", eventTypes) .put("UserTrackingModes", userTrackingModes) @@ -284,6 +293,11 @@ public Map getConstants() { .build(); } + @ReactMethod + public void setWellKnownTileServer(final String tileServer) { + InstanceManagerImpl.setWellKnownTileServer(tileServer); + } + @ReactMethod public void setAccessToken(final String accessToken) { mReactContext.runOnUiQueueThread(new Runnable() { diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java index 4a97e55d7..02d6faf6a 100644 --- a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java +++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java @@ -8,7 +8,24 @@ public static void getInstance(Context context, String accessToken) { Mapbox.getInstance(context, accessToken); } + public static void setWellKnownTileServer(String wellKnownTileServer) { + if (wellKnownTileServer != "mapbox") { + Logger.w("InstanceManagerImpl", "setWellKnownTileServer: only mapbox is supported"); + return; + } + } + public static String getAccessToken() { return Mapbox.getAccessToken(); } + + public static String getLibraryName() { + return "mapbox-gl"; + } + + public static Map getTileServers() { + HashMap result = new HashMap(); + result.put("Mapbox", "mapbox"); + return result; + } } diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java index 3d11fc70c..866405dab 100644 --- a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java +++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java @@ -1,15 +1,42 @@ package com.mapbox.rctmgl.impl; import android.content.Context; + import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.WellKnownTileServer; +import com.mapbox.mapboxsdk.log.Logger; + +import java.util.HashMap; +import java.util.Map; public class InstanceManagerImpl { public static void getInstance(Context context, String accessToken) { - Mapbox.getInstance(context, accessToken, WellKnownTileServer.Mapbox); + if (wellKnownTileServer == null) { + Logger.w("InstanceManagerImpl", "setAccessToken requires setWellKnownTileServer for MapLibre, see setWellKnownTileServer docs for implications"); + wellKnownTileServer = WellKnownTileServer.MapLibre.name(); + } + Mapbox.getInstance(context, accessToken, WellKnownTileServer.valueOf(wellKnownTileServer) ); + } + + public static Map getTileServers() { + HashMap result = new HashMap(); + result.put("Mapbox", WellKnownTileServer.Mapbox.name()); + result.put("MapLibre", WellKnownTileServer.MapLibre.name()); + result.put("MapTiler", WellKnownTileServer.MapTiler.name()); + return result; + } + + static String wellKnownTileServer = null; + + public static void setWellKnownTileServer(String wellKnownTileServer) { + InstanceManagerImpl.wellKnownTileServer = wellKnownTileServer; } public static String getAccessToken() { - return null; + return Mapbox.getApiKey(); + } + + public static String getLibraryName() { + return "maplibre"; } } diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt index 77f3ac814..81b3bfb4e 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt @@ -179,11 +179,7 @@ class RCTMGLImages(context: Context, private val mManager: RCTMGLImagesManager) if (missingImages.size > 0) { val task = DownloadMapImageTask(context, map, null) val params = missingImages.toTypedArray() - for (param in params) { - task.execute(param) - } - - + task.execute(*params) } } diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt index d9c97691f..2e0d69957 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt @@ -15,20 +15,17 @@ import com.mapbox.geojson.Feature import com.mapbox.geojson.Point import com.mapbox.maps.* import com.mapbox.maps.extension.observable.eventdata.MapLoadingErrorEventData +import com.mapbox.maps.extension.observable.eventdata.StyleImageMissingEventData import com.mapbox.maps.extension.style.layers.Layer import com.mapbox.maps.extension.style.layers.generated.* import com.mapbox.maps.extension.style.layers.getLayer -import com.mapbox.maps.extension.style.utils.unwrap import com.mapbox.maps.extension.style.layers.properties.generated.Visibility import com.mapbox.maps.plugin.annotation.annotations import com.mapbox.maps.plugin.annotation.generated.OnPointAnnotationClickListener import com.mapbox.maps.plugin.annotation.generated.PointAnnotation import com.mapbox.maps.plugin.annotation.generated.PointAnnotationManager import com.mapbox.maps.plugin.annotation.generated.createPointAnnotationManager -import com.mapbox.maps.plugin.delegates.listeners.OnCameraChangeListener -import com.mapbox.maps.plugin.delegates.listeners.OnMapIdleListener -import com.mapbox.maps.plugin.delegates.listeners.OnMapLoadErrorListener -import com.mapbox.maps.plugin.delegates.listeners.OnMapLoadedListener +import com.mapbox.maps.plugin.delegates.listeners.* import com.mapbox.maps.plugin.gestures.* import com.mapbox.rctmgl.R import com.mapbox.rctmgl.components.AbstractMapFeature @@ -363,7 +360,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV ScreenCoordinate(screenPoint.x + halfWidth, screenPoint.y + halfHeight) ) - getMapboxMap().queryRenderedFeatures(screenBox, + getMapboxMap().queryRenderedFeatures(RenderedQueryGeometry(screenBox), RenderedQueryOptions( source.layerIDs, null @@ -379,7 +376,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV hitTouchableSources.add(source) } } else { - Logger.e("handleTapInSources", features.error) + Logger.e("handleTapInSources", features.error ?: "n/a") } handleTapInSources(sources, screenPoint, hits, hitTouchableSources, handleTap) } @@ -755,5 +752,15 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV onMapReady(mMap) val _this = this mMap.addOnMapLoadedListener(OnMapLoadedListener { (begin, end) -> _this.handleMapChangedEvent(EventTypes.DID_FINISH_LOADING_MAP) }) + mMap.addOnStyleImageMissingListener(OnStyleImageMissingListener { (begin, end, id) -> + for (images in mImages) { + if (images.addMissingImageToStyle(id, mMap)) { + return@OnStyleImageMissingListener + } + } + for (images in mImages) { + images.sendImageMissingEvent(id, mMap) + } + }) } } \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java deleted file mode 100644 index c8f1f5441..000000000 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.mapbox.rctmgl.components.styles; - -import android.content.Context; -import androidx.annotation.NonNull; - -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableMapKeySetIterator; -import com.mapbox.maps.MapboxMap; -import com.mapbox.rctmgl.utils.DownloadMapImageTask; -import com.mapbox.rctmgl.utils.ImageEntry; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class RCTMGLStyle { - private Context mContext; - private ReadableMap mReactStyle; - private MapboxMap mMap; - - public RCTMGLStyle(@NonNull Context context, @NonNull ReadableMap reactStyle, @NonNull MapboxMap map) { - mContext = context; - mReactStyle = reactStyle; - mMap = map; - } - - public List getAllStyleKeys() { - if (mReactStyle == null) { - return new ArrayList<>(); - } - - ReadableMapKeySetIterator it = mReactStyle.keySetIterator(); - List keys = new ArrayList<>(); - - while (it.hasNextKey()) { - String key = it.nextKey(); - - if (!key.equals("__MAPBOX_STYLESHEET__")) { - keys.add(key); - } - } - - return keys; - } - - public RCTMGLStyleValue getStyleValueForKey(String styleKey) { - ReadableMap styleValueConfig = mReactStyle.getMap(styleKey); - - if (styleValueConfig == null) { - // TODO: throw exeception here - return null; - } - - return new RCTMGLStyleValue(styleValueConfig); - } - - public void addImage(RCTMGLStyleValue styleValue) { - addImage(styleValue, null); - } - - public ImageEntry imageEntry(RCTMGLStyleValue styleValue) { - return new ImageEntry(styleValue.getImageURI(), styleValue.getImageScale()); - } - - public void addImage(RCTMGLStyleValue styleValue, DownloadMapImageTask.OnAllImagesLoaded callback) { - if (!styleValue.shouldAddImage()) { - if (callback != null) { - callback.onAllImagesLoaded(); - } - return; - } - - String uriStr = styleValue.getImageURI(); - Map.Entry[] images = new Map.Entry[]{ new AbstractMap.SimpleEntry(uriStr, imageEntry(styleValue)) }; - DownloadMapImageTask task = new DownloadMapImageTask(mContext, mMap, callback); - task.execute(images); - } -} diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt new file mode 100644 index 000000000..7ec9adcaa --- /dev/null +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt @@ -0,0 +1,62 @@ +package com.mapbox.rctmgl.components.styles + +import android.content.Context +import com.facebook.react.bridge.ReadableMap +import com.mapbox.maps.MapboxMap +import com.mapbox.rctmgl.utils.ImageEntry +import com.mapbox.rctmgl.utils.DownloadMapImageTask +import java.util.AbstractMap +import java.util.ArrayList + +class RCTMGLStyle(private val mContext: Context, reactStyle: ReadableMap, map: MapboxMap) { + private val mReactStyle: ReadableMap? + private val mMap: MapboxMap + val allStyleKeys: List + get() { + if (mReactStyle == null) { + return ArrayList() + } + val it = mReactStyle.keySetIterator() + val keys: MutableList = ArrayList() + while (it.hasNextKey()) { + val key = it.nextKey() + if (key != "__MAPBOX_STYLESHEET__") { + keys.add(key) + } + } + return keys + } + + fun getStyleValueForKey(styleKey: String?): RCTMGLStyleValue? { + val styleValueConfig = mReactStyle!!.getMap(styleKey!!) + ?: // TODO: throw exeception here + return null + return RCTMGLStyleValue(styleValueConfig) + } + + fun imageEntry(styleValue: RCTMGLStyleValue): ImageEntry { + return ImageEntry(styleValue.imageURI, styleValue.imageScale) + } + + @JvmOverloads + fun addImage(styleValue: RCTMGLStyleValue, callback: DownloadMapImageTask.OnAllImagesLoaded? = null) { + if (!styleValue.shouldAddImage()) { + callback?.onAllImagesLoaded() + return + } + val uriStr = styleValue.imageURI + val images = arrayOf>( + AbstractMap.SimpleEntry( + uriStr, + imageEntry(styleValue) + ) + ) + val task = DownloadMapImageTask(mContext, mMap, callback) + task.execute(*images) + } + + init { + mReactStyle = reactStyle + mMap = map + } +} \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt index b88b81f94..d61a25595 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt @@ -183,7 +183,7 @@ class RCTMGLStyleValue(config: ReadableMap) { init { type = config.getString("styletype") mPayload = config.getMap("stylevalue") - var isAddImage = false + isAddImage = false if ("image" == type) { imageScale = ImageEntry.defaultScale if ("hashmap" == mPayload!!.getString("type")) { diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java deleted file mode 100644 index 0e30d4f81..000000000 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java +++ /dev/null @@ -1,301 +0,0 @@ -package com.mapbox.rctmgl.components.styles.layers; - -import android.content.Context; - -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.common.logging.FLog; - -import com.mapbox.maps.extension.style.StyleContract; -import com.mapbox.maps.extension.style.layers.Layer; -import com.mapbox.maps.MapboxMap; -import com.mapbox.maps.Style; -import com.mapbox.maps.extension.style.expressions.generated.Expression; -import com.mapbox.maps.extension.style.layers.properties.generated.Visibility; -import com.mapbox.maps.extension.style.layers.LayerUtils; - - -import com.mapbox.rctmgl.components.AbstractMapFeature; -import com.mapbox.rctmgl.components.mapview.RCTMGLMapView; -import com.mapbox.rctmgl.components.styles.sources.AbstractSourceConsumer; -import com.mapbox.rctmgl.utils.ExpressionParser; -// import com.mapbox.rctmgl.utils.ExpressionParser; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - - -public abstract class RCTLayer extends AbstractSourceConsumer { - public static final String LOG_TAG = "RCTLayer"; - - protected String mID; - protected String mSourceID; - protected String mAboveLayerID; - protected String mBelowLayerID; - - protected Integer mLayerIndex; - protected boolean mVisible; - protected Double mMinZoomLevel; - protected Double mMaxZoomLevel; - protected ReadableMap mReactStyle; - protected Expression mFilter; - - protected MapboxMap mMap; - protected T mLayer; - - protected Context mContext; - protected RCTMGLMapView mMapView; - - protected boolean mHadFilter; - - public RCTLayer(Context context) { - super(context); - mContext = context; - mHadFilter = false; - } - - public String getID() { - return mID; - } - - public void setID(String id) { - mID = id; - } - - public void setSourceID(String sourceID) { - mSourceID = sourceID; - } - - public void setAboveLayerID(String aboveLayerID) { - if (mAboveLayerID != null && mAboveLayerID.equals(aboveLayerID)) { - return; - } - - mAboveLayerID = aboveLayerID; - if (mLayer != null) { - removeFromMap(mMapView); - addAbove(mAboveLayerID); - } - } - - public void setBelowLayerID(String belowLayerID) { - if (mBelowLayerID != null && mBelowLayerID.equals(belowLayerID)) { - return; - } - - mBelowLayerID = belowLayerID; - if (mLayer != null) { - removeFromMap(mMapView); - addBelow(mBelowLayerID); - } - } - - public void setLayerIndex(int layerIndex) { - if (mLayerIndex != null && mLayerIndex == layerIndex) { - return; - } - - mLayerIndex = layerIndex; - if (mLayer != null) { - removeFromMap(mMapView); - addAtIndex(mLayerIndex); - } - } - - public void setVisible(boolean visible) { - mVisible = visible; - - if (mLayer != null) { - mLayer.visibility(mVisible ? Visibility.VISIBLE : Visibility.NONE); - } - } - - public void setMinZoomLevel(double minZoomLevel) { - mMinZoomLevel = minZoomLevel; - - if (mLayer != null) { - mLayer.minZoom((float) minZoomLevel); - } - } - - public void setMaxZoomLevel(double maxZoomLevel) { - mMaxZoomLevel = maxZoomLevel; - - if (mLayer != null) { - mLayer.maxZoom((float) maxZoomLevel); - } - } - - public void setReactStyle(ReadableMap reactStyle) { - mReactStyle = reactStyle; - - if (mLayer != null) { - addStyles(); - } - } - - public void setFilter(ReadableArray readableFilterArray) { - Expression filterExpression = ExpressionParser.from(readableFilterArray); - - mFilter = filterExpression; - - if (mLayer != null) { - if (mFilter != null) { - mHadFilter = true; - updateFilter(mFilter); - } else if (mHadFilter) { - updateFilter(Expression.literal(true)); - } - } - } - - public void add() { - if (!hasInitialized()) { - return; - } - if (getStyle() == null) return; - - /* V10TODO - String userBackgroundID = LocationComponentConstants.BACKGROUND_LAYER; - Layer userLocationBackgroundLayer = getStyle().getLayer(userBackgroundID); - - // place below user location layer - if (userLocationBackgroundLayer != null) { - getStyle().addLayerBelow(mLayer, userBackgroundID); - mMapView.layerAdded(mLayer); - return; - } */ - - LayerUtils.addLayer(getStyle(), (StyleContract.StyleLayerExtension) mLayer); - mMapView.layerAdded(mLayer); - } - - public void addAbove(final String aboveLayerID) { - mMapView.waitForLayer(aboveLayerID, new RCTMGLMapView.FoundLayerCallback() { - public void found(Layer layer) { - if (!hasInitialized()) { - return; - } - if (getStyle() == null) return; - LayerUtils.addLayerAbove(getStyle(), (StyleContract.StyleLayerExtension) mLayer, aboveLayerID); - mMapView.layerAdded(mLayer); - } - }); - } - - public void addBelow(final String belowLayerID) { - mMapView.waitForLayer(belowLayerID, new RCTMGLMapView.FoundLayerCallback() { - public void found(Layer layer) { - if (!hasInitialized()) { - return; - } - if (getStyle() == null) return; - LayerUtils.addLayerBelow(getStyle(), (StyleContract.StyleLayerExtension) mLayer, belowLayerID); - mMapView.layerAdded(mLayer); - } - }); - } - - public void addAtIndex(int index) { - if (!hasInitialized()) { - return; - } - if (getStyle() == null) return; - int layerSize = getStyle().getStyleLayers().size(); - if (index >= layerSize) { - FLog.e(LOG_TAG, "Layer index is greater than number of layers on map. Layer inserted at end of layer stack."); - index = layerSize - 1; - } - LayerUtils.addLayerAt(getStyle(), (StyleContract.StyleLayerExtension) mLayer, index); - mMapView.layerAdded(mLayer); - } - - protected void insertLayer() { - if (getStyle() == null) return; - if (LayerUtils.getLayer(getStyle(), mID) != null) { - return; // prevent adding a layer twice - } - - if (mAboveLayerID != null) { - addAbove(mAboveLayerID); - } else if (mBelowLayerID != null) { - addBelow(mBelowLayerID); - } else if (mLayerIndex != null) { - addAtIndex(mLayerIndex); - } else { - add(); - } - - setZoomBounds(); - } - - protected void setZoomBounds() { - if (mMaxZoomLevel != null) { - mLayer.maxZoom(mMaxZoomLevel.floatValue()); - } - - if (mMinZoomLevel != null) { - mLayer.minZoom(mMinZoomLevel.floatValue()); - } - } - - protected void updateFilter(Expression expression) { - // override if you want to update the filter - } - - private T getLayerAs(Style style, String id) { - Layer result = LayerUtils.getLayer(style, mID); - - try { - return (T)result; - } catch (ClassCastException exception) { - return null; - } - } - - @Override - public void addToMap(RCTMGLMapView mapView) { - mMap = mapView.getMapboxMap(); - mMapView = mapView; - - if (getStyle() == null) return; - - T existingLayer = getLayerAs(getStyle(), mID); - if (existingLayer != null) { - mLayer = existingLayer; - } else { - mLayer = makeLayer(); - insertLayer(); - } - - addStyles(); - if (mFilter != null) { - mHadFilter = true; - updateFilter(mFilter); - } - } - - @Override - public void removeFromMap(RCTMGLMapView mapView) { - if (getStyle() != null) { - getStyle().removeStyleLayer(mLayer.getLayerId()); - } - } - - private Style getStyle() { - // v10TOOD: adding anything seems to make getStyle null - if (mMap == null) { - return null; - } - return mMapView.getSavedStyle(); -// return mMap.getStyle(); - } - - public abstract T makeLayer(); - public abstract void addStyles(); - - private boolean hasInitialized() { - return mMap != null && mLayer != null; - } -} diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt new file mode 100644 index 000000000..0dcc11bf1 --- /dev/null +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt @@ -0,0 +1,274 @@ +package com.mapbox.rctmgl.components.styles.layers + +import android.content.Context +import com.mapbox.maps.extension.style.layers.Layer +import com.mapbox.rctmgl.components.mapview.RCTMGLMapView +import com.mapbox.maps.Style +import com.mapbox.maps.MapView +import com.mapbox.rctmgl.components.styles.sources.AbstractSourceConsumer +import com.facebook.react.bridge.ReadableMap +import com.mapbox.maps.MapboxMap +import com.facebook.react.bridge.ReadableArray +import com.mapbox.rctmgl.components.mapview.RCTMGLMapView.FoundLayerCallback +import com.facebook.common.logging.FLog +import com.mapbox.maps.extension.style.expressions.dsl.generated.literal +import com.mapbox.maps.extension.style.expressions.generated.Expression +import com.mapbox.maps.extension.style.layers.* +import com.mapbox.maps.extension.style.layers.properties.generated.Visibility +import com.mapbox.rctmgl.components.styles.layers.RCTLayer +import com.mapbox.rctmgl.modules.RCTMGLLogging +import com.mapbox.rctmgl.utils.ExpressionParser +import java.lang.ClassCastException +import com.mapbox.rctmgl.utils.Logger + + +// import com.mapbox.rctmgl.utils.ExpressionParser; +abstract class RCTLayer(protected var mContext: Context) : AbstractSourceConsumer( + mContext +) { + override var iD: String? = null + @JvmField + protected var mSourceID: String? = null + protected var mAboveLayerID: String? = null + protected var mBelowLayerID: String? = null + protected var mLayerIndex: Int? = null + protected var mVisible = false + protected var mMinZoomLevel: Double? = null + protected var mMaxZoomLevel: Double? = null + @JvmField + protected var mReactStyle: ReadableMap? = null + protected var mFilter: Expression? = null + @JvmField + protected var mMap: MapboxMap? = null + @JvmField + protected var mLayer: T? = null + protected var mMapView: RCTMGLMapView? = null + protected var mHadFilter = false + + fun setSourceID(sourceID: String?) { + mSourceID = sourceID + } + + fun setAboveLayerID(aboveLayerID: String) { + if (mAboveLayerID != null && mAboveLayerID == aboveLayerID) { + return + } + mAboveLayerID = aboveLayerID + if (mLayer != null) { + removeFromMap(mMapView!!) + addAbove(mAboveLayerID) + } + } + + fun setBelowLayerID(belowLayerID: String) { + if (mBelowLayerID != null && mBelowLayerID == belowLayerID) { + return + } + mBelowLayerID = belowLayerID + if (mLayer != null) { + removeFromMap(mMapView!!) + addBelow(mBelowLayerID) + } + } + + fun setLayerIndex(layerIndex: Int) { + if (mLayerIndex != null && mLayerIndex == layerIndex) { + return + } + mLayerIndex = layerIndex + if (mLayer != null) { + removeFromMap(mMapView!!) + addAtIndex(mLayerIndex!!) + } + } + + fun setVisible(visible: Boolean) { + mVisible = visible + if (mLayer != null) { + mLayer!!.visibility(if (mVisible) Visibility.VISIBLE else Visibility.NONE) + } + } + + fun setMinZoomLevel(minZoomLevel: Double) { + mMinZoomLevel = minZoomLevel + if (mLayer != null) { + mLayer!!.minZoom(minZoomLevel.toFloat().toDouble()) + } + } + + fun setMaxZoomLevel(maxZoomLevel: Double) { + mMaxZoomLevel = maxZoomLevel + if (mLayer != null) { + mLayer!!.maxZoom(maxZoomLevel.toFloat().toDouble()) + } + } + + fun setReactStyle(reactStyle: ReadableMap?) { + mReactStyle = reactStyle + if (mLayer != null) { + addStyles() + } + } + + fun setFilter(readableFilterArray: ReadableArray?) { + val filterExpression = ExpressionParser.from(readableFilterArray) + mFilter = filterExpression + if (mLayer != null) { + if (mFilter != null) { + mHadFilter = true + updateFilter(mFilter) + } else if (mHadFilter) { + updateFilter(literal(true)) + } + } + } + + fun add() { + if (!hasInitialized()) { + return + } + if (style == null) return + + /* V10TODO + String userBackgroundID = LocationComponentConstants.BACKGROUND_LAYER; + Layer userLocationBackgroundLayer = getStyle().getLayer(userBackgroundID); + + // place below user location layer + if (userLocationBackgroundLayer != null) { + getStyle().addLayerBelow(mLayer, userBackgroundID); + mMapView.layerAdded(mLayer); + return; + } */ + + Logger.logged("RCTLayer.add") { + style!!.addLayer(mLayer!!); + mMapView!!.layerAdded(mLayer!!) + } + } + + fun addAbove(aboveLayerID: String?) { + mMapView!!.waitForLayer(aboveLayerID!!, object : FoundLayerCallback { + override fun found(layer: Layer?) { + if (!hasInitialized()) { + return + } + if (style == null) return + style!!.addLayerAbove(mLayer!!, aboveLayerID) + mMapView!!.layerAdded(mLayer!!) + } + }) + } + + fun addBelow(belowLayerID: String?) { + mMapView!!.waitForLayer(belowLayerID!!, object : FoundLayerCallback { + override fun found(layer: Layer?) { + if (!hasInitialized()) { + return + } + if (style == null) return + style!!.addLayerBelow(mLayer!!, belowLayerID) + mMapView!!.layerAdded(mLayer!!) + } + }) + } + + fun addAtIndex(index: Int) { + var index = index + if (!hasInitialized()) { + return + } + if (style == null) return + val layerSize = style!!.styleLayers.size + if (index >= layerSize) { + FLog.e( + LOG_TAG, + "Layer index is greater than number of layers on map. Layer inserted at end of layer stack." + ) + index = layerSize - 1 + } + style!!.addLayerAt(mLayer!!, index) + mMapView!!.layerAdded(mLayer!!) + } + + protected fun insertLayer() { + if (style == null) return + if (style!!.getLayer(iD!!) != null) { + return // prevent adding a layer twice + } + if (mAboveLayerID != null) { + addAbove(mAboveLayerID) + } else if (mBelowLayerID != null) { + addBelow(mBelowLayerID) + } else if (mLayerIndex != null) { + addAtIndex(mLayerIndex!!) + } else { + add() + } + setZoomBounds() + } + + protected fun setZoomBounds() { + if (mMaxZoomLevel != null) { + mLayer!!.maxZoom(mMaxZoomLevel!!.toFloat().toDouble()) + } + if (mMinZoomLevel != null) { + mLayer!!.minZoom(mMinZoomLevel!!.toFloat().toDouble()) + } + } + + protected open fun updateFilter(expression: Expression?) { + // override if you want to update the filter + } + + private fun getLayerAs(style: Style?, id: String?): T? { + val result = style!!.getLayer(iD!!) + return try { + result as T? + } catch (exception: ClassCastException) { + null + } + } + + override fun addToMap(mapView: RCTMGLMapView) { + mMap = mapView.getMapboxMap() + mMapView = mapView + if (style == null) return + val existingLayer = getLayerAs(style, iD) + if (existingLayer != null) { + mLayer = existingLayer + } else { + mLayer = makeLayer() + insertLayer() + } + addStyles() + if (mFilter != null) { + mHadFilter = true + updateFilter(mFilter) + } + } + + override fun removeFromMap(mapView: RCTMGLMapView) { + if (style != null) { + style!!.removeStyleLayer(mLayer!!.layerId) + } + } + + // v10TOOD: adding anything seems to make getStyle null + // return mMap.getStyle(); + private val style: Style? + private get() =// v10TOOD: adding anything seems to make getStyle null + if (mMap == null) { + null + } else mMapView!!.savedStyle + + // return mMap.getStyle(); + abstract fun makeLayer(): T + abstract fun addStyles() + private fun hasInitialized(): Boolean { + return mMap != null && mLayer != null + } + + companion object { + const val LOG_TAG = "RCTLayer" + } +} \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java index 762339622..aac3ac50c 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java @@ -13,7 +13,7 @@ public RCTMGLBackgroundLayer(Context context) { @Override public BackgroundLayer makeLayer() { - return new BackgroundLayer(mID); + return new BackgroundLayer(getID()); } @Override diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java index 09fe226ec..4f38631b1 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java @@ -28,7 +28,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public CircleLayer makeLayer() { - CircleLayer layer = new CircleLayer(mID, mSourceID); + CircleLayer layer = new CircleLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java index a73344f1a..e85fbf7df 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java @@ -27,7 +27,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public FillExtrusionLayer makeLayer() { - FillExtrusionLayer layer = new FillExtrusionLayer(mID, mSourceID); + FillExtrusionLayer layer = new FillExtrusionLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java index e1a42dc43..2eb1ccc48 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java @@ -27,7 +27,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public FillLayer makeLayer() { - FillLayer layer = new FillLayer(mID, mSourceID); + FillLayer layer = new FillLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java index 8895221e0..d7a1633a0 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java @@ -27,7 +27,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public HeatmapLayer makeLayer() { - HeatmapLayer layer = new HeatmapLayer(mID, mSourceID); + HeatmapLayer layer = new HeatmapLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java index c43468dde..9b39b6c7e 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java @@ -27,7 +27,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public LineLayer makeLayer() { - LineLayer layer = new LineLayer(mID, mSourceID); + LineLayer layer = new LineLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java index a82c31880..b1bb56248 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java @@ -14,7 +14,7 @@ public RCTMGLRasterLayer(Context context) { @Override public RasterLayer makeLayer() { - return new RasterLayer(mID, mSourceID); + return new RasterLayer(getID(), mSourceID); } @Override diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.java deleted file mode 100644 index e518c5e52..000000000 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.mapbox.rctmgl.components.styles.layers; - -import android.content.Context; - -import com.mapbox.maps.extension.style.expressions.generated.Expression; -import com.mapbox.maps.extension.style.layers.generated.SkyLayer; -import com.mapbox.rctmgl.components.mapview.RCTMGLMapView; -import com.mapbox.rctmgl.components.styles.RCTMGLStyle; -import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory; -import com.mapbox.rctmgl.utils.Logger; - -public class RCTMGLSkyLayer extends RCTLayer { - private String mSourceLayerID; - - public RCTMGLSkyLayer(Context context) { - super(context); - } - - @Override - protected void updateFilter(Expression expression) { - mLayer.filter(expression); - } - - @Override - public void addToMap(RCTMGLMapView mapView) { - super.addToMap(mapView); - } - - @Override - public SkyLayer makeLayer() { - SkyLayer layer = new SkyLayer(mID); - - return layer; - } - - @Override - public void addStyles() { - RCTMGLStyleFactory.setSkyLayerStyle(mLayer, new RCTMGLStyle(getContext(), mReactStyle, mMap)); - } - - public void setSourceLayerID(String sourceLayerID) { - Logger.e("RCTMGLSkyLayer", "Source layer should not be set for source layer id"); - } -} diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt new file mode 100644 index 000000000..c60c2e0e3 --- /dev/null +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt @@ -0,0 +1,35 @@ +package com.mapbox.rctmgl.components.styles.layers + +import android.content.Context +import com.mapbox.maps.extension.style.expressions.generated.Expression +import com.mapbox.maps.extension.style.layers.generated.SkyLayer +import com.mapbox.rctmgl.components.styles.layers.RCTLayer +import com.mapbox.rctmgl.utils.Logger.e +import com.mapbox.rctmgl.components.mapview.RCTMGLMapView +import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory +import com.mapbox.rctmgl.components.styles.RCTMGLStyle + +class RCTMGLSkyLayer(context: Context?) : RCTLayer( + context!! +) { + private val mSourceLayerID: String? = null + override fun updateFilter(expression: Expression?) { + mLayer!!.filter(expression!!) + } + + override fun addToMap(mapView: RCTMGLMapView) { + super.addToMap(mapView) + } + + override fun makeLayer(): SkyLayer { + return SkyLayer(iD!!) + } + + override fun addStyles() { + RCTMGLStyleFactory.setSkyLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle!!, mMap!!)) + } + + fun setSourceLayerID(sourceLayerID: String?) { + e("RCTMGLSkyLayer", "Source layer should not be set for source layer id") + } +} \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java index ac48ce6f0..74f37464e 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java @@ -27,7 +27,7 @@ public void addToMap(RCTMGLMapView mapView) { @Override public SymbolLayer makeLayer() { - SymbolLayer layer = new SymbolLayer(mID, mSourceID); + SymbolLayer layer = new SymbolLayer(getID(), mSourceID); if (mSourceLayerID != null) { layer.sourceLayer(mSourceLayerID); diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt index 7a8fd0a3a..838f6f5fc 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt @@ -4,6 +4,7 @@ import android.content.Context import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource import com.mapbox.rctmgl.utils.ImageEntry import android.graphics.drawable.BitmapDrawable +import com.facebook.react.bridge.ReadableMap import com.mapbox.rctmgl.components.mapview.RCTMGLMapView import com.mapbox.rctmgl.events.FeatureClickEvent import com.facebook.react.bridge.WritableMap @@ -164,6 +165,10 @@ class RCTMGLShapeSource(context: Context, private val mManager: RCTMGLShapeSourc } } + private fun callbackSuccess(callbackID: String, payload: WritableMap) { + val event = AndroidCallbackEvent(this, callbackID, payload) + mManager.handleEvent(event) + } private fun callbackError(callbackID: String, error: String, where: String) { val payload: WritableMap = WritableNativeMap() payload.putString("error", "$where: $error") @@ -171,111 +176,86 @@ class RCTMGLShapeSource(context: Context, private val mManager: RCTMGLShapeSourc mManager.handleEvent(event) } - fun getClusterExpansionZoom(callbackID: String, clusterId: Int) { - if (mSource == null) { - val payload: WritableMap = WritableNativeMap() - payload.putString("error", "source is not yet loaded") - val event = AndroidCallbackEvent(this, callbackID, payload) - mManager.handleEvent(event) - return - } - val options = SourceQueryOptions( - null, - Expression.eq(Expression.get("cluster_id"), Expression.literal(clusterId.toLong())) - ) - val _this = this - mMap!!.querySourceFeatures( - iD!!, - options, - QueryFeaturesCallback { features -> - if (features.isValue) { - val cluster = features.value!![0] - mMap!!.queryFeatureExtensions( - iD!!, - cluster.feature, - "supercluster", - "expansion-zoom", - null, - QueryFeatureExtensionCallback { extension -> - if (extension.isValue) { - val contents = extension.value!!.value!!.contents - if (contents is Long) { - val payload: WritableMap = WritableNativeMap() - payload.putInt("data", contents.toInt()) - val event = AndroidCallbackEvent(_this, callbackID, payload) - mManager.handleEvent(event) - return@QueryFeatureExtensionCallback - } else { - callbackError( - callbackID, - "Not a number", - "getClusterExpansionZoom/queryFeatureExtensions2" - ) - return@QueryFeatureExtensionCallback - } - } else { - callbackError( - callbackID, - extension.error ?: "Unknown error", - "getClusterExpansionZoom/queryFeatureExtensions" - ) - return@QueryFeatureExtensionCallback - } - } - ) + fun getClusterExpansionZoom(callbackID: String, featureJSON: String) { + val feature = Feature.fromJson(featureJSON) + + mMap!!.getGeoJsonClusterExpansionZoom(iD!!, feature, QueryFeatureExtensionCallback { features -> + if (features.isValue) { + val contents = features.value!!.value!!.contents + val payload: WritableMap = WritableNativeMap() + + if (contents is Long) { + val payload: WritableMap = WritableNativeMap() + payload.putInt("data", contents.toInt()) + callbackSuccess(callbackID, payload) + return@QueryFeatureExtensionCallback } else { callbackError( callbackID, - features.error ?: "Unknown error", - "getClusterExpansionZoom/querySourceFeatures" + "Not a number: $contents", + "getClusterExpansionZoom/getGeoJsonClusterExpansionZoom" ) - return@QueryFeaturesCallback + return@QueryFeatureExtensionCallback } + } else { + callbackError( + callbackID, + features.error ?: "Unknown error", + "getClusterExpansionZoom/getGeoJsonClusterExpansionZoom" + ) + return@QueryFeatureExtensionCallback } - ) + }) } - fun getClusterLeaves(callbackID: String, clusterId: Int, number: Int, offset: Int) { - val options = SourceQueryOptions( - null, - Expression.eq(Expression.get("cluster_id"), Expression.literal(clusterId.toLong())) - ) - mMap!!.querySourceFeatures( - iD!!, - options, QueryFeaturesCallback { features -> - if (features.isValue) { - val cluster = features.value!![0] - mMap!!.queryFeatureExtensions( - iD!!, cluster.feature, "supercluster", "leaves", null, - QueryFeatureExtensionCallback { extension -> - if (extension.isValue) { - val leaves = extension.value!! - .featureCollection - val payload: WritableMap = WritableNativeMap() - payload.putString( - "data", - FeatureCollection.fromFeatures(leaves!!).toJson() - ) - } else { - callbackError( - callbackID, - features.error ?: "Unknown error", - "getClusterLeaves/queryFeatureExtensions" - ) - return@QueryFeatureExtensionCallback - } - } - ) - } else { - callbackError( - callbackID, - features.error ?: "Unknown error", - "getClusterLeaves/querySourceFeatures" - ) - return@QueryFeaturesCallback - } + fun getClusterLeaves(callbackID: String, featureJSON: String, number: Int, offset: Int) { + val feature = Feature.fromJson(featureJSON) + + val _this = this + mMap!!.getGeoJsonClusterLeaves(iD!!, feature, number.toLong(), offset.toLong(), QueryFeatureExtensionCallback { features -> + if (features.isValue) { + val leaves = features.value!! + .featureCollection + val payload: WritableMap = WritableNativeMap() + payload.putString( + "data", + FeatureCollection.fromFeatures(leaves!!).toJson() + ) + callbackSuccess(callbackID, payload) + } else { + callbackError( + callbackID, + features.error ?: "Unknown error", + "getClusterLeaves/getGeoJsonClusterLeaves" + ) + return@QueryFeatureExtensionCallback + } + }) + } + + fun getClusterChildren(callbackID: String, featureJSON: String) { + val feature = Feature.fromJson(featureJSON) + + val _this = this + mMap!!.getGeoJsonClusterChildren(iD!!, feature, QueryFeatureExtensionCallback { features -> + if (features.isValue) { + val children = features.value!! + .featureCollection + val payload: WritableMap = WritableNativeMap() + payload.putString( + "data", + FeatureCollection.fromFeatures(children!!).toJson() + ) + callbackSuccess(callbackID, payload) + }else { + callbackError( + callbackID, + features.error ?: "Unknown error", + "getClusterLeaves/queryFeatureExtensions" + ) + return@QueryFeatureExtensionCallback } - ) + }) } /*companion object { diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt index 1a19a44a3..ddc6d7b0f 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt @@ -152,6 +152,7 @@ class RCTMGLShapeSourceManager(private val mContext: ReactApplicationContext) : .put("features", METHOD_FEATURES) .put("getClusterExpansionZoom", METHOD_GET_CLUSTER_EXPANSION_ZOOM) .put("getClusterLeaves", METHOD_GET_CLUSTER_LEAVES) + .put("getClusterChildren", METHOD_GET_CLUSTER_CHILDREN) .build() } @@ -159,20 +160,28 @@ class RCTMGLShapeSourceManager(private val mContext: ReactApplicationContext) : if (args == null) { return } + + val callbackID = args.getString(0); + when (commandID) { METHOD_FEATURES -> source.querySourceFeatures( - args.getString(0), + callbackID, ExpressionParser.from(args.getArray(1)) ) METHOD_GET_CLUSTER_EXPANSION_ZOOM -> source.getClusterExpansionZoom( - args.getString(0), args.getInt(1) + callbackID, + args.getString(1) ) METHOD_GET_CLUSTER_LEAVES -> source.getClusterLeaves( - args.getString(0), - args.getInt(1), + callbackID, + args.getString(1), args.getInt(2), args.getInt(3) ) + METHOD_GET_CLUSTER_CHILDREN -> source.getClusterChildren( + callbackID, + args.getString(1) + ) } } @@ -184,5 +193,6 @@ class RCTMGLShapeSourceManager(private val mContext: ReactApplicationContext) : const val METHOD_FEATURES = 103 const val METHOD_GET_CLUSTER_EXPANSION_ZOOM = 104 const val METHOD_GET_CLUSTER_LEAVES = 105 + const val METHOD_GET_CLUSTER_CHILDREN = 106 } } diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLModule.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLModule.kt index b55f22f3f..4e1215448 100644 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLModule.kt +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/modules/RCTMGLModule.kt @@ -66,7 +66,7 @@ class RCTMGLModule(private val mReactContext: ReactApplicationContext) : ReactCo // style source constants val styleSourceConsts: MutableMap = HashMap() - styleSourceConsts["DefaultSourceID"] = "TODO-defautl id" //v10todo + styleSourceConsts["DefaultSourceID"] = "composite" // line layer constants val lineJoin: MutableMap = HashMap() diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.java deleted file mode 100644 index a32d86779..000000000 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.mapbox.rctmgl.utils; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.AsyncTask; -import android.util.DisplayMetrics; -import android.util.Log; - -import com.facebook.common.logging.FLog; -import com.facebook.common.references.CloseableReference; -import com.facebook.datasource.DataSource; -import com.facebook.datasource.DataSources; -import com.facebook.drawee.backends.pipeline.Fresco; -import com.facebook.imagepipeline.common.RotationOptions; -import com.facebook.imagepipeline.image.CloseableImage; -import com.facebook.imagepipeline.image.CloseableStaticBitmap; -import com.facebook.imagepipeline.request.ImageRequest; -import com.facebook.imagepipeline.request.ImageRequestBuilder; -import com.facebook.react.views.imagehelper.ImageSource; -import com.mapbox.maps.MapboxMap; -import com.mapbox.maps.Style; - -import java.io.File; -import java.lang.ref.WeakReference; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - -/** - * Created by nickitaliano on 9/13/17. - */ - -public class DownloadMapImageTask extends AsyncTask, Void, List>> { - public static final String LOG_TAG = "DownloadMapImageTask"; - - private WeakReference mContext; - private WeakReference mMap; - @Nullable - private OnAllImagesLoaded mCallback; - private final Object mCallerContext; - - public DownloadMapImageTask(Context context, MapboxMap map, @Nullable OnAllImagesLoaded callback) { - mContext = new WeakReference<>(context.getApplicationContext()); - mMap = new WeakReference<>(map); - mCallback = callback; - mCallerContext = this; - } - - public interface OnAllImagesLoaded { - void onAllImagesLoaded(); - } - - @SafeVarargs - @Override - protected final List> doInBackground(Map.Entry... objects) { - List> images = new ArrayList<>(); - - Context context = mContext.get(); - if (context == null) return images; - - Resources resources = context.getResources(); - DisplayMetrics metrics = resources.getDisplayMetrics(); - - for (Map.Entry object : objects) { - ImageEntry imageEntry = object.getValue(); - - String uri = imageEntry.uri; - - if (uri.startsWith("/")) { - uri = Uri.fromFile(new File(uri)).toString(); - } - - if (uri.startsWith("http://") || uri.startsWith("https://") || - uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:")) { - ImageSource source = new ImageSource(context, uri); - ImageRequest request = ImageRequestBuilder.newBuilderWithSource(source.getUri()) - .setRotationOptions(RotationOptions.autoRotate()) - .build(); - - DataSource> dataSource = - Fresco.getImagePipeline().fetchDecodedImage(request, mCallerContext); - - CloseableReference result = null; - try { - result = DataSources.waitForFinalResult(dataSource); - if (result != null) { - CloseableImage image = result.get(); - if (image instanceof CloseableStaticBitmap) { - CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; - Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap() - // Copy the bitmap to make sure it doesn't get recycled when we release - // the fresco reference. - .copy(Bitmap.Config.ARGB_8888, true); - bitmap.setDensity((int) ((double) DisplayMetrics.DENSITY_DEFAULT * imageEntry.getScaleOr(1.0))); - images.add(new AbstractMap.SimpleEntry<>(object.getKey(), bitmap)); - } else { - FLog.e(LOG_TAG, "Failed to load bitmap from: " + uri); - } - } else { - FLog.e(LOG_TAG, "Failed to load bitmap from: " + uri); - } - } catch (Throwable e) { - Log.w(LOG_TAG, e.getLocalizedMessage()); - } finally { - dataSource.close(); - if (result != null) { - CloseableReference.closeSafely(result); - } - } - } else { - // local asset required from JS require('image.png') or import icon from 'image.png' while in release mode - Bitmap bitmap = BitmapUtils.getBitmapFromResource(context, uri, getBitmapOptions(metrics, imageEntry.scale)); - if (bitmap != null) { - images.add(new AbstractMap.SimpleEntry<>(object.getKey(), bitmap)); - } else { - FLog.e(LOG_TAG, "Failed to load bitmap from: " + uri); - } - } - } - - return images; - } - - @Override - protected void onPostExecute(List> images) { - MapboxMap map = mMap.get(); - if (map != null && images != null && images.size() > 0) { - Style style = map.getStyle(); - if (style != null) { - HashMap bitmapImages = new HashMap<>(); - for (Map.Entry image : images) { - bitmapImages.put(image.getKey(), image.getValue()); - style.addImage(image.getKey(), image.getValue()); - } - // style.addImages(bitmapImages); - } - } - - if (mCallback != null) { - mCallback.onAllImagesLoaded(); - } - } - - private BitmapFactory.Options getBitmapOptions(DisplayMetrics metrics, Double scale) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inScreenDensity = metrics.densityDpi; - options.inTargetDensity = metrics.densityDpi; - if (scale != ImageEntry.defaultScale) { - options.inDensity = (int) ((double) DisplayMetrics.DENSITY_DEFAULT * scale); - } - return options; - } -} diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.kt new file mode 100644 index 000000000..d7d67f2b5 --- /dev/null +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/DownloadMapImageTask.kt @@ -0,0 +1,151 @@ +package com.mapbox.rctmgl.utils + +import android.content.Context +import android.graphics.Bitmap +import com.mapbox.maps.Style +import com.mapbox.maps.MapboxMap +import com.mapbox.rctmgl.utils.DownloadMapImageTask.OnAllImagesLoaded +import android.os.AsyncTask +import com.mapbox.rctmgl.utils.ImageEntry +import android.util.DisplayMetrics +import com.mapbox.rctmgl.utils.DownloadMapImageTask +import android.graphics.BitmapFactory +import android.net.Uri +import android.util.Log +import com.facebook.common.logging.FLog +import com.facebook.common.references.CloseableReference +import com.facebook.datasource.DataSources +import com.facebook.drawee.backends.pipeline.Fresco +import com.facebook.imagepipeline.common.RotationOptions +import com.facebook.imagepipeline.image.CloseableImage +import com.facebook.imagepipeline.image.CloseableStaticBitmap +import com.facebook.imagepipeline.request.ImageRequestBuilder +import com.facebook.react.views.imagehelper.ImageSource +import java.io.File +import java.lang.ref.WeakReference +import java.util.AbstractMap +import java.util.ArrayList +import java.util.HashMap + +class DownloadMapImageTask(context: Context, map: MapboxMap, callback: OnAllImagesLoaded?) : + AsyncTask, Void?, List>?>() { + private val mContext: WeakReference + private val mMap: WeakReference + private val mCallback: OnAllImagesLoaded? + private val mCallerContext: Any + + interface OnAllImagesLoaded { + fun onAllImagesLoaded() + } + + @SafeVarargs + protected override fun doInBackground(vararg objects: Map.Entry): List>? { + val images: MutableList> = ArrayList() + val context = mContext.get() ?: return images + val resources = context.resources + val metrics = resources.displayMetrics + for ((key, imageEntry) in objects) { + var uri = imageEntry.uri + if (uri.startsWith("/")) { + uri = Uri.fromFile(File(uri)).toString() + } + if (uri.startsWith("http://") || uri.startsWith("https://") || + uri.startsWith("file://") || uri.startsWith("asset://") || uri.startsWith("data:") + ) { + val source = ImageSource(context, uri) + val request = ImageRequestBuilder.newBuilderWithSource(source.uri) + .setRotationOptions(RotationOptions.autoRotate()) + .build() + val dataSource = + Fresco.getImagePipeline().fetchDecodedImage(request, mCallerContext) + var result: CloseableReference? = null + try { + result = DataSources.waitForFinalResult(dataSource) + if (result != null) { + val image = result.get() + if (image is CloseableStaticBitmap) { + val bitmap = + image.underlyingBitmap // Copy the bitmap to make sure it doesn't get recycled when we release + // the fresco reference. + .copy(Bitmap.Config.ARGB_8888, true) + bitmap.density = + (DisplayMetrics.DENSITY_DEFAULT.toDouble() * imageEntry.getScaleOr( + 1.0 + )).toInt() + images.add( + AbstractMap.SimpleEntry( + key, bitmap + ) + ) + } else { + FLog.e(LOG_TAG, "Failed to load bitmap from: $uri") + } + } else { + FLog.e(LOG_TAG, "Failed to load bitmap from: $uri") + } + } catch (e: Throwable) { + Log.w(LOG_TAG, e.localizedMessage) + } finally { + dataSource.close() + if (result != null) { + CloseableReference.closeSafely(result) + } + } + } else { + // local asset required from JS require('image.png') or import icon from 'image.png' while in release mode + val bitmap = BitmapUtils.getBitmapFromResource( + context, + uri, + getBitmapOptions(metrics, imageEntry.scale) + ) + if (bitmap != null) { + images.add( + AbstractMap.SimpleEntry( + key, bitmap + ) + ) + } else { + FLog.e(LOG_TAG, "Failed to load bitmap from: $uri") + } + } + } + return images + } + + override fun onPostExecute(images: List>?) { + val map = mMap.get() + if (map != null && images != null && images.size > 0) { + val style = map.getStyle() + if (style != null) { + val bitmapImages = HashMap() + for ((key, value) in images) { + bitmapImages[key] = value + style.addImage(key, value) + } + // style.addImages(bitmapImages); + } + } + mCallback?.onAllImagesLoaded() + } + + private fun getBitmapOptions(metrics: DisplayMetrics, scale: Double): BitmapFactory.Options { + val options = BitmapFactory.Options() + options.inScreenDensity = metrics.densityDpi + options.inTargetDensity = metrics.densityDpi + if (scale != ImageEntry.defaultScale) { + options.inDensity = (DisplayMetrics.DENSITY_DEFAULT.toDouble() * scale).toInt() + } + return options + } + + companion object { + const val LOG_TAG = "DownloadMapImageTask" + } + + init { + mContext = WeakReference(context.applicationContext) + mMap = WeakReference(map) + mCallback = callback + mCallerContext = this + } +} \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.java deleted file mode 100644 index 5253f7828..000000000 --- a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.mapbox.rctmgl.utils; -import android.util.Log; - - -public class Logger { - public static interface LoggerDefinition { - public void v(String tag, String msg); - public void v(String tag, String msg, Throwable tr); - public void d(String tag, String msg); - public void d(String tag, String msg, Throwable tr); - public void i(String tag, String msg); - public void i(String tag, String msg, Throwable tr); - public void w(String tag, String msg); - public void w(String tag, String msg, Throwable tr); - public void e(String tag, String msg); - public void e(String tag, String msg, Throwable tr); - - } - - static LoggerDefinition logger = new LoggerDefinition() { - @Override - public void v(String tag, String msg) { - Log.v(tag, msg); - } - - @Override - public void v(String tag, String msg, Throwable tr) { - Log.v(tag, msg, tr); - } - - @Override - public void d(String tag, String msg) { - Log.d(tag, msg); - } - - @Override - public void d(String tag, String msg, Throwable tr) { - Log.d(tag, msg); - } - - @Override - public void i(String tag, String msg) { - Log.i(tag, msg); - } - - @Override - public void i(String tag, String msg, Throwable tr) { - Log.i(tag, msg, tr); - } - - @Override - public void w(String tag, String msg) { - Log.w(tag, msg); - } - - @Override - public void w(String tag, String msg, Throwable tr) { - Log.w(tag, msg); - } - - @Override - public void e(String tag, String msg) { - Log.e(tag, msg); - } - - @Override - public void e(String tag, String msg, Throwable tr) { - Log.e(tag, msg, tr); - } - }; - - public static void setVerbosity(int logLevel) { - Logger.logLevel = logLevel; - } - - public static void setLoggerDefinition(LoggerDefinition dest) { - logger = dest; - } - - private static int logLevel; - - static public void d(String tag, String msg) { - if (logLevel <= Log.DEBUG) { - logger.d(tag, msg); - } - } - - static public void v(String tag, String msg) { - if (logLevel <= Log.VERBOSE) { - logger.v(tag, msg); - } - } - - static public void i(String tag, String msg) { - if (logLevel <= Log.INFO) { - logger.i(tag, msg); - } - } - - static public void w(String tag, String msg) { - if (logLevel <= Log.VERBOSE) { - logger.w(tag, msg); - } - } - - static public void w(String tag,String msg, Throwable tr) { - if (logLevel <= Log.VERBOSE) { - logger.w(tag,msg,tr); - } - } - - public static void e(String tag, String msg) { - if (logLevel <= Log.ERROR) { - logger.e(tag, msg); - } - } - - static public void e(String tag, String msg, Throwable tr) { - if (logLevel <= Log.ERROR) { - logger.e(tag, msg, tr); - } - } - - -}; \ No newline at end of file diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.kt new file mode 100644 index 000000000..e64ca83f4 --- /dev/null +++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/utils/Logger.kt @@ -0,0 +1,120 @@ +package com.mapbox.rctmgl.utils + +import android.util.Log +import com.mapbox.rctmgl.utils.Logger.LoggerDefinition + +object Logger { + var logger: LoggerDefinition = object : LoggerDefinition { + override fun v(tag: String, msg: String) { + Log.v(tag, msg!!) + } + + override fun v(tag: String, msg: String, tr: Throwable) { + Log.v(tag, msg, tr) + } + + override fun d(tag: String, msg: String) { + Log.d(tag, msg!!) + } + + override fun d(tag: String, msg: String, tr: Throwable) { + Log.d(tag, msg!!) + } + + override fun i(tag: String, msg: String) { + Log.i(tag, msg!!) + } + + override fun i(tag: String, msg: String, tr: Throwable) { + Log.i(tag, msg, tr) + } + + override fun w(tag: String, msg: String) { + Log.w(tag, msg!!) + } + + override fun w(tag: String, msg: String, tr: Throwable) { + Log.w(tag, msg!!) + } + + override fun e(tag: String, msg: String) { + Log.e(tag, msg!!) + } + + override fun e(tag: String, msg: String, tr: Throwable) { + Log.e(tag, msg, tr) + } + } + + fun setVerbosity(logLevel: Int) { + Logger.logLevel = logLevel + } + + fun setLoggerDefinition(dest: LoggerDefinition) { + logger = dest + } + + private var logLevel = 0 + fun d(tag: String, msg: String) { + if (logLevel <= Log.DEBUG) { + logger.d(tag, msg) + } + } + + fun v(tag: String, msg: String) { + if (logLevel <= Log.VERBOSE) { + logger.v(tag, msg) + } + } + + fun i(tag: String, msg: String) { + if (logLevel <= Log.INFO) { + logger.i(tag, msg) + } + } + + fun w(tag: String, msg: String) { + if (logLevel <= Log.VERBOSE) { + logger.w(tag, msg) + } + } + + fun w(tag: String, msg: String, tr: Throwable) { + if (logLevel <= Log.VERBOSE) { + logger.w(tag, msg, tr) + } + } + + fun e(tag: String, msg: String) { + if (logLevel <= Log.ERROR) { + logger.e(tag, msg) + } + } + + fun e(tag: String, msg: String, tr: Throwable) { + if (logLevel <= Log.ERROR) { + logger.e(tag, msg, tr) + } + } + + fun logged(tag:String, callback: () -> Unit) { + try { + callback() + } catch (error: Exception) { + Logger.e(tag, "Exception - error: $error") + } + } + + interface LoggerDefinition { + fun v(tag: String, msg: String) + fun v(tag: String, msg: String, tr: Throwable) + fun d(tag: String, msg: String) + fun d(tag: String, msg: String, tr: Throwable) + fun i(tag: String, msg: String) + fun i(tag: String, msg: String, tr: Throwable) + fun w(tag: String, msg: String) + fun w(tag: String, msg: String, tr: Throwable) + fun e(tag: String, msg: String) + fun e(tag: String, msg: String, tr: Throwable) + } +} \ No newline at end of file diff --git a/docs/MapboxGL.md b/docs/MapboxGL.md index 33732aa6b..cd87f13ea 100644 --- a/docs/MapboxGL.md +++ b/docs/MapboxGL.md @@ -13,6 +13,16 @@ sets the accessToken, which is required when you want to use mapbox tiles not required when using other tiles +#### setWellKnownTileServer(tileServer) + +##### arguments +| Name | Type | Required | Description | +| ---- | :--: | :------: | :----------: | +| `tileServer` | `String` | `Yes` | tile server | + +##### Description +No-op on non MapLibre implemntations. Use MapboxGL.TileServer.Mapbox to consume mapbox tiles with maplibre. *Note*: Consuming mapbox with MapLibre has different pricing than with the official SDK. Other values: MapboxGL.TileServer.MapLibre, MapboxGL.TileServer.MapTiler + #### getAccessToken() ##### arguments diff --git a/ios/RCTMGL-v10/Extensions/CoordinateBounds+toArray.swift b/ios/RCTMGL-v10/Extensions/CoordinateBounds+toArray.swift new file mode 100644 index 000000000..cc08b3c5a --- /dev/null +++ b/ios/RCTMGL-v10/Extensions/CoordinateBounds+toArray.swift @@ -0,0 +1,10 @@ +import MapboxMaps + +internal extension CoordinateBounds { + func toArray() -> [[Double]] { + return [ + northeast.toArray(), + southwest.toArray() + ] + } +} diff --git a/ios/RCTMGL-v10/RCTMGLBackgroundLayer.swift b/ios/RCTMGL-v10/RCTMGLBackgroundLayer.swift index f0d78afab..3d16d100e 100644 --- a/ios/RCTMGL-v10/RCTMGLBackgroundLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLBackgroundLayer.swift @@ -16,8 +16,8 @@ class RCTMGLBackgroundLayer: RCTMGLLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout BackgroundLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout BackgroundLayer) in if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL-v10/RCTMGLCamera.swift b/ios/RCTMGL-v10/RCTMGLCamera.swift index e1f11a60a..350ab7d9e 100644 --- a/ios/RCTMGL-v10/RCTMGLCamera.swift +++ b/ios/RCTMGL-v10/RCTMGLCamera.swift @@ -2,7 +2,7 @@ import Foundation import MapboxMaps import Turf -protocol RCTMGLMapComponent { +protocol RCTMGLMapComponent : class { func addToMap(_ map: RCTMGLMapView, style: Style) func removeFromMap(_ map: RCTMGLMapView) diff --git a/ios/RCTMGL-v10/RCTMGLCircleLayer.swift b/ios/RCTMGL-v10/RCTMGLCircleLayer.swift index a5b5dd9c0..548f8c80e 100644 --- a/ios/RCTMGL-v10/RCTMGLCircleLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLCircleLayer.swift @@ -17,8 +17,8 @@ class RCTMGLCircleLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout CircleLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout CircleLayer) in if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL-v10/RCTMGLFillExtrustionLayer.swift b/ios/RCTMGL-v10/RCTMGLFillExtrustionLayer.swift index e577dd1c7..e399b554e 100644 --- a/ios/RCTMGL-v10/RCTMGLFillExtrustionLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLFillExtrustionLayer.swift @@ -16,8 +16,8 @@ class RCTMGLFillExtrusionLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout FillExtrusionLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout FillExtrusionLayer) in if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL-v10/RCTMGLFillLayer.swift b/ios/RCTMGL-v10/RCTMGLFillLayer.swift index d1216f8e3..a1adac6da 100644 --- a/ios/RCTMGL-v10/RCTMGLFillLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLFillLayer.swift @@ -17,8 +17,8 @@ class RCTMGLFillLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout FillLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout FillLayer) in if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL-v10/RCTMGLHeatmapLayer.swift b/ios/RCTMGL-v10/RCTMGLHeatmapLayer.swift index f30b1c792..73a7b3aff 100644 --- a/ios/RCTMGL-v10/RCTMGLHeatmapLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLHeatmapLayer.swift @@ -17,8 +17,8 @@ class RCTMGLHeatmapLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout HeatmapLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout HeatmapLayer) in if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL-v10/RCTMGLLayer.swift b/ios/RCTMGL-v10/RCTMGLLayer.swift index 9ed30cce4..0ea27ec52 100644 --- a/ios/RCTMGL-v10/RCTMGLLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLLayer.swift @@ -117,13 +117,19 @@ class RCTMGLLayer : UIView, RCTMGLMapComponent, RCTMGLSourceConsumer { } func layerType() -> Layer.Type { - fatalError("Subclasses need to implement the `layerType` method.") + fatalError("Subclasses need to implement the `layerType` method. \(self)") } - func apply(style : Style) { + func apply(style : Style) throws { fatalError("Subclasses need to implement the `apply` method.") } + final func loggedApply(style: Style) { + logged("updateLayer", info: { "\(self.layerType()).\(optional: self.id)" }) { + try apply(style: style) + } + } + func position() -> LayerPosition { if let belowLayerID = belowLayerID { return .below(belowLayerID) @@ -137,6 +143,9 @@ class RCTMGLLayer : UIView, RCTMGLMapComponent, RCTMGLSourceConsumer { } func inserLayer(_ map: RCTMGLMapView) { + if self.style == nil { + print("inserLayer but style is nil") + } if let style = style, let styleLayer = styleLayer { insert(style, layerPosition: position()) { map.layerAdded(styleLayer) @@ -146,7 +155,7 @@ class RCTMGLLayer : UIView, RCTMGLMapComponent, RCTMGLSourceConsumer { func updateLayer(_ map: RCTMGLMapView) { if let style = style, let _ = styleLayer { - apply(style: style) + loggedApply(style: style) } } @@ -159,12 +168,7 @@ class RCTMGLLayer : UIView, RCTMGLMapComponent, RCTMGLSourceConsumer { let result = try style.source(withId: self.sourceID!, type: T.self) return result } - - func addToMap(_ map: RCTMGLMapView) { - self.style = map.mapboxMap.style - self.map = map - } - + func addedToMap() { } @@ -242,7 +246,7 @@ class RCTMGLLayer : UIView, RCTMGLMapComponent, RCTMGLSourceConsumer { private func optionsChanged() { if let style = self.style { self.setOptions(&self.styleLayer!) - self.apply(style: style) + self.loggedApply(style: style) } } diff --git a/ios/RCTMGL-v10/RCTMGLLineLayer.swift b/ios/RCTMGL-v10/RCTMGLLineLayer.swift index ba90fc6f2..c95ddd04a 100644 --- a/ios/RCTMGL-v10/RCTMGLLineLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLLineLayer.swift @@ -16,8 +16,8 @@ class RCTMGLLineLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout LineLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout LineLayer) in if self.styleLayer != nil { self.setOptions(&self.styleLayer!) } diff --git a/ios/RCTMGL-v10/RCTMGLMapView.swift b/ios/RCTMGL-v10/RCTMGLMapView.swift index a0d48723b..32f5e6014 100644 --- a/ios/RCTMGL-v10/RCTMGLMapView.swift +++ b/ios/RCTMGL-v10/RCTMGLMapView.swift @@ -8,13 +8,16 @@ open class RCTMGLMapView : MapView { var reactOnLongPress : RCTBubblingEventBlock? var reactOnMapChange : RCTBubblingEventBlock? + var styleLoaded: Bool = false + var styleLoadWaiters : [(MapboxMap)->Void] = [] + var reactCamera : RCTMGLCamera? var images : [RCTMGLImages] = [] var sources : [RCTMGLSource] = [] var handleMapChangedEvents = Set() - var onStyleLoadedComponents: [RCTMGLMapComponent]? = [] + var onStyleLoadedComponents: [RCTMGLMapComponent] = [] private var isPendingInitialLayout = true private var isGestureActive = false @@ -33,30 +36,48 @@ open class RCTMGLMapView : MapView { var mapView : MapView { get { return self } } - - @objc open override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { + + func addToMap(_ subview: UIView) { if let mapComponent = subview as? RCTMGLMapComponent { - if mapComponent.waitForStyleLoad(), self.onStyleLoadedComponents != nil { - onStyleLoadedComponents!.append(mapComponent) + let style = mapView.mapboxMap.style + if mapComponent.waitForStyleLoad() { + onStyleLoadedComponents.append(mapComponent) + if (style.isLoaded) { + mapComponent.addToMap(self, style: style) + } } else { - mapComponent.addToMap(self, style: self.mapboxMap.style) + mapComponent.addToMap(self, style: style) } + } else { + print("addToMap.Subviews: \(subview.reactSubviews())") + subview.reactSubviews().forEach { addToMap($0) } } if let source = subview as? RCTMGLSource { sources.append(source) } - - super.insertReactSubview(subview, at: atIndex) } - @objc open override func removeReactSubview(_ subview:UIView!) { + func removeFromMap(_ subview: UIView) { if let mapComponent = subview as? RCTMGLMapComponent { + if mapComponent.waitForStyleLoad() { + onStyleLoadedComponents.removeAll { $0 === mapComponent } + } mapComponent.removeFromMap(self) + } else { + subview.reactSubviews().forEach { removeFromMap($0) } } if let source = subview as? RCTMGLSource { sources.removeAll { $0 == source } } + } + @objc open override func insertReactSubview(_ subview: UIView!, at atIndex: Int) { + addToMap(subview) + super.insertReactSubview(subview, at: atIndex) + } + + @objc open override func removeReactSubview(_ subview:UIView!) { + removeFromMap(subview) super.removeReactSubview(subview) } @@ -175,6 +196,7 @@ open class RCTMGLMapView : MapView { } @objc func setReactStyleURL(_ value: String?) { + self.styleLoaded = false if let value = value { if let _ = URL(string: value) { mapView.mapboxMap.loadStyleURI(StyleURI(rawValue: value)!) @@ -336,11 +358,19 @@ extension RCTMGLMapView { self.fireEvent(event: event, callback: self.reactOnMapChange) }) - self.mapboxMap.onNext(.styleLoaded, handler: { (event) in - self.onStyleLoadedComponents?.forEach { (component) in + self.mapboxMap.onEvery(.styleLoaded, handler: { (event) in + self.onStyleLoadedComponents.forEach { (component) in component.addToMap(self, style: self.mapboxMap.style) } - self.onStyleLoadedComponents = nil + + if !self.styleLoaded { + self.styleLoaded = true + if let mapboxMap = self.mapboxMap { + let waiters = self.styleLoadWaiters + self.styleLoadWaiters = [] + waiters.forEach { $0(mapboxMap) } + } + } let event = RCTMGLEvent(type:.didFinishLoadingStyle, payload: nil) self.fireEvent(event: event, callback: self.reactOnMapChange) @@ -527,12 +557,10 @@ extension RCTMGLMapView { fatalError("mapboxMap is null") } - if mapboxMap.style.isLoaded { + if styleLoaded { block(mapboxMap) } else { - mapboxMap.onNext(.styleLoaded) { _ in - block(mapboxMap) - } + styleLoadWaiters.append(block) } } } diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.m b/ios/RCTMGL-v10/RCTMGLMapViewManager.m index 29995d719..5f2c04bda 100644 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.m +++ b/ios/RCTMGL-v10/RCTMGLMapViewManager.m @@ -58,6 +58,10 @@ @interface RCT_EXTERN_REMAP_MODULE(RCTMGLMapView, RCTMGLMapViewManager, RCTViewM resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getVisibleBounds:(nonnull NSNumber*)reactTag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(queryRenderedFeaturesAtPoint:(nonnull NSNumber*)reactTag atPoint:(NSArray*)point withFilter:(NSArray*)filter diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.swift b/ios/RCTMGL-v10/RCTMGLMapViewManager.swift index 796d75692..9b9a49dee 100644 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.swift +++ b/ios/RCTMGL-v10/RCTMGLMapViewManager.swift @@ -160,6 +160,16 @@ extension RCTMGLMapViewManager { resolver(["zoom": mapboxMap.cameraState.zoom]) } } + + @objc + func getVisibleBounds( + _ reactTag: NSNumber, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + withMapView(reactTag, name:"getVisibleBounds", rejecter: rejecter) { mapView in + resolver(["visibleBounds": mapView.mapboxMap.coordinateBounds(for: mapView.bounds).toArray()]) + } + } } // MARK: - queryRenderedFeatures diff --git a/ios/RCTMGL-v10/RCTMGLRasterLayer.swift b/ios/RCTMGL-v10/RCTMGLRasterLayer.swift index 0fb469320..668abbb6e 100644 --- a/ios/RCTMGL-v10/RCTMGLRasterLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLRasterLayer.swift @@ -11,8 +11,8 @@ class RCTMGLRasterLayer: RCTMGLLayer { return layer } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: RasterLayer.self) { (layer : inout RasterLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: RasterLayer.self) { (layer : inout RasterLayer) in if let styleLayer = self.styleLayer as? RasterLayer { layer = styleLayer } @@ -41,4 +41,8 @@ class RCTMGLRasterLayer: RCTMGLLayer { func isAddedToMap() -> Bool { return true } + + override func layerType() -> Layer.Type { + return LayerType.self + } } diff --git a/ios/RCTMGL-v10/RCTMGLShapeSource.swift b/ios/RCTMGL-v10/RCTMGLShapeSource.swift index 73fc0a620..3542821b7 100644 --- a/ios/RCTMGL-v10/RCTMGLShapeSource.swift +++ b/ios/RCTMGL-v10/RCTMGLShapeSource.swift @@ -133,6 +133,13 @@ extension RCTMGLShapeSource } } } + + func parse(_ shape: String) throws -> Feature { + guard let data = shape.data(using: .utf8) else { + throw RCTMGLError.parseError("shape is not utf8") + } + return try JSONDecoder().decode(Feature.self, from: data) + } func parse(_ shape: String?) throws -> GeoJSONObject { guard let shape = shape else { @@ -220,7 +227,7 @@ extension RCTMGLShapeSource } } - func getClusterLeaves(_ clusterId: NSNumber, + func getClusterLeaves(_ featureJSON: String, number: uint, offset: uint, completion: @escaping (Result) -> Void) @@ -230,26 +237,40 @@ extension RCTMGLShapeSource return } - let options = SourceQueryOptions(sourceLayerIds: nil, filter: Exp(.eq) { - Exp(.get) { "cluster_id" } - clusterId.uintValue - }) - mapView.mapboxMap.querySourceFeatures(for: id, options: options) { result in - switch result { - case .success(let features): - let cluster = features[0] - mapView.mapboxMap.queryFeatureExtension(for: self.id, feature: cluster.feature, extension: "supercluster", extensionField: "leaves") { - result in - switch result { - case .success(let features): - completion(.success(features)) - case .failure(let error): - completion(.failure(error)) - } + logged("RCTMGLShapeSource.getClusterLeaves", rejecter: { (_,_,error) in + completion(.failure(error!)) + }) { + let cluster : Feature = try parse(featureJSON); + mapView.mapboxMap.queryFeatureExtension(for: self.id, feature: cluster, extension: "supercluster", extensionField: "leaves", args: ["limit": UInt64(number),"offset": UInt64(offset)]) { + result in + switch result { + case .success(let features): + completion(.success(features)) + case .failure(let error): + completion(.failure(error)) + } + } + } + } + + func getClusterChildren(_ featureJSON: String, completion: @escaping (Result) -> Void) { + guard let mapView = map?.mapView else { + completion(.failure(RCTMGLError.failed("getClusterChildren: no mapView"))) + return + } + + logged("RCTMGLShapeSource.getClusterChildren", rejecter: { (_,_,error) in + completion(.failure(error!)) + }) { + let cluster : Feature = try parse(featureJSON); + mapView.mapboxMap.queryFeatureExtension(for: self.id, feature: cluster, extension: "supercluster", extensionField: "children") { + result in + switch result { + case .success(let features): + completion(.success(features)) + case .failure(let error): + completion(.failure(error)) } - - case .failure(let error): - completion(.failure(error)) } } } diff --git a/ios/RCTMGL-v10/RCTMGLShapeSourceManager.m b/ios/RCTMGL-v10/RCTMGLShapeSourceManager.m index 2186063a6..9449b7929 100644 --- a/ios/RCTMGL-v10/RCTMGLShapeSourceManager.m +++ b/ios/RCTMGL-v10/RCTMGLShapeSourceManager.m @@ -1,7 +1,8 @@ #import #import -@interface RCT_EXTERN_MODULE(RCTMGLShapeSourceManager, RCTViewManager) +@interface +RCT_EXTERN_REMAP_MODULE(RCTMGLShapeSource, RCTMGLShapeSourceManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(id, NSString) RCT_EXPORT_VIEW_PROPERTY(url, NSString) @@ -22,16 +23,22 @@ @interface RCT_EXTERN_MODULE(RCTMGLShapeSourceManager, RCTViewManager) RCT_REMAP_VIEW_PROPERTY(onMapboxShapeSourcePress, onPress, RCTBubblingEventBlock) + RCT_EXTERN_METHOD(getClusterExpansionZoom:(nonnull NSNumber*)reactTag clusterId:(nonnull NSNumber*)clusterId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) RCT_EXTERN_METHOD(getClusterLeaves:(nonnull NSNumber*)reactTag - clusterId:(nonnull NSNumber *)clusterId + featureJSON:(nonnull NSString*)featureJSON number:(NSUInteger) number offset:(NSUInteger) offset resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getClusterChildren:(nonnull NSNumber*)reactTag + featureJSON:(nonnull NSString*)featureJSON + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + @end diff --git a/ios/RCTMGL-v10/RCTMGLShapeSourceManager.swift b/ios/RCTMGL-v10/RCTMGLShapeSourceManager.swift index 97148c25b..7cb642af2 100644 --- a/ios/RCTMGL-v10/RCTMGLShapeSourceManager.swift +++ b/ios/RCTMGL-v10/RCTMGLShapeSourceManager.swift @@ -8,16 +8,42 @@ class RCTMGLShapeSourceManager: RCTViewManager { @objc override func view() -> UIView { return RCTMGLShapeSource() } - +} + +// MARK: - helpers + +extension RCTMGLShapeSourceManager { + func withShapeSource( + _ reactTag: NSNumber, + name: String, + rejecter: @escaping RCTPromiseRejectBlock, + fn: @escaping (_: RCTMGLShapeSource) -> Void) -> Void + { + self.bridge.uiManager.addUIBlock { (manager, viewRegistry) in + let view = viewRegistry![reactTag] + + guard let shapeSource = view! as? RCTMGLShapeSource else { + RCTLogError("Invalid react tag, could not find RCTMGLShapeSource"); + rejecter(name, "Unknown find reactTag: \(reactTag)", nil) + return; + } + + fn(shapeSource) + } + } +} + +// MARK: - react methods + +extension RCTMGLShapeSourceManager { @objc func getClusterExpansionZoom( _ reactTag: NSNumber, clusterId: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { - self.bridge.uiManager.addUIBlock { (manager, viewRegistry) in - let shapeSource = viewRegistry?[reactTag] as! RCTMGLShapeSource - let shapes = shapeSource.getClusterExpansionZoom(clusterId) { result in + self.withShapeSource(reactTag, name:"getClusterExpansionZoom", rejecter: rejecter) { shapeSource in + shapeSource.getClusterExpansionZoom(clusterId) { result in switch result { case .success(let zoom): resolver([ @@ -32,24 +58,49 @@ class RCTMGLShapeSourceManager: RCTViewManager { @objc func getClusterLeaves( _ reactTag: NSNumber, - clusterId: NSNumber, + featureJSON: String, number: uint, offset: uint, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { - self.bridge.uiManager.addUIBlock { (manager, viewRegistry) in - let shapeSource = viewRegistry?[reactTag] as! RCTMGLShapeSource - let shapes = shapeSource.getClusterLeaves(clusterId, number: number, offset: offset) { result in + self.withShapeSource(reactTag, name:"getClusterLeaves", rejecter: rejecter) { shapeSource in + shapeSource.getClusterLeaves(featureJSON, number: number, offset: offset) { result in switch result { case .success(let features): - resolver([ - "data": ["type":"FeatureCollection", "features": features.features] - ]) + logged("getClusterLeaves", rejecter: rejecter) { + let featuresJSON : Any = try features.features.toJSON() + resolver([ + "data": ["type":"FeatureCollection", "features": featuresJSON] + ]) + } case .failure(let error): rejecter(error.localizedDescription, "Error.getClusterLeaves", error) } } } } + + @objc func getClusterChildren( + _ reactTag: NSNumber, + featureJSON: String, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { + self.withShapeSource(reactTag, name:"getClusterChildren", rejecter: rejecter) { shapeSource in + shapeSource.getClusterChildren(featureJSON) { result in + switch result { + case .success(let features): + logged("getClusterChildren", rejecter: rejecter) { + let featuresJSON : Any = try features.features.toJSON() + resolver([ + "data": ["type":"FeatureCollection", "features": featuresJSON] + ]) + } + case .failure(let error): + rejecter(error.localizedDescription, "Error.getClusterChildren", error) + } + } + } + } } + diff --git a/ios/RCTMGL-v10/RCTMGLSkyLayer.swift b/ios/RCTMGL-v10/RCTMGLSkyLayer.swift index 79f751c43..897a1d68d 100644 --- a/ios/RCTMGL-v10/RCTMGLSkyLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLSkyLayer.swift @@ -5,10 +5,7 @@ class RCTMGLSkyLayer: RCTMGLLayer { typealias LayerType = SkyLayer override func makeLayer(style: Style) throws -> Layer { - let vectorSource : VectorSource = try self.layerWithSourceID(in: style) - var layer = LayerType(id: self.id!) - layer.sourceLayer = self.sourceLayerID - layer.source = sourceID + let layer = LayerType(id: self.id!) return layer } @@ -16,9 +13,9 @@ class RCTMGLSkyLayer: RCTMGLLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout LayerType) in - if var styleLayer = self.styleLayer as? LayerType { + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout LayerType) in + if let styleLayer = self.styleLayer as? LayerType { layer = styleLayer } } diff --git a/ios/RCTMGL-v10/RCTMGLStyleValue.swift b/ios/RCTMGL-v10/RCTMGLStyleValue.swift index 0d873bd98..84fdb6544 100644 --- a/ios/RCTMGL-v10/RCTMGLStyleValue.swift +++ b/ios/RCTMGL-v10/RCTMGLStyleValue.swift @@ -124,8 +124,13 @@ class RCTMGLStyleValue { } let result = values.map { items -> (String,Any) in - let key = items[0] + var key = items[0] let value = items[1] + if let keyd = key as? [String:String], + keyd["type"] == "string", + let value = keyd["value"] { + key = value + } guard let key = key as? String else { fatalError("First item should be a string key") } diff --git a/ios/RCTMGL-v10/RCTMGLSymbolLayer.swift b/ios/RCTMGL-v10/RCTMGLSymbolLayer.swift index 4bf39117d..f1e5d8731 100644 --- a/ios/RCTMGL-v10/RCTMGLSymbolLayer.swift +++ b/ios/RCTMGL-v10/RCTMGLSymbolLayer.swift @@ -17,8 +17,8 @@ class RCTMGLSymbolLayer: RCTMGLVectorLayer { return LayerType.self } - override func apply(style : Style) { - try! style.updateLayer(withId: id, type: LayerType.self) { (layer : inout SymbolLayer) in + override func apply(style : Style) throws { + try style.updateLayer(withId: id, type: LayerType.self) { (layer : inout SymbolLayer) in if var styleLayer = self.styleLayer as? LayerType { layer = styleLayer } diff --git a/ios/RCTMGL/MGLModule.m b/ios/RCTMGL/MGLModule.m index 76a9b7340..36310604a 100644 --- a/ios/RCTMGL/MGLModule.m +++ b/ios/RCTMGL/MGLModule.m @@ -52,7 +52,7 @@ + (BOOL)requiresMainQueueSetup [styleURLS setObject:[MGLStyle.outdoorsStyleURL absoluteString] forKey:@"Outdoors"]; [styleURLS setObject:[MGLStyle.satelliteStyleURL absoluteString] forKey:@"Satellite"]; [styleURLS setObject:[MGLStyle.satelliteStreetsStyleURL absoluteString] forKey:@"SatelliteStreet"]; - [tileServers setObject:@"mapbox" forKey:@"Mapbox"] + [tileServers setObject:@"mapbox" forKey:@"Mapbox"]; [impl setObject:@"mapbox-gl" forKey:@"Library"]; #endif diff --git a/javascript/utils/Logger.js b/javascript/utils/Logger.js index cc96f6e14..5ced48d4f 100644 --- a/javascript/utils/Logger.js +++ b/javascript/utils/Logger.js @@ -111,4 +111,6 @@ class Logger { } } +Logger.sharedInstance().start(); + export default Logger; diff --git a/package.json b/package.json index c7da3a09c..c6342efbc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@rnmapbox/maps", "description": "A Mapbox react native module for creating custom maps", - "version": "10.0.0-beta.9", + "version": "10.0.0-beta.15", "publishConfig": { "access": "public" },