Skip to content

Commit

Permalink
Implement feature state
Browse files Browse the repository at this point in the history
  • Loading branch information
davor-bauk-sh committed Feb 27, 2025
1 parent 0bc1935 commit d2ae4eb
Show file tree
Hide file tree
Showing 17 changed files with 1,012 additions and 311 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.rnmapbox.rnmbx.components.mapview
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import com.facebook.react.bridge.WritableNativeMap
import com.rnmapbox.rnmbx.NativeMapViewModuleSpec
Expand All @@ -12,6 +13,7 @@ import com.rnmapbox.rnmbx.utils.ViewRefTag
import com.rnmapbox.rnmbx.utils.ViewTagResolver
import com.rnmapbox.rnmbx.utils.extensions.toCoordinate
import com.rnmapbox.rnmbx.utils.extensions.toScreenCoordinate
import com.rnmapbox.rnmbx.utils.extensions.toValueHashMap

class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver: ViewTagResolver) : NativeMapViewModuleSpec(context) {
private fun withMapViewOnUIThread(
Expand Down Expand Up @@ -158,6 +160,44 @@ class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver:
}
}

override fun setFeatureState(
viewRef: ViewRefTag?,
featureId: String,
state: ReadableMap,
sourceId: String,
sourceLayerId: String?,
promise: Promise
) {
withMapViewOnUIThread(viewRef, promise) {
it.setFeatureState(featureId, state.toValueHashMap(), sourceId, sourceLayerId, createCommandResponse(promise))
}
}

override fun getFeatureState(
viewRef: ViewRefTag?,
featureId: String,
sourceId: String,
sourceLayerId: String?,
promise: Promise
) {
withMapViewOnUIThread(viewRef, promise) {
it.getFeatureState(featureId, sourceId, sourceLayerId, createCommandResponse(promise))
}
}

override fun removeFeatureState(
viewRef: ViewRefTag?,
featureId: String,
stateKey: String?,
sourceId: String,
sourceLayerId: String?,
promise: Promise
) {
withMapViewOnUIThread(viewRef, promise) {
it.removeFeatureState(featureId, stateKey, sourceId, sourceLayerId, createCommandResponse(promise))
}
}

override fun querySourceFeatures(
viewRef: ViewRefTag?,
sourceId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,24 @@ import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionNam
import com.mapbox.maps.extension.style.layers.properties.generated.Visibility
import com.mapbox.maps.extension.style.projection.generated.Projection
import com.mapbox.maps.extension.style.projection.generated.setProjection
import com.mapbox.maps.logE
import com.mapbox.maps.plugin.attribution.attribution
import com.mapbox.maps.plugin.compass.compass
import com.mapbox.maps.plugin.delegates.listeners.*
import com.mapbox.maps.plugin.gestures.*
import com.mapbox.maps.plugin.logo.logo
import com.mapbox.maps.plugin.scalebar.scalebar
import com.mapbox.maps.toCameraOptions
import com.mapbox.maps.viewannotation.ViewAnnotationManager
import com.rnmapbox.rnmbx.R
import com.rnmapbox.rnmbx.components.AbstractMapFeature
import com.rnmapbox.rnmbx.components.RemovalReason
import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerView
import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerViewManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotation
import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationCoordinator
import com.rnmapbox.rnmbx.components.camera.RNMBXCamera
import com.rnmapbox.rnmbx.components.images.ImageManager
import com.rnmapbox.rnmbx.components.images.RNMBXImages
import com.rnmapbox.rnmbx.components.location.LocationComponentManager
import com.rnmapbox.rnmbx.components.location.RNMBXNativeUserLocation
Expand All @@ -64,17 +68,12 @@ import com.rnmapbox.rnmbx.events.MapClickEvent
import com.rnmapbox.rnmbx.events.constants.EventTypes
import com.rnmapbox.rnmbx.utils.*
import com.rnmapbox.rnmbx.utils.extensions.toReadableArray
import java.util.*

import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationCoordinator
import com.rnmapbox.rnmbx.components.images.ImageManager

import com.rnmapbox.rnmbx.utils.extensions.toStringKeyPairs
import com.rnmapbox.rnmbx.v11compat.event.*
import com.rnmapbox.rnmbx.v11compat.feature.*
import com.rnmapbox.rnmbx.v11compat.mapboxmap.*
import com.rnmapbox.rnmbx.v11compat.ornamentsettings.*
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import org.json.*


fun <T> MutableList<T>.removeIf21(predicate: (T) -> Boolean): Boolean {
var removed = false
Expand Down Expand Up @@ -1097,6 +1096,50 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie
}
}

fun setFeatureState(
featureId: String,
state: HashMap<String, Value>,
sourceId: String,
sourceLayerId: String?,
response: CommandResponse
) {
mapView.getMapboxMap().setFeatureState(sourceId, sourceLayerId, featureId, Value.valueOf(state))
response.success { }
}

fun getFeatureState(
featureId: String,
sourceId: String,
sourceLayerId: String?,
response: CommandResponse
) {
mapView.getMapboxMap().getFeatureState(sourceId, sourceLayerId, featureId) { expected ->
if (expected.isValue) {
response.success {
val state = expected.value?.contents;
if (state is Map<*,*>) {
it.putMap("featureState", writableMapOf(*state.toStringKeyPairs()))
} else {
it.putMap("featureState", Arguments.createMap())
}
}
} else {
response.error(expected.error ?: "Unknown error")
}
}
}

fun removeFeatureState(
featureId: String,
stateKey: String?,
sourceId: String,
sourceLayerId: String?,
response: CommandResponse
) {
mapView.getMapboxMap().removeFeatureState(sourceId, sourceLayerId, featureId, stateKey)
response.success { }
}

fun match(layer: Layer, sourceId:String, sourceLayerId: String?) : Boolean {
fun match(actSourceId: String, actSourceLayerId: String?) : Boolean {
return (actSourceId == sourceId && ((sourceLayerId == null) || (sourceLayerId == actSourceLayerId)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ open class ViewTagResolver(val context: ReactApplicationContext) {
try {
val view = manager.resolveView(viewTag)

list.forEach { it.fn(view) }
list.forEach { view?.let { itView -> it.fn(itView) } }
} catch (err: IllegalViewOperationException) {
list.forEach { it.reject?.reject(err) }
}
Expand Down
11 changes: 11 additions & 0 deletions android/src/main/java/com/rnmapbox/rnmbx/utils/extensions/Map.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.rnmapbox.rnmbx.utils.extensions

fun Map<*, *>.toStringKeyPairs(): Array<Pair<String, *>> {
return this.entries.fold(mutableListOf<Pair<String, *>>()) { acc, (key, value) ->
acc.apply {
if (key is String) {
add(key to value)
}
}
}.toTypedArray()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package com.rnmapbox.rnmbx.utils
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.WritableArray
import com.facebook.react.bridge.WritableMap
import com.mapbox.bindgen.Value
import com.rnmapbox.rnmbx.utils.extensions.toStringKeyPairs


fun writableMapOf(vararg values: Pair<String, *>): WritableMap {
val map = Arguments.createMap()
Expand All @@ -14,8 +17,23 @@ fun writableMapOf(vararg values: Pair<String, *>): WritableMap {
is Int -> map.putInt(key, value)
is Long -> map.putInt(key, value.toInt())
is String -> map.putString(key, value)
is Map<*,*> -> map.putMap(key, writableMapOf(*value.toStringKeyPairs()))
is Array<*> -> map.putArray(key, writableArrayOf(*value.map{ it as Any }.toTypedArray()))
is WritableMap -> map.putMap(key, value)
is WritableArray -> map.putArray(key, value)
is Value -> {
val contents = value.contents
when (contents) {
null -> map.putNull(key)
is Boolean -> map.putBoolean(key, contents)
is Double -> map.putDouble(key, contents)
is Int -> map.putInt(key, contents)
is Long -> map.putInt(key, contents.toInt())
is String -> map.putString(key, contents)
is WritableMap -> map.putMap(key, contents)
is WritableArray -> map.putArray(key, contents)
}
}
else -> throw IllegalArgumentException("Unsupported value type ${value::class.java.name} for key [$key]")
}
}
Expand All @@ -32,8 +50,25 @@ fun writableArrayOf(vararg values: Any): WritableArray {
is Int -> array.pushInt(value)
is Long -> array.pushInt(value.toInt())
is String -> array.pushString(value)
is Map<*,*> -> array.pushMap(writableMapOf(*value.toStringKeyPairs()))
is Array<*> -> array.pushArray(writableArrayOf(*value.map{ it as Any }.toTypedArray()))
is WritableMap -> array.pushMap(value)
is WritableArray -> array.pushArray(value)
is Value -> {
val contents = value.contents
when (contents) {
null -> array.pushNull()
is Boolean -> array.pushBoolean(contents)
is Double -> array.pushDouble(contents)
is Int -> array.pushInt(contents)
is Long -> array.pushInt(contents.toInt())
is String -> array.pushString(contents)
is Map<*,*> -> array.pushMap(writableMapOf(*contents.toStringKeyPairs()))
is Array<*> -> array.pushArray(writableArrayOf(*contents.map{ it as Any }.toTypedArray()))
is WritableMap -> array.pushMap(contents)
is WritableArray -> array.pushArray(contents)
}
}
else -> throw IllegalArgumentException("Unsupported value type ${value::class.java.name}")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactModuleWithSpec;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -86,4 +87,16 @@ public NativeMapViewModuleSpec(ReactApplicationContext reactContext) {
@ReactMethod
@DoNotStrip
public abstract void querySourceFeatures(@Nullable Double viewRef, String sourceId, ReadableArray withFilter, ReadableArray withSourceLayerIDs, Promise promise);

@ReactMethod
@DoNotStrip
public abstract void setFeatureState(@Nullable Double viewRef, String featureId, ReadableMap state, String sourceId, @Nullable String sourceLayerId, Promise promise);

@ReactMethod
@DoNotStrip
public abstract void getFeatureState(@Nullable Double viewRef, String featureId, String sourceId, @Nullable String sourceLayerId, Promise promise);

@ReactMethod
@DoNotStrip
public abstract void removeFeatureState(@Nullable Double viewRef, String featureId, @Nullable String stateKey, String sourceId, @Nullable String sourceLayerId, Promise promise);
}
38 changes: 38 additions & 0 deletions docs/MapView.md
Original file line number Diff line number Diff line change
Expand Up @@ -730,4 +730,42 @@ await this._map.setSourceVisibility(false, 'composite', 'building')
```


### setFeatureState(featureId, state, sourceId[, sourceLayerId])

Updates the state map of a feature within a style source.<br/><br/>Updates entries in the state map of a given feature within a style source.<br/>Only entries listed in the `state` will be updated.<br/>An entry in the feature state map that is not listed in `state` will retain its previous value.

#### arguments
| Name | Type | Required | Description |
| ---- | :--: | :------: | :----------: |
| `featureId` | `string` | `Yes` | Identifier of the feature whose state should be updated. |
| `state` | `{[k:string]:NativeArg}` | `Yes` | undefined |
| `sourceId` | `string` | `Yes` | undefined |
| `sourceLayerId` | `n/a` | `No` | undefined |


[Feature State](../examples/V10/FeatureState)### getFeatureState(featureId, sourceId[, sourceLayerId])

Returns the state map of a feature within a style source.

#### arguments
| Name | Type | Required | Description |
| ---- | :--: | :------: | :----------: |
| `featureId` | `string` | `Yes` | Identifier of the feature whose state should be queried. |
| `sourceId` | `string` | `Yes` | Style source identifier. |
| `sourceLayerId` | `string` | `No` | Style source layer identifier (for multi-layer sources such as vector sources). |


[Feature State](../examples/V10/FeatureState)### removeFeatureState(featureId, stateKey, sourceId[, sourceLayerId])

Removes entries from a feature state object.<br/><br/>Removes a specified property or all properties from a feature’s state object,<br/>depending on the value of `stateKey`.

#### arguments
| Name | Type | Required | Description |
| ---- | :--: | :------: | :----------: |
| `featureId` | `string` | `Yes` | Identifier of the feature whose state should be removed. |
| `stateKey` | `string \| null` | `Yes` | The name of the property to remove. If `null`, all feature’s state object properties are removed. |
| `sourceId` | `string` | `Yes` | Style source identifier. |
| `sourceLayerId` | `string` | `No` | Style source layer identifier (for multi-layer sources such as vector sources). |


[Feature State](../examples/V10/FeatureState)
Loading

0 comments on commit d2ae4eb

Please # to comment.