From b9a7361d500ed63dad9e0e97c45d9209a0b562b1 Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 25 Apr 2024 01:04:42 +0200 Subject: [PATCH 01/12] Add ground overlay platform interface and android implementation --- .../example/lib/ground_overlay.dart | 140 ++++++++++ .../google_maps_flutter/example/lib/main.dart | 2 + .../google_maps_flutter/example/pubspec.yaml | 5 + .../lib/google_maps_flutter.dart | 2 + .../lib/src/controller.dart | 15 ++ .../lib/src/google_map.dart | 29 +++ .../google_maps_flutter/pubspec.yaml | 5 + .../flutter/plugins/googlemaps/Convert.java | 59 +++++ .../plugins/googlemaps/GoogleMapBuilder.java | 7 + .../googlemaps/GoogleMapController.java | 37 +++ .../plugins/googlemaps/GoogleMapFactory.java | 3 + .../plugins/googlemaps/GoogleMapListener.java | 1 + .../googlemaps/GoogleMapOptionsSink.java | 2 + .../googlemaps/GroundOverlayBuilder.java | 69 +++++ .../googlemaps/GroundOverlayController.java | 80 ++++++ .../googlemaps/GroundOverlayOptionsSink.java | 19 ++ .../googlemaps/GroundOverlaysController.java | 114 +++++++++ .../example/pubspec.yaml | 5 + .../lib/src/google_maps_flutter_android.dart | 29 +++ .../google_maps_flutter_android/pubspec.yaml | 5 + .../example/ios14/pubspec.yaml | 5 + .../shared/maps_example_dart/pubspec.yaml | 5 + .../lib/src/google_maps_flutter_ios.dart | 21 +- .../google_maps_flutter_ios/pubspec.yaml | 5 + .../lib/src/events/map_event.dart | 9 + .../method_channel_google_maps_flutter.dart | 39 ++- .../google_maps_flutter_platform.dart | 20 ++ .../lib/src/types/ground_overlay.dart | 241 ++++++++++++++++++ .../lib/src/types/ground_overlay_updates.dart | 22 ++ .../lib/src/types/map_objects.dart | 2 + .../lib/src/types/types.dart | 3 + .../lib/src/types/utils/ground_overlay.dart | 15 ++ .../google_maps_flutter_platform_test.dart | 1 + .../example/pubspec.yaml | 7 +- .../google_maps_flutter_web/pubspec.yaml | 5 + 35 files changed, 1016 insertions(+), 12 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java create mode 100644 packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart new file mode 100644 index 000000000000..1d4b4a41b517 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'page.dart'; + +class GroundOverlayPage extends GoogleMapExampleAppPage { + const GroundOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Ground overlay', key: key); + + @override + Widget build(BuildContext context) { + return const GroundOverlayBody(); + } +} + +class GroundOverlayBody extends StatefulWidget { + const GroundOverlayBody({super.key}); + + @override + State createState() => GroundOverlayBodyState(); +} + +class GroundOverlayBodyState extends State { + GroundOverlayBodyState(); + + GoogleMapController? controller; + BitmapDescriptor? _overlayImage; + double _bearing = 0; + double _opacity = 1.0; + + // ignore: use_setters_to_change_properties + void _onMapCreated(GoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeGroundOverlay() { + setState(() { + _overlayImage = null; + }); + } + + void _addGroundOverlay() { + BitmapDescriptor.fromAssetImage( + ImageConfiguration.empty, + 'assets/red_square.png', + ).then((BitmapDescriptor bitmap) { + setState(() { + _overlayImage = bitmap; + }); + }); + } + + @override + Widget build(BuildContext context) { + final Set overlays = { + if (_overlayImage != null) + GroundOverlay( + groundOverlayId: const GroundOverlayId('ground_overlay_1'), + bitmap: _overlayImage, + location: const LatLng(59.935460, 30.325177), + width: 200, + bearing: _bearing, + opacity: _opacity, + ), + }; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: GoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 15.0, + ), + groundOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + ), + ...[ + if (overlays.isEmpty) + TextButton( + onPressed: _addGroundOverlay, + child: const Text('Add ground overlay'), + ), + if (overlays.isNotEmpty) + TextButton( + onPressed: _removeGroundOverlay, + child: const Text('Remove ground overlay'), + ), + if (overlays.isNotEmpty) + const Padding(padding: EdgeInsets.all(8), child: Text('Bearing')), + if (overlays.isNotEmpty) + Slider( + label: 'Bearing', + value: _bearing, + max: 360, + onChanged: (double value) { + setState(() { + _bearing = value; + }); + }, + ), + if (overlays.isNotEmpty) + const Padding( + padding: EdgeInsets.all(8), + child: Text('Opacity'), + ), + if (overlays.isNotEmpty) + Slider( + label: 'Opacity', + value: _opacity * 100, + max: 100, + onChanged: (double value) { + setState(() { + _opacity = value / 100.0; + }); + }, + ), + ], + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart index a0060e1c7254..8395baa28451 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart @@ -9,6 +9,7 @@ import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'animate_camera.dart'; +import 'ground_overlay.dart'; import 'lite_mode.dart'; import 'map_click.dart'; import 'map_coordinates.dart'; @@ -42,6 +43,7 @@ final List _allPages = [ const SnapshotPage(), const LiteModePage(), const TileOverlayPage(), + const GroundOverlayPage(), const MapIdPage(), ]; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 4911beb65792..7d83cb2b8f87 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -33,3 +33,8 @@ flutter: uses-material-design: true assets: - assets/ + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_android: {path: ../../../google_maps_flutter/google_maps_flutter_android}, google_maps_flutter_ios: {path: ../../../google_maps_flutter/google_maps_flutter_ios}, google_maps_flutter_platform_interface: {path: ../../../google_maps_flutter/google_maps_flutter_platform_interface}, google_maps_flutter_web: {path: ../../../google_maps_flutter/google_maps_flutter_web}} diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index 7eb4af947318..4db8ab30010c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -27,6 +27,8 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf Cap, Circle, CircleId, + GroundOverlay, + GroundOverlayId, InfoWindow, JointType, LatLng, diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart index 393288a6165f..f57670a1fdf8 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/controller.dart @@ -74,6 +74,9 @@ class GoogleMapController { GoogleMapsFlutterPlatform.instance .onCircleTap(mapId: mapId) .listen((CircleTapEvent e) => _googleMapState.onCircleTap(e.value)); + GoogleMapsFlutterPlatform.instance.onGroundOverlayTap(mapId: mapId).listen( + (GroundOverlayTapEvent e) => + _googleMapState.onGroundOverlayTap(e.value)); GoogleMapsFlutterPlatform.instance .onTap(mapId: mapId) .listen((MapTapEvent e) => _googleMapState.onTap(e.position)); @@ -159,6 +162,18 @@ class GoogleMapController { .clearTileCache(tileOverlayId, mapId: mapId); } + /// Updates ground overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future _updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates) { + return GoogleMapsFlutterPlatform.instance + .updateGroundOverlays(groundOverlayUpdates, mapId: mapId); + } + /// Starts an animated change of the map camera position. /// /// The returned [Future] completes after the change has been started on the diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart index c50ffccfa634..ff0c915a0471 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart @@ -122,6 +122,7 @@ class GoogleMap extends StatefulWidget { this.circles = const {}, this.onCameraMoveStarted, this.tileOverlays = const {}, + this.groundOverlays = const {}, this.onCameraMove, this.onCameraIdle, this.onTap, @@ -217,6 +218,9 @@ class GoogleMap extends StatefulWidget { /// Tile overlays to be placed on the map. final Set tileOverlays; + /// Ground overlays to be placed on the map. + final Set groundOverlays; + /// Called when the camera starts moving. /// /// This can be initiated by the following: @@ -328,6 +332,8 @@ class _GoogleMapState extends State { Map _polygons = {}; Map _polylines = {}; Map _circles = {}; + Map _groundOverlays = + {}; late MapConfiguration _mapConfiguration; @override @@ -347,6 +353,7 @@ class _GoogleMapState extends State { polygons: widget.polygons, polylines: widget.polylines, circles: widget.circles, + groundOverlays: widget.groundOverlays, ), mapConfiguration: _mapConfiguration, ); @@ -360,6 +367,7 @@ class _GoogleMapState extends State { _polygons = keyByPolygonId(widget.polygons); _polylines = keyByPolylineId(widget.polylines); _circles = keyByCircleId(widget.circles); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); } @override @@ -382,6 +390,7 @@ class _GoogleMapState extends State { _updatePolylines(); _updateCircles(); _updateTileOverlays(); + _updateGroundOverlays(); } Future _updateOptions() async { @@ -428,6 +437,14 @@ class _GoogleMapState extends State { unawaited(controller._updateTileOverlays(widget.tileOverlays)); } + Future _updateGroundOverlays() async { + final GoogleMapController controller = await _controller.future; + + unawaited(controller._updateGroundOverlays(GroundOverlayUpdates.from( + _groundOverlays.values.toSet(), widget.groundOverlays))); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + Future onPlatformViewCreated(int id) async { final GoogleMapController controller = await GoogleMapController.init( id, @@ -436,6 +453,7 @@ class _GoogleMapState extends State { ); _controller.complete(controller); unawaited(_updateTileOverlays()); + unawaited(_updateGroundOverlays()); final MapCreatedCallback? onMapCreated = widget.onMapCreated; if (onMapCreated != null) { onMapCreated(controller); @@ -519,6 +537,17 @@ class _GoogleMapState extends State { } } + void onGroundOverlayTap(GroundOverlayId groundOverlayId) { + final GroundOverlay? groundOverlay = _groundOverlays[groundOverlayId]; + if (groundOverlay == null) { + throw UnknownMapObjectIdError('groundOverlay', groundOverlayId, 'onTap'); + } + final VoidCallback? onTap = groundOverlay.onTap; + if (onTap != null) { + onTap(); + } + } + void onInfoWindowTap(MarkerId markerId) { final Marker? marker = _markers[markerId]; if (marker == null) { diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 3ab5430b0955..acdcb2f03751 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -40,3 +40,8 @@ topics: # The example deliberately includes limited-use secrets. false_secrets: - /example/web/index.html + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_android: {path: ../../google_maps_flutter/google_maps_flutter_android}, google_maps_flutter_ios: {path: ../../google_maps_flutter/google_maps_flutter_ios}, google_maps_flutter_platform_interface: {path: ../../google_maps_flutter/google_maps_flutter_platform_interface}, google_maps_flutter_web: {path: ../../google_maps_flutter/google_maps_flutter_web}} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 8b0796207d3c..9aa25b781188 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -427,6 +427,15 @@ static Map tileOverlayArgumentsToJson( return data; } + static Object groundOverlayIdToJson(String groundOverlayId) { + if (groundOverlayId == null) { + return null; + } + final Map data = new HashMap<>(1); + data.put("groundOverlayId", groundOverlayId); + return data; + } + static Object latLngToJson(LatLng latLng) { return Arrays.asList(latLng.latitude, latLng.longitude); } @@ -861,6 +870,56 @@ static String interpretCircleOptions(Object o, CircleOptionsSink sink) { } } + static String interpretGroundOverlayOptions(Object o, GroundOverlayOptionsSink sink) { + final Map data = toMap(o); + final Object consumeTapEvents = data.get("consumeTapEvents"); + if (consumeTapEvents != null) { + sink.setConsumeTapEvents(toBoolean(consumeTapEvents)); + } + final Object transparency = data.get("transparency"); + if (transparency != null) { + sink.setTransparency(toFloat(transparency)); + } + + final Object width = data.get("width"); + final Object height = data.get("height"); + final Object location = data.get("location"); + final Object bounds = data.get("bounds"); + if (height != null) { + sink.setLocation(toLatLng(location), toFloat(width), toFloat(height), null); + } else { + if (width != null) { + sink.setLocation(toLatLng(location), toFloat(width), null, null); + } else { + sink.setLocation(null, null, null, toLatLngBounds(bounds)); + } + } + + final Object bearing = data.get("bearing"); + if (bearing != null) { + sink.setBearing(toFloat(bearing)); + } + final Object visible = data.get("visible"); + if (visible != null) { + sink.setVisible(toBoolean(visible)); + } + final Object zIndex = data.get("zIndex"); + if (zIndex != null) { + sink.setZIndex(toFloat(zIndex)); + } + + final Object bitmap = data.get("bitmap"); + if (bitmap != null) { + sink.setBitmapDescriptor(toBitmapDescriptor(bitmap)); + } + final String groundOverlayId = (String) data.get("groundOverlayId"); + if (groundOverlayId == null) { + throw new IllegalArgumentException("groundOverlayId was null"); + } else { + return groundOverlayId; + } + } + @VisibleForTesting static List toPoints(Object o) { final List data = toList(o); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index 02477418d425..3317301962e9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -28,6 +28,7 @@ class GoogleMapBuilder implements GoogleMapOptionsSink { private Object initialPolylines; private Object initialCircles; private List> initialTileOverlays; + private Object initialGroundOverlays; private Rect padding = new Rect(0, 0, 0, 0); private @Nullable String style; @@ -52,6 +53,7 @@ GoogleMapController build( controller.setInitialCircles(initialCircles); controller.setPadding(padding.top, padding.left, padding.bottom, padding.right); controller.setInitialTileOverlays(initialTileOverlays); + controller.setInitialGroundOverlays(initialGroundOverlays); controller.setMapStyle(style); return controller; } @@ -189,6 +191,11 @@ public void setInitialTileOverlays(List> initialTileOverlays) { this.initialTileOverlays = initialTileOverlays; } + @Override + public void setInitialGroundOverlays(Object initialGroundOverlays) { + this.initialGroundOverlays = initialGroundOverlays; + } + @Override public void setMapStyle(@Nullable String style) { this.style = style; diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 24d66fed24c5..54a49c056bd7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -32,6 +32,7 @@ import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.model.CameraPosition; import com.google.android.gms.maps.model.Circle; +import com.google.android.gms.maps.model.GroundOverlay; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; import com.google.android.gms.maps.model.MapStyleOptions; @@ -89,6 +90,7 @@ class GoogleMapController private final PolylinesController polylinesController; private final CirclesController circlesController; private final TileOverlaysController tileOverlaysController; + private final GroundOverlaysController groundOverlaysController; private MarkerManager markerManager; private MarkerManager.Collection markerCollection; private List initialMarkers; @@ -97,6 +99,7 @@ class GoogleMapController private List initialPolylines; private List initialCircles; private List> initialTileOverlays; + private List initialGroundOverlays; // Null except between initialization and onMapReady. private @Nullable String initialMapStyle; private @Nullable String lastStyleError; @@ -125,6 +128,7 @@ class GoogleMapController this.polylinesController = new PolylinesController(methodChannel, assetManager, density); this.circlesController = new CirclesController(methodChannel, density); this.tileOverlaysController = new TileOverlaysController(methodChannel); + this.groundOverlaysController = new GroundOverlaysController(methodChannel); } // Constructor for testing purposes only @@ -204,6 +208,7 @@ public void onMapReady(GoogleMap googleMap) { polylinesController.setGoogleMap(googleMap); circlesController.setGoogleMap(googleMap); tileOverlaysController.setGoogleMap(googleMap); + groundOverlaysController.setGoogleMap(googleMap); setMarkerCollectionListener(this); setClusterItemClickListener(this); setClusterItemRenderedListener(this); @@ -213,6 +218,7 @@ public void onMapReady(GoogleMap googleMap) { updateInitialPolylines(); updateInitialCircles(); updateInitialTileOverlays(); + updateInitialGroundOverlays(); if (initialPadding != null && initialPadding.size() == 4) { setPadding( initialPadding.get(0), @@ -466,6 +472,17 @@ public void onSnapshotReady(Bitmap bitmap) { result.success(null); break; } + case "groundOverlays#update": + { + List groundOverlaysToAdd = call.argument("groundOverlaysToAdd"); + groundOverlaysController.addGroundOverlays(groundOverlaysToAdd); + List groundOverlaysToChange = call.argument("groundOverlaysToChange"); + groundOverlaysController.changeGroundOverlays(groundOverlaysToChange); + List groundOverlayIdsToRemove = call.argument("groundOverlayIdsToRemove"); + groundOverlaysController.removeGroundOverlays(groundOverlayIdsToRemove); + result.success(null); + break; + } case "map#isCompassEnabled": { result.success(googleMap.getUiSettings().isCompassEnabled()); @@ -659,6 +676,11 @@ public void onCircleClick(Circle circle) { circlesController.onCircleTap(circle.getId()); } + @Override + public void onGroundOverlayClick(GroundOverlay groundOverlay) { + groundOverlaysController.onGroundOverlayTap(groundOverlay.getId()); + } + @Override public void dispose() { if (disposed) { @@ -688,6 +710,7 @@ private void setGoogleMapListener(@Nullable GoogleMapListener listener) { googleMap.setOnPolygonClickListener(listener); googleMap.setOnPolylineClickListener(listener); googleMap.setOnCircleClickListener(listener); + googleMap.setOnGroundOverlayClickListener(listener); googleMap.setOnMapClickListener(listener); googleMap.setOnMapLongClickListener(listener); } @@ -995,6 +1018,20 @@ private void updateInitialTileOverlays() { tileOverlaysController.addTileOverlays(initialTileOverlays); } + @Override + public void setInitialGroundOverlays(Object initialGroundOverlays) { + ArrayList groundOverlays = (ArrayList) initialGroundOverlays; + this.initialGroundOverlays = groundOverlays != null ? new ArrayList<>(groundOverlays) : null; + + if (googleMap != null) { + updateInitialGroundOverlays(); + } + } + + private void updateInitialGroundOverlays() { + groundOverlaysController.addGroundOverlays(initialGroundOverlays); + } + @SuppressLint("MissingPermission") private void updateMyLocationSettings() { if (hasLocationPermission()) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index b8d6485d35eb..bd5ae7c1d918 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -61,6 +61,9 @@ public PlatformView create(@NonNull Context context, int id, @Nullable Object ar if (params.containsKey("tileOverlaysToAdd")) { builder.setInitialTileOverlays((List>) params.get("tileOverlaysToAdd")); } + if (params.containsKey("groundOverlaysToAdd")) { + builder.setInitialGroundOverlays(params.get("groundOverlaysToAdd")); + } final Object cloudMapId = ((Map) options).get("cloudMapId"); if (cloudMapId != null) { builder.setMapId((String) cloudMapId); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java index 0a5c3ec67e27..8b44931447bc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapListener.java @@ -15,6 +15,7 @@ interface GoogleMapListener GoogleMap.OnPolygonClickListener, GoogleMap.OnPolylineClickListener, GoogleMap.OnCircleClickListener, + GoogleMap.OnGroundOverlayClickListener, GoogleMap.OnMapClickListener, GoogleMap.OnMapLongClickListener, GoogleMap.OnMarkerDragListener {} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java index 9f744a653b3c..4d13cc58c10f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java @@ -59,5 +59,7 @@ interface GoogleMapOptionsSink { void setInitialTileOverlays(List> initialTileOverlays); + void setInitialGroundOverlays(Object initialGroundOverlays); + void setMapStyle(@Nullable String style); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java new file mode 100644 index 000000000000..9c2ff0453302 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java @@ -0,0 +1,69 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.GroundOverlayOptions; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; + + +class GroundOverlayBuilder implements GroundOverlayOptionsSink { + private final GroundOverlayOptions groundOverlayOptions; + private boolean consumeTapEvents; + + GroundOverlayBuilder() { + groundOverlayOptions = new GroundOverlayOptions(); + } + + GroundOverlayOptions build() { + return groundOverlayOptions; + } + + boolean consumeTapEvents() { + return consumeTapEvents; + } + + @Override + public void setConsumeTapEvents(boolean consumeTapEvents) { + this.consumeTapEvents = consumeTapEvents; + groundOverlayOptions.clickable(consumeTapEvents); + } + + @Override + public void setVisible(boolean visible) { + groundOverlayOptions.visible(visible); + } + + @Override + public void setZIndex(float zIndex) { + groundOverlayOptions.zIndex(zIndex); + } + + @Override + public void setLocation(Object location, Object width, Object height, Object bounds) { + if (height != null) { + groundOverlayOptions.position((LatLng) location, (float) width, (float) height); + } else { + if (width != null) { + groundOverlayOptions.position((LatLng) location, (float) width); + } else { + groundOverlayOptions.positionFromBounds((LatLngBounds) bounds); + } + } + } + + @Override + public void setBitmapDescriptor(BitmapDescriptor bd) { + groundOverlayOptions.image(bd); + } + + @Override + public void setBearing(float bearing) { + groundOverlayOptions.bearing(bearing); + } + + @Override + public void setTransparency(float transparency) { + groundOverlayOptions.transparency(transparency); + } + +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java new file mode 100644 index 000000000000..5bf36ffe9e76 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java @@ -0,0 +1,80 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.GroundOverlay; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; + + +class GroundOverlayController implements GroundOverlayOptionsSink { + private final GroundOverlay groundOverlay; + private final String googleMapsGroundOverlayId; + private boolean consumeTapEvents; + + + GroundOverlayController(GroundOverlay groundOverlay, boolean consumeTapEvents) { + this.groundOverlay = groundOverlay; + this.consumeTapEvents = consumeTapEvents; + this.googleMapsGroundOverlayId = this.groundOverlay.getId(); + } + + + boolean consumeTapEvents() { + return consumeTapEvents; + } + + @Override + public void setConsumeTapEvents(boolean consumeTapEvents) { + this.consumeTapEvents = consumeTapEvents; + } + + @Override + public void setVisible(boolean visible) { + this.groundOverlay.setVisible(visible); + } + + @Override + public void setZIndex(float zIndex) { + this.groundOverlay.setZIndex(zIndex); + } + + void remove() { + groundOverlay.remove(); + } + + @Override + public void setLocation(Object location, Object width, Object height, Object bounds) { + if (height != null && width != null) { + this.groundOverlay.setDimensions((float) width, (float) height); + } else { + if (width != null) { + this.groundOverlay.setDimensions((float) width); + } + } + if (location != null) { + this.groundOverlay.setPosition((LatLng) location); + } + if (bounds != null) { + this.groundOverlay.setPositionFromBounds((LatLngBounds) bounds); + } + } + + @Override + public void setBitmapDescriptor(BitmapDescriptor bd) { + this.groundOverlay.setImage(bd); + } + + @Override + public void setBearing(float bearing) { + this.groundOverlay.setBearing(bearing); + } + + @Override + public void setTransparency(float transparency) { + this.groundOverlay.setTransparency(transparency); + } + + String getGoogleMapsGroundOverlayId() { + return this.googleMapsGroundOverlayId; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java new file mode 100644 index 000000000000..20f36a89236f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java @@ -0,0 +1,19 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.model.BitmapDescriptor; + +interface GroundOverlayOptionsSink { + void setConsumeTapEvents(boolean consumeTapEvents); + + void setVisible(boolean visible); + + void setZIndex(float zIndex); + + void setLocation(Object location, Object width, Object height, Object bounds); + + void setBitmapDescriptor(BitmapDescriptor bd); + + void setBearing(float bearing); + + void setTransparency(float transparency); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java new file mode 100644 index 000000000000..c35a0efffedf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java @@ -0,0 +1,114 @@ +package io.flutter.plugins.googlemaps; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.GroundOverlay; +import com.google.android.gms.maps.model.GroundOverlayOptions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.flutter.plugin.common.MethodChannel; + +class GroundOverlaysController { + + private GoogleMap googleMap; + private final Map groundOverlayIdToController; + private final Map googleMapsGroundOverlayIdToDartOverlayId; + private MethodChannel methodChannel; + + GroundOverlaysController(MethodChannel methodChannel) { + this.methodChannel = methodChannel; + this.groundOverlayIdToController = new HashMap<>(); + this.googleMapsGroundOverlayIdToDartOverlayId = new HashMap<>(); + } + + void setGoogleMap(GoogleMap googleMap) { + this.googleMap = googleMap; + } + + void addGroundOverlays(List groundOverlaysToAdd) { + if (groundOverlaysToAdd != null) { + for (Object groundOverlayToAdd : groundOverlaysToAdd) { + addGroundOverlay(groundOverlayToAdd); + } + } + } + + private void addGroundOverlay(Object groundOverlay) { + if (groundOverlay == null) { + return; + } + + GroundOverlayBuilder groundOverlayBuilder = new GroundOverlayBuilder(); + String groundOverlayId = Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayBuilder); + GroundOverlayOptions options = groundOverlayBuilder.build(); + addGroundOverlay(groundOverlayId, options, groundOverlayBuilder.consumeTapEvents()); + } + + private void addGroundOverlay( + String groundOverlayId, GroundOverlayOptions groundOverlayOptions, boolean consumeTapEvents) { + final GroundOverlay groundOverlay = googleMap.addGroundOverlay(groundOverlayOptions); + + GroundOverlayController controller = new GroundOverlayController(groundOverlay, consumeTapEvents); + groundOverlayIdToController.put(groundOverlayId, controller); + googleMapsGroundOverlayIdToDartOverlayId.put(groundOverlay.getId(), groundOverlayId); + + } + + boolean onGroundOverlayTap(String googleOverlayId) { + String overlayId = googleMapsGroundOverlayIdToDartOverlayId.get(googleOverlayId); + if (overlayId == null) { + return false; + } + methodChannel.invokeMethod("groundOverlay#onTap", Convert.groundOverlayIdToJson(overlayId)); + GroundOverlayController groundOverlayController = groundOverlayIdToController.get(overlayId); + if (groundOverlayController != null) { + return groundOverlayController.consumeTapEvents(); + } + return false; + } + + void changeGroundOverlays(List groundOverlaysToChange) { + if (groundOverlaysToChange != null) { + for (Object groundOverlayToChange : groundOverlaysToChange) { + changeGroundOverlay(groundOverlayToChange); + } + } + } + + private void changeGroundOverlay(Object groundOverlay) { + if (groundOverlay == null) { + return; + } + String groundOverlayId = getGroundOverlayId(groundOverlay); + GroundOverlayController groundOverlayController = groundOverlayIdToController.get(groundOverlayId); + if (groundOverlayController != null) { + Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayController); + } + } + + void removeGroundOverlays(List groundOverlaysToRemove) { + if (groundOverlaysToRemove == null) { + return; + } + + for (Object rawGroundOverlayId : groundOverlaysToRemove) { + if (rawGroundOverlayId == null) { + continue; + } + String groundOverlayId = (String) rawGroundOverlayId; + final GroundOverlayController groundOverlayController = groundOverlayIdToController.remove(groundOverlayId); + if (groundOverlayController != null) { + groundOverlayController.remove(); + googleMapsGroundOverlayIdToDartOverlayId.remove(groundOverlayController.getGoogleMapsGroundOverlayId()); + } + } + } + + @SuppressWarnings("unchecked") + private static String getGroundOverlayId(Object groundOverlay) { + Map overlayMap = (Map) groundOverlay; + return (String) overlayMap.get("groundOverlayId"); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml index ddac3d7b231c..aa0401915266 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml @@ -33,3 +33,8 @@ flutter: uses-material-design: true assets: - assets/ + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_android: {path: ../../../google_maps_flutter/google_maps_flutter_android}, google_maps_flutter_platform_interface: {path: ../../../google_maps_flutter/google_maps_flutter_platform_interface}} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 76b258d651c1..9280e60c3ac2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -172,6 +172,11 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + @override Stream onTap({required int mapId}) { return _events(mapId).whereType(); @@ -279,6 +284,12 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { arguments['zoom'] as int?, ); return tile.toJson(); + case 'groundOverlay#onTap': + final Map arguments = _getArgumentDictionary(call); + final GroundOverlayId groundOverlayId = + GroundOverlayId(arguments['groundOverlayId']! as String); + _mapEventStreamController + .add(GroundOverlayTapEvent(mapId, groundOverlayId)); case 'cluster#onTap': final Map arguments = _getArgumentDictionary(call); final Cluster cluster = parseCluster( @@ -379,6 +390,17 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { ); } + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + return _channel(mapId).invokeMethod( + 'groundOverlays#update', + groundOverlayUpdates.toJson(), + ); + } + @override Future updateClusterManagers( ClusterManagerUpdates clusterManagerUpdates, { @@ -588,6 +610,9 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { 'tileOverlaysToAdd': serializeTileOverlaySet(mapObjects.tileOverlays), 'clusterManagersToAdd': serializeClusterManagerSet(mapObjects.clusterManagers), + 'groundOverlaysToAdd': serializeGroundOverlaySet( + mapObjects.groundOverlays, + ), }; const String viewType = 'plugins.flutter.dev/google_maps_android'; @@ -666,6 +691,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { Set circles = const {}, Set tileOverlays = const {}, Set clusterManagers = const {}, + Set groundOverlays = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, }) { @@ -681,6 +707,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { polylines: polylines, circles: circles, clusterManagers: clusterManagers, + groundOverlays: groundOverlays, tileOverlays: tileOverlays), mapOptions: mapOptions, ); @@ -697,6 +724,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { Set circles = const {}, Set tileOverlays = const {}, Set clusterManagers = const {}, + Set groundOverlays = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, }) { @@ -711,6 +739,7 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { circles: circles, tileOverlays: tileOverlays, clusterManagers: clusterManagers, + groundOverlays: groundOverlays, gestureRecognizers: gestureRecognizers, mapOptions: mapOptions, ); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index f14b973f0d51..1d7ee7c3e901 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -34,3 +34,8 @@ topics: - google-maps - google-maps-flutter - map + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_platform_interface: {path: ../../google_maps_flutter/google_maps_flutter_platform_interface}} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/pubspec.yaml index 0c50df87f12e..b13707c9041f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/pubspec.yaml @@ -32,3 +32,8 @@ flutter: uses-material-design: true assets: - assets/ + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_ios: {path: ../../../../google_maps_flutter/google_maps_flutter_ios}, google_maps_flutter_platform_interface: {path: ../../../../google_maps_flutter/google_maps_flutter_platform_interface}} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml index 810adc8ee21f..f1845cc0ef67 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml @@ -27,3 +27,8 @@ dev_dependencies: flutter: uses-material-design: true + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_ios: {path: ../../../../../google_maps_flutter/google_maps_flutter_ios}, google_maps_flutter_platform_interface: {path: ../../../../../google_maps_flutter/google_maps_flutter_platform_interface}} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart index 56f3cc5a0794..c20e9795970c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart @@ -255,6 +255,12 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { arguments['zoom'] as int?, ); return tile.toJson(); + case 'groundOverlay#onTap': + final Map arguments = _getArgumentDictionary(call); + final GroundOverlayId groundOverlayId = + GroundOverlayId(arguments['groundOverlayId']! as String); + _mapEventStreamController + .add(GroundOverlayTapEvent(mapId, groundOverlayId)); default: throw MissingPluginException(); } @@ -527,6 +533,7 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, }) { @@ -537,11 +544,13 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { initialCameraPosition: initialCameraPosition, textDirection: textDirection), mapObjects: MapObjects( - markers: markers, - polygons: polygons, - polylines: polylines, - circles: circles, - tileOverlays: tileOverlays), + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + groundOverlays: groundOverlays, + ), mapOptions: mapOptions, ); } @@ -556,6 +565,7 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, }) { @@ -569,6 +579,7 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { polylines: polylines, circles: circles, tileOverlays: tileOverlays, + groundOverlays: groundOverlays, gestureRecognizers: gestureRecognizers, mapOptions: mapOptions, ); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index e84115146296..85be04f7b3aa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -32,3 +32,8 @@ topics: - google-maps - google-maps-flutter - map + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_platform_interface: {path: ../../google_maps_flutter/google_maps_flutter_platform_interface}} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart index 67a026d90557..fb039b79d3c5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/events/map_event.dart @@ -176,3 +176,12 @@ class ClusterTapEvent extends MapEvent { /// cluster icon managed by [ClusterManager]. ClusterTapEvent(super.mapId, super.cluster); } + +/// An event fired when a [GroundOverlay] is tapped. +class GroundOverlayTapEvent extends MapEvent { + /// Build GroundOverlayTap Event triggered from the map represented by `mapId`. + /// + /// The `value` of this event is a [GroundOverlayId] object that represents + /// the tapped GroundOverlay + GroundOverlayTapEvent(super.mapId, super.groundOverlayId); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart index dd728cf1349d..3f990193d849 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/method_channel/method_channel_google_maps_flutter.dart @@ -171,6 +171,11 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + Future _handleMethodCall(MethodCall call, int mapId) async { switch (call.method) { case 'camera#onMoveStarted': @@ -293,6 +298,12 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { bounds: bounds, ), )); + case 'groundOverlay#onTap': + final Map arguments = _getArgumentDictionary(call); + final GroundOverlayId groundOverlayId = + GroundOverlayId(arguments['groundOverlayId']! as String); + _mapEventStreamController + .add(GroundOverlayTapEvent(mapId, groundOverlayId)); default: throw MissingPluginException(); } @@ -404,6 +415,17 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { }); } + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + return channel(mapId).invokeMethod( + 'groundOverlays#update', + groundOverlayUpdates.toJson(), + ); + } + @override Future animateCamera( CameraUpdate cameraUpdate, { @@ -631,6 +653,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set clusterManagers = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, @@ -642,12 +665,14 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { initialCameraPosition: initialCameraPosition, textDirection: textDirection), mapObjects: MapObjects( - markers: markers, - polygons: polygons, - polylines: polylines, - circles: circles, - clusterManagers: clusterManagers, - tileOverlays: tileOverlays), + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + clusterManagers: clusterManagers, + tileOverlays: tileOverlays, + groundOverlays: groundOverlays, + ), mapOptions: mapOptions, ); } @@ -662,6 +687,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set clusterManagers = const {}, Set>? gestureRecognizers, Map mapOptions = const {}, @@ -676,6 +702,7 @@ class MethodChannelGoogleMapsFlutter extends GoogleMapsFlutterPlatform { polylines: polylines, circles: circles, tileOverlays: tileOverlays, + groundOverlays: groundOverlays, clusterManagers: clusterManagers, gestureRecognizers: gestureRecognizers, mapOptions: mapOptions, diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart index 648c6a162d68..147d62470f11 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/platform_interface/google_maps_flutter_platform.dart @@ -156,6 +156,20 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { 'updateClusterManagers() has not been implemented.'); } + /// Updates ground overlay configuration. + /// + /// Change listeners are notified once the update has been made on the + /// platform side. + /// + /// The returned [Future] completes after listeners have been notified. + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + throw UnimplementedError( + 'updateGroundOverlays() has not been implemented.'); + } + /// Clears the tile cache so that all tiles will be requested again from the /// [TileProvider]. /// @@ -361,6 +375,11 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { throw UnimplementedError('onCircleTap() has not been implemented.'); } + /// A [GroundOverlay] has been tapped. + Stream onGroundOverlayTap({required int mapId}) { + throw UnimplementedError('onGroundOverlayTap() has not been implemented.'); + } + /// A Map has been tapped at a certain [LatLng]. Stream onTap({required int mapId}) { throw UnimplementedError('onTap() has not been implemented.'); @@ -398,6 +417,7 @@ abstract class GoogleMapsFlutterPlatform extends PlatformInterface { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set>? gestureRecognizers = const >{}, // TODO(stuartmorgan): Replace with a structured type that's part of the diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart new file mode 100644 index 000000000000..63b58360cfa6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart @@ -0,0 +1,241 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/foundation.dart' show immutable; + +import 'types.dart'; + +/// Uniquely identifies a [GroundOverlay] among [GoogleMap] ground overlays. +@immutable +class GroundOverlayId extends MapsObjectId { + /// Creates an immutable identifier for a [GroundOverlay]. + const GroundOverlayId(super.value); +} + +/// Ground overlays are image overlays that are tied to latitude/longitude coordinates. +/// +/// They move when you drag or zoom the map. +/// +/// A ground overlay is an image that is fixed to a map. Unlike markers, +/// ground overlays are oriented against the Earth's surface rather than the screen, +/// so rotating, tilting or zooming the map will change the orientation of the image. +/// Ground overlays are useful when you wish to fix a single image at one area on the map. +/// If you want to add extensive imagery that covers a large portion of the map, +/// you should consider a Tile overlay. +@immutable +class GroundOverlay implements MapsObject { + /// Creates an immutable representation of a [GroundOverlay] to draw on [GoogleMap]. + /// The following ground overlay positioning is allowed by the Google Maps Api + /// 1. Using [height], [width] and [LatLng] + /// 2. Using [width], [width] + /// 3. Using [LatLngBounds] + const GroundOverlay({ + required this.groundOverlayId, + this.clickable = false, + this.location, + this.zIndex = 0, + this.onTap, + this.visible = true, + this.bitmap, + this.bounds, + this.width, + this.height, + this.bearing = 0.0, + this.anchor = Offset.zero, + this.opacity = 1.0, + }) : assert( + (height != null && + width != null && + location != null && + bounds == null) || + (height == null && + width == null && + location == null && + bounds != null) || + (height == null && + width != null && + location != null && + bounds == null) || + (height == null && + width == null && + location == null && + bounds == null), + 'Only one of the three types of positioning is allowed, please refer ' + 'to the https://developers.google.com/maps/documentation/android-sdk/groundoverlay#add_an_overlay'), + assert(0.0 <= opacity && opacity <= 1.0); + + /// Creates an immutable representation of a [GroundOverlay] to draw on [GoogleMap] + /// using [LatLngBounds] + const GroundOverlay.fromBounds( + this.bounds, { + required this.groundOverlayId, + this.anchor = Offset.zero, + this.bearing = 0.0, + this.bitmap, + this.clickable = false, + this.onTap, + this.opacity = 1.0, + this.visible = true, + this.zIndex = 0, + }) : assert(0.0 <= opacity && opacity <= 1.0), + location = null, + height = null, + width = null; + + /// Uniquely identifies a [GroundOverlay]. + final GroundOverlayId groundOverlayId; + + @override + GroundOverlayId get mapsId => groundOverlayId; + + /// Specifies whether the [GroundOverlay] is clickable. + /// + /// If this is false, [onTap] callback will not be triggered. + final bool clickable; + + /// Geographical location of the center of the ground overlay. + final LatLng? location; + + /// True if the ground overlay is visible. + final bool visible; + + /// Specifies the ground overlay's zIndex, i.e., the order in which it will be drawn. + /// + /// Overlays are drawn in order of z-index, so that lower values means drawn + /// earlier, and thus appearing to be closer to the surface of the Earth. + final int zIndex; + + /// Callbacks to receive tap events for ground overlay placed on this map. + final VoidCallback? onTap; + + /// A description of the bitmap used to draw the ground overlay image. + final BitmapDescriptor? bitmap; + + /// Width of the ground overlay in meters + final double? width; + + /// Height of the ground overlay in meters + final double? height; + + /// The bearing of the ground overlay in degrees clockwise from north. + /// + /// The center of the rotation will be the image's anchor. + /// This is optional and the default bearing is 0. + final double bearing; + + /// The anchor aligns with the ground overlay's location. + /// + /// The anchor point is specified in 2D continuous space where (0,0), (1,0), (0,1) and (1,1) + /// denote the top-left, top-right, bottom-left and bottom-right corners respectively. + /// Default anchor is (0.5, 0.5). + final Offset anchor; + + /// The transparency of the ground overlay. The default transparency is 0 (opaque). + final double opacity; + + /// A latitude/longitude alignment of the ground overlay. + final LatLngBounds? bounds; + + /// Creates a new [GroundOverlay] object whose values are the same as this instance, + /// unless overwritten by the specified parameters. + GroundOverlay copyWith({ + BitmapDescriptor? bitmapParam, + Offset? anchorParam, + int? zIndexParam, + bool? visibleParam, + bool? clickableParam, + double? widthParam, + double? heightParam, + double? bearingParam, + LatLng? locationParam, + LatLngBounds? boundsParam, + VoidCallback? onTapParam, + double? opacityParam, + }) { + return GroundOverlay( + groundOverlayId: groundOverlayId, + clickable: clickableParam ?? clickable, + bitmap: bitmapParam ?? bitmap, + opacity: opacityParam ?? opacity, + location: locationParam ?? location, + visible: visibleParam ?? visible, + bearing: bearingParam ?? bearing, + anchor: anchorParam ?? anchor, + height: heightParam ?? height, + bounds: boundsParam ?? bounds, + zIndex: zIndexParam ?? zIndex, + width: widthParam ?? width, + onTap: onTapParam ?? onTap); + } + + /// Creates a new [GroundOverlay] object whose values are the same as this instance. + @override + GroundOverlay clone() => copyWith(); + + /// Converts this object to something serializable in JSON. + @override + Object toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('groundOverlayId', groundOverlayId.value); + addIfPresent('clickable', clickable); + addIfPresent('transparency', 1 - opacity); + addIfPresent('bearing', bearing); + addIfPresent('visible', visible); + addIfPresent('zIndex', zIndex); + addIfPresent('height', height); + addIfPresent('anchor', _offsetToJson(anchor)); + addIfPresent('bounds', bounds?.toJson()); + addIfPresent('bitmap', bitmap?.toJson()); + addIfPresent('width', width); + if (location != null) { + json['location'] = _locationToJson(); + } + return json; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + + if (other.runtimeType != runtimeType) { + return false; + } + + final GroundOverlay typedOther = other as GroundOverlay; + + return groundOverlayId == typedOther.groundOverlayId && + bitmap == typedOther.bitmap && + clickable == typedOther.clickable && + opacity == typedOther.opacity && + location == typedOther.location && + bearing == typedOther.bearing && + visible == typedOther.visible && + height == typedOther.height && + zIndex == typedOther.zIndex && + bounds == typedOther.bounds && + anchor == typedOther.anchor && + width == typedOther.width && + onTap == typedOther.onTap; + } + + @override + int get hashCode => groundOverlayId.hashCode; + + dynamic _locationToJson() => location?.toJson(); + + dynamic _offsetToJson(Offset offset) { + return [offset.dx, offset.dy]; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart new file mode 100644 index 000000000000..d2fef358dfb2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart @@ -0,0 +1,22 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'types.dart'; + +/// [GroundOverlay] update events to be applied to the [GoogleMap]. +class GroundOverlayUpdates extends MapsObjectUpdates { + /// Computes [GroundOverlayUpdates] given previous and current [GroundOverlay]s. + GroundOverlayUpdates.from(super.previous, super.current) + : super.from(objectName: 'groundOverlay'); + + /// Set of GroundOverlays to be added in this update. + Set get groundOverlaysToAdd => objectsToAdd; + + /// Set of GroundOverlayIds to be removed in this update. + Set get groundOverlayIdsToRemove => + objectIdsToRemove.cast(); + + /// Set of GroundOverlays to be changed in this update. + Set get groundOverlaysToChange => objectsToChange; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/map_objects.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/map_objects.dart index 009a6a078268..5b885cdaa7b8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/map_objects.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/map_objects.dart @@ -21,6 +21,7 @@ class MapObjects { this.polylines = const {}, this.circles = const {}, this.tileOverlays = const {}, + this.groundOverlays = const {}, this.clusterManagers = const {}, }); @@ -29,5 +30,6 @@ class MapObjects { final Set polylines; final Set circles; final Set tileOverlays; + final Set groundOverlays; final Set clusterManagers; } diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart index 3ef0e4ab18b5..43de61845f46 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/types.dart @@ -12,6 +12,8 @@ export 'circle_updates.dart'; export 'cluster.dart'; export 'cluster_manager.dart'; export 'cluster_manager_updates.dart'; +export 'ground_overlay.dart'; +export 'ground_overlay_updates.dart'; export 'joint_type.dart'; export 'location.dart'; export 'map_configuration.dart'; @@ -34,6 +36,7 @@ export 'ui.dart'; // Export the utils used by the Widget export 'utils/circle.dart'; export 'utils/cluster_manager.dart'; +export 'utils/ground_overlay.dart'; export 'utils/marker.dart'; export 'utils/polygon.dart'; export 'utils/polyline.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart new file mode 100644 index 000000000000..3b0059bcf80a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart @@ -0,0 +1,15 @@ +import '../types.dart'; +import 'maps_object.dart'; + +/// Converts an [Iterable] of [GroundOverlay] in a Map of +/// [GroundOverlayId] -> [GroundOverlay]. +Map keyByGroundOverlayId( + Iterable groundOverlays) { + return keyByMapsObjectId(groundOverlays) + .cast(); +} + +/// Converts a Set of [GroundOverlay]s into something serializable in JSON. +Object serializeGroundOverlaySet(Set groundOverlays) { + return serializeMapsObjectSet(groundOverlays); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart index b0e48fd474bb..504fa0e3e031 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/platform_interface/google_maps_flutter_platform_test.dart @@ -144,6 +144,7 @@ class BuildViewGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, + Set groundOverlays = const {}, Set clusterManagers = const {}, Set>? gestureRecognizers = const >{}, diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 85a89ed5bf96..20497f00f5dc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -29,9 +29,14 @@ flutter: assets: - assets/ +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins dependency_overrides: + # Override the google_maps_flutter dependency on google_maps_flutter_web. # TODO(ditman): Unwind the circular dependency. This will create problems # if we need to make a breaking change to google_maps_flutter_web. + google_maps_flutter_platform_interface: + path: ../../../google_maps_flutter/google_maps_flutter_platform_interface google_maps_flutter_web: - path: ../ + path: ../../../google_maps_flutter/google_maps_flutter_web diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 76707dd7c1e9..dacd691901ea 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -40,3 +40,8 @@ topics: # The example deliberately includes limited-use secrets. false_secrets: - /example/web/index.html + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins +dependency_overrides: + {google_maps_flutter_platform_interface: {path: ../../google_maps_flutter/google_maps_flutter_platform_interface}} From 007fb323ef50c4e0491f980457e2d29cf3f6ee49 Mon Sep 17 00:00:00 2001 From: pdenert Date: Tue, 11 Jun 2024 23:40:33 +0200 Subject: [PATCH 02/12] Add ios implementation --- .../example/android/app/build.gradle | 2 +- .../example/lib/ground_overlay.dart | 2 +- .../ios/Classes/FLTGoogleMapsPlugin.h | 1 + .../ios/Classes/GoogleMapController.h | 1 + .../ios/Classes/GoogleMapController.m | 26 +- .../GoogleMapGroundOverlayController.h | 46 +++ .../GoogleMapGroundOverlayController.m | 318 ++++++++++++++++++ .../lib/src/google_maps_flutter_ios.dart | 18 + .../lib/src/types/ground_overlay.dart | 22 +- 9 files changed, 412 insertions(+), 24 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m diff --git a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle index a1ea94ae55cd..8638eb2f3089 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter/example/android/app/build.gradle @@ -30,7 +30,7 @@ android { defaultConfig { applicationId "io.flutter.plugins.googlemapsexample" - minSdkVersion 20 + minSdkVersion flutter.minSdkVersion targetSdkVersion 28 multiDexEnabled true versionCode flutterVersionCode.toInteger() diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart index 1d4b4a41b517..acc9c1ea429f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart @@ -82,7 +82,7 @@ class GroundOverlayBodyState extends State { Center( child: SizedBox( width: 350.0, - height: 300.0, + height: 500.0, child: GoogleMap( initialCameraPosition: const CameraPosition( target: LatLng(59.935460, 30.325177), diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h index 26f69eaf3882..2e86613f7c23 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h @@ -9,6 +9,7 @@ #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" +#import "GoogleMapGroundOverlayController.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h index d1069ac16b39..073228797ba5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h @@ -8,6 +8,7 @@ #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" +#import "GoogleMapGroundOverlayController.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m index 4c747f3eeba0..8fe89c6cd766 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m @@ -67,6 +67,7 @@ @interface FLTGoogleMapController () @property(nonatomic, strong) FLTPolylinesController *polylinesController; @property(nonatomic, strong) FLTCirclesController *circlesController; @property(nonatomic, strong) FLTTileOverlaysController *tileOverlaysController; +@property(nonatomic, strong) FLTGroundOverlaysController *groundOverlaysController; // The resulting error message, if any, from the last attempt to set the map style. // This is used to provide access to errors after the fact, since the map style is generally set at // creation time and there's no mechanism to return non-fatal error details during platform view @@ -136,6 +137,9 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView _tileOverlaysController = [[FLTTileOverlaysController alloc] init:_channel mapView:_mapView registrar:registrar]; + _groundOverlaysController = [[FLTGroundOverlaysController alloc] init:_channel + mapView:_mapView + registrar:registrar]; id markersToAdd = args[@"markersToAdd"]; if ([markersToAdd isKindOfClass:[NSArray class]]) { [_markersController addMarkers:markersToAdd]; @@ -156,6 +160,10 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; } + id groundOverlaysToAdd = args[@"groundOverlaysToAdd"]; + if ([groundOverlaysToAdd isKindOfClass:[NSArray class]]) { + [_groundOverlaysController addGroundOverlays:groundOverlaysToAdd]; + } [_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil]; } @@ -356,6 +364,20 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { id rawTileOverlayId = call.arguments[@"tileOverlayId"]; [self.tileOverlaysController clearTileCacheWithIdentifier:rawTileOverlayId]; result(nil); + } else if ([call.method isEqualToString:@"groundOverlays#update"]) { + id groundOverlaysToAdd = call.arguments[@"groundOverlaysToAdd"]; + if ([groundOverlaysToAdd isKindOfClass:[NSArray class]]) { + [self.groundOverlaysController addGroundOverlays:groundOverlaysToAdd]; + } + id groundOverlaysToChange = call.arguments[@"groundOverlaysToChange"]; + if ([groundOverlaysToChange isKindOfClass:[NSArray class]]) { + [self.groundOverlaysController changeGroundOverlays:groundOverlaysToChange]; + } + id groundOverlayIdsToRemove = call.arguments[@"groundOverlayIdsToRemove"]; + if ([groundOverlayIdsToRemove isKindOfClass:[NSArray class]]) { + [self.groundOverlaysController removeGroundOverlayWithIdentifiers:groundOverlayIdsToRemove]; + } + result(nil); } else if ([call.method isEqualToString:@"map#isCompassEnabled"]) { NSNumber *isCompassEnabled = @(self.mapView.settings.compassButton); result(isCompassEnabled); @@ -565,7 +587,9 @@ - (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { [self.polygonsController didTapPolygonWithIdentifier:overlayId]; } else if ([self.circlesController hasCircleWithIdentifier:overlayId]) { [self.circlesController didTapCircleWithIdentifier:overlayId]; - } + } else if ([self.groundOverlaysController hasGroundOverlayWithIdentifier:overlayId]) { + [self.groundOverlaysController didTapGroundOverlayWithIdentifier:overlayId]; + } } - (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h new file mode 100644 index 000000000000..9d3b03f592df --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h @@ -0,0 +1,46 @@ +// // Copyright 2024 The Flutter Authors. All rights reserved. +// // Use of this source code is governed by a BSD-style license that can be +// // found in the LICENSE file. + +#import +#import +#import "GoogleMapController.h" + +// Defines ground overlay UI options writable from Flutter. +@protocol FLTGoogleMapGroundOverlayOptionsSink +- (void)setBearing:(CLLocationDirection)bearing; +- (void)setBitmapDescriptor:(UIImage*)bd; +- (void)setBounds:(GMSCoordinateBounds*)bounds; +- (void)setConsumeTapEvents:(BOOL)consume; +- (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height:(CGFloat)height; +- (void)setOpacity:(float)opacity; +- (void)setVisible:(BOOL)visible; +- (void)setZIndex:(int)zIndex; +@end + +// Defines ground overlay controllable by Flutter. +@interface FLTGoogleMapGroundOverlayController : NSObject +@property(atomic, readonly) NSString* groundOverlayId; +- (instancetype)initGroundOverlayWithPosition:(CLLocationCoordinate2D)position + icon:(UIImage*)icon + groundOverlayId:(NSString*)groundOverlayId + mapView:(GMSMapView*)mapView; +- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds*)bounds + icon:(UIImage*)icon + groundOverlayId:(NSString*)groundOverlayId + mapView:(GMSMapView*)mapView; +- (BOOL)consumeTapEvents; +- (void)removeGroundOverlay; +@end + +@interface FLTGroundOverlaysController : NSObject +- (instancetype)init:(FlutterMethodChannel*)methodChannel + mapView:(GMSMapView*)mapView + registrar:(NSObject*)registrar; +- (void)addGroundOverlays:(NSArray*)groundOverlaysToAdd; +- (void)changeGroundOverlays:(NSArray*)groundOverlaysToChange; +- (void)removeGroundOverlayWithIdentifiers:(NSArray*)groundOverlayIdsToRemove; +- (void)onGroundOverlayTap:(NSString*)groundOverlayId; +- (bool)hasGroundOverlayWithIdentifier:(NSString*)groundOverlayId; +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier; +@end \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m new file mode 100644 index 000000000000..c8480e4a2fc8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m @@ -0,0 +1,318 @@ +// // Copyright 2019 The Chromium Authors. All rights reserved. +// // Use of this source code is governed by a BSD-style license that can be +// // found in the LICENSE file. + +#import "GoogleMapGroundOverlayController.h" +#import "FLTGoogleMapJSONConversions.h" + +static UIImage* ExtractBitmapDescriptor(NSObject* registrar, NSArray* bitmap); + +@interface FLTGoogleMapGroundOverlayController () + +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; +@property(weak, nonatomic) GMSMapView *mapView; +@property(assign, nonatomic) BOOL consumeTapEvents; + +@end + +@implementation FLTGoogleMapGroundOverlayController + +- (instancetype)initGroundOverlayWithPosition:(CLLocationCoordinate2D)position + icon:(UIImage*)icon + groundOverlayId:(NSString *)groundOverlayId + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + float zoomLevel = mapView.camera.zoom; + _groundOverlay = [GMSGroundOverlay groundOverlayWithPosition:position icon:icon zoomLevel:zoomLevel]; + _mapView = mapView; + _groundOverlayId = groundOverlayId; + _groundOverlay.userData = @[ _groundOverlayId ]; + self.consumeTapEvents = NO; + } + return self; +} + +- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds*)bounds + icon:(UIImage*)icon + groundOverlayId:(NSString*)groundOverlayId + mapView:(GMSMapView*)mapView { + self = [super init]; + if (self) { + _groundOverlay = [GMSGroundOverlay groundOverlayWithBounds:bounds icon:icon]; + _mapView = mapView; + _groundOverlayId = groundOverlayId; + _groundOverlay.userData = @[ _groundOverlayId ]; + self.consumeTapEvents = NO; + } + return self; +} + +- (BOOL)consumeTapEvents { + return self.consumeTapEvents; +} + +- (void)removeGroundOverlay { + self.groundOverlay.map = nil; +} + +#pragma mark - FLTGoogleMapGroundOverlayOptionsSink methods + +- (void)setConsumeTapEvents:(BOOL)consumes { + self.groundOverlay.tappable = consumes; +} + +- (void)setVisible:(BOOL)visible { + self.groundOverlay.map = visible ? _mapView : nil; +} + +- (void)setZIndex:(int)zIndex { + self.groundOverlay.zIndex = zIndex; +} + +- (void)setBounds:(GMSCoordinateBounds *)bounds { + self.groundOverlay.bounds = bounds; +} + +- (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height:(CGFloat)height { + self.groundOverlay.position = location; +} + +- (void)setBitmapDescriptor:(UIImage*)bd { + self.groundOverlay.icon = bd; +} + +- (void)setBearing:(CLLocationDirection)bearing { + self.groundOverlay.bearing = bearing; +} + +- (void)setOpacity:(float)opacity { + self.groundOverlay.opacity = opacity; +} + +@end + +static void InterpretGroundOverlayOptions(NSDictionary* data, id sink, + NSObject* registrar) { + NSNumber* consumeTapEvents = data[@"consumeTapEvents"]; + if (consumeTapEvents != nil) { + [sink setConsumeTapEvents:consumeTapEvents.boolValue]; + } + + NSNumber* visible = data[@"visible"]; + if (visible != nil) { + [sink setVisible:visible.boolValue]; + } + + NSNumber *zIndex = data[@"zIndex"]; + if (zIndex != nil && zIndex != (id)[NSNull null]) { + [sink setZIndex:zIndex.intValue]; + } + + NSNumber* transparency = data[@"transparency"]; + if (transparency != nil && transparency != (id)[NSNull null]) { + float transparencyFloat = [transparency floatValue]; + float opacity = 1 - transparencyFloat; + [sink setOpacity:opacity]; + } + + NSNumber* width = data[@"width"]; + NSNumber* height = data[@"height"]; + NSArray* location = data[@"location"]; + if (location) { + if (height != nil) { + [sink setLocation:[FLTGoogleMapJSONConversions locationFromLatLong:location] width:width.doubleValue height:height.doubleValue]; + } else { + if (width != nil) { + [sink setLocation:[FLTGoogleMapJSONConversions locationFromLatLong:location] width:width.doubleValue height:150]; + } + } + } + + NSArray* bounds = data[@"bounds"]; + if (bounds) { + [sink setBounds:[FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:bounds]]; + } + + NSNumber* bearing = data[@"bearing"]; + if (bearing != nil) { + [sink setBearing:bearing.floatValue]; + } + + NSArray* bitmap = data[@"bitmap"]; + if (bitmap) { + UIImage* image = ExtractBitmapDescriptor(registrar, bitmap); + [sink setBitmapDescriptor:image]; + } +} + +static UIImage* scaleImage(UIImage* image, NSNumber* scaleParam) { + double scale = 1.0; + if ([scaleParam isKindOfClass:[NSNumber class]]) { + scale = scaleParam.doubleValue; + } + if (fabs(scale - 1) > 1e-3) { + return [UIImage imageWithCGImage:[image CGImage] + scale:(image.scale * scale) + orientation:(image.imageOrientation)]; + } + return image; +} + +static UIImage* ExtractBitmapDescriptor(NSObject* registrar, NSArray* bitmapData) { + UIImage* image; + if ([bitmapData.firstObject isEqualToString:@"fromAsset"]) { + if (bitmapData.count == 2) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapData[1]]]; + } else { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapData[1] + fromPackage:bitmapData[2]]]; + } + } else if ([bitmapData.firstObject isEqualToString:@"fromAssetImage"]) { + if (bitmapData.count == 3) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapData[1]]]; + NSNumber* scaleParam = bitmapData[2]; + image = scaleImage(image, scaleParam); + } else { + NSString* error = + [NSString stringWithFormat:@"'fromAssetImage' should have exactly 3 arguments. Got: %lu", + (unsigned long)bitmapData.count]; + NSException* exception = [NSException exceptionWithName:@"InvalidBitmapDescriptor" + reason:error + userInfo:nil]; + @throw exception; + } + } else if ([bitmapData[0] isEqualToString:@"fromBytes"]) { + if (bitmapData.count == 2) { + @try { + FlutterStandardTypedData* byteData = bitmapData[1]; + CGFloat screenScale = [[UIScreen mainScreen] scale]; + image = [UIImage imageWithData:[byteData data] scale:screenScale]; + } @catch (NSException* exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } else { + NSString* error = [NSString + stringWithFormat:@"fromBytes should have exactly one argument, the bytes. Got: %lu", + (unsigned long)bitmapData.count]; + NSException* exception = [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:error + userInfo:nil]; + @throw exception; + } + } + + return image; +} + +@interface FLTGroundOverlaysController () + +@property(strong, nonatomic) NSMutableDictionary* groundOverlayIdToController; +@property(strong, nonatomic) FlutterMethodChannel* methodChannel; +@property(weak, nonatomic) NSObject* registrar; +@property(weak, nonatomic) GMSMapView* mapView; + +@end + +@implementation FLTGroundOverlaysController + +- (instancetype)init:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _methodChannel = methodChannel; + _mapView = mapView; + _groundOverlayIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addGroundOverlays:(NSArray*)groundOverlaysToAdd { + for (NSDictionary *groundOverlay in groundOverlaysToAdd) { + GMSCoordinateBounds* bounds = [FLTGroundOverlaysController getBounds:groundOverlay]; + UIImage* icon = [FLTGroundOverlaysController getImage:groundOverlay registrar:_registrar]; + NSString* groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; + + if (bounds) { + CLLocationCoordinate2D location = [FLTGoogleMapJSONConversions locationFromLatLong:groundOverlay[@"location"]]; + FLTGoogleMapGroundOverlayController* controller = + [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithPosition:location + icon:icon + groundOverlayId:groundOverlayId + mapView:_mapView]; + InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); + _groundOverlayIdToController[groundOverlayId] = controller; + } else { + FLTGoogleMapGroundOverlayController* controller = + [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithBounds:bounds + icon:icon + groundOverlayId:groundOverlayId + mapView:_mapView]; + InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); + _groundOverlayIdToController[groundOverlayId] = controller; + } + } +} + +- (void)changeGroundOverlays:(NSArray*)groundOverlaysToChange { + for (NSDictionary* groundOverlay in groundOverlaysToChange) { + NSString* groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; + FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[groundOverlayId]; + if (!controller) { + continue; + } + InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); + } +} + +- (void)removeGroundOverlayWithIdentifiers:(NSArray *)groundOverlayIdsToRemove { + for (NSString* groundOverlayId in groundOverlayIdsToRemove) { + if (!groundOverlayId) { + continue; + } + FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[groundOverlayId]; + if (!controller) { + continue; + } + [controller removeGroundOverlay]; + [_groundOverlayIdToController removeObjectForKey:groundOverlayId]; + } +} + +- (bool)hasGroundOverlayWithIdentifier:(NSString *)groundOverlayId { + if (!groundOverlayId) { + return false; + } + return _groundOverlayIdToController[groundOverlayId] != nil; +} + +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[identifier]; + if (!controller) { + return; + } + [_methodChannel invokeMethod:@"groundOverlay#onTap" arguments:@{@"groundOverlayId" : identifier}]; +} + ++ (GMSCoordinateBounds *)getBounds:(NSDictionary *)groundOverlay { + NSArray* bounds = groundOverlay[@"bounds"]; + return [FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:bounds]; +} + ++ (UIImage *)getImage:(NSDictionary *)groundOverlay registrar:(NSObject*) registrar { + NSArray* image = groundOverlay[@"bitmap"]; + return ExtractBitmapDescriptor(registrar, image); +} + ++ (NSString *)getGroundOverlayId:(NSDictionary *)groundOverlay { + return groundOverlay[@"groundOverlayId"]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart index c20e9795970c..5c32b05d88a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart @@ -153,6 +153,11 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + @override Stream onTap({required int mapId}) { return _events(mapId).whereType(); @@ -350,6 +355,17 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { ); } + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + return _channel(mapId).invokeMethod( + 'groundOverlays#update', + groundOverlayUpdates.toJson(), + ); + } + @override Future clearTileCache( TileOverlayId tileOverlayId, { @@ -494,6 +510,8 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { 'polylinesToAdd': serializePolylineSet(mapObjects.polylines), 'circlesToAdd': serializeCircleSet(mapObjects.circles), 'tileOverlaysToAdd': serializeTileOverlaySet(mapObjects.tileOverlays), + 'groundOverlaysToAdd': + serializeGroundOverlaySet(mapObjects.groundOverlays), }; return UiKitView( diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart index 63b58360cfa6..3a15892b0cd0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart @@ -40,31 +40,12 @@ class GroundOverlay implements MapsObject { this.onTap, this.visible = true, this.bitmap, - this.bounds, this.width, this.height, this.bearing = 0.0, this.anchor = Offset.zero, this.opacity = 1.0, - }) : assert( - (height != null && - width != null && - location != null && - bounds == null) || - (height == null && - width == null && - location == null && - bounds != null) || - (height == null && - width != null && - location != null && - bounds == null) || - (height == null && - width == null && - location == null && - bounds == null), - 'Only one of the three types of positioning is allowed, please refer ' - 'to the https://developers.google.com/maps/documentation/android-sdk/groundoverlay#add_an_overlay'), + }) : bounds = null, assert(0.0 <= opacity && opacity <= 1.0); /// Creates an immutable representation of a [GroundOverlay] to draw on [GoogleMap] @@ -165,7 +146,6 @@ class GroundOverlay implements MapsObject { bearing: bearingParam ?? bearing, anchor: anchorParam ?? anchor, height: heightParam ?? height, - bounds: boundsParam ?? bounds, zIndex: zIndexParam ?? zIndex, width: widthParam ?? width, onTap: onTapParam ?? onTap); From bb40253982794e026820aa7a592481f1cff0342f Mon Sep 17 00:00:00 2001 From: pdenert Date: Tue, 11 Jun 2024 23:46:08 +0200 Subject: [PATCH 03/12] Format code --- .../ios/Classes/QueueUtils.h | 2 +- .../googlemaps/GoogleMapController.java | 2 +- .../googlemaps/GroundOverlayBuilder.java | 96 +++++----- .../googlemaps/GroundOverlayController.java | 133 +++++++------ .../googlemaps/GroundOverlayOptionsSink.java | 14 +- .../googlemaps/GroundOverlaysController.java | 176 +++++++++--------- .../ios/Classes/FLTGoogleMapsPlugin.h | 2 +- .../ios/Classes/GoogleMapController.h | 2 +- .../ios/Classes/GoogleMapController.m | 2 +- .../GoogleMapGroundOverlayController.h | 36 ++-- .../GoogleMapGroundOverlayController.m | 137 +++++++------- 11 files changed, 305 insertions(+), 297 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h index a7e22da716d0..e230a53508fa 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h +++ b/packages/camera/camera_avfoundation/ios/Classes/QueueUtils.h @@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN /// Queue-specific context data to be associated with the capture session queue. -extern const char* FLTCaptureSessionQueueSpecific; +extern const char *FLTCaptureSessionQueueSpecific; /// Ensures the given block to be run on the main queue. /// If caller site is already on the main queue, the block will be run diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 54a49c056bd7..75984b161538 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -472,7 +472,7 @@ public void onSnapshotReady(Bitmap bitmap) { result.success(null); break; } - case "groundOverlays#update": + case "groundOverlays#update": { List groundOverlaysToAdd = call.argument("groundOverlaysToAdd"); groundOverlaysController.addGroundOverlays(groundOverlaysToAdd); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java index 9c2ff0453302..04e9a908a2ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java @@ -5,65 +5,63 @@ import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; - class GroundOverlayBuilder implements GroundOverlayOptionsSink { - private final GroundOverlayOptions groundOverlayOptions; - private boolean consumeTapEvents; + private final GroundOverlayOptions groundOverlayOptions; + private boolean consumeTapEvents; - GroundOverlayBuilder() { - groundOverlayOptions = new GroundOverlayOptions(); - } + GroundOverlayBuilder() { + groundOverlayOptions = new GroundOverlayOptions(); + } - GroundOverlayOptions build() { - return groundOverlayOptions; - } + GroundOverlayOptions build() { + return groundOverlayOptions; + } - boolean consumeTapEvents() { - return consumeTapEvents; - } + boolean consumeTapEvents() { + return consumeTapEvents; + } - @Override - public void setConsumeTapEvents(boolean consumeTapEvents) { - this.consumeTapEvents = consumeTapEvents; - groundOverlayOptions.clickable(consumeTapEvents); - } + @Override + public void setConsumeTapEvents(boolean consumeTapEvents) { + this.consumeTapEvents = consumeTapEvents; + groundOverlayOptions.clickable(consumeTapEvents); + } - @Override - public void setVisible(boolean visible) { - groundOverlayOptions.visible(visible); - } + @Override + public void setVisible(boolean visible) { + groundOverlayOptions.visible(visible); + } - @Override - public void setZIndex(float zIndex) { - groundOverlayOptions.zIndex(zIndex); - } + @Override + public void setZIndex(float zIndex) { + groundOverlayOptions.zIndex(zIndex); + } - @Override - public void setLocation(Object location, Object width, Object height, Object bounds) { - if (height != null) { - groundOverlayOptions.position((LatLng) location, (float) width, (float) height); - } else { - if (width != null) { - groundOverlayOptions.position((LatLng) location, (float) width); - } else { - groundOverlayOptions.positionFromBounds((LatLngBounds) bounds); - } - } + @Override + public void setLocation(Object location, Object width, Object height, Object bounds) { + if (height != null) { + groundOverlayOptions.position((LatLng) location, (float) width, (float) height); + } else { + if (width != null) { + groundOverlayOptions.position((LatLng) location, (float) width); + } else { + groundOverlayOptions.positionFromBounds((LatLngBounds) bounds); + } } + } - @Override - public void setBitmapDescriptor(BitmapDescriptor bd) { - groundOverlayOptions.image(bd); - } + @Override + public void setBitmapDescriptor(BitmapDescriptor bd) { + groundOverlayOptions.image(bd); + } - @Override - public void setBearing(float bearing) { - groundOverlayOptions.bearing(bearing); - } - - @Override - public void setTransparency(float transparency) { - groundOverlayOptions.transparency(transparency); - } + @Override + public void setBearing(float bearing) { + groundOverlayOptions.bearing(bearing); + } + @Override + public void setTransparency(float transparency) { + groundOverlayOptions.transparency(transparency); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java index 5bf36ffe9e76..310c3c2a0f74 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java @@ -5,76 +5,73 @@ import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.LatLngBounds; - class GroundOverlayController implements GroundOverlayOptionsSink { - private final GroundOverlay groundOverlay; - private final String googleMapsGroundOverlayId; - private boolean consumeTapEvents; - - - GroundOverlayController(GroundOverlay groundOverlay, boolean consumeTapEvents) { - this.groundOverlay = groundOverlay; - this.consumeTapEvents = consumeTapEvents; - this.googleMapsGroundOverlayId = this.groundOverlay.getId(); - } - - - boolean consumeTapEvents() { - return consumeTapEvents; - } - - @Override - public void setConsumeTapEvents(boolean consumeTapEvents) { - this.consumeTapEvents = consumeTapEvents; - } - - @Override - public void setVisible(boolean visible) { - this.groundOverlay.setVisible(visible); - } - - @Override - public void setZIndex(float zIndex) { - this.groundOverlay.setZIndex(zIndex); - } - - void remove() { - groundOverlay.remove(); + private final GroundOverlay groundOverlay; + private final String googleMapsGroundOverlayId; + private boolean consumeTapEvents; + + GroundOverlayController(GroundOverlay groundOverlay, boolean consumeTapEvents) { + this.groundOverlay = groundOverlay; + this.consumeTapEvents = consumeTapEvents; + this.googleMapsGroundOverlayId = this.groundOverlay.getId(); + } + + boolean consumeTapEvents() { + return consumeTapEvents; + } + + @Override + public void setConsumeTapEvents(boolean consumeTapEvents) { + this.consumeTapEvents = consumeTapEvents; + } + + @Override + public void setVisible(boolean visible) { + this.groundOverlay.setVisible(visible); + } + + @Override + public void setZIndex(float zIndex) { + this.groundOverlay.setZIndex(zIndex); + } + + void remove() { + groundOverlay.remove(); + } + + @Override + public void setLocation(Object location, Object width, Object height, Object bounds) { + if (height != null && width != null) { + this.groundOverlay.setDimensions((float) width, (float) height); + } else { + if (width != null) { + this.groundOverlay.setDimensions((float) width); + } } - - @Override - public void setLocation(Object location, Object width, Object height, Object bounds) { - if (height != null && width != null) { - this.groundOverlay.setDimensions((float) width, (float) height); - } else { - if (width != null) { - this.groundOverlay.setDimensions((float) width); - } - } - if (location != null) { - this.groundOverlay.setPosition((LatLng) location); - } - if (bounds != null) { - this.groundOverlay.setPositionFromBounds((LatLngBounds) bounds); - } - } - - @Override - public void setBitmapDescriptor(BitmapDescriptor bd) { - this.groundOverlay.setImage(bd); + if (location != null) { + this.groundOverlay.setPosition((LatLng) location); } - - @Override - public void setBearing(float bearing) { - this.groundOverlay.setBearing(bearing); - } - - @Override - public void setTransparency(float transparency) { - this.groundOverlay.setTransparency(transparency); - } - - String getGoogleMapsGroundOverlayId() { - return this.googleMapsGroundOverlayId; + if (bounds != null) { + this.groundOverlay.setPositionFromBounds((LatLngBounds) bounds); } + } + + @Override + public void setBitmapDescriptor(BitmapDescriptor bd) { + this.groundOverlay.setImage(bd); + } + + @Override + public void setBearing(float bearing) { + this.groundOverlay.setBearing(bearing); + } + + @Override + public void setTransparency(float transparency) { + this.groundOverlay.setTransparency(transparency); + } + + String getGoogleMapsGroundOverlayId() { + return this.googleMapsGroundOverlayId; + } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java index 20f36a89236f..47d6a1641f32 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java @@ -3,17 +3,17 @@ import com.google.android.gms.maps.model.BitmapDescriptor; interface GroundOverlayOptionsSink { - void setConsumeTapEvents(boolean consumeTapEvents); + void setConsumeTapEvents(boolean consumeTapEvents); - void setVisible(boolean visible); + void setVisible(boolean visible); - void setZIndex(float zIndex); + void setZIndex(float zIndex); - void setLocation(Object location, Object width, Object height, Object bounds); + void setLocation(Object location, Object width, Object height, Object bounds); - void setBitmapDescriptor(BitmapDescriptor bd); + void setBitmapDescriptor(BitmapDescriptor bd); - void setBearing(float bearing); + void setBearing(float bearing); - void setTransparency(float transparency); + void setTransparency(float transparency); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java index c35a0efffedf..561d0f644efe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java @@ -3,112 +3,114 @@ import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.GroundOverlay; import com.google.android.gms.maps.model.GroundOverlayOptions; - +import io.flutter.plugin.common.MethodChannel; import java.util.HashMap; import java.util.List; import java.util.Map; -import io.flutter.plugin.common.MethodChannel; - class GroundOverlaysController { - private GoogleMap googleMap; - private final Map groundOverlayIdToController; - private final Map googleMapsGroundOverlayIdToDartOverlayId; - private MethodChannel methodChannel; - - GroundOverlaysController(MethodChannel methodChannel) { - this.methodChannel = methodChannel; - this.groundOverlayIdToController = new HashMap<>(); - this.googleMapsGroundOverlayIdToDartOverlayId = new HashMap<>(); + private GoogleMap googleMap; + private final Map groundOverlayIdToController; + private final Map googleMapsGroundOverlayIdToDartOverlayId; + private MethodChannel methodChannel; + + GroundOverlaysController(MethodChannel methodChannel) { + this.methodChannel = methodChannel; + this.groundOverlayIdToController = new HashMap<>(); + this.googleMapsGroundOverlayIdToDartOverlayId = new HashMap<>(); + } + + void setGoogleMap(GoogleMap googleMap) { + this.googleMap = googleMap; + } + + void addGroundOverlays(List groundOverlaysToAdd) { + if (groundOverlaysToAdd != null) { + for (Object groundOverlayToAdd : groundOverlaysToAdd) { + addGroundOverlay(groundOverlayToAdd); + } } + } - void setGoogleMap(GoogleMap googleMap) { - this.googleMap = googleMap; + private void addGroundOverlay(Object groundOverlay) { + if (groundOverlay == null) { + return; } - void addGroundOverlays(List groundOverlaysToAdd) { - if (groundOverlaysToAdd != null) { - for (Object groundOverlayToAdd : groundOverlaysToAdd) { - addGroundOverlay(groundOverlayToAdd); - } - } + GroundOverlayBuilder groundOverlayBuilder = new GroundOverlayBuilder(); + String groundOverlayId = + Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayBuilder); + GroundOverlayOptions options = groundOverlayBuilder.build(); + addGroundOverlay(groundOverlayId, options, groundOverlayBuilder.consumeTapEvents()); + } + + private void addGroundOverlay( + String groundOverlayId, GroundOverlayOptions groundOverlayOptions, boolean consumeTapEvents) { + final GroundOverlay groundOverlay = googleMap.addGroundOverlay(groundOverlayOptions); + + GroundOverlayController controller = + new GroundOverlayController(groundOverlay, consumeTapEvents); + groundOverlayIdToController.put(groundOverlayId, controller); + googleMapsGroundOverlayIdToDartOverlayId.put(groundOverlay.getId(), groundOverlayId); + } + + boolean onGroundOverlayTap(String googleOverlayId) { + String overlayId = googleMapsGroundOverlayIdToDartOverlayId.get(googleOverlayId); + if (overlayId == null) { + return false; } - - private void addGroundOverlay(Object groundOverlay) { - if (groundOverlay == null) { - return; - } - - GroundOverlayBuilder groundOverlayBuilder = new GroundOverlayBuilder(); - String groundOverlayId = Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayBuilder); - GroundOverlayOptions options = groundOverlayBuilder.build(); - addGroundOverlay(groundOverlayId, options, groundOverlayBuilder.consumeTapEvents()); + methodChannel.invokeMethod("groundOverlay#onTap", Convert.groundOverlayIdToJson(overlayId)); + GroundOverlayController groundOverlayController = groundOverlayIdToController.get(overlayId); + if (groundOverlayController != null) { + return groundOverlayController.consumeTapEvents(); } - - private void addGroundOverlay( - String groundOverlayId, GroundOverlayOptions groundOverlayOptions, boolean consumeTapEvents) { - final GroundOverlay groundOverlay = googleMap.addGroundOverlay(groundOverlayOptions); - - GroundOverlayController controller = new GroundOverlayController(groundOverlay, consumeTapEvents); - groundOverlayIdToController.put(groundOverlayId, controller); - googleMapsGroundOverlayIdToDartOverlayId.put(groundOverlay.getId(), groundOverlayId); - + return false; + } + + void changeGroundOverlays(List groundOverlaysToChange) { + if (groundOverlaysToChange != null) { + for (Object groundOverlayToChange : groundOverlaysToChange) { + changeGroundOverlay(groundOverlayToChange); + } } + } - boolean onGroundOverlayTap(String googleOverlayId) { - String overlayId = googleMapsGroundOverlayIdToDartOverlayId.get(googleOverlayId); - if (overlayId == null) { - return false; - } - methodChannel.invokeMethod("groundOverlay#onTap", Convert.groundOverlayIdToJson(overlayId)); - GroundOverlayController groundOverlayController = groundOverlayIdToController.get(overlayId); - if (groundOverlayController != null) { - return groundOverlayController.consumeTapEvents(); - } - return false; + private void changeGroundOverlay(Object groundOverlay) { + if (groundOverlay == null) { + return; } - - void changeGroundOverlays(List groundOverlaysToChange) { - if (groundOverlaysToChange != null) { - for (Object groundOverlayToChange : groundOverlaysToChange) { - changeGroundOverlay(groundOverlayToChange); - } - } + String groundOverlayId = getGroundOverlayId(groundOverlay); + GroundOverlayController groundOverlayController = + groundOverlayIdToController.get(groundOverlayId); + if (groundOverlayController != null) { + Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayController); } + } - private void changeGroundOverlay(Object groundOverlay) { - if (groundOverlay == null) { - return; - } - String groundOverlayId = getGroundOverlayId(groundOverlay); - GroundOverlayController groundOverlayController = groundOverlayIdToController.get(groundOverlayId); - if (groundOverlayController != null) { - Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayController); - } + void removeGroundOverlays(List groundOverlaysToRemove) { + if (groundOverlaysToRemove == null) { + return; } - void removeGroundOverlays(List groundOverlaysToRemove) { - if (groundOverlaysToRemove == null) { - return; - } - - for (Object rawGroundOverlayId : groundOverlaysToRemove) { - if (rawGroundOverlayId == null) { - continue; - } - String groundOverlayId = (String) rawGroundOverlayId; - final GroundOverlayController groundOverlayController = groundOverlayIdToController.remove(groundOverlayId); - if (groundOverlayController != null) { - groundOverlayController.remove(); - googleMapsGroundOverlayIdToDartOverlayId.remove(groundOverlayController.getGoogleMapsGroundOverlayId()); - } - } + for (Object rawGroundOverlayId : groundOverlaysToRemove) { + if (rawGroundOverlayId == null) { + continue; + } + String groundOverlayId = (String) rawGroundOverlayId; + final GroundOverlayController groundOverlayController = + groundOverlayIdToController.remove(groundOverlayId); + if (groundOverlayController != null) { + groundOverlayController.remove(); + googleMapsGroundOverlayIdToDartOverlayId.remove( + groundOverlayController.getGoogleMapsGroundOverlayId()); + } } + } - @SuppressWarnings("unchecked") - private static String getGroundOverlayId(Object groundOverlay) { - Map overlayMap = (Map) groundOverlay; - return (String) overlayMap.get("groundOverlayId"); - } + @SuppressWarnings("unchecked") + private static String getGroundOverlayId(Object groundOverlay) { + Map overlayMap = (Map) groundOverlay; + return (String) overlayMap.get("groundOverlayId"); + } } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h index 2e86613f7c23..5dfba10528b1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapsPlugin.h @@ -6,10 +6,10 @@ #import #import "GoogleMapCircleController.h" #import "GoogleMapController.h" +#import "GoogleMapGroundOverlayController.h" #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" -#import "GoogleMapGroundOverlayController.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h index 073228797ba5..7506962e1f49 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h @@ -5,10 +5,10 @@ #import #import #import "GoogleMapCircleController.h" +#import "GoogleMapGroundOverlayController.h" #import "GoogleMapMarkerController.h" #import "GoogleMapPolygonController.h" #import "GoogleMapPolylineController.h" -#import "GoogleMapGroundOverlayController.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m index 8fe89c6cd766..ca7c68daa82a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m @@ -589,7 +589,7 @@ - (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { [self.circlesController didTapCircleWithIdentifier:overlayId]; } else if ([self.groundOverlaysController hasGroundOverlayWithIdentifier:overlayId]) { [self.groundOverlaysController didTapGroundOverlayWithIdentifier:overlayId]; - } + } } - (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h index 9d3b03f592df..7e1e5d8f3e5b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h @@ -9,8 +9,8 @@ // Defines ground overlay UI options writable from Flutter. @protocol FLTGoogleMapGroundOverlayOptionsSink - (void)setBearing:(CLLocationDirection)bearing; -- (void)setBitmapDescriptor:(UIImage*)bd; -- (void)setBounds:(GMSCoordinateBounds*)bounds; +- (void)setBitmapDescriptor:(UIImage *)bd; +- (void)setBounds:(GMSCoordinateBounds *)bounds; - (void)setConsumeTapEvents:(BOOL)consume; - (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height:(CGFloat)height; - (void)setOpacity:(float)opacity; @@ -20,27 +20,27 @@ // Defines ground overlay controllable by Flutter. @interface FLTGoogleMapGroundOverlayController : NSObject -@property(atomic, readonly) NSString* groundOverlayId; +@property(atomic, readonly) NSString *groundOverlayId; - (instancetype)initGroundOverlayWithPosition:(CLLocationCoordinate2D)position - icon:(UIImage*)icon - groundOverlayId:(NSString*)groundOverlayId - mapView:(GMSMapView*)mapView; -- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds*)bounds - icon:(UIImage*)icon - groundOverlayId:(NSString*)groundOverlayId - mapView:(GMSMapView*)mapView; + icon:(UIImage *)icon + groundOverlayId:(NSString *)groundOverlayId + mapView:(GMSMapView *)mapView; +- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds *)bounds + icon:(UIImage *)icon + groundOverlayId:(NSString *)groundOverlayId + mapView:(GMSMapView *)mapView; - (BOOL)consumeTapEvents; - (void)removeGroundOverlay; @end @interface FLTGroundOverlaysController : NSObject -- (instancetype)init:(FlutterMethodChannel*)methodChannel - mapView:(GMSMapView*)mapView - registrar:(NSObject*)registrar; -- (void)addGroundOverlays:(NSArray*)groundOverlaysToAdd; -- (void)changeGroundOverlays:(NSArray*)groundOverlaysToChange; -- (void)removeGroundOverlayWithIdentifiers:(NSArray*)groundOverlayIdsToRemove; -- (void)onGroundOverlayTap:(NSString*)groundOverlayId; -- (bool)hasGroundOverlayWithIdentifier:(NSString*)groundOverlayId; +- (instancetype)init:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar; +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd; +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange; +- (void)removeGroundOverlayWithIdentifiers:(NSArray *)groundOverlayIdsToRemove; +- (void)onGroundOverlayTap:(NSString *)groundOverlayId; +- (bool)hasGroundOverlayWithIdentifier:(NSString *)groundOverlayId; - (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier; @end \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m index c8480e4a2fc8..4b1fa270a58b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m @@ -5,7 +5,8 @@ #import "GoogleMapGroundOverlayController.h" #import "FLTGoogleMapJSONConversions.h" -static UIImage* ExtractBitmapDescriptor(NSObject* registrar, NSArray* bitmap); +static UIImage *ExtractBitmapDescriptor(NSObject *registrar, + NSArray *bitmap); @interface FLTGoogleMapGroundOverlayController () @@ -15,16 +16,18 @@ @interface FLTGoogleMapGroundOverlayController () @end -@implementation FLTGoogleMapGroundOverlayController +@implementation FLTGoogleMapGroundOverlayController - (instancetype)initGroundOverlayWithPosition:(CLLocationCoordinate2D)position - icon:(UIImage*)icon + icon:(UIImage *)icon groundOverlayId:(NSString *)groundOverlayId mapView:(GMSMapView *)mapView { self = [super init]; if (self) { float zoomLevel = mapView.camera.zoom; - _groundOverlay = [GMSGroundOverlay groundOverlayWithPosition:position icon:icon zoomLevel:zoomLevel]; + _groundOverlay = [GMSGroundOverlay groundOverlayWithPosition:position + icon:icon + zoomLevel:zoomLevel]; _mapView = mapView; _groundOverlayId = groundOverlayId; _groundOverlay.userData = @[ _groundOverlayId ]; @@ -33,10 +36,10 @@ - (instancetype)initGroundOverlayWithPosition:(CLLocationCoordinate2D)position return self; } -- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds*)bounds - icon:(UIImage*)icon - groundOverlayId:(NSString*)groundOverlayId - mapView:(GMSMapView*)mapView { +- (instancetype)initGroundOverlayWithBounds:(GMSCoordinateBounds *)bounds + icon:(UIImage *)icon + groundOverlayId:(NSString *)groundOverlayId + mapView:(GMSMapView *)mapView { self = [super init]; if (self) { _groundOverlay = [GMSGroundOverlay groundOverlayWithBounds:bounds icon:icon]; @@ -78,7 +81,7 @@ - (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height self.groundOverlay.position = location; } -- (void)setBitmapDescriptor:(UIImage*)bd { +- (void)setBitmapDescriptor:(UIImage *)bd { self.groundOverlay.icon = bd; } @@ -92,14 +95,15 @@ - (void)setOpacity:(float)opacity { @end -static void InterpretGroundOverlayOptions(NSDictionary* data, id sink, - NSObject* registrar) { - NSNumber* consumeTapEvents = data[@"consumeTapEvents"]; +static void InterpretGroundOverlayOptions(NSDictionary *data, + id sink, + NSObject *registrar) { + NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; if (consumeTapEvents != nil) { [sink setConsumeTapEvents:consumeTapEvents.boolValue]; } - NSNumber* visible = data[@"visible"]; + NSNumber *visible = data[@"visible"]; if (visible != nil) { [sink setVisible:visible.boolValue]; } @@ -109,44 +113,48 @@ static void InterpretGroundOverlayOptions(NSDictionary* data, id* registrar, NSArray* bitmapData) { - UIImage* image; +static UIImage *ExtractBitmapDescriptor(NSObject *registrar, + NSArray *bitmapData) { + UIImage *image; if ([bitmapData.firstObject isEqualToString:@"fromAsset"]) { if (bitmapData.count == 2) { image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapData[1]]]; @@ -171,13 +180,13 @@ static void InterpretGroundOverlayOptions(NSDictionary* data, id* registrar; -@property(weak, nonatomic) GMSMapView* mapView; +@property(strong, nonatomic) NSMutableDictionary *groundOverlayIdToController; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; @end -@implementation FLTGroundOverlaysController +@implementation FLTGroundOverlaysController - (instancetype)init:(FlutterMethodChannel *)methodChannel mapView:(GMSMapView *)mapView @@ -231,37 +240,38 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel return self; } -- (void)addGroundOverlays:(NSArray*)groundOverlaysToAdd { +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd { for (NSDictionary *groundOverlay in groundOverlaysToAdd) { - GMSCoordinateBounds* bounds = [FLTGroundOverlaysController getBounds:groundOverlay]; - UIImage* icon = [FLTGroundOverlaysController getImage:groundOverlay registrar:_registrar]; - NSString* groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; - + GMSCoordinateBounds *bounds = [FLTGroundOverlaysController getBounds:groundOverlay]; + UIImage *icon = [FLTGroundOverlaysController getImage:groundOverlay registrar:_registrar]; + NSString *groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; + if (bounds) { - CLLocationCoordinate2D location = [FLTGoogleMapJSONConversions locationFromLatLong:groundOverlay[@"location"]]; - FLTGoogleMapGroundOverlayController* controller = + CLLocationCoordinate2D location = + [FLTGoogleMapJSONConversions locationFromLatLong:groundOverlay[@"location"]]; + FLTGoogleMapGroundOverlayController *controller = [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithPosition:location - icon:icon - groundOverlayId:groundOverlayId - mapView:_mapView]; + icon:icon + groundOverlayId:groundOverlayId + mapView:_mapView]; InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); _groundOverlayIdToController[groundOverlayId] = controller; } else { - FLTGoogleMapGroundOverlayController* controller = + FLTGoogleMapGroundOverlayController *controller = [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithBounds:bounds icon:icon - groundOverlayId:groundOverlayId - mapView:_mapView]; + groundOverlayId:groundOverlayId + mapView:_mapView]; InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); _groundOverlayIdToController[groundOverlayId] = controller; } } } -- (void)changeGroundOverlays:(NSArray*)groundOverlaysToChange { - for (NSDictionary* groundOverlay in groundOverlaysToChange) { - NSString* groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; - FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[groundOverlayId]; +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange { + for (NSDictionary *groundOverlay in groundOverlaysToChange) { + NSString *groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; + FLTGoogleMapGroundOverlayController *controller = _groundOverlayIdToController[groundOverlayId]; if (!controller) { continue; } @@ -270,11 +280,11 @@ - (void)changeGroundOverlays:(NSArray*)groundOverlaysToChange { } - (void)removeGroundOverlayWithIdentifiers:(NSArray *)groundOverlayIdsToRemove { - for (NSString* groundOverlayId in groundOverlayIdsToRemove) { + for (NSString *groundOverlayId in groundOverlayIdsToRemove) { if (!groundOverlayId) { continue; } - FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[groundOverlayId]; + FLTGoogleMapGroundOverlayController *controller = _groundOverlayIdToController[groundOverlayId]; if (!controller) { continue; } @@ -294,7 +304,7 @@ - (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { if (!identifier) { return; } - FLTGoogleMapGroundOverlayController* controller = _groundOverlayIdToController[identifier]; + FLTGoogleMapGroundOverlayController *controller = _groundOverlayIdToController[identifier]; if (!controller) { return; } @@ -302,12 +312,13 @@ - (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { } + (GMSCoordinateBounds *)getBounds:(NSDictionary *)groundOverlay { - NSArray* bounds = groundOverlay[@"bounds"]; + NSArray *bounds = groundOverlay[@"bounds"]; return [FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:bounds]; } -+ (UIImage *)getImage:(NSDictionary *)groundOverlay registrar:(NSObject*) registrar { - NSArray* image = groundOverlay[@"bitmap"]; ++ (UIImage *)getImage:(NSDictionary *)groundOverlay + registrar:(NSObject *)registrar { + NSArray *image = groundOverlay[@"bitmap"]; return ExtractBitmapDescriptor(registrar, image); } From 7f94b89b1af6f603fb8eccde54a12719c110ff30 Mon Sep 17 00:00:00 2001 From: pdenert Date: Wed, 12 Jun 2024 20:41:01 +0200 Subject: [PATCH 04/12] remove web pubspec changes --- .../google_maps_flutter_web/example/pubspec.yaml | 9 +-------- .../google_maps_flutter_web/pubspec.yaml | 5 ----- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 20497f00f5dc..1bf458f7ac79 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -29,14 +29,7 @@ flutter: assets: - assets/ -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins dependency_overrides: - # Override the google_maps_flutter dependency on google_maps_flutter_web. - # TODO(ditman): Unwind the circular dependency. This will create problems - # if we need to make a breaking change to google_maps_flutter_web. - google_maps_flutter_platform_interface: - path: ../../../google_maps_flutter/google_maps_flutter_platform_interface google_maps_flutter_web: - path: ../../../google_maps_flutter/google_maps_flutter_web + path: ../ diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index dacd691901ea..76707dd7c1e9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -40,8 +40,3 @@ topics: # The example deliberately includes limited-use secrets. false_secrets: - /example/web/index.html - -# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. -# See https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changing-federated-plugins -dependency_overrides: - {google_maps_flutter_platform_interface: {path: ../../google_maps_flutter/google_maps_flutter_platform_interface}} From 0439d395b2a87ac82bba3fac54a5dd504ca73e9e Mon Sep 17 00:00:00 2001 From: pdenert Date: Wed, 12 Jun 2024 20:44:29 +0200 Subject: [PATCH 05/12] Update version and changelog --- packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md | 4 ++++ packages/google_maps_flutter/google_maps_flutter/pubspec.yaml | 2 +- .../google_maps_flutter_android/CHANGELOG.md | 4 ++++ .../google_maps_flutter_android/pubspec.yaml | 2 +- .../google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md | 4 ++++ .../google_maps_flutter/google_maps_flutter_ios/pubspec.yaml | 2 +- .../google_maps_flutter_platform_interface/CHANGELOG.md | 4 ++++ .../google_maps_flutter_platform_interface/pubspec.yaml | 2 +- 8 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index c92f63deb0eb..267cafc8fc8c 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Add ground overlay support for Android and iOS. + ## 2.7.0 * Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index acdcb2f03751..c2217c78dc30 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.7.0 +version: 2.8.0 environment: sdk: ^3.4.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index f2fcc3cc80e4..97c9e25a9353 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.10.0 + +* Add ground overlay support for Android and iOS. + ## 2.9.0 * Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 1d7ee7c3e901..4bdd7515db26 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.9.0 +version: 2.10.0 environment: sdk: ^3.4.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index a43cf9c5d5f0..d42213313130 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Add ground overlay support for Android and iOS. + ## 2.7.0 * Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index 85be04f7b3aa..d8ca648e66a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.7.0 +version: 2.8.0 environment: sdk: ^3.2.3 diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md index c4a3cebf3b5f..57cbbf97ac12 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.0 + +* Add ground overlay support for Android and iOS. + ## 2.7.1 * Undeprecates `BitmapDescriptor.fromAssetImage`. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml index 6f0f5d54942d..e9d672efb1c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/google_maps_f issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.7.1 +version: 2.8.0 environment: sdk: ^3.2.0 From 6c991f71b6eac7de459b06155e85f56976e436aa Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 13 Jun 2024 10:00:30 +0200 Subject: [PATCH 06/12] Rename location to position as it is in sdk --- .../flutter/plugins/googlemaps/Convert.java | 13 +-- .../googlemaps/GroundOverlayBuilder.java | 10 +- .../googlemaps/GroundOverlayController.java | 10 +- .../googlemaps/GroundOverlayOptionsSink.java | 6 +- .../GoogleMapGroundOverlayController.h | 8 +- .../GoogleMapGroundOverlayController.m | 42 ++------- .../lib/src/types/ground_overlay.dart | 93 ++++++++++++++----- 7 files changed, 108 insertions(+), 74 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index 9aa25b781188..bbf5b104b82e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -870,7 +870,8 @@ static String interpretCircleOptions(Object o, CircleOptionsSink sink) { } } - static String interpretGroundOverlayOptions(Object o, GroundOverlayOptionsSink sink) { + static String interpretGroundOverlayOptions( + Object o, GroundOverlayOptionsSink sink, AssetManager assetManager, float density) { final Map data = toMap(o); final Object consumeTapEvents = data.get("consumeTapEvents"); if (consumeTapEvents != null) { @@ -883,15 +884,15 @@ static String interpretGroundOverlayOptions(Object o, GroundOverlayOptionsSink s final Object width = data.get("width"); final Object height = data.get("height"); - final Object location = data.get("location"); + final Object position = data.get("position"); final Object bounds = data.get("bounds"); if (height != null) { - sink.setLocation(toLatLng(location), toFloat(width), toFloat(height), null); + sink.setPosition(toLatLng(position), toFloat(width), toFloat(height), null); } else { if (width != null) { - sink.setLocation(toLatLng(location), toFloat(width), null, null); + sink.setPosition(toLatLng(position), toFloat(width), null, null); } else { - sink.setLocation(null, null, null, toLatLngBounds(bounds)); + sink.setPosition(null, null, null, toLatLngBounds(bounds)); } } @@ -910,7 +911,7 @@ static String interpretGroundOverlayOptions(Object o, GroundOverlayOptionsSink s final Object bitmap = data.get("bitmap"); if (bitmap != null) { - sink.setBitmapDescriptor(toBitmapDescriptor(bitmap)); + sink.setBitmapDescriptor(toBitmapDescriptor(bitmap, assetManager, density)); } final String groundOverlayId = (String) data.get("groundOverlayId"); if (groundOverlayId == null) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java index 04e9a908a2ba..d4f646025e89 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayBuilder.java @@ -1,3 +1,7 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.googlemaps; import com.google.android.gms.maps.model.BitmapDescriptor; @@ -38,12 +42,12 @@ public void setZIndex(float zIndex) { } @Override - public void setLocation(Object location, Object width, Object height, Object bounds) { + public void setPosition(Object position, Object width, Object height, Object bounds) { if (height != null) { - groundOverlayOptions.position((LatLng) location, (float) width, (float) height); + groundOverlayOptions.position((LatLng) position, (float) width, (float) height); } else { if (width != null) { - groundOverlayOptions.position((LatLng) location, (float) width); + groundOverlayOptions.position((LatLng) position, (float) width); } else { groundOverlayOptions.positionFromBounds((LatLngBounds) bounds); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java index 310c3c2a0f74..be2e6839a1a2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayController.java @@ -1,3 +1,7 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.googlemaps; import com.google.android.gms.maps.model.BitmapDescriptor; @@ -40,7 +44,7 @@ void remove() { } @Override - public void setLocation(Object location, Object width, Object height, Object bounds) { + public void setPosition(Object position, Object width, Object height, Object bounds) { if (height != null && width != null) { this.groundOverlay.setDimensions((float) width, (float) height); } else { @@ -48,8 +52,8 @@ public void setLocation(Object location, Object width, Object height, Object bou this.groundOverlay.setDimensions((float) width); } } - if (location != null) { - this.groundOverlay.setPosition((LatLng) location); + if (position != null) { + this.groundOverlay.setPosition((LatLng) position); } if (bounds != null) { this.groundOverlay.setPositionFromBounds((LatLngBounds) bounds); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java index 47d6a1641f32..3d103d2e0d76 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlayOptionsSink.java @@ -1,3 +1,7 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.googlemaps; import com.google.android.gms.maps.model.BitmapDescriptor; @@ -9,7 +13,7 @@ interface GroundOverlayOptionsSink { void setZIndex(float zIndex); - void setLocation(Object location, Object width, Object height, Object bounds); + void setPosition(Object position, Object width, Object height, Object bounds); void setBitmapDescriptor(BitmapDescriptor bd); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h index 7e1e5d8f3e5b..d3a513eab115 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.h @@ -1,6 +1,6 @@ -// // Copyright 2024 The Flutter Authors. All rights reserved. -// // Use of this source code is governed by a BSD-style license that can be -// // found in the LICENSE file. +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #import #import @@ -12,7 +12,7 @@ - (void)setBitmapDescriptor:(UIImage *)bd; - (void)setBounds:(GMSCoordinateBounds *)bounds; - (void)setConsumeTapEvents:(BOOL)consume; -- (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height:(CGFloat)height; +- (void)setPosition:(CLLocationCoordinate2D)position width:(CGFloat)width height:(CGFloat)height; - (void)setOpacity:(float)opacity; - (void)setVisible:(BOOL)visible; - (void)setZIndex:(int)zIndex; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m index 4b1fa270a58b..7230e3328f03 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapGroundOverlayController.m @@ -1,6 +1,6 @@ -// // Copyright 2019 The Chromium Authors. All rights reserved. -// // Use of this source code is governed by a BSD-style license that can be -// // found in the LICENSE file. +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #import "GoogleMapGroundOverlayController.h" #import "FLTGoogleMapJSONConversions.h" @@ -77,8 +77,8 @@ - (void)setBounds:(GMSCoordinateBounds *)bounds { self.groundOverlay.bounds = bounds; } -- (void)setLocation:(CLLocationCoordinate2D)location width:(CGFloat)width height:(CGFloat)height { - self.groundOverlay.position = location; +- (void)setPosition:(CLLocationCoordinate2D)position width:(CGFloat)width height:(CGFloat)height { + self.groundOverlay.position = position; } - (void)setBitmapDescriptor:(UIImage *)bd { @@ -120,28 +120,6 @@ static void InterpretGroundOverlayOptions(NSDictionary *data, [sink setOpacity:opacity]; } - NSNumber *width = data[@"width"]; - NSNumber *height = data[@"height"]; - NSArray *location = data[@"location"]; - if (location) { - if (height != nil) { - [sink setLocation:[FLTGoogleMapJSONConversions locationFromLatLong:location] - width:width.doubleValue - height:height.doubleValue]; - } else { - if (width != nil) { - [sink setLocation:[FLTGoogleMapJSONConversions locationFromLatLong:location] - width:width.doubleValue - height:150]; - } - } - } - - NSArray *bounds = data[@"bounds"]; - if (bounds) { - [sink setBounds:[FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:bounds]]; - } - NSNumber *bearing = data[@"bearing"]; if (bearing != nil) { [sink setBearing:bearing.floatValue]; @@ -242,21 +220,21 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel - (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd { for (NSDictionary *groundOverlay in groundOverlaysToAdd) { - GMSCoordinateBounds *bounds = [FLTGroundOverlaysController getBounds:groundOverlay]; UIImage *icon = [FLTGroundOverlaysController getImage:groundOverlay registrar:_registrar]; NSString *groundOverlayId = [FLTGroundOverlaysController getGroundOverlayId:groundOverlay]; - if (bounds) { - CLLocationCoordinate2D location = - [FLTGoogleMapJSONConversions locationFromLatLong:groundOverlay[@"location"]]; + if (groundOverlay[@"bounds"] == nil) { + CLLocationCoordinate2D position = + [FLTGoogleMapJSONConversions locationFromLatLong:groundOverlay[@"position"]]; FLTGoogleMapGroundOverlayController *controller = - [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithPosition:location + [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithPosition:position icon:icon groundOverlayId:groundOverlayId mapView:_mapView]; InterpretGroundOverlayOptions(groundOverlay, controller, _registrar); _groundOverlayIdToController[groundOverlayId] = controller; } else { + GMSCoordinateBounds *bounds = [FLTGroundOverlaysController getBounds:groundOverlay]; FLTGoogleMapGroundOverlayController *controller = [[FLTGoogleMapGroundOverlayController alloc] initGroundOverlayWithBounds:bounds icon:icon diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart index 3a15892b0cd0..1ff15c71be8f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart @@ -1,4 +1,4 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2024 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -30,12 +30,12 @@ class GroundOverlay implements MapsObject { /// Creates an immutable representation of a [GroundOverlay] to draw on [GoogleMap]. /// The following ground overlay positioning is allowed by the Google Maps Api /// 1. Using [height], [width] and [LatLng] - /// 2. Using [width], [width] + /// 2. Using [width] and [LatLng] /// 3. Using [LatLngBounds] - const GroundOverlay({ + const GroundOverlay._({ required this.groundOverlayId, this.clickable = false, - this.location, + this.position, this.zIndex = 0, this.onTap, this.visible = true, @@ -45,6 +45,43 @@ class GroundOverlay implements MapsObject { this.bearing = 0.0, this.anchor = Offset.zero, this.opacity = 1.0, + this.bounds, + }) : assert( + (height != null && + width != null && + position != null && + bounds == null) || + (height == null && + width == null && + position == null && + bounds != null) || + (height == null && + width != null && + position != null && + bounds == null) || + (height == null && + width == null && + position == null && + bounds == null), + 'Only one of the three types of positioning is allowed, please refer ' + 'to the https://developers.google.com/maps/documentation/android-sdk/groundoverlay#add_an_overlay'), + assert(0.0 <= opacity && opacity <= 1.0); + + /// Creates an immutable representation of a [GroundOverlay] to draw on [GoogleMap] + /// using [LatLng] and [width] + const GroundOverlay.fromPosition({ + required this.groundOverlayId, + required LatLng this.position, + required double this.width, + this.clickable = false, + this.zIndex = 0, + this.onTap, + this.visible = true, + this.bitmap, + this.height, + this.bearing = 0.0, + this.anchor = Offset.zero, + this.opacity = 1.0, }) : bounds = null, assert(0.0 <= opacity && opacity <= 1.0); @@ -62,7 +99,7 @@ class GroundOverlay implements MapsObject { this.visible = true, this.zIndex = 0, }) : assert(0.0 <= opacity && opacity <= 1.0), - location = null, + position = null, height = null, width = null; @@ -78,7 +115,7 @@ class GroundOverlay implements MapsObject { final bool clickable; /// Geographical location of the center of the ground overlay. - final LatLng? location; + final LatLng? position; /// True if the ground overlay is visible. final bool visible; @@ -131,24 +168,26 @@ class GroundOverlay implements MapsObject { double? widthParam, double? heightParam, double? bearingParam, - LatLng? locationParam, + LatLng? positionParam, LatLngBounds? boundsParam, VoidCallback? onTapParam, double? opacityParam, }) { - return GroundOverlay( - groundOverlayId: groundOverlayId, - clickable: clickableParam ?? clickable, - bitmap: bitmapParam ?? bitmap, - opacity: opacityParam ?? opacity, - location: locationParam ?? location, - visible: visibleParam ?? visible, - bearing: bearingParam ?? bearing, - anchor: anchorParam ?? anchor, - height: heightParam ?? height, - zIndex: zIndexParam ?? zIndex, - width: widthParam ?? width, - onTap: onTapParam ?? onTap); + return GroundOverlay._( + groundOverlayId: groundOverlayId, + clickable: clickableParam ?? clickable, + bitmap: bitmapParam ?? bitmap, + opacity: opacityParam ?? opacity, + position: positionParam ?? position, + visible: visibleParam ?? visible, + bearing: bearingParam ?? bearing, + anchor: anchorParam ?? anchor, + height: heightParam ?? height, + zIndex: zIndexParam ?? zIndex, + width: widthParam ?? width, + onTap: onTapParam ?? onTap, + bounds: boundsParam ?? bounds, + ); } /// Creates a new [GroundOverlay] object whose values are the same as this instance. @@ -177,8 +216,8 @@ class GroundOverlay implements MapsObject { addIfPresent('bounds', bounds?.toJson()); addIfPresent('bitmap', bitmap?.toJson()); addIfPresent('width', width); - if (location != null) { - json['location'] = _locationToJson(); + if (position != null) { + json['position'] = _positionToJson(); } return json; } @@ -193,13 +232,17 @@ class GroundOverlay implements MapsObject { return false; } - final GroundOverlay typedOther = other as GroundOverlay; + if (other is! GroundOverlay) { + return false; + } + + final GroundOverlay typedOther = other; return groundOverlayId == typedOther.groundOverlayId && bitmap == typedOther.bitmap && clickable == typedOther.clickable && opacity == typedOther.opacity && - location == typedOther.location && + position == typedOther.position && bearing == typedOther.bearing && visible == typedOther.visible && height == typedOther.height && @@ -213,7 +256,7 @@ class GroundOverlay implements MapsObject { @override int get hashCode => groundOverlayId.hashCode; - dynamic _locationToJson() => location?.toJson(); + dynamic _positionToJson() => position?.toJson(); dynamic _offsetToJson(Offset offset) { return [offset.dx, offset.dy]; From 8239ba3e13d523b249403e346e8c756d2269e7df Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 13 Jun 2024 10:01:07 +0200 Subject: [PATCH 07/12] Update android to use AssetManager in GroundOverlays --- .../plugins/googlemaps/GoogleMapController.java | 7 +++++-- .../googlemaps/GroundOverlaysController.java | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index 75984b161538..acc97cc54023 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -128,7 +128,8 @@ class GoogleMapController this.polylinesController = new PolylinesController(methodChannel, assetManager, density); this.circlesController = new CirclesController(methodChannel, density); this.tileOverlaysController = new TileOverlaysController(methodChannel); - this.groundOverlaysController = new GroundOverlaysController(methodChannel); + this.groundOverlaysController = + new GroundOverlaysController(methodChannel, assetManager, density); } // Constructor for testing purposes only @@ -144,7 +145,8 @@ class GoogleMapController PolygonsController polygonsController, PolylinesController polylinesController, CirclesController circlesController, - TileOverlaysController tileOverlaysController) { + TileOverlaysController tileOverlaysController, + GroundOverlaysController groundOverlaysController) { this.id = id; this.context = context; this.methodChannel = methodChannel; @@ -158,6 +160,7 @@ class GoogleMapController this.polylinesController = polylinesController; this.circlesController = circlesController; this.tileOverlaysController = tileOverlaysController; + this.groundOverlaysController = groundOverlaysController; } @Override diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java index 561d0f644efe..96718abd468b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GroundOverlaysController.java @@ -1,5 +1,10 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.googlemaps; +import android.content.res.AssetManager; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.GroundOverlay; import com.google.android.gms.maps.model.GroundOverlayOptions; @@ -14,11 +19,15 @@ class GroundOverlaysController { private final Map groundOverlayIdToController; private final Map googleMapsGroundOverlayIdToDartOverlayId; private MethodChannel methodChannel; + private final AssetManager assetManager; + private final float density; - GroundOverlaysController(MethodChannel methodChannel) { + GroundOverlaysController(MethodChannel methodChannel, AssetManager assetManager, float density) { this.methodChannel = methodChannel; this.groundOverlayIdToController = new HashMap<>(); this.googleMapsGroundOverlayIdToDartOverlayId = new HashMap<>(); + this.assetManager = assetManager; + this.density = density; } void setGoogleMap(GoogleMap googleMap) { @@ -40,7 +49,8 @@ private void addGroundOverlay(Object groundOverlay) { GroundOverlayBuilder groundOverlayBuilder = new GroundOverlayBuilder(); String groundOverlayId = - Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayBuilder); + Convert.interpretGroundOverlayOptions( + groundOverlay, groundOverlayBuilder, assetManager, density); GroundOverlayOptions options = groundOverlayBuilder.build(); addGroundOverlay(groundOverlayId, options, groundOverlayBuilder.consumeTapEvents()); } @@ -84,7 +94,8 @@ private void changeGroundOverlay(Object groundOverlay) { GroundOverlayController groundOverlayController = groundOverlayIdToController.get(groundOverlayId); if (groundOverlayController != null) { - Convert.interpretGroundOverlayOptions(groundOverlay, groundOverlayController); + Convert.interpretGroundOverlayOptions( + groundOverlay, groundOverlayController, assetManager, density); } } From f8ec1b993e2c2b19c4ee40c0054f9cd043a46f8a Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 13 Jun 2024 10:01:16 +0200 Subject: [PATCH 08/12] Update example --- .../example/lib/ground_overlay.dart | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart index acc9c1ea429f..071555e2f885 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/ground_overlay.dart @@ -65,14 +65,22 @@ class GroundOverlayBodyState extends State { Widget build(BuildContext context) { final Set overlays = { if (_overlayImage != null) - GroundOverlay( + GroundOverlay.fromPosition( groundOverlayId: const GroundOverlayId('ground_overlay_1'), bitmap: _overlayImage, - location: const LatLng(59.935460, 30.325177), + position: const LatLng(59.935460, 30.325177), width: 200, bearing: _bearing, opacity: _opacity, ), + if (_overlayImage != null) + GroundOverlay.fromBounds( + LatLngBounds( + southwest: const LatLng(59.945460, 30.335177), + northeast: const LatLng(59.946460, 30.336177)), + groundOverlayId: const GroundOverlayId('ground_overlay_3'), + bitmap: _overlayImage, + ), }; return Column( mainAxisSize: MainAxisSize.min, From 07ae965c59d4466fce8d2cf24918204843a63ec4 Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 13 Jun 2024 10:01:29 +0200 Subject: [PATCH 09/12] Update licenses --- .../lib/src/types/ground_overlay_updates.dart | 2 +- .../lib/src/types/utils/ground_overlay.dart | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart index d2fef358dfb2..7f382408593d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart @@ -1,4 +1,4 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2024 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart index 3b0059bcf80a..eebf7d5f5e0a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/utils/ground_overlay.dart @@ -1,3 +1,7 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import '../types.dart'; import 'maps_object.dart'; From e996d1f361af36afd56bd1479cf31fe79cb7e251 Mon Sep 17 00:00:00 2001 From: pdenert Date: Thu, 13 Jun 2024 10:01:42 +0200 Subject: [PATCH 10/12] Add platform interface test --- .../test/types/ground_overlay_test.dart | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_test.dart new file mode 100644 index 000000000000..627c521ff6c1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_test.dart @@ -0,0 +1,186 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:google_maps_flutter_platform_interface/src/types/types.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('ground overlay id tests', () { + test('equality', () async { + const GroundOverlayId id1 = GroundOverlayId('1'); + const GroundOverlayId id2 = GroundOverlayId('1'); + const GroundOverlayId id3 = GroundOverlayId('2'); + expect(id1, id2); + expect(id1, isNot(id3)); + }); + + test('toString', () async { + const GroundOverlayId id1 = GroundOverlayId('1'); + expect(id1.toString(), 'GroundOverlayId(1)'); + }); + }); + + group('ground overlay tests', () { + test('GroundOverlay.fromPosition toJson returns correct format', () async { + const GroundOverlay groundOverlay = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Object json = groundOverlay.toJson(); + expect(json, { + 'groundOverlayId': 'id', + 'clickable': false, + 'transparency': 0.0, + 'bearing': 0.0, + 'visible': true, + 'zIndex': 0, + 'anchor': [0.0, 0.0], + 'width': 200.0, + 'position': [32.0, 32.0] + }); + + final GroundOverlay groundOverlayAllOptions = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('id'), + position: const LatLng(32.0, 32.0), + width: 200, + height: 100, + clickable: true, + zIndex: 2, + onTap: () {}, + visible: false, + bitmap: BitmapDescriptor.defaultMarker, + bearing: 1.0, + anchor: const Offset(0.5, 0.5), + opacity: 0.7, + ); + final Object jsonAllOptions = groundOverlayAllOptions.toJson(); + expect(jsonAllOptions, { + 'groundOverlayId': 'id', + 'clickable': true, + 'transparency': 0.30000000000000004, + 'bearing': 1.0, + 'visible': false, + 'zIndex': 2, + 'height': 100.0, + 'anchor': [0.5, 0.5], + 'bitmap': ['defaultMarker'], + 'width': 200.0, + 'position': [32.0, 32.0] + }); + }); + + test('GroundOverlay.fromBounds toJson returns correct format', () async { + final GroundOverlay groundOverlay = GroundOverlay.fromBounds( + LatLngBounds( + southwest: const LatLng(32.0, 33.0), + northeast: const LatLng(33.0, 32.0), + ), + groundOverlayId: const GroundOverlayId('id'), + ); + final Object json = groundOverlay.toJson(); + expect(json, { + 'groundOverlayId': 'id', + 'clickable': false, + 'transparency': 0.0, + 'bearing': 0.0, + 'visible': true, + 'zIndex': 0, + 'anchor': [0.0, 0.0], + 'bounds': [ + [32.0, 33.0], + [33.0, 32.0], + ] + }); + }); + + test('invalid opacity throws', () async { + expect( + () => GroundOverlay.fromPosition( + position: const LatLng(32.0, 32.0), + width: 200, + groundOverlayId: const GroundOverlayId('id1'), + opacity: -0.1, + ), + throwsAssertionError, + ); + expect( + () => GroundOverlay.fromPosition( + position: const LatLng(32.0, 32.0), + width: 200, + groundOverlayId: const GroundOverlayId('id2'), + opacity: 1.2, + ), + throwsAssertionError, + ); + }); + + test('equality', () async { + const GroundOverlay groundOverlay1 = GroundOverlay.fromPosition( + position: LatLng(32.0, 32.0), + width: 200, + groundOverlayId: GroundOverlayId('idEquality1'), + opacity: 0.5, + ); + const GroundOverlay groundOverlay2 = GroundOverlay.fromPosition( + position: LatLng(32.0, 32.0), + width: 200, + groundOverlayId: GroundOverlayId('idEquality1'), + opacity: 0.5, + ); + const GroundOverlay groundOverlay3 = GroundOverlay.fromPosition( + position: LatLng(33.0, 33.0), + width: 300, + groundOverlayId: GroundOverlayId('idEquality2'), + opacity: 0.7, + ); + + expect(groundOverlay1, equals(groundOverlay2)); + expect(groundOverlay1, isNot(equals(groundOverlay3))); + }); + + test('clone', () { + const GroundOverlay original = GroundOverlay.fromPosition( + position: LatLng(32.0, 32.0), + width: 200, + groundOverlayId: GroundOverlayId('idClone'), + opacity: 0.5, + ); + final GroundOverlay clone = original.clone(); + + // Check if the clone is equal to the original + expect(clone, equals(original)); + // Check if the clone is not the same instance as the original + expect(identical(clone, original), isFalse); + }); + + test('hashCode', () { + const GroundOverlay groundOverlay1 = GroundOverlay.fromPosition( + position: LatLng(32.0, 32.0), + width: 200, + groundOverlayId: GroundOverlayId('idHashCode'), + opacity: 0.5, + ); + const GroundOverlay groundOverlay2 = GroundOverlay.fromPosition( + position: LatLng(32.0, 32.0), + width: 200, + groundOverlayId: GroundOverlayId('idHashCode'), + opacity: 0.5, + ); + const GroundOverlay groundOverlay3 = GroundOverlay.fromPosition( + position: LatLng(33.0, 33.0), + width: 300, + groundOverlayId: GroundOverlayId('idDifferent'), + opacity: 0.7, + ); + + expect(groundOverlay1.hashCode, equals(groundOverlay2.hashCode)); + expect(groundOverlay1.hashCode, isNot(equals(groundOverlay3.hashCode))); + expect(groundOverlay1.hashCode, equals(groundOverlay1.hashCode)); + }); + }); +} From 5e78e4395095ed6a013cf8b0513e9de8e6f4c7e1 Mon Sep 17 00:00:00 2001 From: pdenert Date: Sat, 15 Jun 2024 00:31:23 +0200 Subject: [PATCH 11/12] Add ground overlay updates tests --- .../types/ground_overlay_updates_test.dart | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_updates_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_updates_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_updates_test.dart new file mode 100644 index 000000000000..a2068eb3b832 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/ground_overlay_updates_test.dart @@ -0,0 +1,216 @@ +// Copyright 2024 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + group('ground overlay updates tests', () { + test('Correctly set toRemove, toAdd and toChange', () async { + const GroundOverlay to1 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id1'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to2 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id2'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3Changed = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + opacity: 0.5, + ); + const GroundOverlay to4 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id4'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Set previous = {to1, to2, to3}; + final Set current = {to2, to3Changed, to4}; + final GroundOverlayUpdates updates = + GroundOverlayUpdates.from(previous, current); + + final Set toRemove = { + const GroundOverlayId('id1') + }; + expect(updates.groundOverlayIdsToRemove, toRemove); + + final Set toAdd = {to4}; + expect(updates.groundOverlaysToAdd, toAdd); + + final Set toChange = {to3Changed}; + expect(updates.groundOverlaysToChange, toChange); + }); + + test('toJson', () async { + const GroundOverlay to1 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id1'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to2 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id2'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3Changed = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + opacity: 0.5, + ); + const GroundOverlay to4 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id4'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Set previous = {to1, to2, to3}; + final Set current = {to2, to3Changed, to4}; + final GroundOverlayUpdates updates = + GroundOverlayUpdates.from(previous, current); + + final Object json = updates.toJson(); + expect(json, { + 'groundOverlaysToAdd': + serializeGroundOverlaySet(updates.groundOverlaysToAdd), + 'groundOverlaysToChange': + serializeGroundOverlaySet(updates.groundOverlaysToChange), + 'groundOverlayIdsToRemove': updates.groundOverlayIdsToRemove + .map((GroundOverlayId m) => m.value) + .toList() + }); + }); + + test('eqaulity', () async { + const GroundOverlay to1 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id1'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to2 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id2'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3Changed = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + opacity: 0.5, + ); + const GroundOverlay to4 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id4'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Set previous = {to1, to2, to3}; + final Set current1 = {to2, to3Changed, to4}; + final Set current2 = {to2, to3Changed, to4}; + final Set current3 = {to2, to4}; + final GroundOverlayUpdates updates1 = + GroundOverlayUpdates.from(previous, current1); + final GroundOverlayUpdates updates2 = + GroundOverlayUpdates.from(previous, current2); + final GroundOverlayUpdates updates3 = + GroundOverlayUpdates.from(previous, current3); + + expect(updates1, updates2); + expect(updates1, isNot(updates3)); + }); + + test('hashCode', () async { + const GroundOverlay to1 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id1'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to2 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id2'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3Changed = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + opacity: 0.5, + ); + const GroundOverlay to4 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id4'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Set previous = {to1, to2, to3}; + final Set current = {to2, to3Changed, to4}; + final GroundOverlayUpdates updates = + GroundOverlayUpdates.from(previous, current); + + expect(updates.hashCode, equals(updates.hashCode)); + }); + + test('toString', () async { + const GroundOverlay to1 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id1'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to2 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id2'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + ); + const GroundOverlay to3Changed = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id3'), + position: LatLng(32.0, 32.0), + width: 200, + opacity: 0.5, + ); + const GroundOverlay to4 = GroundOverlay.fromPosition( + groundOverlayId: GroundOverlayId('id4'), + position: LatLng(32.0, 32.0), + width: 200, + ); + final Set previous = {to1, to2, to3}; + final Set current = {to2, to3Changed, to4}; + final GroundOverlayUpdates updates = + GroundOverlayUpdates.from(previous, current); + + expect( + updates.toString(), + 'GroundOverlayUpdates(add: ${updates.groundOverlaysToAdd}, ' + 'remove: ${updates.groundOverlayIdsToRemove}, ' + 'change: ${updates.groundOverlaysToChange})'); + }); + }); +} From a654a686789eb735140f18c1ba726c259cc16d2a Mon Sep 17 00:00:00 2001 From: pdenert Date: Sat, 15 Jun 2024 00:34:56 +0200 Subject: [PATCH 12/12] Revert changes in web --- .../google_maps_flutter_web/example/pubspec.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index 1bf458f7ac79..85a89ed5bf96 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -30,6 +30,8 @@ flutter: - assets/ dependency_overrides: - + # Override the google_maps_flutter dependency on google_maps_flutter_web. + # TODO(ditman): Unwind the circular dependency. This will create problems + # if we need to make a breaking change to google_maps_flutter_web. google_maps_flutter_web: path: ../