From 899aaee35c3d45faa463bd1ea0b0c2f4112fe097 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 16 Sep 2024 19:50:52 +0200 Subject: [PATCH 01/24] add point and line to geojson --- example/assets/geojson/lake-constance.geojson | 302 +++++++++++++++++- 1 file changed, 297 insertions(+), 5 deletions(-) diff --git a/example/assets/geojson/lake-constance.geojson b/example/assets/geojson/lake-constance.geojson index fa38a43e..456605d4 100644 --- a/example/assets/geojson/lake-constance.geojson +++ b/example/assets/geojson/lake-constance.geojson @@ -3,7 +3,13 @@ "features": [ { "type": "Feature", - "properties": {}, + "properties": { + "stroke": "#555555", + "stroke-width": 2, + "stroke-opacity": 1, + "fill": "#006eff", + "fill-opacity": 0.5 + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -926,11 +932,18 @@ ] ] ] - } + }, + "id": 0 }, { "type": "Feature", - "properties": {}, + "properties": { + "stroke": "#555555", + "stroke-width": 2, + "stroke-opacity": 1, + "fill": "#006eff", + "fill-opacity": 0.5 + }, "geometry": { "type": "Polygon", "coordinates": [ @@ -1777,7 +1790,286 @@ ] ] ] - } + }, + "id": 1 + }, + { + "type": "Feature", + "properties": { + "marker-color": "#44ff00", + "marker-size": "medium", + "marker-symbol": "circle" + }, + "geometry": { + "coordinates": [ + 9.612023924867714, + 47.78123442179836 + ], + "type": "Point" + }, + "id": 2 + }, + { + "type": "Feature", + "properties": { + "stroke": "#ff0000", + "stroke-width": 2, + "stroke-opacity": 1 + }, + "geometry": { + "coordinates": [ + [ + 8.799117107928566, + 47.98031816347611 + ], + [ + 8.802328819792677, + 47.98076582463398 + ], + [ + 8.817904468759707, + 47.97745570014669 + ], + [ + 8.826390707612575, + 47.97244912896508 + ], + [ + 8.84188371730258, + 47.971915035837725 + ], + [ + 8.85029608449463, + 47.967779690393144 + ], + [ + 8.852578427361692, + 47.96088225610791 + ], + [ + 8.85972977956527, + 47.95763666134866 + ], + [ + 8.860756091700068, + 47.95321071446159 + ], + [ + 8.862281911076224, + 47.95161027803556 + ], + [ + 8.864992467984365, + 47.95072764504209 + ], + [ + 8.87241161716912, + 47.951133910812075 + ], + [ + 8.88036168488702, + 47.95072393821974 + ], + [ + 8.883852331924714, + 47.94927687485284 + ], + [ + 8.889116318020058, + 47.94979644093698 + ], + [ + 8.894212150334823, + 47.949760113191275 + ], + [ + 8.89686922826536, + 47.95042881837165 + ], + [ + 8.90097357323745, + 47.95235725855733 + ], + [ + 8.903401026366964, + 47.95333512052477 + ], + [ + 8.90853424918015, + 47.95436653075481 + ], + [ + 8.912984319885538, + 47.955741250130984 + ], + [ + 8.920632002647665, + 47.95948483507931 + ], + [ + 8.93128560533225, + 47.962891797978045 + ], + [ + 8.942141808964891, + 47.964834314637955 + ], + [ + 8.945351040880723, + 47.96607579837854 + ], + [ + 8.953740994906042, + 47.97431440467997 + ], + [ + 8.955183655954187, + 47.97556187853948 + ], + [ + 8.980001942528048, + 47.9835245361206 + ], + [ + 8.985014566204484, + 47.98624681282624 + ], + [ + 8.992431562288289, + 47.98675079034763 + ], + [ + 8.998457236384041, + 47.988285180762944 + ], + [ + 9.002950586623086, + 47.98723448417749 + ], + [ + 9.007456726238615, + 47.98807598531127 + ], + [ + 9.018791023659105, + 47.988268233444416 + ], + [ + 9.025941096772556, + 47.98607812509849 + ], + [ + 9.032167710890548, + 47.98565116348948 + ], + [ + 9.0425847424045, + 47.98398600752353 + ], + [ + 9.047255542069024, + 47.98325347250184 + ], + [ + 9.068694613567288, + 47.986853029526 + ], + [ + 9.079932652188717, + 47.99091871503305 + ], + [ + 9.08337858941482, + 47.99331600728851 + ], + [ + 9.086502553152542, + 47.99655061510569 + ], + [ + 9.100070457331725, + 48.00056940419924 + ], + [ + 9.112663861277838, + 48.004626463075624 + ], + [ + 9.116716325761303, + 48.00401905221722 + ], + [ + 9.118981849700475, + 47.998880528914185 + ], + [ + 9.12078212120079, + 47.99632053346093 + ], + [ + 9.145500430251786, + 47.99980913370595 + ], + [ + 9.158384208371189, + 48.004602101069565 + ], + [ + 9.175291790464513, + 48.0009797534496 + ], + [ + 9.190364345811616, + 48.00203873237297 + ], + [ + 9.198439358447331, + 48.00520875178674 + ], + [ + 9.202555904172954, + 48.00880720120335 + ], + [ + 9.207477631885041, + 48.00843946025233 + ], + [ + 9.219795657188257, + 48.01376252258876 + ], + [ + 9.232358074932307, + 48.01352132221842 + ], + [ + 9.239203031974398, + 48.01882104696671 + ], + [ + 9.249607388831635, + 48.01847383078007 + ], + [ + 9.248516081925175, + 48.03109776319255 + ], + [ + 9.23729166283212, + 48.045756481204506 + ], + [ + 9.222818584686621, + 48.0684021146711 + ], + [ + 9.207442853196198, + 48.07521325271787 + ] + ], + "type": "LineString" + }, + "id": 3 } ] -} +} \ No newline at end of file From 56ea8b02b8bb026dd18d42c1570a302c9384e1bd Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:24:33 +0200 Subject: [PATCH 02/24] add public API layer and source objects --- lib/maplibre.dart | 3 +- lib/src/layers.dart | 29 ----- lib/src/native/widget_state.dart | 24 ++++ lib/src/sources.dart | 16 --- lib/src/style/layers/background_layer.dart | 27 ++++ lib/src/style/layers/circle_layer.dart | 17 +++ .../style/layers/fill_extrusion_layer.dart | 13 ++ lib/src/style/layers/fill_layer.dart | 17 +++ lib/src/style/layers/heatmap_layer.dart | 13 ++ lib/src/style/layers/hillshade_layer.dart | 13 ++ lib/src/style/layers/layer.dart | 66 ++++++++++ lib/src/style/layers/line_layer.dart | 13 ++ lib/src/style/layers/raster_layer.dart | 17 +++ lib/src/style/layers/symbol_layer.dart | 17 +++ lib/src/style/sources/geo_json_source.dart | 33 +++++ lib/src/style/sources/image_source.dart | 24 ++++ lib/src/style/sources/raster_dem_source.dart | 116 ++++++++++++++++++ lib/src/style/sources/raster_source.dart | 66 ++++++++++ lib/src/style/sources/source.dart | 24 ++++ lib/src/style/sources/vector_source.dart | 62 ++++++++++ lib/src/style/sources/video_source.dart | 35 ++++++ lib/src/style/style.dart | 2 + lib/src/web/widget_state.dart | 31 +++++ pigeons/run_code_gen.ps1 | 2 +- 24 files changed, 632 insertions(+), 48 deletions(-) delete mode 100644 lib/src/layers.dart delete mode 100644 lib/src/sources.dart create mode 100644 lib/src/style/layers/background_layer.dart create mode 100644 lib/src/style/layers/circle_layer.dart create mode 100644 lib/src/style/layers/fill_extrusion_layer.dart create mode 100644 lib/src/style/layers/fill_layer.dart create mode 100644 lib/src/style/layers/heatmap_layer.dart create mode 100644 lib/src/style/layers/hillshade_layer.dart create mode 100644 lib/src/style/layers/layer.dart create mode 100644 lib/src/style/layers/line_layer.dart create mode 100644 lib/src/style/layers/raster_layer.dart create mode 100644 lib/src/style/layers/symbol_layer.dart create mode 100644 lib/src/style/sources/geo_json_source.dart create mode 100644 lib/src/style/sources/image_source.dart create mode 100644 lib/src/style/sources/raster_dem_source.dart create mode 100644 lib/src/style/sources/raster_source.dart create mode 100644 lib/src/style/sources/source.dart create mode 100644 lib/src/style/sources/vector_source.dart create mode 100644 lib/src/style/sources/video_source.dart create mode 100644 lib/src/style/style.dart diff --git a/lib/maplibre.dart b/lib/maplibre.dart index 4dc8023c..92047843 100644 --- a/lib/maplibre.dart +++ b/lib/maplibre.dart @@ -3,11 +3,10 @@ export 'package:geotypes/geotypes.dart'; export 'src/annotations.dart'; -export 'src/layers.dart'; export 'src/lng_lat_bounds.dart'; export 'src/map.dart'; export 'src/map_camera.dart'; export 'src/map_controller.dart'; export 'src/map_options.dart'; -export 'src/sources.dart'; +export 'src/style/style.dart'; export 'src/utils.dart'; diff --git a/lib/src/layers.dart b/lib/src/layers.dart deleted file mode 100644 index 3d3360e2..00000000 --- a/lib/src/layers.dart +++ /dev/null @@ -1,29 +0,0 @@ -/// The base Layer class that can't be used directly. Use [CircleLayer] or -/// [FillLayer] instead. -sealed class Layer { - const Layer(); -} - -/// A layer that contains circles. -final class CircleLayer extends Layer { - /// Default constructor for a [CircleLayer] instance. - const CircleLayer({required this.id, required this.sourceId}); - - /// The layer id. - final String id; - - /// The id of the source that should get used. - final String sourceId; -} - -/// A layer that contains polygons. -final class FillLayer extends Layer { - /// Default constructor for a [FillLayer] instance. - const FillLayer({required this.id, required this.sourceId}); - - /// The layer id. - final String id; - - /// The id of the source that should get used. - final String sourceId; -} diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index 9206e30d..73955fe5 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -118,6 +118,20 @@ final class MapLibreMapStateNative extends State _hostApi.addFillLayer(id: layer.id, sourceId: layer.sourceId), CircleLayer() => _hostApi.addCircleLayer(id: layer.id, sourceId: layer.sourceId), + // TODO: Handle this case. + BackgroundLayer() => throw UnimplementedError(), + // TODO: Handle this case. + FillExtrusionLayer() => throw UnimplementedError(), + // TODO: Handle this case. + HeatmapLayer() => throw UnimplementedError(), + // TODO: Handle this case. + HillshadeLayer() => throw UnimplementedError(), + // TODO: Handle this case. + LineLayer() => throw UnimplementedError(), + // TODO: Handle this case. + RasterLayer() => throw UnimplementedError(), + // TODO: Handle this case. + SymbolLayer() => throw UnimplementedError(), }; } @@ -126,6 +140,16 @@ final class MapLibreMapStateNative extends State await switch (source) { GeoJsonSource() => _hostApi.addGeoJsonSource(id: source.id, data: source.data), + // TODO: Handle this case. + RasterDemSource() => throw UnimplementedError(), + // TODO: Handle this case. + RasterSource() => throw UnimplementedError(), + // TODO: Handle this case. + VectorSource() => throw UnimplementedError(), + // TODO: Handle this case. + ImageSource() => throw UnimplementedError(), + // TODO: Handle this case. + VideoSource() => throw UnimplementedError(), }; } diff --git a/lib/src/sources.dart b/lib/src/sources.dart deleted file mode 100644 index b6f02b70..00000000 --- a/lib/src/sources.dart +++ /dev/null @@ -1,16 +0,0 @@ -/// The base Source class that can't be used directly. -sealed class Source { - const Source(); -} - -/// A layer that contains circles. -final class GeoJsonSource extends Source { - /// The default constructor for a [GeoJsonSource] object. - const GeoJsonSource({required this.id, required this.data}); - - /// The id of the [GeoJsonSource]. - final String id; - - /// The GeoJSON data. - final String data; -} diff --git a/lib/src/style/layers/background_layer.dart b/lib/src/style/layers/background_layer.dart new file mode 100644 index 00000000..75dfa069 --- /dev/null +++ b/lib/src/style/layers/background_layer.dart @@ -0,0 +1,27 @@ +part of 'layer.dart'; + +/// https://maplibre.org/maplibre-style-spec/layers/#background +final class BackgroundLayer extends Layer { + /// Create a new [BackgroundLayer]. + const BackgroundLayer({ + required super.id, + this.visible = true, + this.color = const Color(0x00000000), + this.opacity = 1, + }); + + /// Whether this layer is displayed. + /// + /// Defaults to visible. + final bool visible; + + /// The color with which the background will be drawn. + /// + /// Defaults to #000000 (black). + final Color color; + + /// The opacity at which the background will be drawn. + /// + /// Defaults to 1. + final double opacity; +} diff --git a/lib/src/style/layers/circle_layer.dart b/lib/src/style/layers/circle_layer.dart new file mode 100644 index 00000000..98a0d31d --- /dev/null +++ b/lib/src/style/layers/circle_layer.dart @@ -0,0 +1,17 @@ +part of 'layer.dart'; + +/// A layer that contains circles. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#circle +final class CircleLayer extends Layer { + /// Default constructor for a [CircleLayer] instance. + const CircleLayer({ + required super.id, + required this.sourceId, + }); + + /// The id of the source that should get used. + final String sourceId; + + // TODO add properties +} diff --git a/lib/src/style/layers/fill_extrusion_layer.dart b/lib/src/style/layers/fill_extrusion_layer.dart new file mode 100644 index 00000000..b51d950a --- /dev/null +++ b/lib/src/style/layers/fill_extrusion_layer.dart @@ -0,0 +1,13 @@ +part of 'layer.dart'; + +/// A layer that contains circles. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#circle +final class FillExtrusionLayer extends Layer { + /// Default constructor for a [FillExtrusionLayer] instance. + const FillExtrusionLayer({ + required super.id, + }); + + // TODO add properties +} diff --git a/lib/src/style/layers/fill_layer.dart b/lib/src/style/layers/fill_layer.dart new file mode 100644 index 00000000..cd66bff3 --- /dev/null +++ b/lib/src/style/layers/fill_layer.dart @@ -0,0 +1,17 @@ +part of 'layer.dart'; + +/// A layer that contains polygons. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#fill +final class FillLayer extends Layer { + /// Default constructor for a [FillLayer] instance. + const FillLayer({ + required super.id, + required this.sourceId, + }); + + /// The id of the source that should get used. + final String sourceId; + + // TODO add properties +} diff --git a/lib/src/style/layers/heatmap_layer.dart b/lib/src/style/layers/heatmap_layer.dart new file mode 100644 index 00000000..8a48ef04 --- /dev/null +++ b/lib/src/style/layers/heatmap_layer.dart @@ -0,0 +1,13 @@ +part of 'layer.dart'; + +/// A layer that contains circles. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#circle +final class HeatmapLayer extends Layer { + /// Default constructor for a [HeatmapLayer] instance. + const HeatmapLayer({ + required super.id, + }); + + // TODO add properties +} diff --git a/lib/src/style/layers/hillshade_layer.dart b/lib/src/style/layers/hillshade_layer.dart new file mode 100644 index 00000000..57299d56 --- /dev/null +++ b/lib/src/style/layers/hillshade_layer.dart @@ -0,0 +1,13 @@ +part of 'layer.dart'; + +/// A layer that contains circles. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#circle +final class HillshadeLayer extends Layer { + /// Default constructor for a [HillshadeLayer] instance. + const HillshadeLayer({ + required super.id, + }); + + // TODO add properties +} diff --git a/lib/src/style/layers/layer.dart b/lib/src/style/layers/layer.dart new file mode 100644 index 00000000..4c99c39d --- /dev/null +++ b/lib/src/style/layers/layer.dart @@ -0,0 +1,66 @@ +import 'dart:ui'; + +part 'background_layer.dart'; +part 'circle_layer.dart'; +part 'fill_extrusion_layer.dart'; +part 'fill_layer.dart'; +part 'heatmap_layer.dart'; +part 'hillshade_layer.dart'; +part 'line_layer.dart'; +part 'raster_layer.dart'; +part 'symbol_layer.dart'; + +/// The base Layer class that can't be used directly. +sealed class Layer { + const Layer({ + required this.id, + this.metadata, + this.source, + this.sourceLayer, + this.minZoom, + this.maxZoom, + this.paint, + this.filter, + this.layout, + }); + + /// Unique layer name. + final String id; + + /// Arbitrary properties useful to track with the layer, but do not influence + /// rendering. Properties should be prefixed to avoid collisions, + /// like 'maplibre:'. + final Map? metadata; + + /// Name of a source description to be used for this layer. Required for all + /// layer types except background. + final String? source; + + /// Layer to use from a vector tile source. Required for vector tile sources; + /// prohibited for all other source types, including GeoJSON sources. + final String? sourceLayer; + + /// The minimum zoom level for the layer. At zoom levels less than the + /// minzoom, the layer will be hidden. + /// + /// Needs to be in the range of [0,24]. + final double? minZoom; + + /// The maximum zoom level for the layer. At zoom levels equal to or greater + /// than the maxzoom, the layer will be hidden. + /// + /// Needs to be in the range of [0,24]. + final double? maxZoom; + + /// A expression specifying conditions on source features. Only features that + /// match the filter are displayed. Zoom expressions in filters are only + /// evaluated at integer zoom levels. The feature-state expression is not + /// supported in filter expressions. + final Object? filter; + + /// Layout properties for the layer. + final Object? layout; + + /// Default paint properties for this layer. + final Object? paint; +} diff --git a/lib/src/style/layers/line_layer.dart b/lib/src/style/layers/line_layer.dart new file mode 100644 index 00000000..e36f57ee --- /dev/null +++ b/lib/src/style/layers/line_layer.dart @@ -0,0 +1,13 @@ +part of 'layer.dart'; + +/// A layer that contains circles. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#circle +final class LineLayer extends Layer { + /// Default constructor for a [LineLayer] instance. + const LineLayer({ + required super.id, + }); + + // TODO add properties +} diff --git a/lib/src/style/layers/raster_layer.dart b/lib/src/style/layers/raster_layer.dart new file mode 100644 index 00000000..e4a86e3c --- /dev/null +++ b/lib/src/style/layers/raster_layer.dart @@ -0,0 +1,17 @@ +part of 'layer.dart'; + +/// A layer that contains markers. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#symbol +final class RasterLayer extends Layer { + /// Default constructor for a [RasterLayer] instance. + const RasterLayer({ + required super.id, + required this.sourceId, + }); + + /// The id of the source that should get used. + final String sourceId; + + // TODO add properties +} diff --git a/lib/src/style/layers/symbol_layer.dart b/lib/src/style/layers/symbol_layer.dart new file mode 100644 index 00000000..5c284f25 --- /dev/null +++ b/lib/src/style/layers/symbol_layer.dart @@ -0,0 +1,17 @@ +part of 'layer.dart'; + +/// A layer that contains markers. +/// +/// https://maplibre.org/maplibre-style-spec/layers/#symbol +final class SymbolLayer extends Layer { + /// Default constructor for a [SymbolLayer] instance. + const SymbolLayer({ + required super.id, + required this.sourceId, + }); + + /// The id of the source that should get used. + final String sourceId; + + // TODO add properties +} diff --git a/lib/src/style/sources/geo_json_source.dart b/lib/src/style/sources/geo_json_source.dart new file mode 100644 index 00000000..4d703c4c --- /dev/null +++ b/lib/src/style/sources/geo_json_source.dart @@ -0,0 +1,33 @@ +part of 'source.dart'; + +/// A GeoJSON source. Data must be provided via a "data" property, whose value +/// can be a URL or inline GeoJSON. When using in a browser, the GeoJSON data +/// must be on the same domain as the map or served with CORS headers. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#geojson +final class GeoJsonSource extends Source { + /// The default constructor for a [GeoJsonSource] object. + const GeoJsonSource({ + required this.id, + required this.data, + this.maxZoom = 18, + this.attribution, + }); + + /// The id of the [GeoJsonSource]. + final String id; + + /// A URL to a GeoJSON file, or GeoJSON string. + final String data; + + /// Maximum zoom level at which to create vector tiles (higher means greater + /// detail at high zoom levels). + /// + /// Defaults to 18. + final double maxZoom; + + /// Contains an attribution to be displayed when the map is shown to a user. + final String? attribution; + + // TODO add more fields https://maplibre.org/maplibre-style-spec/sources/#buffer +} diff --git a/lib/src/style/sources/image_source.dart b/lib/src/style/sources/image_source.dart new file mode 100644 index 00000000..fbf85367 --- /dev/null +++ b/lib/src/style/sources/image_source.dart @@ -0,0 +1,24 @@ +part of 'source.dart'; + +/// An image source. The url value contains the image location. The coordinates +/// array contains [longitude, latitude] pairs for the image corners listed in +/// clockwise order: top left, top right, bottom right, bottom left. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#image +final class ImageSource extends Source { + /// The default constructor for a [ImageSource] object. + const ImageSource({ + required this.id, + required this.url, + required this.coordinates, + }); + + /// The id of the [ImageSource]. + final String id; + + /// URL that points to an image. + final String url; + + /// Corners of image specified in longitude, latitude pairs. + final List coordinates; +} diff --git a/lib/src/style/sources/raster_dem_source.dart b/lib/src/style/sources/raster_dem_source.dart new file mode 100644 index 00000000..2af2cfef --- /dev/null +++ b/lib/src/style/sources/raster_dem_source.dart @@ -0,0 +1,116 @@ +part of 'source.dart'; + +/// A raster DEM source. Only supports Mapbox Terrain RGB and Mapzen +/// Terrarium tiles. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#raster-dem +final class RasterDemSource extends Source { + /// The default constructor for a [RasterDemSource] object. + const RasterDemSource({ + this.url, + this.tiles, + this.bounds = const [-180, -85.051129, 180, 85.051129], + this.minZoom = 0, + this.maxZoom = 2, + this.tileSize = 512, + this.attribution, + this.encoding = const RasterDemMapboxEncoding(), + this.volatile = false, + }); + + /// A URL to a TileJSON resource. Supported protocols are `http:` and + /// `https:`. + final String? url; + + /// An array of one or more tile source URLs, as in the TileJSON spec. + final List? tiles; + + /// An array containing the longitude and latitude of the southwest and + /// northeast corners of the source's bounding box in the following order: + /// `sw.lng, sw.lat, ne.lng, ne.lat`. When this property is included in a + /// source, no tiles outside of the given bounds are requested by MapLibre. + /// + /// Defaults to `-180, -85.051129, 180, 85.051129`. + final List bounds; + + /// Minimum zoom level for which tiles are available, as in the TileJSON spec. + /// + /// Defaults to 0. + final double minZoom; + + /// Maximum zoom level for which tiles are available, as in the TileJSON + /// spec. Data from tiles at the maxzoom are used when displaying the map at + /// higher zoom levels. + /// + /// Defaults to 22. + final double maxZoom; + + /// The minimum visual size to display tiles for this layer. Only + /// configurable for raster layers. + /// + /// Defaults to 512. + final double tileSize; + + /// Contains an attribution to be displayed when the map is shown to a user. + final String? attribution; + + /// The encoding used by this source. Mapbox Terrain RGB is used by default. + final RasterDemEncoding encoding; + + /// A setting to determine whether a source's tiles are cached locally. + /// + /// Defaults to false. Not available on web. + final bool volatile; +} + +/// The encoding used by this source. Mapbox Terrain RGB is used by default. +sealed class RasterDemEncoding { + const RasterDemEncoding(); +} + +/// Terrarium format PNG tiles. +/// See https://aws.amazon.com/es/public-datasets/terrain/ for more info. +final class RasterDemTerrariumEncoding extends RasterDemEncoding { + /// Create a [RasterDemCustomEncoding]. + const RasterDemTerrariumEncoding(); +} + +/// Mapbox Terrain RGB tiles. +/// See https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb +/// for more info. +final class RasterDemMapboxEncoding extends RasterDemEncoding { + /// Create a [RasterDemMapboxEncoding]. + const RasterDemMapboxEncoding(); +} + +/// Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift +/// parameters. +final class RasterDemCustomEncoding extends RasterDemEncoding { + /// Create a [RasterDemCustomEncoding]. + const RasterDemCustomEncoding({ + this.redFactor = 1, + this.blueFactor = 1, + this.greenFactor = 1, + this.baseShift = 0, + }); + + /// Value that will be multiplied by the red channel value when decoding. + /// + /// Defaults to 1. + final double redFactor; + + /// Value that will be multiplied by the blue channel value when decoding. + /// + /// Defaults to 1. + final double blueFactor; + + /// Value that will be multiplied by the green channel value when decoding. + /// + /// Defaults to 1. + final double greenFactor; + + /// Value that will be added to the encoding mix when decoding. + /// + /// Defaults to 0. + final double baseShift; +} diff --git a/lib/src/style/sources/raster_source.dart b/lib/src/style/sources/raster_source.dart new file mode 100644 index 00000000..43315e43 --- /dev/null +++ b/lib/src/style/sources/raster_source.dart @@ -0,0 +1,66 @@ +part of 'source.dart'; + +/// A raster tile source. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#raster +final class RasterSource extends Source { + /// The default constructor for a [RasterSource] object. + const RasterSource({ + this.url, + this.tiles, + this.bounds = const [-180, -85.051129, 180, 85.051129], + this.minZoom = 0, + this.maxZoom = 2, + this.tileSize = 512, + this.scheme = TileScheme.xyz, + this.attribution, + this.volatile = false, + }); + + /// A URL to a TileJSON resource. Supported protocols are `http:` and + /// `https:`. + final String? url; + + /// An array of one or more tile source URLs, as in the TileJSON spec. + final List? tiles; + + /// An array containing the longitude and latitude of the southwest and + /// northeast corners of the source's bounding box in the following order: + /// `sw.lng, sw.lat, ne.lng, ne.lat`. When this property is included in a + /// source, no tiles outside of the given bounds are requested by MapLibre. + /// + /// Defaults to `-180, -85.051129, 180, 85.051129`. + final List bounds; + + /// Minimum zoom level for which tiles are available, as in the TileJSON spec. + /// + /// Defaults to 0. + final double minZoom; + + /// Maximum zoom level for which tiles are available, as in the TileJSON + /// spec. Data from tiles at the maxzoom are used when displaying the map at + /// higher zoom levels. + /// + /// Defaults to 22. + final double maxZoom; + + /// The minimum visual size to display tiles for this layer. Only + /// configurable for raster layers. + /// + /// Defaults to 512. + final double tileSize; + + /// Influences the y direction of the tile coordinates. The global-mercator + /// (aka Spherical Mercator) profile is assumed. + /// + /// Defaults to xyz. + final TileScheme scheme; + + /// Contains an attribution to be displayed when the map is shown to a user. + final String? attribution; + + /// A setting to determine whether a source's tiles are cached locally. + /// + /// Defaults to false. Not available on web. + final bool volatile; +} diff --git a/lib/src/style/sources/source.dart b/lib/src/style/sources/source.dart new file mode 100644 index 00000000..a266132c --- /dev/null +++ b/lib/src/style/sources/source.dart @@ -0,0 +1,24 @@ +import 'package:maplibre/maplibre.dart'; + +part 'geo_json_source.dart'; +part 'raster_dem_source.dart'; +part 'raster_source.dart'; +part 'vector_source.dart'; +part 'image_source.dart'; +part 'video_source.dart'; + +/// The base Source class that can't be used directly. +/// +/// https://maplibre.org/maplibre-style-spec/sources +sealed class Source { + const Source(); +} + +/// Influences the y direction of the tile coordinates. +enum TileScheme { + /// Slippy map tilenames scheme. + xyz, + + /// OSGeo spec scheme. + tms; +} diff --git a/lib/src/style/sources/vector_source.dart b/lib/src/style/sources/vector_source.dart new file mode 100644 index 00000000..a5675448 --- /dev/null +++ b/lib/src/style/sources/vector_source.dart @@ -0,0 +1,62 @@ +part of 'source.dart'; + +/// A vector tile source. Tiles must be in Mapbox Vector Tile format. All +/// geometric coordinates in vector tiles must be between -1 * extent and +/// (extent * 2) - 1 inclusive. All layers that use a vector source must +/// specify a source-layer value. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#vector +final class VectorSource extends Source { + /// The default constructor for a [VectorSource] object. + const VectorSource({ + this.url, + this.tiles, + this.bounds = const [-180, -85.051129, 180, 85.051129], + this.scheme = TileScheme.xyz, + this.minZoom = 0, + this.maxZoom = 2, + this.attribution, + this.volatile = false, + }); + + /// A URL to a TileJSON resource. Supported protocols are `http:` and + /// `https:`. + final String? url; + + /// An array of one or more tile source URLs, as in the TileJSON spec. + final List? tiles; + + /// An array containing the longitude and latitude of the southwest and + /// northeast corners of the source's bounding box in the following order: + /// `sw.lng, sw.lat, ne.lng, ne.lat`. When this property is included in a + /// source, no tiles outside of the given bounds are requested by MapLibre. + /// + /// Defaults to `-180, -85.051129, 180, 85.051129`. + final List bounds; + + /// Influences the y direction of the tile coordinates. The global-mercator + /// (aka Spherical Mercator) profile is assumed. + /// + /// Defaults to xyz. + final TileScheme scheme; + + /// Minimum zoom level for which tiles are available, as in the TileJSON spec. + /// + /// Defaults to 0. + final double minZoom; + + /// Maximum zoom level for which tiles are available, as in the TileJSON + /// spec. Data from tiles at the maxzoom are used when displaying the map at + /// higher zoom levels. + /// + /// Defaults to 22. + final double maxZoom; + + /// Contains an attribution to be displayed when the map is shown to a user. + final String? attribution; + + /// A setting to determine whether a source's tiles are cached locally. + /// + /// Defaults to false. Not available on web. + final bool volatile; +} diff --git a/lib/src/style/sources/video_source.dart b/lib/src/style/sources/video_source.dart new file mode 100644 index 00000000..4b4d10df --- /dev/null +++ b/lib/src/style/sources/video_source.dart @@ -0,0 +1,35 @@ +part of 'source.dart'; + +/// A video source. The urls value is an array. For each URL in the array, a +/// video element source will be created. To support the video across +/// browsers, supply URLs in multiple formats. +/// +/// The coordinates array contains [longitude, latitude] pairs for the video +/// corners listed in clockwise order: top left, top right, bottom right, bottom +/// left. +/// +/// When rendered as a raster layer, the layer's raster-fade-duration property +/// will cause the video to fade in. This happens when playback is started, +/// paused and resumed, or when the video's coordinates are updated. To avoid +/// this behavior, set the layer's raster-fade-duration property to 0. +/// +/// Only supported on web. +/// +/// https://maplibre.org/maplibre-style-spec/sources/#video +final class VideoSource extends Source { + /// The default constructor for a [VideoSource] object. + const VideoSource({ + required this.id, + required this.urls, + required this.coordinates, + }); + + /// The id of the [VideoSource]. + final String id; + + /// URLs to video content in order of preferred format. + final List urls; + + /// Corners of video specified in longitude, latitude pairs. + final List coordinates; +} diff --git a/lib/src/style/style.dart b/lib/src/style/style.dart new file mode 100644 index 00000000..270a9f6a --- /dev/null +++ b/lib/src/style/style.dart @@ -0,0 +1,2 @@ +export 'layers/layer.dart'; +export 'sources/source.dart'; diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index f1795e15..677fa6f8 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -264,6 +264,16 @@ final class MapLibreMapStateWeb extends State source.id, interop.SourceSpecification.geoJson(type: 'geojson', data: data), ); + case RasterDemSource(): + // TODO: Handle this case. + case RasterSource(): + // TODO: Handle this case. + case VectorSource(): + // TODO: Handle this case. + case ImageSource(): + // TODO: Handle this case. + case VideoSource(): + // TODO: Handle this case. } } @@ -286,6 +296,27 @@ final class MapLibreMapStateWeb extends State source: layer.sourceId, ), ); + case BackgroundLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case FillExtrusionLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case HeatmapLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case HillshadeLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case LineLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case RasterLayer(): + // TODO: Handle this case. + throw UnimplementedError(); + case SymbolLayer(): + // TODO: Handle this case. + throw UnimplementedError(); } } diff --git a/pigeons/run_code_gen.ps1 b/pigeons/run_code_gen.ps1 index 695b8ed0..839c2452 100644 --- a/pigeons/run_code_gen.ps1 +++ b/pigeons/run_code_gen.ps1 @@ -13,4 +13,4 @@ dart run pigeon --input pigeons/pigeon.dart dart format . # Copy file from ios to macos directory -Copy-Item ios/Classes/Pigeon.g.swift -Destination macos/Classes/Pigeon.g.swift \ No newline at end of file +Copy-Item ios/Classes/Pigeon.g.swift -Destination macos/Classes/Pigeon.g.swift From d9f48b89425944367a2076c05f133dad63e8f586 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Mon, 16 Sep 2024 23:48:58 +0200 Subject: [PATCH 03/24] add LayerWithSource, optional addLayer(beforeId) --- ...-constance.geojson => lake-constance.json} | 0 example/lib/annotations_page.dart | 10 +- lib/src/map_controller.dart | 7 +- lib/src/native/widget_state.dart | 15 ++- lib/src/style/layers/circle_layer.dart | 7 +- .../style/layers/fill_extrusion_layer.dart | 3 +- lib/src/style/layers/fill_layer.dart | 8 +- lib/src/style/layers/heatmap_layer.dart | 3 +- lib/src/style/layers/hillshade_layer.dart | 3 +- lib/src/style/layers/layer.dart | 32 ++++-- lib/src/style/layers/line_layer.dart | 3 +- lib/src/style/layers/raster_layer.dart | 7 +- lib/src/style/layers/symbol_layer.dart | 7 +- lib/src/style/sources/geo_json_source.dart | 5 +- lib/src/style/sources/image_source.dart | 5 +- lib/src/style/sources/raster_dem_source.dart | 1 + lib/src/style/sources/raster_source.dart | 1 + lib/src/style/sources/source.dart | 5 +- lib/src/style/sources/vector_source.dart | 6 ++ lib/src/style/sources/video_source.dart | 5 +- lib/src/web/interop/map.dart | 39 ++++++-- lib/src/web/widget_state.dart | 99 ++++++++++++++----- 22 files changed, 189 insertions(+), 82 deletions(-) rename example/assets/geojson/{lake-constance.geojson => lake-constance.json} (100%) diff --git a/example/assets/geojson/lake-constance.geojson b/example/assets/geojson/lake-constance.json similarity index 100% rename from example/assets/geojson/lake-constance.geojson rename to example/assets/geojson/lake-constance.json diff --git a/example/lib/annotations_page.dart b/example/lib/annotations_page.dart index 1c441dd3..86843d7e 100644 --- a/example/lib/annotations_page.dart +++ b/example/lib/annotations_page.dart @@ -31,12 +31,18 @@ class _AnnotationsPageState extends State { ); } final geojson = await rootBundle - .loadString('assets/geojson/lake-constance.geojson'); + .loadString('assets/geojson/lake-constance.json'); await _controller.addSource( GeoJsonSource(id: 'LakeConstance', data: geojson), ); await _controller.addLayer( - const FillLayer(id: 'LakeConstance', sourceId: 'LakeConstance'), + const FillLayer(id: 'geojson-fill', sourceId: 'LakeConstance'), + ); + await _controller.addLayer( + const LineLayer(id: 'geojson-line', sourceId: 'LakeConstance'), + ); + await _controller.addLayer( + const SymbolLayer(id: 'geojson-symbol', sourceId: 'LakeConstance'), ); }, ), diff --git a/lib/src/map_controller.dart b/lib/src/map_controller.dart index 9c4ec5ff..24fe41da 100644 --- a/lib/src/map_controller.dart +++ b/lib/src/map_controller.dart @@ -39,7 +39,12 @@ abstract interface class MapController { /// Add a new layer to the map. The source must be added before adding it to /// the map. - Future addLayer(Layer layer); + /// + /// `beforeId` The ID of an existing layer to insert the new layer before, + /// resulting in the new layer appearing visually beneath the existing layer. + /// If this argument is not specified, the layer will be appended to the end + /// of the layers array and appear visually above all other layers. + Future addLayer(Layer layer, {String? beforeId}); /// Get the current camera position on the map. Future getCamera(); diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index 73955fe5..4aed4ac0 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -17,6 +17,19 @@ final class MapLibreMapStateNative extends State @override Widget build(BuildContext context) { if (Platform.isAndroid) { + // Texture Layer (or Texture Layer Hybrid Composition) + // Platform Views are rendered into a texture. Flutter draws the + // platform views (via the texture). Flutter content is rendered + // directly into a Surface. + // + good performance for Android Views + // + best performance for Flutter rendering. + // + all transformations work correctly. + // - quick scrolling (e.g. a web view) will be janky + // - SurfaceViews are problematic in this mode and will be moved into a + // virtual display (breaking a11y) + // - Text magnifier will break unless Flutter is rendered into a + // TextureView. + // https://docs.flutter.dev/platform-integration/android/platform-views#texturelayerhybridcompisition return AndroidView( viewType: 'plugins.flutter.io/maplibre', onPlatformViewCreated: _onPlatformViewCreated, @@ -112,7 +125,7 @@ final class MapLibreMapStateNative extends State ); @override - Future addLayer(Layer layer) async { + Future addLayer(Layer layer, {String? beforeId}) async { await switch (layer) { FillLayer() => _hostApi.addFillLayer(id: layer.id, sourceId: layer.sourceId), diff --git a/lib/src/style/layers/circle_layer.dart b/lib/src/style/layers/circle_layer.dart index 98a0d31d..e1c7769b 100644 --- a/lib/src/style/layers/circle_layer.dart +++ b/lib/src/style/layers/circle_layer.dart @@ -3,15 +3,12 @@ part of 'layer.dart'; /// A layer that contains circles. /// /// https://maplibre.org/maplibre-style-spec/layers/#circle -final class CircleLayer extends Layer { +final class CircleLayer extends LayerWithSource { /// Default constructor for a [CircleLayer] instance. const CircleLayer({ required super.id, - required this.sourceId, + required super.sourceId, }); - /// The id of the source that should get used. - final String sourceId; - // TODO add properties } diff --git a/lib/src/style/layers/fill_extrusion_layer.dart b/lib/src/style/layers/fill_extrusion_layer.dart index b51d950a..fa567ca9 100644 --- a/lib/src/style/layers/fill_extrusion_layer.dart +++ b/lib/src/style/layers/fill_extrusion_layer.dart @@ -3,10 +3,11 @@ part of 'layer.dart'; /// A layer that contains circles. /// /// https://maplibre.org/maplibre-style-spec/layers/#circle -final class FillExtrusionLayer extends Layer { +final class FillExtrusionLayer extends LayerWithSource { /// Default constructor for a [FillExtrusionLayer] instance. const FillExtrusionLayer({ required super.id, + required super.sourceId, }); // TODO add properties diff --git a/lib/src/style/layers/fill_layer.dart b/lib/src/style/layers/fill_layer.dart index cd66bff3..4df31190 100644 --- a/lib/src/style/layers/fill_layer.dart +++ b/lib/src/style/layers/fill_layer.dart @@ -3,15 +3,11 @@ part of 'layer.dart'; /// A layer that contains polygons. /// /// https://maplibre.org/maplibre-style-spec/layers/#fill -final class FillLayer extends Layer { +final class FillLayer extends LayerWithSource { /// Default constructor for a [FillLayer] instance. const FillLayer({ required super.id, - required this.sourceId, + required super.sourceId, }); - - /// The id of the source that should get used. - final String sourceId; - // TODO add properties } diff --git a/lib/src/style/layers/heatmap_layer.dart b/lib/src/style/layers/heatmap_layer.dart index 8a48ef04..0251650d 100644 --- a/lib/src/style/layers/heatmap_layer.dart +++ b/lib/src/style/layers/heatmap_layer.dart @@ -3,10 +3,11 @@ part of 'layer.dart'; /// A layer that contains circles. /// /// https://maplibre.org/maplibre-style-spec/layers/#circle -final class HeatmapLayer extends Layer { +final class HeatmapLayer extends LayerWithSource { /// Default constructor for a [HeatmapLayer] instance. const HeatmapLayer({ required super.id, + required super.sourceId, }); // TODO add properties diff --git a/lib/src/style/layers/hillshade_layer.dart b/lib/src/style/layers/hillshade_layer.dart index 57299d56..65e8a5ff 100644 --- a/lib/src/style/layers/hillshade_layer.dart +++ b/lib/src/style/layers/hillshade_layer.dart @@ -3,10 +3,11 @@ part of 'layer.dart'; /// A layer that contains circles. /// /// https://maplibre.org/maplibre-style-spec/layers/#circle -final class HillshadeLayer extends Layer { +final class HillshadeLayer extends LayerWithSource { /// Default constructor for a [HillshadeLayer] instance. const HillshadeLayer({ required super.id, + required super.sourceId, }); // TODO add properties diff --git a/lib/src/style/layers/layer.dart b/lib/src/style/layers/layer.dart index 4c99c39d..671fe64e 100644 --- a/lib/src/style/layers/layer.dart +++ b/lib/src/style/layers/layer.dart @@ -1,5 +1,7 @@ import 'dart:ui'; +import 'package:maplibre/maplibre.dart'; + part 'background_layer.dart'; part 'circle_layer.dart'; part 'fill_extrusion_layer.dart'; @@ -15,8 +17,6 @@ sealed class Layer { const Layer({ required this.id, this.metadata, - this.source, - this.sourceLayer, this.minZoom, this.maxZoom, this.paint, @@ -32,14 +32,6 @@ sealed class Layer { /// like 'maplibre:'. final Map? metadata; - /// Name of a source description to be used for this layer. Required for all - /// layer types except background. - final String? source; - - /// Layer to use from a vector tile source. Required for vector tile sources; - /// prohibited for all other source types, including GeoJSON sources. - final String? sourceLayer; - /// The minimum zoom level for the layer. At zoom levels less than the /// minzoom, the layer will be hidden. /// @@ -64,3 +56,23 @@ sealed class Layer { /// Default paint properties for this layer. final Object? paint; } + +/// A [Layer] that pulls its data from a [Source]. Basically every layer +/// except [BackgroundLayer]. +sealed class LayerWithSource extends Layer { + /// const constructor for [LayerWithSource]. + const LayerWithSource({ + required super.id, + required this.sourceId, + super.metadata, + super.minZoom, + super.maxZoom, + super.paint, + super.filter, + super.layout, + }); + + /// Name of a source description to be used for this layer. Required for all + /// layer types except background. + final String sourceId; +} diff --git a/lib/src/style/layers/line_layer.dart b/lib/src/style/layers/line_layer.dart index e36f57ee..8a3fccc5 100644 --- a/lib/src/style/layers/line_layer.dart +++ b/lib/src/style/layers/line_layer.dart @@ -3,10 +3,11 @@ part of 'layer.dart'; /// A layer that contains circles. /// /// https://maplibre.org/maplibre-style-spec/layers/#circle -final class LineLayer extends Layer { +final class LineLayer extends LayerWithSource { /// Default constructor for a [LineLayer] instance. const LineLayer({ required super.id, + required super.sourceId, }); // TODO add properties diff --git a/lib/src/style/layers/raster_layer.dart b/lib/src/style/layers/raster_layer.dart index e4a86e3c..b91a52a3 100644 --- a/lib/src/style/layers/raster_layer.dart +++ b/lib/src/style/layers/raster_layer.dart @@ -3,15 +3,12 @@ part of 'layer.dart'; /// A layer that contains markers. /// /// https://maplibre.org/maplibre-style-spec/layers/#symbol -final class RasterLayer extends Layer { +final class RasterLayer extends LayerWithSource { /// Default constructor for a [RasterLayer] instance. const RasterLayer({ required super.id, - required this.sourceId, + required super.sourceId, }); - /// The id of the source that should get used. - final String sourceId; - // TODO add properties } diff --git a/lib/src/style/layers/symbol_layer.dart b/lib/src/style/layers/symbol_layer.dart index 5c284f25..620a7962 100644 --- a/lib/src/style/layers/symbol_layer.dart +++ b/lib/src/style/layers/symbol_layer.dart @@ -3,15 +3,12 @@ part of 'layer.dart'; /// A layer that contains markers. /// /// https://maplibre.org/maplibre-style-spec/layers/#symbol -final class SymbolLayer extends Layer { +final class SymbolLayer extends LayerWithSource { /// Default constructor for a [SymbolLayer] instance. const SymbolLayer({ required super.id, - required this.sourceId, + required super.sourceId, }); - /// The id of the source that should get used. - final String sourceId; - // TODO add properties } diff --git a/lib/src/style/sources/geo_json_source.dart b/lib/src/style/sources/geo_json_source.dart index 4d703c4c..b9e39ac8 100644 --- a/lib/src/style/sources/geo_json_source.dart +++ b/lib/src/style/sources/geo_json_source.dart @@ -8,15 +8,12 @@ part of 'source.dart'; final class GeoJsonSource extends Source { /// The default constructor for a [GeoJsonSource] object. const GeoJsonSource({ - required this.id, + required super.id, required this.data, this.maxZoom = 18, this.attribution, }); - /// The id of the [GeoJsonSource]. - final String id; - /// A URL to a GeoJSON file, or GeoJSON string. final String data; diff --git a/lib/src/style/sources/image_source.dart b/lib/src/style/sources/image_source.dart index fbf85367..04144d22 100644 --- a/lib/src/style/sources/image_source.dart +++ b/lib/src/style/sources/image_source.dart @@ -8,14 +8,11 @@ part of 'source.dart'; final class ImageSource extends Source { /// The default constructor for a [ImageSource] object. const ImageSource({ - required this.id, + required super.id, required this.url, required this.coordinates, }); - /// The id of the [ImageSource]. - final String id; - /// URL that points to an image. final String url; diff --git a/lib/src/style/sources/raster_dem_source.dart b/lib/src/style/sources/raster_dem_source.dart index 2af2cfef..1022ea44 100644 --- a/lib/src/style/sources/raster_dem_source.dart +++ b/lib/src/style/sources/raster_dem_source.dart @@ -7,6 +7,7 @@ part of 'source.dart'; final class RasterDemSource extends Source { /// The default constructor for a [RasterDemSource] object. const RasterDemSource({ + required super.id, this.url, this.tiles, this.bounds = const [-180, -85.051129, 180, 85.051129], diff --git a/lib/src/style/sources/raster_source.dart b/lib/src/style/sources/raster_source.dart index 43315e43..07287478 100644 --- a/lib/src/style/sources/raster_source.dart +++ b/lib/src/style/sources/raster_source.dart @@ -6,6 +6,7 @@ part of 'source.dart'; final class RasterSource extends Source { /// The default constructor for a [RasterSource] object. const RasterSource({ + required super.id, this.url, this.tiles, this.bounds = const [-180, -85.051129, 180, 85.051129], diff --git a/lib/src/style/sources/source.dart b/lib/src/style/sources/source.dart index a266132c..65aaecda 100644 --- a/lib/src/style/sources/source.dart +++ b/lib/src/style/sources/source.dart @@ -11,7 +11,10 @@ part 'video_source.dart'; /// /// https://maplibre.org/maplibre-style-spec/sources sealed class Source { - const Source(); + const Source({required this.id}); + + /// The id of the source. + final String id; } /// Influences the y direction of the tile coordinates. diff --git a/lib/src/style/sources/vector_source.dart b/lib/src/style/sources/vector_source.dart index a5675448..ef831dec 100644 --- a/lib/src/style/sources/vector_source.dart +++ b/lib/src/style/sources/vector_source.dart @@ -9,6 +9,7 @@ part of 'source.dart'; final class VectorSource extends Source { /// The default constructor for a [VectorSource] object. const VectorSource({ + required super.id, this.url, this.tiles, this.bounds = const [-180, -85.051129, 180, 85.051129], @@ -17,6 +18,7 @@ final class VectorSource extends Source { this.maxZoom = 2, this.attribution, this.volatile = false, + this.sourceLayer, }); /// A URL to a TileJSON resource. Supported protocols are `http:` and @@ -59,4 +61,8 @@ final class VectorSource extends Source { /// /// Defaults to false. Not available on web. final bool volatile; + + /// Layer to use from a vector tile source. Required for vector tile sources; + /// prohibited for all other source types, including GeoJSON sources. + final String? sourceLayer; } diff --git a/lib/src/style/sources/video_source.dart b/lib/src/style/sources/video_source.dart index 4b4d10df..da0ad7d9 100644 --- a/lib/src/style/sources/video_source.dart +++ b/lib/src/style/sources/video_source.dart @@ -19,14 +19,11 @@ part of 'source.dart'; final class VideoSource extends Source { /// The default constructor for a [VideoSource] object. const VideoSource({ - required this.id, + required super.id, required this.urls, required this.coordinates, }); - /// The id of the [VideoSource]. - final String id; - /// URLs to video content in order of preferred format. final List urls; diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index d382bd45..35a934b8 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -16,7 +16,7 @@ extension type Map._(Camera _) implements Camera { external void addSource(String id, SourceSpecification source); /// https://github.com/maplibre/maplibre-gl-js/blob/41e5b32f5bd6264cbc4a8b38210ec6a410152259/src/ui/map.ts#L2412 - external void addLayer(AddLayerObject layer, [String? beforeId]); + external void addLayer(LayerSpecification layer, [String? beforeId]); /// Convert a coordinate to a screen location. /// @@ -121,7 +121,7 @@ extension type LngLatBounds._(JSObject _) implements JSObject { @JS() extension type FitBoundsOptions._(JSObject _) implements JSObject { /// Create a new JS [FitBoundsOptions] object. - external factory FitBoundsOptions({ + external FitBoundsOptions({ bool? linear, // TODO Offset? offset, num? maxZoom, @@ -134,7 +134,7 @@ extension type FitBoundsOptions._(JSObject _) implements JSObject { @JS() extension type SourceSpecification._(JSObject _) implements JSObject { /// The default constructor for a [SourceSpecification]. - external factory SourceSpecification({required String type}); + external SourceSpecification({required String type}); /// Create a new GeoJSON source. external factory SourceSpecification.geoJson({ @@ -144,16 +144,41 @@ extension type SourceSpecification._(JSObject _) implements JSObject { String? attribution, num? buffer, }); + + /// Create a new raster DEM source. + external factory SourceSpecification.rasterDem({ + required String type, + }); + + /// Create a new raster source. + external factory SourceSpecification.raster({ + required String type, + }); + + /// Create a new vector source. + external factory SourceSpecification.vector({ + required String type, + }); + + /// Create a new image source. + external factory SourceSpecification.image({ + required String type, + }); + + /// Create a new video source. + external factory SourceSpecification.video({ + required String type, + }); } /// The specifications of map layers. @anonymous @JS() -extension type AddLayerObject._(JSObject _) implements JSObject { - /// The default constructor for a [AddLayerObject]. - external factory AddLayerObject({ +extension type LayerSpecification._(JSObject _) implements JSObject { + /// The default constructor for a [LayerSpecification]. + external LayerSpecification({ required String id, required String type, - required String source, + required String? source, }); } diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 677fa6f8..c5167871 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -262,27 +262,45 @@ final class MapLibreMapStateWeb extends State final data = parse(source.data); _map.addSource( source.id, - interop.SourceSpecification.geoJson(type: 'geojson', data: data), + interop.SourceSpecification.geoJson( + type: 'geojson', + data: data, + ), ); case RasterDemSource(): - // TODO: Handle this case. + _map.addSource( + source.id, + interop.SourceSpecification.rasterDem(type: 'raster-dem'), + ); case RasterSource(): - // TODO: Handle this case. + _map.addSource( + source.id, + interop.SourceSpecification.raster(type: 'raster'), + ); case VectorSource(): - // TODO: Handle this case. + _map.addSource( + source.id, + interop.SourceSpecification.vector(type: 'vector'), + ); case ImageSource(): - // TODO: Handle this case. + _map.addSource( + source.id, + interop.SourceSpecification.image(type: 'image'), + ); case VideoSource(): - // TODO: Handle this case. + _map.addSource( + source.id, + interop.SourceSpecification.video(type: 'video'), + ); } } @override - Future addLayer(Layer layer) async { + Future addLayer(Layer layer, {String? beforeId}) async { switch (layer) { case FillLayer(): _map.addLayer( - interop.AddLayerObject( + interop.LayerSpecification( id: layer.id, type: 'fill', source: layer.sourceId, @@ -290,33 +308,68 @@ final class MapLibreMapStateWeb extends State ); case CircleLayer(): _map.addLayer( - interop.AddLayerObject( + interop.LayerSpecification( id: layer.id, type: 'circle', source: layer.sourceId, ), ); case BackgroundLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'background', + source: null, + ), + ); case FillExtrusionLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'fill-extrusion', + source: layer.sourceId, + ), + ); case HeatmapLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'heatmap', + source: layer.sourceId, + ), + ); case HillshadeLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'hillshade', + source: layer.sourceId, + ), + ); case LineLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'line', + source: layer.sourceId, + ), + ); case RasterLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'raster', + source: layer.sourceId, + ), + ); case SymbolLayer(): - // TODO: Handle this case. - throw UnimplementedError(); + _map.addLayer( + interop.LayerSpecification( + id: layer.id, + type: 'symbol', + source: layer.sourceId, + ), + ); } } From 360b6a3fad0d59bf7639985537932d9f8451a03c Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 00:29:52 +0200 Subject: [PATCH 04/24] working geojson example on web --- example/assets/geojson/cities.json | 21 ++ example/assets/geojson/lake-constance.json | 278 ------------------ example/assets/geojson/path.json | 267 +++++++++++++++++ example/lib/annotations_page.dart | 54 +++- example/lib/main.dart | 2 +- example/lib/menu_page.dart | 4 +- lib/src/style/layers/background_layer.dart | 2 + lib/src/style/layers/circle_layer.dart | 2 + .../style/layers/fill_extrusion_layer.dart | 2 + lib/src/style/layers/fill_layer.dart | 2 + lib/src/style/layers/heatmap_layer.dart | 2 + lib/src/style/layers/hillshade_layer.dart | 2 + lib/src/style/layers/layer.dart | 12 +- lib/src/style/layers/line_layer.dart | 4 +- lib/src/style/layers/raster_layer.dart | 2 + lib/src/style/layers/symbol_layer.dart | 2 + lib/src/web/interop/annotations.dart | 2 +- lib/src/web/interop/events.dart | 2 +- lib/src/web/interop/map.dart | 10 +- lib/src/web/widget_state.dart | 22 +- 20 files changed, 385 insertions(+), 309 deletions(-) create mode 100644 example/assets/geojson/cities.json create mode 100644 example/assets/geojson/path.json diff --git a/example/assets/geojson/cities.json b/example/assets/geojson/cities.json new file mode 100644 index 00000000..0cc8e145 --- /dev/null +++ b/example/assets/geojson/cities.json @@ -0,0 +1,21 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "marker-color": "#44ff00", + "marker-size": "medium", + "marker-symbol": "circle" + }, + "geometry": { + "coordinates": [ + 9.612023924867714, + 47.78123442179836 + ], + "type": "Point" + }, + "id": 0 + } + ] +} \ No newline at end of file diff --git a/example/assets/geojson/lake-constance.json b/example/assets/geojson/lake-constance.json index 456605d4..303fb57c 100644 --- a/example/assets/geojson/lake-constance.json +++ b/example/assets/geojson/lake-constance.json @@ -1792,284 +1792,6 @@ ] }, "id": 1 - }, - { - "type": "Feature", - "properties": { - "marker-color": "#44ff00", - "marker-size": "medium", - "marker-symbol": "circle" - }, - "geometry": { - "coordinates": [ - 9.612023924867714, - 47.78123442179836 - ], - "type": "Point" - }, - "id": 2 - }, - { - "type": "Feature", - "properties": { - "stroke": "#ff0000", - "stroke-width": 2, - "stroke-opacity": 1 - }, - "geometry": { - "coordinates": [ - [ - 8.799117107928566, - 47.98031816347611 - ], - [ - 8.802328819792677, - 47.98076582463398 - ], - [ - 8.817904468759707, - 47.97745570014669 - ], - [ - 8.826390707612575, - 47.97244912896508 - ], - [ - 8.84188371730258, - 47.971915035837725 - ], - [ - 8.85029608449463, - 47.967779690393144 - ], - [ - 8.852578427361692, - 47.96088225610791 - ], - [ - 8.85972977956527, - 47.95763666134866 - ], - [ - 8.860756091700068, - 47.95321071446159 - ], - [ - 8.862281911076224, - 47.95161027803556 - ], - [ - 8.864992467984365, - 47.95072764504209 - ], - [ - 8.87241161716912, - 47.951133910812075 - ], - [ - 8.88036168488702, - 47.95072393821974 - ], - [ - 8.883852331924714, - 47.94927687485284 - ], - [ - 8.889116318020058, - 47.94979644093698 - ], - [ - 8.894212150334823, - 47.949760113191275 - ], - [ - 8.89686922826536, - 47.95042881837165 - ], - [ - 8.90097357323745, - 47.95235725855733 - ], - [ - 8.903401026366964, - 47.95333512052477 - ], - [ - 8.90853424918015, - 47.95436653075481 - ], - [ - 8.912984319885538, - 47.955741250130984 - ], - [ - 8.920632002647665, - 47.95948483507931 - ], - [ - 8.93128560533225, - 47.962891797978045 - ], - [ - 8.942141808964891, - 47.964834314637955 - ], - [ - 8.945351040880723, - 47.96607579837854 - ], - [ - 8.953740994906042, - 47.97431440467997 - ], - [ - 8.955183655954187, - 47.97556187853948 - ], - [ - 8.980001942528048, - 47.9835245361206 - ], - [ - 8.985014566204484, - 47.98624681282624 - ], - [ - 8.992431562288289, - 47.98675079034763 - ], - [ - 8.998457236384041, - 47.988285180762944 - ], - [ - 9.002950586623086, - 47.98723448417749 - ], - [ - 9.007456726238615, - 47.98807598531127 - ], - [ - 9.018791023659105, - 47.988268233444416 - ], - [ - 9.025941096772556, - 47.98607812509849 - ], - [ - 9.032167710890548, - 47.98565116348948 - ], - [ - 9.0425847424045, - 47.98398600752353 - ], - [ - 9.047255542069024, - 47.98325347250184 - ], - [ - 9.068694613567288, - 47.986853029526 - ], - [ - 9.079932652188717, - 47.99091871503305 - ], - [ - 9.08337858941482, - 47.99331600728851 - ], - [ - 9.086502553152542, - 47.99655061510569 - ], - [ - 9.100070457331725, - 48.00056940419924 - ], - [ - 9.112663861277838, - 48.004626463075624 - ], - [ - 9.116716325761303, - 48.00401905221722 - ], - [ - 9.118981849700475, - 47.998880528914185 - ], - [ - 9.12078212120079, - 47.99632053346093 - ], - [ - 9.145500430251786, - 47.99980913370595 - ], - [ - 9.158384208371189, - 48.004602101069565 - ], - [ - 9.175291790464513, - 48.0009797534496 - ], - [ - 9.190364345811616, - 48.00203873237297 - ], - [ - 9.198439358447331, - 48.00520875178674 - ], - [ - 9.202555904172954, - 48.00880720120335 - ], - [ - 9.207477631885041, - 48.00843946025233 - ], - [ - 9.219795657188257, - 48.01376252258876 - ], - [ - 9.232358074932307, - 48.01352132221842 - ], - [ - 9.239203031974398, - 48.01882104696671 - ], - [ - 9.249607388831635, - 48.01847383078007 - ], - [ - 9.248516081925175, - 48.03109776319255 - ], - [ - 9.23729166283212, - 48.045756481204506 - ], - [ - 9.222818584686621, - 48.0684021146711 - ], - [ - 9.207442853196198, - 48.07521325271787 - ] - ], - "type": "LineString" - }, - "id": 3 } ] } \ No newline at end of file diff --git a/example/assets/geojson/path.json b/example/assets/geojson/path.json new file mode 100644 index 00000000..0711003c --- /dev/null +++ b/example/assets/geojson/path.json @@ -0,0 +1,267 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { + "stroke": "#ff0000", + "stroke-width": 2, + "stroke-opacity": 1 + }, + "geometry": { + "coordinates": [ + [ + 8.799117107928566, + 47.98031816347611 + ], + [ + 8.802328819792677, + 47.98076582463398 + ], + [ + 8.817904468759707, + 47.97745570014669 + ], + [ + 8.826390707612575, + 47.97244912896508 + ], + [ + 8.84188371730258, + 47.971915035837725 + ], + [ + 8.85029608449463, + 47.967779690393144 + ], + [ + 8.852578427361692, + 47.96088225610791 + ], + [ + 8.85972977956527, + 47.95763666134866 + ], + [ + 8.860756091700068, + 47.95321071446159 + ], + [ + 8.862281911076224, + 47.95161027803556 + ], + [ + 8.864992467984365, + 47.95072764504209 + ], + [ + 8.87241161716912, + 47.951133910812075 + ], + [ + 8.88036168488702, + 47.95072393821974 + ], + [ + 8.883852331924714, + 47.94927687485284 + ], + [ + 8.889116318020058, + 47.94979644093698 + ], + [ + 8.894212150334823, + 47.949760113191275 + ], + [ + 8.89686922826536, + 47.95042881837165 + ], + [ + 8.90097357323745, + 47.95235725855733 + ], + [ + 8.903401026366964, + 47.95333512052477 + ], + [ + 8.90853424918015, + 47.95436653075481 + ], + [ + 8.912984319885538, + 47.955741250130984 + ], + [ + 8.920632002647665, + 47.95948483507931 + ], + [ + 8.93128560533225, + 47.962891797978045 + ], + [ + 8.942141808964891, + 47.964834314637955 + ], + [ + 8.945351040880723, + 47.96607579837854 + ], + [ + 8.953740994906042, + 47.97431440467997 + ], + [ + 8.955183655954187, + 47.97556187853948 + ], + [ + 8.980001942528048, + 47.9835245361206 + ], + [ + 8.985014566204484, + 47.98624681282624 + ], + [ + 8.992431562288289, + 47.98675079034763 + ], + [ + 8.998457236384041, + 47.988285180762944 + ], + [ + 9.002950586623086, + 47.98723448417749 + ], + [ + 9.007456726238615, + 47.98807598531127 + ], + [ + 9.018791023659105, + 47.988268233444416 + ], + [ + 9.025941096772556, + 47.98607812509849 + ], + [ + 9.032167710890548, + 47.98565116348948 + ], + [ + 9.0425847424045, + 47.98398600752353 + ], + [ + 9.047255542069024, + 47.98325347250184 + ], + [ + 9.068694613567288, + 47.986853029526 + ], + [ + 9.079932652188717, + 47.99091871503305 + ], + [ + 9.08337858941482, + 47.99331600728851 + ], + [ + 9.086502553152542, + 47.99655061510569 + ], + [ + 9.100070457331725, + 48.00056940419924 + ], + [ + 9.112663861277838, + 48.004626463075624 + ], + [ + 9.116716325761303, + 48.00401905221722 + ], + [ + 9.118981849700475, + 47.998880528914185 + ], + [ + 9.12078212120079, + 47.99632053346093 + ], + [ + 9.145500430251786, + 47.99980913370595 + ], + [ + 9.158384208371189, + 48.004602101069565 + ], + [ + 9.175291790464513, + 48.0009797534496 + ], + [ + 9.190364345811616, + 48.00203873237297 + ], + [ + 9.198439358447331, + 48.00520875178674 + ], + [ + 9.202555904172954, + 48.00880720120335 + ], + [ + 9.207477631885041, + 48.00843946025233 + ], + [ + 9.219795657188257, + 48.01376252258876 + ], + [ + 9.232358074932307, + 48.01352132221842 + ], + [ + 9.239203031974398, + 48.01882104696671 + ], + [ + 9.249607388831635, + 48.01847383078007 + ], + [ + 9.248516081925175, + 48.03109776319255 + ], + [ + 9.23729166283212, + 48.045756481204506 + ], + [ + 9.222818584686621, + 48.0684021146711 + ], + [ + 9.207442853196198, + 48.07521325271787 + ] + ], + "type": "LineString" + }, + "id": 0 + } + ] +} \ No newline at end of file diff --git a/example/lib/annotations_page.dart b/example/lib/annotations_page.dart index 86843d7e..f2923d94 100644 --- a/example/lib/annotations_page.dart +++ b/example/lib/annotations_page.dart @@ -4,22 +4,22 @@ import 'package:flutter/services.dart'; import 'package:maplibre/maplibre.dart'; @immutable -class AnnotationsPage extends StatefulWidget { - const AnnotationsPage({super.key}); +class GeoJsonPage extends StatefulWidget { + const GeoJsonPage({super.key}); - static const location = '/annotations'; + static const location = '/geojson'; @override - State createState() => _AnnotationsPageState(); + State createState() => _GeoJsonPageState(); } -class _AnnotationsPageState extends State { +class _GeoJsonPageState extends State { late final MapController _controller; @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Annotations')), + appBar: AppBar(title: const Text('GeoJSON')), body: MapLibreMap( options: MapOptions(zoom: 7, center: Position(9.17, 47.68)), onMapCreated: (controller) => _controller = controller, @@ -27,22 +27,50 @@ class _AnnotationsPageState extends State { if (kIsWeb) { // This kind of Marker is only supported on web final _ = await _controller.addMarker( - Marker(point: Position(9.17, 47.68)), + Marker(point: Position(9, 47)), ); } - final geojson = await rootBundle - .loadString('assets/geojson/lake-constance.json'); + + // show Polygon as fill layer + final geojsonPolygon = + await rootBundle.loadString('assets/geojson/lake-constance.json'); await _controller.addSource( - GeoJsonSource(id: 'LakeConstance', data: geojson), + GeoJsonSource(id: 'LakeConstance', data: geojsonPolygon), ); await _controller.addLayer( - const FillLayer(id: 'geojson-fill', sourceId: 'LakeConstance'), + const FillLayer( + id: 'geojson-fill', + sourceId: 'LakeConstance', + paint: {'fill-color': '#00F'}, + ), + ); + + // show LineString as line layer + final geojsonLine = + await rootBundle.loadString('assets/geojson/path.json'); + await _controller.addSource( + GeoJsonSource(id: 'Path', data: geojsonLine), ); await _controller.addLayer( - const LineLayer(id: 'geojson-line', sourceId: 'LakeConstance'), + const LineLayer( + id: 'geojson-line', + sourceId: 'Path', + paint: {'line-color': '#F00'}, + ), + ); + + // show Point as circle layer + final geojsonPoints = + await rootBundle.loadString('assets/geojson/cities.json'); + await _controller.addSource( + GeoJsonSource(id: 'Cities', data: geojsonPoints), ); await _controller.addLayer( - const SymbolLayer(id: 'geojson-symbol', sourceId: 'LakeConstance'), + const CircleLayer( + id: 'geojson-circle', + sourceId: 'Cities', + paint: {'circle-color': '#0F0', 'circle-radius': 20}, + ), ); }, ), diff --git a/example/lib/main.dart b/example/lib/main.dart index 7ba170fb..b3f4e9f3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget { KioskPage.location: (context) => const KioskPage(), StyledMapPage.location: (context) => const StyledMapPage(), WebControlsPage.location: (context) => const WebControlsPage(), - AnnotationsPage.location: (context) => const AnnotationsPage(), + GeoJsonPage.location: (context) => const GeoJsonPage(), CallbacksPage.location: (context) => const CallbacksPage(), ControllerPage.location: (context) => const ControllerPage(), TwoMapsPage.location: (context) => const TwoMapsPage(), diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 5cc0890e..558a2543 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -26,9 +26,9 @@ class MenuPage extends StatelessWidget { location: StyledMapPage.location, ), ItemCard( - label: 'Annotations', + label: 'GeoJSON', iconData: Icons.location_on, - location: AnnotationsPage.location, + location: GeoJsonPage.location, ), ItemCard( label: 'Callbacks', diff --git a/lib/src/style/layers/background_layer.dart b/lib/src/style/layers/background_layer.dart index 75dfa069..8ec137f2 100644 --- a/lib/src/style/layers/background_layer.dart +++ b/lib/src/style/layers/background_layer.dart @@ -8,6 +8,8 @@ final class BackgroundLayer extends Layer { this.visible = true, this.color = const Color(0x00000000), this.opacity = 1, + super.layout, + super.paint, }); /// Whether this layer is displayed. diff --git a/lib/src/style/layers/circle_layer.dart b/lib/src/style/layers/circle_layer.dart index e1c7769b..52216c01 100644 --- a/lib/src/style/layers/circle_layer.dart +++ b/lib/src/style/layers/circle_layer.dart @@ -8,6 +8,8 @@ final class CircleLayer extends LayerWithSource { const CircleLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/style/layers/fill_extrusion_layer.dart b/lib/src/style/layers/fill_extrusion_layer.dart index fa567ca9..8c2d3561 100644 --- a/lib/src/style/layers/fill_extrusion_layer.dart +++ b/lib/src/style/layers/fill_extrusion_layer.dart @@ -8,6 +8,8 @@ final class FillExtrusionLayer extends LayerWithSource { const FillExtrusionLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/style/layers/fill_layer.dart b/lib/src/style/layers/fill_layer.dart index 4df31190..961ff72c 100644 --- a/lib/src/style/layers/fill_layer.dart +++ b/lib/src/style/layers/fill_layer.dart @@ -8,6 +8,8 @@ final class FillLayer extends LayerWithSource { const FillLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties } diff --git a/lib/src/style/layers/heatmap_layer.dart b/lib/src/style/layers/heatmap_layer.dart index 0251650d..343120e0 100644 --- a/lib/src/style/layers/heatmap_layer.dart +++ b/lib/src/style/layers/heatmap_layer.dart @@ -8,6 +8,8 @@ final class HeatmapLayer extends LayerWithSource { const HeatmapLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/style/layers/hillshade_layer.dart b/lib/src/style/layers/hillshade_layer.dart index 65e8a5ff..116985f4 100644 --- a/lib/src/style/layers/hillshade_layer.dart +++ b/lib/src/style/layers/hillshade_layer.dart @@ -8,6 +8,8 @@ final class HillshadeLayer extends LayerWithSource { const HillshadeLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/style/layers/layer.dart b/lib/src/style/layers/layer.dart index 671fe64e..cd4e383e 100644 --- a/lib/src/style/layers/layer.dart +++ b/lib/src/style/layers/layer.dart @@ -16,12 +16,12 @@ part 'symbol_layer.dart'; sealed class Layer { const Layer({ required this.id, + this.layout = const {}, + this.paint = const {}, this.metadata, this.minZoom, this.maxZoom, - this.paint, this.filter, - this.layout, }); /// Unique layer name. @@ -51,10 +51,10 @@ sealed class Layer { final Object? filter; /// Layout properties for the layer. - final Object? layout; + final Map layout; /// Default paint properties for this layer. - final Object? paint; + final Map paint; } /// A [Layer] that pulls its data from a [Source]. Basically every layer @@ -64,12 +64,12 @@ sealed class LayerWithSource extends Layer { const LayerWithSource({ required super.id, required this.sourceId, + super.paint = const {}, + super.layout = const {}, super.metadata, super.minZoom, super.maxZoom, - super.paint, super.filter, - super.layout, }); /// Name of a source description to be used for this layer. Required for all diff --git a/lib/src/style/layers/line_layer.dart b/lib/src/style/layers/line_layer.dart index 8a3fccc5..87b7add9 100644 --- a/lib/src/style/layers/line_layer.dart +++ b/lib/src/style/layers/line_layer.dart @@ -8,7 +8,9 @@ final class LineLayer extends LayerWithSource { const LineLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); - // TODO add properties +// TODO add properties } diff --git a/lib/src/style/layers/raster_layer.dart b/lib/src/style/layers/raster_layer.dart index b91a52a3..534a60bf 100644 --- a/lib/src/style/layers/raster_layer.dart +++ b/lib/src/style/layers/raster_layer.dart @@ -8,6 +8,8 @@ final class RasterLayer extends LayerWithSource { const RasterLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/style/layers/symbol_layer.dart b/lib/src/style/layers/symbol_layer.dart index 620a7962..611899c9 100644 --- a/lib/src/style/layers/symbol_layer.dart +++ b/lib/src/style/layers/symbol_layer.dart @@ -8,6 +8,8 @@ final class SymbolLayer extends LayerWithSource { const SymbolLayer({ required super.id, required super.sourceId, + super.layout, + super.paint, }); // TODO add properties diff --git a/lib/src/web/interop/annotations.dart b/lib/src/web/interop/annotations.dart index 1e292525..12f2cc14 100644 --- a/lib/src/web/interop/annotations.dart +++ b/lib/src/web/interop/annotations.dart @@ -10,7 +10,7 @@ extension type Marker._(IControl _) implements IControl { external Marker setLngLat(LngLat lngLat); /// Add the marker to a MapLibre map. - external Marker addTo(Map map); + external Marker addTo(JsMap map); } /// The anonymous option class for a [Marker]. diff --git a/lib/src/web/interop/events.dart b/lib/src/web/interop/events.dart index 9c1ee5a7..7dce31fc 100644 --- a/lib/src/web/interop/events.dart +++ b/lib/src/web/interop/events.dart @@ -4,7 +4,7 @@ part of 'interop.dart'; @JS() extension type MapLibreEvent._(JSObject _) implements JSObject { - external Map target; + external JsMap target; external JSString type; external T? originalEvent; } diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index 35a934b8..31e79a86 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -1,10 +1,10 @@ part of 'interop.dart'; /// The JavaScript MapLibre Map object. -@JS() -extension type Map._(Camera _) implements Camera { +@JS('Map') +extension type JsMap._(Camera _) implements Camera { /// Create a new MapLibre map. - external Map(MapOptions options); + external JsMap(MapOptions options); /// Add a web-only control button to the map. external void addControl(IControl control); @@ -64,7 +64,7 @@ extension type Map._(Camera _) implements Camera { external LngLatBounds getBounds(); } -/// Anonymous MapOptions for the MapLibre JavaScript [Map]. +/// Anonymous MapOptions for the MapLibre JavaScript [JsMap]. @anonymous @JS() extension type MapOptions._(JSObject _) implements JSObject { @@ -180,5 +180,7 @@ extension type LayerSpecification._(JSObject _) implements JSObject { required String id, required String type, required String? source, + required JSAny layout, + required JSAny paint, }); } diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index c5167871..7c799841 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -17,7 +17,7 @@ final class MapLibreMapStateWeb extends State static int _counter = 0; final _viewName = 'plugins.flutter.io/maplibre${_counter++}'; late HTMLDivElement _htmlElement; - late interop.Map _map; + late interop.JsMap _map; Completer? _moveCompleter; MapOptions get _options => widget.options; @@ -33,7 +33,7 @@ final class MapLibreMapStateWeb extends State ..style.height = '100%' ..style.width = '100%'; - _map = interop.Map( + _map = interop.JsMap( interop.MapOptions( container: _htmlElement, style: _options.style, @@ -304,6 +304,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'fill', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case CircleLayer(): @@ -312,6 +314,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'circle', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case BackgroundLayer(): @@ -320,6 +324,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'background', source: null, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case FillExtrusionLayer(): @@ -328,6 +334,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'fill-extrusion', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case HeatmapLayer(): @@ -336,6 +344,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'heatmap', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case HillshadeLayer(): @@ -344,6 +354,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'hillshade', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case LineLayer(): @@ -352,6 +364,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'line', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case RasterLayer(): @@ -360,6 +374,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'raster', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); case SymbolLayer(): @@ -368,6 +384,8 @@ final class MapLibreMapStateWeb extends State id: layer.id, type: 'symbol', source: layer.sourceId, + layout: layer.layout.jsify()!, + paint: layer.paint.jsify()!, ), ); } From 04cc6e62681229e99c9039d4b18a8c046000c7d5 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 01:11:29 +0200 Subject: [PATCH 05/24] native: addBackgroundLayer --- .../josxha/maplibre/MapLibreMapController.kt | 6 ++ .../com/github/josxha/maplibre/Pigeon.g.kt | 21 ++++++ ios/Classes/Pigeon.g.swift | 20 +++++ lib/src/native/pigeon.g.dart | 25 +++++++ lib/src/native/widget_state.dart | 5 +- linux/pigeon.g.cc | 74 +++++++++++++++++++ linux/pigeon.g.h | 20 +++++ macos/Classes/Pigeon.g.swift | 20 +++++ pigeons/pigeon.dart | 8 ++ windows/runner/pigeon.g.cpp | 29 ++++++++ windows/runner/pigeon.g.h | 4 + 11 files changed, 229 insertions(+), 3 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 60519a4d..d6a96cf3 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -23,6 +23,7 @@ import org.maplibre.android.maps.MapLibreMapOptions import org.maplibre.android.maps.MapView import org.maplibre.android.maps.OnMapReadyCallback import org.maplibre.android.maps.Style +import org.maplibre.android.style.layers.BackgroundLayer import org.maplibre.android.style.layers.CircleLayer import org.maplibre.android.style.layers.FillLayer import org.maplibre.android.style.sources.GeoJsonSource @@ -185,6 +186,11 @@ class MapLibreMapController( callback(Result.success(Unit)) } + override fun addBackgroundLayer(id: String, callback: (Result) -> Unit) { + mapLibreMap.style?.addLayer(BackgroundLayer(id)) + callback(Result.success(Unit)) + } + override fun addGeoJsonSource( id: String, data: String, diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt index 12ea0066..6a4eb1c1 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt @@ -288,6 +288,8 @@ interface MapLibreHostApi { fun addFillLayer(id: String, sourceId: String, callback: (Result) -> Unit) /** Add a circle layer to the map style. */ fun addCircleLayer(id: String, sourceId: String, callback: (Result) -> Unit) + /** Add a background layer to the map style. */ + fun addBackgroundLayer(id: String, callback: (Result) -> Unit) /** Add a GeoJSON source to the map style. */ fun addGeoJsonSource(id: String, data: String, callback: (Result) -> Unit) /** @@ -468,6 +470,25 @@ interface MapLibreHostApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + api.addBackgroundLayer(idArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/ios/Classes/Pigeon.g.swift b/ios/Classes/Pigeon.g.swift index 3f0028de..0e814e7f 100644 --- a/ios/Classes/Pigeon.g.swift +++ b/ios/Classes/Pigeon.g.swift @@ -326,6 +326,8 @@ protocol MapLibreHostApi { func addFillLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) /// Add a circle layer to the map style. func addCircleLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + /// Add a background layer to the map style. + func addBackgroundLayer(id: String, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and @@ -491,6 +493,24 @@ class MapLibreHostApiSetup { } else { addCircleLayerChannel.setMessageHandler(nil) } + /// Add a background layer to the map style. + let addBackgroundLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addBackgroundLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.addBackgroundLayer(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addBackgroundLayerChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/lib/src/native/pigeon.g.dart b/lib/src/native/pigeon.g.dart index 0e1e27e7..61ba6e05 100644 --- a/lib/src/native/pigeon.g.dart +++ b/lib/src/native/pigeon.g.dart @@ -513,6 +513,31 @@ class MapLibreHostApi { } } + /// Add a background layer to the map style. + Future addBackgroundLayer({required String id}) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([id]) 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 { + return; + } + } + /// Add a GeoJSON source to the map style. Future addGeoJsonSource( {required String id, required String data}) async { diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index 4aed4ac0..0ba17553 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -21,7 +21,7 @@ final class MapLibreMapStateNative extends State // Platform Views are rendered into a texture. Flutter draws the // platform views (via the texture). Flutter content is rendered // directly into a Surface. - // + good performance for Android Views + // + good performance for Android Views // + best performance for Flutter rendering. // + all transformations work correctly. // - quick scrolling (e.g. a web view) will be janky @@ -131,8 +131,7 @@ final class MapLibreMapStateNative extends State _hostApi.addFillLayer(id: layer.id, sourceId: layer.sourceId), CircleLayer() => _hostApi.addCircleLayer(id: layer.id, sourceId: layer.sourceId), - // TODO: Handle this case. - BackgroundLayer() => throw UnimplementedError(), + BackgroundLayer() => _hostApi.addBackgroundLayer(id: layer.id), // TODO: Handle this case. FillExtrusionLayer() => throw UnimplementedError(), // TODO: Handle this case. diff --git a/linux/pigeon.g.cc b/linux/pigeon.g.cc index c9b2c8b5..a28f5640 100644 --- a/linux/pigeon.g.cc +++ b/linux/pigeon.g.cc @@ -876,6 +876,45 @@ static MaplibreMapLibreHostApiAddCircleLayerResponse* maplibre_map_libre_host_ap return self; } +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddBackgroundLayerResponse, maplibre_map_libre_host_api_add_background_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_BACKGROUND_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddBackgroundLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddBackgroundLayerResponse, maplibre_map_libre_host_api_add_background_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_background_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddBackgroundLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_BACKGROUND_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_background_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_background_layer_response_init(MaplibreMapLibreHostApiAddBackgroundLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_background_layer_response_class_init(MaplibreMapLibreHostApiAddBackgroundLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_background_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddBackgroundLayerResponse* maplibre_map_libre_host_api_add_background_layer_response_new() { + MaplibreMapLibreHostApiAddBackgroundLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_BACKGROUND_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_background_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddBackgroundLayerResponse* maplibre_map_libre_host_api_add_background_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddBackgroundLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_BACKGROUND_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_background_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddGeoJsonSourceResponse, maplibre_map_libre_host_api_add_geo_json_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_GEO_JSON_SOURCE_RESPONSE, GObject) struct _MaplibreMapLibreHostApiAddGeoJsonSourceResponse { @@ -1140,6 +1179,19 @@ static void maplibre_map_libre_host_api_add_circle_layer_cb(FlBasicMessageChanne self->vtable->add_circle_layer(id, source_id, handle, self->user_data); } +static void maplibre_map_libre_host_api_add_background_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_background_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_background_layer(id, handle, self->user_data); +} + static void maplibre_map_libre_host_api_add_geo_json_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); @@ -1205,6 +1257,9 @@ void maplibre_map_libre_host_api_set_method_handlers(FlBinaryMessenger* messenge g_autofree gchar* add_circle_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addCircleLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_circle_layer_channel = fl_basic_message_channel_new(messenger, add_circle_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_circle_layer_channel, maplibre_map_libre_host_api_add_circle_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_background_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_background_layer_channel = fl_basic_message_channel_new(messenger, add_background_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_background_layer_channel, maplibre_map_libre_host_api_add_background_layer_cb, g_object_ref(api_data), g_object_unref); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, maplibre_map_libre_host_api_add_geo_json_source_cb, g_object_ref(api_data), g_object_unref); @@ -1241,6 +1296,9 @@ void maplibre_map_libre_host_api_clear_method_handlers(FlBinaryMessenger* messen g_autofree gchar* add_circle_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addCircleLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_circle_layer_channel = fl_basic_message_channel_new(messenger, add_circle_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_circle_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_background_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_background_layer_channel = fl_basic_message_channel_new(messenger, add_background_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_background_layer_channel, nullptr, nullptr, nullptr); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, nullptr, nullptr, nullptr); @@ -1377,6 +1435,22 @@ void maplibre_map_libre_host_api_respond_error_add_circle_layer(MaplibreMapLibre } } +void maplibre_map_libre_host_api_respond_add_background_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddBackgroundLayerResponse) response = maplibre_map_libre_host_api_add_background_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addBackgroundLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_background_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddBackgroundLayerResponse) response = maplibre_map_libre_host_api_add_background_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addBackgroundLayer", error->message); + } +} + void maplibre_map_libre_host_api_respond_add_geo_json_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { g_autoptr(MaplibreMapLibreHostApiAddGeoJsonSourceResponse) response = maplibre_map_libre_host_api_add_geo_json_source_response_new(); g_autoptr(GError) error = nullptr; diff --git a/linux/pigeon.g.h b/linux/pigeon.g.h index 59f343eb..98246905 100644 --- a/linux/pigeon.g.h +++ b/linux/pigeon.g.h @@ -341,6 +341,7 @@ typedef struct { void (*to_lng_lat)(double x, double y, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_fill_layer)(const gchar* id, const gchar* source_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_circle_layer)(const gchar* id, const gchar* source_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_background_layer)(const gchar* id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_geo_json_source)(const gchar* id, const gchar* data, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); MaplibreMapLibreHostApiGetMetersPerPixelAtLatitudeResponse* (*get_meters_per_pixel_at_latitude)(double latitude, gpointer user_data); } MaplibreMapLibreHostApiVTable; @@ -524,6 +525,25 @@ void maplibre_map_libre_host_api_respond_add_circle_layer(MaplibreMapLibreHostAp */ void maplibre_map_libre_host_api_respond_error_add_circle_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); +/** + * maplibre_map_libre_host_api_respond_add_background_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addBackgroundLayer. + */ +void maplibre_map_libre_host_api_respond_add_background_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_background_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addBackgroundLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_background_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + /** * maplibre_map_libre_host_api_respond_add_geo_json_source: * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. diff --git a/macos/Classes/Pigeon.g.swift b/macos/Classes/Pigeon.g.swift index 3f0028de..0e814e7f 100644 --- a/macos/Classes/Pigeon.g.swift +++ b/macos/Classes/Pigeon.g.swift @@ -326,6 +326,8 @@ protocol MapLibreHostApi { func addFillLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) /// Add a circle layer to the map style. func addCircleLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + /// Add a background layer to the map style. + func addBackgroundLayer(id: String, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and @@ -491,6 +493,24 @@ class MapLibreHostApiSetup { } else { addCircleLayerChannel.setMessageHandler(nil) } + /// Add a background layer to the map style. + let addBackgroundLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addBackgroundLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.addBackgroundLayer(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addBackgroundLayerChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index 8bbe7a50..62bab4cf 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -67,6 +67,14 @@ abstract interface class MapLibreHostApi { @async void addCircleLayer({required String id, required String sourceId}); + /// Add a background layer to the map style. + @async + void addBackgroundLayer({ + required String id, + Map layout, + Map paint, + }); + /// Add a GeoJSON source to the map style. @async void addGeoJsonSource({ diff --git a/windows/runner/pigeon.g.cpp b/windows/runner/pigeon.g.cpp index 9cb7609e..6ebcfb5a 100644 --- a/windows/runner/pigeon.g.cpp +++ b/windows/runner/pigeon.g.cpp @@ -734,6 +734,35 @@ void MapLibreHostApi::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + api->AddBackgroundLayer(id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource" + prepended_suffix, &GetCodec()); if (api != nullptr) { diff --git a/windows/runner/pigeon.g.h b/windows/runner/pigeon.g.h index 9080da00..c3384860 100644 --- a/windows/runner/pigeon.g.h +++ b/windows/runner/pigeon.g.h @@ -346,6 +346,10 @@ class MapLibreHostApi { const std::string& id, const std::string& source_id, std::function reply)> result) = 0; + // Add a background layer to the map style. + virtual void AddBackgroundLayer( + const std::string& id, + std::function reply)> result) = 0; // Add a GeoJSON source to the map style. virtual void AddGeoJsonSource( const std::string& id, From 3140b0b8d0fb926694b9fc30a69da4b509f57865 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 01:20:38 +0200 Subject: [PATCH 06/24] make use of beforeId on web --- lib/src/web/widget_state.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 7c799841..cbd27da6 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -307,6 +307,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case CircleLayer(): _map.addLayer( @@ -317,6 +318,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case BackgroundLayer(): _map.addLayer( @@ -327,6 +329,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case FillExtrusionLayer(): _map.addLayer( @@ -337,6 +340,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case HeatmapLayer(): _map.addLayer( @@ -347,6 +351,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case HillshadeLayer(): _map.addLayer( @@ -357,6 +362,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case LineLayer(): _map.addLayer( @@ -367,6 +373,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case RasterLayer(): _map.addLayer( @@ -377,6 +384,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); case SymbolLayer(): _map.addLayer( @@ -387,6 +395,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), + beforeId, ); } } From d20eb32b4c73f6ea8cde45c826c981a4f7f0acc7 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 02:23:03 +0200 Subject: [PATCH 07/24] native: add layers --- .../josxha/maplibre/MapLibreMapController.kt | 192 ++++++- .../com/github/josxha/maplibre/Pigeon.g.kt | 171 +++++- ios/Classes/Pigeon.g.swift | 165 +++++- lib/src/map_controller.dart | 4 +- lib/src/native/pigeon.g.dart | 231 +++++++- lib/src/native/widget_state.dart | 81 ++- lib/src/style/layers/layer.dart | 4 +- lib/src/web/widget_state.dart | 20 +- linux/pigeon.g.cc | 516 +++++++++++++++++- linux/pigeon.g.h | 126 ++++- macos/Classes/Pigeon.g.swift | 165 +++++- pigeons/pigeon.dart | 81 ++- windows/runner/pigeon.g.cpp | 342 +++++++++++- windows/runner/pigeon.g.h | 57 ++ 14 files changed, 2062 insertions(+), 93 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index d6a96cf3..191c796c 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -25,7 +25,12 @@ import org.maplibre.android.maps.OnMapReadyCallback import org.maplibre.android.maps.Style import org.maplibre.android.style.layers.BackgroundLayer import org.maplibre.android.style.layers.CircleLayer +import org.maplibre.android.style.layers.FillExtrusionLayer import org.maplibre.android.style.layers.FillLayer +import org.maplibre.android.style.layers.HeatmapLayer +import org.maplibre.android.style.layers.HillshadeLayer +import org.maplibre.android.style.layers.LineLayer +import org.maplibre.android.style.layers.PropertyValue import org.maplibre.android.style.sources.GeoJsonSource import kotlin.coroutines.cancellation.CancellationException @@ -153,6 +158,174 @@ class MapLibreMapController( callback(Result.success(LngLat(latLng.longitude, latLng.latitude))) } + override fun addFillLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = FillLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addCircleLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = CircleLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addBackgroundLayer( + id: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = BackgroundLayer(id) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addFillExtrusionLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = FillExtrusionLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addHeatmapLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = HeatmapLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addHillshadeLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = HillshadeLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addLineLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + val layer = LineLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) + } + + override fun addRasterLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + TODO("Not yet implemented") + } + + override fun addSymbolLayer( + id: String, + sourceId: String, + layout: Map, + paint: Map, + belowLayerId: String?, + callback: (Result) -> Unit + ) { + TODO("Not yet implemented") + } + override fun getCamera(callback: (Result) -> Unit) { val position = mapLibreMap.cameraPosition val target = mapLibreMap.cameraPosition.target!! @@ -172,25 +345,6 @@ class MapLibreMapController( callback(Result.success(lngLatBounds)) } - override fun addFillLayer(id: String, sourceId: String, callback: (Result) -> Unit) { - mapLibreMap.style?.addLayer(FillLayer(id, sourceId)) - callback(Result.success(Unit)) - } - - override fun addCircleLayer( - id: String, - sourceId: String, - callback: (Result) -> Unit - ) { - mapLibreMap.style?.addLayer(CircleLayer(id, sourceId)) - callback(Result.success(Unit)) - } - - override fun addBackgroundLayer(id: String, callback: (Result) -> Unit) { - mapLibreMap.style?.addLayer(BackgroundLayer(id)) - callback(Result.success(Unit)) - } - override fun addGeoJsonSource( id: String, data: String, diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt index 6a4eb1c1..5efe9068 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt @@ -285,11 +285,23 @@ interface MapLibreHostApi { /** Convert a screen location to a coordinate. */ fun toLngLat(x: Double, y: Double, callback: (Result) -> Unit) /** Add a fill layer to the map style. */ - fun addFillLayer(id: String, sourceId: String, callback: (Result) -> Unit) + fun addFillLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) /** Add a circle layer to the map style. */ - fun addCircleLayer(id: String, sourceId: String, callback: (Result) -> Unit) + fun addCircleLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) /** Add a background layer to the map style. */ - fun addBackgroundLayer(id: String, callback: (Result) -> Unit) + fun addBackgroundLayer(id: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a fill extrusion layer to the map style. */ + fun addFillExtrusionLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a heatmap layer to the map style. */ + fun addHeatmapLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a hillshade layer to the map style. */ + fun addHillshadeLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a line layer to the map style. */ + fun addLineLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a raster layer to the map style. */ + fun addRasterLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Add a symbol layer to the map style. */ + fun addSymbolLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) /** Add a GeoJSON source to the map style. */ fun addGeoJsonSource(id: String, data: String, callback: (Result) -> Unit) /** @@ -437,7 +449,10 @@ interface MapLibreHostApi { val args = message as List val idArg = args[0] as String val sourceIdArg = args[1] as String - api.addFillLayer(idArg, sourceIdArg) { result: Result -> + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addFillLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -457,7 +472,10 @@ interface MapLibreHostApi { val args = message as List val idArg = args[0] as String val sourceIdArg = args[1] as String - api.addCircleLayer(idArg, sourceIdArg) { result: Result -> + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addCircleLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) @@ -476,7 +494,148 @@ interface MapLibreHostApi { channel.setMessageHandler { message, reply -> val args = message as List val idArg = args[0] as String - api.addBackgroundLayer(idArg) { result: Result -> + val layoutArg = args[1] as Map + val paintArg = args[2] as Map + val belowLayerIdArg = args[3] as String? + api.addBackgroundLayer(idArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addFillExtrusionLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addHeatmapLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addHillshadeLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addLineLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addRasterLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val sourceIdArg = args[1] as String + val layoutArg = args[2] as Map + val paintArg = args[3] as Map + val belowLayerIdArg = args[4] as String? + api.addSymbolLayer(idArg, sourceIdArg, layoutArg, paintArg, belowLayerIdArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(wrapError(error)) diff --git a/ios/Classes/Pigeon.g.swift b/ios/Classes/Pigeon.g.swift index 0e814e7f..d83ae957 100644 --- a/ios/Classes/Pigeon.g.swift +++ b/ios/Classes/Pigeon.g.swift @@ -323,11 +323,23 @@ protocol MapLibreHostApi { /// Convert a screen location to a coordinate. func toLngLat(x: Double, y: Double, completion: @escaping (Result) -> Void) /// Add a fill layer to the map style. - func addFillLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + func addFillLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a circle layer to the map style. - func addCircleLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + func addCircleLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a background layer to the map style. - func addBackgroundLayer(id: String, completion: @escaping (Result) -> Void) + func addBackgroundLayer(id: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a fill extrusion layer to the map style. + func addFillExtrusionLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a heatmap layer to the map style. + func addHeatmapLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a hillshade layer to the map style. + func addHillshadeLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a line layer to the map style. + func addLineLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a raster layer to the map style. + func addRasterLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a symbol layer to the map style. + func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and @@ -462,7 +474,10 @@ class MapLibreHostApiSetup { let args = message as! [Any?] let idArg = args[0] as! String let sourceIdArg = args[1] as! String - api.addFillLayer(id: idArg, sourceId: sourceIdArg) { result in + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addFillLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -481,7 +496,10 @@ class MapLibreHostApiSetup { let args = message as! [Any?] let idArg = args[0] as! String let sourceIdArg = args[1] as! String - api.addCircleLayer(id: idArg, sourceId: sourceIdArg) { result in + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addCircleLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -499,7 +517,10 @@ class MapLibreHostApiSetup { addBackgroundLayerChannel.setMessageHandler { message, reply in let args = message as! [Any?] let idArg = args[0] as! String - api.addBackgroundLayer(id: idArg) { result in + let layoutArg = args[1] as! [String: Any] + let paintArg = args[2] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[3]) + api.addBackgroundLayer(id: idArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -511,6 +532,138 @@ class MapLibreHostApiSetup { } else { addBackgroundLayerChannel.setMessageHandler(nil) } + /// Add a fill extrusion layer to the map style. + let addFillExtrusionLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addFillExtrusionLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addFillExtrusionLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addFillExtrusionLayerChannel.setMessageHandler(nil) + } + /// Add a heatmap layer to the map style. + let addHeatmapLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addHeatmapLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addHeatmapLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addHeatmapLayerChannel.setMessageHandler(nil) + } + /// Add a hillshade layer to the map style. + let addHillshadeLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addHillshadeLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addHillshadeLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addHillshadeLayerChannel.setMessageHandler(nil) + } + /// Add a line layer to the map style. + let addLineLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addLineLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addLineLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addLineLayerChannel.setMessageHandler(nil) + } + /// Add a raster layer to the map style. + let addRasterLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addRasterLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterLayerChannel.setMessageHandler(nil) + } + /// Add a symbol layer to the map style. + let addSymbolLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addSymbolLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addSymbolLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addSymbolLayerChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/lib/src/map_controller.dart b/lib/src/map_controller.dart index 24fe41da..a9b6342b 100644 --- a/lib/src/map_controller.dart +++ b/lib/src/map_controller.dart @@ -40,11 +40,11 @@ abstract interface class MapController { /// Add a new layer to the map. The source must be added before adding it to /// the map. /// - /// `beforeId` The ID of an existing layer to insert the new layer before, + /// `belowLayerId` The ID of an existing layer to insert the new layer before, /// resulting in the new layer appearing visually beneath the existing layer. /// If this argument is not specified, the layer will be appended to the end /// of the layers array and appear visually above all other layers. - Future addLayer(Layer layer, {String? beforeId}); + Future addLayer(Layer layer, {String? belowLayerId}); /// Get the current camera position on the map. Future getCamera(); diff --git a/lib/src/native/pigeon.g.dart b/lib/src/native/pigeon.g.dart index 61ba6e05..1320f5f8 100644 --- a/lib/src/native/pigeon.g.dart +++ b/lib/src/native/pigeon.g.dart @@ -462,8 +462,13 @@ class MapLibreHostApi { } /// Add a fill layer to the map style. - Future addFillLayer( - {required String id, required String sourceId}) async { + Future addFillLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillLayer$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = @@ -472,8 +477,9 @@ class MapLibreHostApi { pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([id, sourceId]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -488,8 +494,13 @@ class MapLibreHostApi { } /// Add a circle layer to the map style. - Future addCircleLayer( - {required String id, required String sourceId}) async { + Future addCircleLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addCircleLayer$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = @@ -498,8 +509,9 @@ class MapLibreHostApi { pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([id, sourceId]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -514,7 +526,12 @@ class MapLibreHostApi { } /// Add a background layer to the map style. - Future addBackgroundLayer({required String id}) async { + Future addBackgroundLayer({ + required String id, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { final String pigeonVar_channelName = 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer$pigeonVar_messageChannelSuffix'; final BasicMessageChannel pigeonVar_channel = @@ -523,8 +540,200 @@ class MapLibreHostApi { pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = - await pigeonVar_channel.send([id]) as List?; + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, layout, paint, belowLayerId]) 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 { + return; + } + } + + /// Add a fill extrusion layer to the map style. + Future addFillExtrusionLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + 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 { + return; + } + } + + /// Add a heatmap layer to the map style. + Future addHeatmapLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + 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 { + return; + } + } + + /// Add a hillshade layer to the map style. + Future addHillshadeLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + 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 { + return; + } + } + + /// Add a line layer to the map style. + Future addLineLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + 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 { + return; + } + } + + /// Add a raster layer to the map style. + Future addRasterLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + 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 { + return; + } + } + + /// Add a symbol layer to the map style. + Future addSymbolLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, sourceId, layout, paint, belowLayerId]) + as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index 0ba17553..64307828 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -125,25 +125,70 @@ final class MapLibreMapStateNative extends State ); @override - Future addLayer(Layer layer, {String? beforeId}) async { + Future addLayer(Layer layer, {String? belowLayerId}) async { await switch (layer) { - FillLayer() => - _hostApi.addFillLayer(id: layer.id, sourceId: layer.sourceId), - CircleLayer() => - _hostApi.addCircleLayer(id: layer.id, sourceId: layer.sourceId), - BackgroundLayer() => _hostApi.addBackgroundLayer(id: layer.id), - // TODO: Handle this case. - FillExtrusionLayer() => throw UnimplementedError(), - // TODO: Handle this case. - HeatmapLayer() => throw UnimplementedError(), - // TODO: Handle this case. - HillshadeLayer() => throw UnimplementedError(), - // TODO: Handle this case. - LineLayer() => throw UnimplementedError(), - // TODO: Handle this case. - RasterLayer() => throw UnimplementedError(), - // TODO: Handle this case. - SymbolLayer() => throw UnimplementedError(), + FillLayer() => _hostApi.addFillLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + CircleLayer() => _hostApi.addCircleLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + BackgroundLayer() => _hostApi.addBackgroundLayer( + id: layer.id, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + FillExtrusionLayer() => _hostApi.addFillExtrusionLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + HeatmapLayer() => _hostApi.addHeatmapLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + HillshadeLayer() => _hostApi.addHillshadeLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + LineLayer() => _hostApi.addLineLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + RasterLayer() => _hostApi.addRasterLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), + SymbolLayer() => _hostApi.addSymbolLayer( + id: layer.id, + sourceId: layer.sourceId, + belowLayerId: belowLayerId, + layout: layer.layout, + paint: layer.paint, + ), }; } diff --git a/lib/src/style/layers/layer.dart b/lib/src/style/layers/layer.dart index cd4e383e..18399580 100644 --- a/lib/src/style/layers/layer.dart +++ b/lib/src/style/layers/layer.dart @@ -51,10 +51,10 @@ sealed class Layer { final Object? filter; /// Layout properties for the layer. - final Map layout; + final Map layout; /// Default paint properties for this layer. - final Map paint; + final Map paint; } /// A [Layer] that pulls its data from a [Source]. Basically every layer diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index cbd27da6..1fecfa57 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -296,7 +296,7 @@ final class MapLibreMapStateWeb extends State } @override - Future addLayer(Layer layer, {String? beforeId}) async { + Future addLayer(Layer layer, {String? belowLayerId}) async { switch (layer) { case FillLayer(): _map.addLayer( @@ -307,7 +307,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case CircleLayer(): _map.addLayer( @@ -318,7 +318,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case BackgroundLayer(): _map.addLayer( @@ -329,7 +329,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case FillExtrusionLayer(): _map.addLayer( @@ -340,7 +340,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case HeatmapLayer(): _map.addLayer( @@ -351,7 +351,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case HillshadeLayer(): _map.addLayer( @@ -362,7 +362,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case LineLayer(): _map.addLayer( @@ -373,7 +373,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case RasterLayer(): _map.addLayer( @@ -384,7 +384,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); case SymbolLayer(): _map.addLayer( @@ -395,7 +395,7 @@ final class MapLibreMapStateWeb extends State layout: layer.layout.jsify()!, paint: layer.paint.jsify()!, ), - beforeId, + belowLayerId, ); } } diff --git a/linux/pigeon.g.cc b/linux/pigeon.g.cc index a28f5640..04fb37d2 100644 --- a/linux/pigeon.g.cc +++ b/linux/pigeon.g.cc @@ -915,6 +915,240 @@ static MaplibreMapLibreHostApiAddBackgroundLayerResponse* maplibre_map_libre_hos return self; } +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddFillExtrusionLayerResponse, maplibre_map_libre_host_api_add_fill_extrusion_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_FILL_EXTRUSION_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddFillExtrusionLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddFillExtrusionLayerResponse, maplibre_map_libre_host_api_add_fill_extrusion_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_fill_extrusion_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_FILL_EXTRUSION_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_fill_extrusion_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_fill_extrusion_layer_response_init(MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_fill_extrusion_layer_response_class_init(MaplibreMapLibreHostApiAddFillExtrusionLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_fill_extrusion_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* maplibre_map_libre_host_api_add_fill_extrusion_layer_response_new() { + MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_FILL_EXTRUSION_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_fill_extrusion_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* maplibre_map_libre_host_api_add_fill_extrusion_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddFillExtrusionLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_FILL_EXTRUSION_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_fill_extrusion_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddHeatmapLayerResponse, maplibre_map_libre_host_api_add_heatmap_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_HEATMAP_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddHeatmapLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddHeatmapLayerResponse, maplibre_map_libre_host_api_add_heatmap_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_heatmap_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddHeatmapLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HEATMAP_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_heatmap_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_heatmap_layer_response_init(MaplibreMapLibreHostApiAddHeatmapLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_heatmap_layer_response_class_init(MaplibreMapLibreHostApiAddHeatmapLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_heatmap_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddHeatmapLayerResponse* maplibre_map_libre_host_api_add_heatmap_layer_response_new() { + MaplibreMapLibreHostApiAddHeatmapLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HEATMAP_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_heatmap_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddHeatmapLayerResponse* maplibre_map_libre_host_api_add_heatmap_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddHeatmapLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HEATMAP_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_heatmap_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddHillshadeLayerResponse, maplibre_map_libre_host_api_add_hillshade_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_HILLSHADE_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddHillshadeLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddHillshadeLayerResponse, maplibre_map_libre_host_api_add_hillshade_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_hillshade_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddHillshadeLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HILLSHADE_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_hillshade_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_hillshade_layer_response_init(MaplibreMapLibreHostApiAddHillshadeLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_hillshade_layer_response_class_init(MaplibreMapLibreHostApiAddHillshadeLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_hillshade_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddHillshadeLayerResponse* maplibre_map_libre_host_api_add_hillshade_layer_response_new() { + MaplibreMapLibreHostApiAddHillshadeLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HILLSHADE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_hillshade_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddHillshadeLayerResponse* maplibre_map_libre_host_api_add_hillshade_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddHillshadeLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_HILLSHADE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_hillshade_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddLineLayerResponse, maplibre_map_libre_host_api_add_line_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_LINE_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddLineLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddLineLayerResponse, maplibre_map_libre_host_api_add_line_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_line_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddLineLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_LINE_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_line_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_line_layer_response_init(MaplibreMapLibreHostApiAddLineLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_line_layer_response_class_init(MaplibreMapLibreHostApiAddLineLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_line_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddLineLayerResponse* maplibre_map_libre_host_api_add_line_layer_response_new() { + MaplibreMapLibreHostApiAddLineLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_LINE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_line_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddLineLayerResponse* maplibre_map_libre_host_api_add_line_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddLineLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_LINE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_line_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddRasterLayerResponse, maplibre_map_libre_host_api_add_raster_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_RASTER_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddRasterLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddRasterLayerResponse, maplibre_map_libre_host_api_add_raster_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_raster_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddRasterLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_raster_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_raster_layer_response_init(MaplibreMapLibreHostApiAddRasterLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_raster_layer_response_class_init(MaplibreMapLibreHostApiAddRasterLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_raster_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddRasterLayerResponse* maplibre_map_libre_host_api_add_raster_layer_response_new() { + MaplibreMapLibreHostApiAddRasterLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddRasterLayerResponse* maplibre_map_libre_host_api_add_raster_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddRasterLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddSymbolLayerResponse, maplibre_map_libre_host_api_add_symbol_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_SYMBOL_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddSymbolLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddSymbolLayerResponse, maplibre_map_libre_host_api_add_symbol_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_symbol_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddSymbolLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_SYMBOL_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_symbol_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_symbol_layer_response_init(MaplibreMapLibreHostApiAddSymbolLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_add_symbol_layer_response_class_init(MaplibreMapLibreHostApiAddSymbolLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_symbol_layer_response_dispose; +} + +static MaplibreMapLibreHostApiAddSymbolLayerResponse* maplibre_map_libre_host_api_add_symbol_layer_response_new() { + MaplibreMapLibreHostApiAddSymbolLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_SYMBOL_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_symbol_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddSymbolLayerResponse* maplibre_map_libre_host_api_add_symbol_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddSymbolLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_SYMBOL_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_symbol_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddGeoJsonSourceResponse, maplibre_map_libre_host_api_add_geo_json_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_GEO_JSON_SOURCE_RESPONSE, GObject) struct _MaplibreMapLibreHostApiAddGeoJsonSourceResponse { @@ -1160,8 +1394,14 @@ static void maplibre_map_libre_host_api_add_fill_layer_cb(FlBasicMessageChannel* const gchar* id = fl_value_get_string(value0); FlValue* value1 = fl_value_get_list_value(message_, 1); const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); - self->vtable->add_fill_layer(id, source_id, handle, self->user_data); + self->vtable->add_fill_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); } static void maplibre_map_libre_host_api_add_circle_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { @@ -1175,8 +1415,14 @@ static void maplibre_map_libre_host_api_add_circle_layer_cb(FlBasicMessageChanne const gchar* id = fl_value_get_string(value0); FlValue* value1 = fl_value_get_list_value(message_, 1); const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); - self->vtable->add_circle_layer(id, source_id, handle, self->user_data); + self->vtable->add_circle_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); } static void maplibre_map_libre_host_api_add_background_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { @@ -1188,8 +1434,140 @@ static void maplibre_map_libre_host_api_add_background_layer_cb(FlBasicMessageCh FlValue* value0 = fl_value_get_list_value(message_, 0); const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + FlValue* layout = value1; + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* paint = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + const gchar* below_layer_id = fl_value_get_string(value3); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_background_layer(id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_fill_extrusion_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_fill_extrusion_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_fill_extrusion_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_heatmap_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_heatmap_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); - self->vtable->add_background_layer(id, handle, self->user_data); + self->vtable->add_heatmap_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_hillshade_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_hillshade_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_hillshade_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_line_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_line_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_line_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_raster_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_raster_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_raster_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_symbol_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_symbol_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* source_id = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* layout = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* paint = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + const gchar* below_layer_id = fl_value_get_string(value4); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_symbol_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); } static void maplibre_map_libre_host_api_add_geo_json_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { @@ -1260,6 +1638,24 @@ void maplibre_map_libre_host_api_set_method_handlers(FlBinaryMessenger* messenge g_autofree gchar* add_background_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_background_layer_channel = fl_basic_message_channel_new(messenger, add_background_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_background_layer_channel, maplibre_map_libre_host_api_add_background_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_fill_extrusion_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_fill_extrusion_layer_channel = fl_basic_message_channel_new(messenger, add_fill_extrusion_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_fill_extrusion_layer_channel, maplibre_map_libre_host_api_add_fill_extrusion_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_heatmap_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_heatmap_layer_channel = fl_basic_message_channel_new(messenger, add_heatmap_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_heatmap_layer_channel, maplibre_map_libre_host_api_add_heatmap_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_hillshade_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_hillshade_layer_channel = fl_basic_message_channel_new(messenger, add_hillshade_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_hillshade_layer_channel, maplibre_map_libre_host_api_add_hillshade_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_line_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_line_layer_channel = fl_basic_message_channel_new(messenger, add_line_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_line_layer_channel, maplibre_map_libre_host_api_add_line_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_raster_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_layer_channel = fl_basic_message_channel_new(messenger, add_raster_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_layer_channel, maplibre_map_libre_host_api_add_raster_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_symbol_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_symbol_layer_channel = fl_basic_message_channel_new(messenger, add_symbol_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_symbol_layer_channel, maplibre_map_libre_host_api_add_symbol_layer_cb, g_object_ref(api_data), g_object_unref); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, maplibre_map_libre_host_api_add_geo_json_source_cb, g_object_ref(api_data), g_object_unref); @@ -1299,6 +1695,24 @@ void maplibre_map_libre_host_api_clear_method_handlers(FlBinaryMessenger* messen g_autofree gchar* add_background_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addBackgroundLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_background_layer_channel = fl_basic_message_channel_new(messenger, add_background_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_background_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_fill_extrusion_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_fill_extrusion_layer_channel = fl_basic_message_channel_new(messenger, add_fill_extrusion_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_fill_extrusion_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_heatmap_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_heatmap_layer_channel = fl_basic_message_channel_new(messenger, add_heatmap_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_heatmap_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_hillshade_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_hillshade_layer_channel = fl_basic_message_channel_new(messenger, add_hillshade_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_hillshade_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_line_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_line_layer_channel = fl_basic_message_channel_new(messenger, add_line_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_line_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_raster_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_layer_channel = fl_basic_message_channel_new(messenger, add_raster_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_symbol_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_symbol_layer_channel = fl_basic_message_channel_new(messenger, add_symbol_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_symbol_layer_channel, nullptr, nullptr, nullptr); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, nullptr, nullptr, nullptr); @@ -1451,6 +1865,102 @@ void maplibre_map_libre_host_api_respond_error_add_background_layer(MaplibreMapL } } +void maplibre_map_libre_host_api_respond_add_fill_extrusion_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddFillExtrusionLayerResponse) response = maplibre_map_libre_host_api_add_fill_extrusion_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addFillExtrusionLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_fill_extrusion_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddFillExtrusionLayerResponse) response = maplibre_map_libre_host_api_add_fill_extrusion_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addFillExtrusionLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_heatmap_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddHeatmapLayerResponse) response = maplibre_map_libre_host_api_add_heatmap_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addHeatmapLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_heatmap_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddHeatmapLayerResponse) response = maplibre_map_libre_host_api_add_heatmap_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addHeatmapLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_hillshade_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddHillshadeLayerResponse) response = maplibre_map_libre_host_api_add_hillshade_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addHillshadeLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_hillshade_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddHillshadeLayerResponse) response = maplibre_map_libre_host_api_add_hillshade_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addHillshadeLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_line_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddLineLayerResponse) response = maplibre_map_libre_host_api_add_line_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addLineLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_line_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddLineLayerResponse) response = maplibre_map_libre_host_api_add_line_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addLineLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_raster_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddRasterLayerResponse) response = maplibre_map_libre_host_api_add_raster_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_raster_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddRasterLayerResponse) response = maplibre_map_libre_host_api_add_raster_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_symbol_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddSymbolLayerResponse) response = maplibre_map_libre_host_api_add_symbol_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addSymbolLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_symbol_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddSymbolLayerResponse) response = maplibre_map_libre_host_api_add_symbol_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addSymbolLayer", error->message); + } +} + void maplibre_map_libre_host_api_respond_add_geo_json_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { g_autoptr(MaplibreMapLibreHostApiAddGeoJsonSourceResponse) response = maplibre_map_libre_host_api_add_geo_json_source_response_new(); g_autoptr(GError) error = nullptr; diff --git a/linux/pigeon.g.h b/linux/pigeon.g.h index 98246905..ef34e78d 100644 --- a/linux/pigeon.g.h +++ b/linux/pigeon.g.h @@ -339,9 +339,15 @@ typedef struct { void (*get_visible_region)(MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*to_screen_location)(double lng, double lat, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*to_lng_lat)(double x, double y, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); - void (*add_fill_layer)(const gchar* id, const gchar* source_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); - void (*add_circle_layer)(const gchar* id, const gchar* source_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); - void (*add_background_layer)(const gchar* id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_fill_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_circle_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_background_layer)(const gchar* id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_fill_extrusion_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_heatmap_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_hillshade_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_line_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_raster_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_symbol_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_geo_json_source)(const gchar* id, const gchar* data, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); MaplibreMapLibreHostApiGetMetersPerPixelAtLatitudeResponse* (*get_meters_per_pixel_at_latitude)(double latitude, gpointer user_data); } MaplibreMapLibreHostApiVTable; @@ -544,6 +550,120 @@ void maplibre_map_libre_host_api_respond_add_background_layer(MaplibreMapLibreHo */ void maplibre_map_libre_host_api_respond_error_add_background_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); +/** + * maplibre_map_libre_host_api_respond_add_fill_extrusion_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addFillExtrusionLayer. + */ +void maplibre_map_libre_host_api_respond_add_fill_extrusion_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_fill_extrusion_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addFillExtrusionLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_fill_extrusion_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_heatmap_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addHeatmapLayer. + */ +void maplibre_map_libre_host_api_respond_add_heatmap_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_heatmap_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addHeatmapLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_heatmap_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_hillshade_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addHillshadeLayer. + */ +void maplibre_map_libre_host_api_respond_add_hillshade_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_hillshade_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addHillshadeLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_hillshade_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_line_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addLineLayer. + */ +void maplibre_map_libre_host_api_respond_add_line_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_line_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addLineLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_line_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_raster_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addRasterLayer. + */ +void maplibre_map_libre_host_api_respond_add_raster_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_raster_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addRasterLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_raster_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_symbol_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addSymbolLayer. + */ +void maplibre_map_libre_host_api_respond_add_symbol_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_symbol_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addSymbolLayer. + */ +void maplibre_map_libre_host_api_respond_error_add_symbol_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + /** * maplibre_map_libre_host_api_respond_add_geo_json_source: * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. diff --git a/macos/Classes/Pigeon.g.swift b/macos/Classes/Pigeon.g.swift index 0e814e7f..d83ae957 100644 --- a/macos/Classes/Pigeon.g.swift +++ b/macos/Classes/Pigeon.g.swift @@ -323,11 +323,23 @@ protocol MapLibreHostApi { /// Convert a screen location to a coordinate. func toLngLat(x: Double, y: Double, completion: @escaping (Result) -> Void) /// Add a fill layer to the map style. - func addFillLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + func addFillLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a circle layer to the map style. - func addCircleLayer(id: String, sourceId: String, completion: @escaping (Result) -> Void) + func addCircleLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a background layer to the map style. - func addBackgroundLayer(id: String, completion: @escaping (Result) -> Void) + func addBackgroundLayer(id: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a fill extrusion layer to the map style. + func addFillExtrusionLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a heatmap layer to the map style. + func addHeatmapLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a hillshade layer to the map style. + func addHillshadeLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a line layer to the map style. + func addLineLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a raster layer to the map style. + func addRasterLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Add a symbol layer to the map style. + func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and @@ -462,7 +474,10 @@ class MapLibreHostApiSetup { let args = message as! [Any?] let idArg = args[0] as! String let sourceIdArg = args[1] as! String - api.addFillLayer(id: idArg, sourceId: sourceIdArg) { result in + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addFillLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -481,7 +496,10 @@ class MapLibreHostApiSetup { let args = message as! [Any?] let idArg = args[0] as! String let sourceIdArg = args[1] as! String - api.addCircleLayer(id: idArg, sourceId: sourceIdArg) { result in + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addCircleLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -499,7 +517,10 @@ class MapLibreHostApiSetup { addBackgroundLayerChannel.setMessageHandler { message, reply in let args = message as! [Any?] let idArg = args[0] as! String - api.addBackgroundLayer(id: idArg) { result in + let layoutArg = args[1] as! [String: Any] + let paintArg = args[2] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[3]) + api.addBackgroundLayer(id: idArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in switch result { case .success: reply(wrapResult(nil)) @@ -511,6 +532,138 @@ class MapLibreHostApiSetup { } else { addBackgroundLayerChannel.setMessageHandler(nil) } + /// Add a fill extrusion layer to the map style. + let addFillExtrusionLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addFillExtrusionLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addFillExtrusionLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addFillExtrusionLayerChannel.setMessageHandler(nil) + } + /// Add a heatmap layer to the map style. + let addHeatmapLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addHeatmapLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addHeatmapLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addHeatmapLayerChannel.setMessageHandler(nil) + } + /// Add a hillshade layer to the map style. + let addHillshadeLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addHillshadeLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addHillshadeLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addHillshadeLayerChannel.setMessageHandler(nil) + } + /// Add a line layer to the map style. + let addLineLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addLineLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addLineLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addLineLayerChannel.setMessageHandler(nil) + } + /// Add a raster layer to the map style. + let addRasterLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addRasterLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterLayerChannel.setMessageHandler(nil) + } + /// Add a symbol layer to the map style. + let addSymbolLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addSymbolLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let sourceIdArg = args[1] as! String + let layoutArg = args[2] as! [String: Any] + let paintArg = args[3] as! [String: Any] + let belowLayerIdArg: String? = nilOrValue(args[4]) + api.addSymbolLayer(id: idArg, sourceId: sourceIdArg, layout: layoutArg, paint: paintArg, belowLayerId: belowLayerIdArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addSymbolLayerChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index 62bab4cf..eaeafa44 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -61,18 +61,91 @@ abstract interface class MapLibreHostApi { /// Add a fill layer to the map style. @async - void addFillLayer({required String id, required String sourceId}); + void addFillLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); /// Add a circle layer to the map style. @async - void addCircleLayer({required String id, required String sourceId}); + void addCircleLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); /// Add a background layer to the map style. @async void addBackgroundLayer({ required String id, - Map layout, - Map paint, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a fill extrusion layer to the map style. + @async + void addFillExtrusionLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a heatmap layer to the map style. + @async + void addHeatmapLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a hillshade layer to the map style. + @async + void addHillshadeLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a line layer to the map style. + @async + void addLineLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a raster layer to the map style. + @async + void addRasterLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, + }); + + /// Add a symbol layer to the map style. + @async + void addSymbolLayer({ + required String id, + required String sourceId, + required Map layout, + required Map paint, + String? belowLayerId, }); /// Add a GeoJSON source to the map style. diff --git a/windows/runner/pigeon.g.cpp b/windows/runner/pigeon.g.cpp index 6ebcfb5a..be1b35bd 100644 --- a/windows/runner/pigeon.g.cpp +++ b/windows/runner/pigeon.g.cpp @@ -682,7 +682,21 @@ void MapLibreHostApi::SetUp( return; } const auto& source_id_arg = std::get(encodable_source_id_arg); - api->AddFillLayer(id_arg, source_id_arg, [reply](std::optional&& output) { + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddFillLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { if (output.has_value()) { reply(WrapError(output.value())); return; @@ -717,7 +731,21 @@ void MapLibreHostApi::SetUp( return; } const auto& source_id_arg = std::get(encodable_source_id_arg); - api->AddCircleLayer(id_arg, source_id_arg, [reply](std::optional&& output) { + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddCircleLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { if (output.has_value()) { reply(WrapError(output.value())); return; @@ -746,7 +774,315 @@ void MapLibreHostApi::SetUp( return; } const auto& id_arg = std::get(encodable_id_arg); - api->AddBackgroundLayer(id_arg, [reply](std::optional&& output) { + const auto& encodable_layout_arg = args.at(1); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(2); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(3); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddBackgroundLayer(id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addFillExtrusionLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddFillExtrusionLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHeatmapLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddHeatmapLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addHillshadeLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddHillshadeLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addLineLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddLineLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddRasterLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_source_id_arg = args.at(1); + if (encodable_source_id_arg.IsNull()) { + reply(WrapError("source_id_arg unexpectedly null.")); + return; + } + const auto& source_id_arg = std::get(encodable_source_id_arg); + const auto& encodable_layout_arg = args.at(2); + if (encodable_layout_arg.IsNull()) { + reply(WrapError("layout_arg unexpectedly null.")); + return; + } + const auto& layout_arg = std::get(encodable_layout_arg); + const auto& encodable_paint_arg = args.at(3); + if (encodable_paint_arg.IsNull()) { + reply(WrapError("paint_arg unexpectedly null.")); + return; + } + const auto& paint_arg = std::get(encodable_paint_arg); + const auto& encodable_below_layer_id_arg = args.at(4); + const auto* below_layer_id_arg = std::get_if(&encodable_below_layer_id_arg); + api->AddSymbolLayer(id_arg, source_id_arg, layout_arg, paint_arg, below_layer_id_arg, [reply](std::optional&& output) { if (output.has_value()) { reply(WrapError(output.value())); return; diff --git a/windows/runner/pigeon.g.h b/windows/runner/pigeon.g.h index c3384860..b2c6c8a7 100644 --- a/windows/runner/pigeon.g.h +++ b/windows/runner/pigeon.g.h @@ -340,15 +340,72 @@ class MapLibreHostApi { virtual void AddFillLayer( const std::string& id, const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, std::function reply)> result) = 0; // Add a circle layer to the map style. virtual void AddCircleLayer( const std::string& id, const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, std::function reply)> result) = 0; // Add a background layer to the map style. virtual void AddBackgroundLayer( const std::string& id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a fill extrusion layer to the map style. + virtual void AddFillExtrusionLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a heatmap layer to the map style. + virtual void AddHeatmapLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a hillshade layer to the map style. + virtual void AddHillshadeLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a line layer to the map style. + virtual void AddLineLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a raster layer to the map style. + virtual void AddRasterLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, + std::function reply)> result) = 0; + // Add a symbol layer to the map style. + virtual void AddSymbolLayer( + const std::string& id, + const std::string& source_id, + const flutter::EncodableMap& layout, + const flutter::EncodableMap& paint, + const std::string* below_layer_id, std::function reply)> result) = 0; // Add a GeoJSON source to the map style. virtual void AddGeoJsonSource( From 6e77b70df4445742ec602f70155b4cff4834c45c Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 02:30:30 +0200 Subject: [PATCH 08/24] increase line width, fix imports --- example/lib/{annotations_page.dart => geojson_page.dart} | 2 +- example/lib/main.dart | 2 +- example/lib/menu_page.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename example/lib/{annotations_page.dart => geojson_page.dart} (97%) diff --git a/example/lib/annotations_page.dart b/example/lib/geojson_page.dart similarity index 97% rename from example/lib/annotations_page.dart rename to example/lib/geojson_page.dart index f2923d94..7600436b 100644 --- a/example/lib/annotations_page.dart +++ b/example/lib/geojson_page.dart @@ -55,7 +55,7 @@ class _GeoJsonPageState extends State { const LineLayer( id: 'geojson-line', sourceId: 'Path', - paint: {'line-color': '#F00'}, + paint: {'line-color': '#F00', 'line-width': 3}, ), ); diff --git a/example/lib/main.dart b/example/lib/main.dart index b3f4e9f3..819d64ad 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; +import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/kiosk_page.dart'; import 'package:maplibre_example/menu_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 558a2543..381e3ba9 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; +import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; import 'package:maplibre_example/web_controls_page.dart'; From 5e3e6f494fac5928109b13c3f93ec545b8ee0a9a Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 02:35:06 +0200 Subject: [PATCH 09/24] android: missing layers --- .../josxha/maplibre/MapLibreMapController.kt | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 191c796c..c891278a 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -31,6 +31,8 @@ import org.maplibre.android.style.layers.HeatmapLayer import org.maplibre.android.style.layers.HillshadeLayer import org.maplibre.android.style.layers.LineLayer import org.maplibre.android.style.layers.PropertyValue +import org.maplibre.android.style.layers.RasterLayer +import org.maplibre.android.style.layers.SymbolLayer import org.maplibre.android.style.sources.GeoJsonSource import kotlin.coroutines.cancellation.CancellationException @@ -312,7 +314,17 @@ class MapLibreMapController( belowLayerId: String?, callback: (Result) -> Unit ) { - TODO("Not yet implemented") + val layer = RasterLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) } override fun addSymbolLayer( @@ -323,7 +335,17 @@ class MapLibreMapController( belowLayerId: String?, callback: (Result) -> Unit ) { - TODO("Not yet implemented") + val layer = SymbolLayer(id, sourceId) + var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } + layer.setProperties(*properties.toTypedArray()) + if (belowLayerId == null) { + mapLibreMap.style?.addLayer(layer) + } else { + mapLibreMap.style?.addLayerBelow(layer, belowLayerId) + } + callback(Result.success(Unit)) } override fun getCamera(callback: (Result) -> Unit) { From c6cf4e202fa51850927635fb803d0d699303a590 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 03:20:02 +0200 Subject: [PATCH 10/24] implement on android (not complete) --- .../josxha/maplibre/MapLibreMapController.kt | 72 +++ .../com/github/josxha/maplibre/Pigeon.g.kt | 186 +++++++- ios/Classes/Pigeon.g.swift | 168 ++++++- lib/src/native/pigeon.g.dart | 230 ++++++++- lib/src/native/widget_state.dart | 84 +++- lib/src/style/sources/raster_dem_source.dart | 4 +- lib/src/style/sources/raster_source.dart | 2 +- linux/pigeon.g.cc | 446 ++++++++++++++++-- linux/pigeon.g.h | 112 +++++ macos/Classes/Pigeon.g.swift | 168 ++++++- pigeons/pigeon.dart | 79 ++++ windows/runner/pigeon.g.cpp | 312 +++++++++++- windows/runner/pigeon.g.h | 68 +++ 13 files changed, 1845 insertions(+), 86 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index c891278a..2ffed441 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -6,7 +6,9 @@ import MapCamera import MapLibreFlutterApi import MapLibreHostApi import MapOptions +import RasterDemEncoding import ScreenLocation +import TileScheme import android.content.Context import android.graphics.PointF import android.view.View @@ -34,6 +36,9 @@ import org.maplibre.android.style.layers.PropertyValue import org.maplibre.android.style.layers.RasterLayer import org.maplibre.android.style.layers.SymbolLayer import org.maplibre.android.style.sources.GeoJsonSource +import org.maplibre.android.style.sources.RasterDemSource +import org.maplibre.android.style.sources.RasterSource +import org.maplibre.android.style.sources.VectorSource import kotlin.coroutines.cancellation.CancellationException class MapLibreMapController( @@ -376,6 +381,73 @@ class MapLibreMapController( callback(Result.success(Unit)) } + override fun addImageSource( + id: String, + url: String, + coordinates: List, + callback: (Result) -> Unit + ) { + TODO("Not yet implemented") + } + + override fun addRasterSource( + id: String, + url: String?, + tiles: List?, + bounds: List, + minZoom: Double, + maxZoom: Double, + tileSize: Long, + scheme: TileScheme, + attribution: String?, + volatile: Boolean, + callback: (Result) -> Unit + ) { + // TODO apply other properties + mapLibreMap.style?.addSource(RasterSource(id, url)) + callback(Result.success(Unit)) + } + + override fun addRasterDemSource( + id: String, + url: String?, + tiles: List?, + bounds: List, + minZoom: Double, + maxZoom: Double, + tileSize: Long, + attribution: String?, + encoding: RasterDemEncoding, + volatile: Boolean, + redFactor: Double, + blueFactor: Double, + greenFactor: Double, + baseShift: Double, + callback: (Result) -> Unit + ) { + // TODO apply other properties + mapLibreMap.style?.addSource(RasterDemSource(id, url)) + callback(Result.success(Unit)) + } + + override fun addVectorSource( + id: String, + url: String?, + tiles: List?, + bounds: List, + scheme: TileScheme, + minZoom: Double, + maxZoom: Double, + attribution: String?, + volatile: Boolean, + sourceLayer: String?, + callback: (Result) -> Unit + ) { + // TODO apply other properties + mapLibreMap.style?.addSource(VectorSource(id, url)) + callback(Result.success(Unit)) + } + override fun getMetersPerPixelAtLatitude(latitude: Double): Double = mapLibreMap.projection.getMetersPerPixelAtLatitude(latitude) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt index 5efe9068..2cbbf60a 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt @@ -46,6 +46,39 @@ class FlutterError ( val details: Any? = null ) : Throwable() +/** Influences the y direction of the tile coordinates. */ +enum class TileScheme(val raw: Int) { + /** Slippy map tilenames scheme. */ + XYZ(0), + /** OSGeo spec scheme. */ + TMS(1); + + companion object { + fun ofRaw(raw: Int): TileScheme? { + return values().firstOrNull { it.raw == raw } + } + } +} + +/** The encoding used by this source. Mapbox Terrain RGB is used by default. */ +enum class RasterDemEncoding(val raw: Int) { + /** Terrarium format PNG tiles. */ + TERRARIUM(0), + /** Mapbox Terrain RGB tiles. */ + MAPBOX(1), + /** + * Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + * parameters. + */ + CUSTOM(2); + + companion object { + fun ofRaw(raw: Int): RasterDemEncoding? { + return values().firstOrNull { it.raw == raw } + } + } +} + /** * The map options define initial values for the MapLibre map. * @@ -212,26 +245,36 @@ private open class PigeonPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { 129.toByte() -> { + return (readValue(buffer) as Long?)?.let { + TileScheme.ofRaw(it.toInt()) + } + } + 130.toByte() -> { + return (readValue(buffer) as Long?)?.let { + RasterDemEncoding.ofRaw(it.toInt()) + } + } + 131.toByte() -> { return (readValue(buffer) as? List)?.let { MapOptions.fromList(it) } } - 130.toByte() -> { + 132.toByte() -> { return (readValue(buffer) as? List)?.let { LngLat.fromList(it) } } - 131.toByte() -> { + 133.toByte() -> { return (readValue(buffer) as? List)?.let { ScreenLocation.fromList(it) } } - 132.toByte() -> { + 134.toByte() -> { return (readValue(buffer) as? List)?.let { MapCamera.fromList(it) } } - 133.toByte() -> { + 135.toByte() -> { return (readValue(buffer) as? List)?.let { LngLatBounds.fromList(it) } @@ -241,24 +284,32 @@ private open class PigeonPigeonCodec : StandardMessageCodec() { } override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { when (value) { - is MapOptions -> { + is TileScheme -> { stream.write(129) + writeValue(stream, value.raw) + } + is RasterDemEncoding -> { + stream.write(130) + writeValue(stream, value.raw) + } + is MapOptions -> { + stream.write(131) writeValue(stream, value.toList()) } is LngLat -> { - stream.write(130) + stream.write(132) writeValue(stream, value.toList()) } is ScreenLocation -> { - stream.write(131) + stream.write(133) writeValue(stream, value.toList()) } is MapCamera -> { - stream.write(132) + stream.write(134) writeValue(stream, value.toList()) } is LngLatBounds -> { - stream.write(133) + stream.write(135) writeValue(stream, value.toList()) } else -> super.writeValue(stream, value) @@ -304,6 +355,14 @@ interface MapLibreHostApi { fun addSymbolLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) /** Add a GeoJSON source to the map style. */ fun addGeoJsonSource(id: String, data: String, callback: (Result) -> Unit) + /** Add a image source to the map style. */ + fun addImageSource(id: String, url: String, coordinates: List, callback: (Result) -> Unit) + /** Add a raster source to the map style. */ + fun addRasterSource(id: String, url: String?, tiles: List?, bounds: List, minZoom: Double, maxZoom: Double, tileSize: Long, scheme: TileScheme, attribution: String?, volatile: Boolean, callback: (Result) -> Unit) + /** Add a raster DEM source to the map style. */ + fun addRasterDemSource(id: String, url: String?, tiles: List?, bounds: List, minZoom: Double, maxZoom: Double, tileSize: Long, attribution: String?, encoding: RasterDemEncoding, volatile: Boolean, redFactor: Double, blueFactor: Double, greenFactor: Double, baseShift: Double, callback: (Result) -> Unit) + /** Add a vector source to the map style. */ + fun addVectorSource(id: String, url: String?, tiles: List?, bounds: List, scheme: TileScheme, minZoom: Double, maxZoom: Double, attribution: String?, volatile: Boolean, sourceLayer: String?, callback: (Result) -> Unit) /** * Returns the distance spanned by one pixel at the specified latitude and * current zoom level. @@ -668,6 +727,115 @@ interface MapLibreHostApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val urlArg = args[1] as String + val coordinatesArg = args[2] as List + api.addImageSource(idArg, urlArg, coordinatesArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val urlArg = args[1] as String? + val tilesArg = args[2] as List? + val boundsArg = args[3] as List + val minZoomArg = args[4] as Double + val maxZoomArg = args[5] as Double + val tileSizeArg = args[6] as Long + val schemeArg = args[7] as TileScheme + val attributionArg = args[8] as String? + val volatileArg = args[9] as Boolean + api.addRasterSource(idArg, urlArg, tilesArg, boundsArg, minZoomArg, maxZoomArg, tileSizeArg, schemeArg, attributionArg, volatileArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val urlArg = args[1] as String? + val tilesArg = args[2] as List? + val boundsArg = args[3] as List + val minZoomArg = args[4] as Double + val maxZoomArg = args[5] as Double + val tileSizeArg = args[6] as Long + val attributionArg = args[7] as String? + val encodingArg = args[8] as RasterDemEncoding + val volatileArg = args[9] as Boolean + val redFactorArg = args[10] as Double + val blueFactorArg = args[11] as Double + val greenFactorArg = args[12] as Double + val baseShiftArg = args[13] as Double + api.addRasterDemSource(idArg, urlArg, tilesArg, boundsArg, minZoomArg, maxZoomArg, tileSizeArg, attributionArg, encodingArg, volatileArg, redFactorArg, blueFactorArg, greenFactorArg, baseShiftArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + val urlArg = args[1] as String? + val tilesArg = args[2] as List? + val boundsArg = args[3] as List + val schemeArg = args[4] as TileScheme + val minZoomArg = args[5] as Double + val maxZoomArg = args[6] as Double + val attributionArg = args[7] as String? + val volatileArg = args[8] as Boolean + val sourceLayerArg = args[9] as String? + api.addVectorSource(idArg, urlArg, tilesArg, boundsArg, schemeArg, minZoomArg, maxZoomArg, attributionArg, volatileArg, sourceLayerArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/ios/Classes/Pigeon.g.swift b/ios/Classes/Pigeon.g.swift index d83ae957..532573ec 100644 --- a/ios/Classes/Pigeon.g.swift +++ b/ios/Classes/Pigeon.g.swift @@ -68,6 +68,25 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +/// Influences the y direction of the tile coordinates. +enum TileScheme: Int { + /// Slippy map tilenames scheme. + case xyz = 0 + /// OSGeo spec scheme. + case tms = 1 +} + +/// The encoding used by this source. Mapbox Terrain RGB is used by default. +enum RasterDemEncoding: Int { + /// Terrarium format PNG tiles. + case terrarium = 0 + /// Mapbox Terrain RGB tiles. + case mapbox = 1 + /// Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + /// parameters. + case custom = 2 +} + /// The map options define initial values for the MapLibre map. /// /// Generated class from Pigeon that represents data sent in messages. @@ -254,14 +273,26 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { case 129: - return MapOptions.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return TileScheme(rawValue: enumResultAsInt) + } + return nil case 130: - return LngLat.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return RasterDemEncoding(rawValue: enumResultAsInt) + } + return nil case 131: - return ScreenLocation.fromList(self.readValue() as! [Any?]) + return MapOptions.fromList(self.readValue() as! [Any?]) case 132: - return MapCamera.fromList(self.readValue() as! [Any?]) + return LngLat.fromList(self.readValue() as! [Any?]) case 133: + return ScreenLocation.fromList(self.readValue() as! [Any?]) + case 134: + return MapCamera.fromList(self.readValue() as! [Any?]) + case 135: return LngLatBounds.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -271,20 +302,26 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { private class PigeonPigeonCodecWriter: FlutterStandardWriter { override func writeValue(_ value: Any) { - if let value = value as? MapOptions { + if let value = value as? TileScheme { super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? RasterDemEncoding { + super.writeByte(130) + super.writeValue(value.rawValue) + } else if let value = value as? MapOptions { + super.writeByte(131) super.writeValue(value.toList()) } else if let value = value as? LngLat { - super.writeByte(130) + super.writeByte(132) super.writeValue(value.toList()) } else if let value = value as? ScreenLocation { - super.writeByte(131) + super.writeByte(133) super.writeValue(value.toList()) } else if let value = value as? MapCamera { - super.writeByte(132) + super.writeByte(134) super.writeValue(value.toList()) } else if let value = value as? LngLatBounds { - super.writeByte(133) + super.writeByte(135) super.writeValue(value.toList()) } else { super.writeValue(value) @@ -342,6 +379,14 @@ protocol MapLibreHostApi { func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) + /// Add a image source to the map style. + func addImageSource(id: String, url: String, coordinates: [LngLat], completion: @escaping (Result) -> Void) + /// Add a raster source to the map style. + func addRasterSource(id: String, url: String?, tiles: [String]?, bounds: [Double], minZoom: Double, maxZoom: Double, tileSize: Int64, scheme: TileScheme, attribution: String?, volatile: Bool, completion: @escaping (Result) -> Void) + /// Add a raster DEM source to the map style. + func addRasterDemSource(id: String, url: String?, tiles: [String]?, bounds: [Double], minZoom: Double, maxZoom: Double, tileSize: Int64, attribution: String?, encoding: RasterDemEncoding, volatile: Bool, redFactor: Double, blueFactor: Double, greenFactor: Double, baseShift: Double, completion: @escaping (Result) -> Void) + /// Add a vector source to the map style. + func addVectorSource(id: String, url: String?, tiles: [String]?, bounds: [Double], scheme: TileScheme, minZoom: Double, maxZoom: Double, attribution: String?, volatile: Bool, sourceLayer: String?, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. func getMetersPerPixelAtLatitude(latitude: Double) throws -> Double @@ -683,6 +728,111 @@ class MapLibreHostApiSetup { } else { addGeoJsonSourceChannel.setMessageHandler(nil) } + /// Add a image source to the map style. + let addImageSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addImageSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg = args[1] as! String + let coordinatesArg = args[2] as! [LngLat] + api.addImageSource(id: idArg, url: urlArg, coordinates: coordinatesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addImageSourceChannel.setMessageHandler(nil) + } + /// Add a raster source to the map style. + let addRasterSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let minZoomArg = args[4] as! Double + let maxZoomArg = args[5] as! Double + let tileSizeArg = args[6] as! Int64 + let schemeArg = args[7] as! TileScheme + let attributionArg: String? = nilOrValue(args[8]) + let volatileArg = args[9] as! Bool + api.addRasterSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, minZoom: minZoomArg, maxZoom: maxZoomArg, tileSize: tileSizeArg, scheme: schemeArg, attribution: attributionArg, volatile: volatileArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterSourceChannel.setMessageHandler(nil) + } + /// Add a raster DEM source to the map style. + let addRasterDemSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterDemSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let minZoomArg = args[4] as! Double + let maxZoomArg = args[5] as! Double + let tileSizeArg = args[6] as! Int64 + let attributionArg: String? = nilOrValue(args[7]) + let encodingArg = args[8] as! RasterDemEncoding + let volatileArg = args[9] as! Bool + let redFactorArg = args[10] as! Double + let blueFactorArg = args[11] as! Double + let greenFactorArg = args[12] as! Double + let baseShiftArg = args[13] as! Double + api.addRasterDemSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, minZoom: minZoomArg, maxZoom: maxZoomArg, tileSize: tileSizeArg, attribution: attributionArg, encoding: encodingArg, volatile: volatileArg, redFactor: redFactorArg, blueFactor: blueFactorArg, greenFactor: greenFactorArg, baseShift: baseShiftArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterDemSourceChannel.setMessageHandler(nil) + } + /// Add a vector source to the map style. + let addVectorSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addVectorSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let schemeArg = args[4] as! TileScheme + let minZoomArg = args[5] as! Double + let maxZoomArg = args[6] as! Double + let attributionArg: String? = nilOrValue(args[7]) + let volatileArg = args[8] as! Bool + let sourceLayerArg: String? = nilOrValue(args[9]) + api.addVectorSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, scheme: schemeArg, minZoom: minZoomArg, maxZoom: maxZoomArg, attribution: attributionArg, volatile: volatileArg, sourceLayer: sourceLayerArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addVectorSourceChannel.setMessageHandler(nil) + } /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. let getMetersPerPixelAtLatitudeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) diff --git a/lib/src/native/pigeon.g.dart b/lib/src/native/pigeon.g.dart index 1320f5f8..c0ee1ba4 100644 --- a/lib/src/native/pigeon.g.dart +++ b/lib/src/native/pigeon.g.dart @@ -26,6 +26,28 @@ List wrapResponse( return [error.code, error.message, error.details]; } +/// Influences the y direction of the tile coordinates. +enum TileScheme { + /// Slippy map tilenames scheme. + xyz, + + /// OSGeo spec scheme. + tms, +} + +/// The encoding used by this source. Mapbox Terrain RGB is used by default. +enum RasterDemEncoding { + /// Terrarium format PNG tiles. + terrarium, + + /// Mapbox Terrain RGB tiles. + mapbox, + + /// Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + /// parameters. + custom, +} + /// The map options define initial values for the MapLibre map. class MapOptions { MapOptions({ @@ -224,20 +246,26 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is MapOptions) { + } else if (value is TileScheme) { buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is RasterDemEncoding) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is MapOptions) { + buffer.putUint8(131); writeValue(buffer, value.encode()); } else if (value is LngLat) { - buffer.putUint8(130); + buffer.putUint8(132); writeValue(buffer, value.encode()); } else if (value is ScreenLocation) { - buffer.putUint8(131); + buffer.putUint8(133); writeValue(buffer, value.encode()); } else if (value is MapCamera) { - buffer.putUint8(132); + buffer.putUint8(134); writeValue(buffer, value.encode()); } else if (value is LngLatBounds) { - buffer.putUint8(133); + buffer.putUint8(135); writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); @@ -248,14 +276,20 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - return MapOptions.decode(readValue(buffer)!); + final int? value = readValue(buffer) as int?; + return value == null ? null : TileScheme.values[value]; case 130: - return LngLat.decode(readValue(buffer)!); + final int? value = readValue(buffer) as int?; + return value == null ? null : RasterDemEncoding.values[value]; case 131: - return ScreenLocation.decode(readValue(buffer)!); + return MapOptions.decode(readValue(buffer)!); case 132: - return MapCamera.decode(readValue(buffer)!); + return LngLat.decode(readValue(buffer)!); case 133: + return ScreenLocation.decode(readValue(buffer)!); + case 134: + return MapCamera.decode(readValue(buffer)!); + case 135: return LngLatBounds.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -773,6 +807,184 @@ class MapLibreHostApi { } } + /// Add a image source to the map style. + Future addImageSource({ + required String id, + required String url, + required List coordinates, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([id, url, coordinates]) 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 { + return; + } + } + + /// Add a raster source to the map style. + Future addRasterSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required double minZoom, + required double maxZoom, + required int tileSize, + required TileScheme scheme, + required String? attribution, + required bool volatile, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([ + id, + url, + tiles, + bounds, + minZoom, + maxZoom, + tileSize, + scheme, + attribution, + volatile + ]) 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 { + return; + } + } + + /// Add a raster DEM source to the map style. + Future addRasterDemSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required double minZoom, + required double maxZoom, + required int tileSize, + required String? attribution, + required RasterDemEncoding encoding, + required bool volatile, + double redFactor = 1, + double blueFactor = 1, + double greenFactor = 1, + double baseShift = 0, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([ + id, + url, + tiles, + bounds, + minZoom, + maxZoom, + tileSize, + attribution, + encoding, + volatile, + redFactor, + blueFactor, + greenFactor, + baseShift + ]) 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 { + return; + } + } + + /// Add a vector source to the map style. + Future addVectorSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required TileScheme scheme, + required double minZoom, + required double maxZoom, + required String? attribution, + required bool volatile, + required String? sourceLayer, + }) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([ + id, + url, + tiles, + bounds, + scheme, + minZoom, + maxZoom, + attribution, + volatile, + sourceLayer + ]) 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 { + return; + } + } + /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. Future getMetersPerPixelAtLatitude(double latitude) async { diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index 64307828..f6cfbb69 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -197,16 +197,80 @@ final class MapLibreMapStateNative extends State await switch (source) { GeoJsonSource() => _hostApi.addGeoJsonSource(id: source.id, data: source.data), - // TODO: Handle this case. - RasterDemSource() => throw UnimplementedError(), - // TODO: Handle this case. - RasterSource() => throw UnimplementedError(), - // TODO: Handle this case. - VectorSource() => throw UnimplementedError(), - // TODO: Handle this case. - ImageSource() => throw UnimplementedError(), - // TODO: Handle this case. - VideoSource() => throw UnimplementedError(), + RasterDemSource() => switch (source.encoding) { + final RasterDemCustomEncoding encoding => _hostApi.addRasterDemSource( + id: source.id, + attribution: source.attribution, + bounds: source.bounds, + volatile: source.volatile, + url: source.url, + tiles: source.tiles, + minZoom: source.minZoom, + maxZoom: source.maxZoom, + tileSize: source.tileSize, + encoding: pigeon.RasterDemEncoding.custom, + greenFactor: encoding.greenFactor, + blueFactor: encoding.blueFactor, + redFactor: encoding.redFactor, + baseShift: encoding.baseShift, + ), + _ => _hostApi.addRasterDemSource( + id: source.id, + attribution: source.attribution, + bounds: source.bounds, + volatile: source.volatile, + url: source.url, + tiles: source.tiles, + minZoom: source.minZoom, + maxZoom: source.maxZoom, + tileSize: source.tileSize, + encoding: switch (source.encoding) { + RasterDemTerrariumEncoding() => + pigeon.RasterDemEncoding.terrarium, + RasterDemMapboxEncoding() => pigeon.RasterDemEncoding.mapbox, + RasterDemCustomEncoding() => pigeon.RasterDemEncoding.custom, + }, + ), + }, + RasterSource() => _hostApi.addRasterSource( + id: source.id, + bounds: source.bounds, + url: source.url, + tiles: source.tiles, + minZoom: source.minZoom, + maxZoom: source.maxZoom, + attribution: source.attribution, + tileSize: source.tileSize, + volatile: source.volatile, + scheme: switch (source.scheme) { + TileScheme.xyz => pigeon.TileScheme.xyz, + TileScheme.tms => pigeon.TileScheme.tms, + }, + ), + VectorSource() => _hostApi.addVectorSource( + id: source.id, + bounds: source.bounds, + attribution: source.attribution, + maxZoom: source.maxZoom, + minZoom: source.minZoom, + scheme: switch (source.scheme) { + TileScheme.xyz => pigeon.TileScheme.xyz, + TileScheme.tms => pigeon.TileScheme.tms, + }, + sourceLayer: source.sourceLayer, + tiles: source.tiles, + url: source.url, + volatile: source.volatile, + ), + ImageSource() => _hostApi.addImageSource( + id: source.id, + url: source.url, + coordinates: source.coordinates + .map((e) => e.toLngLat()) + .toList(growable: false), + ), + VideoSource() => + throw UnimplementedError('Video source is only supported on web.'), }; } diff --git a/lib/src/style/sources/raster_dem_source.dart b/lib/src/style/sources/raster_dem_source.dart index 1022ea44..7174ed13 100644 --- a/lib/src/style/sources/raster_dem_source.dart +++ b/lib/src/style/sources/raster_dem_source.dart @@ -50,7 +50,7 @@ final class RasterDemSource extends Source { /// configurable for raster layers. /// /// Defaults to 512. - final double tileSize; + final int tileSize; /// Contains an attribution to be displayed when the map is shown to a user. final String? attribution; @@ -72,7 +72,7 @@ sealed class RasterDemEncoding { /// Terrarium format PNG tiles. /// See https://aws.amazon.com/es/public-datasets/terrain/ for more info. final class RasterDemTerrariumEncoding extends RasterDemEncoding { - /// Create a [RasterDemCustomEncoding]. + /// Create a [RasterDemTerrariumEncoding]. const RasterDemTerrariumEncoding(); } diff --git a/lib/src/style/sources/raster_source.dart b/lib/src/style/sources/raster_source.dart index 07287478..a4e60510 100644 --- a/lib/src/style/sources/raster_source.dart +++ b/lib/src/style/sources/raster_source.dart @@ -49,7 +49,7 @@ final class RasterSource extends Source { /// configurable for raster layers. /// /// Defaults to 512. - final double tileSize; + final int tileSize; /// Influences the y direction of the tile coordinates. The global-mercator /// (aka Spherical Mercator) profile is assumed. diff --git a/linux/pigeon.g.cc b/linux/pigeon.g.cc index 04fb37d2..61503bfd 100644 --- a/linux/pigeon.g.cc +++ b/linux/pigeon.g.cc @@ -89,7 +89,7 @@ static FlValue* maplibre_map_options_to_list(MaplibreMapOptions* self) { fl_value_append_take(values, fl_value_new_float(self->zoom)); fl_value_append_take(values, fl_value_new_float(self->tilt)); fl_value_append_take(values, fl_value_new_float(self->bearing)); - fl_value_append_take(values, self->center != nullptr ? fl_value_new_custom_object(130, G_OBJECT(self->center)) : fl_value_new_null()); + fl_value_append_take(values, self->center != nullptr ? fl_value_new_custom_object(132, G_OBJECT(self->center)) : fl_value_new_null()); fl_value_append_take(values, fl_value_new_bool(self->listens_on_click)); fl_value_append_take(values, fl_value_new_bool(self->listens_on_long_click)); return values; @@ -275,7 +275,7 @@ double maplibre_map_camera_get_bearing(MaplibreMapCamera* self) { static FlValue* maplibre_map_camera_to_list(MaplibreMapCamera* self) { FlValue* values = fl_value_new_list(); - fl_value_append_take(values, fl_value_new_custom_object(130, G_OBJECT(self->center))); + fl_value_append_take(values, fl_value_new_custom_object(132, G_OBJECT(self->center))); fl_value_append_take(values, fl_value_new_float(self->zoom)); fl_value_append_take(values, fl_value_new_float(self->tilt)); fl_value_append_take(values, fl_value_new_float(self->bearing)); @@ -375,36 +375,48 @@ struct _MaplibreMessageCodec { G_DEFINE_TYPE(MaplibreMessageCodec, maplibre_message_codec, fl_standard_message_codec_get_type()) -static gboolean maplibre_message_codec_write_maplibre_map_options(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreMapOptions* value, GError** error) { +static gboolean maplibre_message_codec_write_maplibre_tile_scheme(FlStandardMessageCodec* codec, GByteArray* buffer, FlValue* value, GError** error) { uint8_t type = 129; g_byte_array_append(buffer, &type, sizeof(uint8_t)); + return fl_standard_message_codec_write_value(codec, buffer, value, error); +} + +static gboolean maplibre_message_codec_write_maplibre_raster_dem_encoding(FlStandardMessageCodec* codec, GByteArray* buffer, FlValue* value, GError** error) { + uint8_t type = 130; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); + return fl_standard_message_codec_write_value(codec, buffer, value, error); +} + +static gboolean maplibre_message_codec_write_maplibre_map_options(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreMapOptions* value, GError** error) { + uint8_t type = 131; + g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_map_options_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_lng_lat(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreLngLat* value, GError** error) { - uint8_t type = 130; + uint8_t type = 132; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_lng_lat_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_screen_location(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreScreenLocation* value, GError** error) { - uint8_t type = 131; + uint8_t type = 133; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_screen_location_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_map_camera(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreMapCamera* value, GError** error) { - uint8_t type = 132; + uint8_t type = 134; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_map_camera_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); } static gboolean maplibre_message_codec_write_maplibre_lng_lat_bounds(FlStandardMessageCodec* codec, GByteArray* buffer, MaplibreLngLatBounds* value, GError** error) { - uint8_t type = 133; + uint8_t type = 135; g_byte_array_append(buffer, &type, sizeof(uint8_t)); g_autoptr(FlValue) values = maplibre_lng_lat_bounds_to_list(value); return fl_standard_message_codec_write_value(codec, buffer, values, error); @@ -414,14 +426,18 @@ static gboolean maplibre_message_codec_write_value(FlStandardMessageCodec* codec if (fl_value_get_type(value) == FL_VALUE_TYPE_CUSTOM) { switch (fl_value_get_custom_type(value)) { case 129: - return maplibre_message_codec_write_maplibre_map_options(codec, buffer, MAPLIBRE_MAP_OPTIONS(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_tile_scheme(codec, buffer, reinterpret_cast(const_cast(fl_value_get_custom_value(value))), error); case 130: - return maplibre_message_codec_write_maplibre_lng_lat(codec, buffer, MAPLIBRE_LNG_LAT(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_raster_dem_encoding(codec, buffer, reinterpret_cast(const_cast(fl_value_get_custom_value(value))), error); case 131: - return maplibre_message_codec_write_maplibre_screen_location(codec, buffer, MAPLIBRE_SCREEN_LOCATION(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_map_options(codec, buffer, MAPLIBRE_MAP_OPTIONS(fl_value_get_custom_value_object(value)), error); case 132: - return maplibre_message_codec_write_maplibre_map_camera(codec, buffer, MAPLIBRE_MAP_CAMERA(fl_value_get_custom_value_object(value)), error); + return maplibre_message_codec_write_maplibre_lng_lat(codec, buffer, MAPLIBRE_LNG_LAT(fl_value_get_custom_value_object(value)), error); case 133: + return maplibre_message_codec_write_maplibre_screen_location(codec, buffer, MAPLIBRE_SCREEN_LOCATION(fl_value_get_custom_value_object(value)), error); + case 134: + return maplibre_message_codec_write_maplibre_map_camera(codec, buffer, MAPLIBRE_MAP_CAMERA(fl_value_get_custom_value_object(value)), error); + case 135: return maplibre_message_codec_write_maplibre_lng_lat_bounds(codec, buffer, MAPLIBRE_LNG_LAT_BOUNDS(fl_value_get_custom_value_object(value)), error); } } @@ -429,6 +445,14 @@ static gboolean maplibre_message_codec_write_value(FlStandardMessageCodec* codec return FL_STANDARD_MESSAGE_CODEC_CLASS(maplibre_message_codec_parent_class)->write_value(codec, buffer, value, error); } +static FlValue* maplibre_message_codec_read_maplibre_tile_scheme(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { + return fl_value_new_custom(129, fl_standard_message_codec_read_value(codec, buffer, offset, error), (GDestroyNotify)fl_value_unref); +} + +static FlValue* maplibre_message_codec_read_maplibre_raster_dem_encoding(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { + return fl_value_new_custom(130, fl_standard_message_codec_read_value(codec, buffer, offset, error), (GDestroyNotify)fl_value_unref); +} + static FlValue* maplibre_message_codec_read_maplibre_map_options(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { g_autoptr(FlValue) values = fl_standard_message_codec_read_value(codec, buffer, offset, error); if (values == nullptr) { @@ -441,7 +465,7 @@ static FlValue* maplibre_message_codec_read_maplibre_map_options(FlStandardMessa return nullptr; } - return fl_value_new_custom_object(129, G_OBJECT(value)); + return fl_value_new_custom_object(131, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_lng_lat(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -456,7 +480,7 @@ static FlValue* maplibre_message_codec_read_maplibre_lng_lat(FlStandardMessageCo return nullptr; } - return fl_value_new_custom_object(130, G_OBJECT(value)); + return fl_value_new_custom_object(132, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_screen_location(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -471,7 +495,7 @@ static FlValue* maplibre_message_codec_read_maplibre_screen_location(FlStandardM return nullptr; } - return fl_value_new_custom_object(131, G_OBJECT(value)); + return fl_value_new_custom_object(133, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_map_camera(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -486,7 +510,7 @@ static FlValue* maplibre_message_codec_read_maplibre_map_camera(FlStandardMessag return nullptr; } - return fl_value_new_custom_object(132, G_OBJECT(value)); + return fl_value_new_custom_object(134, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_maplibre_lng_lat_bounds(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, GError** error) { @@ -501,20 +525,24 @@ static FlValue* maplibre_message_codec_read_maplibre_lng_lat_bounds(FlStandardMe return nullptr; } - return fl_value_new_custom_object(133, G_OBJECT(value)); + return fl_value_new_custom_object(135, G_OBJECT(value)); } static FlValue* maplibre_message_codec_read_value_of_type(FlStandardMessageCodec* codec, GBytes* buffer, size_t* offset, int type, GError** error) { switch (type) { case 129: - return maplibre_message_codec_read_maplibre_map_options(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_tile_scheme(codec, buffer, offset, error); case 130: - return maplibre_message_codec_read_maplibre_lng_lat(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_raster_dem_encoding(codec, buffer, offset, error); case 131: - return maplibre_message_codec_read_maplibre_screen_location(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_map_options(codec, buffer, offset, error); case 132: - return maplibre_message_codec_read_maplibre_map_camera(codec, buffer, offset, error); + return maplibre_message_codec_read_maplibre_lng_lat(codec, buffer, offset, error); case 133: + return maplibre_message_codec_read_maplibre_screen_location(codec, buffer, offset, error); + case 134: + return maplibre_message_codec_read_maplibre_map_camera(codec, buffer, offset, error); + case 135: return maplibre_message_codec_read_maplibre_lng_lat_bounds(codec, buffer, offset, error); default: return FL_STANDARD_MESSAGE_CODEC_CLASS(maplibre_message_codec_parent_class)->read_value_of_type(codec, buffer, offset, type, error); @@ -668,7 +696,7 @@ static void maplibre_map_libre_host_api_get_camera_response_class_init(MaplibreM static MaplibreMapLibreHostApiGetCameraResponse* maplibre_map_libre_host_api_get_camera_response_new(MaplibreMapCamera* return_value) { MaplibreMapLibreHostApiGetCameraResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_GET_CAMERA_RESPONSE(g_object_new(maplibre_map_libre_host_api_get_camera_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(132, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(134, G_OBJECT(return_value))); return self; } @@ -707,7 +735,7 @@ static void maplibre_map_libre_host_api_get_visible_region_response_class_init(M static MaplibreMapLibreHostApiGetVisibleRegionResponse* maplibre_map_libre_host_api_get_visible_region_response_new(MaplibreLngLatBounds* return_value) { MaplibreMapLibreHostApiGetVisibleRegionResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_GET_VISIBLE_REGION_RESPONSE(g_object_new(maplibre_map_libre_host_api_get_visible_region_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(133, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(135, G_OBJECT(return_value))); return self; } @@ -746,7 +774,7 @@ static void maplibre_map_libre_host_api_to_screen_location_response_class_init(M static MaplibreMapLibreHostApiToScreenLocationResponse* maplibre_map_libre_host_api_to_screen_location_response_new(MaplibreScreenLocation* return_value) { MaplibreMapLibreHostApiToScreenLocationResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_TO_SCREEN_LOCATION_RESPONSE(g_object_new(maplibre_map_libre_host_api_to_screen_location_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(131, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(133, G_OBJECT(return_value))); return self; } @@ -785,7 +813,7 @@ static void maplibre_map_libre_host_api_to_lng_lat_response_class_init(MaplibreM static MaplibreMapLibreHostApiToLngLatResponse* maplibre_map_libre_host_api_to_lng_lat_response_new(MaplibreLngLat* return_value) { MaplibreMapLibreHostApiToLngLatResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_TO_LNG_LAT_RESPONSE(g_object_new(maplibre_map_libre_host_api_to_lng_lat_response_get_type(), nullptr)); self->value = fl_value_new_list(); - fl_value_append_take(self->value, fl_value_new_custom_object(130, G_OBJECT(return_value))); + fl_value_append_take(self->value, fl_value_new_custom_object(132, G_OBJECT(return_value))); return self; } @@ -1188,6 +1216,162 @@ static MaplibreMapLibreHostApiAddGeoJsonSourceResponse* maplibre_map_libre_host_ return self; } +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddImageSourceResponse, maplibre_map_libre_host_api_add_image_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_IMAGE_SOURCE_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddImageSourceResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddImageSourceResponse, maplibre_map_libre_host_api_add_image_source_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_image_source_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddImageSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_IMAGE_SOURCE_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_image_source_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_image_source_response_init(MaplibreMapLibreHostApiAddImageSourceResponse* self) { +} + +static void maplibre_map_libre_host_api_add_image_source_response_class_init(MaplibreMapLibreHostApiAddImageSourceResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_image_source_response_dispose; +} + +static MaplibreMapLibreHostApiAddImageSourceResponse* maplibre_map_libre_host_api_add_image_source_response_new() { + MaplibreMapLibreHostApiAddImageSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_IMAGE_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_image_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddImageSourceResponse* maplibre_map_libre_host_api_add_image_source_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddImageSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_IMAGE_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_image_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddRasterSourceResponse, maplibre_map_libre_host_api_add_raster_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_RASTER_SOURCE_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddRasterSourceResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddRasterSourceResponse, maplibre_map_libre_host_api_add_raster_source_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_raster_source_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddRasterSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_SOURCE_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_raster_source_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_raster_source_response_init(MaplibreMapLibreHostApiAddRasterSourceResponse* self) { +} + +static void maplibre_map_libre_host_api_add_raster_source_response_class_init(MaplibreMapLibreHostApiAddRasterSourceResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_raster_source_response_dispose; +} + +static MaplibreMapLibreHostApiAddRasterSourceResponse* maplibre_map_libre_host_api_add_raster_source_response_new() { + MaplibreMapLibreHostApiAddRasterSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddRasterSourceResponse* maplibre_map_libre_host_api_add_raster_source_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddRasterSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddRasterDemSourceResponse, maplibre_map_libre_host_api_add_raster_dem_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_RASTER_DEM_SOURCE_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddRasterDemSourceResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddRasterDemSourceResponse, maplibre_map_libre_host_api_add_raster_dem_source_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_raster_dem_source_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddRasterDemSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_DEM_SOURCE_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_raster_dem_source_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_raster_dem_source_response_init(MaplibreMapLibreHostApiAddRasterDemSourceResponse* self) { +} + +static void maplibre_map_libre_host_api_add_raster_dem_source_response_class_init(MaplibreMapLibreHostApiAddRasterDemSourceResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_raster_dem_source_response_dispose; +} + +static MaplibreMapLibreHostApiAddRasterDemSourceResponse* maplibre_map_libre_host_api_add_raster_dem_source_response_new() { + MaplibreMapLibreHostApiAddRasterDemSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_DEM_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_dem_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddRasterDemSourceResponse* maplibre_map_libre_host_api_add_raster_dem_source_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddRasterDemSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_RASTER_DEM_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_raster_dem_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddVectorSourceResponse, maplibre_map_libre_host_api_add_vector_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_VECTOR_SOURCE_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiAddVectorSourceResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiAddVectorSourceResponse, maplibre_map_libre_host_api_add_vector_source_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_add_vector_source_response_dispose(GObject* object) { + MaplibreMapLibreHostApiAddVectorSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_VECTOR_SOURCE_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_add_vector_source_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_add_vector_source_response_init(MaplibreMapLibreHostApiAddVectorSourceResponse* self) { +} + +static void maplibre_map_libre_host_api_add_vector_source_response_class_init(MaplibreMapLibreHostApiAddVectorSourceResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_add_vector_source_response_dispose; +} + +static MaplibreMapLibreHostApiAddVectorSourceResponse* maplibre_map_libre_host_api_add_vector_source_response_new() { + MaplibreMapLibreHostApiAddVectorSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_VECTOR_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_vector_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiAddVectorSourceResponse* maplibre_map_libre_host_api_add_vector_source_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiAddVectorSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_ADD_VECTOR_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_add_vector_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + struct _MaplibreMapLibreHostApiGetMetersPerPixelAtLatitudeResponse { GObject parent_instance; @@ -1585,6 +1769,124 @@ static void maplibre_map_libre_host_api_add_geo_json_source_cb(FlBasicMessageCha self->vtable->add_geo_json_source(id, data, handle, self->user_data); } +static void maplibre_map_libre_host_api_add_image_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_image_source == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* url = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* coordinates = value2; + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_image_source(id, url, coordinates, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_raster_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_raster_source == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* url = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* tiles = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* bounds = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + double min_zoom = fl_value_get_float(value4); + FlValue* value5 = fl_value_get_list_value(message_, 5); + double max_zoom = fl_value_get_float(value5); + FlValue* value6 = fl_value_get_list_value(message_, 6); + int64_t tile_size = fl_value_get_int(value6); + FlValue* value7 = fl_value_get_list_value(message_, 7); + MaplibreTileScheme scheme = static_cast(fl_value_get_int(reinterpret_cast(const_cast(fl_value_get_custom_value(value7))))); + FlValue* value8 = fl_value_get_list_value(message_, 8); + const gchar* attribution = fl_value_get_string(value8); + FlValue* value9 = fl_value_get_list_value(message_, 9); + gboolean volatile = fl_value_get_bool(value9); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_raster_source(id, url, tiles, bounds, min_zoom, max_zoom, tile_size, scheme, attribution, volatile, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_raster_dem_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_raster_dem_source == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* url = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* tiles = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* bounds = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + double min_zoom = fl_value_get_float(value4); + FlValue* value5 = fl_value_get_list_value(message_, 5); + double max_zoom = fl_value_get_float(value5); + FlValue* value6 = fl_value_get_list_value(message_, 6); + int64_t tile_size = fl_value_get_int(value6); + FlValue* value7 = fl_value_get_list_value(message_, 7); + const gchar* attribution = fl_value_get_string(value7); + FlValue* value8 = fl_value_get_list_value(message_, 8); + MaplibreRasterDemEncoding encoding = static_cast(fl_value_get_int(reinterpret_cast(const_cast(fl_value_get_custom_value(value8))))); + FlValue* value9 = fl_value_get_list_value(message_, 9); + gboolean volatile = fl_value_get_bool(value9); + FlValue* value10 = fl_value_get_list_value(message_, 10); + double red_factor = fl_value_get_float(value10); + FlValue* value11 = fl_value_get_list_value(message_, 11); + double blue_factor = fl_value_get_float(value11); + FlValue* value12 = fl_value_get_list_value(message_, 12); + double green_factor = fl_value_get_float(value12); + FlValue* value13 = fl_value_get_list_value(message_, 13); + double base_shift = fl_value_get_float(value13); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_raster_dem_source(id, url, tiles, bounds, min_zoom, max_zoom, tile_size, attribution, encoding, volatile, red_factor, blue_factor, green_factor, base_shift, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_add_vector_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->add_vector_source == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + FlValue* value1 = fl_value_get_list_value(message_, 1); + const gchar* url = fl_value_get_string(value1); + FlValue* value2 = fl_value_get_list_value(message_, 2); + FlValue* tiles = value2; + FlValue* value3 = fl_value_get_list_value(message_, 3); + FlValue* bounds = value3; + FlValue* value4 = fl_value_get_list_value(message_, 4); + MaplibreTileScheme scheme = static_cast(fl_value_get_int(reinterpret_cast(const_cast(fl_value_get_custom_value(value4))))); + FlValue* value5 = fl_value_get_list_value(message_, 5); + double min_zoom = fl_value_get_float(value5); + FlValue* value6 = fl_value_get_list_value(message_, 6); + double max_zoom = fl_value_get_float(value6); + FlValue* value7 = fl_value_get_list_value(message_, 7); + const gchar* attribution = fl_value_get_string(value7); + FlValue* value8 = fl_value_get_list_value(message_, 8); + gboolean volatile = fl_value_get_bool(value8); + FlValue* value9 = fl_value_get_list_value(message_, 9); + const gchar* source_layer = fl_value_get_string(value9); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->add_vector_source(id, url, tiles, bounds, scheme, min_zoom, max_zoom, attribution, volatile, source_layer, handle, self->user_data); +} + static void maplibre_map_libre_host_api_get_meters_per_pixel_at_latitude_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); @@ -1659,6 +1961,18 @@ void maplibre_map_libre_host_api_set_method_handlers(FlBinaryMessenger* messenge g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, maplibre_map_libre_host_api_add_geo_json_source_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_image_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_image_source_channel = fl_basic_message_channel_new(messenger, add_image_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_image_source_channel, maplibre_map_libre_host_api_add_image_source_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_raster_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_source_channel = fl_basic_message_channel_new(messenger, add_raster_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_source_channel, maplibre_map_libre_host_api_add_raster_source_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_raster_dem_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_dem_source_channel = fl_basic_message_channel_new(messenger, add_raster_dem_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_dem_source_channel, maplibre_map_libre_host_api_add_raster_dem_source_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* add_vector_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_vector_source_channel = fl_basic_message_channel_new(messenger, add_vector_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_vector_source_channel, maplibre_map_libre_host_api_add_vector_source_cb, g_object_ref(api_data), g_object_unref); g_autofree gchar* get_meters_per_pixel_at_latitude_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude%s", dot_suffix); g_autoptr(FlBasicMessageChannel) get_meters_per_pixel_at_latitude_channel = fl_basic_message_channel_new(messenger, get_meters_per_pixel_at_latitude_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(get_meters_per_pixel_at_latitude_channel, maplibre_map_libre_host_api_get_meters_per_pixel_at_latitude_cb, g_object_ref(api_data), g_object_unref); @@ -1716,6 +2030,18 @@ void maplibre_map_libre_host_api_clear_method_handlers(FlBinaryMessenger* messen g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_image_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_image_source_channel = fl_basic_message_channel_new(messenger, add_image_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_image_source_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_raster_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_source_channel = fl_basic_message_channel_new(messenger, add_raster_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_source_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_raster_dem_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_raster_dem_source_channel = fl_basic_message_channel_new(messenger, add_raster_dem_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_raster_dem_source_channel, nullptr, nullptr, nullptr); + g_autofree gchar* add_vector_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) add_vector_source_channel = fl_basic_message_channel_new(messenger, add_vector_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(add_vector_source_channel, nullptr, nullptr, nullptr); g_autofree gchar* get_meters_per_pixel_at_latitude_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude%s", dot_suffix); g_autoptr(FlBasicMessageChannel) get_meters_per_pixel_at_latitude_channel = fl_basic_message_channel_new(messenger, get_meters_per_pixel_at_latitude_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(get_meters_per_pixel_at_latitude_channel, nullptr, nullptr, nullptr); @@ -1977,6 +2303,70 @@ void maplibre_map_libre_host_api_respond_error_add_geo_json_source(MaplibreMapLi } } +void maplibre_map_libre_host_api_respond_add_image_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddImageSourceResponse) response = maplibre_map_libre_host_api_add_image_source_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addImageSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_image_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddImageSourceResponse) response = maplibre_map_libre_host_api_add_image_source_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addImageSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_raster_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddRasterSourceResponse) response = maplibre_map_libre_host_api_add_raster_source_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_raster_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddRasterSourceResponse) response = maplibre_map_libre_host_api_add_raster_source_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_raster_dem_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddRasterDemSourceResponse) response = maplibre_map_libre_host_api_add_raster_dem_source_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterDemSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_raster_dem_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddRasterDemSourceResponse) response = maplibre_map_libre_host_api_add_raster_dem_source_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addRasterDemSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_add_vector_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiAddVectorSourceResponse) response = maplibre_map_libre_host_api_add_vector_source_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addVectorSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_add_vector_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiAddVectorSourceResponse) response = maplibre_map_libre_host_api_add_vector_source_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "addVectorSource", error->message); + } +} + struct _MaplibreMapLibreFlutterApi { GObject parent_instance; @@ -2234,7 +2624,7 @@ static void maplibre_map_libre_flutter_api_on_click_cb(GObject* object, GAsyncRe void maplibre_map_libre_flutter_api_on_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(130, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(132, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -2313,7 +2703,7 @@ static void maplibre_map_libre_flutter_api_on_secondary_click_cb(GObject* object void maplibre_map_libre_flutter_api_on_secondary_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(130, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(132, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onSecondaryClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -2392,7 +2782,7 @@ static void maplibre_map_libre_flutter_api_on_double_click_cb(GObject* object, G void maplibre_map_libre_flutter_api_on_double_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(130, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(132, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onDoubleClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); @@ -2471,7 +2861,7 @@ static void maplibre_map_libre_flutter_api_on_long_click_cb(GObject* object, GAs void maplibre_map_libre_flutter_api_on_long_click(MaplibreMapLibreFlutterApi* self, MaplibreLngLat* point, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(FlValue) args = fl_value_new_list(); - fl_value_append_take(args, fl_value_new_custom_object(130, G_OBJECT(point))); + fl_value_append_take(args, fl_value_new_custom_object(132, G_OBJECT(point))); g_autofree gchar* channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreFlutterApi.onLongClick%s", self->suffix); g_autoptr(MaplibreMessageCodec) codec = maplibre_message_codec_new(); FlBasicMessageChannel* channel = fl_basic_message_channel_new(self->messenger, channel_name, FL_MESSAGE_CODEC(codec)); diff --git a/linux/pigeon.g.h b/linux/pigeon.g.h index ef34e78d..a620aecc 100644 --- a/linux/pigeon.g.h +++ b/linux/pigeon.g.h @@ -8,6 +8,38 @@ G_BEGIN_DECLS +/** + * MaplibreTileScheme: + * MAPLIBRE_TILE_SCHEME_XYZ: + * Slippy map tilenames scheme. + * MAPLIBRE_TILE_SCHEME_TMS: + * OSGeo spec scheme. + * + * Influences the y direction of the tile coordinates. + */ +typedef enum { + MAPLIBRE_TILE_SCHEME_XYZ = 0, + MAPLIBRE_TILE_SCHEME_TMS = 1 +} MaplibreTileScheme; + +/** + * MaplibreRasterDemEncoding: + * MAPLIBRE_RASTER_DEM_ENCODING_TERRARIUM: + * Terrarium format PNG tiles. + * MAPLIBRE_RASTER_DEM_ENCODING_MAPBOX: + * Mapbox Terrain RGB tiles. + * MAPLIBRE_RASTER_DEM_ENCODING_CUSTOM: + * Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + * parameters. + * + * The encoding used by this source. Mapbox Terrain RGB is used by default. + */ +typedef enum { + MAPLIBRE_RASTER_DEM_ENCODING_TERRARIUM = 0, + MAPLIBRE_RASTER_DEM_ENCODING_MAPBOX = 1, + MAPLIBRE_RASTER_DEM_ENCODING_CUSTOM = 2 +} MaplibreRasterDemEncoding; + /** * MaplibreMapOptions: * @@ -349,6 +381,10 @@ typedef struct { void (*add_raster_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_symbol_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_geo_json_source)(const gchar* id, const gchar* data, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_image_source)(const gchar* id, const gchar* url, FlValue* coordinates, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_raster_source)(const gchar* id, const gchar* url, FlValue* tiles, FlValue* bounds, double min_zoom, double max_zoom, int64_t tile_size, MaplibreTileScheme scheme, const gchar* attribution, gboolean volatile, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_raster_dem_source)(const gchar* id, const gchar* url, FlValue* tiles, FlValue* bounds, double min_zoom, double max_zoom, int64_t tile_size, const gchar* attribution, MaplibreRasterDemEncoding encoding, gboolean volatile, double red_factor, double blue_factor, double green_factor, double base_shift, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*add_vector_source)(const gchar* id, const gchar* url, FlValue* tiles, FlValue* bounds, MaplibreTileScheme scheme, double min_zoom, double max_zoom, const gchar* attribution, gboolean volatile, const gchar* source_layer, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); MaplibreMapLibreHostApiGetMetersPerPixelAtLatitudeResponse* (*get_meters_per_pixel_at_latitude)(double latitude, gpointer user_data); } MaplibreMapLibreHostApiVTable; @@ -683,6 +719,82 @@ void maplibre_map_libre_host_api_respond_add_geo_json_source(MaplibreMapLibreHos */ void maplibre_map_libre_host_api_respond_error_add_geo_json_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); +/** + * maplibre_map_libre_host_api_respond_add_image_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addImageSource. + */ +void maplibre_map_libre_host_api_respond_add_image_source(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_image_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addImageSource. + */ +void maplibre_map_libre_host_api_respond_error_add_image_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_raster_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addRasterSource. + */ +void maplibre_map_libre_host_api_respond_add_raster_source(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_raster_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addRasterSource. + */ +void maplibre_map_libre_host_api_respond_error_add_raster_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_raster_dem_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addRasterDemSource. + */ +void maplibre_map_libre_host_api_respond_add_raster_dem_source(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_raster_dem_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addRasterDemSource. + */ +void maplibre_map_libre_host_api_respond_error_add_raster_dem_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_add_vector_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.addVectorSource. + */ +void maplibre_map_libre_host_api_respond_add_vector_source(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_add_vector_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.addVectorSource. + */ +void maplibre_map_libre_host_api_respond_error_add_vector_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + G_DECLARE_FINAL_TYPE(MaplibreMapLibreFlutterApiGetOptionsResponse, maplibre_map_libre_flutter_api_get_options_response, MAPLIBRE, MAP_LIBRE_FLUTTER_API_GET_OPTIONS_RESPONSE, GObject) /** diff --git a/macos/Classes/Pigeon.g.swift b/macos/Classes/Pigeon.g.swift index d83ae957..532573ec 100644 --- a/macos/Classes/Pigeon.g.swift +++ b/macos/Classes/Pigeon.g.swift @@ -68,6 +68,25 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } +/// Influences the y direction of the tile coordinates. +enum TileScheme: Int { + /// Slippy map tilenames scheme. + case xyz = 0 + /// OSGeo spec scheme. + case tms = 1 +} + +/// The encoding used by this source. Mapbox Terrain RGB is used by default. +enum RasterDemEncoding: Int { + /// Terrarium format PNG tiles. + case terrarium = 0 + /// Mapbox Terrain RGB tiles. + case mapbox = 1 + /// Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + /// parameters. + case custom = 2 +} + /// The map options define initial values for the MapLibre map. /// /// Generated class from Pigeon that represents data sent in messages. @@ -254,14 +273,26 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { case 129: - return MapOptions.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return TileScheme(rawValue: enumResultAsInt) + } + return nil case 130: - return LngLat.fromList(self.readValue() as! [Any?]) + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) + if let enumResultAsInt = enumResultAsInt { + return RasterDemEncoding(rawValue: enumResultAsInt) + } + return nil case 131: - return ScreenLocation.fromList(self.readValue() as! [Any?]) + return MapOptions.fromList(self.readValue() as! [Any?]) case 132: - return MapCamera.fromList(self.readValue() as! [Any?]) + return LngLat.fromList(self.readValue() as! [Any?]) case 133: + return ScreenLocation.fromList(self.readValue() as! [Any?]) + case 134: + return MapCamera.fromList(self.readValue() as! [Any?]) + case 135: return LngLatBounds.fromList(self.readValue() as! [Any?]) default: return super.readValue(ofType: type) @@ -271,20 +302,26 @@ private class PigeonPigeonCodecReader: FlutterStandardReader { private class PigeonPigeonCodecWriter: FlutterStandardWriter { override func writeValue(_ value: Any) { - if let value = value as? MapOptions { + if let value = value as? TileScheme { super.writeByte(129) + super.writeValue(value.rawValue) + } else if let value = value as? RasterDemEncoding { + super.writeByte(130) + super.writeValue(value.rawValue) + } else if let value = value as? MapOptions { + super.writeByte(131) super.writeValue(value.toList()) } else if let value = value as? LngLat { - super.writeByte(130) + super.writeByte(132) super.writeValue(value.toList()) } else if let value = value as? ScreenLocation { - super.writeByte(131) + super.writeByte(133) super.writeValue(value.toList()) } else if let value = value as? MapCamera { - super.writeByte(132) + super.writeByte(134) super.writeValue(value.toList()) } else if let value = value as? LngLatBounds { - super.writeByte(133) + super.writeByte(135) super.writeValue(value.toList()) } else { super.writeValue(value) @@ -342,6 +379,14 @@ protocol MapLibreHostApi { func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) + /// Add a image source to the map style. + func addImageSource(id: String, url: String, coordinates: [LngLat], completion: @escaping (Result) -> Void) + /// Add a raster source to the map style. + func addRasterSource(id: String, url: String?, tiles: [String]?, bounds: [Double], minZoom: Double, maxZoom: Double, tileSize: Int64, scheme: TileScheme, attribution: String?, volatile: Bool, completion: @escaping (Result) -> Void) + /// Add a raster DEM source to the map style. + func addRasterDemSource(id: String, url: String?, tiles: [String]?, bounds: [Double], minZoom: Double, maxZoom: Double, tileSize: Int64, attribution: String?, encoding: RasterDemEncoding, volatile: Bool, redFactor: Double, blueFactor: Double, greenFactor: Double, baseShift: Double, completion: @escaping (Result) -> Void) + /// Add a vector source to the map style. + func addVectorSource(id: String, url: String?, tiles: [String]?, bounds: [Double], scheme: TileScheme, minZoom: Double, maxZoom: Double, attribution: String?, volatile: Bool, sourceLayer: String?, completion: @escaping (Result) -> Void) /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. func getMetersPerPixelAtLatitude(latitude: Double) throws -> Double @@ -683,6 +728,111 @@ class MapLibreHostApiSetup { } else { addGeoJsonSourceChannel.setMessageHandler(nil) } + /// Add a image source to the map style. + let addImageSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addImageSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg = args[1] as! String + let coordinatesArg = args[2] as! [LngLat] + api.addImageSource(id: idArg, url: urlArg, coordinates: coordinatesArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addImageSourceChannel.setMessageHandler(nil) + } + /// Add a raster source to the map style. + let addRasterSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let minZoomArg = args[4] as! Double + let maxZoomArg = args[5] as! Double + let tileSizeArg = args[6] as! Int64 + let schemeArg = args[7] as! TileScheme + let attributionArg: String? = nilOrValue(args[8]) + let volatileArg = args[9] as! Bool + api.addRasterSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, minZoom: minZoomArg, maxZoom: maxZoomArg, tileSize: tileSizeArg, scheme: schemeArg, attribution: attributionArg, volatile: volatileArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterSourceChannel.setMessageHandler(nil) + } + /// Add a raster DEM source to the map style. + let addRasterDemSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addRasterDemSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let minZoomArg = args[4] as! Double + let maxZoomArg = args[5] as! Double + let tileSizeArg = args[6] as! Int64 + let attributionArg: String? = nilOrValue(args[7]) + let encodingArg = args[8] as! RasterDemEncoding + let volatileArg = args[9] as! Bool + let redFactorArg = args[10] as! Double + let blueFactorArg = args[11] as! Double + let greenFactorArg = args[12] as! Double + let baseShiftArg = args[13] as! Double + api.addRasterDemSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, minZoom: minZoomArg, maxZoom: maxZoomArg, tileSize: tileSizeArg, attribution: attributionArg, encoding: encodingArg, volatile: volatileArg, redFactor: redFactorArg, blueFactor: blueFactorArg, greenFactor: greenFactorArg, baseShift: baseShiftArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addRasterDemSourceChannel.setMessageHandler(nil) + } + /// Add a vector source to the map style. + let addVectorSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + addVectorSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + let urlArg: String? = nilOrValue(args[1]) + let tilesArg: [String]? = nilOrValue(args[2]) + let boundsArg = args[3] as! [Double] + let schemeArg = args[4] as! TileScheme + let minZoomArg = args[5] as! Double + let maxZoomArg = args[6] as! Double + let attributionArg: String? = nilOrValue(args[7]) + let volatileArg = args[8] as! Bool + let sourceLayerArg: String? = nilOrValue(args[9]) + api.addVectorSource(id: idArg, url: urlArg, tiles: tilesArg, bounds: boundsArg, scheme: schemeArg, minZoom: minZoomArg, maxZoom: maxZoomArg, attribution: attributionArg, volatile: volatileArg, sourceLayer: sourceLayerArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + addVectorSourceChannel.setMessageHandler(nil) + } /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. let getMetersPerPixelAtLatitudeChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index eaeafa44..18a729e8 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -155,6 +155,63 @@ abstract interface class MapLibreHostApi { required String data, }); + /// Add a image source to the map style. + @async + void addImageSource({ + required String id, + required String url, + required List coordinates, + }); + + /// Add a raster source to the map style. + @async + void addRasterSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required double minZoom, + required double maxZoom, + required int tileSize, + required TileScheme scheme, + required String? attribution, + required bool volatile, + }); + + /// Add a raster DEM source to the map style. + @async + void addRasterDemSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required double minZoom, + required double maxZoom, + required int tileSize, + required String? attribution, + required RasterDemEncoding encoding, + required bool volatile, + double redFactor = 1, + double blueFactor = 1, + double greenFactor = 1, + double baseShift = 0, + }); + + /// Add a vector source to the map style. + @async + void addVectorSource({ + required String id, + required String? url, + required List? tiles, + required List bounds, + required TileScheme scheme, + required double minZoom, + required double maxZoom, + required String? attribution, + required bool volatile, + required String? sourceLayer, + }); + /// Returns the distance spanned by one pixel at the specified latitude and /// current zoom level. double getMetersPerPixelAtLatitude(double latitude); @@ -267,3 +324,25 @@ class LngLatBounds { final double latitudeSouth; final double latitudeNorth; } + +/// Influences the y direction of the tile coordinates. +enum TileScheme { + /// Slippy map tilenames scheme. + xyz, + + /// OSGeo spec scheme. + tms; +} + +/// The encoding used by this source. Mapbox Terrain RGB is used by default. +enum RasterDemEncoding { + /// Terrarium format PNG tiles. + terrarium, + + /// Mapbox Terrain RGB tiles. + mapbox, + + /// Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + /// parameters. + custom; +} diff --git a/windows/runner/pigeon.g.cpp b/windows/runner/pigeon.g.cpp index be1b35bd..fd4c30c9 100644 --- a/windows/runner/pigeon.g.cpp +++ b/windows/runner/pigeon.g.cpp @@ -413,18 +413,28 @@ EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( flutter::ByteStreamReader* stream) const { switch (type) { case 129: { - return CustomEncodableValue(MapOptions::FromEncodableList(std::get(ReadValue(stream)))); + const auto& encodable_enum_arg = ReadValue(stream); + const int64_t enum_arg_value = encodable_enum_arg.IsNull() ? 0 : encodable_enum_arg.LongValue(); + return encodable_enum_arg.IsNull() ? EncodableValue() : CustomEncodableValue(static_cast(enum_arg_value)); } case 130: { - return CustomEncodableValue(LngLat::FromEncodableList(std::get(ReadValue(stream)))); + const auto& encodable_enum_arg = ReadValue(stream); + const int64_t enum_arg_value = encodable_enum_arg.IsNull() ? 0 : encodable_enum_arg.LongValue(); + return encodable_enum_arg.IsNull() ? EncodableValue() : CustomEncodableValue(static_cast(enum_arg_value)); } case 131: { - return CustomEncodableValue(ScreenLocation::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(MapOptions::FromEncodableList(std::get(ReadValue(stream)))); } case 132: { - return CustomEncodableValue(MapCamera::FromEncodableList(std::get(ReadValue(stream)))); + return CustomEncodableValue(LngLat::FromEncodableList(std::get(ReadValue(stream)))); } case 133: { + return CustomEncodableValue(ScreenLocation::FromEncodableList(std::get(ReadValue(stream)))); + } + case 134: { + return CustomEncodableValue(MapCamera::FromEncodableList(std::get(ReadValue(stream)))); + } + case 135: { return CustomEncodableValue(LngLatBounds::FromEncodableList(std::get(ReadValue(stream)))); } default: @@ -436,28 +446,38 @@ void PigeonInternalCodecSerializer::WriteValue( const EncodableValue& value, flutter::ByteStreamWriter* stream) const { if (const CustomEncodableValue* custom_value = std::get_if(&value)) { - if (custom_value->type() == typeid(MapOptions)) { + if (custom_value->type() == typeid(TileScheme)) { stream->WriteByte(129); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(RasterDemEncoding)) { + stream->WriteByte(130); + WriteValue(EncodableValue(static_cast(std::any_cast(*custom_value))), stream); + return; + } + if (custom_value->type() == typeid(MapOptions)) { + stream->WriteByte(131); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(LngLat)) { - stream->WriteByte(130); + stream->WriteByte(132); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(ScreenLocation)) { - stream->WriteByte(131); + stream->WriteByte(133); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(MapCamera)) { - stream->WriteByte(132); + stream->WriteByte(134); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } if (custom_value->type() == typeid(LngLatBounds)) { - stream->WriteByte(133); + stream->WriteByte(135); WriteValue(EncodableValue(std::any_cast(*custom_value).ToEncodableList()), stream); return; } @@ -1134,6 +1154,280 @@ void MapLibreHostApi::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addImageSource" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_url_arg = args.at(1); + if (encodable_url_arg.IsNull()) { + reply(WrapError("url_arg unexpectedly null.")); + return; + } + const auto& url_arg = std::get(encodable_url_arg); + const auto& encodable_coordinates_arg = args.at(2); + if (encodable_coordinates_arg.IsNull()) { + reply(WrapError("coordinates_arg unexpectedly null.")); + return; + } + const auto& coordinates_arg = std::get(encodable_coordinates_arg); + api->AddImageSource(id_arg, url_arg, coordinates_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterSource" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_url_arg = args.at(1); + const auto* url_arg = std::get_if(&encodable_url_arg); + const auto& encodable_tiles_arg = args.at(2); + const auto* tiles_arg = std::get_if(&encodable_tiles_arg); + const auto& encodable_bounds_arg = args.at(3); + if (encodable_bounds_arg.IsNull()) { + reply(WrapError("bounds_arg unexpectedly null.")); + return; + } + const auto& bounds_arg = std::get(encodable_bounds_arg); + const auto& encodable_min_zoom_arg = args.at(4); + if (encodable_min_zoom_arg.IsNull()) { + reply(WrapError("min_zoom_arg unexpectedly null.")); + return; + } + const auto& min_zoom_arg = std::get(encodable_min_zoom_arg); + const auto& encodable_max_zoom_arg = args.at(5); + if (encodable_max_zoom_arg.IsNull()) { + reply(WrapError("max_zoom_arg unexpectedly null.")); + return; + } + const auto& max_zoom_arg = std::get(encodable_max_zoom_arg); + const auto& encodable_tile_size_arg = args.at(6); + if (encodable_tile_size_arg.IsNull()) { + reply(WrapError("tile_size_arg unexpectedly null.")); + return; + } + const int64_t tile_size_arg = encodable_tile_size_arg.LongValue(); + const auto& encodable_scheme_arg = args.at(7); + if (encodable_scheme_arg.IsNull()) { + reply(WrapError("scheme_arg unexpectedly null.")); + return; + } + const auto& scheme_arg = std::any_cast(std::get(encodable_scheme_arg)); + const auto& encodable_attribution_arg = args.at(8); + const auto* attribution_arg = std::get_if(&encodable_attribution_arg); + const auto& encodable_volatile_arg = args.at(9); + if (encodable_volatile_arg.IsNull()) { + reply(WrapError("volatile_arg unexpectedly null.")); + return; + } + const auto& volatile_arg = std::get(encodable_volatile_arg); + api->AddRasterSource(id_arg, url_arg, tiles_arg, bounds_arg, min_zoom_arg, max_zoom_arg, tile_size_arg, scheme_arg, attribution_arg, volatile_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addRasterDemSource" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_url_arg = args.at(1); + const auto* url_arg = std::get_if(&encodable_url_arg); + const auto& encodable_tiles_arg = args.at(2); + const auto* tiles_arg = std::get_if(&encodable_tiles_arg); + const auto& encodable_bounds_arg = args.at(3); + if (encodable_bounds_arg.IsNull()) { + reply(WrapError("bounds_arg unexpectedly null.")); + return; + } + const auto& bounds_arg = std::get(encodable_bounds_arg); + const auto& encodable_min_zoom_arg = args.at(4); + if (encodable_min_zoom_arg.IsNull()) { + reply(WrapError("min_zoom_arg unexpectedly null.")); + return; + } + const auto& min_zoom_arg = std::get(encodable_min_zoom_arg); + const auto& encodable_max_zoom_arg = args.at(5); + if (encodable_max_zoom_arg.IsNull()) { + reply(WrapError("max_zoom_arg unexpectedly null.")); + return; + } + const auto& max_zoom_arg = std::get(encodable_max_zoom_arg); + const auto& encodable_tile_size_arg = args.at(6); + if (encodable_tile_size_arg.IsNull()) { + reply(WrapError("tile_size_arg unexpectedly null.")); + return; + } + const int64_t tile_size_arg = encodable_tile_size_arg.LongValue(); + const auto& encodable_attribution_arg = args.at(7); + const auto* attribution_arg = std::get_if(&encodable_attribution_arg); + const auto& encodable_encoding_arg = args.at(8); + if (encodable_encoding_arg.IsNull()) { + reply(WrapError("encoding_arg unexpectedly null.")); + return; + } + const auto& encoding_arg = std::any_cast(std::get(encodable_encoding_arg)); + const auto& encodable_volatile_arg = args.at(9); + if (encodable_volatile_arg.IsNull()) { + reply(WrapError("volatile_arg unexpectedly null.")); + return; + } + const auto& volatile_arg = std::get(encodable_volatile_arg); + const auto& encodable_red_factor_arg = args.at(10); + if (encodable_red_factor_arg.IsNull()) { + reply(WrapError("red_factor_arg unexpectedly null.")); + return; + } + const auto& red_factor_arg = std::get(encodable_red_factor_arg); + const auto& encodable_blue_factor_arg = args.at(11); + if (encodable_blue_factor_arg.IsNull()) { + reply(WrapError("blue_factor_arg unexpectedly null.")); + return; + } + const auto& blue_factor_arg = std::get(encodable_blue_factor_arg); + const auto& encodable_green_factor_arg = args.at(12); + if (encodable_green_factor_arg.IsNull()) { + reply(WrapError("green_factor_arg unexpectedly null.")); + return; + } + const auto& green_factor_arg = std::get(encodable_green_factor_arg); + const auto& encodable_base_shift_arg = args.at(13); + if (encodable_base_shift_arg.IsNull()) { + reply(WrapError("base_shift_arg unexpectedly null.")); + return; + } + const auto& base_shift_arg = std::get(encodable_base_shift_arg); + api->AddRasterDemSource(id_arg, url_arg, tiles_arg, bounds_arg, min_zoom_arg, max_zoom_arg, tile_size_arg, attribution_arg, encoding_arg, volatile_arg, red_factor_arg, blue_factor_arg, green_factor_arg, base_shift_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addVectorSource" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + const auto& encodable_url_arg = args.at(1); + const auto* url_arg = std::get_if(&encodable_url_arg); + const auto& encodable_tiles_arg = args.at(2); + const auto* tiles_arg = std::get_if(&encodable_tiles_arg); + const auto& encodable_bounds_arg = args.at(3); + if (encodable_bounds_arg.IsNull()) { + reply(WrapError("bounds_arg unexpectedly null.")); + return; + } + const auto& bounds_arg = std::get(encodable_bounds_arg); + const auto& encodable_scheme_arg = args.at(4); + if (encodable_scheme_arg.IsNull()) { + reply(WrapError("scheme_arg unexpectedly null.")); + return; + } + const auto& scheme_arg = std::any_cast(std::get(encodable_scheme_arg)); + const auto& encodable_min_zoom_arg = args.at(5); + if (encodable_min_zoom_arg.IsNull()) { + reply(WrapError("min_zoom_arg unexpectedly null.")); + return; + } + const auto& min_zoom_arg = std::get(encodable_min_zoom_arg); + const auto& encodable_max_zoom_arg = args.at(6); + if (encodable_max_zoom_arg.IsNull()) { + reply(WrapError("max_zoom_arg unexpectedly null.")); + return; + } + const auto& max_zoom_arg = std::get(encodable_max_zoom_arg); + const auto& encodable_attribution_arg = args.at(7); + const auto* attribution_arg = std::get_if(&encodable_attribution_arg); + const auto& encodable_volatile_arg = args.at(8); + if (encodable_volatile_arg.IsNull()) { + reply(WrapError("volatile_arg unexpectedly null.")); + return; + } + const auto& volatile_arg = std::get(encodable_volatile_arg); + const auto& encodable_source_layer_arg = args.at(9); + const auto* source_layer_arg = std::get_if(&encodable_source_layer_arg); + api->AddVectorSource(id_arg, url_arg, tiles_arg, bounds_arg, scheme_arg, min_zoom_arg, max_zoom_arg, attribution_arg, volatile_arg, source_layer_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.getMetersPerPixelAtLatitude" + prepended_suffix, &GetCodec()); if (api != nullptr) { diff --git a/windows/runner/pigeon.g.h b/windows/runner/pigeon.g.h index b2c6c8a7..07079310 100644 --- a/windows/runner/pigeon.g.h +++ b/windows/runner/pigeon.g.h @@ -57,6 +57,25 @@ template class ErrorOr { }; +// Influences the y direction of the tile coordinates. +enum class TileScheme { + // Slippy map tilenames scheme. + kXyz = 0, + // OSGeo spec scheme. + kTms = 1 +}; + +// The encoding used by this source. Mapbox Terrain RGB is used by default. +enum class RasterDemEncoding { + // Terrarium format PNG tiles. + kTerrarium = 0, + // Mapbox Terrain RGB tiles. + kMapbox = 1, + // Decodes tiles using the redFactor, blueFactor, greenFactor, baseShift + // parameters. + kCustom = 2 +}; + // The map options define initial values for the MapLibre map. // @@ -412,6 +431,55 @@ class MapLibreHostApi { const std::string& id, const std::string& data, std::function reply)> result) = 0; + // Add a image source to the map style. + virtual void AddImageSource( + const std::string& id, + const std::string& url, + const flutter::EncodableList& coordinates, + std::function reply)> result) = 0; + // Add a raster source to the map style. + virtual void AddRasterSource( + const std::string& id, + const std::string* url, + const flutter::EncodableList* tiles, + const flutter::EncodableList& bounds, + double min_zoom, + double max_zoom, + int64_t tile_size, + const TileScheme& scheme, + const std::string* attribution, + bool volatile, + std::function reply)> result) = 0; + // Add a raster DEM source to the map style. + virtual void AddRasterDemSource( + const std::string& id, + const std::string* url, + const flutter::EncodableList* tiles, + const flutter::EncodableList& bounds, + double min_zoom, + double max_zoom, + int64_t tile_size, + const std::string* attribution, + const RasterDemEncoding& encoding, + bool volatile, + double red_factor, + double blue_factor, + double green_factor, + double base_shift, + std::function reply)> result) = 0; + // Add a vector source to the map style. + virtual void AddVectorSource( + const std::string& id, + const std::string* url, + const flutter::EncodableList* tiles, + const flutter::EncodableList& bounds, + const TileScheme& scheme, + double min_zoom, + double max_zoom, + const std::string* attribution, + bool volatile, + const std::string* source_layer, + std::function reply)> result) = 0; // Returns the distance spanned by one pixel at the specified latitude and // current zoom level. virtual ErrorOr GetMetersPerPixelAtLatitude(double latitude) = 0; From 885d821699fd4ffb6958a475a939eb1b94afcd4a Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 03:34:29 +0200 Subject: [PATCH 11/24] use some more properties --- .../josxha/maplibre/MapLibreMapController.kt | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 2ffed441..f66698c1 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -11,6 +11,7 @@ import ScreenLocation import TileScheme import android.content.Context import android.graphics.PointF +import android.net.Uri import android.view.View import android.widget.FrameLayout import androidx.lifecycle.DefaultLifecycleObserver @@ -20,6 +21,7 @@ import org.maplibre.android.MapLibre import org.maplibre.android.camera.CameraPosition import org.maplibre.android.camera.CameraUpdateFactory import org.maplibre.android.geometry.LatLng +import org.maplibre.android.geometry.LatLngQuad import org.maplibre.android.maps.MapLibreMap import org.maplibre.android.maps.MapLibreMapOptions import org.maplibre.android.maps.MapView @@ -36,9 +38,13 @@ import org.maplibre.android.style.layers.PropertyValue import org.maplibre.android.style.layers.RasterLayer import org.maplibre.android.style.layers.SymbolLayer import org.maplibre.android.style.sources.GeoJsonSource +import org.maplibre.android.style.sources.ImageSource import org.maplibre.android.style.sources.RasterDemSource import org.maplibre.android.style.sources.RasterSource +import org.maplibre.android.style.sources.TileSet import org.maplibre.android.style.sources.VectorSource +import java.net.URI +import java.net.URL import kotlin.coroutines.cancellation.CancellationException class MapLibreMapController( @@ -387,7 +393,15 @@ class MapLibreMapController( coordinates: List, callback: (Result) -> Unit ) { - TODO("Not yet implemented") + val quad = LatLngQuad( + LatLng(coordinates[0].lat, coordinates[0].lng), + LatLng(coordinates[0].lat, coordinates[0].lng), + LatLng(coordinates[0].lat, coordinates[0].lng), + LatLng(coordinates[0].lat, coordinates[0].lng) + ) + val source = ImageSource(id, quad, URI(url)) + mapLibreMap.style?.addSource(source) + callback(Result.success(Unit)) } override fun addRasterSource( @@ -403,8 +417,10 @@ class MapLibreMapController( volatile: Boolean, callback: (Result) -> Unit ) { + val source = RasterSource(id, url, tileSize.toInt()) + source.isVolatile = volatile // TODO apply other properties - mapLibreMap.style?.addSource(RasterSource(id, url)) + mapLibreMap.style?.addSource(source) callback(Result.success(Unit)) } @@ -425,8 +441,10 @@ class MapLibreMapController( baseShift: Double, callback: (Result) -> Unit ) { + val source = RasterDemSource(id, url, tileSize.toInt()) + source.isVolatile = volatile // TODO apply other properties - mapLibreMap.style?.addSource(RasterDemSource(id, url)) + mapLibreMap.style?.addSource(source) callback(Result.success(Unit)) } @@ -443,8 +461,10 @@ class MapLibreMapController( sourceLayer: String?, callback: (Result) -> Unit ) { + val source = VectorSource(id, url) + source.isVolatile = volatile // TODO apply other properties - mapLibreMap.style?.addSource(VectorSource(id, url)) + mapLibreMap.style?.addSource(source) callback(Result.success(Unit)) } From 0cd762c3522a5c8608a760a33cd1e21c013aed74 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 12:53:49 +0200 Subject: [PATCH 12/24] create LayersPage --- example/lib/layers_page.dart | 217 ++++++++++++++++++++++++++++++++++ example/lib/main.dart | 2 + example/lib/menu_page.dart | 6 + lib/src/web/widget_state.dart | 7 +- 4 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 example/lib/layers_page.dart diff --git a/example/lib/layers_page.dart b/example/lib/layers_page.dart new file mode 100644 index 00000000..41499c09 --- /dev/null +++ b/example/lib/layers_page.dart @@ -0,0 +1,217 @@ +// ignore_for_file: prefer_single_quotes, require_trailing_commas + +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersPage extends StatefulWidget { + const LayersPage({super.key}); + + static const location = '/layers'; + + @override + State createState() => _LayersPageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceEarthquakesId = 'earthquakes'; + +class _LayersPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Controller')), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8), + child: Wrap( + spacing: 8, + runSpacing: 8, + children: [ + OutlinedButton( + onPressed: () async { + await _controller.addLayer(_heatmapLayer); + await _controller.flyTo( + center: Position(-120, 50), + zoom: 2, + ); + }, + child: const Text('Heatmap'), + ), + OutlinedButton( + onPressed: () async { + await _controller.addLayer(_circleLayer); + await _controller.flyTo( + center: Position(-152.9959, 59.8150), + zoom: 9, + ); + }, + child: const Text('Circle'), + ), + ], + ), + ), + Expanded( + child: MapLibreMap( + options: MapOptions( + center: Position(-120, 50), + onClick: (point) => debugPrint('${point.lng}, ${point.lat}'), + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ), + ], + ), + ); + } + + Future _onStyleLoaded() async { + const sourceEarthquakes = GeoJsonSource( + id: _sourceEarthquakesId, + data: + 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', + ); + await _controller.addSource(sourceEarthquakes); + } +} + +// TODO fill layer +// TODO fill extrusion layer +// TODO line layer +// TODO raster layer +// TODO hillshade layer + +const _heatmapLayer = HeatmapLayer( + id: _layerId, + sourceId: _sourceEarthquakesId, + paint: { + // Increase the heatmap weight based on frequency and property magnitude + 'heatmap-weight': [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 0, + 0, + 6, + 1 + ], + // Increase the heatmap color weight weight by zoom level + // heatmap-intensity is a multiplier on top of heatmap-weight + 'heatmap-intensity': [ + 'interpolate', + ['linear'], + ['zoom'], + 0, + 1, + 9, + 3 + ], + // Color ramp for heatmap. Domain is 0 (low) to 1 (high). + // Begin color ramp at 0-stop with a 0-transparency color + // to create a blur-like effect. + 'heatmap-color': [ + 'interpolate', + ['linear'], + ['heatmap-density'], + 0, + 'rgba(33,102,172,0)', + 0.2, + 'rgb(103,169,207)', + 0.4, + 'rgb(209,229,240)', + 0.6, + 'rgb(253,219,199)', + 0.8, + 'rgb(239,138,98)', + 1, + 'rgb(178,24,43)' + ], + // Adjust the heatmap radius by zoom level + 'heatmap-radius': [ + 'interpolate', + ['linear'], + ['zoom'], + 0, + 2, + 9, + 20 + ], + // Transition from heatmap to circle layer by zoom level + 'heatmap-opacity': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + 1, + 9, + 0 + ] + }, +); + +const _circleLayer = CircleLayer( + id: _layerId, + sourceId: _sourceEarthquakesId, + paint: { + // Size circle radius by earthquake magnitude and zoom level + 'circle-radius': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 1, + 6, + 4 + ], + 16, + [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 5, + 6, + 50 + ] + ], + // Color circle by earthquake magnitude + 'circle-color': [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 'rgba(33,102,172,0)', + 2, + 'rgb(103,169,207)', + 3, + 'rgb(209,229,240)', + 4, + 'rgb(253,219,199)', + 5, + 'rgb(239,138,98)', + 6, + 'rgb(178,24,43)' + ], + 'circle-stroke-color': 'white', + 'circle-stroke-width': 1, + // Transition from heatmap to circle layer by zoom level + 'circle-opacity': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + 0, + 8, + 1 + ] + }, +); diff --git a/example/lib/main.dart b/example/lib/main.dart index 819d64ad..5da19848 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,6 +3,7 @@ import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/kiosk_page.dart'; +import 'package:maplibre_example/layers_page.dart'; import 'package:maplibre_example/menu_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; @@ -25,6 +26,7 @@ class MyApp extends StatelessWidget { MenuPage.location: (context) => const MenuPage(), KioskPage.location: (context) => const KioskPage(), StyledMapPage.location: (context) => const StyledMapPage(), + LayersPage.location: (context) => const LayersPage(), WebControlsPage.location: (context) => const WebControlsPage(), GeoJsonPage.location: (context) => const GeoJsonPage(), CallbacksPage.location: (context) => const CallbacksPage(), diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 381e3ba9..380cd5c5 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/geojson_page.dart'; +import 'package:maplibre_example/layers_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; import 'package:maplibre_example/web_controls_page.dart'; @@ -30,6 +31,11 @@ class MenuPage extends StatelessWidget { iconData: Icons.location_on, location: GeoJsonPage.location, ), + ItemCard( + label: 'Layers', + iconData: Icons.layers, + location: LayersPage.location, + ), ItemCard( label: 'Callbacks', iconData: Icons.back_hand, diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 1fecfa57..0aa9bc92 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -259,7 +259,12 @@ final class MapLibreMapStateWeb extends State Future addSource(Source source) async { switch (source) { case GeoJsonSource(): - final data = parse(source.data); + JSAny data; + if (source.data[0] == '{') { + data = parse(source.data); + } else { + data = source.data.jsify()!; + } _map.addSource( source.id, interop.SourceSpecification.geoJson( From 999dc382955c47cf1c4e80dbfde60ea31ab92764 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:06:45 +0200 Subject: [PATCH 13/24] add `removeLayer()` and `removeSource()` --- .../josxha/maplibre/MapLibreMapController.kt | 11 ++ .../com/github/josxha/maplibre/Pigeon.g.kt | 42 +++++ example/lib/layers_page.dart | 2 + ios/Classes/Pigeon.g.swift | 40 +++++ lib/src/map_controller.dart | 6 + lib/src/native/pigeon.g.dart | 50 ++++++ lib/src/native/widget_state.dart | 6 + lib/src/web/interop/map.dart | 6 + lib/src/web/widget_state.dart | 6 + linux/pigeon.g.cc | 148 ++++++++++++++++++ linux/pigeon.g.h | 40 +++++ macos/Classes/Pigeon.g.swift | 40 +++++ pigeons/pigeon.dart | 8 + windows/runner/pigeon.g.cpp | 58 +++++++ windows/runner/pigeon.g.h | 8 + 15 files changed, 471 insertions(+) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index f66698c1..86a45d81 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -359,6 +359,17 @@ class MapLibreMapController( callback(Result.success(Unit)) } + override fun removeLayer(id: String, callback: (Result) -> Unit) { + mapLibreMap.style?.removeLayer(id) + callback(Result.success(Unit)) + + } + + override fun removeSource(id: String, callback: (Result) -> Unit) { + mapLibreMap.style?.removeSource(id) + callback(Result.success(Unit)) + } + override fun getCamera(callback: (Result) -> Unit) { val position = mapLibreMap.cameraPosition val target = mapLibreMap.cameraPosition.target!! diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt index 2cbbf60a..b72639fa 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/Pigeon.g.kt @@ -353,6 +353,10 @@ interface MapLibreHostApi { fun addRasterLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) /** Add a symbol layer to the map style. */ fun addSymbolLayer(id: String, sourceId: String, layout: Map, paint: Map, belowLayerId: String?, callback: (Result) -> Unit) + /** Removes the layer with the given ID from the map's style. */ + fun removeLayer(id: String, callback: (Result) -> Unit) + /** Removes the source with the given ID from the map's style. */ + fun removeSource(id: String, callback: (Result) -> Unit) /** Add a GeoJSON source to the map style. */ fun addGeoJsonSource(id: String, data: String, callback: (Result) -> Unit) /** Add a image source to the map style. */ @@ -707,6 +711,44 @@ interface MapLibreHostApi { channel.setMessageHandler(null) } } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + api.removeLayer(idArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val idArg = args[0] as String + api.removeSource(idArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } run { val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource$separatedMessageChannelSuffix", codec) if (api != null) { diff --git a/example/lib/layers_page.dart b/example/lib/layers_page.dart index 41499c09..3cb72bb3 100644 --- a/example/lib/layers_page.dart +++ b/example/lib/layers_page.dart @@ -33,6 +33,7 @@ class _LayersPageState extends State { children: [ OutlinedButton( onPressed: () async { + await _controller.removeLayer(_layerId); await _controller.addLayer(_heatmapLayer); await _controller.flyTo( center: Position(-120, 50), @@ -43,6 +44,7 @@ class _LayersPageState extends State { ), OutlinedButton( onPressed: () async { + await _controller.removeLayer(_layerId); await _controller.addLayer(_circleLayer); await _controller.flyTo( center: Position(-152.9959, 59.8150), diff --git a/ios/Classes/Pigeon.g.swift b/ios/Classes/Pigeon.g.swift index 532573ec..4f1b8843 100644 --- a/ios/Classes/Pigeon.g.swift +++ b/ios/Classes/Pigeon.g.swift @@ -377,6 +377,10 @@ protocol MapLibreHostApi { func addRasterLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a symbol layer to the map style. func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Removes the layer with the given ID from the map's style. + func removeLayer(id: String, completion: @escaping (Result) -> Void) + /// Removes the source with the given ID from the map's style. + func removeSource(id: String, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Add a image source to the map style. @@ -709,6 +713,42 @@ class MapLibreHostApiSetup { } else { addSymbolLayerChannel.setMessageHandler(nil) } + /// Removes the layer with the given ID from the map's style. + let removeLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.removeLayer(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeLayerChannel.setMessageHandler(nil) + } + /// Removes the source with the given ID from the map's style. + let removeSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.removeSource(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeSourceChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/lib/src/map_controller.dart b/lib/src/map_controller.dart index a9b6342b..54d154ae 100644 --- a/lib/src/map_controller.dart +++ b/lib/src/map_controller.dart @@ -46,6 +46,12 @@ abstract interface class MapController { /// of the layers array and appear visually above all other layers. Future addLayer(Layer layer, {String? belowLayerId}); + /// Removes the layer with the given ID from the map's style. + Future removeLayer(String id); + + /// Removes the source with the given ID from the map's style. + Future removeSource(String id); + /// Get the current camera position on the map. Future getCamera(); diff --git a/lib/src/native/pigeon.g.dart b/lib/src/native/pigeon.g.dart index c0ee1ba4..43f6bdaa 100644 --- a/lib/src/native/pigeon.g.dart +++ b/lib/src/native/pigeon.g.dart @@ -781,6 +781,56 @@ class MapLibreHostApi { } } + /// Removes the layer with the given ID from the map's style. + Future removeLayer(String id) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([id]) 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 { + return; + } + } + + /// Removes the source with the given ID from the map's style. + Future removeSource(String id) async { + final String pigeonVar_channelName = + 'dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([id]) 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 { + return; + } + } + /// Add a GeoJSON source to the map style. Future addGeoJsonSource( {required String id, required String data}) async { diff --git a/lib/src/native/widget_state.dart b/lib/src/native/widget_state.dart index f6cfbb69..0f3f508b 100644 --- a/lib/src/native/widget_state.dart +++ b/lib/src/native/widget_state.dart @@ -318,4 +318,10 @@ final class MapLibreMapStateNative extends State latitudeNorth: bounds.latitudeNorth, ); } + + @override + Future removeLayer(String id) async => _hostApi.removeLayer(id); + + @override + Future removeSource(String id) => _hostApi.removeSource(id); } diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index 31e79a86..5b0719f4 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -62,6 +62,12 @@ extension type JsMap._(Camera _) implements Camera { /// non-zero, the visible region is not an axis-aligned rectangle, and the /// result is the smallest bounds that encompasses the visible region. external LngLatBounds getBounds(); + + /// Removes the layer with the given ID from the map's style. + external void removeLayer(String id); + + /// Removes the source with the given ID from the map's style. + external void removeSource(String id); } /// Anonymous MapOptions for the MapLibre JavaScript [JsMap]. diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 0aa9bc92..058af458 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -432,4 +432,10 @@ final class MapLibreMapStateWeb extends State latitudeNorth: bounds.getNorth().toDouble(), ); } + + @override + Future removeLayer(String id) async => _map.removeLayer(id); + + @override + Future removeSource(String id) async => _map.removeSource(id); } diff --git a/linux/pigeon.g.cc b/linux/pigeon.g.cc index 61503bfd..6221db21 100644 --- a/linux/pigeon.g.cc +++ b/linux/pigeon.g.cc @@ -1177,6 +1177,84 @@ static MaplibreMapLibreHostApiAddSymbolLayerResponse* maplibre_map_libre_host_ap return self; } +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiRemoveLayerResponse, maplibre_map_libre_host_api_remove_layer_response, MAPLIBRE, MAP_LIBRE_HOST_API_REMOVE_LAYER_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiRemoveLayerResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiRemoveLayerResponse, maplibre_map_libre_host_api_remove_layer_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_remove_layer_response_dispose(GObject* object) { + MaplibreMapLibreHostApiRemoveLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_LAYER_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_remove_layer_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_remove_layer_response_init(MaplibreMapLibreHostApiRemoveLayerResponse* self) { +} + +static void maplibre_map_libre_host_api_remove_layer_response_class_init(MaplibreMapLibreHostApiRemoveLayerResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_remove_layer_response_dispose; +} + +static MaplibreMapLibreHostApiRemoveLayerResponse* maplibre_map_libre_host_api_remove_layer_response_new() { + MaplibreMapLibreHostApiRemoveLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_remove_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiRemoveLayerResponse* maplibre_map_libre_host_api_remove_layer_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiRemoveLayerResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_LAYER_RESPONSE(g_object_new(maplibre_map_libre_host_api_remove_layer_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + +G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiRemoveSourceResponse, maplibre_map_libre_host_api_remove_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_REMOVE_SOURCE_RESPONSE, GObject) + +struct _MaplibreMapLibreHostApiRemoveSourceResponse { + GObject parent_instance; + + FlValue* value; +}; + +G_DEFINE_TYPE(MaplibreMapLibreHostApiRemoveSourceResponse, maplibre_map_libre_host_api_remove_source_response, G_TYPE_OBJECT) + +static void maplibre_map_libre_host_api_remove_source_response_dispose(GObject* object) { + MaplibreMapLibreHostApiRemoveSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_SOURCE_RESPONSE(object); + g_clear_pointer(&self->value, fl_value_unref); + G_OBJECT_CLASS(maplibre_map_libre_host_api_remove_source_response_parent_class)->dispose(object); +} + +static void maplibre_map_libre_host_api_remove_source_response_init(MaplibreMapLibreHostApiRemoveSourceResponse* self) { +} + +static void maplibre_map_libre_host_api_remove_source_response_class_init(MaplibreMapLibreHostApiRemoveSourceResponseClass* klass) { + G_OBJECT_CLASS(klass)->dispose = maplibre_map_libre_host_api_remove_source_response_dispose; +} + +static MaplibreMapLibreHostApiRemoveSourceResponse* maplibre_map_libre_host_api_remove_source_response_new() { + MaplibreMapLibreHostApiRemoveSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_remove_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_null()); + return self; +} + +static MaplibreMapLibreHostApiRemoveSourceResponse* maplibre_map_libre_host_api_remove_source_response_new_error(const gchar* code, const gchar* message, FlValue* details) { + MaplibreMapLibreHostApiRemoveSourceResponse* self = MAPLIBRE_MAP_LIBRE_HOST_API_REMOVE_SOURCE_RESPONSE(g_object_new(maplibre_map_libre_host_api_remove_source_response_get_type(), nullptr)); + self->value = fl_value_new_list(); + fl_value_append_take(self->value, fl_value_new_string(code)); + fl_value_append_take(self->value, fl_value_new_string(message != nullptr ? message : "")); + fl_value_append_take(self->value, details != nullptr ? fl_value_ref(details) : fl_value_new_null()); + return self; +} + G_DECLARE_FINAL_TYPE(MaplibreMapLibreHostApiAddGeoJsonSourceResponse, maplibre_map_libre_host_api_add_geo_json_source_response, MAPLIBRE, MAP_LIBRE_HOST_API_ADD_GEO_JSON_SOURCE_RESPONSE, GObject) struct _MaplibreMapLibreHostApiAddGeoJsonSourceResponse { @@ -1754,6 +1832,32 @@ static void maplibre_map_libre_host_api_add_symbol_layer_cb(FlBasicMessageChanne self->vtable->add_symbol_layer(id, source_id, layout, paint, below_layer_id, handle, self->user_data); } +static void maplibre_map_libre_host_api_remove_layer_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->remove_layer == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->remove_layer(id, handle, self->user_data); +} + +static void maplibre_map_libre_host_api_remove_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { + MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); + + if (self->vtable == nullptr || self->vtable->remove_source == nullptr) { + return; + } + + FlValue* value0 = fl_value_get_list_value(message_, 0); + const gchar* id = fl_value_get_string(value0); + g_autoptr(MaplibreMapLibreHostApiResponseHandle) handle = maplibre_map_libre_host_api_response_handle_new(channel, response_handle); + self->vtable->remove_source(id, handle, self->user_data); +} + static void maplibre_map_libre_host_api_add_geo_json_source_cb(FlBasicMessageChannel* channel, FlValue* message_, FlBasicMessageChannelResponseHandle* response_handle, gpointer user_data) { MaplibreMapLibreHostApi* self = MAPLIBRE_MAP_LIBRE_HOST_API(user_data); @@ -1958,6 +2062,12 @@ void maplibre_map_libre_host_api_set_method_handlers(FlBinaryMessenger* messenge g_autofree gchar* add_symbol_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_symbol_layer_channel = fl_basic_message_channel_new(messenger, add_symbol_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_symbol_layer_channel, maplibre_map_libre_host_api_add_symbol_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* remove_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) remove_layer_channel = fl_basic_message_channel_new(messenger, remove_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(remove_layer_channel, maplibre_map_libre_host_api_remove_layer_cb, g_object_ref(api_data), g_object_unref); + g_autofree gchar* remove_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) remove_source_channel = fl_basic_message_channel_new(messenger, remove_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(remove_source_channel, maplibre_map_libre_host_api_remove_source_cb, g_object_ref(api_data), g_object_unref); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, maplibre_map_libre_host_api_add_geo_json_source_cb, g_object_ref(api_data), g_object_unref); @@ -2027,6 +2137,12 @@ void maplibre_map_libre_host_api_clear_method_handlers(FlBinaryMessenger* messen g_autofree gchar* add_symbol_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addSymbolLayer%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_symbol_layer_channel = fl_basic_message_channel_new(messenger, add_symbol_layer_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_symbol_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* remove_layer_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) remove_layer_channel = fl_basic_message_channel_new(messenger, remove_layer_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(remove_layer_channel, nullptr, nullptr, nullptr); + g_autofree gchar* remove_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource%s", dot_suffix); + g_autoptr(FlBasicMessageChannel) remove_source_channel = fl_basic_message_channel_new(messenger, remove_source_channel_name, FL_MESSAGE_CODEC(codec)); + fl_basic_message_channel_set_message_handler(remove_source_channel, nullptr, nullptr, nullptr); g_autofree gchar* add_geo_json_source_channel_name = g_strdup_printf("dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource%s", dot_suffix); g_autoptr(FlBasicMessageChannel) add_geo_json_source_channel = fl_basic_message_channel_new(messenger, add_geo_json_source_channel_name, FL_MESSAGE_CODEC(codec)); fl_basic_message_channel_set_message_handler(add_geo_json_source_channel, nullptr, nullptr, nullptr); @@ -2287,6 +2403,38 @@ void maplibre_map_libre_host_api_respond_error_add_symbol_layer(MaplibreMapLibre } } +void maplibre_map_libre_host_api_respond_remove_layer(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiRemoveLayerResponse) response = maplibre_map_libre_host_api_remove_layer_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "removeLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_remove_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiRemoveLayerResponse) response = maplibre_map_libre_host_api_remove_layer_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "removeLayer", error->message); + } +} + +void maplibre_map_libre_host_api_respond_remove_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { + g_autoptr(MaplibreMapLibreHostApiRemoveSourceResponse) response = maplibre_map_libre_host_api_remove_source_response_new(); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "removeSource", error->message); + } +} + +void maplibre_map_libre_host_api_respond_error_remove_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details) { + g_autoptr(MaplibreMapLibreHostApiRemoveSourceResponse) response = maplibre_map_libre_host_api_remove_source_response_new_error(code, message, details); + g_autoptr(GError) error = nullptr; + if (!fl_basic_message_channel_respond(response_handle->channel, response_handle->response_handle, response->value, &error)) { + g_warning("Failed to send response to %s.%s: %s", "MapLibreHostApi", "removeSource", error->message); + } +} + void maplibre_map_libre_host_api_respond_add_geo_json_source(MaplibreMapLibreHostApiResponseHandle* response_handle) { g_autoptr(MaplibreMapLibreHostApiAddGeoJsonSourceResponse) response = maplibre_map_libre_host_api_add_geo_json_source_response_new(); g_autoptr(GError) error = nullptr; diff --git a/linux/pigeon.g.h b/linux/pigeon.g.h index a620aecc..70351549 100644 --- a/linux/pigeon.g.h +++ b/linux/pigeon.g.h @@ -380,6 +380,8 @@ typedef struct { void (*add_line_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_raster_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_symbol_layer)(const gchar* id, const gchar* source_id, FlValue* layout, FlValue* paint, const gchar* below_layer_id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*remove_layer)(const gchar* id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); + void (*remove_source)(const gchar* id, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_geo_json_source)(const gchar* id, const gchar* data, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_image_source)(const gchar* id, const gchar* url, FlValue* coordinates, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); void (*add_raster_source)(const gchar* id, const gchar* url, FlValue* tiles, FlValue* bounds, double min_zoom, double max_zoom, int64_t tile_size, MaplibreTileScheme scheme, const gchar* attribution, gboolean volatile, MaplibreMapLibreHostApiResponseHandle* response_handle, gpointer user_data); @@ -700,6 +702,44 @@ void maplibre_map_libre_host_api_respond_add_symbol_layer(MaplibreMapLibreHostAp */ void maplibre_map_libre_host_api_respond_error_add_symbol_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); +/** + * maplibre_map_libre_host_api_respond_remove_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.removeLayer. + */ +void maplibre_map_libre_host_api_respond_remove_layer(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_remove_layer: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.removeLayer. + */ +void maplibre_map_libre_host_api_respond_error_remove_layer(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + +/** + * maplibre_map_libre_host_api_respond_remove_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * + * Responds to MapLibreHostApi.removeSource. + */ +void maplibre_map_libre_host_api_respond_remove_source(MaplibreMapLibreHostApiResponseHandle* response_handle); + +/** + * maplibre_map_libre_host_api_respond_error_remove_source: + * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. + * @code: error code. + * @message: error message. + * @details: (allow-none): error details or %NULL. + * + * Responds with an error to MapLibreHostApi.removeSource. + */ +void maplibre_map_libre_host_api_respond_error_remove_source(MaplibreMapLibreHostApiResponseHandle* response_handle, const gchar* code, const gchar* message, FlValue* details); + /** * maplibre_map_libre_host_api_respond_add_geo_json_source: * @response_handle: a #MaplibreMapLibreHostApiResponseHandle. diff --git a/macos/Classes/Pigeon.g.swift b/macos/Classes/Pigeon.g.swift index 532573ec..4f1b8843 100644 --- a/macos/Classes/Pigeon.g.swift +++ b/macos/Classes/Pigeon.g.swift @@ -377,6 +377,10 @@ protocol MapLibreHostApi { func addRasterLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) /// Add a symbol layer to the map style. func addSymbolLayer(id: String, sourceId: String, layout: [String: Any], paint: [String: Any], belowLayerId: String?, completion: @escaping (Result) -> Void) + /// Removes the layer with the given ID from the map's style. + func removeLayer(id: String, completion: @escaping (Result) -> Void) + /// Removes the source with the given ID from the map's style. + func removeSource(id: String, completion: @escaping (Result) -> Void) /// Add a GeoJSON source to the map style. func addGeoJsonSource(id: String, data: String, completion: @escaping (Result) -> Void) /// Add a image source to the map style. @@ -709,6 +713,42 @@ class MapLibreHostApiSetup { } else { addSymbolLayerChannel.setMessageHandler(nil) } + /// Removes the layer with the given ID from the map's style. + let removeLayerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeLayerChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.removeLayer(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeLayerChannel.setMessageHandler(nil) + } + /// Removes the source with the given ID from the map's style. + let removeSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + removeSourceChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let idArg = args[0] as! String + api.removeSource(id: idArg) { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + removeSourceChannel.setMessageHandler(nil) + } /// Add a GeoJSON source to the map style. let addGeoJsonSourceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) if let api = api { diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index 18a729e8..bc7bff1d 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -148,6 +148,14 @@ abstract interface class MapLibreHostApi { String? belowLayerId, }); + /// Removes the layer with the given ID from the map's style. + @async + void removeLayer(String id); + + /// Removes the source with the given ID from the map's style. + @async + void removeSource(String id); + /// Add a GeoJSON source to the map style. @async void addGeoJsonSource({ diff --git a/windows/runner/pigeon.g.cpp b/windows/runner/pigeon.g.cpp index fd4c30c9..a706733e 100644 --- a/windows/runner/pigeon.g.cpp +++ b/windows/runner/pigeon.g.cpp @@ -1119,6 +1119,64 @@ void MapLibreHostApi::SetUp( channel.SetMessageHandler(nullptr); } } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeLayer" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + api->RemoveLayer(id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } + { + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.removeSource" + prepended_suffix, &GetCodec()); + if (api != nullptr) { + channel.SetMessageHandler([api](const EncodableValue& message, const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_id_arg = args.at(0); + if (encodable_id_arg.IsNull()) { + reply(WrapError("id_arg unexpectedly null.")); + return; + } + const auto& id_arg = std::get(encodable_id_arg); + api->RemoveSource(id_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel.SetMessageHandler(nullptr); + } + } { BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.maplibre.MapLibreHostApi.addGeoJsonSource" + prepended_suffix, &GetCodec()); if (api != nullptr) { diff --git a/windows/runner/pigeon.g.h b/windows/runner/pigeon.g.h index 07079310..ba1d70ed 100644 --- a/windows/runner/pigeon.g.h +++ b/windows/runner/pigeon.g.h @@ -426,6 +426,14 @@ class MapLibreHostApi { const flutter::EncodableMap& paint, const std::string* below_layer_id, std::function reply)> result) = 0; + // Removes the layer with the given ID from the map's style. + virtual void RemoveLayer( + const std::string& id, + std::function reply)> result) = 0; + // Removes the source with the given ID from the map's style. + virtual void RemoveSource( + const std::string& id, + std::function reply)> result) = 0; // Add a GeoJSON source to the map style. virtual void AddGeoJsonSource( const std::string& id, From 9895d3ffcf7dba16306a0283c194a7ad529ffce7 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:36:54 +0200 Subject: [PATCH 14/24] add raster layer example --- example/lib/layers_page.dart | 48 ++++++++++++++++++++++++++++++----- lib/src/web/interop/map.dart | 3 +++ lib/src/web/widget_state.dart | 7 ++++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/example/lib/layers_page.dart b/example/lib/layers_page.dart index 3cb72bb3..03b86bca 100644 --- a/example/lib/layers_page.dart +++ b/example/lib/layers_page.dart @@ -15,14 +15,16 @@ class LayersPage extends StatefulWidget { const _layerId = 'showcaseLayer'; const _sourceEarthquakesId = 'earthquakes'; +const _sourceOpenStreetMapId = 'openStreetMap'; class _LayersPageState extends State { + bool _someLayerActive = false; late final MapController _controller; @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('Controller')), + appBar: AppBar(title: const Text('Map Layers')), body: Column( children: [ Padding( @@ -33,7 +35,10 @@ class _LayersPageState extends State { children: [ OutlinedButton( onPressed: () async { - await _controller.removeLayer(_layerId); + if (_someLayerActive) { + await _controller.removeLayer(_layerId); + } + _someLayerActive = true; await _controller.addLayer(_heatmapLayer); await _controller.flyTo( center: Position(-120, 50), @@ -44,7 +49,10 @@ class _LayersPageState extends State { ), OutlinedButton( onPressed: () async { - await _controller.removeLayer(_layerId); + if (_someLayerActive) { + await _controller.removeLayer(_layerId); + } + _someLayerActive = true; await _controller.addLayer(_circleLayer); await _controller.flyTo( center: Position(-152.9959, 59.8150), @@ -53,6 +61,21 @@ class _LayersPageState extends State { }, child: const Text('Circle'), ), + OutlinedButton( + onPressed: () async { + if (_someLayerActive) { + await _controller.removeLayer(_layerId); + } + _someLayerActive = true; + // TODO raster layer not working + await _controller.addLayer(_rasterLayer); + await _controller.flyTo( + center: Position(-102, 39), + zoom: 4, + ); + }, + child: const Text('Raster'), + ), ], ), ), @@ -72,19 +95,27 @@ class _LayersPageState extends State { } Future _onStyleLoaded() async { - const sourceEarthquakes = GeoJsonSource( + const earthquakes = GeoJsonSource( id: _sourceEarthquakesId, data: 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', ); - await _controller.addSource(sourceEarthquakes); + const openStreetMap = RasterSource( + id: _sourceOpenStreetMapId, + tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], + maxZoom: 20, + tileSize: 256, + attribution: + 'OpenStreetMap', + ); + await _controller.addSource(earthquakes); + await _controller.addSource(openStreetMap); } } // TODO fill layer // TODO fill extrusion layer // TODO line layer -// TODO raster layer // TODO hillshade layer const _heatmapLayer = HeatmapLayer( @@ -217,3 +248,8 @@ const _circleLayer = CircleLayer( ] }, ); + +const _rasterLayer = RasterLayer( + id: _layerId, + sourceId: _sourceOpenStreetMapId, +); diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index 5b0719f4..dd64251d 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -159,6 +159,9 @@ extension type SourceSpecification._(JSObject _) implements JSObject { /// Create a new raster source. external factory SourceSpecification.raster({ required String type, + required JSAny? tiles, + required int tileSize, + required String? attribution, }); /// Create a new vector source. diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 058af458..84c37fca 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -280,7 +280,12 @@ final class MapLibreMapStateWeb extends State case RasterSource(): _map.addSource( source.id, - interop.SourceSpecification.raster(type: 'raster'), + interop.SourceSpecification.raster( + type: 'raster', + attribution: source.attribution, + tileSize: source.tileSize, + tiles: source.tiles.jsify(), + ), ); case VectorSource(): _map.addSource( From 78415d68ef91f71f6889c56185de184ef8ab8b0a Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:53:54 +0200 Subject: [PATCH 15/24] hillshade layer --- example/lib/layers_page.dart | 30 ++++++++++++++++++++++++++++-- lib/src/web/interop/map.dart | 3 +++ lib/src/web/widget_state.dart | 7 ++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/example/lib/layers_page.dart b/example/lib/layers_page.dart index 03b86bca..b21f5310 100644 --- a/example/lib/layers_page.dart +++ b/example/lib/layers_page.dart @@ -16,6 +16,7 @@ class LayersPage extends StatefulWidget { const _layerId = 'showcaseLayer'; const _sourceEarthquakesId = 'earthquakes'; const _sourceOpenStreetMapId = 'openStreetMap'; +const _sourceHillshadeId = 'hillshade'; class _LayersPageState extends State { bool _someLayerActive = false; @@ -67,7 +68,6 @@ class _LayersPageState extends State { await _controller.removeLayer(_layerId); } _someLayerActive = true; - // TODO raster layer not working await _controller.addLayer(_rasterLayer); await _controller.flyTo( center: Position(-102, 39), @@ -76,6 +76,20 @@ class _LayersPageState extends State { }, child: const Text('Raster'), ), + OutlinedButton( + onPressed: () async { + if (_someLayerActive) { + await _controller.removeLayer(_layerId); + } + _someLayerActive = true; + await _controller.addLayer(_hillshadeLayer); + await _controller.jumpTo( + center: Position(11.39085, 47.27574), + zoom: 10, + ); + }, + child: const Text('Hillshade'), + ), ], ), ), @@ -100,6 +114,7 @@ class _LayersPageState extends State { data: 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', ); + await _controller.addSource(earthquakes); const openStreetMap = RasterSource( id: _sourceOpenStreetMapId, tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], @@ -108,8 +123,13 @@ class _LayersPageState extends State { attribution: 'OpenStreetMap', ); - await _controller.addSource(earthquakes); await _controller.addSource(openStreetMap); + const hillshade = RasterDemSource( + id: _sourceHillshadeId, + url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json', + tileSize: 256, + ); + await _controller.addSource(hillshade); } } @@ -253,3 +273,9 @@ const _rasterLayer = RasterLayer( id: _layerId, sourceId: _sourceOpenStreetMapId, ); + +const _hillshadeLayer = HillshadeLayer( + id: _layerId, + sourceId: _sourceHillshadeId, + paint: {'hillshade-shadow-color': '#473B24'}, +); diff --git a/lib/src/web/interop/map.dart b/lib/src/web/interop/map.dart index dd64251d..cc602f7b 100644 --- a/lib/src/web/interop/map.dart +++ b/lib/src/web/interop/map.dart @@ -154,6 +154,9 @@ extension type SourceSpecification._(JSObject _) implements JSObject { /// Create a new raster DEM source. external factory SourceSpecification.rasterDem({ required String type, + required String? url, + required int tileSize, + required String? attribution, }); /// Create a new raster source. diff --git a/lib/src/web/widget_state.dart b/lib/src/web/widget_state.dart index 84c37fca..560b47ea 100644 --- a/lib/src/web/widget_state.dart +++ b/lib/src/web/widget_state.dart @@ -275,7 +275,12 @@ final class MapLibreMapStateWeb extends State case RasterDemSource(): _map.addSource( source.id, - interop.SourceSpecification.rasterDem(type: 'raster-dem'), + interop.SourceSpecification.rasterDem( + type: 'raster-dem', + tileSize: source.tileSize, + attribution: source.attribution, + url: source.url, + ), ); case RasterSource(): _map.addSource( From bd57305a04fb5291d8def8012c73f4ed9ffd90c4 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:37:25 +0200 Subject: [PATCH 16/24] split layer examples --- example/lib/layers_circle_page.dart | 109 ++++++++++ example/lib/layers_heatmap_page.dart | 114 ++++++++++ example/lib/layers_hillshade_page.dart | 57 +++++ example/lib/layers_page.dart | 281 ------------------------- example/lib/layers_raster_page.dart | 54 +++++ example/lib/main.dart | 10 +- example/lib/menu_page.dart | 119 +++++++---- 7 files changed, 422 insertions(+), 322 deletions(-) create mode 100644 example/lib/layers_circle_page.dart create mode 100644 example/lib/layers_heatmap_page.dart create mode 100644 example/lib/layers_hillshade_page.dart delete mode 100644 example/lib/layers_page.dart create mode 100644 example/lib/layers_raster_page.dart diff --git a/example/lib/layers_circle_page.dart b/example/lib/layers_circle_page.dart new file mode 100644 index 00000000..42770ffa --- /dev/null +++ b/example/lib/layers_circle_page.dart @@ -0,0 +1,109 @@ +// ignore_for_file: prefer_single_quotes, require_trailing_commas + +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersCirclePage extends StatefulWidget { + const LayersCirclePage({super.key}); + + static const location = '/layers/circle'; + + @override + State createState() => _LayersCirclePageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceId = 'earthquakes'; + +class _LayersCirclePageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Circle Layer')), + body: MapLibreMap( + options: MapOptions( + center: Position(-152.9959, 59.8150), + zoom: 9, + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + const earthquakes = GeoJsonSource( + id: _sourceId, + data: + 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', + ); + await _controller.addSource(earthquakes); + await _controller.addLayer(_circleLayer); + } +} + +const _circleLayer = CircleLayer( + id: _layerId, + sourceId: _sourceId, + paint: { + // Size circle radius by earthquake magnitude and zoom level + 'circle-radius': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 1, + 6, + 4 + ], + 16, + [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 5, + 6, + 50 + ] + ], + // Color circle by earthquake magnitude + 'circle-color': [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 1, + 'rgba(33,102,172,0)', + 2, + 'rgb(103,169,207)', + 3, + 'rgb(209,229,240)', + 4, + 'rgb(253,219,199)', + 5, + 'rgb(239,138,98)', + 6, + 'rgb(178,24,43)' + ], + 'circle-stroke-color': 'white', + 'circle-stroke-width': 1, + // Transition from heatmap to circle layer by zoom level + 'circle-opacity': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + 0, + 8, + 1 + ] + }, +); diff --git a/example/lib/layers_heatmap_page.dart b/example/lib/layers_heatmap_page.dart new file mode 100644 index 00000000..bc0e47d2 --- /dev/null +++ b/example/lib/layers_heatmap_page.dart @@ -0,0 +1,114 @@ +// ignore_for_file: prefer_single_quotes, require_trailing_commas + +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersHeatmapPage extends StatefulWidget { + const LayersHeatmapPage({super.key}); + + static const location = '/layers/heatmap'; + + @override + State createState() => _LayersHeatmapPageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceId = 'earthquakes'; + +class _LayersHeatmapPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Heatmap Layer')), + body: MapLibreMap( + options: MapOptions( + center: Position(-120, 50), + zoom: 2, + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + const earthquakes = GeoJsonSource( + id: _sourceId, + data: + 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', + ); + await _controller.addSource(earthquakes); + await _controller.addLayer(_heatmapLayer); + } +} + +const _heatmapLayer = HeatmapLayer( + id: _layerId, + sourceId: _sourceId, + paint: { + // Increase the heatmap weight based on frequency and property magnitude + 'heatmap-weight': [ + 'interpolate', + ['linear'], + ['get', 'mag'], + 0, + 0, + 6, + 1 + ], + // Increase the heatmap color weight weight by zoom level + // heatmap-intensity is a multiplier on top of heatmap-weight + 'heatmap-intensity': [ + 'interpolate', + ['linear'], + ['zoom'], + 0, + 1, + 9, + 3 + ], + // Color ramp for heatmap. Domain is 0 (low) to 1 (high). + // Begin color ramp at 0-stop with a 0-transparency color + // to create a blur-like effect. + 'heatmap-color': [ + 'interpolate', + ['linear'], + ['heatmap-density'], + 0, + 'rgba(33,102,172,0)', + 0.2, + 'rgb(103,169,207)', + 0.4, + 'rgb(209,229,240)', + 0.6, + 'rgb(253,219,199)', + 0.8, + 'rgb(239,138,98)', + 1, + 'rgb(178,24,43)' + ], + // Adjust the heatmap radius by zoom level + 'heatmap-radius': [ + 'interpolate', + ['linear'], + ['zoom'], + 0, + 2, + 9, + 20 + ], + // Transition from heatmap to circle layer by zoom level + 'heatmap-opacity': [ + 'interpolate', + ['linear'], + ['zoom'], + 7, + 1, + 9, + 0 + ] + }, +); diff --git a/example/lib/layers_hillshade_page.dart b/example/lib/layers_hillshade_page.dart new file mode 100644 index 00000000..1aad87fa --- /dev/null +++ b/example/lib/layers_hillshade_page.dart @@ -0,0 +1,57 @@ +// ignore_for_file: prefer_single_quotes, require_trailing_commas + +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersHillshadePage extends StatefulWidget { + const LayersHillshadePage({super.key}); + + static const location = '/layers/hillshade'; + + @override + State createState() => _LayersHillshadePageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceId = 'hills'; + +class _LayersHillshadePageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Hillshade Layer')), + body: MapLibreMap( + options: MapOptions( + center: Position(11.39085, 47.27574), + zoom: 10, + onClick: (point) => debugPrint('${point.lng}, ${point.lat}'), + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + const hillshade = RasterDemSource( + id: _sourceId, + url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json', + tileSize: 256, + ); + await _controller.addSource(hillshade); + await _controller.addLayer(_hillshadeLayer); + } +} + +// TODO fill layer +// TODO fill extrusion layer +// TODO line layer + +const _hillshadeLayer = HillshadeLayer( + id: _layerId, + sourceId: _sourceId, + paint: {'hillshade-shadow-color': '#473B24'}, +); diff --git a/example/lib/layers_page.dart b/example/lib/layers_page.dart deleted file mode 100644 index b21f5310..00000000 --- a/example/lib/layers_page.dart +++ /dev/null @@ -1,281 +0,0 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas - -import 'package:flutter/material.dart'; -import 'package:maplibre/maplibre.dart'; - -@immutable -class LayersPage extends StatefulWidget { - const LayersPage({super.key}); - - static const location = '/layers'; - - @override - State createState() => _LayersPageState(); -} - -const _layerId = 'showcaseLayer'; -const _sourceEarthquakesId = 'earthquakes'; -const _sourceOpenStreetMapId = 'openStreetMap'; -const _sourceHillshadeId = 'hillshade'; - -class _LayersPageState extends State { - bool _someLayerActive = false; - late final MapController _controller; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Map Layers')), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(8), - child: Wrap( - spacing: 8, - runSpacing: 8, - children: [ - OutlinedButton( - onPressed: () async { - if (_someLayerActive) { - await _controller.removeLayer(_layerId); - } - _someLayerActive = true; - await _controller.addLayer(_heatmapLayer); - await _controller.flyTo( - center: Position(-120, 50), - zoom: 2, - ); - }, - child: const Text('Heatmap'), - ), - OutlinedButton( - onPressed: () async { - if (_someLayerActive) { - await _controller.removeLayer(_layerId); - } - _someLayerActive = true; - await _controller.addLayer(_circleLayer); - await _controller.flyTo( - center: Position(-152.9959, 59.8150), - zoom: 9, - ); - }, - child: const Text('Circle'), - ), - OutlinedButton( - onPressed: () async { - if (_someLayerActive) { - await _controller.removeLayer(_layerId); - } - _someLayerActive = true; - await _controller.addLayer(_rasterLayer); - await _controller.flyTo( - center: Position(-102, 39), - zoom: 4, - ); - }, - child: const Text('Raster'), - ), - OutlinedButton( - onPressed: () async { - if (_someLayerActive) { - await _controller.removeLayer(_layerId); - } - _someLayerActive = true; - await _controller.addLayer(_hillshadeLayer); - await _controller.jumpTo( - center: Position(11.39085, 47.27574), - zoom: 10, - ); - }, - child: const Text('Hillshade'), - ), - ], - ), - ), - Expanded( - child: MapLibreMap( - options: MapOptions( - center: Position(-120, 50), - onClick: (point) => debugPrint('${point.lng}, ${point.lat}'), - ), - onMapCreated: (controller) => _controller = controller, - onStyleLoaded: _onStyleLoaded, - ), - ), - ], - ), - ); - } - - Future _onStyleLoaded() async { - const earthquakes = GeoJsonSource( - id: _sourceEarthquakesId, - data: - 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson', - ); - await _controller.addSource(earthquakes); - const openStreetMap = RasterSource( - id: _sourceOpenStreetMapId, - tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], - maxZoom: 20, - tileSize: 256, - attribution: - 'OpenStreetMap', - ); - await _controller.addSource(openStreetMap); - const hillshade = RasterDemSource( - id: _sourceHillshadeId, - url: 'https://demotiles.maplibre.org/terrain-tiles/tiles.json', - tileSize: 256, - ); - await _controller.addSource(hillshade); - } -} - -// TODO fill layer -// TODO fill extrusion layer -// TODO line layer -// TODO hillshade layer - -const _heatmapLayer = HeatmapLayer( - id: _layerId, - sourceId: _sourceEarthquakesId, - paint: { - // Increase the heatmap weight based on frequency and property magnitude - 'heatmap-weight': [ - 'interpolate', - ['linear'], - ['get', 'mag'], - 0, - 0, - 6, - 1 - ], - // Increase the heatmap color weight weight by zoom level - // heatmap-intensity is a multiplier on top of heatmap-weight - 'heatmap-intensity': [ - 'interpolate', - ['linear'], - ['zoom'], - 0, - 1, - 9, - 3 - ], - // Color ramp for heatmap. Domain is 0 (low) to 1 (high). - // Begin color ramp at 0-stop with a 0-transparency color - // to create a blur-like effect. - 'heatmap-color': [ - 'interpolate', - ['linear'], - ['heatmap-density'], - 0, - 'rgba(33,102,172,0)', - 0.2, - 'rgb(103,169,207)', - 0.4, - 'rgb(209,229,240)', - 0.6, - 'rgb(253,219,199)', - 0.8, - 'rgb(239,138,98)', - 1, - 'rgb(178,24,43)' - ], - // Adjust the heatmap radius by zoom level - 'heatmap-radius': [ - 'interpolate', - ['linear'], - ['zoom'], - 0, - 2, - 9, - 20 - ], - // Transition from heatmap to circle layer by zoom level - 'heatmap-opacity': [ - 'interpolate', - ['linear'], - ['zoom'], - 7, - 1, - 9, - 0 - ] - }, -); - -const _circleLayer = CircleLayer( - id: _layerId, - sourceId: _sourceEarthquakesId, - paint: { - // Size circle radius by earthquake magnitude and zoom level - 'circle-radius': [ - 'interpolate', - ['linear'], - ['zoom'], - 7, - [ - 'interpolate', - ['linear'], - ['get', 'mag'], - 1, - 1, - 6, - 4 - ], - 16, - [ - 'interpolate', - ['linear'], - ['get', 'mag'], - 1, - 5, - 6, - 50 - ] - ], - // Color circle by earthquake magnitude - 'circle-color': [ - 'interpolate', - ['linear'], - ['get', 'mag'], - 1, - 'rgba(33,102,172,0)', - 2, - 'rgb(103,169,207)', - 3, - 'rgb(209,229,240)', - 4, - 'rgb(253,219,199)', - 5, - 'rgb(239,138,98)', - 6, - 'rgb(178,24,43)' - ], - 'circle-stroke-color': 'white', - 'circle-stroke-width': 1, - // Transition from heatmap to circle layer by zoom level - 'circle-opacity': [ - 'interpolate', - ['linear'], - ['zoom'], - 7, - 0, - 8, - 1 - ] - }, -); - -const _rasterLayer = RasterLayer( - id: _layerId, - sourceId: _sourceOpenStreetMapId, -); - -const _hillshadeLayer = HillshadeLayer( - id: _layerId, - sourceId: _sourceHillshadeId, - paint: {'hillshade-shadow-color': '#473B24'}, -); diff --git a/example/lib/layers_raster_page.dart b/example/lib/layers_raster_page.dart new file mode 100644 index 00000000..bca61d31 --- /dev/null +++ b/example/lib/layers_raster_page.dart @@ -0,0 +1,54 @@ +// ignore_for_file: prefer_single_quotes, require_trailing_commas + +import 'package:flutter/material.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersRasterPage extends StatefulWidget { + const LayersRasterPage({super.key}); + + static const location = '/layers/raster'; + + @override + State createState() => _LayersRasterPageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceId = 'openStreetMap'; + +class _LayersRasterPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Raster Layer')), + body: MapLibreMap( + options: MapOptions( + center: Position(-120, 50), + zoom: 2, + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + const openStreetMap = RasterSource( + id: _sourceId, + tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], + maxZoom: 20, + tileSize: 256, + attribution: + 'OpenStreetMap', + ); + await _controller.addSource(openStreetMap); + await _controller.addLayer(_rasterLayer); + } +} + +const _rasterLayer = RasterLayer( + id: _layerId, + sourceId: _sourceId, +); diff --git a/example/lib/main.dart b/example/lib/main.dart index 5da19848..9b1cfd90 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,7 +3,10 @@ import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/kiosk_page.dart'; -import 'package:maplibre_example/layers_page.dart'; +import 'package:maplibre_example/layers_circle_page.dart'; +import 'package:maplibre_example/layers_heatmap_page.dart'; +import 'package:maplibre_example/layers_hillshade_page.dart'; +import 'package:maplibre_example/layers_raster_page.dart'; import 'package:maplibre_example/menu_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; @@ -26,7 +29,10 @@ class MyApp extends StatelessWidget { MenuPage.location: (context) => const MenuPage(), KioskPage.location: (context) => const KioskPage(), StyledMapPage.location: (context) => const StyledMapPage(), - LayersPage.location: (context) => const LayersPage(), + LayersCirclePage.location: (context) => const LayersCirclePage(), + LayersHeatmapPage.location: (context) => const LayersHeatmapPage(), + LayersHillshadePage.location: (context) => const LayersHillshadePage(), + LayersRasterPage.location: (context) => const LayersRasterPage(), WebControlsPage.location: (context) => const WebControlsPage(), GeoJsonPage.location: (context) => const GeoJsonPage(), CallbacksPage.location: (context) => const CallbacksPage(), diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 380cd5c5..8b522ea9 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -3,7 +3,10 @@ import 'package:flutter/material.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; import 'package:maplibre_example/geojson_page.dart'; -import 'package:maplibre_example/layers_page.dart'; +import 'package:maplibre_example/layers_circle_page.dart'; +import 'package:maplibre_example/layers_heatmap_page.dart'; +import 'package:maplibre_example/layers_hillshade_page.dart'; +import 'package:maplibre_example/layers_raster_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; import 'package:maplibre_example/web_controls_page.dart'; @@ -17,45 +20,72 @@ class MenuPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('MapLibre Demo')), - body: GridView.extent( - maxCrossAxisExtent: 200, - childAspectRatio: 1.5, - children: const [ - ItemCard( - label: 'Styled Map', - iconData: Icons.map, - location: StyledMapPage.location, + body: CustomScrollView( + slivers: [ + const SliverToBoxAdapter(child: SectionTitle('General')), + SliverGrid.extent( + maxCrossAxisExtent: 200, + childAspectRatio: 1.5, + children: const [ + ItemCard( + label: 'Styled Map', + iconData: Icons.map, + location: StyledMapPage.location, + ), + ItemCard( + label: 'GeoJSON', + iconData: Icons.location_on, + location: GeoJsonPage.location, + ), + ItemCard( + label: 'Callbacks', + iconData: Icons.back_hand, + location: CallbacksPage.location, + ), + if (kIsWeb) + ItemCard( + label: 'Web Controls', + iconData: Icons.toggle_off, + location: WebControlsPage.location, + ), + ItemCard( + label: 'Controller', + iconData: Icons.api, + location: ControllerPage.location, + ), + ItemCard( + label: 'Two Maps', + iconData: Icons.looks_two, + location: TwoMapsPage.location, + ), + ], ), - ItemCard( - label: 'GeoJSON', - iconData: Icons.location_on, - location: GeoJsonPage.location, - ), - ItemCard( - label: 'Layers', - iconData: Icons.layers, - location: LayersPage.location, - ), - ItemCard( - label: 'Callbacks', - iconData: Icons.back_hand, - location: CallbacksPage.location, - ), - if (kIsWeb) - ItemCard( - label: 'Web Controls', - iconData: Icons.toggle_off, - location: WebControlsPage.location, - ), - ItemCard( - label: 'Controller', - iconData: Icons.api, - location: ControllerPage.location, - ), - ItemCard( - label: 'Two Maps', - iconData: Icons.looks_two, - location: TwoMapsPage.location, + const SliverToBoxAdapter(child: SectionTitle('Map Layers')), + SliverGrid.extent( + maxCrossAxisExtent: 200, + childAspectRatio: 1.5, + children: const [ + ItemCard( + label: 'Circle', + iconData: Icons.circle, + location: LayersCirclePage.location, + ), + ItemCard( + label: 'Heatmap', + iconData: Icons.thermostat, + location: LayersHeatmapPage.location, + ), + ItemCard( + label: 'Hillshade', + iconData: Icons.landscape, + location: LayersHillshadePage.location, + ), + ItemCard( + label: 'Raster', + iconData: Icons.grid_on, + location: LayersRasterPage.location, + ), + ], ), ], ), @@ -89,3 +119,14 @@ class ItemCard extends StatelessWidget { ); } } + +class SectionTitle extends StatelessWidget { + const SectionTitle(this.label, {super.key}); + + final String label; + + @override + Widget build(BuildContext context) { + return ListTile(title: Text(label, style: const TextStyle(fontSize: 18))); + } +} From 8a978628db1300e802a9bdb258fccd5416b0d9c8 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:56:07 +0200 Subject: [PATCH 17/24] split geojson example into layer examples --- example/lib/annotations_page.dart | 37 ++++++++++ example/lib/callbacks_page.dart | 1 - example/lib/controller_page.dart | 1 - example/lib/geojson_page.dart | 79 --------------------- example/lib/kiosk_page.dart | 2 - example/lib/layers_circle_page.dart | 1 - example/lib/layers_fill_extrusion_page.dart | 54 ++++++++++++++ example/lib/layers_fill_page.dart | 47 ++++++++++++ example/lib/layers_heatmap_page.dart | 7 +- example/lib/layers_hillshade_page.dart | 12 +--- example/lib/layers_line_page.dart | 46 ++++++++++++ example/lib/layers_raster_page.dart | 14 ++-- example/lib/main.dart | 11 ++- example/lib/menu_page.dart | 24 ++++++- example/lib/styled_map_page.dart | 1 - example/lib/two_maps_page.dart | 1 - example/lib/web_controls_page.dart | 1 - 17 files changed, 223 insertions(+), 116 deletions(-) create mode 100644 example/lib/annotations_page.dart delete mode 100644 example/lib/geojson_page.dart create mode 100644 example/lib/layers_fill_extrusion_page.dart create mode 100644 example/lib/layers_fill_page.dart create mode 100644 example/lib/layers_line_page.dart diff --git a/example/lib/annotations_page.dart b/example/lib/annotations_page.dart new file mode 100644 index 00000000..f3653f0b --- /dev/null +++ b/example/lib/annotations_page.dart @@ -0,0 +1,37 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class AnnotationsPage extends StatefulWidget { + const AnnotationsPage({super.key}); + + static const location = '/annotations'; + + @override + State createState() => _AnnotationsPageState(); +} + +class _AnnotationsPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Annotations')), + body: MapLibreMap( + options: MapOptions(zoom: 7, center: Position(9.17, 47.68)), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: () async { + if (kIsWeb) { + // This kind of Marker is only supported on web + final _ = await _controller.addMarker( + Marker(point: Position(9, 47)), + ); + } + }, + ), + ); + } +} diff --git a/example/lib/callbacks_page.dart b/example/lib/callbacks_page.dart index c958a33a..2c3a9d21 100644 --- a/example/lib/callbacks_page.dart +++ b/example/lib/callbacks_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/controller_page.dart b/example/lib/controller_page.dart index 668312bc..81ad2c9f 100644 --- a/example/lib/controller_page.dart +++ b/example/lib/controller_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; diff --git a/example/lib/geojson_page.dart b/example/lib/geojson_page.dart deleted file mode 100644 index 7600436b..00000000 --- a/example/lib/geojson_page.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:maplibre/maplibre.dart'; - -@immutable -class GeoJsonPage extends StatefulWidget { - const GeoJsonPage({super.key}); - - static const location = '/geojson'; - - @override - State createState() => _GeoJsonPageState(); -} - -class _GeoJsonPageState extends State { - late final MapController _controller; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('GeoJSON')), - body: MapLibreMap( - options: MapOptions(zoom: 7, center: Position(9.17, 47.68)), - onMapCreated: (controller) => _controller = controller, - onStyleLoaded: () async { - if (kIsWeb) { - // This kind of Marker is only supported on web - final _ = await _controller.addMarker( - Marker(point: Position(9, 47)), - ); - } - - // show Polygon as fill layer - final geojsonPolygon = - await rootBundle.loadString('assets/geojson/lake-constance.json'); - await _controller.addSource( - GeoJsonSource(id: 'LakeConstance', data: geojsonPolygon), - ); - await _controller.addLayer( - const FillLayer( - id: 'geojson-fill', - sourceId: 'LakeConstance', - paint: {'fill-color': '#00F'}, - ), - ); - - // show LineString as line layer - final geojsonLine = - await rootBundle.loadString('assets/geojson/path.json'); - await _controller.addSource( - GeoJsonSource(id: 'Path', data: geojsonLine), - ); - await _controller.addLayer( - const LineLayer( - id: 'geojson-line', - sourceId: 'Path', - paint: {'line-color': '#F00', 'line-width': 3}, - ), - ); - - // show Point as circle layer - final geojsonPoints = - await rootBundle.loadString('assets/geojson/cities.json'); - await _controller.addSource( - GeoJsonSource(id: 'Cities', data: geojsonPoints), - ); - await _controller.addLayer( - const CircleLayer( - id: 'geojson-circle', - sourceId: 'Cities', - paint: {'circle-color': '#0F0', 'circle-radius': 20}, - ), - ); - }, - ), - ); - } -} diff --git a/example/lib/kiosk_page.dart b/example/lib/kiosk_page.dart index 086abddf..b8daef93 100644 --- a/example/lib/kiosk_page.dart +++ b/example/lib/kiosk_page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas - import 'dart:async'; import 'package:flutter/material.dart'; diff --git a/example/lib/layers_circle_page.dart b/example/lib/layers_circle_page.dart index 42770ffa..bb7e9186 100644 --- a/example/lib/layers_circle_page.dart +++ b/example/lib/layers_circle_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/layers_fill_extrusion_page.dart b/example/lib/layers_fill_extrusion_page.dart new file mode 100644 index 00000000..0d2b8b8b --- /dev/null +++ b/example/lib/layers_fill_extrusion_page.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersFillExtrusionPage extends StatefulWidget { + const LayersFillExtrusionPage({super.key}); + + static const location = '/layers/fill-extrusion'; + + @override + State createState() => + _LayersFillExtrusionPageState(); +} + +const _layerId = 'showcaseLayer'; +const _sourceId = 'hills'; + +class _LayersFillExtrusionPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Fill Extrusion Layer')), + body: MapLibreMap( + options: MapOptions( + center: Position(11.39085, 47.27574), + zoom: 10, + ), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + final geojsonPolygon = + await rootBundle.loadString('assets/geojson/lake-constance.json'); + await _controller.addSource( + GeoJsonSource(id: 'LakeConstance', data: geojsonPolygon), + ); + await _controller.addLayer( + const FillLayer( + id: 'geojson-fill', + sourceId: 'LakeConstance', + paint: {'fill-color': '#429ef5'}, + ), + ); + } +} + +// TODO fill extrusion layer +// TODO line layer diff --git a/example/lib/layers_fill_page.dart b/example/lib/layers_fill_page.dart new file mode 100644 index 00000000..549d6866 --- /dev/null +++ b/example/lib/layers_fill_page.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersFillPage extends StatefulWidget { + const LayersFillPage({super.key}); + + static const location = '/layers/fill'; + + @override + State createState() => _LayersFillPageState(); +} + +class _LayersFillPageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Fill Layer')), + body: MapLibreMap( + options: MapOptions(zoom: 7, center: Position(9.17, 47.68)), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + final geojsonPolygon = + await rootBundle.loadString('assets/geojson/lake-constance.json'); + await _controller.addSource( + GeoJsonSource(id: 'LakeConstance', data: geojsonPolygon), + ); + await _controller.addLayer( + const FillLayer( + id: 'geojson-fill', + sourceId: 'LakeConstance', + paint: {'fill-color': '#429ef5'}, + ), + ); + } +} + +// TODO fill extrusion layer +// TODO line layer diff --git a/example/lib/layers_heatmap_page.dart b/example/lib/layers_heatmap_page.dart index bc0e47d2..757561fa 100644 --- a/example/lib/layers_heatmap_page.dart +++ b/example/lib/layers_heatmap_page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; @@ -24,10 +22,7 @@ class _LayersHeatmapPageState extends State { return Scaffold( appBar: AppBar(title: const Text('Heatmap Layer')), body: MapLibreMap( - options: MapOptions( - center: Position(-120, 50), - zoom: 2, - ), + options: MapOptions(center: Position(-120, 50), zoom: 2), onMapCreated: (controller) => _controller = controller, onStyleLoaded: _onStyleLoaded, ), diff --git a/example/lib/layers_hillshade_page.dart b/example/lib/layers_hillshade_page.dart index 1aad87fa..48bd8697 100644 --- a/example/lib/layers_hillshade_page.dart +++ b/example/lib/layers_hillshade_page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; @@ -24,11 +22,7 @@ class _LayersHillshadePageState extends State { return Scaffold( appBar: AppBar(title: const Text('Hillshade Layer')), body: MapLibreMap( - options: MapOptions( - center: Position(11.39085, 47.27574), - zoom: 10, - onClick: (point) => debugPrint('${point.lng}, ${point.lat}'), - ), + options: MapOptions(center: Position(11.39085, 47.27574), zoom: 10), onMapCreated: (controller) => _controller = controller, onStyleLoaded: _onStyleLoaded, ), @@ -46,10 +40,6 @@ class _LayersHillshadePageState extends State { } } -// TODO fill layer -// TODO fill extrusion layer -// TODO line layer - const _hillshadeLayer = HillshadeLayer( id: _layerId, sourceId: _sourceId, diff --git a/example/lib/layers_line_page.dart b/example/lib/layers_line_page.dart new file mode 100644 index 00000000..fa64717c --- /dev/null +++ b/example/lib/layers_line_page.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:maplibre/maplibre.dart'; + +@immutable +class LayersLinePage extends StatefulWidget { + const LayersLinePage({super.key}); + + static const location = '/layers/line'; + + @override + State createState() => _LayersLinePageState(); +} + +class _LayersLinePageState extends State { + late final MapController _controller; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Line Layer')), + body: MapLibreMap( + options: MapOptions(zoom: 7, center: Position(9.17, 47.68)), + onMapCreated: (controller) => _controller = controller, + onStyleLoaded: _onStyleLoaded, + ), + ); + } + + Future _onStyleLoaded() async { + final geojsonLine = await rootBundle.loadString('assets/geojson/path.json'); + await _controller.addSource( + GeoJsonSource(id: 'Path', data: geojsonLine), + ); + await _controller.addLayer( + const LineLayer( + id: 'geojson-line', + sourceId: 'Path', + paint: {'line-color': '#F00', 'line-width': 3}, + ), + ); + } +} + +// TODO fill extrusion layer +// TODO line layer diff --git a/example/lib/layers_raster_page.dart b/example/lib/layers_raster_page.dart index bca61d31..a8e027f1 100644 --- a/example/lib/layers_raster_page.dart +++ b/example/lib/layers_raster_page.dart @@ -1,5 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; @@ -19,15 +17,17 @@ const _sourceId = 'openStreetMap'; class _LayersRasterPageState extends State { late final MapController _controller; + // If you are looking for just a way how to display OpenStreetMap on the + // map then this is NOT the right approach. You can create a Style JSON that + // contains only a raster source for the OpenStreetMap tile server and one + // raster layer to display the raster source on the map. + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Raster Layer')), body: MapLibreMap( - options: MapOptions( - center: Position(-120, 50), - zoom: 2, - ), + options: MapOptions(center: Position(-120, 50), zoom: 2), onMapCreated: (controller) => _controller = controller, onStyleLoaded: _onStyleLoaded, ), @@ -41,7 +41,7 @@ class _LayersRasterPageState extends State { maxZoom: 20, tileSize: 256, attribution: - 'OpenStreetMap', + 'OpenStreetMap', ); await _controller.addSource(openStreetMap); await _controller.addLayer(_rasterLayer); diff --git a/example/lib/main.dart b/example/lib/main.dart index 9b1cfd90..14008796 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; -import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/kiosk_page.dart'; import 'package:maplibre_example/layers_circle_page.dart'; +import 'package:maplibre_example/layers_fill_extrusion_page.dart'; +import 'package:maplibre_example/layers_fill_page.dart'; import 'package:maplibre_example/layers_heatmap_page.dart'; import 'package:maplibre_example/layers_hillshade_page.dart'; +import 'package:maplibre_example/layers_line_page.dart'; import 'package:maplibre_example/layers_raster_page.dart'; import 'package:maplibre_example/menu_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; @@ -32,9 +35,13 @@ class MyApp extends StatelessWidget { LayersCirclePage.location: (context) => const LayersCirclePage(), LayersHeatmapPage.location: (context) => const LayersHeatmapPage(), LayersHillshadePage.location: (context) => const LayersHillshadePage(), + LayersFillPage.location: (context) => const LayersFillPage(), + LayersFillExtrusionPage.location: (context) => + const LayersFillExtrusionPage(), LayersRasterPage.location: (context) => const LayersRasterPage(), + LayersLinePage.location: (context) => const LayersLinePage(), WebControlsPage.location: (context) => const WebControlsPage(), - GeoJsonPage.location: (context) => const GeoJsonPage(), + AnnotationsPage.location: (context) => const AnnotationsPage(), CallbacksPage.location: (context) => const CallbacksPage(), ControllerPage.location: (context) => const ControllerPage(), TwoMapsPage.location: (context) => const TwoMapsPage(), diff --git a/example/lib/menu_page.dart b/example/lib/menu_page.dart index 8b522ea9..b43f0682 100644 --- a/example/lib/menu_page.dart +++ b/example/lib/menu_page.dart @@ -1,11 +1,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:maplibre_example/annotations_page.dart'; import 'package:maplibre_example/callbacks_page.dart'; import 'package:maplibre_example/controller_page.dart'; -import 'package:maplibre_example/geojson_page.dart'; import 'package:maplibre_example/layers_circle_page.dart'; +import 'package:maplibre_example/layers_fill_extrusion_page.dart'; +import 'package:maplibre_example/layers_fill_page.dart'; import 'package:maplibre_example/layers_heatmap_page.dart'; import 'package:maplibre_example/layers_hillshade_page.dart'; +import 'package:maplibre_example/layers_line_page.dart'; import 'package:maplibre_example/layers_raster_page.dart'; import 'package:maplibre_example/styled_map_page.dart'; import 'package:maplibre_example/two_maps_page.dart'; @@ -33,9 +36,9 @@ class MenuPage extends StatelessWidget { location: StyledMapPage.location, ), ItemCard( - label: 'GeoJSON', + label: 'Annotations', iconData: Icons.location_on, - location: GeoJsonPage.location, + location: AnnotationsPage.location, ), ItemCard( label: 'Callbacks', @@ -70,6 +73,16 @@ class MenuPage extends StatelessWidget { iconData: Icons.circle, location: LayersCirclePage.location, ), + ItemCard( + label: 'Fill', + iconData: Icons.format_shapes, + location: LayersFillPage.location, + ), + ItemCard( + label: 'Fill Extrusion', + iconData: Icons.house, + location: LayersFillExtrusionPage.location, + ), ItemCard( label: 'Heatmap', iconData: Icons.thermostat, @@ -80,6 +93,11 @@ class MenuPage extends StatelessWidget { iconData: Icons.landscape, location: LayersHillshadePage.location, ), + ItemCard( + label: 'Line', + iconData: Icons.polyline, + location: LayersLinePage.location, + ), ItemCard( label: 'Raster', iconData: Icons.grid_on, diff --git a/example/lib/styled_map_page.dart b/example/lib/styled_map_page.dart index 144250f4..9c5a6a46 100644 --- a/example/lib/styled_map_page.dart +++ b/example/lib/styled_map_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/two_maps_page.dart b/example/lib/two_maps_page.dart index 0775e086..2ed4906c 100644 --- a/example/lib/two_maps_page.dart +++ b/example/lib/two_maps_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/web_controls_page.dart b/example/lib/web_controls_page.dart index 32e10885..1f60bbc9 100644 --- a/example/lib/web_controls_page.dart +++ b/example/lib/web_controls_page.dart @@ -1,4 +1,3 @@ -// ignore_for_file: prefer_single_quotes, require_trailing_commas import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; From 279f171078aed280799673b8fc2c54ee0eefaa60 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:05:35 +0200 Subject: [PATCH 18/24] implement fill extrusion example --- example/lib/annotations_page.dart | 1 - example/lib/layers_circle_page.dart | 2 + example/lib/layers_fill_extrusion_page.dart | 50 ++++++++++++++------- example/lib/layers_heatmap_page.dart | 2 + example/lib/styled_map_page.dart | 18 ++++---- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/example/lib/annotations_page.dart b/example/lib/annotations_page.dart index f3653f0b..6305320b 100644 --- a/example/lib/annotations_page.dart +++ b/example/lib/annotations_page.dart @@ -1,6 +1,5 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:maplibre/maplibre.dart'; @immutable diff --git a/example/lib/layers_circle_page.dart b/example/lib/layers_circle_page.dart index bb7e9186..6f9648af 100644 --- a/example/lib/layers_circle_page.dart +++ b/example/lib/layers_circle_page.dart @@ -1,4 +1,6 @@ +// ignore_for_file: require_trailing_commas + import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/layers_fill_extrusion_page.dart b/example/lib/layers_fill_extrusion_page.dart index 0d2b8b8b..f254ee72 100644 --- a/example/lib/layers_fill_extrusion_page.dart +++ b/example/lib/layers_fill_extrusion_page.dart @@ -1,6 +1,8 @@ +// ignore_for_file: require_trailing_commas + import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:maplibre/maplibre.dart'; +import 'package:maplibre_example/styled_map_page.dart'; @immutable class LayersFillExtrusionPage extends StatefulWidget { @@ -13,8 +15,7 @@ class LayersFillExtrusionPage extends StatefulWidget { _LayersFillExtrusionPageState(); } -const _layerId = 'showcaseLayer'; -const _sourceId = 'hills'; +const _sourceId = 'floorplan'; class _LayersFillExtrusionPageState extends State { late final MapController _controller; @@ -25,8 +26,11 @@ class _LayersFillExtrusionPageState extends State { appBar: AppBar(title: const Text('Fill Extrusion Layer')), body: MapLibreMap( options: MapOptions( - center: Position(11.39085, 47.27574), - zoom: 10, + center: Position(-87.61694, 41.86625), + zoom: 15.99, + tilt: 40, + bearing: 20, + style: StyledMapPage.styleUrl, ), onMapCreated: (controller) => _controller = controller, onStyleLoaded: _onStyleLoaded, @@ -35,20 +39,34 @@ class _LayersFillExtrusionPageState extends State { } Future _onStyleLoaded() async { - final geojsonPolygon = - await rootBundle.loadString('assets/geojson/lake-constance.json'); await _controller.addSource( - GeoJsonSource(id: 'LakeConstance', data: geojsonPolygon), - ); - await _controller.addLayer( - const FillLayer( - id: 'geojson-fill', - sourceId: 'LakeConstance', - paint: {'fill-color': '#429ef5'}, + const GeoJsonSource( + id: _sourceId, + data: + 'https://maplibre.org/maplibre-gl-js/docs/assets/indoor-3d-map.geojson', ), ); + await _controller.addLayer(_fillExtrusionLayer); } } -// TODO fill extrusion layer -// TODO line layer +const _fillExtrusionLayer = FillExtrusionLayer( + id: 'room-extrusion', + sourceId: _sourceId, + paint: { + // See the MapLibre Style Specification for details on data expressions. + // https://maplibre.org/maplibre-style-spec/expressions/ + + // Get the fill-extrusion-color from the source 'color' property. + 'fill-extrusion-color': ['get', 'color'], + + // Get fill-extrusion-height from the source 'height' property. + 'fill-extrusion-height': ['get', 'height'], + + // Get fill-extrusion-base from the source 'base_height' property. + 'fill-extrusion-base': ['get', 'base_height'], + + // Make extrusions slightly opaque for see through indoor walls. + 'fill-extrusion-opacity': 0.5 + }, +); diff --git a/example/lib/layers_heatmap_page.dart b/example/lib/layers_heatmap_page.dart index 757561fa..32663ae8 100644 --- a/example/lib/layers_heatmap_page.dart +++ b/example/lib/layers_heatmap_page.dart @@ -1,3 +1,5 @@ +// ignore_for_file: require_trailing_commas + import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/styled_map_page.dart b/example/lib/styled_map_page.dart index 9c5a6a46..2300a9a9 100644 --- a/example/lib/styled_map_page.dart +++ b/example/lib/styled_map_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; @@ -8,26 +7,29 @@ class StyledMapPage extends StatefulWidget { static const location = '/styled-map'; - @override - State createState() => _StyledMapPageState(); -} - -class _StyledMapPageState extends State { /// **Use your own key for your project!** /// This key will be rotated occasionally. /// Protomaps offers free usage for non commercial projects and affordable /// pricing for commercial projects. Alternatively, you can host a tile /// server yourself. https://protomaps.com/ - static const _styleUrl = + static const styleUrl = 'https://api.protomaps.com/styles/v2/light.json?key=a6f9aebb3965458c'; + @override + State createState() => _StyledMapPageState(); +} + +class _StyledMapPageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Styled Map')), body: MapLibreMap( options: MapOptions( - center: Position(9.17, 47.68), zoom: 8, style: _styleUrl), + center: Position(9.17, 47.68), + zoom: 8, + style: StyledMapPage.styleUrl, + ), ), ); } From 53e5af2bf2bf8ea048de17564e462e3de019eb82 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:31:35 +0200 Subject: [PATCH 19/24] Update MapLibreMapController.kt --- .../com/github/josxha/maplibre/MapLibreMapController.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 86a45d81..70c467c1 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -394,7 +394,12 @@ class MapLibreMapController( data: String, callback: (Result) -> Unit ) { - mapLibreMap.style?.addSource(GeoJsonSource(id, data)) + if (data.first() == '{') { + mapLibreMap.style?.addSource(GeoJsonSource(id, data)) + } else { + val uri = URI(data) + mapLibreMap.style?.addSource(GeoJsonSource(id, uri)) + } callback(Result.success(Unit)) } From 0982b8db99303912cf8e11d7836648c3c928147e Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:32:07 +0200 Subject: [PATCH 20/24] dart format --- example/lib/callbacks_page.dart | 1 - example/lib/controller_page.dart | 1 - example/lib/layers_circle_page.dart | 1 - example/lib/two_maps_page.dart | 1 - example/lib/web_controls_page.dart | 1 - 5 files changed, 5 deletions(-) diff --git a/example/lib/callbacks_page.dart b/example/lib/callbacks_page.dart index 2c3a9d21..44cb396a 100644 --- a/example/lib/callbacks_page.dart +++ b/example/lib/callbacks_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/controller_page.dart b/example/lib/controller_page.dart index 81ad2c9f..f548b124 100644 --- a/example/lib/controller_page.dart +++ b/example/lib/controller_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/layers_circle_page.dart b/example/lib/layers_circle_page.dart index 6f9648af..0311c78b 100644 --- a/example/lib/layers_circle_page.dart +++ b/example/lib/layers_circle_page.dart @@ -1,4 +1,3 @@ - // ignore_for_file: require_trailing_commas import 'package:flutter/material.dart'; diff --git a/example/lib/two_maps_page.dart b/example/lib/two_maps_page.dart index 2ed4906c..c46e3d07 100644 --- a/example/lib/two_maps_page.dart +++ b/example/lib/two_maps_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; diff --git a/example/lib/web_controls_page.dart b/example/lib/web_controls_page.dart index 1f60bbc9..3d438485 100644 --- a/example/lib/web_controls_page.dart +++ b/example/lib/web_controls_page.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:maplibre/maplibre.dart'; From 6dbc040a1a76647a4cd28d0c7c5eb0816a3f5da9 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:43:39 +0200 Subject: [PATCH 21/24] Update MapLibreMapController.kt --- .../github/josxha/maplibre/MapLibreMapController.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 70c467c1..df858e7a 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -37,6 +37,7 @@ import org.maplibre.android.style.layers.LineLayer import org.maplibre.android.style.layers.PropertyValue import org.maplibre.android.style.layers.RasterLayer import org.maplibre.android.style.layers.SymbolLayer +import org.maplibre.android.style.sources.GeoJsonOptions import org.maplibre.android.style.sources.GeoJsonSource import org.maplibre.android.style.sources.ImageSource import org.maplibre.android.style.sources.RasterDemSource @@ -394,12 +395,13 @@ class MapLibreMapController( data: String, callback: (Result) -> Unit ) { - if (data.first() == '{') { - mapLibreMap.style?.addSource(GeoJsonSource(id, data)) + val options = GeoJsonOptions() + val source = if (data.first() == '{') { + GeoJsonSource(id, data, options) } else { - val uri = URI(data) - mapLibreMap.style?.addSource(GeoJsonSource(id, uri)) + GeoJsonSource(id, URI(data), options) } + mapLibreMap.style?.addSource(source) callback(Result.success(Unit)) } From b16036498f1fa6410d69ec06148fa29f47dfefae Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:52:20 +0200 Subject: [PATCH 22/24] correctly pass paint and layout properties to layers --- .../josxha/maplibre/MapLibreMapController.kt | 69 ++++++++----------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index df858e7a..6b18f7c7 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -11,10 +11,10 @@ import ScreenLocation import TileScheme import android.content.Context import android.graphics.PointF -import android.net.Uri import android.view.View import android.widget.FrameLayout import androidx.lifecycle.DefaultLifecycleObserver +import com.google.gson.Gson import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.platform.PlatformView import org.maplibre.android.MapLibre @@ -27,6 +27,7 @@ import org.maplibre.android.maps.MapLibreMapOptions import org.maplibre.android.maps.MapView import org.maplibre.android.maps.OnMapReadyCallback import org.maplibre.android.maps.Style +import org.maplibre.android.style.expressions.Expression import org.maplibre.android.style.layers.BackgroundLayer import org.maplibre.android.style.layers.CircleLayer import org.maplibre.android.style.layers.FillExtrusionLayer @@ -34,6 +35,7 @@ import org.maplibre.android.style.layers.FillLayer import org.maplibre.android.style.layers.HeatmapLayer import org.maplibre.android.style.layers.HillshadeLayer import org.maplibre.android.style.layers.LineLayer +import org.maplibre.android.style.layers.PaintPropertyValue import org.maplibre.android.style.layers.PropertyValue import org.maplibre.android.style.layers.RasterLayer import org.maplibre.android.style.layers.SymbolLayer @@ -42,12 +44,11 @@ import org.maplibre.android.style.sources.GeoJsonSource import org.maplibre.android.style.sources.ImageSource import org.maplibre.android.style.sources.RasterDemSource import org.maplibre.android.style.sources.RasterSource -import org.maplibre.android.style.sources.TileSet import org.maplibre.android.style.sources.VectorSource import java.net.URI -import java.net.URL import kotlin.coroutines.cancellation.CancellationException + class MapLibreMapController( viewId: Int, private val context: Context, @@ -172,6 +173,23 @@ class MapLibreMapController( callback(Result.success(LngLat(latLng.longitude, latLng.latitude))) } + private val gson = Gson() + private fun parseProperties(entries: Map): Array> { + return entries.map { entry -> + // println("${entry.key}; ${entry.value::class.java.typeName}; ${entry.value}") + when (entry.value) { + is ArrayList<*> -> { + val value = entry.value as ArrayList<*> + val json = gson.toJsonTree(value) + val expression = Expression.Converter.convert(json) + PaintPropertyValue(entry.key, expression) + } + + else -> PaintPropertyValue(entry.key, entry.value) + } + }.toTypedArray() + } + override fun addFillLayer( id: String, sourceId: String, @@ -181,10 +199,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = FillLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -202,10 +217,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = CircleLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -222,10 +234,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = BackgroundLayer(id) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -243,10 +252,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = FillExtrusionLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -264,10 +270,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = HeatmapLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -285,10 +288,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = HillshadeLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -306,10 +306,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = LineLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -327,10 +324,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = RasterLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -348,10 +342,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = SymbolLayer(id, sourceId) - var properties = paint.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) - properties = layout.map { entry -> PropertyValue(entry.key, entry.value) } - layer.setProperties(*properties.toTypedArray()) + layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { From 0ef8c5d1d6d4e683713175249a8c06283680e385 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:28:31 +0200 Subject: [PATCH 23/24] android: fix raster layer example --- .../github/josxha/maplibre/MapLibreMapController.kt | 13 +++++++++++-- example/lib/layers_raster_page.dart | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt index 6b18f7c7..e09275c1 100644 --- a/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt +++ b/android/src/main/kotlin/com/github/josxha/maplibre/MapLibreMapController.kt @@ -44,6 +44,7 @@ import org.maplibre.android.style.sources.GeoJsonSource import org.maplibre.android.style.sources.ImageSource import org.maplibre.android.style.sources.RasterDemSource import org.maplibre.android.style.sources.RasterSource +import org.maplibre.android.style.sources.TileSet import org.maplibre.android.style.sources.VectorSource import java.net.URI import kotlin.coroutines.cancellation.CancellationException @@ -324,7 +325,7 @@ class MapLibreMapController( callback: (Result) -> Unit ) { val layer = RasterLayer(id, sourceId) - layer.setProperties(*parseProperties(paint), *parseProperties(layout)) +// layer.setProperties(*parseProperties(paint), *parseProperties(layout)) if (belowLayerId == null) { mapLibreMap.style?.addLayer(layer) } else { @@ -426,7 +427,15 @@ class MapLibreMapController( volatile: Boolean, callback: (Result) -> Unit ) { - val source = RasterSource(id, url, tileSize.toInt()) + val source = if (url == null) { + // TODO improve this + val tileSet = TileSet("{}", tiles!!.first()) + tileSet.maxZoom = maxZoom.toFloat() + tileSet.minZoom = minZoom.toFloat() + RasterSource(id, tileSet, tileSize.toInt()) + } else { + RasterSource(id, url, tileSize.toInt()) + } source.isVolatile = volatile // TODO apply other properties mapLibreMap.style?.addSource(source) diff --git a/example/lib/layers_raster_page.dart b/example/lib/layers_raster_page.dart index a8e027f1..9eba3668 100644 --- a/example/lib/layers_raster_page.dart +++ b/example/lib/layers_raster_page.dart @@ -27,7 +27,7 @@ class _LayersRasterPageState extends State { return Scaffold( appBar: AppBar(title: const Text('Raster Layer')), body: MapLibreMap( - options: MapOptions(center: Position(-120, 50), zoom: 2), + options: MapOptions(center: Position(9, 48), zoom: 7), onMapCreated: (controller) => _controller = controller, onStyleLoaded: _onStyleLoaded, ), From ec9eea762b6b2e39b78d03f57a5c46c6505dc080 Mon Sep 17 00:00:00 2001 From: Joscha <34318751+josxha@users.noreply.github.com> Date: Tue, 17 Sep 2024 22:51:05 +0200 Subject: [PATCH 24/24] Update CHANGELOG.md --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3881de74..3488edc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,18 +2,19 @@ ### Features -- add `duration` parameter to `flyTo()` +- Add `duration` parameter to `flyTo()`. - `flyTo()` returns after the animation completes or throws an exception if it - has been cancelled + has been cancelled. +- Add sources and layers to the map programmatically. ### Bug fixes -- fix `jumpTo()` never returns +- Fix `jumpTo()` never returns ## 0.0.1+1 -- fix urls to website and embedded screenshots -- remove unused `plugin_platform_interface` dependency +- Fix urls to website and embedded screenshots +- Remove unused `plugin_platform_interface` dependency ## 0.0.1