From 343c68ff967b9fdcdc93756a7bcefbf28fd2786c Mon Sep 17 00:00:00 2001 From: Ankur Khandelwal Date: Mon, 13 Sep 2021 12:21:18 +0300 Subject: [PATCH] add support for promoteId --- .../sources/generated/GeoJsonSourceTest.kt | 13 +++++ .../sources/generated/VectorSourceTest.kt | 13 +++++ .../style/sources/generated/GeoJsonSource.kt | 46 +++++++++++++++++ .../style/sources/generated/VectorSource.kt | 49 +++++++++++++++++++ .../maps/extension/style/types/PromoteId.kt | 48 ++++++++++++++++++ .../sources/generated/GeoJsonSourceTest.kt | 31 ++++++++++++ .../sources/generated/VectorSourceTest.kt | 31 ++++++++++++ 7 files changed, 231 insertions(+) create mode 100644 extension-style/src/main/java/com/mapbox/maps/extension/style/types/PromoteId.kt diff --git a/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/GeoJsonSourceTest.kt b/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/GeoJsonSourceTest.kt index b78bba5c0a..cd220defa1 100644 --- a/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/GeoJsonSourceTest.kt +++ b/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/GeoJsonSourceTest.kt @@ -8,6 +8,7 @@ import com.mapbox.geojson.Feature import com.mapbox.geojson.FeatureCollection import com.mapbox.maps.extension.style.expressions.dsl.generated.* import com.mapbox.maps.extension.style.sources.generated.* +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.testapp.style.BaseStyleTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull @@ -245,6 +246,17 @@ class GeoJsonSourceTest : BaseStyleTest() { assertEquals(true, testSource.generateId) } + @Test + @UiThreadTest + fun promoteIdTest() { + val testSource = geoJsonSource("testId") { + url(TEST_URI) + promoteId(PromoteId(propertyName = "abc")) + } + setupSource(testSource) + assertEquals(PromoteId(propertyName = "abc"), testSource.promoteId) + } + @Test @UiThreadTest fun prefetchZoomDeltaTest() { @@ -455,6 +467,7 @@ class GeoJsonSourceTest : BaseStyleTest() { assertNotNull("defaultClusterMaxZoom should not be null", GeoJsonSource.defaultClusterMaxZoom) assertNotNull("defaultLineMetrics should not be null", GeoJsonSource.defaultLineMetrics) assertNotNull("defaultGenerateId should not be null", GeoJsonSource.defaultGenerateId) + assertNotNull("defaultPromoteId should not be null", GeoJsonSource.defaultPromoteId) assertNotNull("defaultPrefetchZoomDelta should not be null", GeoJsonSource.defaultPrefetchZoomDelta) } diff --git a/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/VectorSourceTest.kt b/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/VectorSourceTest.kt index e962d3b96f..327ef7bdd9 100644 --- a/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/VectorSourceTest.kt +++ b/extension-style-app/src/androidTest/java/com/mapbox/maps/testapp/style/sources/generated/VectorSourceTest.kt @@ -6,6 +6,7 @@ import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import com.mapbox.maps.extension.style.sources.TileSet import com.mapbox.maps.extension.style.sources.generated.* +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.testapp.style.BaseStyleTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull @@ -144,6 +145,17 @@ class VectorSourceTest : BaseStyleTest() { assertEquals("abc", testSource.attribution) } + @Test + @UiThreadTest + fun promoteIdTest() { + val testSource = vectorSource("testId") { + url(TEST_URI) + promoteId(PromoteId(propertyName = "abc")) + } + setupSource(testSource) + assertEquals(PromoteId(propertyName = "abc"), testSource.promoteId) + } + @Test @UiThreadTest fun volatileTest() { @@ -262,6 +274,7 @@ class VectorSourceTest : BaseStyleTest() { assertNotNull("defaultScheme should not be null", VectorSource.defaultScheme) assertNotNull("defaultMinzoom should not be null", VectorSource.defaultMinzoom) assertNotNull("defaultMaxzoom should not be null", VectorSource.defaultMaxzoom) + assertNotNull("defaultPromoteId should not be null", VectorSource.defaultPromoteId) assertNotNull("defaultVolatile should not be null", VectorSource.defaultVolatile) assertNotNull("defaultPrefetchZoomDelta should not be null", VectorSource.defaultPrefetchZoomDelta) assertNotNull("defaultMinimumTileUpdateInterval should not be null", VectorSource.defaultMinimumTileUpdateInterval) diff --git a/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSource.kt b/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSource.kt index 8388cda0c9..8ad2f33262 100644 --- a/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSource.kt +++ b/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSource.kt @@ -16,6 +16,7 @@ import com.mapbox.maps.extension.style.expressions.generated.Expression import com.mapbox.maps.extension.style.layers.properties.PropertyValue import com.mapbox.maps.extension.style.sources.OnGeoJsonParsed import com.mapbox.maps.extension.style.sources.Source +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.extension.style.types.SourceDsl import com.mapbox.maps.extension.style.utils.TypeUtils import com.mapbox.maps.extension.style.utils.silentUnwrap @@ -254,6 +255,24 @@ class GeoJsonSource(builder: Builder) : Source(builder.sourceId) { */ get() = getPropertyValue("generateId") + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. + */ + val promoteId: PromoteId? + /** + * Get the PromoteId property + * + * @return PromoteId + */ + get() { + val propertyValue = getPropertyValue("promoteId") + propertyValue?.let { + return PromoteId.fromProperty(it) + } + return null + } + /** * When loading a map, if PrefetchZoomDelta is set to any number greater than 0, the map * will first request a tile at zoom level lower than zoom - delta, but so that @@ -560,6 +579,15 @@ class GeoJsonSource(builder: Builder) : Source(builder.sourceId) { properties[propertyValue.propertyName] = propertyValue } + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. + */ + fun promoteId(value: PromoteId) = apply { + val propertyValue = PropertyValue("promoteId", TypeUtils.wrapToValue(value.toValue())) + properties[propertyValue.propertyName] = propertyValue + } + /** * When loading a map, if PrefetchZoomDelta is set to any number greater than 0, the map * will first request a tile at zoom level lower than zoom - delta, but so that @@ -736,6 +764,24 @@ class GeoJsonSource(builder: Builder) : Source(builder.sourceId) { */ get() = StyleManager.getStyleSourcePropertyDefaultValue("geojson", "generateId").silentUnwrap() + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. + */ + val defaultPromoteId: PromoteId? + /** + * Get the PromoteId property + * + * @return PromoteId + */ + get() { + val propertyValue = StyleManager.getStyleSourcePropertyDefaultValue("geojson", "promoteId").silentUnwrap() + propertyValue?.let { + return PromoteId.fromProperty(it) + } + return null + } + /** * When loading a map, if PrefetchZoomDelta is set to any number greater than 0, the map * will first request a tile at zoom level lower than zoom - delta, but so that diff --git a/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/VectorSource.kt b/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/VectorSource.kt index d250f459d7..37d0ae8be3 100644 --- a/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/VectorSource.kt +++ b/extension-style/src/main/java/com/mapbox/maps/extension/style/sources/generated/VectorSource.kt @@ -6,6 +6,7 @@ import com.mapbox.maps.StyleManager import com.mapbox.maps.extension.style.layers.properties.PropertyValue import com.mapbox.maps.extension.style.sources.Source import com.mapbox.maps.extension.style.sources.TileSet +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.extension.style.types.SourceDsl import com.mapbox.maps.extension.style.utils.TypeUtils import com.mapbox.maps.extension.style.utils.silentUnwrap @@ -145,6 +146,25 @@ class VectorSource(builder: Builder) : Source(builder.sourceId) { */ get() = getPropertyValue("attribution") + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. If specified as a string for a vector tile + * source, the same property is used across all its source layers. + */ + val promoteId: PromoteId? + /** + * Get the PromoteId property + * + * @return PromoteId + */ + get() { + val propertyValue = getPropertyValue("promoteId") + propertyValue?.let { + return PromoteId.fromProperty(it) + } + return null + } + /** * A setting to determine whether a source's tiles are cached locally. */ @@ -301,6 +321,16 @@ class VectorSource(builder: Builder) : Source(builder.sourceId) { properties[propertyValue.propertyName] = propertyValue } + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. If specified as a string for a vector tile + * source, the same property is used across all its source layers. + */ + fun promoteId(value: PromoteId) = apply { + val propertyValue = PropertyValue("promoteId", TypeUtils.wrapToValue(value.toValue())) + properties[propertyValue.propertyName] = propertyValue + } + /** * A setting to determine whether a source's tiles are cached locally. */ @@ -418,6 +448,25 @@ class VectorSource(builder: Builder) : Source(builder.sourceId) { */ get() = StyleManager.getStyleSourcePropertyDefaultValue("vector", "maxzoom").silentUnwrap() + /** + * A property to use as a feature id (for feature state). Either a property name, or + * an object of the form `{: }`. If specified as a string for a vector tile + * source, the same property is used across all its source layers. + */ + val defaultPromoteId: PromoteId? + /** + * Get the PromoteId property + * + * @return PromoteId + */ + get() { + val propertyValue = StyleManager.getStyleSourcePropertyDefaultValue("vector", "promoteId").silentUnwrap() + propertyValue?.let { + return PromoteId.fromProperty(it) + } + return null + } + /** * A setting to determine whether a source's tiles are cached locally. */ diff --git a/extension-style/src/main/java/com/mapbox/maps/extension/style/types/PromoteId.kt b/extension-style/src/main/java/com/mapbox/maps/extension/style/types/PromoteId.kt new file mode 100644 index 0000000000..37e5596f1a --- /dev/null +++ b/extension-style/src/main/java/com/mapbox/maps/extension/style/types/PromoteId.kt @@ -0,0 +1,48 @@ +package com.mapbox.maps.extension.style.types + +import androidx.annotation.Keep +import com.mapbox.bindgen.Value +import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource +import com.mapbox.maps.extension.style.sources.generated.VectorSource + +/** + * Holds a property type to promote a specific feature for feature state API. + * + * @param sourceId source layer id of the feature, either source [GeoJsonSource] or [VectorSource]. + * @param propertyName feature property name. + * + * For more information see [The online documentation]https://docs.mapbox.com/mapbox-gl-js/style-spec/types/#promoteId). + */ +@Keep +data class PromoteId @JvmOverloads constructor( + val sourceId: String? = null, + val propertyName: String +) { + internal fun toValue(): Value { + sourceId?.let { + return Value(hashMapOf(sourceId to Value(propertyName))) + } + return Value(propertyName) + } + + companion object { + /** + * Construct a [PromoteId] object from a Property returned from the core. + * Can be either of type [String] or [HashMap] of + */ + fun fromProperty(propertyName: Any): PromoteId { + return when (propertyName) { + is String -> { + PromoteId(propertyName = propertyName) + } + is HashMap<*, *> -> { + @Suppress("UNCHECKED_CAST") + val propertyMap = propertyName as HashMap + val key = propertyMap.keys.iterator().next() + PromoteId(key, propertyMap[key] ?: "") + } + else -> throw RuntimeException("Wrapping \"${propertyName}\" to PromoteId is not supported.") + } + } + } +} \ No newline at end of file diff --git a/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSourceTest.kt b/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSourceTest.kt index b2788a0342..766b66ff97 100644 --- a/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSourceTest.kt +++ b/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/GeoJsonSourceTest.kt @@ -16,6 +16,7 @@ import com.mapbox.maps.extension.style.StyleInterface import com.mapbox.maps.extension.style.expressions.dsl.generated.get import com.mapbox.maps.extension.style.expressions.dsl.generated.literal import com.mapbox.maps.extension.style.expressions.dsl.generated.sum +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.extension.style.utils.TypeUtils import io.mockk.* import org.junit.Assert.* @@ -382,6 +383,27 @@ class GeoJsonSourceTest { verify { style.getStyleSourceProperty("testId", "generateId") } } + @Test + fun promoteIdSet() { + val testSource = geoJsonSource("testId") { + promoteId(PromoteId(propertyName = "abc")) + } + testSource.bindTo(style) + + verify { style.addStyleSource("testId", capture(valueSlot)) } + assertTrue(valueSlot.captured.toString().contains("promoteId=abc")) + } + + @Test + fun promoteIdGet() { + every { styleProperty.value } returns TypeUtils.wrapToValue("abc") + val testSource = geoJsonSource("testId") {} + testSource.bindTo(style) + + assertEquals(PromoteId(propertyName = "abc"), testSource.promoteId) + verify { style.getStyleSourceProperty("testId", "promoteId") } + } + @Test fun prefetchZoomDeltaSet() { val testSource = geoJsonSource("testId") { @@ -647,6 +669,15 @@ class GeoJsonSourceTest { verify { StyleManager.getStyleSourcePropertyDefaultValue("geojson", "generateId") } } + @Test + fun defaultPromoteIdGet() { + every { styleProperty.value } returns TypeUtils.wrapToValue("abc") + + val expectedValue = PromoteId(propertyName = "abc") + assertEquals(expectedValue.toValue().toString(), GeoJsonSource.defaultPromoteId?.toValue().toString()) + verify { StyleManager.getStyleSourcePropertyDefaultValue("geojson", "promoteId") } + } + @Test fun defaultPrefetchZoomDeltaGet() { every { styleProperty.value } returns TypeUtils.wrapToValue(1L) diff --git a/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/VectorSourceTest.kt b/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/VectorSourceTest.kt index 528611a397..b6f492e47c 100644 --- a/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/VectorSourceTest.kt +++ b/extension-style/src/test/java/com/mapbox/maps/extension/style/sources/generated/VectorSourceTest.kt @@ -11,6 +11,7 @@ import com.mapbox.maps.StylePropertyValueKind import com.mapbox.maps.extension.style.ShadowStyleManager import com.mapbox.maps.extension.style.StyleInterface import com.mapbox.maps.extension.style.sources.TileSet +import com.mapbox.maps.extension.style.types.PromoteId import com.mapbox.maps.extension.style.utils.TypeUtils import io.mockk.* import org.junit.Assert.* @@ -236,6 +237,27 @@ class VectorSourceTest { verify { style.getStyleSourceProperty("testId", "attribution") } } + @Test + fun promoteIdSet() { + val testSource = vectorSource("testId") { + promoteId(PromoteId(propertyName = "abc")) + } + testSource.bindTo(style) + + verify { style.addStyleSource("testId", capture(valueSlot)) } + assertTrue(valueSlot.captured.toString().contains("promoteId=abc")) + } + + @Test + fun promoteIdGet() { + every { styleProperty.value } returns TypeUtils.wrapToValue("abc") + val testSource = vectorSource("testId") {} + testSource.bindTo(style) + + assertEquals(PromoteId(propertyName = "abc"), testSource.promoteId) + verify { style.getStyleSourceProperty("testId", "promoteId") } + } + @Test fun volatileSet() { val testSource = vectorSource("testId") { @@ -417,6 +439,15 @@ class VectorSourceTest { verify { StyleManager.getStyleSourcePropertyDefaultValue("vector", "maxzoom") } } + @Test + fun defaultPromoteIdGet() { + every { styleProperty.value } returns TypeUtils.wrapToValue("abc") + + val expectedValue = PromoteId(propertyName = "abc") + assertEquals(expectedValue.toValue().toString(), VectorSource.defaultPromoteId?.toValue().toString()) + verify { StyleManager.getStyleSourcePropertyDefaultValue("vector", "promoteId") } + } + @Test fun defaultVolatileGet() { every { styleProperty.value } returns TypeUtils.wrapToValue(true)