Skip to content
New issue

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

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

Already on GitHub? # to your account

feat: Feature state #3741

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -68,6 +68,7 @@ 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.*
Expand Down Expand Up @@ -1097,6 +1098,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
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