From 0ae57625db773fd1d44c0b4ae98e5883912101dc Mon Sep 17 00:00:00 2001 From: Release SDK bot for Maps SDK team Date: Wed, 8 Jan 2025 18:16:38 -0500 Subject: [PATCH] Add map.addInteraction, add Standard featuresets --- CHANGELOG.md | 18 + .../com/mapbox/maps/mapbox_maps/Extentions.kt | 45 +- .../mapbox_maps/MapInterfaceController.kt | 53 +- .../maps/mapbox_maps/MapboxMapController.kt | 55 ++ .../maps/mapbox_maps/pigeons/MapInterfaces.kt | 511 +++++++--------- .../interactive_features_test.dart | 83 +-- example/ios/Podfile.lock | 5 +- example/lib/interactive_features_example.dart | 107 ++-- .../Classes/Extensions.swift | 36 +- .../Classes/Generated/MapInterfaces.swift | 529 ++++++++--------- .../Classes/MapInterfaceController.swift | 32 +- .../Classes/MapboxMapController.swift | 32 + lib/mapbox_maps_flutter.dart | 4 + lib/src/callbacks.dart | 4 + lib/src/mapbox_map.dart | 76 ++- lib/src/mapbox_maps_platform.dart | 17 + lib/src/pigeons/map_interfaces.dart | 547 ++++++++---------- .../interactive_features.dart | 44 ++ .../standard_buildings.dart | 52 ++ .../standard_place_labels.dart | 64 ++ .../interactive_features/standard_poi.dart | 85 +++ 21 files changed, 1210 insertions(+), 1189 deletions(-) create mode 100644 lib/src/style/interactive_features/interactive_features.dart create mode 100644 lib/src/style/interactive_features/standard_buildings.dart create mode 100644 lib/src/style/interactive_features/standard_place_labels.dart create mode 100644 lib/src/style/interactive_features/standard_poi.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 7735c5be..6579250d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,24 @@ # main * Add support for Swift Package Manager. +* Introduce the experimental Interactions API, a toolset that allows you to handle interactions on both layers and basemap features for styles. This API introduces a new concept called `Featureset`, which allows Evolving Basemap styles, such as Standard, to export an abstract set of features, such as POI, buildings, and place labels, regardless of which layers they are rendered on. An `Interaction` can then be targeted to these features, modifying their state when interacted with. For example, you can add a `TapInteraction` to your map which targets the `buildings` `Featureset`. When a user taps on a building, the building will be highlighted and its color will change to blue. + +```dart +var tapInteraction = TapInteraction(Featureset.standardBuildings()) +mapboxMap.addInteraction(tapInteraction, + (_, FeaturesetFeature feature) { + mapboxMap.setFeatureStateForFeaturesetFeature(feature, + StandardBuildingState(highlight: true)); + } +); +``` + +Specific changes: + * Introduce the experimental `MapboxMap.addInteractions` method, which allows you to add interactions to the map. + * Introduce `TapInteraction` and `LongTapInteraction`, which allow you to add tap and longTap interactions to the map. + * Introduce `FeaturesetDescriptor` -- and convenience descriptors for `StandardBuildings`, `StandardPOIs`, and `StandardPlaceLabels` -- which allow you to describe the featureset you want `Interactions` to target. + * Introduce low-level methods for creating and manipulating interactive features: `queryRenderedFeatures`, `querySourceFeatures`, `setFeatureState`, `getFeatureState`, `removeFeatureState`, `resetFeatureState` +* For more guidance with using these new features see `interactive_features_example.dart`. ### 2.5.0 diff --git a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/Extentions.kt b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/Extentions.kt index 9bb93df8..ec31b99f 100644 --- a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/Extentions.kt +++ b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/Extentions.kt @@ -16,7 +16,6 @@ import com.mapbox.maps.MapboxExperimental import com.mapbox.maps.StylePackError import com.mapbox.maps.applyDefaultParams import com.mapbox.maps.debugoptions.MapViewDebugOptions -import com.mapbox.maps.extension.style.expressions.generated.Expression import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName import com.mapbox.maps.extension.style.light.LightPosition import com.mapbox.maps.extension.style.light.generated.ambientLight @@ -290,29 +289,27 @@ fun FeaturesetDescriptor.toTypedFeaturesetDescriptor(): TypedFeaturesetDescripto ) } -fun FeaturesetQueryTarget.toFeaturesetQueryTarget(): com.mapbox.maps.FeaturesetQueryTarget { - return com.mapbox.maps.FeaturesetQueryTarget(featureset.toFeatureSetDescriptor(), filter?.let { Expression.fromRaw(filter) }, id) -} - @OptIn(MapboxExperimental::class) fun Map.toFeatureState(): com.mapbox.maps.interactions.FeatureState { val map = this return FeatureState { for ((key, value) in map) { - when (value) { - is String -> { - addStringState(key, value) - } - is Long -> { - addLongState(key, value) - } - is Double -> { - addDoubleState(key, value) - } - is Boolean -> { - addBooleanState(key, value) + value?.let { + when (value) { + is String -> { + addStringState(key, value) + } + is Long -> { + addLongState(key, value) + } + is Double -> { + addDoubleState(key, value) + } + is Boolean -> { + addBooleanState(key, value) + } + else -> throw (RuntimeException("Unsupported (key, value): ($key, $value)")) } - else -> throw (RuntimeException("Unsupported (key, value): ($key, $value)")) } } } @@ -321,7 +318,7 @@ fun Map.toFeatureState(): com.mapbox.maps.interactions.FeatureStat @OptIn(MapboxExperimental::class) @SuppressLint("RestrictedApi") fun FeaturesetFeature.toFeaturesetFeature(): com.mapbox.maps.interactions.FeaturesetFeature { - val jsonObject: JsonObject = JsonParser.parseString(properties.toString()).getAsJsonObject() + val jsonObject: JsonObject = JsonParser.parseString(Gson().toJson(properties)).getAsJsonObject() featureset.featuresetId?.let { return com.mapbox.maps.interactions.FeaturesetFeature( id?.toFeaturesetFeatureId(), @@ -642,6 +639,16 @@ fun com.mapbox.maps.interactions.FeaturesetFeature.toFLTFeatureset ) } +@SuppressLint("RestrictedApi") +@OptIn(MapboxExperimental::class) +fun com.mapbox.maps.InteractionContext.toFLTMapContentGestureContext(): MapContentGestureContext { + return MapContentGestureContext( + ScreenCoordinate(screenCoordinate.x, screenCoordinate.y), + coordinateInfo.coordinate, + GestureState.ENDED + ) +} + fun com.mapbox.maps.QueriedSourceFeature.toFLTQueriedSourceFeature(): QueriedSourceFeature { return QueriedSourceFeature(queriedFeature.toFLTQueriedFeature()) } diff --git a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapInterfaceController.kt b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapInterfaceController.kt index f889203c..086082ae 100644 --- a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapInterfaceController.kt +++ b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapInterfaceController.kt @@ -23,7 +23,6 @@ import com.mapbox.maps.mapbox_maps.pigeons.FeatureExtensionValue import com.mapbox.maps.mapbox_maps.pigeons.FeaturesetDescriptor import com.mapbox.maps.mapbox_maps.pigeons.FeaturesetFeature import com.mapbox.maps.mapbox_maps.pigeons.FeaturesetFeatureId -import com.mapbox.maps.mapbox_maps.pigeons.FeaturesetQueryTarget import com.mapbox.maps.mapbox_maps.pigeons.MapDebugOptions import com.mapbox.maps.mapbox_maps.pigeons.MapOptions import com.mapbox.maps.mapbox_maps.pigeons.NorthOrientation @@ -180,32 +179,6 @@ class MapInterfaceController( } } - @OptIn(MapboxExperimental::class, MapboxDelicateApi::class) - override fun queryRenderedFeaturesForTargets( - geometry: _RenderedQueryGeometry, - targets: List, - callback: (Result>) -> Unit - ) { - mapboxMap.queryRenderedFeatures( - geometry.toRenderedQueryGeometry(context), - targets.map { target -> - target.toFeaturesetQueryTarget() - } - ) { - if (it.isError) { - callback(Result.failure(Throwable(it.error))) - } else { - callback( - Result.success( - it.value!!.map { feature -> - feature.toFLTQueriedRenderedFeature() - }.toMutableList() - ) - ) - } - } - } - @OptIn(MapboxExperimental::class) override fun queryRenderedFeaturesForFeatureset( geometry: _RenderedQueryGeometry, @@ -214,8 +187,8 @@ class MapInterfaceController( callback: (Result>) -> Unit ) { mapboxMap.queryRenderedFeatures( - geometry.toRenderedQueryGeometry(context), featureset.toTypedFeaturesetDescriptor() as TypedFeaturesetDescriptor<*, com.mapbox.maps.interactions.FeaturesetFeature>, + geometry.toRenderedQueryGeometry(context), filter?.let { Expression.fromRaw(filter) } ) { callback( @@ -234,8 +207,8 @@ class MapInterfaceController( ) { val geometry = RenderedQueryGeometry(ScreenBox(ScreenCoordinate(0.0, 0.0), ScreenCoordinate(mapView.width.toDouble(), mapView.height.toDouble()))) mapboxMap.queryRenderedFeatures( - geometry, featureset.toTypedFeaturesetDescriptor() as TypedFeaturesetDescriptor<*, com.mapbox.maps.interactions.FeaturesetFeature>, + geometry, filter?.let { Expression.fromRaw(filter) } ) { callback( @@ -264,28 +237,6 @@ class MapInterfaceController( } } - @OptIn(MapboxExperimental::class) - override fun querySourceFeaturesForTargets( - target: FeaturesetQueryTarget, - callback: (Result>) -> Unit - ) { - mapboxMap.querySourceFeatures( - target.featureset.toTypedFeaturesetDescriptor(), - target.filter?.let { Expression.fromRaw(target.filter) }, - target.id - ) { - if (it.isError) { - callback(Result.failure(Throwable(it.error))) - } else { - callback( - Result.success( - it.value!!.map { feature -> feature.toFLTQueriedSourceFeature() }.toMutableList() - ) - ) - } - } - } - override fun getGeoJsonClusterLeaves( sourceIdentifier: String, cluster: Map, diff --git a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapboxMapController.kt b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapboxMapController.kt index 06002819..755b0e23 100644 --- a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapboxMapController.kt +++ b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/MapboxMapController.kt @@ -11,13 +11,20 @@ import androidx.lifecycle.setViewTreeLifecycleOwner import com.mapbox.bindgen.Value import com.mapbox.common.SettingsServiceFactory import com.mapbox.common.SettingsServiceStorageType +import com.mapbox.common.toValue +import com.mapbox.maps.ClickInteraction +import com.mapbox.maps.FeaturesetDescriptor +import com.mapbox.maps.LongClickInteraction import com.mapbox.maps.MapInitOptions import com.mapbox.maps.MapView import com.mapbox.maps.MapboxMap +import com.mapbox.maps.extension.style.expressions.dsl.generated.id import com.mapbox.maps.mapbox_maps.annotation.AnnotationController import com.mapbox.maps.mapbox_maps.pigeons.AttributionSettingsInterface import com.mapbox.maps.mapbox_maps.pigeons.CompassSettingsInterface import com.mapbox.maps.mapbox_maps.pigeons.GesturesSettingsInterface +import com.mapbox.maps.mapbox_maps.pigeons.InteractionType +import com.mapbox.maps.mapbox_maps.pigeons.InteractionsListener import com.mapbox.maps.mapbox_maps.pigeons.LogoSettingsInterface import com.mapbox.maps.mapbox_maps.pigeons.Projection import com.mapbox.maps.mapbox_maps.pigeons.ScaleBarSettingsInterface @@ -235,6 +242,54 @@ class MapboxMapController( gestureController.removeListeners() result.success(null) } + "interactions#add_interaction" -> { + val listener = InteractionsListener(messenger, channelSuffix) + val arguments: HashMap = call.arguments as? HashMap ?: return + val featuresetDescriptorList = arguments["featuresetDescriptor"] as? List ?: return + val featuresetDescriptor = com.mapbox.maps.mapbox_maps.pigeons.FeaturesetDescriptor.fromList(featuresetDescriptorList) + val interactionTypeRaw = arguments["interactionType"] as? Int ?: return + val interactionType = InteractionType.ofRaw(interactionTypeRaw) + val stopPropagation = arguments["stopPropagation"] as? Boolean ?: return + val id = arguments["id"] as? Int ?: return + val filter = arguments["filter"] as? String + val radius = arguments["radius"] as? Double + + featuresetDescriptor.featuresetId?.let { + when (interactionType) { + InteractionType.TAP -> mapboxMap?.addInteraction( + ClickInteraction.featureset(id = it, importId = featuresetDescriptor.importId, filter = filter.toValue(), radius = radius) { featuresetFeature, context -> + listener.onInteraction(context.toFLTMapContentGestureContext(), featuresetFeature.toFLTFeaturesetFeature(), id.toLong()) { _ -> } + return@featureset stopPropagation + } + ) + InteractionType.LONG_TAP -> mapboxMap?.addInteraction( + LongClickInteraction.featureset(id = it, importId = featuresetDescriptor.importId, filter = filter.toValue(), radius = radius) { featuresetFeature, context -> + listener.onInteraction(context.toFLTMapContentGestureContext(), featuresetFeature.toFLTFeaturesetFeature(), id.toLong()) { _ -> } + return@featureset stopPropagation + } + ) + null -> return + } + } ?: featuresetDescriptor.layerId?.let { + when (interactionType) { + InteractionType.TAP -> mapboxMap?.addInteraction( + ClickInteraction.layer(id = it, filter = filter.toValue(), radius = radius) { featuresetFeature, context -> + listener.onInteraction(context.toFLTMapContentGestureContext(), featuresetFeature.toFLTFeaturesetFeature(), id.toLong()) { _ -> } + return@layer stopPropagation + } + ) + InteractionType.LONG_TAP -> mapboxMap?.addInteraction( + LongClickInteraction.layer(id = it, filter = filter.toValue(), radius = radius) { featuresetFeature, context -> + listener.onInteraction(context.toFLTMapContentGestureContext(), featuresetFeature.toFLTFeaturesetFeature(), id.toLong()) { _ -> } + return@layer stopPropagation + } + ) + null -> return + } + } + + result.success(null) + } "platform#releaseMethodChannels" -> { dispose() result.success(null) diff --git a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/pigeons/MapInterfaces.kt b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/pigeons/MapInterfaces.kt index c788fbc3..e85888e3 100644 --- a/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/pigeons/MapInterfaces.kt +++ b/android/src/main/kotlin/com/mapbox/maps/mapbox_maps/pigeons/MapInterfaces.kt @@ -35,6 +35,10 @@ private fun wrapError(exception: Throwable): List { } } +private fun createConnectionError(channelName: String): FlutterError { + return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "") +} + /** * Error class for passing custom error details to Flutter via a thrown PlatformException. * @property code The error code. @@ -230,8 +234,8 @@ enum class ViewAnnotationAnchor(val raw: Int) { } enum class InteractionType(val raw: Int) { - CLICK(0), - LONG_CLICK(1); + TAP(0), + LONG_TAP(1); companion object { fun ofRaw(raw: Int): InteractionType? { @@ -1398,44 +1402,55 @@ data class FeaturesetFeatureId( } /** Generated class from Pigeon that represents data sent in messages. */ -data class Interaction( - val typedFeaturesetDescriptor: TypedFeaturesetDescriptor, - val interactionType: InteractionType, - val filter: String? = null +data class FeatureState( + val map: Map ) { companion object { - fun fromList(pigeonVar_list: List): Interaction { - val typedFeaturesetDescriptor = pigeonVar_list[0] as TypedFeaturesetDescriptor - val interactionType = pigeonVar_list[1] as InteractionType - val filter = pigeonVar_list[2] as String? - return Interaction(typedFeaturesetDescriptor, interactionType, filter) + fun fromList(pigeonVar_list: List): FeatureState { + val map = pigeonVar_list[0] as Map + return FeatureState(map) } } fun toList(): List { return listOf( - typedFeaturesetDescriptor, - interactionType, - filter, + map, ) } } -/** Generated class from Pigeon that represents data sent in messages. */ -data class TypedFeaturesetDescriptor( +/** + * An interaction that can be added to the map. + * + * To create an interaction use ``TapInteraction`` and ``LongClickInteraction`` implementations. + * + * See also: ``MapboxMap/addInteraction``. + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class Interaction( val featuresetDescriptor: FeaturesetDescriptor, - val featuresetType: String + val interactionType: InteractionType, + val stopPropagation: Boolean, + val filter: String? = null, + val radius: Double? = null ) { companion object { - fun fromList(pigeonVar_list: List): TypedFeaturesetDescriptor { + fun fromList(pigeonVar_list: List): Interaction { val featuresetDescriptor = pigeonVar_list[0] as FeaturesetDescriptor - val featuresetType = pigeonVar_list[1] as String - return TypedFeaturesetDescriptor(featuresetDescriptor, featuresetType) + val interactionType = pigeonVar_list[1] as InteractionType + val stopPropagation = pigeonVar_list[2] as Boolean + val filter = pigeonVar_list[3] as String? + val radius = pigeonVar_list[4] as Double? + return Interaction(featuresetDescriptor, interactionType, stopPropagation, filter, radius) } } fun toList(): List { return listOf( featuresetDescriptor, - featuresetType, + interactionType, + stopPropagation, + filter, + radius, ) } } @@ -1443,34 +1458,12 @@ data class TypedFeaturesetDescriptor( /** * A featureset descriptor. * - * The descriptor instance acts as a universal target for interactions or querying rendered features (see - * ``MapboxMap/queryRenderedFeatures(with:featureset:filter:completion:)``). - * * Generated class from Pigeon that represents data sent in messages. */ data class FeaturesetDescriptor( - /** - * An optional unique identifier for the featureset within the style. - * This id is used to reference a specific featureset. - * - * * Note: If `featuresetId` is provided and valid, it takes precedence over `layerId`, - * * meaning `layerId` will not be considered even if it has a valid value. - */ val featuresetId: String? = null, - /** - * An optional import id that is required if the featureset is defined within an imported style. - * If the featureset belongs to the current style, this field should be set to a null string. - * - * Note: `importId` is only applicable when used in conjunction with `featuresetId` - * and has no effect when used with `layerId`. - */ + /** */ val importId: String? = null, - /** - * An optional unique identifier for the layer within the current style. - * - * Note: If `featuresetId` is valid, `layerId` will be ignored even if it has a valid value. - * Additionally, `importId` does not apply when using `layerId`. - */ val layerId: String? = null ) { companion object { @@ -1490,33 +1483,12 @@ data class FeaturesetDescriptor( } } -/** - * A basic feature of a featureset. - * - * The featureset feature is different to the `Turf.Feature`. The latter represents any GeoJSON feature, while the former is a high level representation of features. - * - * Generated class from Pigeon that represents data sent in messages. - */ +/** Generated class from Pigeon that represents data sent in messages. */ data class FeaturesetFeature( - /** - * An identifier of the feature. - * - * The identifier can be `nil` if the underlying source doesn't have identifiers for features. - * In this case it's impossible to set a feature state for an individual feature. - */ val id: FeaturesetFeatureId? = null, - /** A featureset descriptor denoting the featureset this feature belongs to. */ val featureset: FeaturesetDescriptor, - /** A feature geometry. */ val geometry: Map, - /** Feature JSON properties. */ val properties: Map, - /** - * A feature state. - * - * This is a **snapshot** of the state that the feature had when it was interacted with. - * To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. - */ val state: Map ) { companion object { @@ -2084,315 +2056,325 @@ private open class MapInterfacesPigeonCodec : StandardMessageCodec() { } 138.toByte() -> { return (readValue(buffer) as Long?)?.let { - Type.ofRaw(it.toInt()) + GestureState.ofRaw(it.toInt()) } } 139.toByte() -> { return (readValue(buffer) as Long?)?.let { - FillExtrusionBaseAlignment.ofRaw(it.toInt()) + Type.ofRaw(it.toInt()) } } 140.toByte() -> { return (readValue(buffer) as Long?)?.let { - FillExtrusionHeightAlignment.ofRaw(it.toInt()) + FillExtrusionBaseAlignment.ofRaw(it.toInt()) } } 141.toByte() -> { return (readValue(buffer) as Long?)?.let { - BackgroundPitchAlignment.ofRaw(it.toInt()) + FillExtrusionHeightAlignment.ofRaw(it.toInt()) } } 142.toByte() -> { return (readValue(buffer) as Long?)?.let { - StylePackErrorType.ofRaw(it.toInt()) + BackgroundPitchAlignment.ofRaw(it.toInt()) } } 143.toByte() -> { return (readValue(buffer) as Long?)?.let { - ResponseErrorReason.ofRaw(it.toInt()) + StylePackErrorType.ofRaw(it.toInt()) } } 144.toByte() -> { return (readValue(buffer) as Long?)?.let { - OfflineRegionDownloadState.ofRaw(it.toInt()) + ResponseErrorReason.ofRaw(it.toInt()) } } 145.toByte() -> { return (readValue(buffer) as Long?)?.let { - TileStoreUsageMode.ofRaw(it.toInt()) + OfflineRegionDownloadState.ofRaw(it.toInt()) } } 146.toByte() -> { return (readValue(buffer) as Long?)?.let { - StylePropertyValueKind.ofRaw(it.toInt()) + TileStoreUsageMode.ofRaw(it.toInt()) } } 147.toByte() -> { return (readValue(buffer) as Long?)?.let { - StyleProjectionName.ofRaw(it.toInt()) + StylePropertyValueKind.ofRaw(it.toInt()) } } 148.toByte() -> { return (readValue(buffer) as Long?)?.let { - Anchor.ofRaw(it.toInt()) + StyleProjectionName.ofRaw(it.toInt()) } } 149.toByte() -> { return (readValue(buffer) as Long?)?.let { - HttpMethod.ofRaw(it.toInt()) + Anchor.ofRaw(it.toInt()) } } 150.toByte() -> { return (readValue(buffer) as Long?)?.let { - HttpRequestErrorType.ofRaw(it.toInt()) + HttpMethod.ofRaw(it.toInt()) } } 151.toByte() -> { return (readValue(buffer) as Long?)?.let { - DownloadErrorCode.ofRaw(it.toInt()) + HttpRequestErrorType.ofRaw(it.toInt()) } } 152.toByte() -> { return (readValue(buffer) as Long?)?.let { - DownloadState.ofRaw(it.toInt()) + DownloadErrorCode.ofRaw(it.toInt()) } } 153.toByte() -> { return (readValue(buffer) as Long?)?.let { - TileRegionErrorType.ofRaw(it.toInt()) + DownloadState.ofRaw(it.toInt()) } } 154.toByte() -> { return (readValue(buffer) as Long?)?.let { - _MapEvent.ofRaw(it.toInt()) + TileRegionErrorType.ofRaw(it.toInt()) } } 155.toByte() -> { - return (readValue(buffer) as? List)?.let { - PointDecoder.fromList(it) + return (readValue(buffer) as Long?)?.let { + _MapEvent.ofRaw(it.toInt()) } } 156.toByte() -> { return (readValue(buffer) as? List)?.let { - FeatureDecoder.fromList(it) + PointDecoder.fromList(it) } } 157.toByte() -> { return (readValue(buffer) as? List)?.let { - GlyphsRasterizationOptions.fromList(it) + FeatureDecoder.fromList(it) } } 158.toByte() -> { return (readValue(buffer) as? List)?.let { - TileCoverOptions.fromList(it) + GlyphsRasterizationOptions.fromList(it) } } 159.toByte() -> { return (readValue(buffer) as? List)?.let { - MbxEdgeInsets.fromList(it) + TileCoverOptions.fromList(it) } } 160.toByte() -> { return (readValue(buffer) as? List)?.let { - CameraOptions.fromList(it) + MbxEdgeInsets.fromList(it) } } 161.toByte() -> { return (readValue(buffer) as? List)?.let { - CameraState.fromList(it) + CameraOptions.fromList(it) } } 162.toByte() -> { return (readValue(buffer) as? List)?.let { - CameraBoundsOptions.fromList(it) + CameraState.fromList(it) } } 163.toByte() -> { return (readValue(buffer) as? List)?.let { - CameraBounds.fromList(it) + CameraBoundsOptions.fromList(it) } } 164.toByte() -> { return (readValue(buffer) as? List)?.let { - MapAnimationOptions.fromList(it) + CameraBounds.fromList(it) } } 165.toByte() -> { return (readValue(buffer) as? List)?.let { - CoordinateBounds.fromList(it) + MapAnimationOptions.fromList(it) } } 166.toByte() -> { return (readValue(buffer) as? List)?.let { - MapDebugOptions.fromList(it) + CoordinateBounds.fromList(it) } } 167.toByte() -> { return (readValue(buffer) as? List)?.let { - TileCacheBudgetInMegabytes.fromList(it) + MapDebugOptions.fromList(it) } } 168.toByte() -> { return (readValue(buffer) as? List)?.let { - TileCacheBudgetInTiles.fromList(it) + TileCacheBudgetInMegabytes.fromList(it) } } 169.toByte() -> { return (readValue(buffer) as? List)?.let { - MapOptions.fromList(it) + TileCacheBudgetInTiles.fromList(it) } } 170.toByte() -> { return (readValue(buffer) as? List)?.let { - ScreenCoordinate.fromList(it) + MapOptions.fromList(it) } } 171.toByte() -> { return (readValue(buffer) as? List)?.let { - ScreenBox.fromList(it) + ScreenCoordinate.fromList(it) } } 172.toByte() -> { return (readValue(buffer) as? List)?.let { - CoordinateBoundsZoom.fromList(it) + ScreenBox.fromList(it) } } 173.toByte() -> { return (readValue(buffer) as? List)?.let { - Size.fromList(it) + CoordinateBoundsZoom.fromList(it) } } 174.toByte() -> { return (readValue(buffer) as? List)?.let { - RenderedQueryOptions.fromList(it) + Size.fromList(it) } } 175.toByte() -> { return (readValue(buffer) as? List)?.let { - SourceQueryOptions.fromList(it) + RenderedQueryOptions.fromList(it) } } 176.toByte() -> { return (readValue(buffer) as? List)?.let { - FeatureExtensionValue.fromList(it) + SourceQueryOptions.fromList(it) } } 177.toByte() -> { return (readValue(buffer) as? List)?.let { - LayerPosition.fromList(it) + FeatureExtensionValue.fromList(it) } } 178.toByte() -> { return (readValue(buffer) as? List)?.let { - QueriedRenderedFeature.fromList(it) + LayerPosition.fromList(it) } } 179.toByte() -> { return (readValue(buffer) as? List)?.let { - QueriedSourceFeature.fromList(it) + QueriedRenderedFeature.fromList(it) } } 180.toByte() -> { return (readValue(buffer) as? List)?.let { - QueriedFeature.fromList(it) + QueriedSourceFeature.fromList(it) } } 181.toByte() -> { return (readValue(buffer) as? List)?.let { - FeaturesetFeatureId.fromList(it) + QueriedFeature.fromList(it) } } 182.toByte() -> { return (readValue(buffer) as? List)?.let { - Interaction.fromList(it) + FeaturesetFeatureId.fromList(it) } } 183.toByte() -> { return (readValue(buffer) as? List)?.let { - TypedFeaturesetDescriptor.fromList(it) + FeatureState.fromList(it) } } 184.toByte() -> { return (readValue(buffer) as? List)?.let { - FeaturesetDescriptor.fromList(it) + Interaction.fromList(it) } } 185.toByte() -> { return (readValue(buffer) as? List)?.let { - FeaturesetFeature.fromList(it) + FeaturesetDescriptor.fromList(it) } } 186.toByte() -> { return (readValue(buffer) as? List)?.let { - FeaturesetQueryTarget.fromList(it) + FeaturesetFeature.fromList(it) } } 187.toByte() -> { return (readValue(buffer) as? List)?.let { - _RenderedQueryGeometry.fromList(it) + FeaturesetQueryTarget.fromList(it) } } 188.toByte() -> { return (readValue(buffer) as? List)?.let { - ProjectedMeters.fromList(it) + MapContentGestureContext.fromList(it) } } 189.toByte() -> { return (readValue(buffer) as? List)?.let { - MercatorCoordinate.fromList(it) + _RenderedQueryGeometry.fromList(it) } } 190.toByte() -> { return (readValue(buffer) as? List)?.let { - StyleObjectInfo.fromList(it) + ProjectedMeters.fromList(it) } } 191.toByte() -> { return (readValue(buffer) as? List)?.let { - StyleProjection.fromList(it) + MercatorCoordinate.fromList(it) } } 192.toByte() -> { return (readValue(buffer) as? List)?.let { - FlatLight.fromList(it) + StyleObjectInfo.fromList(it) } } 193.toByte() -> { return (readValue(buffer) as? List)?.let { - DirectionalLight.fromList(it) + StyleProjection.fromList(it) } } 194.toByte() -> { return (readValue(buffer) as? List)?.let { - AmbientLight.fromList(it) + FlatLight.fromList(it) } } 195.toByte() -> { return (readValue(buffer) as? List)?.let { - MbxImage.fromList(it) + DirectionalLight.fromList(it) } } 196.toByte() -> { return (readValue(buffer) as? List)?.let { - ImageStretches.fromList(it) + AmbientLight.fromList(it) } } 197.toByte() -> { return (readValue(buffer) as? List)?.let { - ImageContent.fromList(it) + MbxImage.fromList(it) } } 198.toByte() -> { return (readValue(buffer) as? List)?.let { - TransitionOptions.fromList(it) + ImageStretches.fromList(it) } } 199.toByte() -> { return (readValue(buffer) as? List)?.let { - CanonicalTileID.fromList(it) + ImageContent.fromList(it) } } 200.toByte() -> { + return (readValue(buffer) as? List)?.let { + TransitionOptions.fromList(it) + } + } + 201.toByte() -> { + return (readValue(buffer) as? List)?.let { + CanonicalTileID.fromList(it) + } + } + 202.toByte() -> { return (readValue(buffer) as? List)?.let { StylePropertyValue.fromList(it) } @@ -2438,258 +2420,266 @@ private open class MapInterfacesPigeonCodec : StandardMessageCodec() { stream.write(137) writeValue(stream, value.raw) } - is Type -> { + is GestureState -> { stream.write(138) writeValue(stream, value.raw) } - is FillExtrusionBaseAlignment -> { + is Type -> { stream.write(139) writeValue(stream, value.raw) } - is FillExtrusionHeightAlignment -> { + is FillExtrusionBaseAlignment -> { stream.write(140) writeValue(stream, value.raw) } - is BackgroundPitchAlignment -> { + is FillExtrusionHeightAlignment -> { stream.write(141) writeValue(stream, value.raw) } - is StylePackErrorType -> { + is BackgroundPitchAlignment -> { stream.write(142) writeValue(stream, value.raw) } - is ResponseErrorReason -> { + is StylePackErrorType -> { stream.write(143) writeValue(stream, value.raw) } - is OfflineRegionDownloadState -> { + is ResponseErrorReason -> { stream.write(144) writeValue(stream, value.raw) } - is TileStoreUsageMode -> { + is OfflineRegionDownloadState -> { stream.write(145) writeValue(stream, value.raw) } - is StylePropertyValueKind -> { + is TileStoreUsageMode -> { stream.write(146) writeValue(stream, value.raw) } - is StyleProjectionName -> { + is StylePropertyValueKind -> { stream.write(147) writeValue(stream, value.raw) } - is Anchor -> { + is StyleProjectionName -> { stream.write(148) writeValue(stream, value.raw) } - is HttpMethod -> { + is Anchor -> { stream.write(149) writeValue(stream, value.raw) } - is HttpRequestErrorType -> { + is HttpMethod -> { stream.write(150) writeValue(stream, value.raw) } - is DownloadErrorCode -> { + is HttpRequestErrorType -> { stream.write(151) writeValue(stream, value.raw) } - is DownloadState -> { + is DownloadErrorCode -> { stream.write(152) writeValue(stream, value.raw) } - is TileRegionErrorType -> { + is DownloadState -> { stream.write(153) writeValue(stream, value.raw) } - is _MapEvent -> { + is TileRegionErrorType -> { stream.write(154) writeValue(stream, value.raw) } - is Point -> { + is _MapEvent -> { stream.write(155) - writeValue(stream, value.toList()) + writeValue(stream, value.raw) } - is Feature -> { + is Point -> { stream.write(156) writeValue(stream, value.toList()) } - is GlyphsRasterizationOptions -> { + is Feature -> { stream.write(157) writeValue(stream, value.toList()) } - is TileCoverOptions -> { + is GlyphsRasterizationOptions -> { stream.write(158) writeValue(stream, value.toList()) } - is MbxEdgeInsets -> { + is TileCoverOptions -> { stream.write(159) writeValue(stream, value.toList()) } - is CameraOptions -> { + is MbxEdgeInsets -> { stream.write(160) writeValue(stream, value.toList()) } - is CameraState -> { + is CameraOptions -> { stream.write(161) writeValue(stream, value.toList()) } - is CameraBoundsOptions -> { + is CameraState -> { stream.write(162) writeValue(stream, value.toList()) } - is CameraBounds -> { + is CameraBoundsOptions -> { stream.write(163) writeValue(stream, value.toList()) } - is MapAnimationOptions -> { + is CameraBounds -> { stream.write(164) writeValue(stream, value.toList()) } - is CoordinateBounds -> { + is MapAnimationOptions -> { stream.write(165) writeValue(stream, value.toList()) } - is MapDebugOptions -> { + is CoordinateBounds -> { stream.write(166) writeValue(stream, value.toList()) } - is TileCacheBudgetInMegabytes -> { + is MapDebugOptions -> { stream.write(167) writeValue(stream, value.toList()) } - is TileCacheBudgetInTiles -> { + is TileCacheBudgetInMegabytes -> { stream.write(168) writeValue(stream, value.toList()) } - is MapOptions -> { + is TileCacheBudgetInTiles -> { stream.write(169) writeValue(stream, value.toList()) } - is ScreenCoordinate -> { + is MapOptions -> { stream.write(170) writeValue(stream, value.toList()) } - is ScreenBox -> { + is ScreenCoordinate -> { stream.write(171) writeValue(stream, value.toList()) } - is CoordinateBoundsZoom -> { + is ScreenBox -> { stream.write(172) writeValue(stream, value.toList()) } - is Size -> { + is CoordinateBoundsZoom -> { stream.write(173) writeValue(stream, value.toList()) } - is RenderedQueryOptions -> { + is Size -> { stream.write(174) writeValue(stream, value.toList()) } - is SourceQueryOptions -> { + is RenderedQueryOptions -> { stream.write(175) writeValue(stream, value.toList()) } - is FeatureExtensionValue -> { + is SourceQueryOptions -> { stream.write(176) writeValue(stream, value.toList()) } - is LayerPosition -> { + is FeatureExtensionValue -> { stream.write(177) writeValue(stream, value.toList()) } - is QueriedRenderedFeature -> { + is LayerPosition -> { stream.write(178) writeValue(stream, value.toList()) } - is QueriedSourceFeature -> { + is QueriedRenderedFeature -> { stream.write(179) writeValue(stream, value.toList()) } - is QueriedFeature -> { + is QueriedSourceFeature -> { stream.write(180) writeValue(stream, value.toList()) } - is FeaturesetFeatureId -> { + is QueriedFeature -> { stream.write(181) writeValue(stream, value.toList()) } - is Interaction -> { + is FeaturesetFeatureId -> { stream.write(182) writeValue(stream, value.toList()) } - is TypedFeaturesetDescriptor -> { + is FeatureState -> { stream.write(183) writeValue(stream, value.toList()) } - is FeaturesetDescriptor -> { + is Interaction -> { stream.write(184) writeValue(stream, value.toList()) } - is FeaturesetFeature -> { + is FeaturesetDescriptor -> { stream.write(185) writeValue(stream, value.toList()) } - is FeaturesetQueryTarget -> { + is FeaturesetFeature -> { stream.write(186) writeValue(stream, value.toList()) } - is _RenderedQueryGeometry -> { + is FeaturesetQueryTarget -> { stream.write(187) writeValue(stream, value.toList()) } - is ProjectedMeters -> { + is MapContentGestureContext -> { stream.write(188) writeValue(stream, value.toList()) } - is MercatorCoordinate -> { + is _RenderedQueryGeometry -> { stream.write(189) writeValue(stream, value.toList()) } - is StyleObjectInfo -> { + is ProjectedMeters -> { stream.write(190) writeValue(stream, value.toList()) } - is StyleProjection -> { + is MercatorCoordinate -> { stream.write(191) writeValue(stream, value.toList()) } - is FlatLight -> { + is StyleObjectInfo -> { stream.write(192) writeValue(stream, value.toList()) } - is DirectionalLight -> { + is StyleProjection -> { stream.write(193) writeValue(stream, value.toList()) } - is AmbientLight -> { + is FlatLight -> { stream.write(194) writeValue(stream, value.toList()) } - is MbxImage -> { + is DirectionalLight -> { stream.write(195) writeValue(stream, value.toList()) } - is ImageStretches -> { + is AmbientLight -> { stream.write(196) writeValue(stream, value.toList()) } - is ImageContent -> { + is MbxImage -> { stream.write(197) writeValue(stream, value.toList()) } - is TransitionOptions -> { + is ImageStretches -> { stream.write(198) writeValue(stream, value.toList()) } - is CanonicalTileID -> { + is ImageContent -> { stream.write(199) writeValue(stream, value.toList()) } - is StylePropertyValue -> { + is TransitionOptions -> { stream.write(200) writeValue(stream, value.toList()) } + is CanonicalTileID -> { + stream.write(201) + writeValue(stream, value.toList()) + } + is StylePropertyValue -> { + stream.write(202) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -3364,6 +3354,31 @@ interface _CameraManager { } } } +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class InteractionsListener(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by InteractionsListener. */ + val codec: MessageCodec by lazy { + MapInterfacesPigeonCodec() + } + } + fun onInteraction(contextArg: MapContentGestureContext, featureArg: FeaturesetFeature, interactionIDArg: Long, callback: (Result) -> Unit) { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(contextArg, featureArg, interactionIDArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} /** * Map class provides map rendering functionality. * @@ -3462,23 +3477,14 @@ interface _MapInterface { * @return A `cancelable` object that could be used to cancel the pending query. */ fun queryRenderedFeatures(geometry: _RenderedQueryGeometry, options: RenderedQueryOptions, callback: (Result>) -> Unit) - /** - * Queries the map for rendered features using featureset descriptors. - * - * This method allows to query both featureset from imported styles and user layers in the root style. - * The results can be additionally filtered per-featureset. - * - * - Important: This is a low-level method. If you need to handle basic gestures on map content, please prefer ``MapboxMap/ queryRenderedFeaturesForFeatureset()``. - * - * @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. - * @param targets An array of targets to query with. - */ - fun queryRenderedFeaturesForTargets(geometry: _RenderedQueryGeometry, targets: List, callback: (Result>) -> Unit) /** * Queries the map for rendered features with one typed featureset. * * The results array will contain features of the type specified by this featureset. * + * - Important: If you need to handle basic gestures on map content, + * please prefer to use Interactions API, see `MapboxMap/addInteraction`. + * * @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. * @param featureset A typed featureset to query with. * @param filter An additional filter for features. @@ -3489,6 +3495,9 @@ interface _MapInterface { * * This is same as `MapboxMap/ queryRenderedFeaturesForFeatureset()`` called with geometry matching the current viewport. * + * - Important: If you need to handle basic gestures on map content, + * please prefer to use Interactions API, see `MapboxMap/addInteraction`. + * * @param featureset A typed featureset to query with. * @param filter An additional filter for features. */ @@ -3501,12 +3510,6 @@ interface _MapInterface { * @param completion The `query features completion` called when the query completes. */ fun querySourceFeatures(sourceId: String, options: SourceQueryOptions, callback: (Result>) -> Unit) - /** - * Queries the source features for a given featureset. - * - * @param target A featureset query target. - */ - fun querySourceFeaturesForTargets(target: FeaturesetQueryTarget, callback: (Result>) -> Unit) /** * Returns all the leaves (original points) of a cluster (given its cluster_id) from a GeoJsonSource, with pagination support: limit is the number of leaves * to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination). @@ -3569,10 +3572,8 @@ interface _MapInterface { * @param featureset The featureset to look the feature in. * @param featureId Identifier of the feature whose state should be updated. * @param state Map of entries to update with their respective new values - * - * @return A `Cancelable` object that could be used to cancel the pending operation. */ - fun setFeatureStateForFeaturesetDescriptor(featureset: TypedFeaturesetDescriptor, featureId: FeaturesetFeatureId, state: Map, callback: (Result) -> Unit) + fun setFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, state: Map, callback: (Result) -> Unit) /** * Update the state map of an individual feature. * @@ -3581,8 +3582,6 @@ interface _MapInterface { * * @param feature The feature to update. * @param state Map of entries to update with their respective new values - * - * @return A `Cancelable` object that could be used to cancel the pending operation. */ fun setFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, state: Map, callback: (Result) -> Unit) /** @@ -3595,7 +3594,7 @@ interface _MapInterface { * @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). * @param featureId The feature identifier of the feature whose state should be queried. * - * @return A `Cancelable` object that could be used to cancel the pending operation. + * @return A String representing the Feature's state map. */ fun getFeatureState(sourceId: String, sourceLayerId: String?, featureId: String, callback: (Result) -> Unit) /** @@ -3604,15 +3603,15 @@ interface _MapInterface { * @param featureset A featureset the feature belongs to. * @param featureId Identifier of the feature whose state should be queried. * - * @return A `Cancelable` object that could be used to cancel the pending query. + * @return The Feature's state map or an empty map if the feature could not be found. */ fun getFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, callback: (Result>) -> Unit) /** * Get the state map of a feature within a style source. * - * @param feature An interactive feature to query the state from. + * @param feature An interactive feature to query the state of. * - * @return A `Cancelable` object that could be used to cancel the pending query. + * @return The Feature's state map or an empty map if the feature could not be found. */ fun getFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, callback: (Result>) -> Unit) /** @@ -3622,7 +3621,7 @@ interface _MapInterface { * `stateKey`. * * Note that updates to feature state are asynchronous, so changes made by this method might not be - * immediately visible using `getStateFeature`. + * immediately visible using `getFeatureState`. * * @param sourceId The style source identifier. * @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). @@ -3637,8 +3636,6 @@ interface _MapInterface { * @param featureset A featureset the feature belongs to. * @param featureId Identifier of the feature whose state should be removed. * @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - * - * @return A `Cancelable` object that could be used to cancel the pending operation. */ fun removeFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, stateKey: String?, callback: (Result) -> Unit) /** @@ -3647,8 +3644,6 @@ interface _MapInterface { * * @param feature An interactive feature to update. * @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - * - * @return A `Cancelable` object that could be used to cancel the pending operation. */ fun removeFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, stateKey: String?, callback: (Result) -> Unit) /** @@ -3658,11 +3653,8 @@ interface _MapInterface { * immediately visible using ``MapboxMap/getFeatureState()``. * * @param featureset A featureset descriptor - * - * @return A `Cancelable` object that could be used to cancel the pending operation. */ fun resetFeatureStatesForFeatureset(featureset: FeaturesetDescriptor, callback: (Result) -> Unit) - fun addInteraction(interaction: Interaction, callback: (Result) -> Unit) /** Reduces memory use. Useful to call when the application gets paused or sent to background. */ fun reduceMemoryUse() /** @@ -4070,27 +4062,6 @@ interface _MapInterface { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.queryRenderedFeaturesForTargets$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val geometryArg = args[0] as _RenderedQueryGeometry - val targetsArg = args[1] as List - api.queryRenderedFeaturesForTargets(geometryArg, targetsArg) { result: Result> -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.queryRenderedFeaturesForFeatureset$separatedMessageChannelSuffix", codec) if (api != null) { @@ -4155,26 +4126,6 @@ interface _MapInterface { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.querySourceFeaturesForTargets$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val targetArg = args[0] as FeaturesetQueryTarget - api.querySourceFeaturesForTargets(targetArg) { result: Result> -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.getGeoJsonClusterLeaves$separatedMessageChannelSuffix", codec) if (api != null) { @@ -4267,7 +4218,7 @@ interface _MapInterface { if (api != null) { channel.setMessageHandler { message, reply -> val args = message as List - val featuresetArg = args[0] as TypedFeaturesetDescriptor + val featuresetArg = args[0] as FeaturesetDescriptor val featureIdArg = args[1] as FeaturesetFeatureId val stateArg = args[2] as Map api.setFeatureStateForFeaturesetDescriptor(featuresetArg, featureIdArg, stateArg) { result: Result -> @@ -4448,26 +4399,6 @@ interface _MapInterface { channel.setMessageHandler(null) } } - run { - val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.addInteraction$separatedMessageChannelSuffix", codec) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val interactionArg = args[0] as Interaction - api.addInteraction(interactionArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.reduceMemoryUse$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/example/integration_test/interactive_features_test.dart b/example/integration_test/interactive_features_test.dart index cd98eeec..34f5f802 100644 --- a/example/integration_test/interactive_features_test.dart +++ b/example/integration_test/interactive_features_test.dart @@ -83,15 +83,15 @@ void main() { geometry: Point(coordinates: Position(0.01, 0.01)).toJson(), properties: {}, state: {}); - Map state = { + var state = FeatureState(map: { "highlight": true, - }; + }); // test set and get featurestate await mapboxMap.setFeatureStateForFeaturesetFeature(feature, state); var returnedFeatureState = await mapboxMap.getFeatureStateForFeaturesetFeature(feature); - expect(returnedFeatureState, state); + expect(returnedFeatureState, state.map); // test remove featurestate await mapboxMap.removeFeatureStateForFeaturesetFeature( @@ -105,7 +105,7 @@ void main() { await mapboxMap.setFeatureStateForFeaturesetFeature(feature, state); var returnedFeatureState3 = await mapboxMap.getFeatureStateForFeaturesetFeature(feature); - expect(returnedFeatureState3, state); + expect(returnedFeatureState3, state.map); await mapboxMap.resetFeatureStatesForFeatureset( FeaturesetDescriptor(featuresetId: "poi", importId: "nested")); @@ -133,9 +133,9 @@ void main() { var featuresetDescriptor = FeaturesetDescriptor(featuresetId: "poi", importId: "nested"); var featuresetID = FeaturesetFeatureId(id: "11", namespace: "A"); - Map state = { + var state = FeatureState(map: { "highlight": true, - }; + }); await Future.delayed(Duration(seconds: 1)); @@ -145,7 +145,7 @@ void main() { var returnedFeatureState = await mapboxMap.getFeatureStateForFeaturesetDescriptor( featuresetDescriptor, featuresetID); - expect(returnedFeatureState, state); + expect(returnedFeatureState, state.map); // test remove featurestate await mapboxMap.removeFeatureStateForFeaturesetDescriptor( @@ -176,9 +176,9 @@ void main() { var featuresetID = FeaturesetFeatureId(id: "11", namespace: "A"); var featuresetDescriptor = FeaturesetDescriptor(featuresetId: "poi", importId: "nested"); - Map state = { + var state = FeatureState(map: { "hide": true, - }; + }); var filter = '["==",["get", "type"], "A"]'; Map expectedProperties = { "name": "nest1", @@ -196,7 +196,7 @@ void main() { expect(queryResult.length, 1); expect(poi.id?.id, featuresetID.id); expect(poi.id?.namespace, featuresetID.namespace); - expect(poi.state, state); + expect(poi.state, state.map); expect(point.coordinates.lat, closeTo(0.01, 0.05)); expect(point.coordinates.lng, closeTo(0.01, 0.05)); expect(poi.properties, expectedProperties); @@ -222,67 +222,4 @@ void main() { expect(returnedFeaturesets.length, 1); expect(returnedFeaturesets.first.importId, "nested"); }); - - testWidgets('test_query_featureset_target', (WidgetTester tester) async { - // load style and position camera - final mapFuture = app.main( - width: 200, - height: 200, - camera: - CameraOptions(center: Point(coordinates: Position(0, 0)), zoom: 10), - alignment: Alignment(100, 100)); - await tester.pumpAndSettle(); - final mapboxMap = await mapFuture; - var styleJson = await rootBundle.loadString('assets/featuresetsStyle.json'); - mapboxMap.style.setStyleJSON(styleJson); - - await app.events.onMapLoaded.future; - await Future.delayed(Duration(seconds: 1)); - - var featuresetFilter = '["==", ["get", "type"], "B"]'; - var layerFilter = '["==", ["get", "filter"], true]'; - var featuresetPOI = - FeaturesetDescriptor(featuresetId: "poi", importId: "nested"); - var featuresetLayer = FeaturesetDescriptor(layerId: "circle-2"); - var coord = await mapboxMap - .pixelForCoordinate(Point(coordinates: Position(0.01, 0.01))); - var targets = [ - FeaturesetQueryTarget( - featureset: featuresetPOI, filter: featuresetFilter, id: 1), - FeaturesetQueryTarget( - featureset: featuresetLayer, filter: layerFilter, id: 2) - ]; - Map expectedProperties = { - "name": "qux", - "filter": true, - "bar": 2 - }; - Map expectedProperties2 = { - "type": "B", - "class": "poi", - "name": "nest2" - }; - - var returnedQuery = await mapboxMap.queryRenderedFeaturesForTargets( - RenderedQueryGeometry.fromScreenCoordinate(coord), targets); - var firstFeature = - Feature.fromFeature(returnedQuery[0]!.queriedFeature.feature); - var secondFeature = - Feature.fromFeature(returnedQuery[1]!.queriedFeature.feature); - - expect(returnedQuery.length, 2); - expect(returnedQuery[0]?.queryTargets?.length, 1); - expect(returnedQuery[0]?.queryTargets?.last.id, 2); - expect(returnedQuery[0]?.queryTargets?.last.featureset.layerId, "circle-2"); - expect(returnedQuery[0]?.queryTargets?.last.filter, null); - expect(firstFeature.id.toString(), "2"); - expect(firstFeature.properties, expectedProperties); - expect(returnedQuery[1]?.queryTargets?.length, 1); - expect(returnedQuery[1]?.queryTargets?.last.id, 1); - expect(returnedQuery[1]?.queryTargets?.last.featureset.featuresetId, "poi"); - expect(returnedQuery[1]?.queryTargets?.last.featureset.importId, "nested"); - expect(returnedQuery[1]?.queryTargets?.last.filter, null); - expect(secondFeature.id.toString(), "12"); - expect(secondFeature.properties, expectedProperties2); - }); } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 751421f5..d1b1af82 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,5 +1,7 @@ PODS: - Flutter (1.0.0) + - integration_test (0.0.1): + - Flutter - mapbox_maps_flutter (2.5.0): - Flutter - MapboxMaps (~> 11.9.0) @@ -38,7 +40,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - mapbox_maps_flutter: 37d79738fac5ae570b4d67ffebf9dafcb7c4fff2 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + mapbox_maps_flutter: d51b6d48ba9d8231a77269f1743ec175099d7b15 MapboxCommon: 678bfc4b477a804244fd7323c79cc7f2402f844e MapboxCoreMaps: 5cd77c7251dea10903135e8427c788212bd26346 MapboxMaps: 2ce57c4ec89d8f05eacfebdd39b01216e0c06168 diff --git a/example/lib/interactive_features_example.dart b/example/lib/interactive_features_example.dart index 46f51b42..23a77bfe 100644 --- a/example/lib/interactive_features_example.dart +++ b/example/lib/interactive_features_example.dart @@ -8,7 +8,7 @@ class InteractiveFeaturesExample extends StatefulWidget implements Example { @override final String title = 'Interactive Features'; @override - final String? subtitle = 'Click to select buildings, long-click to unselect'; + final String? subtitle = 'Tap a Buildings to highlight it or a POI to hide it'; @override State createState() => InteractiveFeaturesState(); @@ -22,69 +22,41 @@ class InteractiveFeaturesState extends State { this.mapboxMap = mapboxMap; mapboxMap.style; - var featureset = - FeaturesetDescriptor(featuresetId: "buildings", importId: "basemap"); - - var typedFeaturesetDescriptor = TypedFeaturesetDescriptor( - featuresetDescriptor: featureset, featuresetType: "featureset"); - - var interactionType = InteractionType.CLICK; - - var interaction = Interaction( - typedFeaturesetDescriptor: typedFeaturesetDescriptor, - interactionType: interactionType); - mapboxMap.addInteraction(interaction); - } - - _onTap(context) async { - // Define the geometry to query, in this case the point where the user clicked. - var clicked = await mapboxMap?.pixelForCoordinate(context.point); - var renderedQueryGeometry = - RenderedQueryGeometry.fromScreenCoordinate(clicked!); - - // Define the featureset to query. In this case "buildings", which is defined in the - // Standard Experimental style. - var featureset = - FeaturesetDescriptor(featuresetId: "buildings", importId: "basemap"); - - // Query the featureset for the geometry - var queriedFeatures = await mapboxMap?.queryRenderedFeaturesForFeatureset( - geometry: renderedQueryGeometry, featureset: featureset); - var featuresetFeature = queriedFeatures?.first; - - var typedFeaturesetDescriptor = TypedFeaturesetDescriptor( - featuresetDescriptor: featureset, featuresetType: "featureset"); - - if (featuresetFeature != null) { - // Define the state to set for the feature, in this case highlighting - // Set that featurestate on that featuresetFeature - Map state = { - "highlight": true, - }; - mapboxMap?.setFeatureStateForFeaturesetDescriptor( - typedFeaturesetDescriptor, featuresetFeature.id!, state); - //mapboxMap?.setFeatureStateForFeaturesetFeature(featuresetFeature, state); - } - } - - _onLongTap(context) async { - // Define the geometry to query, in this case the point where the user clicked. - var clicked = await mapboxMap?.pixelForCoordinate(context.point); - var renderedQueryGeometry = - RenderedQueryGeometry.fromScreenCoordinate(clicked!); - - // Query the featureset for the geometry - var featureset = - FeaturesetDescriptor(featuresetId: "buildings", importId: "basemap"); - var queriedFeatures = await mapboxMap?.queryRenderedFeaturesForFeatureset( - geometry: renderedQueryGeometry, featureset: featureset); - var featuresetFeatureId = queriedFeatures?.first.id; - - // Remove that feature state - if (featuresetFeatureId != null) { - mapboxMap?.removeFeatureStateForFeaturesetDescriptor( - featureset: featureset, featureId: featuresetFeatureId); - } + /// Define interactions for 3D Buildings + + // Define a tap interaction targeting the Buildings featureset in the Standard style + var tapInteraction = TapInteraction(Featureset.standardBuildings()); + + // Define a state to highlight the building when it is interacted with + StandardBuildingState featureState = StandardBuildingState(highlight: true); + + // Add the tap interaction to the map, set the action to occur when a building is tapped (highlight it) + mapboxMap.addInteraction(tapInteraction, (_, FeaturesetFeature feature) { + mapboxMap.setFeatureStateForFeaturesetFeature(feature, featureState); + var buildingFeature = StandardBuildingsFeature( + feature.geometry, feature.properties, feature.state, + id: feature.id); + print("Building feature id: ${buildingFeature.id}"); + }); + + // On long tap, remove the highlight state + mapboxMap.addInteraction(LongTapInteraction(Featureset.standardBuildings()), + (_, FeaturesetFeature feature) { + mapboxMap.removeFeatureStateForFeaturesetFeature(feature: feature); + }); + + /// Define interactions for Points of Interest + + // Define a tap interaction targeting the POI featureset in the Standard style, including a click radius + // Do not stop propagation of the click event to lower layers + var tapInteractionPOI = TapInteraction(Featureset.standardPoi(), + radius: 10, stopPropagation: false); + + // Define a state to hide the POI when it is interacted with + mapboxMap.addInteraction(tapInteractionPOI, (_, FeaturesetFeature feature) { + mapboxMap.setFeatureStateForFeaturesetFeature( + feature, StandardPoiState(hide: true)); + }); } @override @@ -97,14 +69,9 @@ class InteractiveFeaturesState extends State { bearing: 49.92, zoom: 16.35, pitch: 40), - - /// DON'T USE Standard Experimental style in production, it will break over time. - /// Currently this feature is in preview. - styleUri: MapboxStyles.STANDARD_EXPERIMENTAL, + styleUri: MapboxStyles.STANDARD, textureView: true, onMapCreated: _onMapCreated, - onTapListener: _onTap, - onLongTapListener: _onLongTap, )); } } diff --git a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Extensions.swift b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Extensions.swift index 1ab74db9..cc05d4b5 100644 --- a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Extensions.swift +++ b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Extensions.swift @@ -221,13 +221,6 @@ extension FeaturesetFeatureId { } } -extension FeaturesetQueryTarget { - func toMapFeaturesetQueryTarget() -> MapboxMaps.FeaturesetQueryTarget { - let filterExpression = try? filter.flatMap { try $0.toExp() } - return MapboxMaps.FeaturesetQueryTarget(featureset: featureset.toMapFeaturesetDescriptor(), filter: filterExpression, id: id.map { UInt64($0) }) - } -} - extension FeaturesetDescriptor { func toMapFeaturesetDescriptor() -> MapboxMaps.FeaturesetDescriptor { if let featuresetId { @@ -250,27 +243,6 @@ extension FeaturesetFeature { } } -extension Interaction { - func toMapInteraction(completion: @escaping (FeaturesetFeature) -> Void) -> MapboxMaps.Interaction { - let filterExpression = try? filter.flatMap { try $0.toExp() } - - switch interactionType { - case .cLICK: - return TapInteraction.init(typedFeaturesetDescriptor.featuresetDescriptor.toMapFeaturesetDescriptor(), filter: filterExpression) { _, _ in - // TODO: figure out how to pass typed completion with pigeon - print("tapped") - return true - } - case .lONGCLICK: - return LongPressInteraction.init(typedFeaturesetDescriptor.featuresetDescriptor.toMapFeaturesetDescriptor(), filter: filterExpression) { featuresetFeature, _ in - - completion(featuresetFeature.toFLTFeaturesetFeature()) - return true - } - } - } -} - extension MercatorCoordinate { func toMercatorCoordinate() -> MapboxMaps.MercatorCoordinate { return MapboxMaps.MercatorCoordinate(x: x, y: y) @@ -491,17 +463,11 @@ extension MapboxMaps.QueriedSourceFeature { return QueriedSourceFeature(queriedFeature: queriedFeature.toFLTQueriedFeature()) } } -extension MapboxMaps.FeaturesetQueryTarget { - func toFLTFeaturesetQueryTarget() -> FeaturesetQueryTarget { - return FeaturesetQueryTarget(featureset: featureset.toFLTFeaturesetDescriptor(), filter: filter?.description, id: id.map { Int64($0) }) - } -} extension MapboxMaps.QueriedRenderedFeature { func toFLTQueriedRenderedFeature() -> QueriedRenderedFeature { return QueriedRenderedFeature( queriedFeature: queriedFeature.toFLTQueriedFeature(), - layers: layers, - queryTargets: queryTargets.map({$0.toFLTFeaturesetQueryTarget()})) + layers: layers) } } extension MapboxMaps.QueriedFeature { diff --git a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Generated/MapInterfaces.swift b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Generated/MapInterfaces.swift index 0f61e792..36fcbba2 100644 --- a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Generated/MapInterfaces.swift +++ b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/Generated/MapInterfaces.swift @@ -57,6 +57,10 @@ private func wrapError(_ error: Any) -> [Any?] { ] } +private func createConnectionError(withChannelName channelName: String) -> MapInterfacesError { + return MapInterfacesError(code: "channel-error", message: "Unable to establish connection on channel: '\(channelName)'.", details: "") +} + private func isNullish(_ value: Any?) -> Bool { return value is NSNull || value == nil } @@ -187,8 +191,8 @@ enum ViewAnnotationAnchor: Int { } enum InteractionType: Int { - case cLICK = 0 - case lONGCLICK = 1 + case tAP = 0 + case lONGTAP = 1 } /// Type information of the variant's content @@ -1244,78 +1248,72 @@ struct FeaturesetFeatureId { } /// Generated class from Pigeon that represents data sent in messages. -struct Interaction { - var typedFeaturesetDescriptor: TypedFeaturesetDescriptor - var interactionType: InteractionType - var filter: String? +struct FeatureState { + var map: [String: Any?] // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> Interaction? { - let typedFeaturesetDescriptor = pigeonVar_list[0] as! TypedFeaturesetDescriptor - let interactionType = pigeonVar_list[1] as! InteractionType - let filter: String? = nilOrValue(pigeonVar_list[2]) + static func fromList(_ pigeonVar_list: [Any?]) -> FeatureState? { + let map = pigeonVar_list[0] as! [String: Any?] - return Interaction( - typedFeaturesetDescriptor: typedFeaturesetDescriptor, - interactionType: interactionType, - filter: filter + return FeatureState( + map: map ) } func toList() -> [Any?] { return [ - typedFeaturesetDescriptor, - interactionType, - filter, + map ] } } +/// An interaction that can be added to the map. +/// +/// To create an interaction use ``TapInteraction`` and ``LongClickInteraction`` implementations. +/// +/// See also: ``MapboxMap/addInteraction``. +/// /// Generated class from Pigeon that represents data sent in messages. -struct TypedFeaturesetDescriptor { +struct Interaction { var featuresetDescriptor: FeaturesetDescriptor - var featuresetType: String + var interactionType: InteractionType + var stopPropagation: Bool + var filter: String? + var radius: Double? // swift-format-ignore: AlwaysUseLowerCamelCase - static func fromList(_ pigeonVar_list: [Any?]) -> TypedFeaturesetDescriptor? { + static func fromList(_ pigeonVar_list: [Any?]) -> Interaction? { let featuresetDescriptor = pigeonVar_list[0] as! FeaturesetDescriptor - let featuresetType = pigeonVar_list[1] as! String + let interactionType = pigeonVar_list[1] as! InteractionType + let stopPropagation = pigeonVar_list[2] as! Bool + let filter: String? = nilOrValue(pigeonVar_list[3]) + let radius: Double? = nilOrValue(pigeonVar_list[4]) - return TypedFeaturesetDescriptor( + return Interaction( featuresetDescriptor: featuresetDescriptor, - featuresetType: featuresetType + interactionType: interactionType, + stopPropagation: stopPropagation, + filter: filter, + radius: radius ) } func toList() -> [Any?] { return [ featuresetDescriptor, - featuresetType, + interactionType, + stopPropagation, + filter, + radius, ] } } /// A featureset descriptor. /// -/// The descriptor instance acts as a universal target for interactions or querying rendered features (see -/// ``MapboxMap/queryRenderedFeatures(with:featureset:filter:completion:)``). -/// /// Generated class from Pigeon that represents data sent in messages. struct FeaturesetDescriptor { - /// An optional unique identifier for the featureset within the style. - /// This id is used to reference a specific featureset. - /// - /// * Note: If `featuresetId` is provided and valid, it takes precedence over `layerId`, - /// * meaning `layerId` will not be considered even if it has a valid value. var featuresetId: String? - /// An optional import id that is required if the featureset is defined within an imported style. - /// If the featureset belongs to the current style, this field should be set to a null string. - /// - /// Note: `importId` is only applicable when used in conjunction with `featuresetId` - /// and has no effect when used with `layerId`. + /// var importId: String? - /// An optional unique identifier for the layer within the current style. - /// - /// Note: If `featuresetId` is valid, `layerId` will be ignored even if it has a valid value. - /// Additionally, `importId` does not apply when using `layerId`. var layerId: String? // swift-format-ignore: AlwaysUseLowerCamelCase @@ -1339,27 +1337,12 @@ struct FeaturesetDescriptor { } } -/// A basic feature of a featureset. -/// -/// The featureset feature is different to the `Turf.Feature`. The latter represents any GeoJSON feature, while the former is a high level representation of features. -/// /// Generated class from Pigeon that represents data sent in messages. struct FeaturesetFeature { - /// An identifier of the feature. - /// - /// The identifier can be `nil` if the underlying source doesn't have identifiers for features. - /// In this case it's impossible to set a feature state for an individual feature. var id: FeaturesetFeatureId? - /// A featureset descriptor denoting the featureset this feature belongs to. var featureset: FeaturesetDescriptor - /// A feature geometry. var geometry: [String?: Any?] - /// Feature JSON properties. var properties: [String: Any?] - /// A feature state. - /// - /// This is a **snapshot** of the state that the feature had when it was interacted with. - /// To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. var state: [String: Any?] // swift-format-ignore: AlwaysUseLowerCamelCase @@ -1981,196 +1964,204 @@ private class MapInterfacesPigeonCodecReader: FlutterStandardReader { case 138: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return Type(rawValue: enumResultAsInt) + return GestureState(rawValue: enumResultAsInt) } return nil case 139: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return FillExtrusionBaseAlignment(rawValue: enumResultAsInt) + return Type(rawValue: enumResultAsInt) } return nil case 140: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return FillExtrusionHeightAlignment(rawValue: enumResultAsInt) + return FillExtrusionBaseAlignment(rawValue: enumResultAsInt) } return nil case 141: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return BackgroundPitchAlignment(rawValue: enumResultAsInt) + return FillExtrusionHeightAlignment(rawValue: enumResultAsInt) } return nil case 142: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return StylePackErrorType(rawValue: enumResultAsInt) + return BackgroundPitchAlignment(rawValue: enumResultAsInt) } return nil case 143: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return ResponseErrorReason(rawValue: enumResultAsInt) + return StylePackErrorType(rawValue: enumResultAsInt) } return nil case 144: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return OfflineRegionDownloadState(rawValue: enumResultAsInt) + return ResponseErrorReason(rawValue: enumResultAsInt) } return nil case 145: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return TileStoreUsageMode(rawValue: enumResultAsInt) + return OfflineRegionDownloadState(rawValue: enumResultAsInt) } return nil case 146: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return StylePropertyValueKind(rawValue: enumResultAsInt) + return TileStoreUsageMode(rawValue: enumResultAsInt) } return nil case 147: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return StyleProjectionName(rawValue: enumResultAsInt) + return StylePropertyValueKind(rawValue: enumResultAsInt) } return nil case 148: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return Anchor(rawValue: enumResultAsInt) + return StyleProjectionName(rawValue: enumResultAsInt) } return nil case 149: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return HttpMethod(rawValue: enumResultAsInt) + return Anchor(rawValue: enumResultAsInt) } return nil case 150: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return HttpRequestErrorType(rawValue: enumResultAsInt) + return HttpMethod(rawValue: enumResultAsInt) } return nil case 151: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return DownloadErrorCode(rawValue: enumResultAsInt) + return HttpRequestErrorType(rawValue: enumResultAsInt) } return nil case 152: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return DownloadState(rawValue: enumResultAsInt) + return DownloadErrorCode(rawValue: enumResultAsInt) } return nil case 153: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return TileRegionErrorType(rawValue: enumResultAsInt) + return DownloadState(rawValue: enumResultAsInt) } return nil case 154: let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) if let enumResultAsInt = enumResultAsInt { - return _MapEvent(rawValue: enumResultAsInt) + return TileRegionErrorType(rawValue: enumResultAsInt) } return nil case 155: - return Point.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return _MapEvent(rawValue: enumResultAsInt) + } + return nil case 156: - return Feature.fromList(self.readValue() as! [Any?]) + return Point.fromList(self.readValue() as! [Any?]) case 157: - return GlyphsRasterizationOptions.fromList(self.readValue() as! [Any?]) + return Feature.fromList(self.readValue() as! [Any?]) case 158: - return TileCoverOptions.fromList(self.readValue() as! [Any?]) + return GlyphsRasterizationOptions.fromList(self.readValue() as! [Any?]) case 159: - return MbxEdgeInsets.fromList(self.readValue() as! [Any?]) + return TileCoverOptions.fromList(self.readValue() as! [Any?]) case 160: - return CameraOptions.fromList(self.readValue() as! [Any?]) + return MbxEdgeInsets.fromList(self.readValue() as! [Any?]) case 161: - return CameraState.fromList(self.readValue() as! [Any?]) + return CameraOptions.fromList(self.readValue() as! [Any?]) case 162: - return CameraBoundsOptions.fromList(self.readValue() as! [Any?]) + return CameraState.fromList(self.readValue() as! [Any?]) case 163: - return CameraBounds.fromList(self.readValue() as! [Any?]) + return CameraBoundsOptions.fromList(self.readValue() as! [Any?]) case 164: - return MapAnimationOptions.fromList(self.readValue() as! [Any?]) + return CameraBounds.fromList(self.readValue() as! [Any?]) case 165: - return CoordinateBounds.fromList(self.readValue() as! [Any?]) + return MapAnimationOptions.fromList(self.readValue() as! [Any?]) case 166: - return MapDebugOptions.fromList(self.readValue() as! [Any?]) + return CoordinateBounds.fromList(self.readValue() as! [Any?]) case 167: - return TileCacheBudgetInMegabytes.fromList(self.readValue() as! [Any?]) + return MapDebugOptions.fromList(self.readValue() as! [Any?]) case 168: - return TileCacheBudgetInTiles.fromList(self.readValue() as! [Any?]) + return TileCacheBudgetInMegabytes.fromList(self.readValue() as! [Any?]) case 169: - return MapOptions.fromList(self.readValue() as! [Any?]) + return TileCacheBudgetInTiles.fromList(self.readValue() as! [Any?]) case 170: - return ScreenCoordinate.fromList(self.readValue() as! [Any?]) + return MapOptions.fromList(self.readValue() as! [Any?]) case 171: - return ScreenBox.fromList(self.readValue() as! [Any?]) + return ScreenCoordinate.fromList(self.readValue() as! [Any?]) case 172: - return CoordinateBoundsZoom.fromList(self.readValue() as! [Any?]) + return ScreenBox.fromList(self.readValue() as! [Any?]) case 173: - return Size.fromList(self.readValue() as! [Any?]) + return CoordinateBoundsZoom.fromList(self.readValue() as! [Any?]) case 174: - return RenderedQueryOptions.fromList(self.readValue() as! [Any?]) + return Size.fromList(self.readValue() as! [Any?]) case 175: - return SourceQueryOptions.fromList(self.readValue() as! [Any?]) + return RenderedQueryOptions.fromList(self.readValue() as! [Any?]) case 176: - return FeatureExtensionValue.fromList(self.readValue() as! [Any?]) + return SourceQueryOptions.fromList(self.readValue() as! [Any?]) case 177: - return LayerPosition.fromList(self.readValue() as! [Any?]) + return FeatureExtensionValue.fromList(self.readValue() as! [Any?]) case 178: - return QueriedRenderedFeature.fromList(self.readValue() as! [Any?]) + return LayerPosition.fromList(self.readValue() as! [Any?]) case 179: - return QueriedSourceFeature.fromList(self.readValue() as! [Any?]) + return QueriedRenderedFeature.fromList(self.readValue() as! [Any?]) case 180: - return QueriedFeature.fromList(self.readValue() as! [Any?]) + return QueriedSourceFeature.fromList(self.readValue() as! [Any?]) case 181: - return FeaturesetFeatureId.fromList(self.readValue() as! [Any?]) + return QueriedFeature.fromList(self.readValue() as! [Any?]) case 182: - return Interaction.fromList(self.readValue() as! [Any?]) + return FeaturesetFeatureId.fromList(self.readValue() as! [Any?]) case 183: - return TypedFeaturesetDescriptor.fromList(self.readValue() as! [Any?]) + return FeatureState.fromList(self.readValue() as! [Any?]) case 184: - return FeaturesetDescriptor.fromList(self.readValue() as! [Any?]) + return Interaction.fromList(self.readValue() as! [Any?]) case 185: - return FeaturesetFeature.fromList(self.readValue() as! [Any?]) + return FeaturesetDescriptor.fromList(self.readValue() as! [Any?]) case 186: - return FeaturesetQueryTarget.fromList(self.readValue() as! [Any?]) + return FeaturesetFeature.fromList(self.readValue() as! [Any?]) case 187: - return _RenderedQueryGeometry.fromList(self.readValue() as! [Any?]) + return FeaturesetQueryTarget.fromList(self.readValue() as! [Any?]) case 188: - return ProjectedMeters.fromList(self.readValue() as! [Any?]) + return MapContentGestureContext.fromList(self.readValue() as! [Any?]) case 189: - return MercatorCoordinate.fromList(self.readValue() as! [Any?]) + return _RenderedQueryGeometry.fromList(self.readValue() as! [Any?]) case 190: - return StyleObjectInfo.fromList(self.readValue() as! [Any?]) + return ProjectedMeters.fromList(self.readValue() as! [Any?]) case 191: - return StyleProjection.fromList(self.readValue() as! [Any?]) + return MercatorCoordinate.fromList(self.readValue() as! [Any?]) case 192: - return FlatLight.fromList(self.readValue() as! [Any?]) + return StyleObjectInfo.fromList(self.readValue() as! [Any?]) case 193: - return DirectionalLight.fromList(self.readValue() as! [Any?]) + return StyleProjection.fromList(self.readValue() as! [Any?]) case 194: - return AmbientLight.fromList(self.readValue() as! [Any?]) + return FlatLight.fromList(self.readValue() as! [Any?]) case 195: - return MbxImage.fromList(self.readValue() as! [Any?]) + return DirectionalLight.fromList(self.readValue() as! [Any?]) case 196: - return ImageStretches.fromList(self.readValue() as! [Any?]) + return AmbientLight.fromList(self.readValue() as! [Any?]) case 197: - return ImageContent.fromList(self.readValue() as! [Any?]) + return MbxImage.fromList(self.readValue() as! [Any?]) case 198: - return TransitionOptions.fromList(self.readValue() as! [Any?]) + return ImageStretches.fromList(self.readValue() as! [Any?]) case 199: - return CanonicalTileID.fromList(self.readValue() as! [Any?]) + return ImageContent.fromList(self.readValue() as! [Any?]) case 200: + return TransitionOptions.fromList(self.readValue() as! [Any?]) + case 201: + return CanonicalTileID.fromList(self.readValue() as! [Any?]) + case 202: return StylePropertyValue.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -2207,195 +2198,201 @@ private class MapInterfacesPigeonCodecWriter: FlutterStandardWriter { } else if let value = value as? InteractionType { super.writeByte(137) super.writeValue(value.rawValue) - } else if let value = value as? Type { + } else if let value = value as? GestureState { super.writeByte(138) super.writeValue(value.rawValue) - } else if let value = value as? FillExtrusionBaseAlignment { + } else if let value = value as? Type { super.writeByte(139) super.writeValue(value.rawValue) - } else if let value = value as? FillExtrusionHeightAlignment { + } else if let value = value as? FillExtrusionBaseAlignment { super.writeByte(140) super.writeValue(value.rawValue) - } else if let value = value as? BackgroundPitchAlignment { + } else if let value = value as? FillExtrusionHeightAlignment { super.writeByte(141) super.writeValue(value.rawValue) - } else if let value = value as? StylePackErrorType { + } else if let value = value as? BackgroundPitchAlignment { super.writeByte(142) super.writeValue(value.rawValue) - } else if let value = value as? ResponseErrorReason { + } else if let value = value as? StylePackErrorType { super.writeByte(143) super.writeValue(value.rawValue) - } else if let value = value as? OfflineRegionDownloadState { + } else if let value = value as? ResponseErrorReason { super.writeByte(144) super.writeValue(value.rawValue) - } else if let value = value as? TileStoreUsageMode { + } else if let value = value as? OfflineRegionDownloadState { super.writeByte(145) super.writeValue(value.rawValue) - } else if let value = value as? StylePropertyValueKind { + } else if let value = value as? TileStoreUsageMode { super.writeByte(146) super.writeValue(value.rawValue) - } else if let value = value as? StyleProjectionName { + } else if let value = value as? StylePropertyValueKind { super.writeByte(147) super.writeValue(value.rawValue) - } else if let value = value as? Anchor { + } else if let value = value as? StyleProjectionName { super.writeByte(148) super.writeValue(value.rawValue) - } else if let value = value as? HttpMethod { + } else if let value = value as? Anchor { super.writeByte(149) super.writeValue(value.rawValue) - } else if let value = value as? HttpRequestErrorType { + } else if let value = value as? HttpMethod { super.writeByte(150) super.writeValue(value.rawValue) - } else if let value = value as? DownloadErrorCode { + } else if let value = value as? HttpRequestErrorType { super.writeByte(151) super.writeValue(value.rawValue) - } else if let value = value as? DownloadState { + } else if let value = value as? DownloadErrorCode { super.writeByte(152) super.writeValue(value.rawValue) - } else if let value = value as? TileRegionErrorType { + } else if let value = value as? DownloadState { super.writeByte(153) super.writeValue(value.rawValue) - } else if let value = value as? _MapEvent { + } else if let value = value as? TileRegionErrorType { super.writeByte(154) super.writeValue(value.rawValue) - } else if let value = value as? Point { + } else if let value = value as? _MapEvent { super.writeByte(155) - super.writeValue(value.toList()) - } else if let value = value as? Feature { + super.writeValue(value.rawValue) + } else if let value = value as? Point { super.writeByte(156) super.writeValue(value.toList()) - } else if let value = value as? GlyphsRasterizationOptions { + } else if let value = value as? Feature { super.writeByte(157) super.writeValue(value.toList()) - } else if let value = value as? TileCoverOptions { + } else if let value = value as? GlyphsRasterizationOptions { super.writeByte(158) super.writeValue(value.toList()) - } else if let value = value as? MbxEdgeInsets { + } else if let value = value as? TileCoverOptions { super.writeByte(159) super.writeValue(value.toList()) - } else if let value = value as? CameraOptions { + } else if let value = value as? MbxEdgeInsets { super.writeByte(160) super.writeValue(value.toList()) - } else if let value = value as? CameraState { + } else if let value = value as? CameraOptions { super.writeByte(161) super.writeValue(value.toList()) - } else if let value = value as? CameraBoundsOptions { + } else if let value = value as? CameraState { super.writeByte(162) super.writeValue(value.toList()) - } else if let value = value as? CameraBounds { + } else if let value = value as? CameraBoundsOptions { super.writeByte(163) super.writeValue(value.toList()) - } else if let value = value as? MapAnimationOptions { + } else if let value = value as? CameraBounds { super.writeByte(164) super.writeValue(value.toList()) - } else if let value = value as? CoordinateBounds { + } else if let value = value as? MapAnimationOptions { super.writeByte(165) super.writeValue(value.toList()) - } else if let value = value as? MapDebugOptions { + } else if let value = value as? CoordinateBounds { super.writeByte(166) super.writeValue(value.toList()) - } else if let value = value as? TileCacheBudgetInMegabytes { + } else if let value = value as? MapDebugOptions { super.writeByte(167) super.writeValue(value.toList()) - } else if let value = value as? TileCacheBudgetInTiles { + } else if let value = value as? TileCacheBudgetInMegabytes { super.writeByte(168) super.writeValue(value.toList()) - } else if let value = value as? MapOptions { + } else if let value = value as? TileCacheBudgetInTiles { super.writeByte(169) super.writeValue(value.toList()) - } else if let value = value as? ScreenCoordinate { + } else if let value = value as? MapOptions { super.writeByte(170) super.writeValue(value.toList()) - } else if let value = value as? ScreenBox { + } else if let value = value as? ScreenCoordinate { super.writeByte(171) super.writeValue(value.toList()) - } else if let value = value as? CoordinateBoundsZoom { + } else if let value = value as? ScreenBox { super.writeByte(172) super.writeValue(value.toList()) - } else if let value = value as? Size { + } else if let value = value as? CoordinateBoundsZoom { super.writeByte(173) super.writeValue(value.toList()) - } else if let value = value as? RenderedQueryOptions { + } else if let value = value as? Size { super.writeByte(174) super.writeValue(value.toList()) - } else if let value = value as? SourceQueryOptions { + } else if let value = value as? RenderedQueryOptions { super.writeByte(175) super.writeValue(value.toList()) - } else if let value = value as? FeatureExtensionValue { + } else if let value = value as? SourceQueryOptions { super.writeByte(176) super.writeValue(value.toList()) - } else if let value = value as? LayerPosition { + } else if let value = value as? FeatureExtensionValue { super.writeByte(177) super.writeValue(value.toList()) - } else if let value = value as? QueriedRenderedFeature { + } else if let value = value as? LayerPosition { super.writeByte(178) super.writeValue(value.toList()) - } else if let value = value as? QueriedSourceFeature { + } else if let value = value as? QueriedRenderedFeature { super.writeByte(179) super.writeValue(value.toList()) - } else if let value = value as? QueriedFeature { + } else if let value = value as? QueriedSourceFeature { super.writeByte(180) super.writeValue(value.toList()) - } else if let value = value as? FeaturesetFeatureId { + } else if let value = value as? QueriedFeature { super.writeByte(181) super.writeValue(value.toList()) - } else if let value = value as? Interaction { + } else if let value = value as? FeaturesetFeatureId { super.writeByte(182) super.writeValue(value.toList()) - } else if let value = value as? TypedFeaturesetDescriptor { + } else if let value = value as? FeatureState { super.writeByte(183) super.writeValue(value.toList()) - } else if let value = value as? FeaturesetDescriptor { + } else if let value = value as? Interaction { super.writeByte(184) super.writeValue(value.toList()) - } else if let value = value as? FeaturesetFeature { + } else if let value = value as? FeaturesetDescriptor { super.writeByte(185) super.writeValue(value.toList()) - } else if let value = value as? FeaturesetQueryTarget { + } else if let value = value as? FeaturesetFeature { super.writeByte(186) super.writeValue(value.toList()) - } else if let value = value as? _RenderedQueryGeometry { + } else if let value = value as? FeaturesetQueryTarget { super.writeByte(187) super.writeValue(value.toList()) - } else if let value = value as? ProjectedMeters { + } else if let value = value as? MapContentGestureContext { super.writeByte(188) super.writeValue(value.toList()) - } else if let value = value as? MercatorCoordinate { + } else if let value = value as? _RenderedQueryGeometry { super.writeByte(189) super.writeValue(value.toList()) - } else if let value = value as? StyleObjectInfo { + } else if let value = value as? ProjectedMeters { super.writeByte(190) super.writeValue(value.toList()) - } else if let value = value as? StyleProjection { + } else if let value = value as? MercatorCoordinate { super.writeByte(191) super.writeValue(value.toList()) - } else if let value = value as? FlatLight { + } else if let value = value as? StyleObjectInfo { super.writeByte(192) super.writeValue(value.toList()) - } else if let value = value as? DirectionalLight { + } else if let value = value as? StyleProjection { super.writeByte(193) super.writeValue(value.toList()) - } else if let value = value as? AmbientLight { + } else if let value = value as? FlatLight { super.writeByte(194) super.writeValue(value.toList()) - } else if let value = value as? MbxImage { + } else if let value = value as? DirectionalLight { super.writeByte(195) super.writeValue(value.toList()) - } else if let value = value as? ImageStretches { + } else if let value = value as? AmbientLight { super.writeByte(196) super.writeValue(value.toList()) - } else if let value = value as? ImageContent { + } else if let value = value as? MbxImage { super.writeByte(197) super.writeValue(value.toList()) - } else if let value = value as? TransitionOptions { + } else if let value = value as? ImageStretches { super.writeByte(198) super.writeValue(value.toList()) - } else if let value = value as? CanonicalTileID { + } else if let value = value as? ImageContent { super.writeByte(199) super.writeValue(value.toList()) - } else if let value = value as? StylePropertyValue { + } else if let value = value as? TransitionOptions { super.writeByte(200) super.writeValue(value.toList()) + } else if let value = value as? CanonicalTileID { + super.writeByte(201) + super.writeValue(value.toList()) + } else if let value = value as? StylePropertyValue { + super.writeByte(202) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -3121,6 +3118,39 @@ class _CameraManagerSetup { } } } +/// Generated protocol from Pigeon that represents Flutter messages that can be called from Swift. +protocol InteractionsListenerProtocol { + func onInteraction(context contextArg: MapContentGestureContext, feature featureArg: FeaturesetFeature, interactionID interactionIDArg: Int64, completion: @escaping (Result) -> Void) +} +class InteractionsListener: InteractionsListenerProtocol { + private let binaryMessenger: FlutterBinaryMessenger + private let messageChannelSuffix: String + init(binaryMessenger: FlutterBinaryMessenger, messageChannelSuffix: String = "") { + self.binaryMessenger = binaryMessenger + self.messageChannelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" + } + var codec: MapInterfacesPigeonCodec { + return MapInterfacesPigeonCodec.shared + } + func onInteraction(context contextArg: MapContentGestureContext, feature featureArg: FeaturesetFeature, interactionID interactionIDArg: Int64, completion: @escaping (Result) -> Void) { + let channelName: String = "dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel(name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([contextArg, featureArg, interactionIDArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + completion(.failure(createConnectionError(withChannelName: channelName))) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + completion(.failure(MapInterfacesError(code: code, message: message, details: details))) + } else { + completion(.success(Void())) + } + } + } +} /// Map class provides map rendering functionality. /// /// @@ -3195,19 +3225,12 @@ protocol _MapInterface { /// @param completion The `query features completion` called when the query completes. /// @return A `cancelable` object that could be used to cancel the pending query. func queryRenderedFeatures(geometry: _RenderedQueryGeometry, options: RenderedQueryOptions, completion: @escaping (Result<[QueriedRenderedFeature?], Error>) -> Void) - /// Queries the map for rendered features using featureset descriptors. - /// - /// This method allows to query both featureset from imported styles and user layers in the root style. - /// The results can be additionally filtered per-featureset. - /// - /// - Important: This is a low-level method. If you need to handle basic gestures on map content, please prefer ``MapboxMap/ queryRenderedFeaturesForFeatureset()``. - /// - /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. - /// @param targets An array of targets to query with. - func queryRenderedFeaturesForTargets(geometry: _RenderedQueryGeometry, targets: [FeaturesetQueryTarget], completion: @escaping (Result<[QueriedRenderedFeature], Error>) -> Void) /// Queries the map for rendered features with one typed featureset. /// /// The results array will contain features of the type specified by this featureset. + /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. /// /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. /// @param featureset A typed featureset to query with. @@ -3216,6 +3239,9 @@ protocol _MapInterface { /// Queries all rendered features in current viewport, using one typed featureset. /// /// This is same as `MapboxMap/ queryRenderedFeaturesForFeatureset()`` called with geometry matching the current viewport. + /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. /// /// @param featureset A typed featureset to query with. /// @param filter An additional filter for features. @@ -3226,10 +3252,6 @@ protocol _MapInterface { /// @param options The `source query options` for querying source features. /// @param completion The `query features completion` called when the query completes. func querySourceFeatures(sourceId: String, options: SourceQueryOptions, completion: @escaping (Result<[QueriedSourceFeature?], Error>) -> Void) - /// Queries the source features for a given featureset. - /// - /// @param target A featureset query target. - func querySourceFeaturesForTargets(target: FeaturesetQueryTarget, completion: @escaping (Result<[QueriedSourceFeature], Error>) -> Void) /// Returns all the leaves (original points) of a cluster (given its cluster_id) from a GeoJsonSource, with pagination support: limit is the number of leaves /// to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination). /// @@ -3283,9 +3305,7 @@ protocol _MapInterface { /// @param featureset The featureset to look the feature in. /// @param featureId Identifier of the feature whose state should be updated. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. - func setFeatureStateForFeaturesetDescriptor(featureset: TypedFeaturesetDescriptor, featureId: FeaturesetFeatureId, state: [String: Any?], completion: @escaping (Result) -> Void) + func setFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, state: [String: Any?], completion: @escaping (Result) -> Void) /// Update the state map of an individual feature. /// /// The feature should have a non-nil ``FeaturesetFeatureType/id``. Otherwise, @@ -3293,8 +3313,6 @@ protocol _MapInterface { /// /// @param feature The feature to update. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. func setFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, state: [String: Any?], completion: @escaping (Result) -> Void) /// Gets the state map of a feature within a style source. /// @@ -3305,20 +3323,20 @@ protocol _MapInterface { /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). /// @param featureId The feature identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. + /// @return A String representing the Feature's state map. func getFeatureState(sourceId: String, sourceLayerId: String?, featureId: String, completion: @escaping (Result) -> Void) /// Get the state map of a feature within a style source. /// /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. func getFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, completion: @escaping (Result<[String: Any?], Error>) -> Void) /// Get the state map of a feature within a style source. /// - /// @param feature An interactive feature to query the state from. + /// @param feature An interactive feature to query the state of. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. func getFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, completion: @escaping (Result<[String: Any?], Error>) -> Void) /// Removes entries from a feature state object. /// @@ -3326,7 +3344,7 @@ protocol _MapInterface { /// `stateKey`. /// /// Note that updates to feature state are asynchronous, so changes made by this method might not be - /// immediately visible using `getStateFeature`. + /// immediately visible using `getFeatureState`. /// /// @param sourceId The style source identifier. /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). @@ -3339,16 +3357,12 @@ protocol _MapInterface { /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be removed. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. func removeFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, stateKey: String?, completion: @escaping (Result) -> Void) /// Removes entries from a specified Feature. /// Remove a specified property or all property from a feature's state object, depending on the value of `stateKey`. /// /// @param feature An interactive feature to update. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. func removeFeatureStateForFeaturesetFeature(feature: FeaturesetFeature, stateKey: String?, completion: @escaping (Result) -> Void) /// Reset all the feature states within a featureset. /// @@ -3356,10 +3370,7 @@ protocol _MapInterface { /// immediately visible using ``MapboxMap/getFeatureState()``. /// /// @param featureset A featureset descriptor - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. func resetFeatureStatesForFeatureset(featureset: FeaturesetDescriptor, completion: @escaping (Result) -> Void) - func addInteraction(interaction: Interaction, completion: @escaping (Result) -> Void) /// Reduces memory use. Useful to call when the application gets paused or sent to background. func reduceMemoryUse() throws /// Gets elevation for the given coordinate. @@ -3752,36 +3763,12 @@ class _MapInterfaceSetup { } else { queryRenderedFeaturesChannel.setMessageHandler(nil) } - /// Queries the map for rendered features using featureset descriptors. - /// - /// This method allows to query both featureset from imported styles and user layers in the root style. - /// The results can be additionally filtered per-featureset. - /// - /// - Important: This is a low-level method. If you need to handle basic gestures on map content, please prefer ``MapboxMap/ queryRenderedFeaturesForFeatureset()``. - /// - /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. - /// @param targets An array of targets to query with. - let queryRenderedFeaturesForTargetsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.queryRenderedFeaturesForTargets\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - queryRenderedFeaturesForTargetsChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let geometryArg = args[0] as! _RenderedQueryGeometry - let targetsArg = args[1] as! [FeaturesetQueryTarget] - api.queryRenderedFeaturesForTargets(geometry: geometryArg, targets: targetsArg) { result in - switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) - } - } - } - } else { - queryRenderedFeaturesForTargetsChannel.setMessageHandler(nil) - } /// Queries the map for rendered features with one typed featureset. /// /// The results array will contain features of the type specified by this featureset. + /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. /// /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. /// @param featureset A typed featureset to query with. @@ -3808,6 +3795,9 @@ class _MapInterfaceSetup { /// Queries all rendered features in current viewport, using one typed featureset. /// /// This is same as `MapboxMap/ queryRenderedFeaturesForFeatureset()`` called with geometry matching the current viewport. + /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. /// /// @param featureset A typed featureset to query with. /// @param filter An additional filter for features. @@ -3852,26 +3842,6 @@ class _MapInterfaceSetup { } else { querySourceFeaturesChannel.setMessageHandler(nil) } - /// Queries the source features for a given featureset. - /// - /// @param target A featureset query target. - let querySourceFeaturesForTargetsChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.querySourceFeaturesForTargets\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - querySourceFeaturesForTargetsChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let targetArg = args[0] as! FeaturesetQueryTarget - api.querySourceFeaturesForTargets(target: targetArg) { result in - switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) - } - } - } - } else { - querySourceFeaturesForTargetsChannel.setMessageHandler(nil) - } /// Returns all the leaves (original points) of a cluster (given its cluster_id) from a GeoJsonSource, with pagination support: limit is the number of leaves /// to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination). /// @@ -3997,13 +3967,11 @@ class _MapInterfaceSetup { /// @param featureset The featureset to look the feature in. /// @param featureId Identifier of the feature whose state should be updated. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. let setFeatureStateForFeaturesetDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.setFeatureStateForFeaturesetDescriptor\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { setFeatureStateForFeaturesetDescriptorChannel.setMessageHandler { message, reply in let args = message as! [Any?] - let featuresetArg = args[0] as! TypedFeaturesetDescriptor + let featuresetArg = args[0] as! FeaturesetDescriptor let featureIdArg = args[1] as! FeaturesetFeatureId let stateArg = args[2] as! [String: Any?] api.setFeatureStateForFeaturesetDescriptor(featureset: featuresetArg, featureId: featureIdArg, state: stateArg) { result in @@ -4025,8 +3993,6 @@ class _MapInterfaceSetup { /// /// @param feature The feature to update. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. let setFeatureStateForFeaturesetFeatureChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.setFeatureStateForFeaturesetFeature\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { setFeatureStateForFeaturesetFeatureChannel.setMessageHandler { message, reply in @@ -4054,7 +4020,7 @@ class _MapInterfaceSetup { /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). /// @param featureId The feature identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. + /// @return A String representing the Feature's state map. let getFeatureStateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.getFeatureState\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getFeatureStateChannel.setMessageHandler { message, reply in @@ -4079,7 +4045,7 @@ class _MapInterfaceSetup { /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. let getFeatureStateForFeaturesetDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.getFeatureStateForFeaturesetDescriptor\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getFeatureStateForFeaturesetDescriptorChannel.setMessageHandler { message, reply in @@ -4100,9 +4066,9 @@ class _MapInterfaceSetup { } /// Get the state map of a feature within a style source. /// - /// @param feature An interactive feature to query the state from. + /// @param feature An interactive feature to query the state of. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. let getFeatureStateForFeaturesetFeatureChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.getFeatureStateForFeaturesetFeature\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { getFeatureStateForFeaturesetFeatureChannel.setMessageHandler { message, reply in @@ -4126,7 +4092,7 @@ class _MapInterfaceSetup { /// `stateKey`. /// /// Note that updates to feature state are asynchronous, so changes made by this method might not be - /// immediately visible using `getStateFeature`. + /// immediately visible using `getFeatureState`. /// /// @param sourceId The style source identifier. /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). @@ -4158,8 +4124,6 @@ class _MapInterfaceSetup { /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be removed. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. let removeFeatureStateForFeaturesetDescriptorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.removeFeatureStateForFeaturesetDescriptor\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { removeFeatureStateForFeaturesetDescriptorChannel.setMessageHandler { message, reply in @@ -4184,8 +4148,6 @@ class _MapInterfaceSetup { /// /// @param feature An interactive feature to update. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. let removeFeatureStateForFeaturesetFeatureChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.removeFeatureStateForFeaturesetFeature\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { removeFeatureStateForFeaturesetFeatureChannel.setMessageHandler { message, reply in @@ -4210,8 +4172,6 @@ class _MapInterfaceSetup { /// immediately visible using ``MapboxMap/getFeatureState()``. /// /// @param featureset A featureset descriptor - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. let resetFeatureStatesForFeaturesetChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.resetFeatureStatesForFeatureset\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { resetFeatureStatesForFeaturesetChannel.setMessageHandler { message, reply in @@ -4229,23 +4189,6 @@ class _MapInterfaceSetup { } else { resetFeatureStatesForFeaturesetChannel.setMessageHandler(nil) } - let addInteractionChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.addInteraction\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) - if let api = api { - addInteractionChannel.setMessageHandler { message, reply in - let args = message as! [Any?] - let interactionArg = args[0] as! Interaction - api.addInteraction(interaction: interactionArg) { result in - switch result { - case .success(let res): - reply(wrapResult(res)) - case .failure(let error): - reply(wrapError(error)) - } - } - } - } else { - addInteractionChannel.setMessageHandler(nil) - } /// Reduces memory use. Useful to call when the application gets paused or sent to background. let reduceMemoryUseChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.reduceMemoryUse\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapInterfaceController.swift b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapInterfaceController.swift index c13980e7..51a52239 100644 --- a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapInterfaceController.swift +++ b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapInterfaceController.swift @@ -198,17 +198,6 @@ final class MapInterfaceController: _MapInterface { } } - func queryRenderedFeaturesForTargets(geometry: _RenderedQueryGeometry, targets: [FeaturesetQueryTarget], completion: @escaping (Result<[QueriedRenderedFeature], any Error>) -> Void) { - self.mapboxMap.queryRenderedFeatures(with: geometry, targets: targets.map({$0.toMapFeaturesetQueryTarget()})) { result in - switch result { - case .success(let features): - completion(.success(features.map({$0.toFLTQueriedRenderedFeature()}))) - case .failure(let error): - completion(.failure(FlutterError(code: MapInterfaceController.errorCode, message: "\(error)", details: nil))) - } - } - } - func queryRenderedFeaturesForFeatureset(geometry: _RenderedQueryGeometry, featureset: FeaturesetDescriptor, filter: String?, completion: @escaping (Result<[FeaturesetFeature], any Error>) -> Void) { let filterExpression = try? filter.flatMap { try $0.toExp() } self.mapboxMap.queryRenderedFeatures(with: geometry, featureset: featureset.toMapFeaturesetDescriptor(), filter: filterExpression) { result in @@ -248,17 +237,6 @@ final class MapInterfaceController: _MapInterface { } } - func querySourceFeaturesForTargets(target: FeaturesetQueryTarget, completion: @escaping (Result<[QueriedSourceFeature], any Error>) -> Void) { - self.mapboxMap.querySourceFeatures(for: target.toMapFeaturesetQueryTarget()) { result in - switch result { - case .success(let features): - completion(.success(features.map({$0.toFLTQueriedSourceFeature()}))) - case .failure(let error): - completion(.failure(FlutterError(code: MapInterfaceController.errorCode, message: "\(error)", details: nil))) - } - } - } - func getGeoJsonClusterLeaves(sourceIdentifier: String, cluster: [String?: Any?], limit: Int64?, offset: Int64?, completion: @escaping (Result) -> Void) { guard let feature = convertDictionaryToFeature(dict: cluster) else { completion(.failure(FlutterError(code: MapInterfaceController.errorCode, message: "Feature format error", details: convertDictionaryToString(dict: cluster)))) @@ -315,11 +293,11 @@ final class MapInterfaceController: _MapInterface { } } - func setFeatureStateForFeaturesetDescriptor(featureset: TypedFeaturesetDescriptor, featureId: FeaturesetFeatureId, state: [String: Any?], completion: @escaping (Result) -> Void) { + func setFeatureStateForFeaturesetDescriptor(featureset: FeaturesetDescriptor, featureId: FeaturesetFeatureId, state: [String: Any?], completion: @escaping (Result) -> Void) { guard let state = JSONObject.init(turfRawValue: state) else { return } - self.mapboxMap.setFeatureState(featureset: featureset.featuresetDescriptor.toMapFeaturesetDescriptor(), featureId: featureId.toMapFeaturesetFeatureId(), state: state) { error in + self.mapboxMap.setFeatureState(featureset: featureset.toMapFeaturesetDescriptor(), featureId: featureId.toMapFeaturesetFeatureId(), state: state) { error in if let error { completion(.failure(FlutterError( code: "setFeatureStateError", @@ -435,12 +413,6 @@ final class MapInterfaceController: _MapInterface { } } - func addInteraction(interaction: Interaction, completion: @escaping (Result) -> Void) { - mapboxMap.addInteraction(interaction.toMapInteraction(completion: { _ in - print("no op") - })) - } - func reduceMemoryUse() throws { mapboxMap.reduceMemoryUse() } diff --git a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapboxMapController.swift b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapboxMapController.swift index 2c276ce6..f83d7c87 100644 --- a/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapboxMapController.swift +++ b/ios/mapbox_maps_flutter/Sources/mapbox_maps_flutter/Classes/MapboxMapController.swift @@ -106,6 +106,38 @@ final class MapboxMapController: NSObject, FlutterPlatformView { case "gesture#remove_listeners": gesturesController!.removeListeners() result(nil) + case "interactions#add_interaction": + let listener = InteractionsListener(binaryMessenger: binaryMessenger.messenger, messageChannelSuffix: binaryMessenger.suffix) + guard let arguments = methodCall.arguments as? [String: Any], + let featuresetDescriptorList = arguments["featuresetDescriptor"] as? [String?], + let featuresetDescriptor = FeaturesetDescriptor.fromList(featuresetDescriptorList), + let interactionTypeRaw = arguments["interactionType"] as? Int, + let interactionType = InteractionType(rawValue: interactionTypeRaw), + let stopPropagation = arguments["stopPropagation"] as? Bool, + let id = arguments["id"] as? Int else { + return + } + let filter = arguments["filter"] as? String + let filterExpression = try? filter.flatMap { try $0.toExp() } + let radius = arguments["radius"] as? CGFloat + + switch interactionType { + case .tAP: + mapboxMap.addInteraction( + TapInteraction(featuresetDescriptor.toMapFeaturesetDescriptor(), filter: filterExpression, radius: radius, action: { featuresetFeature, context in + listener.onInteraction(context: context.toFLTMapContentGestureContext(), feature: featuresetFeature.toFLTFeaturesetFeature(), interactionID: Int64(id)) { _ in } + return stopPropagation + }) + ) + case .lONGTAP: + mapboxMap.addInteraction( + LongPressInteraction(featuresetDescriptor.toMapFeaturesetDescriptor(), filter: filterExpression, radius: radius, action: { featuresetFeature, context in + listener.onInteraction(context: context.toFLTMapContentGestureContext(), feature: featuresetFeature.toFLTFeaturesetFeature(), interactionID: Int64(id)) { _ in } + return stopPropagation + }) + ) + } + result(nil) case "platform#releaseMethodChannels": releaseMethodChannels() result(nil) diff --git a/lib/mapbox_maps_flutter.dart b/lib/mapbox_maps_flutter.dart index 9f66b2e7..e949729f 100644 --- a/lib/mapbox_maps_flutter.dart +++ b/lib/mapbox_maps_flutter.dart @@ -57,6 +57,10 @@ part 'src/style/source/rasterdem_source.dart'; part 'src/style/source/rasterarray_source.dart'; part 'src/style/source/vector_source.dart'; part 'src/style/style.dart'; +part 'src/style/interactive_features/interactive_features.dart'; +part 'src/style/interactive_features/standard_buildings.dart'; +part 'src/style/interactive_features/standard_place_labels.dart'; +part 'src/style/interactive_features/standard_poi.dart'; part 'src/location_settings.dart'; part 'src/snapshotter/snapshotter.dart'; part 'src/log_configuration.dart'; diff --git a/lib/src/callbacks.dart b/lib/src/callbacks.dart index c01a9b33..735eed68 100644 --- a/lib/src/callbacks.dart +++ b/lib/src/callbacks.dart @@ -72,3 +72,7 @@ typedef void OnTileRegionLoadProgressListener(TileRegionLoadProgress progress); // TileRegionEstimate load progress callback. typedef void OnTileRegionEstimateProgressListenter( TileRegionEstimateProgress progress); + +// Interaction callback called when a featureset or layer is interacted with. +typedef void OnInteraction( + MapContentGestureContext context, FeaturesetFeature feature); diff --git a/lib/src/mapbox_map.dart b/lib/src/mapbox_map.dart index 0bf51382..d4450177 100644 --- a/lib/src/mapbox_map.dart +++ b/lib/src/mapbox_map.dart @@ -443,15 +443,6 @@ class MapboxMap extends ChangeNotifier { _RenderedQueryGeometry(value: geometry.value, type: geometry.type), options); - /// Queries the map for rendered features using featureset descriptors. - @experimental - Future> queryRenderedFeaturesForTargets( - RenderedQueryGeometry geometry, - List targets) async => - _mapInterface.queryRenderedFeaturesForTargets( - _RenderedQueryGeometry(value: geometry.value, type: geometry.type), - targets); - /// Queries the map for rendered features with one typed featureset. @experimental Future> queryRenderedFeaturesForFeatureset( @@ -474,12 +465,6 @@ class MapboxMap extends ChangeNotifier { String sourceId, SourceQueryOptions options) => _mapInterface.querySourceFeatures(sourceId, options); - /// Queries the source features for a given featureset. - @experimental - Future> querySourceFeaturesForTargets( - FeaturesetQueryTarget target) async => - _mapInterface.querySourceFeaturesForTargets(target); - /// Returns all the leaves (original points) of a cluster (given its cluster_id) from a GeoJsonSource, with pagination support: limit is the number of leaves /// to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination). /// @@ -522,11 +507,11 @@ class MapboxMap extends ChangeNotifier { /// will be updated. An entry in the feature state map that is not listed in `state` will retain its previous value. @experimental Future setFeatureStateForFeaturesetDescriptor( - TypedFeaturesetDescriptor featureset, + FeaturesetDescriptor featureset, FeaturesetFeatureId featureId, - Map state) => + FeatureState state) => _mapInterface.setFeatureStateForFeaturesetDescriptor( - featureset, featureId, state); + featureset, featureId, state.map); /// Update the state map of an individual feature. /// @@ -534,8 +519,8 @@ class MapboxMap extends ChangeNotifier { /// the operation will be no-op and callback will receive an error. @experimental Future setFeatureStateForFeaturesetFeature( - FeaturesetFeature feature, Map state) => - _mapInterface.setFeatureStateForFeaturesetFeature(feature, state); + FeaturesetFeature feature, FeatureState state) => + _mapInterface.setFeatureStateForFeaturesetFeature(feature, state.map); /// Gets the state map of a feature within a style source. /// @@ -596,8 +581,22 @@ class MapboxMap extends ChangeNotifier { FeaturesetDescriptor featureset) => _mapInterface.resetFeatureStatesForFeatureset(featureset); - Future addInteraction(Interaction interaction) => - _mapInterface.addInteraction(interaction); + // References for all interactions added to the map. + _InteractionsList interactionsList = _InteractionsList(interactions: {}); + + /// Add an interaction + @experimental + void addInteraction(Interaction interaction, OnInteraction action) { + interactionsList.interactions[action.hashCode] = _InteractionListener( + onInteractionListener: action, + interactionID: action.hashCode, + ); + + InteractionsListener.setUp(interactionsList, + binaryMessenger: _mapboxMapsPlatform.binaryMessenger, + messageChannelSuffix: _mapboxMapsPlatform.channelSuffix.toString()); + _mapboxMapsPlatform.addInteractionsListeners(interaction, action.hashCode); + } /// Reduces memory use. Useful to call when the application gets paused or sent to background. Future reduceMemoryUse() => _mapInterface.reduceMemoryUse(); @@ -769,3 +768,36 @@ class _GestureListener extends GestureListener { onMapScrollListener?.call(context); } } + +// Listen for a single interaction added to the map, identified by its id +class _InteractionListener extends InteractionsListener { + _InteractionListener({ + required this.interactionID, + required this.onInteractionListener, + }); + + int interactionID; + + final OnInteraction onInteractionListener; + + @override + void onInteraction(MapContentGestureContext context, + FeaturesetFeature feature, int interactionID) { + onInteractionListener.call(context, feature); + } +} + +// Listen to all interactions on the map, determine which interaction to call +class _InteractionsList extends InteractionsListener { + _InteractionsList({ + required this.interactions, + }); + + Map interactions; + + @override + void onInteraction(MapContentGestureContext context, + FeaturesetFeature feature, int interactionID) { + interactions[interactionID]?.onInteraction(context, feature, interactionID); + } +} diff --git a/lib/src/mapbox_maps_platform.dart b/lib/src/mapbox_maps_platform.dart index 8b092c32..6108fa2e 100644 --- a/lib/src/mapbox_maps_platform.dart +++ b/lib/src/mapbox_maps_platform.dart @@ -161,6 +161,23 @@ class _MapboxMapsPlatform { } } + Future addInteractionsListeners( + Interaction interaction, int interactionID) async { + try { + return _channel + .invokeMethod('interactions#add_interaction', { + 'featuresetDescriptor': interaction.featuresetDescriptor.encode(), + 'interactionType': interaction.interactionType.index, + 'filter': interaction.filter, + 'radius': interaction.radius, + 'stopPropagation': interaction.stopPropagation, + 'id': interactionID, + }); + } on PlatformException catch (e) { + return new Future.error(e); + } + } + Future removeGestureListeners() async { try { return _channel.invokeMethod('gesture#remove_listeners'); diff --git a/lib/src/pigeons/map_interfaces.dart b/lib/src/pigeons/map_interfaces.dart index 2d7968cb..aa420e89 100644 --- a/lib/src/pigeons/map_interfaces.dart +++ b/lib/src/pigeons/map_interfaces.dart @@ -169,8 +169,8 @@ enum ViewAnnotationAnchor { } enum InteractionType { - CLICK, - LONG_CLICK, + TAP, + LONG_TAP, } /// Type information of the variant's content @@ -1340,67 +1340,74 @@ class FeaturesetFeatureId { } } -class Interaction { - Interaction({ - required this.typedFeaturesetDescriptor, - required this.interactionType, - this.filter, +class FeatureState { + FeatureState({ + required this.map, }); - TypedFeaturesetDescriptor typedFeaturesetDescriptor; - - InteractionType interactionType; - - String? filter; + Map map; Object encode() { return [ - typedFeaturesetDescriptor, - interactionType, - filter, + map, ]; } - static Interaction decode(Object result) { + static FeatureState decode(Object result) { result as List; - return Interaction( - typedFeaturesetDescriptor: result[0]! as TypedFeaturesetDescriptor, - interactionType: result[1]! as InteractionType, - filter: result[2] as String?, + return FeatureState( + map: (result[0] as Map?)!.cast(), ); } } -class TypedFeaturesetDescriptor { - TypedFeaturesetDescriptor({ +/// An interaction that can be added to the map. +/// +/// To create an interaction use ``TapInteraction`` and ``LongClickInteraction`` implementations. +/// +/// See also: ``MapboxMap/addInteraction``. +class Interaction { + Interaction({ required this.featuresetDescriptor, - required this.featuresetType, + required this.interactionType, + required this.stopPropagation, + this.filter, + this.radius, }); FeaturesetDescriptor featuresetDescriptor; - String featuresetType; + InteractionType interactionType; + + bool stopPropagation; + + String? filter; + + double? radius; Object encode() { return [ featuresetDescriptor, - featuresetType, + interactionType, + stopPropagation, + filter, + radius, ]; } - static TypedFeaturesetDescriptor decode(Object result) { + static Interaction decode(Object result) { result as List; - return TypedFeaturesetDescriptor( + return Interaction( featuresetDescriptor: result[0]! as FeaturesetDescriptor, - featuresetType: result[1]! as String, + interactionType: result[1]! as InteractionType, + stopPropagation: result[2]! as bool, + filter: result[3] as String?, + radius: result[4] as double?, ); } } -/// A featureset descriptor. -/// -/// The descriptor instance acts as a universal target for interactions or querying rendered features (see -/// ``MapboxMap/queryRenderedFeatures(with:featureset:filter:completion:)``). +///A featureset descriptor. class FeaturesetDescriptor { FeaturesetDescriptor({ this.featuresetId, @@ -1408,24 +1415,11 @@ class FeaturesetDescriptor { this.layerId, }); - /// An optional unique identifier for the featureset within the style. - /// This id is used to reference a specific featureset. - /// - /// * Note: If `featuresetId` is provided and valid, it takes precedence over `layerId`, - /// * meaning `layerId` will not be considered even if it has a valid value. String? featuresetId; - /// An optional import id that is required if the featureset is defined within an imported style. - /// If the featureset belongs to the current style, this field should be set to a null string. /// - /// Note: `importId` is only applicable when used in conjunction with `featuresetId` - /// and has no effect when used with `layerId`. String? importId; - /// An optional unique identifier for the layer within the current style. - /// - /// Note: If `featuresetId` is valid, `layerId` will be ignored even if it has a valid value. - /// Additionally, `importId` does not apply when using `layerId`. String? layerId; Object encode() { @@ -1446,9 +1440,6 @@ class FeaturesetDescriptor { } } -/// A basic feature of a featureset. -/// -/// The featureset feature is different to the `Turf.Feature`. The latter represents any GeoJSON feature, while the former is a high level representation of features. class FeaturesetFeature { FeaturesetFeature({ this.id, @@ -1458,25 +1449,14 @@ class FeaturesetFeature { required this.state, }); - /// An identifier of the feature. - /// - /// The identifier can be `nil` if the underlying source doesn't have identifiers for features. - /// In this case it's impossible to set a feature state for an individual feature. FeaturesetFeatureId? id; - /// A featureset descriptor denoting the featureset this feature belongs to. FeaturesetDescriptor featureset; - /// A feature geometry. Map geometry; - /// Feature JSON properties. Map properties; - /// A feature state. - /// - /// This is a **snapshot** of the state that the feature had when it was interacted with. - /// To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. Map state; Object encode() { @@ -2121,195 +2101,201 @@ class MapInterfaces_PigeonCodec extends StandardMessageCodec { } else if (value is InteractionType) { buffer.putUint8(137); writeValue(buffer, value.index); - } else if (value is Type) { + } else if (value is GestureState) { buffer.putUint8(138); writeValue(buffer, value.index); - } else if (value is FillExtrusionBaseAlignment) { + } else if (value is Type) { buffer.putUint8(139); writeValue(buffer, value.index); - } else if (value is FillExtrusionHeightAlignment) { + } else if (value is FillExtrusionBaseAlignment) { buffer.putUint8(140); writeValue(buffer, value.index); - } else if (value is BackgroundPitchAlignment) { + } else if (value is FillExtrusionHeightAlignment) { buffer.putUint8(141); writeValue(buffer, value.index); - } else if (value is StylePackErrorType) { + } else if (value is BackgroundPitchAlignment) { buffer.putUint8(142); writeValue(buffer, value.index); - } else if (value is ResponseErrorReason) { + } else if (value is StylePackErrorType) { buffer.putUint8(143); writeValue(buffer, value.index); - } else if (value is OfflineRegionDownloadState) { + } else if (value is ResponseErrorReason) { buffer.putUint8(144); writeValue(buffer, value.index); - } else if (value is TileStoreUsageMode) { + } else if (value is OfflineRegionDownloadState) { buffer.putUint8(145); writeValue(buffer, value.index); - } else if (value is StylePropertyValueKind) { + } else if (value is TileStoreUsageMode) { buffer.putUint8(146); writeValue(buffer, value.index); - } else if (value is StyleProjectionName) { + } else if (value is StylePropertyValueKind) { buffer.putUint8(147); writeValue(buffer, value.index); - } else if (value is Anchor) { + } else if (value is StyleProjectionName) { buffer.putUint8(148); writeValue(buffer, value.index); - } else if (value is HttpMethod) { + } else if (value is Anchor) { buffer.putUint8(149); writeValue(buffer, value.index); - } else if (value is HttpRequestErrorType) { + } else if (value is HttpMethod) { buffer.putUint8(150); writeValue(buffer, value.index); - } else if (value is DownloadErrorCode) { + } else if (value is HttpRequestErrorType) { buffer.putUint8(151); writeValue(buffer, value.index); - } else if (value is DownloadState) { + } else if (value is DownloadErrorCode) { buffer.putUint8(152); writeValue(buffer, value.index); - } else if (value is TileRegionErrorType) { + } else if (value is DownloadState) { buffer.putUint8(153); writeValue(buffer, value.index); - } else if (value is _MapEvent) { + } else if (value is TileRegionErrorType) { buffer.putUint8(154); writeValue(buffer, value.index); - } else if (value is Point) { + } else if (value is _MapEvent) { buffer.putUint8(155); - writeValue(buffer, value.encode()); - } else if (value is Feature) { + writeValue(buffer, value.index); + } else if (value is Point) { buffer.putUint8(156); writeValue(buffer, value.encode()); - } else if (value is GlyphsRasterizationOptions) { + } else if (value is Feature) { buffer.putUint8(157); writeValue(buffer, value.encode()); - } else if (value is TileCoverOptions) { + } else if (value is GlyphsRasterizationOptions) { buffer.putUint8(158); writeValue(buffer, value.encode()); - } else if (value is MbxEdgeInsets) { + } else if (value is TileCoverOptions) { buffer.putUint8(159); writeValue(buffer, value.encode()); - } else if (value is CameraOptions) { + } else if (value is MbxEdgeInsets) { buffer.putUint8(160); writeValue(buffer, value.encode()); - } else if (value is CameraState) { + } else if (value is CameraOptions) { buffer.putUint8(161); writeValue(buffer, value.encode()); - } else if (value is CameraBoundsOptions) { + } else if (value is CameraState) { buffer.putUint8(162); writeValue(buffer, value.encode()); - } else if (value is CameraBounds) { + } else if (value is CameraBoundsOptions) { buffer.putUint8(163); writeValue(buffer, value.encode()); - } else if (value is MapAnimationOptions) { + } else if (value is CameraBounds) { buffer.putUint8(164); writeValue(buffer, value.encode()); - } else if (value is CoordinateBounds) { + } else if (value is MapAnimationOptions) { buffer.putUint8(165); writeValue(buffer, value.encode()); - } else if (value is MapDebugOptions) { + } else if (value is CoordinateBounds) { buffer.putUint8(166); writeValue(buffer, value.encode()); - } else if (value is TileCacheBudgetInMegabytes) { + } else if (value is MapDebugOptions) { buffer.putUint8(167); writeValue(buffer, value.encode()); - } else if (value is TileCacheBudgetInTiles) { + } else if (value is TileCacheBudgetInMegabytes) { buffer.putUint8(168); writeValue(buffer, value.encode()); - } else if (value is MapOptions) { + } else if (value is TileCacheBudgetInTiles) { buffer.putUint8(169); writeValue(buffer, value.encode()); - } else if (value is ScreenCoordinate) { + } else if (value is MapOptions) { buffer.putUint8(170); writeValue(buffer, value.encode()); - } else if (value is ScreenBox) { + } else if (value is ScreenCoordinate) { buffer.putUint8(171); writeValue(buffer, value.encode()); - } else if (value is CoordinateBoundsZoom) { + } else if (value is ScreenBox) { buffer.putUint8(172); writeValue(buffer, value.encode()); - } else if (value is Size) { + } else if (value is CoordinateBoundsZoom) { buffer.putUint8(173); writeValue(buffer, value.encode()); - } else if (value is RenderedQueryOptions) { + } else if (value is Size) { buffer.putUint8(174); writeValue(buffer, value.encode()); - } else if (value is SourceQueryOptions) { + } else if (value is RenderedQueryOptions) { buffer.putUint8(175); writeValue(buffer, value.encode()); - } else if (value is FeatureExtensionValue) { + } else if (value is SourceQueryOptions) { buffer.putUint8(176); writeValue(buffer, value.encode()); - } else if (value is LayerPosition) { + } else if (value is FeatureExtensionValue) { buffer.putUint8(177); writeValue(buffer, value.encode()); - } else if (value is QueriedRenderedFeature) { + } else if (value is LayerPosition) { buffer.putUint8(178); writeValue(buffer, value.encode()); - } else if (value is QueriedSourceFeature) { + } else if (value is QueriedRenderedFeature) { buffer.putUint8(179); writeValue(buffer, value.encode()); - } else if (value is QueriedFeature) { + } else if (value is QueriedSourceFeature) { buffer.putUint8(180); writeValue(buffer, value.encode()); - } else if (value is FeaturesetFeatureId) { + } else if (value is QueriedFeature) { buffer.putUint8(181); writeValue(buffer, value.encode()); - } else if (value is Interaction) { + } else if (value is FeaturesetFeatureId) { buffer.putUint8(182); writeValue(buffer, value.encode()); - } else if (value is TypedFeaturesetDescriptor) { + } else if (value is FeatureState) { buffer.putUint8(183); writeValue(buffer, value.encode()); - } else if (value is FeaturesetDescriptor) { + } else if (value is Interaction) { buffer.putUint8(184); writeValue(buffer, value.encode()); - } else if (value is FeaturesetFeature) { + } else if (value is FeaturesetDescriptor) { buffer.putUint8(185); writeValue(buffer, value.encode()); - } else if (value is FeaturesetQueryTarget) { + } else if (value is FeaturesetFeature) { buffer.putUint8(186); writeValue(buffer, value.encode()); - } else if (value is _RenderedQueryGeometry) { + } else if (value is FeaturesetQueryTarget) { buffer.putUint8(187); writeValue(buffer, value.encode()); - } else if (value is ProjectedMeters) { + } else if (value is MapContentGestureContext) { buffer.putUint8(188); writeValue(buffer, value.encode()); - } else if (value is MercatorCoordinate) { + } else if (value is _RenderedQueryGeometry) { buffer.putUint8(189); writeValue(buffer, value.encode()); - } else if (value is StyleObjectInfo) { + } else if (value is ProjectedMeters) { buffer.putUint8(190); writeValue(buffer, value.encode()); - } else if (value is StyleProjection) { + } else if (value is MercatorCoordinate) { buffer.putUint8(191); writeValue(buffer, value.encode()); - } else if (value is FlatLight) { + } else if (value is StyleObjectInfo) { buffer.putUint8(192); writeValue(buffer, value.encode()); - } else if (value is DirectionalLight) { + } else if (value is StyleProjection) { buffer.putUint8(193); writeValue(buffer, value.encode()); - } else if (value is AmbientLight) { + } else if (value is FlatLight) { buffer.putUint8(194); writeValue(buffer, value.encode()); - } else if (value is MbxImage) { + } else if (value is DirectionalLight) { buffer.putUint8(195); writeValue(buffer, value.encode()); - } else if (value is ImageStretches) { + } else if (value is AmbientLight) { buffer.putUint8(196); writeValue(buffer, value.encode()); - } else if (value is ImageContent) { + } else if (value is MbxImage) { buffer.putUint8(197); writeValue(buffer, value.encode()); - } else if (value is TransitionOptions) { + } else if (value is ImageStretches) { buffer.putUint8(198); writeValue(buffer, value.encode()); - } else if (value is CanonicalTileID) { + } else if (value is ImageContent) { buffer.putUint8(199); writeValue(buffer, value.encode()); - } else if (value is StylePropertyValue) { + } else if (value is TransitionOptions) { buffer.putUint8(200); writeValue(buffer, value.encode()); + } else if (value is CanonicalTileID) { + buffer.putUint8(201); + writeValue(buffer, value.encode()); + } else if (value is StylePropertyValue) { + buffer.putUint8(202); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -2347,148 +2333,153 @@ class MapInterfaces_PigeonCodec extends StandardMessageCodec { return value == null ? null : InteractionType.values[value]; case 138: final int? value = readValue(buffer) as int?; - return value == null ? null : Type.values[value]; + return value == null ? null : GestureState.values[value]; case 139: final int? value = readValue(buffer) as int?; - return value == null ? null : FillExtrusionBaseAlignment.values[value]; + return value == null ? null : Type.values[value]; case 140: + final int? value = readValue(buffer) as int?; + return value == null ? null : FillExtrusionBaseAlignment.values[value]; + case 141: final int? value = readValue(buffer) as int?; return value == null ? null : FillExtrusionHeightAlignment.values[value]; - case 141: + case 142: final int? value = readValue(buffer) as int?; return value == null ? null : BackgroundPitchAlignment.values[value]; - case 142: + case 143: final int? value = readValue(buffer) as int?; return value == null ? null : StylePackErrorType.values[value]; - case 143: + case 144: final int? value = readValue(buffer) as int?; return value == null ? null : ResponseErrorReason.values[value]; - case 144: + case 145: final int? value = readValue(buffer) as int?; return value == null ? null : OfflineRegionDownloadState.values[value]; - case 145: + case 146: final int? value = readValue(buffer) as int?; return value == null ? null : TileStoreUsageMode.values[value]; - case 146: + case 147: final int? value = readValue(buffer) as int?; return value == null ? null : StylePropertyValueKind.values[value]; - case 147: + case 148: final int? value = readValue(buffer) as int?; return value == null ? null : StyleProjectionName.values[value]; - case 148: + case 149: final int? value = readValue(buffer) as int?; return value == null ? null : Anchor.values[value]; - case 149: + case 150: final int? value = readValue(buffer) as int?; return value == null ? null : HttpMethod.values[value]; - case 150: + case 151: final int? value = readValue(buffer) as int?; return value == null ? null : HttpRequestErrorType.values[value]; - case 151: + case 152: final int? value = readValue(buffer) as int?; return value == null ? null : DownloadErrorCode.values[value]; - case 152: + case 153: final int? value = readValue(buffer) as int?; return value == null ? null : DownloadState.values[value]; - case 153: + case 154: final int? value = readValue(buffer) as int?; return value == null ? null : TileRegionErrorType.values[value]; - case 154: + case 155: final int? value = readValue(buffer) as int?; return value == null ? null : _MapEvent.values[value]; - case 155: - return Point.decode(readValue(buffer)!); case 156: - return Feature.decode(readValue(buffer)!); + return Point.decode(readValue(buffer)!); case 157: - return GlyphsRasterizationOptions.decode(readValue(buffer)!); + return Feature.decode(readValue(buffer)!); case 158: - return TileCoverOptions.decode(readValue(buffer)!); + return GlyphsRasterizationOptions.decode(readValue(buffer)!); case 159: - return MbxEdgeInsets.decode(readValue(buffer)!); + return TileCoverOptions.decode(readValue(buffer)!); case 160: - return CameraOptions.decode(readValue(buffer)!); + return MbxEdgeInsets.decode(readValue(buffer)!); case 161: - return CameraState.decode(readValue(buffer)!); + return CameraOptions.decode(readValue(buffer)!); case 162: - return CameraBoundsOptions.decode(readValue(buffer)!); + return CameraState.decode(readValue(buffer)!); case 163: - return CameraBounds.decode(readValue(buffer)!); + return CameraBoundsOptions.decode(readValue(buffer)!); case 164: - return MapAnimationOptions.decode(readValue(buffer)!); + return CameraBounds.decode(readValue(buffer)!); case 165: - return CoordinateBounds.decode(readValue(buffer)!); + return MapAnimationOptions.decode(readValue(buffer)!); case 166: - return MapDebugOptions.decode(readValue(buffer)!); + return CoordinateBounds.decode(readValue(buffer)!); case 167: - return TileCacheBudgetInMegabytes.decode(readValue(buffer)!); + return MapDebugOptions.decode(readValue(buffer)!); case 168: - return TileCacheBudgetInTiles.decode(readValue(buffer)!); + return TileCacheBudgetInMegabytes.decode(readValue(buffer)!); case 169: - return MapOptions.decode(readValue(buffer)!); + return TileCacheBudgetInTiles.decode(readValue(buffer)!); case 170: - return ScreenCoordinate.decode(readValue(buffer)!); + return MapOptions.decode(readValue(buffer)!); case 171: - return ScreenBox.decode(readValue(buffer)!); + return ScreenCoordinate.decode(readValue(buffer)!); case 172: - return CoordinateBoundsZoom.decode(readValue(buffer)!); + return ScreenBox.decode(readValue(buffer)!); case 173: - return Size.decode(readValue(buffer)!); + return CoordinateBoundsZoom.decode(readValue(buffer)!); case 174: - return RenderedQueryOptions.decode(readValue(buffer)!); + return Size.decode(readValue(buffer)!); case 175: - return SourceQueryOptions.decode(readValue(buffer)!); + return RenderedQueryOptions.decode(readValue(buffer)!); case 176: - return FeatureExtensionValue.decode(readValue(buffer)!); + return SourceQueryOptions.decode(readValue(buffer)!); case 177: - return LayerPosition.decode(readValue(buffer)!); + return FeatureExtensionValue.decode(readValue(buffer)!); case 178: - return QueriedRenderedFeature.decode(readValue(buffer)!); + return LayerPosition.decode(readValue(buffer)!); case 179: - return QueriedSourceFeature.decode(readValue(buffer)!); + return QueriedRenderedFeature.decode(readValue(buffer)!); case 180: - return QueriedFeature.decode(readValue(buffer)!); + return QueriedSourceFeature.decode(readValue(buffer)!); case 181: - return FeaturesetFeatureId.decode(readValue(buffer)!); + return QueriedFeature.decode(readValue(buffer)!); case 182: - return Interaction.decode(readValue(buffer)!); + return FeaturesetFeatureId.decode(readValue(buffer)!); case 183: - return TypedFeaturesetDescriptor.decode(readValue(buffer)!); + return FeatureState.decode(readValue(buffer)!); case 184: - return FeaturesetDescriptor.decode(readValue(buffer)!); + return Interaction.decode(readValue(buffer)!); case 185: - return FeaturesetFeature.decode(readValue(buffer)!); + return FeaturesetDescriptor.decode(readValue(buffer)!); case 186: - return FeaturesetQueryTarget.decode(readValue(buffer)!); + return FeaturesetFeature.decode(readValue(buffer)!); case 187: - return _RenderedQueryGeometry.decode(readValue(buffer)!); + return FeaturesetQueryTarget.decode(readValue(buffer)!); case 188: - return ProjectedMeters.decode(readValue(buffer)!); + return MapContentGestureContext.decode(readValue(buffer)!); case 189: - return MercatorCoordinate.decode(readValue(buffer)!); + return _RenderedQueryGeometry.decode(readValue(buffer)!); case 190: - return StyleObjectInfo.decode(readValue(buffer)!); + return ProjectedMeters.decode(readValue(buffer)!); case 191: - return StyleProjection.decode(readValue(buffer)!); + return MercatorCoordinate.decode(readValue(buffer)!); case 192: - return FlatLight.decode(readValue(buffer)!); + return StyleObjectInfo.decode(readValue(buffer)!); case 193: - return DirectionalLight.decode(readValue(buffer)!); + return StyleProjection.decode(readValue(buffer)!); case 194: - return AmbientLight.decode(readValue(buffer)!); + return FlatLight.decode(readValue(buffer)!); case 195: - return MbxImage.decode(readValue(buffer)!); + return DirectionalLight.decode(readValue(buffer)!); case 196: - return ImageStretches.decode(readValue(buffer)!); + return AmbientLight.decode(readValue(buffer)!); case 197: - return ImageContent.decode(readValue(buffer)!); + return MbxImage.decode(readValue(buffer)!); case 198: - return TransitionOptions.decode(readValue(buffer)!); + return ImageStretches.decode(readValue(buffer)!); case 199: - return CanonicalTileID.decode(readValue(buffer)!); + return ImageContent.decode(readValue(buffer)!); case 200: + return TransitionOptions.decode(readValue(buffer)!); + case 201: + return CanonicalTileID.decode(readValue(buffer)!); + case 202: return StylePropertyValue.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -3352,6 +3343,60 @@ class _CameraManager { } } +abstract class InteractionsListener { + static const MessageCodec pigeonChannelCodec = + MapInterfaces_PigeonCodec(); + + void onInteraction(MapContentGestureContext context, + FeaturesetFeature feature, int interactionID); + + static void setUp( + InteractionsListener? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction was null.'); + final List args = (message as List?)!; + final MapContentGestureContext? arg_context = + (args[0] as MapContentGestureContext?); + assert(arg_context != null, + 'Argument for dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction was null, expected non-null MapContentGestureContext.'); + final FeaturesetFeature? arg_feature = + (args[1] as FeaturesetFeature?); + assert(arg_feature != null, + 'Argument for dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction was null, expected non-null FeaturesetFeature.'); + final int? arg_interactionID = (args[2] as int?); + assert(arg_interactionID != null, + 'Argument for dev.flutter.pigeon.mapbox_maps_flutter.InteractionsListener.onInteraction was null, expected non-null int.'); + try { + api.onInteraction(arg_context!, arg_feature!, arg_interactionID!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + /// Map class provides map rendering functionality. /// class _MapInterface { @@ -3972,51 +4017,13 @@ class _MapInterface { } } - /// Queries the map for rendered features using featureset descriptors. - /// - /// This method allows to query both featureset from imported styles and user layers in the root style. - /// The results can be additionally filtered per-featureset. - /// - /// - Important: This is a low-level method. If you need to handle basic gestures on map content, please prefer ``MapboxMap/ queryRenderedFeaturesForFeatureset()``. - /// - /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. - /// @param targets An array of targets to query with. - Future> queryRenderedFeaturesForTargets( - _RenderedQueryGeometry geometry, - List targets) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.queryRenderedFeaturesForTargets$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([geometry, targets]) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } - } - /// Queries the map for rendered features with one typed featureset. /// /// The results array will contain features of the type specified by this featureset. /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. + /// /// @param geometry A screen geometry to query. Can be a `CGPoint`, `CGRect`, or an array of `CGPoint`. /// @param featureset A typed featureset to query with. /// @param filter An additional filter for features. @@ -4057,6 +4064,9 @@ class _MapInterface { /// /// This is same as `MapboxMap/ queryRenderedFeaturesForFeatureset()`` called with geometry matching the current viewport. /// + /// - Important: If you need to handle basic gestures on map content, + /// please prefer to use Interactions API, see `MapboxMap/addInteraction`. + /// /// @param featureset A typed featureset to query with. /// @param filter An additional filter for features. Future> queryRenderedFeaturesInViewport( @@ -4126,40 +4136,6 @@ class _MapInterface { } } - /// Queries the source features for a given featureset. - /// - /// @param target A featureset query target. - Future> querySourceFeaturesForTargets( - FeaturesetQueryTarget target) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.querySourceFeaturesForTargets$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([target]) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); - } - } - /// Returns all the leaves (original points) of a cluster (given its cluster_id) from a GeoJsonSource, with pagination support: limit is the number of leaves /// to return (set to Infinity for all points), and offset is the amount of points to skip (for pagination). /// @@ -4326,10 +4302,8 @@ class _MapInterface { /// @param featureset The featureset to look the feature in. /// @param featureId Identifier of the feature whose state should be updated. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. Future setFeatureStateForFeaturesetDescriptor( - TypedFeaturesetDescriptor featureset, + FeaturesetDescriptor featureset, FeaturesetFeatureId featureId, Map state) async { final String pigeonVar_channelName = @@ -4362,8 +4336,6 @@ class _MapInterface { /// /// @param feature The feature to update. /// @param state Map of entries to update with their respective new values - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. Future setFeatureStateForFeaturesetFeature( FeaturesetFeature feature, Map state) async { final String pigeonVar_channelName = @@ -4398,7 +4370,7 @@ class _MapInterface { /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). /// @param featureId The feature identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. + /// @return A String representing the Feature's state map. Future getFeatureState( String sourceId, String? sourceLayerId, String featureId) async { final String pigeonVar_channelName = @@ -4434,7 +4406,7 @@ class _MapInterface { /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be queried. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. Future> getFeatureStateForFeaturesetDescriptor( FeaturesetDescriptor featureset, FeaturesetFeatureId featureId) async { final String pigeonVar_channelName = @@ -4468,9 +4440,9 @@ class _MapInterface { /// Get the state map of a feature within a style source. /// - /// @param feature An interactive feature to query the state from. + /// @param feature An interactive feature to query the state of. /// - /// @return A `Cancelable` object that could be used to cancel the pending query. + /// @return The Feature's state map or an empty map if the feature could not be found. Future> getFeatureStateForFeaturesetFeature( FeaturesetFeature feature) async { final String pigeonVar_channelName = @@ -4508,7 +4480,7 @@ class _MapInterface { /// `stateKey`. /// /// Note that updates to feature state are asynchronous, so changes made by this method might not be - /// immediately visible using `getStateFeature`. + /// immediately visible using `getFeatureState`. /// /// @param sourceId The style source identifier. /// @param sourceLayerId The style source layer identifier (for multi-layer sources such as vector sources). @@ -4546,8 +4518,6 @@ class _MapInterface { /// @param featureset A featureset the feature belongs to. /// @param featureId Identifier of the feature whose state should be removed. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. Future removeFeatureStateForFeaturesetDescriptor( FeaturesetDescriptor featureset, FeaturesetFeatureId featureId, @@ -4580,8 +4550,6 @@ class _MapInterface { /// /// @param feature An interactive feature to update. /// @param stateKey The key of the property to remove. If `nil`, all feature's state object properties are removed. Defaults to `nil`. - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. Future removeFeatureStateForFeaturesetFeature( FeaturesetFeature feature, String? stateKey) async { final String pigeonVar_channelName = @@ -4613,8 +4581,6 @@ class _MapInterface { /// immediately visible using ``MapboxMap/getFeatureState()``. /// /// @param featureset A featureset descriptor - /// - /// @return A `Cancelable` object that could be used to cancel the pending operation. Future resetFeatureStatesForFeatureset( FeaturesetDescriptor featureset) async { final String pigeonVar_channelName = @@ -4640,35 +4606,6 @@ class _MapInterface { } } - Future addInteraction(Interaction interaction) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.mapbox_maps_flutter._MapInterface.addInteraction$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( - pigeonVar_channelName, - pigeonChannelCodec, - binaryMessenger: pigeonVar_binaryMessenger, - ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([interaction]) as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as FeaturesetFeature?)!; - } - } - /// Reduces memory use. Useful to call when the application gets paused or sent to background. Future reduceMemoryUse() async { final String pigeonVar_channelName = diff --git a/lib/src/style/interactive_features/interactive_features.dart b/lib/src/style/interactive_features/interactive_features.dart new file mode 100644 index 00000000..a301c5cb --- /dev/null +++ b/lib/src/style/interactive_features/interactive_features.dart @@ -0,0 +1,44 @@ +part of mapbox_maps_flutter; + +// A single tap interaction. +class TapInteraction extends Interaction { + TapInteraction(FeaturesetDescriptor featuresetDescriptor, + {String? filter, double? radius, bool stopPropagation = true}) + : super( + featuresetDescriptor: featuresetDescriptor, + interactionType: InteractionType.TAP, + filter: filter, + radius: radius, + stopPropagation: stopPropagation); +} + +// A long tap interaction +class LongTapInteraction extends Interaction { + LongTapInteraction(FeaturesetDescriptor featuresetDescriptor, + {String? filter, double? radius, bool stopPropagation = true}) + : super( + featuresetDescriptor: featuresetDescriptor, + interactionType: InteractionType.LONG_TAP, + filter: filter, + radius: radius, + stopPropagation: stopPropagation); +} + +extension Featureset on FeaturesetDescriptor { + // A Featureset of buildings in the Standard style + static FeaturesetDescriptor standardBuildings({String importId = "basemap"}) { + return FeaturesetDescriptor(featuresetId: "buildings", importId: importId); + } + + // A Featureset of place labels in the Standard style + static FeaturesetDescriptor standardPlaceLabels( + {String importId = "basemap"}) { + return FeaturesetDescriptor( + featuresetId: "place-labels", importId: importId); + } + + // A Featureset of POIs in the Standard style + static FeaturesetDescriptor standardPoi({String importId = "basemap"}) { + return FeaturesetDescriptor(featuresetId: "poi", importId: importId); + } +} diff --git a/lib/src/style/interactive_features/standard_buildings.dart b/lib/src/style/interactive_features/standard_buildings.dart new file mode 100644 index 00000000..79cbd06b --- /dev/null +++ b/lib/src/style/interactive_features/standard_buildings.dart @@ -0,0 +1,52 @@ +part of mapbox_maps_flutter; + +// A Feature that represents a building in the Standard style. +class StandardBuildingsFeature extends FeaturesetFeature { + // A feature state. + // + // This is a **snapshot** of the state that the feature had when it was interacted with. + // To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. + StandardBuildingState get stateSnapshot { + return StandardBuildingState() + ..highlight = state["highlight"] as bool? + ..select = state["select"] as bool?; + } + + // A high-level building group like building-2d, building-3d, etc. + String? get group { + return properties["group"] as String?; + } + + StandardBuildingsFeature(Map geometry, + Map properties, Map state, + {FeaturesetFeatureId? id}) + : super( + id: id, + featureset: Featureset.standardBuildings(), + geometry: geometry, + properties: properties, + state: state); +} + +// Represents available states for Buildings in the Standard style. +class StandardBuildingState extends FeatureState { + // When `true`, the feature is highlighted. Use this state to create a temporary effect (e.g. hover). + bool? highlight; + + // When `true`, the feature is selected. Use this state to create a permanent effect. Note: the `select` state has a higher priority than `highlight`. + bool? select; + + @override + Map get map { + return { + "highlight": highlight, + "select": select, + }; + } + + StandardBuildingState({this.highlight, this.select}) + : super(map: { + "highlight": highlight, + "select": select, + }); +} diff --git a/lib/src/style/interactive_features/standard_place_labels.dart b/lib/src/style/interactive_features/standard_place_labels.dart new file mode 100644 index 00000000..7f0ddcdf --- /dev/null +++ b/lib/src/style/interactive_features/standard_place_labels.dart @@ -0,0 +1,64 @@ +part of mapbox_maps_flutter; + +// A feature that labels places including countries, states, cities, +// towns, and neighborhoods in the Standard style. +class StandardPlaceLabelsFeature extends FeaturesetFeature { + // A feature state. + // + // This is a **snapshot** of the state that the feature had when it was interacted with. + // To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. + StandardPlaceLabelsState get stateSnapshot { + return StandardPlaceLabelsState() + ..hide = state["hide"] as bool? + ..highlight = state["highlight"] as bool? + ..select = state["select"] as bool?; + } + + // Name of the place label. + String? get name { + return properties["name"] as String?; + } + + // Provides a broad distinction between place types. + String? get category { + return properties["class"] as String?; + } + + StandardPlaceLabelsFeature(Map geometry, + Map properties, Map state, + {FeaturesetFeatureId? id}) + : super( + id: id, + featureset: Featureset.standardPlaceLabels(), + geometry: geometry, + properties: properties, + state: state); +} + +// Represents available states for Place Labels in the Standard style. +class StandardPlaceLabelsState extends FeatureState { + // When `true`, hides the label. Use this state when displaying a custom annotation on top. + bool? hide; + + // When `true`, the feature is highlighted. Use this state to create a temporary effect (e.g. hover). + bool? highlight; + + // When `true`, the feature is selected. Use this state to create a permanent effect. Note: the `select` state has a higher priority than `highlight`. + bool? select; + + @override + Map get map { + return { + "hide": hide, + "highlight": highlight, + "select": select, + }; + } + + StandardPlaceLabelsState({this.hide, this.highlight, this.select}) + : super(map: { + "hide": hide, + "highlight": highlight, + "select": select, + }); +} diff --git a/lib/src/style/interactive_features/standard_poi.dart b/lib/src/style/interactive_features/standard_poi.dart new file mode 100644 index 00000000..1d0faa33 --- /dev/null +++ b/lib/src/style/interactive_features/standard_poi.dart @@ -0,0 +1,85 @@ +part of mapbox_maps_flutter; + +// A feature that is a point of interest in the Standard style. +class StandardPoiFeature extends FeaturesetFeature { + // A feature state. + // + // This is a **snapshot** of the state that the feature had when it was interacted with. + // To update and read the original state, use ``MapboxMap/setFeatureState()`` and ``MapboxMap/getFeatureState()``. + StandardPoiState get stateSnapshot { + return StandardPoiState()..hide = state["hide"] as bool?; + } + + // Name of the point of interest. + String? get name { + return properties["name"] as String?; + } + + // A high-level point of interest category like airport, transit, etc. + String? get group { + return properties["group"] as String?; + } + + // A broad category of point of interest. + String? get category { + return properties["class"] as String?; + } + + // An icon identifier, designed to assign icons using the Maki icon project or other icons that follow the same naming scheme. + String? get maki { + return properties["maki"] as String?; + } + + // Mode of transport served by a stop/station. Expected to be null for non-transit points of interest. + String? get transitMode { + return properties["transit_mode"] as String?; + } + + // A type of transit stop. Expected to be null for non-transit points of interest. + String? get transitStopType { + return properties["transit_stop_type"] as String?; + } + + // A rail station network identifier that is part of specific local or regional transit systems. Expected to be null for non-transit points of interest. + String? get transitNetwork { + return properties["transit_network"] as String?; + } + + // A short identifier code of the airport. Expected to be null for non-airport points of interest + String? get airportRef { + return properties["airport_ref"] as String?; + } + + // POI coordinate. + Point? get coordinate { + return this.geometry["coordinates"] as Point?; + } + + StandardPoiFeature(Map geometry, + Map properties, Map state, + {FeaturesetFeatureId? id}) + : super( + id: id, + featureset: Featureset.standardPoi(), + geometry: geometry, + properties: properties, + state: state); +} + +// Represents available states for POIs in the Standard style. +class StandardPoiState extends FeatureState { + // When `true`, hides the icon and text. + bool? hide; + + @override + Map get map { + return { + "hide": hide + }; + } + + StandardPoiState({this.hide}) + : super(map: { + "hide": hide, + }); +}