From 2312a50049778cbdbef5ccfd1195e962cc425a5e Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 10 Mar 2021 15:22:39 -0800 Subject: [PATCH 01/30] Update pubspec for null-safe versions. --- .../google_maps_flutter_web/CHANGELOG.md | 4 ++++ .../google_maps_flutter_web/example/pubspec.yaml | 8 ++++---- .../google_maps_flutter_web/pubspec.yaml | 6 +++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 29e9287a14fb..2dd27b4bd563 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.0 + +* Migrate package to null-safety. + ## 0.2.1 * Move integration tests to `example`. 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 28955016ab40..fc7df3a12cf4 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 @@ -2,8 +2,8 @@ name: google_maps_flutter_web_integration_tests publish_to: none environment: - sdk: ">=2.2.2 <3.0.0" # Bump this to 2.12 when migrating to nnbd. - flutter: ">=1.27.0-0" # For integration_test from sdk + sdk: ">=2.12.0 <3.0.0" # Bump this to 2.12 when migrating to nnbd. + flutter: ">=2.1.0-0" # For integration_test from sdk dependencies: google_maps_flutter_web: @@ -12,9 +12,9 @@ dependencies: sdk: flutter dev_dependencies: - google_maps: ^3.4.4 + google_maps: ^5.0.1 http: ^0.13.0 - mockito: ^4.1.1+1 # Update to ^5.0.0 as soon as this migrates to null-safety + mockito: ^5.0.0 # Update to ^5.0.0 as soon as this migrates to null-safety flutter_driver: sdk: flutter flutter_test: 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 22df1b24afe0..a129eb7f5dd8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -1,7 +1,7 @@ name: google_maps_flutter_web description: Web platform implementation of google_maps_flutter homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter -version: 0.2.1 +version: 0.3.0 flutter: plugin: @@ -17,7 +17,7 @@ dependencies: sdk: flutter meta: ^1.3.0 google_maps_flutter_platform_interface: ^2.0.1 - google_maps: ^3.4.5 + google_maps: ^5.0.1 stream_transform: ^2.0.0 sanitize_html: ^2.0.0 @@ -27,5 +27,5 @@ dev_dependencies: pedantic: ^1.10.0 environment: - sdk: ">=2.3.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.20.0" From d70c13682c6ca255c4f15ef52f1368f08c9777ba Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 10 Mar 2021 17:38:00 -0800 Subject: [PATCH 02/30] First pass at null-safe gmaps --- .../lib/src/circle.dart | 20 +-- .../lib/src/circles.dart | 12 +- .../lib/src/convert.dart | 152 +++++------------- .../lib/src/google_maps_controller.dart | 94 +++++------ .../lib/src/google_maps_flutter_web.dart | 68 ++++---- .../lib/src/marker.dart | 42 ++--- .../lib/src/markers.dart | 25 +-- .../lib/src/polygon.dart | 18 ++- .../lib/src/polygons.dart | 10 +- .../lib/src/polyline.dart | 18 ++- .../lib/src/polylines.dart | 14 +- .../lib/src/types.dart | 4 +- 12 files changed, 206 insertions(+), 271 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index 84bae1b98e2e..9ddf766995a9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `CircleController` class wraps a [gmaps.Circle] and its `onTap` behavior. class CircleController { - gmaps.Circle _circle; + gmaps.Circle? _circle; final bool _consumeTapEvents; /// Creates a `CircleController`, which wraps a [gmaps.Circle] object and its `onTap` behavior. CircleController({ - @required gmaps.Circle circle, + required gmaps.Circle circle, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _circle = circle, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,21 +26,23 @@ class CircleController { /// Returns the wrapped [gmaps.Circle]. Only used for testing. @visibleForTesting - gmaps.Circle get circle => _circle; + gmaps.Circle? get circle => _circle; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Circle] object. void update(gmaps.CircleOptions options) { - _circle.options = options; + _circle!.options = options; } /// Disposes of the currently wrapped [gmaps.Circle]. void remove() { - _circle.visible = false; - _circle.radius = 0; - _circle.map = null; - _circle = null; + if (_circle != null) { + _circle!.visible = false; + _circle!.radius = 0; + _circle!.map = null; + _circle = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index 659d8ac823a6..6608ed09ba64 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -14,7 +14,7 @@ class CirclesController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. CirclesController({ - @required StreamController stream, + required StreamController stream, }) : _streamController = stream, _circleIdToController = Map(); @@ -26,7 +26,7 @@ class CirclesController extends GeometryController { /// /// Wraps each [Circle] into its corresponding [CircleController]. void addCircles(Set circlesToAdd) { - circlesToAdd?.forEach((circle) { + circlesToAdd.forEach((circle) { _addCircle(circle); }); } @@ -50,20 +50,20 @@ class CirclesController extends GeometryController { /// Updates a set of [Circle] objects with new options. void changeCircles(Set circlesToChange) { - circlesToChange?.forEach((circleToChange) { + circlesToChange.forEach((circleToChange) { _changeCircle(circleToChange); }); } void _changeCircle(Circle circle) { - final circleController = _circleIdToController[circle?.circleId]; + final circleController = _circleIdToController[circle.circleId]; circleController?.update(_circleOptionsFromCircle(circle)); } /// Removes a set of [CircleId]s from the cache. void removeCircles(Set circleIdsToRemove) { - circleIdsToRemove?.forEach((circleId) { - final CircleController circleController = _circleIdToController[circleId]; + circleIdsToRemove.forEach((circleId) { + final CircleController? circleController = _circleIdToController[circleId]; circleController?.remove(); _circleIdToController.remove(circleId); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index c875bf782474..45cb8a29a014 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -115,80 +115,6 @@ bool _isTrafficLayerEnabled(Map rawOptions) { return rawOptions['trafficEnabled'] ?? false; } -// Coverts the incoming JSON object into a List of MapTypeStyler objects. -List _parseStylers(List stylerJsons) { - return stylerJsons?.map((styler) { - return gmaps.MapTypeStyler() - ..color = styler['color'] - ..gamma = styler['gamma'] - ..hue = styler['hue'] - ..invertLightness = styler['invertLightness'] - ..lightness = styler['lightness'] - ..saturation = styler['saturation'] - ..visibility = styler['visibility'] - ..weight = styler['weight']; - })?.toList(); -} - -// Converts a String to its corresponding MapTypeStyleElementType enum value. -final _elementTypeToEnum = { - 'all': gmaps.MapTypeStyleElementType.ALL, - 'geometry': gmaps.MapTypeStyleElementType.GEOMETRY, - 'geometry.fill': gmaps.MapTypeStyleElementType.GEOMETRY_FILL, - 'geometry.stroke': gmaps.MapTypeStyleElementType.GEOMETRY_STROKE, - 'labels': gmaps.MapTypeStyleElementType.LABELS, - 'labels.icon': gmaps.MapTypeStyleElementType.LABELS_ICON, - 'labels.text': gmaps.MapTypeStyleElementType.LABELS_TEXT, - 'labels.text.fill': gmaps.MapTypeStyleElementType.LABELS_TEXT_FILL, - 'labels.text.stroke': gmaps.MapTypeStyleElementType.LABELS_TEXT_STROKE, -}; - -// Converts a String to its corresponding MapTypeStyleFeatureType enum value. -final _featureTypeToEnum = { - 'administrative': gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE, - 'administrative.country': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_COUNTRY, - 'administrative.land_parcel': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_LAND_PARCEL, - 'administrative.locality': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_LOCALITY, - 'administrative.neighborhood': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_NEIGHBORHOOD, - 'administrative.province': - gmaps.MapTypeStyleFeatureType.ADMINISTRATIVE_PROVINCE, - 'all': gmaps.MapTypeStyleFeatureType.ALL, - 'landscape': gmaps.MapTypeStyleFeatureType.LANDSCAPE, - 'landscape.man_made': gmaps.MapTypeStyleFeatureType.LANDSCAPE_MAN_MADE, - 'landscape.natural': gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL, - 'landscape.natural.landcover': - gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL_LANDCOVER, - 'landscape.natural.terrain': - gmaps.MapTypeStyleFeatureType.LANDSCAPE_NATURAL_TERRAIN, - 'poi': gmaps.MapTypeStyleFeatureType.POI, - 'poi.attraction': gmaps.MapTypeStyleFeatureType.POI_ATTRACTION, - 'poi.business': gmaps.MapTypeStyleFeatureType.POI_BUSINESS, - 'poi.government': gmaps.MapTypeStyleFeatureType.POI_GOVERNMENT, - 'poi.medical': gmaps.MapTypeStyleFeatureType.POI_MEDICAL, - 'poi.park': gmaps.MapTypeStyleFeatureType.POI_PARK, - 'poi.place_of_worship': gmaps.MapTypeStyleFeatureType.POI_PLACE_OF_WORSHIP, - 'poi.school': gmaps.MapTypeStyleFeatureType.POI_SCHOOL, - 'poi.sports_complex': gmaps.MapTypeStyleFeatureType.POI_SPORTS_COMPLEX, - 'road': gmaps.MapTypeStyleFeatureType.ROAD, - 'road.arterial': gmaps.MapTypeStyleFeatureType.ROAD_ARTERIAL, - 'road.highway': gmaps.MapTypeStyleFeatureType.ROAD_HIGHWAY, - 'road.highway.controlled_access': - gmaps.MapTypeStyleFeatureType.ROAD_HIGHWAY_CONTROLLED_ACCESS, - 'road.local': gmaps.MapTypeStyleFeatureType.ROAD_LOCAL, - 'transit': gmaps.MapTypeStyleFeatureType.TRANSIT, - 'transit.line': gmaps.MapTypeStyleFeatureType.TRANSIT_LINE, - 'transit.station': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION, - 'transit.station.airport': - gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_AIRPORT, - 'transit.station.bus': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_BUS, - 'transit.station.rail': gmaps.MapTypeStyleFeatureType.TRANSIT_STATION_RAIL, - 'water': gmaps.MapTypeStyleFeatureType.WATER, -}; - // The keys we'd expect to see in a serialized MapTypeStyle JSON object. final _mapStyleKeys = { 'elementType', @@ -202,15 +128,15 @@ bool _isJsonMapStyle(Map value) { } // Converts an incoming JSON-encoded Style info, into the correct gmaps array. -List _mapStyles(String mapStyleJson) { +List _mapStyles(String? mapStyleJson) { List styles = []; if (mapStyleJson != null) { styles = json.decode(mapStyleJson, reviver: (key, value) { if (value is Map && _isJsonMapStyle(value)) { return gmaps.MapTypeStyle() - ..elementType = _elementTypeToEnum[value['elementType']] - ..featureType = _featureTypeToEnum[value['featureType']] - ..stylers = _parseStylers(value['stylers']); + ..elementType = value['elementType'] + ..featureType = value['featureType'] + ..stylers = value['stylers']; } return value; }).cast(); @@ -218,32 +144,32 @@ List _mapStyles(String mapStyleJson) { return styles; } -gmaps.LatLng _latLngToGmLatLng(LatLng latLng) { +gmaps.LatLng? _latLngToGmLatLng(LatLng latLng) { if (latLng == null) return null; return gmaps.LatLng(latLng.latitude, latLng.longitude); } -LatLng _gmLatLngToLatLng(gmaps.LatLng latLng) { +LatLng _gmLatLngToLatLng(gmaps.LatLng? latLng) { if (latLng == null) return _nullLatLng; - return LatLng(latLng.lat, latLng.lng); + return LatLng(latLng.lat!.toDouble(), latLng.lng!.toDouble()); } -LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds latLngBounds) { +LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds? latLngBounds) { if (latLngBounds == null) { return _nullLatLngBounds; } return LatLngBounds( - southwest: _gmLatLngToLatLng(latLngBounds.southWest), - northeast: _gmLatLngToLatLng(latLngBounds.northEast), + southwest: _gmLatLngToLatLng(latLngBounds.southWest!), + northeast: _gmLatLngToLatLng(latLngBounds.northEast!), ); } CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { return CameraPosition( target: _gmLatLngToLatLng(map.center), - bearing: map.heading ?? 0, - tilt: map.tilt ?? 0, + bearing: map.heading?.toDouble() ?? 0, + tilt: map.tilt?.toDouble() ?? 0, zoom: map.zoom?.toDouble() ?? 10, ); } @@ -252,9 +178,9 @@ CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { // TODO: Move to their appropriate objects, maybe make these copy constructors: // Marker.fromMarker(anotherMarker, moreOptions); -gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { - if ((marker.infoWindow?.title?.isEmpty ?? true) && - (marker.infoWindow?.snippet?.isEmpty ?? true)) { +gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { + if ((marker.infoWindow.title?.isEmpty ?? true) && + (marker.infoWindow.snippet?.isEmpty ?? true)) { return null; } @@ -265,14 +191,14 @@ gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { if (marker.infoWindow.title?.isNotEmpty ?? false) { final HtmlElement title = HeadingElement.h3() ..className = 'infowindow-title' - ..innerText = marker.infoWindow.title; + ..innerText = marker.infoWindow.title!; container.children.add(title); } if (marker.infoWindow.snippet?.isNotEmpty ?? false) { final HtmlElement snippet = DivElement() ..className = 'infowindow-snippet' ..setInnerHtml( - sanitizeHtml(marker.infoWindow.snippet), + sanitizeHtml(marker.infoWindow.snippet!), treeSanitizer: NodeTreeSanitizer.trusted, ); container.children.add(snippet); @@ -290,10 +216,10 @@ gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { // Preserves the position from the [currentMarker], if set. gmaps.MarkerOptions _markerOptionsFromMarker( Marker marker, - gmaps.Marker currentMarker, + gmaps.Marker? currentMarker, ) { - final iconConfig = marker.icon?.toJson() as List; - gmaps.Icon icon; + final iconConfig = marker.icon.toJson() as List; + gmaps.Icon? icon; if (iconConfig != null) { if (iconConfig[0] == 'fromAssetImage') { @@ -324,7 +250,7 @@ gmaps.MarkerOptions _markerOptionsFromMarker( marker.position.latitude, marker.position.longitude, ) - ..title = sanitizeHtml(marker.infoWindow?.title ?? "") + ..title = sanitizeHtml(marker.infoWindow.title ?? "") ..zIndex = marker.zIndex ..visible = marker.visible ..opacity = marker.alpha @@ -351,14 +277,14 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( gmaps.GMap googleMap, Polygon polygon) { List path = []; polygon.points.forEach((point) { - path.add(_latLngToGmLatLng(point)); + path.add(_latLngToGmLatLng(point)!); }); final polygonDirection = _isPolygonClockwise(path); List> paths = [path]; int holeIndex = 0; - polygon.holes?.forEach((hole) { + polygon.holes.forEach((hole) { List holePath = - hole.map((point) => _latLngToGmLatLng(point)).toList(); + hole.map((point) => _latLngToGmLatLng(point)!).toList(); if (_isPolygonClockwise(holePath) == polygonDirection) { holePath = holePath.reversed.toList(); if (kDebugMode) { @@ -391,8 +317,8 @@ bool _isPolygonClockwise(List path) { var direction = 0.0; for (var i = 0; i < path.length; i++) { direction = direction + - ((path[(i + 1) % path.length].lat - path[i].lat) * - (path[(i + 1) % path.length].lng + path[i].lng)); + ((path[(i + 1) % path.length].lat! - path[i].lat!) * + (path[(i + 1) % path.length].lng! + path[i].lng!)); } return direction >= 0; } @@ -401,7 +327,7 @@ gmaps.PolylineOptions _polylineOptionsFromPolyline( gmaps.GMap googleMap, Polyline polyline) { List paths = []; polyline.points.forEach((point) { - paths.add(_latLngToGmLatLng(point)); + paths.add(_latLngToGmLatLng(point)!); }); return gmaps.PolylineOptions() @@ -447,7 +373,7 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { map.panBy(json[1], json[2]); break; case 'zoomBy': - gmaps.LatLng focusLatLng; + gmaps.LatLng? focusLatLng; double zoomDelta = json[1] ?? 0; // Web only supports integer changes... int newZoomDelta = zoomDelta < 0 ? zoomDelta.floor() : zoomDelta.ceil(); @@ -460,16 +386,16 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // print('Error computing new focus LatLng. JS Error: ' + e.toString()); } } - map.zoom = map.zoom + newZoomDelta; + map.zoom = map.zoom! + newZoomDelta; if (focusLatLng != null) { map.panTo(focusLatLng); } break; case 'zoomIn': - map.zoom++; + map.zoom = map.zoom! + 1; break; case 'zoomOut': - map.zoom--; + map.zoom = map.zoom! - 1; break; case 'zoomTo': map.zoom = json[1]; @@ -481,17 +407,17 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // original JS by: Byron Singh (https://stackoverflow.com/a/30541162) gmaps.LatLng _pixelToLatLng(gmaps.GMap map, int x, int y) { - final ne = map.bounds.northEast; - final sw = map.bounds.southWest; - final projection = map.projection; + final ne = map.bounds!.northEast; + final sw = map.bounds!.southWest; + final projection = map.projection!; - final topRight = projection.fromLatLngToPoint(ne); - final bottomLeft = projection.fromLatLngToPoint(sw); + final topRight = projection.fromLatLngToPoint!(ne)!; + final bottomLeft = projection.fromLatLngToPoint!(sw)!; - final scale = 1 << map.zoom; // 2 ^ zoom + final scale = 1 << (map.zoom! as int); // 2 ^ zoom final point = - gmaps.Point((x / scale) + bottomLeft.x, (y / scale) + topRight.y); + gmaps.Point((x / scale) + bottomLeft.x!, (y / scale) + topRight.y!); - return projection.fromPointToLatLng(point); + return projection.fromPointToLatLng!(point)!; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index cc8d79a6226d..180f66d10c56 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -27,8 +27,8 @@ class GoogleMapController { String _getViewType(int mapId) => 'plugins.flutter.io/google_maps_$mapId'; // The Flutter widget that contains the rendered Map. - HtmlElementView _widget; - HtmlElement _div; + HtmlElementView? _widget; + late HtmlElement _div; /// The Flutter widget that will contain the rendered Map. Used for caching. HtmlElementView get widget { @@ -37,18 +37,18 @@ class GoogleMapController { viewType: _getViewType(_mapId), ); } - return _widget; + return _widget!; } // The currently-enabled traffic layer. - gmaps.TrafficLayer _trafficLayer; + gmaps.TrafficLayer? _trafficLayer; /// A getter for the current traffic layer. Only for tests. @visibleForTesting - gmaps.TrafficLayer get trafficLayer => _trafficLayer; + gmaps.TrafficLayer? get trafficLayer => _trafficLayer; // The underlying GMap instance. This is the interface with the JS SDK. - gmaps.GMap _googleMap; + gmaps.GMap? _googleMap; // The StreamController used by this controller and the geometry ones. final StreamController _streamController; @@ -57,10 +57,10 @@ class GoogleMapController { Stream get events => _streamController.stream; // Geometry controllers, for different features of the map. - CirclesController _circlesController; - PolygonsController _polygonsController; - PolylinesController _polylinesController; - MarkersController _markersController; + CirclesController? _circlesController; + PolygonsController? _polygonsController; + PolylinesController? _polylinesController; + MarkersController? _markersController; // Keeps track if _attachGeometryControllers has been called or not. bool _controllersBoundToMap = false; @@ -69,9 +69,9 @@ class GoogleMapController { /// Initializes the GMap, and the sub-controllers related to it. Wires events. GoogleMapController({ - @required int mapId, - @required StreamController streamController, - @required CameraPosition initialCameraPosition, + required int mapId, + required StreamController streamController, + required CameraPosition initialCameraPosition, Set markers = const {}, Set polygons = const {}, Set polylines = const {}, @@ -107,11 +107,11 @@ class GoogleMapController { /// Overrides certain properties to install mocks defined during testing. @visibleForTesting void debugSetOverrides({ - DebugCreateMapFunction createMap, - MarkersController markers, - CirclesController circles, - PolygonsController polygons, - PolylinesController polylines, + DebugCreateMapFunction? createMap, + MarkersController? markers, + CirclesController? circles, + PolygonsController? polygons, + PolylinesController? polylines, }) { _overrideCreateMap = createMap; _markersController = markers ?? _markersController; @@ -120,11 +120,11 @@ class GoogleMapController { _polylinesController = polylines ?? _polylinesController; } - DebugCreateMapFunction _overrideCreateMap; + DebugCreateMapFunction? _overrideCreateMap; gmaps.GMap _createMap(HtmlElement div, gmaps.MapOptions options) { if (_overrideCreateMap != null) { - return _overrideCreateMap(div, options); + return _overrideCreateMap!(div, options); } return gmaps.GMap(div, options); } @@ -144,8 +144,8 @@ class GoogleMapController { // Create the map... _googleMap = _createMap(_div, options); - _attachMapEvents(_googleMap); - _attachGeometryControllers(_googleMap); + _attachMapEvents(_googleMap!); + _attachGeometryControllers(_googleMap!); _renderInitialGeometry( markers: _markers, @@ -154,19 +154,19 @@ class GoogleMapController { polylines: _polylines, ); - _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(_rawMapOptions)); + _setTrafficLayer(_googleMap!, _isTrafficLayerEnabled(_rawMapOptions)); } // Funnels map gmap events into the plugin's stream controller. void _attachMapEvents(gmaps.GMap map) { map.onClick.listen((event) { _streamController.add( - MapTapEvent(_mapId, _gmLatLngToLatLng(event.latLng)), + MapTapEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); }); map.onRightclick.listen((event) { _streamController.add( - MapLongPressEvent(_mapId, _gmLatLngToLatLng(event.latLng)), + MapLongPressEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); }); map.onBoundsChanged.listen((event) { @@ -188,28 +188,28 @@ class GoogleMapController { void _attachGeometryControllers(gmaps.GMap map) { // Now we can add the initial geometry. // And bind the (ready) map instance to the other geometry controllers. - _circlesController.bindToMap(_mapId, map); - _polygonsController.bindToMap(_mapId, map); - _polylinesController.bindToMap(_mapId, map); - _markersController.bindToMap(_mapId, map); + _circlesController!.bindToMap(_mapId, map); + _polygonsController!.bindToMap(_mapId, map); + _polylinesController!.bindToMap(_mapId, map); + _markersController!.bindToMap(_mapId, map); _controllersBoundToMap = true; } // Renders the initial sets of geometry. void _renderInitialGeometry({ - Set markers, - Set circles, - Set polygons, - Set polylines, + Set markers = const {}, + Set circles = const {}, + Set polygons = const {}, + Set polylines = const {}, }) { assert( _controllersBoundToMap, 'Geometry controllers must be bound to a map before any geometry can ' + 'be added to them. Ensure _attachGeometryControllers is called first.'); - _markersController.addMarkers(markers); - _circlesController.addCircles(circles); - _polygonsController.addPolygons(polygons); - _polylinesController.addPolylines(polylines); + _markersController!.addMarkers(markers); + _circlesController!.addCircles(circles); + _polygonsController!.addPolygons(polygons); + _polylinesController!.addPolylines(polylines); } // Merges new options coming from the plugin into the _rawMapOptions map. @@ -230,7 +230,7 @@ class GoogleMapController { final newOptions = _mergeRawOptions(optionsUpdate); _setOptions(_rawOptionsToGmapsOptions(newOptions)); - _setTrafficLayer(_googleMap, _isTrafficLayerEnabled(newOptions)); + _setTrafficLayer(_googleMap!, _isTrafficLayerEnabled(newOptions)); } // Sets new [gmaps.MapOptions] on the wrapped map. @@ -242,10 +242,10 @@ class GoogleMapController { void _setTrafficLayer(gmaps.GMap map, bool attach) { if (attach && _trafficLayer == null) { _trafficLayer = gmaps.TrafficLayer(); - _trafficLayer.set('map', map); + _trafficLayer!.set('map', map); } if (!attach && _trafficLayer != null) { - _trafficLayer.set('map', null); + _trafficLayer!.set('map', null); _trafficLayer = null; } } @@ -255,30 +255,30 @@ class GoogleMapController { /// Returns the [LatLngBounds] of the current viewport. Future getVisibleRegion() async { - return _gmLatLngBoundsTolatLngBounds(await _googleMap.bounds); + return _gmLatLngBoundsTolatLngBounds(await _googleMap!.bounds); } /// Returns the [ScreenCoordinate] for a given viewport [LatLng]. Future getScreenCoordinate(LatLng latLng) async { final point = - _googleMap.projection.fromLatLngToPoint(_latLngToGmLatLng(latLng)); - return ScreenCoordinate(x: point.x, y: point.y); + _googleMap!.projection!.fromLatLngToPoint!(_latLngToGmLatLng(latLng))!; + return ScreenCoordinate(x: point.x! as int, y: point.y! as int); } /// Returns the [LatLng] for a `screenCoordinate` (in pixels) of the viewport. Future getLatLng(ScreenCoordinate screenCoordinate) async { final gmaps.LatLng latLng = - _pixelToLatLng(_googleMap, screenCoordinate.x, screenCoordinate.y); + _pixelToLatLng(_googleMap!, screenCoordinate.x, screenCoordinate.y); return _gmLatLngToLatLng(latLng); } /// Applies a `cameraUpdate` to the current viewport. Future moveCamera(CameraUpdate cameraUpdate) async { - return _applyCameraUpdate(_googleMap, cameraUpdate); + return _applyCameraUpdate(_googleMap!, cameraUpdate); } /// Returns the zoom level of the current viewport. - Future getZoomLevel() async => _googleMap.zoom.toDouble(); + Future getZoomLevel() async => _googleMap!.zoom!.toDouble(); // Geometry manipulation @@ -322,7 +322,7 @@ class GoogleMapController { /// Returns true if the [InfoWindow] of the marker identified by [MarkerId] is shown. bool isInfoWindowShown(MarkerId markerId) { - return _markersController?.isInfoWindowShown(markerId); + return _markersController?.isInfoWindowShown(markerId) ?? false; } // Cleanup diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index 5e95a538c07a..4c2a784bb9dc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -45,7 +45,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateMapOptions( Map optionsUpdate, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateRawOptions(optionsUpdate); } @@ -54,7 +54,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateMarkers( MarkerUpdates markerUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateMarkers(markerUpdates); } @@ -63,7 +63,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updatePolygons( PolygonUpdates polygonUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updatePolygons(polygonUpdates); } @@ -72,7 +72,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updatePolylines( PolylineUpdates polylineUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updatePolylines(polylineUpdates); } @@ -81,15 +81,15 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future updateCircles( CircleUpdates circleUpdates, { - @required int mapId, + required int mapId, }) async { _map(mapId).updateCircles(circleUpdates); } @override Future updateTileOverlays({ - @required Set newTileOverlays, - @required int mapId, + required Set newTileOverlays, + required int mapId, }) async { return; // Noop for now! } @@ -97,7 +97,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future clearTileCache( TileOverlayId tileOverlayId, { - @required int mapId, + required int mapId, }) async { return; // Noop for now! } @@ -106,7 +106,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future animateCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) async { return moveCamera(cameraUpdate, mapId: mapId); } @@ -115,7 +115,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future moveCamera( CameraUpdate cameraUpdate, { - @required int mapId, + required int mapId, }) async { return _map(mapId).moveCamera(cameraUpdate); } @@ -128,8 +128,8 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// pass full styles. @override Future setMapStyle( - String mapStyle, { - @required int mapId, + String? mapStyle, { + required int mapId, }) async { _map(mapId).updateRawOptions({ 'styles': _mapStyles(mapStyle), @@ -139,7 +139,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// Returns the bounds of the current viewport. @override Future getVisibleRegion({ - @required int mapId, + required int mapId, }) { return _map(mapId).getVisibleRegion(); } @@ -148,7 +148,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future getScreenCoordinate( LatLng latLng, { - @required int mapId, + required int mapId, }) { return _map(mapId).getScreenCoordinate(latLng); } @@ -157,7 +157,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future getLatLng( ScreenCoordinate screenCoordinate, { - @required int mapId, + required int mapId, }) { return _map(mapId).getLatLng(screenCoordinate); } @@ -170,7 +170,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future showMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { _map(mapId).showInfoWindow(markerId); } @@ -183,7 +183,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future hideMarkerInfoWindow( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { _map(mapId).hideInfoWindow(markerId); } @@ -196,7 +196,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { @override Future isMarkerInfoWindowShown( MarkerId markerId, { - @required int mapId, + required int mapId, }) async { return _map(mapId).isInfoWindowShown(markerId); } @@ -204,7 +204,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { /// Returns the zoom level of the `mapId`. @override Future getZoomLevel({ - @required int mapId, + required int mapId, }) { return _map(mapId).getZoomLevel(); } @@ -213,64 +213,64 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { // into the plugin @override - Stream onCameraMoveStarted({@required int mapId}) { + Stream onCameraMoveStarted({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraMove({@required int mapId}) { + Stream onCameraMove({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCameraIdle({@required int mapId}) { + Stream onCameraIdle({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerTap({@required int mapId}) { + Stream onMarkerTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onInfoWindowTap({@required int mapId}) { + Stream onInfoWindowTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onMarkerDragEnd({@required int mapId}) { + Stream onMarkerDragEnd({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolylineTap({@required int mapId}) { + Stream onPolylineTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onPolygonTap({@required int mapId}) { + Stream onPolygonTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onCircleTap({@required int mapId}) { + Stream onCircleTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onTap({@required int mapId}) { + Stream onTap({required int mapId}) { return _events(mapId).whereType(); } @override - Stream onLongPress({@required int mapId}) { + Stream onLongPress({required int mapId}) { return _events(mapId).whereType(); } /// Disposes of the current map. It can't be used afterwards! @override - void dispose({@required int mapId}) { - _map(mapId)?.dispose(); + void dispose({required int mapId}) { + _map(mapId).dispose(); _mapById.remove(mapId); } @@ -278,13 +278,13 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { Widget buildView( int creationId, PlatformViewCreatedCallback onPlatformViewCreated, { - @required CameraPosition initialCameraPosition, + required CameraPosition initialCameraPosition, Set markers = const {}, Set polygons = const {}, Set polylines = const {}, Set circles = const {}, Set tileOverlays = const {}, - Set> gestureRecognizers = + Set>? gestureRecognizers = const >{}, Map mapOptions = const {}, }) { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 62238fc2d86b..3083b33dd2c4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -6,33 +6,33 @@ part of google_maps_flutter_web; /// The `MarkerController` class wraps a [gmaps.Marker], how it handles events, and its associated (optional) [gmaps.InfoWindow] widget. class MarkerController { - gmaps.Marker _marker; + gmaps.Marker? _marker; final bool _consumeTapEvents; - final gmaps.InfoWindow _infoWindow; + final gmaps.InfoWindow? _infoWindow; bool _infoWindowShown = false; /// Creates a `MarkerController`, which wraps a [gmaps.Marker] object, its `onTap`/`onDrag` behavior, and its associated [gmaps.InfoWindow]. MarkerController({ - @required gmaps.Marker marker, - gmaps.InfoWindow infoWindow, + required gmaps.Marker marker, + gmaps.InfoWindow? infoWindow, bool consumeTapEvents = false, - LatLngCallback onDragEnd, - ui.VoidCallback onTap, + LatLngCallback? onDragEnd, + ui.VoidCallback? onTap, }) : _marker = marker, _infoWindow = infoWindow, _consumeTapEvents = consumeTapEvents { if (onTap != null) { - _marker.onClick.listen((event) { + _marker!.onClick.listen((event) { onTap.call(); }); } if (onDragEnd != null) { - _marker.onDragend.listen((event) { - _marker.position = event.latLng; - onDragEnd.call(event.latLng); + _marker!.onDragend.listen((event) { + _marker!.position = event.latLng; + onDragEnd.call(event.latLng!); }); } } @@ -44,34 +44,36 @@ class MarkerController { bool get infoWindowShown => _infoWindowShown; /// Returns the [gmaps.Marker] associated to this controller. - gmaps.Marker get marker => _marker; + gmaps.Marker? get marker => _marker; /// Returns the [gmaps.InfoWindow] associated to the marker. @visibleForTesting - gmaps.InfoWindow get infoWindow => _infoWindow; + gmaps.InfoWindow? get infoWindow => _infoWindow; /// Updates the options of the wrapped [gmaps.Marker] object. void update( gmaps.MarkerOptions options, { - String newInfoWindowContent, + String? newInfoWindowContent, }) { - _marker.options = options; + _marker!.options = options; if (_infoWindow != null && newInfoWindowContent != null) { - _infoWindow.content = newInfoWindowContent; + _infoWindow!.content = newInfoWindowContent; } } /// Disposes of the currently wrapped [gmaps.Marker]. void remove() { - _marker.visible = false; - _marker.map = null; - _marker = null; + if (_marker != null) { + _marker!.visible = false; + _marker!.map = null; + _marker = null; + } } /// Hide the associated [gmaps.InfoWindow]. void hideInfoWindow() { if (_infoWindow != null) { - _infoWindow.close(); + _infoWindow!.close(); _infoWindowShown = false; } } @@ -79,7 +81,7 @@ class MarkerController { /// Show the associated [gmaps.InfoWindow]. void showInfoWindow() { if (_infoWindow != null) { - _infoWindow.open(_marker.map, _marker); + _infoWindow!.open(_marker!.map, _marker); _infoWindowShown = true; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index bc9827a20270..d387fdc8ea7c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -14,7 +14,7 @@ class MarkersController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. MarkersController({ - @required StreamController stream, + required StreamController stream, }) : _streamController = stream, _markerIdToController = Map(); @@ -26,7 +26,7 @@ class MarkersController extends GeometryController { /// /// Wraps each [Marker] into its corresponding [MarkerController]. void addMarkers(Set markersToAdd) { - markersToAdd?.forEach(_addMarker); + markersToAdd.forEach(_addMarker); } void _addMarker(Marker marker) { @@ -35,14 +35,15 @@ class MarkersController extends GeometryController { } final infoWindowOptions = _infoWindowOptionsFromMarker(marker); - gmaps.InfoWindow gmInfoWindow; + gmaps.InfoWindow? gmInfoWindow; if (infoWindowOptions != null) { gmInfoWindow = gmaps.InfoWindow(infoWindowOptions); // Google Maps' JS SDK does not have a click event on the InfoWindow, so // we make one... if (infoWindowOptions.content is HtmlElement) { - infoWindowOptions.content.onClick.listen((_) { + final content = infoWindowOptions as HtmlElement; + content.onClick.listen((_) { _onInfoWindowTap(marker.markerId); }); } @@ -70,11 +71,11 @@ class MarkersController extends GeometryController { /// Updates a set of [Marker] objects with new options. void changeMarkers(Set markersToChange) { - markersToChange?.forEach(_changeMarker); + markersToChange.forEach(_changeMarker); } void _changeMarker(Marker marker) { - MarkerController markerController = _markerIdToController[marker?.markerId]; + MarkerController? markerController = _markerIdToController[marker.markerId]; if (markerController != null) { final markerOptions = _markerOptionsFromMarker( marker, @@ -83,18 +84,18 @@ class MarkersController extends GeometryController { final infoWindow = _infoWindowOptionsFromMarker(marker); markerController.update( markerOptions, - newInfoWindowContent: infoWindow?.content, + newInfoWindowContent: infoWindow?.content as String?, ); } } /// Removes a set of [MarkerId]s from the cache. void removeMarkers(Set markerIdsToRemove) { - markerIdsToRemove?.forEach(_removeMarker); + markerIdsToRemove.forEach(_removeMarker); } void _removeMarker(MarkerId markerId) { - final MarkerController markerController = _markerIdToController[markerId]; + final MarkerController? markerController = _markerIdToController[markerId]; markerController?.remove(); _markerIdToController.remove(markerId); } @@ -106,7 +107,7 @@ class MarkersController extends GeometryController { /// See also [hideMarkerInfoWindow] and [isInfoWindowShown]. void showMarkerInfoWindow(MarkerId markerId) { _hideAllMarkerInfoWindow(); - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; markerController?.showInfoWindow(); } @@ -114,7 +115,7 @@ class MarkersController extends GeometryController { /// /// See also [showMarkerInfoWindow] and [isInfoWindowShown]. void hideMarkerInfoWindow(MarkerId markerId) { - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; markerController?.hideInfoWindow(); } @@ -122,7 +123,7 @@ class MarkersController extends GeometryController { /// /// See also [showMarkerInfoWindow] and [hideMarkerInfoWindow]. bool isInfoWindowShown(MarkerId markerId) { - MarkerController markerController = _markerIdToController[markerId]; + MarkerController? markerController = _markerIdToController[markerId]; return markerController?.infoWindowShown ?? false; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index 4ce1f022e586..ecde641327f7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `PolygonController` class wraps a [gmaps.Polygon] and its `onTap` behavior. class PolygonController { - gmaps.Polygon _polygon; + gmaps.Polygon? _polygon; final bool _consumeTapEvents; /// Creates a `PolygonController` that wraps a [gmaps.Polygon] object and its `onTap` behavior. PolygonController({ - @required gmaps.Polygon polygon, + required gmaps.Polygon polygon, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _polygon = polygon, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,20 +26,22 @@ class PolygonController { /// Returns the wrapped [gmaps.Polygon]. Only used for testing. @visibleForTesting - gmaps.Polygon get polygon => _polygon; + gmaps.Polygon? get polygon => _polygon; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polygon] object. void update(gmaps.PolygonOptions options) { - _polygon.options = options; + _polygon!.options = options; } /// Disposes of the currently wrapped [gmaps.Polygon]. void remove() { - _polygon.visible = false; - _polygon.map = null; - _polygon = null; + if (_polygon != null) { + _polygon!.visible = false; + _polygon!.map = null; + _polygon = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index 4671e6d77a87..8a9643156351 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -14,7 +14,7 @@ class PolygonsController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolygonsController({ - @required StreamController stream, + required StreamController stream, }) : _streamController = stream, _polygonIdToController = Map(); @@ -60,15 +60,15 @@ class PolygonsController extends GeometryController { } void _changePolygon(Polygon polygon) { - PolygonController polygonController = - _polygonIdToController[polygon?.polygonId]; + PolygonController? polygonController = + _polygonIdToController[polygon.polygonId]; polygonController?.update(_polygonOptionsFromPolygon(googleMap, polygon)); } /// Removes a set of [PolygonId]s from the cache. void removePolygons(Set polygonIdsToRemove) { - polygonIdsToRemove?.forEach((polygonId) { - final PolygonController polygonController = + polygonIdsToRemove.forEach((polygonId) { + final PolygonController? polygonController = _polygonIdToController[polygonId]; polygonController?.remove(); _polygonIdToController.remove(polygonId); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index bf1dbb222555..c5dc0fafa812 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -6,15 +6,15 @@ part of google_maps_flutter_web; /// The `PolygonController` class wraps a [gmaps.Polyline] and its `onTap` behavior. class PolylineController { - gmaps.Polyline _polyline; + gmaps.Polyline? _polyline; final bool _consumeTapEvents; /// Creates a `PolylineController` that wraps a [gmaps.Polyline] object and its `onTap` behavior. PolylineController({ - @required gmaps.Polyline polyline, + required gmaps.Polyline polyline, bool consumeTapEvents = false, - ui.VoidCallback onTap, + ui.VoidCallback? onTap, }) : _polyline = polyline, _consumeTapEvents = consumeTapEvents { if (onTap != null) { @@ -26,20 +26,22 @@ class PolylineController { /// Returns the wrapped [gmaps.Polyline]. Only used for testing. @visibleForTesting - gmaps.Polyline get line => _polyline; + gmaps.Polyline? get line => _polyline; /// Returns `true` if this Controller will use its own `onTap` handler to consume events. bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polyline] object. void update(gmaps.PolylineOptions options) { - _polyline.options = options; + _polyline?.options = options; } /// Disposes of the currently wrapped [gmaps.Polyline]. void remove() { - _polyline.visible = false; - _polyline.map = null; - _polyline = null; + if (_polyline != null) { + _polyline!.visible = false; + _polyline!.map = null; + _polyline = null; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index e91b82fd1947..695b29554c04 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -14,7 +14,7 @@ class PolylinesController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolylinesController({ - @required StreamController stream, + required StreamController stream, }) : _streamController = stream, _polylineIdToController = Map(); @@ -26,7 +26,7 @@ class PolylinesController extends GeometryController { /// /// Wraps each line into its corresponding [PolylineController]. void addPolylines(Set polylinesToAdd) { - polylinesToAdd?.forEach((polyline) { + polylinesToAdd.forEach((polyline) { _addPolyline(polyline); }); } @@ -50,22 +50,22 @@ class PolylinesController extends GeometryController { /// Updates a set of [Polyline] objects with new options. void changePolylines(Set polylinesToChange) { - polylinesToChange?.forEach((polylineToChange) { + polylinesToChange.forEach((polylineToChange) { _changePolyline(polylineToChange); }); } void _changePolyline(Polyline polyline) { - PolylineController polylineController = - _polylineIdToController[polyline?.polylineId]; + PolylineController? polylineController = + _polylineIdToController[polyline.polylineId]; polylineController ?.update(_polylineOptionsFromPolyline(googleMap, polyline)); } /// Removes a set of [PolylineId]s from the cache. void removePolylines(Set polylineIdsToRemove) { - polylineIdsToRemove?.forEach((polylineId) { - final PolylineController polylineController = + polylineIdsToRemove.forEach((polylineId) { + final PolylineController? polylineController = _polylineIdToController[polylineId]; polylineController?.remove(); _polylineIdToController.remove(polylineId); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart index 10b5199a894e..ff980eb4c34b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/types.dart @@ -17,10 +17,10 @@ typedef LatLngCallback = void Function(gmaps.LatLng latLng); /// instance and our internal `mapId` value. abstract class GeometryController { /// The GMap instance that this controller operates on. - gmaps.GMap googleMap; + late gmaps.GMap googleMap; /// The map ID for events. - int mapId; + late int mapId; /// Binds a `mapId` and the [gmaps.GMap] instance to this controller. void bindToMap(int mapId, gmaps.GMap googleMap) { From 4d17954424f24550fa9c33919a4bc1351a0537d8 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 11 Mar 2021 16:36:12 -0800 Subject: [PATCH 03/30] Fix _mapStyles in convert.dart. dartfmt -w . --- .../lib/google_maps_flutter_web.dart | 1 + .../lib/src/circles.dart | 5 ++-- .../lib/src/convert.dart | 25 +++++++++++-------- .../lib/src/markers.dart | 2 +- .../lib/src/polygons.dart | 2 +- .../lib/src/polylines.dart | 2 +- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart index 0aa563ccb889..6dc2dab572a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/google_maps_flutter_web.dart @@ -6,6 +6,7 @@ library google_maps_flutter_web; import 'dart:async'; import 'dart:html'; +import 'dart:js_util'; import 'src/shims/dart_ui.dart' as ui; // Conditionally imports dart:ui in web import 'dart:convert'; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart index 6608ed09ba64..2a19d87adfec 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circles.dart @@ -15,7 +15,7 @@ class CirclesController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. CirclesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _circleIdToController = Map(); /// Returns the cache of [CircleController]s. Test only. @@ -63,7 +63,8 @@ class CirclesController extends GeometryController { /// Removes a set of [CircleId]s from the cache. void removeCircles(Set circleIdsToRemove) { circleIdsToRemove.forEach((circleId) { - final CircleController? circleController = _circleIdToController[circleId]; + final CircleController? circleController = + _circleIdToController[circleId]; circleController?.remove(); _circleIdToController.remove(circleId); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 45cb8a29a014..33fc12009af8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -128,18 +128,23 @@ bool _isJsonMapStyle(Map value) { } // Converts an incoming JSON-encoded Style info, into the correct gmaps array. -List _mapStyles(String? mapStyleJson) { +List _mapStyles(String? mapStyleJson) { List styles = []; if (mapStyleJson != null) { - styles = json.decode(mapStyleJson, reviver: (key, value) { - if (value is Map && _isJsonMapStyle(value)) { - return gmaps.MapTypeStyle() - ..elementType = value['elementType'] - ..featureType = value['featureType'] - ..stylers = value['stylers']; - } - return value; - }).cast(); + styles = json + .decode(mapStyleJson, reviver: (key, value) { + if (value is Map && _isJsonMapStyle(value)) { + return gmaps.MapTypeStyle() + ..elementType = value['elementType'] + ..featureType = value['featureType'] + ..stylers = + (value['stylers'] as List).map((e) => jsify(e)).toList(); + } + return value; + }) + .cast() + .toList(); + // .toList calls are required so the JS API understands the underlying data structure. } return styles; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index d387fdc8ea7c..7538633bdc40 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -15,7 +15,7 @@ class MarkersController extends GeometryController { /// Initialize the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. MarkersController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _markerIdToController = Map(); /// Returns the cache of [MarkerController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart index 8a9643156351..ef51bd6043df 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygons.dart @@ -15,7 +15,7 @@ class PolygonsController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolygonsController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polygonIdToController = Map(); /// Returns the cache of [PolygonController]s. Test only. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart index 695b29554c04..184c0d954744 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polylines.dart @@ -15,7 +15,7 @@ class PolylinesController extends GeometryController { /// Initializes the cache. The [StreamController] comes from the [GoogleMapController], and is shared with other controllers. PolylinesController({ required StreamController stream, - }) : _streamController = stream, + }) : _streamController = stream, _polylineIdToController = Map(); /// Returns the cache of [PolylineContrller]s. Test only. From 9bf65e214302e51fe4f9166b841f2951e3301bee Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Mon, 15 Mar 2021 15:21:12 -0700 Subject: [PATCH 04/30] Fix infoWindow content with the correct HtmlElement type. --- .../google_maps_flutter_web/lib/src/marker.dart | 2 +- .../google_maps_flutter_web/lib/src/markers.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 3083b33dd2c4..5e55562cf1ef 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -53,7 +53,7 @@ class MarkerController { /// Updates the options of the wrapped [gmaps.Marker] object. void update( gmaps.MarkerOptions options, { - String? newInfoWindowContent, + HtmlElement? newInfoWindowContent, }) { _marker!.options = options; if (_infoWindow != null && newInfoWindowContent != null) { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart index 7538633bdc40..704577b6e3fb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/markers.dart @@ -42,7 +42,7 @@ class MarkersController extends GeometryController { // Google Maps' JS SDK does not have a click event on the InfoWindow, so // we make one... if (infoWindowOptions.content is HtmlElement) { - final content = infoWindowOptions as HtmlElement; + final content = infoWindowOptions.content as HtmlElement; content.onClick.listen((_) { _onInfoWindowTap(marker.markerId); }); @@ -84,7 +84,7 @@ class MarkersController extends GeometryController { final infoWindow = _infoWindowOptionsFromMarker(marker); markerController.update( markerOptions, - newInfoWindowContent: infoWindow?.content as String?, + newInfoWindowContent: infoWindow?.content as HtmlElement?, ); } } From b192b45dba9c4273a0d3f30273ce7a14e40f4f59 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 15:29:17 -0700 Subject: [PATCH 05/30] Migrate marker_test.dart --- .../example/integration_test/marker_test.dart | 79 ++++++++++--------- .../example/pubspec.yaml | 1 - .../example/web/index.html | 1 - 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index 1a85f3bb28e1..d634576ea8d5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -2,99 +2,104 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:html' as html; import 'package:integration_test/integration_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -class _MockMarker extends Mock implements gmaps.Marker { - final onClickController = StreamController(); - final onDragEndController = StreamController(); - - @override - Stream get onClick => onClickController.stream; - - @override - Stream get onDragend => onDragEndController.stream; -} - -class _MockMouseEvent extends Mock implements gmaps.MouseEvent {} - -class _MockInfoWindow extends Mock implements gmaps.InfoWindow {} /// Test Markers void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - bool called = false; + late Completer _called; + late Future called; + void onTap() { - called = true; + _called.complete(true); } void onDragEnd(gmaps.LatLng _) { - called = true; + _called.complete(true); } setUp(() { - called = false; + _called = Completer(); + called = _called.future; }); group('MarkerController', () { - _MockMarker marker; + late gmaps.Marker marker; setUp(() { - marker = _MockMarker(); + marker = gmaps.Marker(); }); testWidgets('onTap gets called', (WidgetTester tester) async { MarkerController(marker: marker, onTap: onTap); - // Simulate a click - await marker.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(marker, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await called, isTrue); }); testWidgets('onDragEnd gets called', (WidgetTester tester) async { - when(marker.draggable).thenReturn(true); MarkerController(marker: marker, onDragEnd: onDragEnd); - // Simulate a drag end - await marker.onDragEndController.add(_MockMouseEvent()); - expect(called, isTrue); + + // Trigger a drag end event... + gmaps.Event.trigger(marker, 'dragend', + [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + + expect(await called, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = MarkerController(marker: marker); - final options = gmaps.MarkerOptions()..draggable = false; + final options = gmaps.MarkerOptions()..draggable = true; + + expect(marker.draggable, isNull); + controller.update(options); - verify(marker.options = options); + + expect(marker.draggable, isTrue); }); testWidgets('infoWindow null, showInfoWindow.', (WidgetTester tester) async { final controller = MarkerController(marker: marker); + controller.showInfoWindow(); + expect(controller.infoWindowShown, isFalse); }); testWidgets('showInfoWindow', (WidgetTester tester) async { - final infoWindow = _MockInfoWindow(); + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); final controller = MarkerController(marker: marker, infoWindow: infoWindow); + controller.showInfoWindow(); - verify(infoWindow.open(any, any)).called(1); + + expect(infoWindow.get('map'), map); expect(controller.infoWindowShown, isTrue); }); testWidgets('hideInfoWindow', (WidgetTester tester) async { - final infoWindow = _MockInfoWindow(); + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); final controller = MarkerController(marker: marker, infoWindow: infoWindow); + controller.hideInfoWindow(); - verify(infoWindow.close()).called(1); + + expect(infoWindow.get('map'), isNull); expect(controller.infoWindowShown, isFalse); }); }); 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 fc7df3a12cf4..d2f3116dc3d7 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 @@ -14,7 +14,6 @@ dependencies: dev_dependencies: google_maps: ^5.0.1 http: ^0.13.0 - mockito: ^5.0.0 # Update to ^5.0.0 as soon as this migrates to null-safety flutter_driver: sdk: flutter flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html index f324d1c7538f..3121d189b913 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/web/index.html @@ -12,4 +12,3 @@ - From 567afa2e4fd1ae1adbc8da12b93e4af47bc0bdee Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 15:52:08 -0700 Subject: [PATCH 06/30] Migrate shape_test.dart --- .../example/integration_test/shape_test.dart | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index 0c351971af7c..f87a2d947550 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -2,114 +2,113 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'package:integration_test/integration_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mockito/mockito.dart'; - -class _MockCircle extends Mock implements gmaps.Circle { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} - -class _MockPolygon extends Mock implements gmaps.Polygon { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} - -class _MockPolyline extends Mock implements gmaps.Polyline { - final onClickController = StreamController(); - @override - Stream get onClick => onClickController.stream; -} /// Test Shapes (Circle, Polygon, Polyline) void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - bool called = false; + late Completer _called; + late Future called; void onTap() { - called = true; + _called.complete(true); } setUp(() { - called = false; + _called = Completer(); + called = _called.future; }); group('CircleController', () { - _MockCircle circle; + late gmaps.Circle circle; setUp(() { - circle = _MockCircle(); + circle = gmaps.Circle(); }); testWidgets('onTap gets called', (WidgetTester tester) async { CircleController(circle: circle, consumeTapEvents: true, onTap: onTap); - expect(circle.onClickController.hasListener, isTrue); - // Simulate a click - await circle.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(circle, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await called, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = CircleController(circle: circle); - final options = gmaps.CircleOptions()..draggable = false; + final options = gmaps.CircleOptions()..draggable = true; + + expect(circle.draggable, isNull); + controller.update(options); - verify(circle.options = options); + + expect(circle.draggable, isTrue); }); }); group('PolygonController', () { - _MockPolygon polygon; + late gmaps.Polygon polygon; setUp(() { - polygon = _MockPolygon(); + polygon = gmaps.Polygon(); }); testWidgets('onTap gets called', (WidgetTester tester) async { PolygonController(polygon: polygon, consumeTapEvents: true, onTap: onTap); - expect(polygon.onClickController.hasListener, isTrue); - // Simulate a click - await polygon.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(polygon, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await called, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = PolygonController(polygon: polygon); - final options = gmaps.PolygonOptions()..draggable = false; + final options = gmaps.PolygonOptions()..draggable = true; + + expect(polygon.draggable, isNull); + controller.update(options); - verify(polygon.options = options); + + expect(polygon.draggable, isTrue); }); }); group('PolylineController', () { - _MockPolyline polyline; + late gmaps.Polyline polyline; setUp(() { - polyline = _MockPolyline(); + polyline = gmaps.Polyline(); }); testWidgets('onTap gets called', (WidgetTester tester) async { PolylineController( polyline: polyline, consumeTapEvents: true, onTap: onTap); - expect(polyline.onClickController.hasListener, isTrue); - // Simulate a click - await polyline.onClickController.add(null); - expect(called, isTrue); + + // Trigger a click event... + gmaps.Event.trigger(polyline, 'click', [gmaps.MapMouseEvent()]); + + // The event handling is now truly async. Wait for it... + expect(await called, isTrue); }); testWidgets('update', (WidgetTester tester) async { final controller = PolylineController(polyline: polyline); - final options = gmaps.PolylineOptions()..draggable = false; + final options = gmaps.PolylineOptions()..draggable = true; + + expect(polyline.draggable, isNull); + controller.update(options); - verify(polyline.options = options); + + expect(polyline.draggable, isTrue); }); }); } From 8928c232d8d7ddf948d0aa22cd9b733648b097eb Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 17:23:21 -0700 Subject: [PATCH 07/30] Migrate markers_test.dart --- .../integration_test/markers_test.dart | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index e9e458c85685..55f932ae8ee9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'dart:convert'; -import 'dart:html'; +import 'dart:html' as html; +import 'dart:js_util' show getProperty; -import 'package:http/http.dart' as http; -import 'package:integration_test/integration_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:http/http.dart' as http; +import 'package:integration_test/integration_test.dart'; import 'resources/icon_image_base64.dart'; @@ -20,12 +20,15 @@ void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('MarkersController', () { - StreamController stream; - MarkersController controller; + late StreamController events; + late MarkersController controller; + late gmaps.GMap map; setUp(() { - stream = StreamController(); - controller = MarkersController(stream: stream); + events = StreamController(); + controller = MarkersController(stream: events); + map = gmaps.GMap(html.DivElement()); + controller.bindToMap(123, map); }); testWidgets('addMarkers', (WidgetTester tester) async { @@ -48,7 +51,7 @@ void main() { }; controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].marker.draggable, isFalse); + expect(controller.markers[MarkerId('1')]?.marker?.draggable, isFalse); // Update the marker with radius 10 final updatedMarkers = { @@ -57,7 +60,7 @@ void main() { controller.changeMarkers(updatedMarkers); expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.draggable, isTrue); + expect(controller.markers[MarkerId('1')]?.marker?.draggable, isTrue); }); testWidgets('removeMarkers', (WidgetTester tester) async { @@ -95,15 +98,15 @@ void main() { controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isTrue); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isTrue); controller.hideMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); }); // https://github.com/flutter/flutter/issues/67380 @@ -121,30 +124,23 @@ void main() { }; controller.addMarkers(markers); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); - expect(controller.markers[MarkerId('2')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('1')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isTrue); - expect(controller.markers[MarkerId('2')].infoWindowShown, isFalse); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isTrue); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isFalse); controller.showMarkerInfoWindow(MarkerId('2')); - expect(controller.markers[MarkerId('1')].infoWindowShown, isFalse); - expect(controller.markers[MarkerId('2')].infoWindowShown, isTrue); + expect(controller.markers[MarkerId('1')]?.infoWindowShown, isFalse); + expect(controller.markers[MarkerId('2')]?.infoWindowShown, isTrue); }); // https://github.com/flutter/flutter/issues/64938 testWidgets('markers with icon:null work', (WidgetTester tester) async { - final markers = { - Marker(markerId: MarkerId('1'), icon: null), - }; - - controller.addMarkers(markers); - - expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.icon, isNull); + // The argument type 'Null' can't be assigned to the parameter type 'BitmapDescriptor'. }); // @@ -159,11 +155,15 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.icon, isNotNull); - expect(controller.markers[MarkerId('1')].marker.icon.url, - startsWith('blob:')); + expect(controller.markers[MarkerId('1')]?.marker?.icon, isNotNull); + + final blobUrl = getProperty( + controller.markers[MarkerId('1')]!.marker!.icon!, + 'url', + ); + + expect(blobUrl, startsWith('blob:')); - final blobUrl = controller.markers[MarkerId('1')].marker.icon.url; final response = await http.get(Uri.parse(blobUrl)); expect(response.bodyBytes, bytes, @@ -187,8 +187,8 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - final content = - controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + final content = controller.markers[MarkerId('1')]?.infoWindow?.content + as html.HtmlElement; expect(content.innerHtml, contains('title for test')); expect( content.innerHtml, @@ -211,12 +211,12 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - final content = - controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + final content = controller.markers[MarkerId('1')]?.infoWindow?.content + as html.HtmlElement; content.click(); - final event = await stream.stream.first; + final event = await events.stream.first; expect(event, isA()); expect((event as InfoWindowTapEvent).value, equals(MarkerId('1'))); From ab6653b85f98737cf4ac1d8e2dcb85d8ee7734c1 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 17:44:17 -0700 Subject: [PATCH 08/30] Migrate shapes_test.dart --- .../example/integration_test/shapes_test.dart | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart index 9bb3599311d2..80b4e0823bb5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shapes_test.dart @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; import 'dart:ui'; +import 'dart:html' as html; import 'package:integration_test/integration_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -23,13 +22,20 @@ const _acceptableDelta = 0.01; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + late gmaps.GMap map; + + setUp(() { + map = gmaps.GMap(html.DivElement()); + }); + group('CirclesController', () { - StreamController stream; - CirclesController controller; + late StreamController events; + late CirclesController controller; setUp(() { - stream = StreamController(); - controller = CirclesController(stream: stream); + events = StreamController(); + controller = CirclesController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addCircles', (WidgetTester tester) async { @@ -52,7 +58,7 @@ void main() { }; controller.addCircles(circles); - expect(controller.circles[CircleId('1')].circle.visible, isTrue); + expect(controller.circles[CircleId('1')]?.circle?.visible, isTrue); final updatedCircles = { Circle(circleId: CircleId('1'), visible: false), @@ -60,7 +66,7 @@ void main() { controller.changeCircles(updatedCircles); expect(controller.circles.length, 1); - expect(controller.circles[CircleId('1')].circle.visible, isFalse); + expect(controller.circles[CircleId('1')]?.circle?.visible, isFalse); }); testWidgets('removeCircles', (WidgetTester tester) async { @@ -99,7 +105,7 @@ void main() { controller.addCircles(circles); - final circle = controller.circles.values.first.circle; + final circle = controller.circles.values.first.circle!; expect(circle.get('fillColor'), '#fabada'); expect(circle.get('fillOpacity'), closeTo(0.5, _acceptableDelta)); @@ -109,12 +115,13 @@ void main() { }); group('PolygonsController', () { - StreamController stream; - PolygonsController controller; + late StreamController events; + late PolygonsController controller; setUp(() { - stream = StreamController(); - controller = PolygonsController(stream: stream); + events = StreamController(); + controller = PolygonsController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addPolygons', (WidgetTester tester) async { @@ -137,7 +144,7 @@ void main() { }; controller.addPolygons(polygons); - expect(controller.polygons[PolygonId('1')].polygon.visible, isTrue); + expect(controller.polygons[PolygonId('1')]?.polygon?.visible, isTrue); // Update the polygon final updatedPolygons = { @@ -146,7 +153,7 @@ void main() { controller.changePolygons(updatedPolygons); expect(controller.polygons.length, 1); - expect(controller.polygons[PolygonId('1')].polygon.visible, isFalse); + expect(controller.polygons[PolygonId('1')]?.polygon?.visible, isFalse); }); testWidgets('removePolygons', (WidgetTester tester) async { @@ -185,7 +192,7 @@ void main() { controller.addPolygons(polygons); - final polygon = controller.polygons.values.first.polygon; + final polygon = controller.polygons.values.first.polygon!; expect(polygon.get('fillColor'), '#fabada'); expect(polygon.get('fillOpacity'), closeTo(0.5, _acceptableDelta)); @@ -243,7 +250,7 @@ void main() { final polygon = controller.polygons.values.first.polygon; final pointInHole = gmaps.LatLng(28.632, -68.401); - expect(geometry.poly.containsLocation(pointInHole, polygon), false); + expect(geometry.Poly.containsLocation(pointInHole, polygon), false); }); testWidgets('Hole Path gets reversed to display correctly', @@ -268,25 +275,22 @@ void main() { controller.addPolygons(polygons); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(0).lat, - 28.745); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(1).lat, - 29.57); - expect( - controller.polygons.values.first.polygon.paths.getAt(1).getAt(2).lat, - 27.339); + final paths = controller.polygons.values.first.polygon!.paths!; + + expect(paths.getAt(1)?.getAt(0)?.lat, 28.745); + expect(paths.getAt(1)?.getAt(1)?.lat, 29.57); + expect(paths.getAt(1)?.getAt(2)?.lat, 27.339); }); }); group('PolylinesController', () { - StreamController stream; - PolylinesController controller; + late StreamController events; + late PolylinesController controller; setUp(() { - stream = StreamController(); - controller = PolylinesController(stream: stream); + events = StreamController(); + controller = PolylinesController(stream: events); + controller.bindToMap(123, map); }); testWidgets('addPolylines', (WidgetTester tester) async { @@ -309,7 +313,7 @@ void main() { }; controller.addPolylines(polylines); - expect(controller.lines[PolylineId('1')].line.visible, isTrue); + expect(controller.lines[PolylineId('1')]?.line?.visible, isTrue); final updatedPolylines = { Polyline(polylineId: PolylineId('1'), visible: false), @@ -317,7 +321,7 @@ void main() { controller.changePolylines(updatedPolylines); expect(controller.lines.length, 1); - expect(controller.lines[PolylineId('1')].line.visible, isFalse); + expect(controller.lines[PolylineId('1')]?.line?.visible, isFalse); }); testWidgets('removePolylines', (WidgetTester tester) async { @@ -355,7 +359,7 @@ void main() { controller.addPolylines(lines); - final line = controller.lines.values.first.line; + final line = controller.lines.values.first.line!; expect(line.get('strokeColor'), '#fabada'); expect(line.get('strokeOpacity'), closeTo(0.5, _acceptableDelta)); From ee82b8468d29f71983f8d96349b47ada290567b7 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 19:17:16 -0700 Subject: [PATCH 09/30] Bring back mockito for google_maps_plugin_test --- .../google_maps_flutter_web/example/build.yaml | 6 ++++++ .../google_maps_flutter_web/example/pubspec.yaml | 2 ++ .../google_maps_flutter_web/example/run_test.sh | 5 +++++ 3 files changed, 13 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml new file mode 100644 index 000000000000..db3104bb04c6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/build.yaml @@ -0,0 +1,6 @@ +targets: + $default: + sources: + - integration_test/*.dart + - lib/$lib$ + - $package$ 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 d2f3116dc3d7..347902457185 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 @@ -12,8 +12,10 @@ dependencies: sdk: flutter dev_dependencies: + build_runner: ^1.11.0 google_maps: ^5.0.1 http: ^0.13.0 + mockito: ^5.0.0 # Update to ^5.0.0 as soon as this migrates to null-safety flutter_driver: sdk: flutter flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index aa52974f310e..eed7e4f41127 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -6,6 +6,11 @@ if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." + # flutter pub get + + echo "(Re)generating mocks." + # flutter pub run build_runner build --delete-conflicting-outputs + if [ $# -eq 0 ]; then echo "No target specified, running all tests..." find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' From 1d3435daa7e306142e6942570ea389cb7b730f37 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 16 Mar 2021 19:19:20 -0700 Subject: [PATCH 10/30] Migrate google_maps_plugin_test.dart --- .../google_maps_plugin_test.dart | 73 +++++++---- .../google_maps_plugin_test.mocks.dart | 115 ++++++++++++++++++ .../lib/src/google_maps_controller.dart | 2 +- 3 files changed, 162 insertions(+), 28 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index dee37618c940..2fdb2fab864e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -2,36 +2,40 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:js_util' show getProperty; import 'package:integration_test/integration_test.dart'; import 'package:flutter/widgets.dart'; import 'package:google_maps/google_maps.dart' as gmaps; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; -class _MockGoogleMapController extends Mock implements GoogleMapController {} +import 'google_maps_plugin_test.mocks.dart'; + +@GenerateMocks([], customMocks: [ + MockSpec(returnNullOnMissingStub: true), +]) /// Test GoogleMapsPlugin void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('GoogleMapsPlugin', () { - _MockGoogleMapController controller; - GoogleMapsPlugin plugin; - int reportedMapId; + late MockGoogleMapController controller; + late GoogleMapsPlugin plugin; + int? reportedMapId; void onPlatformViewCreated(int id) { reportedMapId = id; } setUp(() { - controller = _MockGoogleMapController(); + controller = MockGoogleMapController(); plugin = GoogleMapsPlugin(); reportedMapId = null; }); @@ -74,16 +78,7 @@ void main() { testWidgets('throws without _webOnlyMapCreationId', (WidgetTester tester) async { - expect( - () => plugin.buildView( - null, - onPlatformViewCreated, - initialCameraPosition: initialCameraPosition, - ), - throwsAssertionError, - reason: - '_webOnlyMapCreationId is mandatory to prevent unnecessary reloads in web.', - ); + // The argument type 'Null' can't be assigned to the parameter type 'int'. }); testWidgets( @@ -92,14 +87,15 @@ void main() { final Map cache = {}; plugin.debugSetMapById(cache); - final HtmlElementView widget = plugin.buildView( + final Widget widget = plugin.buildView( testMapId, onPlatformViewCreated, initialCameraPosition: initialCameraPosition, ); + expect(widget, isA()); expect( - widget.viewType, + (widget as HtmlElementView).viewType, contains('$testMapId'), reason: 'view type should contain the mapId passed when creating the map.', @@ -119,7 +115,7 @@ void main() { testWidgets('returns cached instance if it already exists', (WidgetTester tester) async { - final expected = HtmlElementView(viewType: 'only-for-testing'); + final Widget expected = HtmlElementView(viewType: 'only-for-testing'); when(controller.widget).thenReturn(expected); plugin.debugSetMapById({testMapId: controller}); @@ -160,11 +156,10 @@ void main() { expect(styles.length, 1); // Let's peek inside the styles... var style = styles[0] as gmaps.MapTypeStyle; - expect(style.featureType, gmaps.MapTypeStyleFeatureType.POI_PARK); - expect( - style.elementType, gmaps.MapTypeStyleElementType.LABELS_TEXT_FILL); - expect(style.stylers.length, 1); - expect(style.stylers[0].color, '#6b9a76'); + expect(style.featureType, 'poi.park'); + expect(style.elementType, 'labels.text.fill'); + expect(style.stylers?.length, 1); + expect(getProperty(style.stylers![0]!, 'color'), '#6b9a76'); }); }); @@ -247,31 +242,50 @@ void main() { verify(controller.moveCamera(expectedUpdates)); }); + // Viewport testWidgets('getVisibleRegion', (WidgetTester tester) async { + when(controller.getVisibleRegion()) + .thenAnswer((_) async => LatLngBounds( + northeast: LatLng(47.2359634, -68.0192019), + southwest: LatLng(34.5019594, -120.4974629), + )); await plugin.getVisibleRegion(mapId: mapId); verify(controller.getVisibleRegion()); }); + testWidgets('getZoomLevel', (WidgetTester tester) async { + when(controller.getZoomLevel()).thenAnswer((_) async => 10); await plugin.getZoomLevel(mapId: mapId); verify(controller.getZoomLevel()); }); + testWidgets('getScreenCoordinate', (WidgetTester tester) async { + when(controller.getScreenCoordinate(any)).thenAnswer( + (_) async => ScreenCoordinate(x: 320, y: 240) // fake return + ); + final latLng = LatLng(43.3613, -5.8499); await plugin.getScreenCoordinate(latLng, mapId: mapId); verify(controller.getScreenCoordinate(latLng)); }); + testWidgets('getLatLng', (WidgetTester tester) async { + when(controller.getLatLng(any)) + .thenAnswer((_) async => LatLng(43.3613, -5.8499) // fake return + ); + final coordinates = ScreenCoordinate(x: 19, y: 26); await plugin.getLatLng(coordinates, mapId: mapId); verify(controller.getLatLng(coordinates)); }); + // InfoWindows testWidgets('showMarkerInfoWindow', (WidgetTester tester) async { final markerId = MarkerId('testing-123'); @@ -280,6 +294,7 @@ void main() { verify(controller.showInfoWindow(markerId)); }); + testWidgets('hideMarkerInfoWindow', (WidgetTester tester) async { final markerId = MarkerId('testing-123'); @@ -287,7 +302,10 @@ void main() { verify(controller.hideInfoWindow(markerId)); }); + testWidgets('isMarkerInfoWindowShown', (WidgetTester tester) async { + when(controller.isInfoWindowShown(any)).thenReturn(true); + final markerId = MarkerId('testing-123'); await plugin.isMarkerInfoWindowShown(markerId, mapId: mapId); @@ -299,7 +317,7 @@ void main() { // Verify all event streams are filtered correctly from the main one... group('Event Streams', () { int mapId = 0; - StreamController streamController; + late StreamController streamController; setUp(() { streamController = StreamController.broadcast(); when(controller.events) @@ -308,7 +326,8 @@ void main() { }); // Dispatches a few events in the global streamController, and expects *only* the passed event to be there. - void _testStreamFiltering(Stream stream, MapEvent event) async { + Future _testStreamFiltering( + Stream stream, MapEvent event) async { Timer.run(() { streamController.add(_OtherMapEvent(mapId)); streamController.add(event); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart new file mode 100644 index 000000000000..39d06bd06291 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart @@ -0,0 +1,115 @@ +// Mocks generated by Mockito 5.0.1 from annotations +// in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart. +// Do not manually edit this file. + +import 'dart:async' as _i6; + +import 'package:flutter/src/widgets/framework.dart' as _i2; +import 'package:google_maps_flutter_platform_interface/src/events/map_event.dart' + as _i7; +import 'package:google_maps_flutter_platform_interface/src/types/camera.dart' + as _i8; +import 'package:google_maps_flutter_platform_interface/src/types/circle_updates.dart' + as _i9; +import 'package:google_maps_flutter_platform_interface/src/types/location.dart' + as _i3; +import 'package:google_maps_flutter_platform_interface/src/types/marker.dart' + as _i13; +import 'package:google_maps_flutter_platform_interface/src/types/marker_updates.dart' + as _i12; +import 'package:google_maps_flutter_platform_interface/src/types/polygon_updates.dart' + as _i10; +import 'package:google_maps_flutter_platform_interface/src/types/polyline_updates.dart' + as _i11; +import 'package:google_maps_flutter_platform_interface/src/types/screen_coordinate.dart' + as _i4; +import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i5; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references +// ignore_for_file: unnecessary_parenthesis + +class _FakeWidget extends _i1.Fake implements _i2.Widget { + // --- ADDED BY HAND --- + @override + String toString({dynamic minLevel}) { + return super.toString(); + } + // --- / ADDED BY HAND --- +} + +class _FakeLatLngBounds extends _i1.Fake implements _i3.LatLngBounds {} + +class _FakeScreenCoordinate extends _i1.Fake implements _i4.ScreenCoordinate {} + +class _FakeLatLng extends _i1.Fake implements _i3.LatLng {} + +/// A class which mocks [GoogleMapController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockGoogleMapController extends _i1.Mock + implements _i5.GoogleMapController { + @override + _i2.Widget get widget => (super.noSuchMethod(Invocation.getter(#widget), + returnValue: _FakeWidget()) as _i2.Widget); + @override + _i6.Stream<_i7.MapEvent> get events => + (super.noSuchMethod(Invocation.getter(#events), + returnValue: Stream<_i7.MapEvent>.empty()) + as _i6.Stream<_i7.MapEvent>); + @override + void updateRawOptions(Map? optionsUpdate) => + super.noSuchMethod(Invocation.method(#updateRawOptions, [optionsUpdate]), + returnValueForMissingStub: null); + @override + _i6.Future<_i3.LatLngBounds> getVisibleRegion() => + (super.noSuchMethod(Invocation.method(#getVisibleRegion, []), + returnValue: Future.value(_FakeLatLngBounds())) + as _i6.Future<_i3.LatLngBounds>); + @override + _i6.Future<_i4.ScreenCoordinate> getScreenCoordinate(_i3.LatLng? latLng) => + (super.noSuchMethod(Invocation.method(#getScreenCoordinate, [latLng]), + returnValue: Future.value(_FakeScreenCoordinate())) + as _i6.Future<_i4.ScreenCoordinate>); + @override + _i6.Future<_i3.LatLng> getLatLng(_i4.ScreenCoordinate? screenCoordinate) => + (super.noSuchMethod(Invocation.method(#getLatLng, [screenCoordinate]), + returnValue: Future.value(_FakeLatLng())) as _i6.Future<_i3.LatLng>); + @override + _i6.Future moveCamera(_i8.CameraUpdate? cameraUpdate) => + (super.noSuchMethod(Invocation.method(#moveCamera, [cameraUpdate]), + returnValue: Future.value(null), + returnValueForMissingStub: Future.value()) as _i6.Future); + @override + _i6.Future getZoomLevel() => + (super.noSuchMethod(Invocation.method(#getZoomLevel, []), + returnValue: Future.value(0.0)) as _i6.Future); + @override + void updateCircles(_i9.CircleUpdates? updates) => + super.noSuchMethod(Invocation.method(#updateCircles, [updates]), + returnValueForMissingStub: null); + @override + void updatePolygons(_i10.PolygonUpdates? updates) => + super.noSuchMethod(Invocation.method(#updatePolygons, [updates]), + returnValueForMissingStub: null); + @override + void updatePolylines(_i11.PolylineUpdates? updates) => + super.noSuchMethod(Invocation.method(#updatePolylines, [updates]), + returnValueForMissingStub: null); + @override + void updateMarkers(_i12.MarkerUpdates? updates) => + super.noSuchMethod(Invocation.method(#updateMarkers, [updates]), + returnValueForMissingStub: null); + @override + void showInfoWindow(_i13.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#showInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + void hideInfoWindow(_i13.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#hideInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + bool isInfoWindowShown(_i13.MarkerId? markerId) => + (super.noSuchMethod(Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: false) as bool); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index 180f66d10c56..e27dfc4caa2f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -31,7 +31,7 @@ class GoogleMapController { late HtmlElement _div; /// The Flutter widget that will contain the rendered Map. Used for caching. - HtmlElementView get widget { + Widget get widget { if (_widget == null && !_streamController.isClosed) { _widget = HtmlElementView( viewType: _getViewType(_mapId), From d10806f85fe841cc5ef7266036594e5227919ed5 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 17 Mar 2021 15:50:44 -0700 Subject: [PATCH 11/30] Tweak the widget getter so it can be made null when disposing. --- .../lib/src/google_maps_controller.dart | 4 ++-- .../lib/src/google_maps_flutter_web.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index e27dfc4caa2f..fe673bc3f7f3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -31,13 +31,13 @@ class GoogleMapController { late HtmlElement _div; /// The Flutter widget that will contain the rendered Map. Used for caching. - Widget get widget { + Widget? get widget { if (_widget == null && !_streamController.isClosed) { _widget = HtmlElementView( viewType: _getViewType(_mapId), ); } - return _widget!; + return _widget; } // The currently-enabled traffic layer. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index 4c2a784bb9dc..629c7eb3b1e6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -314,6 +314,6 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { onPlatformViewCreated.call(creationId); - return mapController.widget; + return mapController.widget!; } } From b0ff2f6ec886d97f4ee3e5983adda5896396c991 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 17 Mar 2021 15:53:26 -0700 Subject: [PATCH 12/30] Add mocks, and the regen script --- .../google_maps_controller_test.mocks.dart | 198 ++++++++++++++++++ .../google_maps_plugin_test.mocks.dart | 83 ++++---- .../example/regen_mocks.sh | 7 + .../example/run_test.sh | 5 - 4 files changed, 240 insertions(+), 53 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart create mode 100755 packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart new file mode 100644 index 000000000000..29557d010341 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart @@ -0,0 +1,198 @@ +// Mocks generated by Mockito 5.0.1 from annotations +// in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart. +// Do not manually edit this file. + +import 'package:google_maps/src/generated/google_maps_core.js.g.dart' as _i2; +import 'package:google_maps_flutter_platform_interface/src/types/circle.dart' + as _i4; +import 'package:google_maps_flutter_platform_interface/src/types/marker.dart' + as _i7; +import 'package:google_maps_flutter_platform_interface/src/types/polygon.dart' + as _i5; +import 'package:google_maps_flutter_platform_interface/src/types/polyline.dart' + as _i6; +import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i3; +import 'package:mockito/mockito.dart' as _i1; + +// ignore_for_file: comment_references +// ignore_for_file: unnecessary_parenthesis + +class _FakeGMap extends _i1.Fake implements _i2.GMap {} + +/// A class which mocks [CirclesController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockCirclesController extends _i1.Mock implements _i3.CirclesController { + @override + Map<_i4.CircleId, _i3.CircleController> get circles => + (super.noSuchMethod(Invocation.getter(#circles), + returnValue: <_i4.CircleId, _i3.CircleController>{}) + as Map<_i4.CircleId, _i3.CircleController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addCircles(Set<_i4.Circle>? circlesToAdd) => + super.noSuchMethod(Invocation.method(#addCircles, [circlesToAdd]), + returnValueForMissingStub: null); + @override + void changeCircles(Set<_i4.Circle>? circlesToChange) => + super.noSuchMethod(Invocation.method(#changeCircles, [circlesToChange]), + returnValueForMissingStub: null); + @override + void removeCircles(Set<_i4.CircleId>? circleIdsToRemove) => + super.noSuchMethod(Invocation.method(#removeCircles, [circleIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [PolygonsController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPolygonsController extends _i1.Mock + implements _i3.PolygonsController { + @override + Map<_i5.PolygonId, _i3.PolygonController> get polygons => + (super.noSuchMethod(Invocation.getter(#polygons), + returnValue: <_i5.PolygonId, _i3.PolygonController>{}) + as Map<_i5.PolygonId, _i3.PolygonController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addPolygons(Set<_i5.Polygon>? polygonsToAdd) => + super.noSuchMethod(Invocation.method(#addPolygons, [polygonsToAdd]), + returnValueForMissingStub: null); + @override + void changePolygons(Set<_i5.Polygon>? polygonsToChange) => + super.noSuchMethod(Invocation.method(#changePolygons, [polygonsToChange]), + returnValueForMissingStub: null); + @override + void removePolygons(Set<_i5.PolygonId>? polygonIdsToRemove) => super + .noSuchMethod(Invocation.method(#removePolygons, [polygonIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [PolylinesController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPolylinesController extends _i1.Mock + implements _i3.PolylinesController { + @override + Map<_i6.PolylineId, _i3.PolylineController> get lines => + (super.noSuchMethod(Invocation.getter(#lines), + returnValue: <_i6.PolylineId, _i3.PolylineController>{}) + as Map<_i6.PolylineId, _i3.PolylineController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addPolylines(Set<_i6.Polyline>? polylinesToAdd) => + super.noSuchMethod(Invocation.method(#addPolylines, [polylinesToAdd]), + returnValueForMissingStub: null); + @override + void changePolylines(Set<_i6.Polyline>? polylinesToChange) => super + .noSuchMethod(Invocation.method(#changePolylines, [polylinesToChange]), + returnValueForMissingStub: null); + @override + void removePolylines(Set<_i6.PolylineId>? polylineIdsToRemove) => super + .noSuchMethod(Invocation.method(#removePolylines, [polylineIdsToRemove]), + returnValueForMissingStub: null); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} + +/// A class which mocks [MarkersController]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMarkersController extends _i1.Mock implements _i3.MarkersController { + @override + Map<_i7.MarkerId, _i3.MarkerController> get markers => + (super.noSuchMethod(Invocation.getter(#markers), + returnValue: <_i7.MarkerId, _i3.MarkerController>{}) + as Map<_i7.MarkerId, _i3.MarkerController>); + @override + _i2.GMap get googleMap => (super.noSuchMethod(Invocation.getter(#googleMap), + returnValue: _FakeGMap()) as _i2.GMap); + @override + set googleMap(_i2.GMap? _googleMap) => + super.noSuchMethod(Invocation.setter(#googleMap, _googleMap), + returnValueForMissingStub: null); + @override + int get mapId => + (super.noSuchMethod(Invocation.getter(#mapId), returnValue: 0) as int); + @override + set mapId(int? _mapId) => + super.noSuchMethod(Invocation.setter(#mapId, _mapId), + returnValueForMissingStub: null); + @override + void addMarkers(Set<_i7.Marker>? markersToAdd) => + super.noSuchMethod(Invocation.method(#addMarkers, [markersToAdd]), + returnValueForMissingStub: null); + @override + void changeMarkers(Set<_i7.Marker>? markersToChange) => + super.noSuchMethod(Invocation.method(#changeMarkers, [markersToChange]), + returnValueForMissingStub: null); + @override + void removeMarkers(Set<_i7.MarkerId>? markerIdsToRemove) => + super.noSuchMethod(Invocation.method(#removeMarkers, [markerIdsToRemove]), + returnValueForMissingStub: null); + @override + void showMarkerInfoWindow(_i7.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#showMarkerInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + void hideMarkerInfoWindow(_i7.MarkerId? markerId) => + super.noSuchMethod(Invocation.method(#hideMarkerInfoWindow, [markerId]), + returnValueForMissingStub: null); + @override + bool isInfoWindowShown(_i7.MarkerId? markerId) => + (super.noSuchMethod(Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: false) as bool); + @override + void bindToMap(int? mapId, _i2.GMap? googleMap) => + super.noSuchMethod(Invocation.method(#bindToMap, [mapId, googleMap]), + returnValueForMissingStub: null); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart index 39d06bd06291..db67e2249264 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart @@ -2,114 +2,101 @@ // in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart. // Do not manually edit this file. -import 'dart:async' as _i6; +import 'dart:async' as _i5; -import 'package:flutter/src/widgets/framework.dart' as _i2; import 'package:google_maps_flutter_platform_interface/src/events/map_event.dart' - as _i7; + as _i6; import 'package:google_maps_flutter_platform_interface/src/types/camera.dart' - as _i8; + as _i7; import 'package:google_maps_flutter_platform_interface/src/types/circle_updates.dart' - as _i9; + as _i8; import 'package:google_maps_flutter_platform_interface/src/types/location.dart' - as _i3; + as _i2; import 'package:google_maps_flutter_platform_interface/src/types/marker.dart' - as _i13; -import 'package:google_maps_flutter_platform_interface/src/types/marker_updates.dart' as _i12; +import 'package:google_maps_flutter_platform_interface/src/types/marker_updates.dart' + as _i11; import 'package:google_maps_flutter_platform_interface/src/types/polygon_updates.dart' - as _i10; + as _i9; import 'package:google_maps_flutter_platform_interface/src/types/polyline_updates.dart' - as _i11; + as _i10; import 'package:google_maps_flutter_platform_interface/src/types/screen_coordinate.dart' - as _i4; -import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i5; + as _i3; +import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i4; import 'package:mockito/mockito.dart' as _i1; // ignore_for_file: comment_references // ignore_for_file: unnecessary_parenthesis -class _FakeWidget extends _i1.Fake implements _i2.Widget { - // --- ADDED BY HAND --- - @override - String toString({dynamic minLevel}) { - return super.toString(); - } - // --- / ADDED BY HAND --- -} +class _FakeLatLngBounds extends _i1.Fake implements _i2.LatLngBounds {} -class _FakeLatLngBounds extends _i1.Fake implements _i3.LatLngBounds {} +class _FakeScreenCoordinate extends _i1.Fake implements _i3.ScreenCoordinate {} -class _FakeScreenCoordinate extends _i1.Fake implements _i4.ScreenCoordinate {} - -class _FakeLatLng extends _i1.Fake implements _i3.LatLng {} +class _FakeLatLng extends _i1.Fake implements _i2.LatLng {} /// A class which mocks [GoogleMapController]. /// /// See the documentation for Mockito's code generation for more information. class MockGoogleMapController extends _i1.Mock - implements _i5.GoogleMapController { - @override - _i2.Widget get widget => (super.noSuchMethod(Invocation.getter(#widget), - returnValue: _FakeWidget()) as _i2.Widget); + implements _i4.GoogleMapController { @override - _i6.Stream<_i7.MapEvent> get events => + _i5.Stream<_i6.MapEvent> get events => (super.noSuchMethod(Invocation.getter(#events), - returnValue: Stream<_i7.MapEvent>.empty()) - as _i6.Stream<_i7.MapEvent>); + returnValue: Stream<_i6.MapEvent>.empty()) + as _i5.Stream<_i6.MapEvent>); @override void updateRawOptions(Map? optionsUpdate) => super.noSuchMethod(Invocation.method(#updateRawOptions, [optionsUpdate]), returnValueForMissingStub: null); @override - _i6.Future<_i3.LatLngBounds> getVisibleRegion() => + _i5.Future<_i2.LatLngBounds> getVisibleRegion() => (super.noSuchMethod(Invocation.method(#getVisibleRegion, []), returnValue: Future.value(_FakeLatLngBounds())) - as _i6.Future<_i3.LatLngBounds>); + as _i5.Future<_i2.LatLngBounds>); @override - _i6.Future<_i4.ScreenCoordinate> getScreenCoordinate(_i3.LatLng? latLng) => + _i5.Future<_i3.ScreenCoordinate> getScreenCoordinate(_i2.LatLng? latLng) => (super.noSuchMethod(Invocation.method(#getScreenCoordinate, [latLng]), returnValue: Future.value(_FakeScreenCoordinate())) - as _i6.Future<_i4.ScreenCoordinate>); + as _i5.Future<_i3.ScreenCoordinate>); @override - _i6.Future<_i3.LatLng> getLatLng(_i4.ScreenCoordinate? screenCoordinate) => + _i5.Future<_i2.LatLng> getLatLng(_i3.ScreenCoordinate? screenCoordinate) => (super.noSuchMethod(Invocation.method(#getLatLng, [screenCoordinate]), - returnValue: Future.value(_FakeLatLng())) as _i6.Future<_i3.LatLng>); + returnValue: Future.value(_FakeLatLng())) as _i5.Future<_i2.LatLng>); @override - _i6.Future moveCamera(_i8.CameraUpdate? cameraUpdate) => + _i5.Future moveCamera(_i7.CameraUpdate? cameraUpdate) => (super.noSuchMethod(Invocation.method(#moveCamera, [cameraUpdate]), returnValue: Future.value(null), - returnValueForMissingStub: Future.value()) as _i6.Future); + returnValueForMissingStub: Future.value()) as _i5.Future); @override - _i6.Future getZoomLevel() => + _i5.Future getZoomLevel() => (super.noSuchMethod(Invocation.method(#getZoomLevel, []), - returnValue: Future.value(0.0)) as _i6.Future); + returnValue: Future.value(0.0)) as _i5.Future); @override - void updateCircles(_i9.CircleUpdates? updates) => + void updateCircles(_i8.CircleUpdates? updates) => super.noSuchMethod(Invocation.method(#updateCircles, [updates]), returnValueForMissingStub: null); @override - void updatePolygons(_i10.PolygonUpdates? updates) => + void updatePolygons(_i9.PolygonUpdates? updates) => super.noSuchMethod(Invocation.method(#updatePolygons, [updates]), returnValueForMissingStub: null); @override - void updatePolylines(_i11.PolylineUpdates? updates) => + void updatePolylines(_i10.PolylineUpdates? updates) => super.noSuchMethod(Invocation.method(#updatePolylines, [updates]), returnValueForMissingStub: null); @override - void updateMarkers(_i12.MarkerUpdates? updates) => + void updateMarkers(_i11.MarkerUpdates? updates) => super.noSuchMethod(Invocation.method(#updateMarkers, [updates]), returnValueForMissingStub: null); @override - void showInfoWindow(_i13.MarkerId? markerId) => + void showInfoWindow(_i12.MarkerId? markerId) => super.noSuchMethod(Invocation.method(#showInfoWindow, [markerId]), returnValueForMissingStub: null); @override - void hideInfoWindow(_i13.MarkerId? markerId) => + void hideInfoWindow(_i12.MarkerId? markerId) => super.noSuchMethod(Invocation.method(#hideInfoWindow, [markerId]), returnValueForMissingStub: null); @override - bool isInfoWindowShown(_i13.MarkerId? markerId) => + bool isInfoWindowShown(_i12.MarkerId? markerId) => (super.noSuchMethod(Invocation.method(#isInfoWindowShown, [markerId]), returnValue: false) as bool); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh new file mode 100755 index 000000000000..5892bbfef0ef --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh @@ -0,0 +1,7 @@ +#!/usr/bin/bash + +flutter pub get + +echo "(Re)generating mocks." + +flutter pub run build_runner build --delete-conflicting-outputs diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index eed7e4f41127..aa52974f310e 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -6,11 +6,6 @@ if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." - # flutter pub get - - echo "(Re)generating mocks." - # flutter pub run build_runner build --delete-conflicting-outputs - if [ $# -eq 0 ]; then echo "No target specified, running all tests..." find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' From d9885b222ccf1f65e339dbfcc34b84ea813ccee0 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 17 Mar 2021 15:55:39 -0700 Subject: [PATCH 13/30] Migrate google_maps_controller_test.dart --- .../google_maps_controller_test.dart | 181 +++++++++--------- 1 file changed, 93 insertions(+), 88 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index fd4df2ee4fd8..2221fa0eda7a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -2,43 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.9 - import 'dart:async'; +import 'dart:html' as html; -import 'package:integration_test/integration_test.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps/google_maps.dart' as gmaps; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; +import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; - -class _MockCirclesController extends Mock implements CirclesController {} +import 'google_maps_controller_test.mocks.dart'; -class _MockPolygonsController extends Mock implements PolygonsController {} +// This value is used when comparing long~num, like +// LatLng values. +const _acceptableDelta = 0.0000000001; -class _MockPolylinesController extends Mock implements PolylinesController {} - -class _MockMarkersController extends Mock implements MarkersController {} - -class _MockGMap extends Mock implements gmaps.GMap { - final onClickController = StreamController.broadcast(); - @override - Stream get onClick => onClickController.stream; - - final onRightclickController = StreamController.broadcast(); - @override - Stream get onRightclick => onRightclickController.stream; - - final onBoundsChangedController = StreamController.broadcast(); - @override - Stream get onBoundsChanged => onBoundsChangedController.stream; - - final onIdleController = StreamController.broadcast(); - @override - Stream get onIdle => onIdleController.stream; -} +@GenerateMocks([], customMocks: [ + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), + MockSpec(returnNullOnMissingStub: true), +]) /// Test Google Map Controller void main() { @@ -46,8 +33,8 @@ void main() { group('GoogleMapController', () { final int mapId = 33930; - GoogleMapController controller; - StreamController stream; + late GoogleMapController controller; + late StreamController stream; // Creates a controller with the default mapId and stream controller, and any `options` needed. GoogleMapController _createController({ @@ -57,7 +44,7 @@ void main() { Set polygons = const {}, Set polylines = const {}, Set circles = const {}, - Map options, + Map? options, }) { return GoogleMapController( mapId: mapId, @@ -81,7 +68,9 @@ void main() { testWidgets('constructor creates widget', (WidgetTester tester) async { expect(controller.widget, isNotNull); - expect(controller.widget.viewType, endsWith('$mapId')); + expect(controller.widget, isA()); + expect((controller.widget as HtmlElementView).viewType, + endsWith('$mapId')); }); testWidgets('widget is cached when reused', (WidgetTester tester) async { @@ -99,18 +88,18 @@ void main() { }); group('init', () { - _MockCirclesController circles; - _MockMarkersController markers; - _MockPolygonsController polygons; - _MockPolylinesController polylines; - _MockGMap map; + late MockCirclesController circles; + late MockMarkersController markers; + late MockPolygonsController polygons; + late MockPolylinesController polylines; + late gmaps.GMap map; setUp(() { - circles = _MockCirclesController(); - markers = _MockMarkersController(); - polygons = _MockPolygonsController(); - polylines = _MockPolylinesController(); - map = _MockGMap(); + circles = MockCirclesController(); + markers = MockMarkersController(); + polygons = MockPolygonsController(); + polylines = MockPolylinesController(); + map = gmaps.GMap(html.DivElement()); }); testWidgets('listens to map events', (WidgetTester tester) async { @@ -123,17 +112,25 @@ void main() { polylines: polylines, ); - expect(map.onClickController.hasListener, isFalse); - expect(map.onRightclickController.hasListener, isFalse); - expect(map.onBoundsChangedController.hasListener, isFalse); - expect(map.onIdleController.hasListener, isFalse); - controller.init(); - expect(map.onClickController.hasListener, isTrue); - expect(map.onRightclickController.hasListener, isTrue); - expect(map.onBoundsChangedController.hasListener, isTrue); - expect(map.onIdleController.hasListener, isTrue); + // Trigger events on the map, and verify they've been broadcast to the stream + final capturedEvents = stream.stream.take(5); + + gmaps.Event.trigger( + map, 'click', [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + gmaps.Event.trigger(map, 'rightclick', + [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); + gmaps.Event.trigger(map, 'bounds_changed', []); // Causes 2 events + gmaps.Event.trigger(map, 'idle', []); + + final events = await capturedEvents.toList(); + + expect(events[0], isA()); + expect(events[1], isA()); + expect(events[2], isA()); + expect(events[3], isA()); + expect(events[4], isA()); }); testWidgets('binds geometry controllers to map\'s', @@ -227,7 +224,7 @@ void main() { testWidgets('empty infoWindow does not create InfoWindow instance.', (WidgetTester tester) async { controller = _createController(markers: { - Marker(markerId: MarkerId('marker-1'), infoWindow: null), + Marker(markerId: MarkerId('marker-1')), }); controller.debugSetOverrides( @@ -239,11 +236,11 @@ void main() { final capturedMarkers = verify(markers.addMarkers(captureAny)).captured[0] as Set; - expect(capturedMarkers.first.infoWindow, isNull); + expect(capturedMarkers.first.infoWindow, InfoWindow.noText); }); group('Initialization options', () { - gmaps.MapOptions capturedOptions; + gmaps.MapOptions? capturedOptions; setUp(() { capturedOptions = null; }); @@ -260,9 +257,9 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.mapTypeId, gmaps.MapTypeId.SATELLITE); - expect(capturedOptions.zoomControl, true); - expect(capturedOptions.gestureHandling, 'auto', + expect(capturedOptions!.mapTypeId, gmaps.MapTypeId.SATELLITE); + expect(capturedOptions!.zoomControl, true); + expect(capturedOptions!.gestureHandling, 'auto', reason: 'by default the map handles zoom/pan gestures internally'); }); @@ -280,7 +277,7 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.gestureHandling, 'none', + expect(capturedOptions!.gestureHandling, 'none', reason: 'disabling scroll gestures disables all gesture handling'); }); @@ -298,16 +295,15 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.gestureHandling, 'none', + expect(capturedOptions!.gestureHandling, 'none', reason: 'disabling scroll gestures disables all gesture handling'); }); testWidgets('does not set initial position if absent', (WidgetTester tester) async { - controller = _createController( - initialCameraPosition: null, - ); + // The argument type 'Null' can't be assigned to the parameter type 'CameraPosition'. + controller = _createController(); controller.debugSetOverrides(createMap: (_, options) { capturedOptions = options; @@ -317,8 +313,9 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.zoom, isNull); - expect(capturedOptions.center, isNull); + expect(capturedOptions!.zoom, 0); + expect(capturedOptions!.center?.lat, 0); + expect(capturedOptions!.center?.lng, 0); }); testWidgets('sets initial position when passed', @@ -340,8 +337,8 @@ void main() { controller.init(); expect(capturedOptions, isNotNull); - expect(capturedOptions.zoom, 12); - expect(capturedOptions.center, isNotNull); + expect(capturedOptions!.zoom, 12); + expect(capturedOptions!.center, isNotNull); }); }); @@ -366,10 +363,15 @@ void main() { // These are the methods that are delegated to the gmaps.GMap object, that we can mock... group('Map control methods', () { - _MockGMap map; + late gmaps.GMap map; setUp(() { - map = _MockGMap(); + map = gmaps.GMap( + html.DivElement(), + gmaps.MapOptions() + ..zoom = 10 + ..center = gmaps.LatLng(0, 0), + ); controller = _createController(); controller.debugSetOverrides(createMap: (_, __) => map); controller.init(); @@ -380,9 +382,8 @@ void main() { controller.updateRawOptions({ 'mapType': 2, }); - final options = verify(map.options = captureAny).captured[0]; - expect(options.mapTypeId, gmaps.MapTypeId.SATELLITE); + expect(map.mapTypeId, gmaps.MapTypeId.SATELLITE); }); testWidgets('can turn on/off traffic', (WidgetTester tester) async { @@ -404,17 +405,19 @@ void main() { group('viewport getters', () { testWidgets('getVisibleRegion', (WidgetTester tester) async { - await controller.getVisibleRegion(); + final gmCenter = map.center!; + final center = + LatLng(gmCenter.lat!.toDouble(), gmCenter.lng!.toDouble()); - verify(map.bounds); + final bounds = await controller.getVisibleRegion(); + + expect(bounds.contains(center), isTrue, + reason: + 'The computed visible region must contain the center of the created map.'); }); testWidgets('getZoomLevel', (WidgetTester tester) async { - when(map.zoom).thenReturn(10); - - await controller.getZoomLevel(); - - verify(map.zoom); + expect(await controller.getZoomLevel(), map.zoom); }); }); @@ -423,10 +426,11 @@ void main() { await (controller .moveCamera(CameraUpdate.newLatLngZoom(LatLng(19, 26), 12))); - verify(map.zoom = 12); - final captured = verify(map.panTo(captureAny)).captured[0]; - expect(captured.lat, 19); - expect(captured.lng, 26); + final gmCenter = map.center!; + + expect(map.zoom, 12); + expect(gmCenter.lat, closeTo(19, _acceptableDelta)); + expect(gmCenter.lng, closeTo(26, _acceptableDelta)); }); }); @@ -445,7 +449,7 @@ void main() { }); testWidgets('updateCircles', (WidgetTester tester) async { - final mock = _MockCirclesController(); + final mock = MockCirclesController(); controller.debugSetOverrides(circles: mock); final previous = { @@ -472,7 +476,7 @@ void main() { }); testWidgets('updateMarkers', (WidgetTester tester) async { - final mock = _MockMarkersController(); + final mock = MockMarkersController(); controller.debugSetOverrides(markers: mock); final previous = { @@ -499,7 +503,7 @@ void main() { }); testWidgets('updatePolygons', (WidgetTester tester) async { - final mock = _MockPolygonsController(); + final mock = MockPolygonsController(); controller.debugSetOverrides(polygons: mock); final previous = { @@ -526,7 +530,7 @@ void main() { }); testWidgets('updatePolylines', (WidgetTester tester) async { - final mock = _MockPolylinesController(); + final mock = MockPolylinesController(); controller.debugSetOverrides(polylines: mock); final previous = { @@ -553,9 +557,10 @@ void main() { }); testWidgets('infoWindow visibility', (WidgetTester tester) async { - final mock = _MockMarkersController(); - controller.debugSetOverrides(markers: mock); + final mock = MockMarkersController(); final markerId = MarkerId('marker-with-infowindow'); + when(mock.isInfoWindowShown(markerId)).thenReturn(true); + controller.debugSetOverrides(markers: mock); controller.showInfoWindow(markerId); From 77e9702c3ec6c8c7a0901f81f14ac01fb406c0d5 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 17 Mar 2021 17:04:11 -0700 Subject: [PATCH 14/30] Call regen_mocks from run_test. Document Mocks. --- .../google_maps_flutter_web/example/README.md | 14 ++++++++++++++ .../google_maps_flutter_web/example/run_test.sh | 2 ++ 2 files changed, 16 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md index 0ec01e025570..5753fa876909 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md @@ -19,3 +19,17 @@ Make sure you have updated to the latest Flutter master. * Single: `./run_test.sh integration_test/TEST_NAME.dart` * All: `./run_test.sh` + +## Mocks + +There's new `.mocks.dart` files next to the test files that use them. + +Mocks are [auto-generated by `package:mockito`](https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#code-generation). + +Mocks can be manually re-generated with the following command: `flutter pub run build_runner build`, or by running the `regen_mocks.sh` script. + +Mocks may change with changes to the API of the classes they're mocking, but also by how they're used within the tests. + +Remember to regenerate the mocks often, and feel free to commit any changes in them. + +(Mocks will be auto-generated by the `run_test.sh` script as well.) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh index aa52974f310e..fcac5f600acb 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/run_test.sh @@ -6,6 +6,8 @@ if pgrep -lf chromedriver > /dev/null; then echo "chromedriver is running." + ./regen_mocks.sh + if [ $# -eq 0 ]; then echo "No target specified, running all tests..." find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}' From 86f79ee86469cb284b7ef1e822a30e363dec4153 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 17 Mar 2021 17:50:00 -0700 Subject: [PATCH 15/30] Add license to regen_mocks.sh --- .../google_maps_flutter_web/example/regen_mocks.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh index 5892bbfef0ef..42db0e882145 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh @@ -1,4 +1,7 @@ #!/usr/bin/bash +# Copyright 2017 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. flutter pub get From 2bd407314848e5b781d69d6becd34b56d587267c Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 18 Mar 2021 14:08:15 -0700 Subject: [PATCH 16/30] Remove tests that don't apply in a post-null-safety world. --- .../google_maps_flutter_web/CHANGELOG.md | 4 ++++ .../google_maps_controller_test.dart | 18 ------------------ .../google_maps_plugin_test.dart | 5 ----- .../example/integration_test/markers_test.dart | 7 +------ 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 2dd27b4bd563..b7f59f78ca86 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,6 +1,10 @@ ## 0.3.0 * Migrate package to null-safety. +* **Breaking changes:** + * The property `icon` of a `Marker` cannot be `null`. Defaults to `BitmapDescriptor.defaultMarker` + * The property `initialCameraPosition` of a `GoogleMapController` can't be `null`. It is also marked as `required`. + * The parameter `creationId` of the `buildView` method cannot be `null` (this should be handled internally for users of the plugin) ## 0.2.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index 2221fa0eda7a..b6037375dd2f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -300,24 +300,6 @@ void main() { 'disabling scroll gestures disables all gesture handling'); }); - testWidgets('does not set initial position if absent', - (WidgetTester tester) async { - // The argument type 'Null' can't be assigned to the parameter type 'CameraPosition'. - controller = _createController(); - - controller.debugSetOverrides(createMap: (_, options) { - capturedOptions = options; - return map; - }); - - controller.init(); - - expect(capturedOptions, isNotNull); - expect(capturedOptions!.zoom, 0); - expect(capturedOptions!.center?.lat, 0); - expect(capturedOptions!.center?.lng, 0); - }); - testWidgets('sets initial position when passed', (WidgetTester tester) async { controller = _createController( diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index 2fdb2fab864e..3a030d554ab1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -76,11 +76,6 @@ void main() { final testMapId = 33930; final initialCameraPosition = CameraPosition(target: LatLng(0, 0)); - testWidgets('throws without _webOnlyMapCreationId', - (WidgetTester tester) async { - // The argument type 'Null' can't be assigned to the parameter type 'int'. - }); - testWidgets( 'returns an HtmlElementView and caches the controller for later', (WidgetTester tester) async { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart index 55f932ae8ee9..6f2bf610f77d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/markers_test.dart @@ -138,12 +138,7 @@ void main() { expect(controller.markers[MarkerId('2')]?.infoWindowShown, isTrue); }); - // https://github.com/flutter/flutter/issues/64938 - testWidgets('markers with icon:null work', (WidgetTester tester) async { - // The argument type 'Null' can't be assigned to the parameter type 'BitmapDescriptor'. - }); - - // + // https://github.com/flutter/flutter/issues/66622 testWidgets('markers with custom bitmap icon work', (WidgetTester tester) async { final bytes = Base64Decoder().convert(iconImageBase64); From a933c529893914d3cd6c18e6f75ec7049af24b82 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 18 Mar 2021 14:13:29 -0700 Subject: [PATCH 17/30] Cleanup lies from pubspec comments. --- .../google_maps_flutter_web/example/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 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 347902457185..d047ae4587b6 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 @@ -2,8 +2,8 @@ name: google_maps_flutter_web_integration_tests publish_to: none environment: - sdk: ">=2.12.0 <3.0.0" # Bump this to 2.12 when migrating to nnbd. - flutter: ">=2.1.0-0" # For integration_test from sdk + sdk: ">=2.12.0 <3.0.0" + flutter: ">=2.1.0-0" # For integration_test (with null safety) from sdk dependencies: google_maps_flutter_web: @@ -15,7 +15,7 @@ dev_dependencies: build_runner: ^1.11.0 google_maps: ^5.0.1 http: ^0.13.0 - mockito: ^5.0.0 # Update to ^5.0.0 as soon as this migrates to null-safety + mockito: ^5.0.0 flutter_driver: sdk: flutter flutter_test: From dce73690c1ba54c422af3d2d91145a3cb2d3eb27 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 18 Mar 2021 14:13:49 -0700 Subject: [PATCH 18/30] No need for left-hand-side type. --- .../example/integration_test/google_maps_plugin_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart index 3a030d554ab1..2de431a5445e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.dart @@ -110,7 +110,7 @@ void main() { testWidgets('returns cached instance if it already exists', (WidgetTester tester) async { - final Widget expected = HtmlElementView(viewType: 'only-for-testing'); + final expected = HtmlElementView(viewType: 'only-for-testing'); when(controller.widget).thenReturn(expected); plugin.debugSetMapById({testMapId: controller}); From f0abbf7d7c261122aaff56216be902abb61e6db0 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 18 Mar 2021 14:20:30 -0700 Subject: [PATCH 19/30] Make return type slightly more strict in _mapStyles convert function. --- .../google_maps_flutter_web/lib/src/convert.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 33fc12009af8..cc71c97d4f08 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -128,7 +128,7 @@ bool _isJsonMapStyle(Map value) { } // Converts an incoming JSON-encoded Style info, into the correct gmaps array. -List _mapStyles(String? mapStyleJson) { +List _mapStyles(String? mapStyleJson) { List styles = []; if (mapStyleJson != null) { styles = json From b17d888d1ff54be0d0b59537a277738abaae0e98 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Thu, 18 Mar 2021 15:02:22 -0700 Subject: [PATCH 20/30] Prevent calling methods on Geometry controllers after calling remove. --- .../example/integration_test/marker_test.dart | 36 +++++++++++ .../example/integration_test/shape_test.dart | 63 +++++++++++++++++++ .../lib/src/circle.dart | 3 + .../lib/src/marker.dart | 10 +++ .../lib/src/polygon.dart | 3 + .../lib/src/polyline.dart | 5 +- 6 files changed, 119 insertions(+), 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index d634576ea8d5..e71b3fd089d9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -102,5 +102,41 @@ void main() { expect(infoWindow.get('map'), isNull); expect(controller.infoWindowShown, isFalse); }); + + group('remove', () { + late MarkerController controller; + + setUp(() { + final infoWindow = gmaps.InfoWindow(); + final map = gmaps.GMap(html.DivElement()); + marker.set('map', map); + controller = MarkerController(marker: marker, infoWindow: infoWindow); + + controller.remove(); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + expect(controller.marker, isNull); + }); + + testWidgets('cannot call update after remove', (WidgetTester tester) async { + final options = gmaps.MarkerOptions()..draggable = true; + expect((){ + controller.update(options); + }, throwsAssertionError); + }); + + testWidgets('cannot call showInfoWindow after remove', (WidgetTester tester) async { + expect((){ + controller.showInfoWindow(); + }, throwsAssertionError); + }); + + testWidgets('cannot call hideInfoWindow after remove', (WidgetTester tester) async { + expect((){ + controller.hideInfoWindow(); + }, throwsAssertionError); + }); + }); }); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index f87a2d947550..c1e3a5c45e5f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -51,6 +51,27 @@ void main() { expect(circle.draggable, isTrue); }); + + group('remove', () { + late CircleController controller; + + setUp(() { + controller = CircleController(circle: circle); + + controller.remove(); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + expect(controller.circle, isNull); + }); + + testWidgets('cannot call update after remove', (WidgetTester tester) async { + final options = gmaps.CircleOptions()..draggable = true; + expect((){ + controller.update(options); + }, throwsAssertionError); + }); + }); }); group('PolygonController', () { @@ -80,6 +101,27 @@ void main() { expect(polygon.draggable, isTrue); }); + + group('remove', () { + late PolygonController controller; + + setUp(() { + controller = PolygonController(polygon: polygon); + + controller.remove(); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + expect(controller.polygon, isNull); + }); + + testWidgets('cannot call update after remove', (WidgetTester tester) async { + final options = gmaps.PolygonOptions()..draggable = true; + expect((){ + controller.update(options); + }, throwsAssertionError); + }); + }); }); group('PolylineController', () { @@ -110,5 +152,26 @@ void main() { expect(polyline.draggable, isTrue); }); + + group('remove', () { + late PolylineController controller; + + setUp(() { + controller = PolylineController(polyline: polyline); + + controller.remove(); + }); + + testWidgets('drops gmaps instance', (WidgetTester tester) async { + expect(controller.line, isNull); + }); + + testWidgets('cannot call update after remove', (WidgetTester tester) async { + final options = gmaps.PolylineOptions()..draggable = true; + expect((){ + controller.update(options); + }, throwsAssertionError); + }); + }); }); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index 9ddf766995a9..16c9adfc6071 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -32,7 +32,10 @@ class CircleController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Circle] object. + /// + /// This cannot be called after [remove]. void update(gmaps.CircleOptions options) { + assert(_circle != null, 'Cannot `update` Circle after calling `remove`.'); _circle!.options = options; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 5e55562cf1ef..88565a98ee7b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -51,10 +51,13 @@ class MarkerController { gmaps.InfoWindow? get infoWindow => _infoWindow; /// Updates the options of the wrapped [gmaps.Marker] object. + /// + /// This cannot be called after [remove]. void update( gmaps.MarkerOptions options, { HtmlElement? newInfoWindowContent, }) { + assert(_marker != null, 'Cannot `update` Marker after calling `remove`.'); _marker!.options = options; if (_infoWindow != null && newInfoWindowContent != null) { _infoWindow!.content = newInfoWindowContent; @@ -64,6 +67,7 @@ class MarkerController { /// Disposes of the currently wrapped [gmaps.Marker]. void remove() { if (_marker != null) { + _infoWindowShown = false; _marker!.visible = false; _marker!.map = null; _marker = null; @@ -71,7 +75,10 @@ class MarkerController { } /// Hide the associated [gmaps.InfoWindow]. + /// + /// This cannot be called after [remove]. void hideInfoWindow() { + assert(_marker != null, 'Cannot `hideInfoWindow` on a `remove`d Marker.'); if (_infoWindow != null) { _infoWindow!.close(); _infoWindowShown = false; @@ -79,7 +86,10 @@ class MarkerController { } /// Show the associated [gmaps.InfoWindow]. + /// + /// This cannot be called after [remove]. void showInfoWindow() { + assert(_marker != null, 'Cannot `showInfoWindow` on a `remove`d Marker.'); if (_infoWindow != null) { _infoWindow!.open(_marker!.map, _marker); _infoWindowShown = true; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index ecde641327f7..c877fa8069ec 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -32,7 +32,10 @@ class PolygonController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polygon] object. + /// + /// This cannot be called after [remove]. void update(gmaps.PolygonOptions options) { + assert(_polygon != null, 'Cannot `update` Polygon after calling `remove`.'); _polygon!.options = options; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index c5dc0fafa812..ab59cfffed69 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -32,8 +32,11 @@ class PolylineController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polyline] object. + /// + /// This cannot be called after [remove]. void update(gmaps.PolylineOptions options) { - _polyline?.options = options; + assert(_polyline != null, 'Cannot `update` Polyline after calling `remove`.'); + _polyline!.options = options; } /// Disposes of the currently wrapped [gmaps.Polyline]. From c33fc212ddc5ca491755093839dfee2fe9881439 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 19 Mar 2021 10:52:53 -0700 Subject: [PATCH 21/30] Some more PR reviews. dartfmt -w . --- .../example/integration_test/marker_test.dart | 15 ++-- .../example/integration_test/shape_test.dart | 15 ++-- .../lib/src/circle.dart | 2 +- .../lib/src/convert.dart | 81 +++++++++++-------- .../lib/src/google_maps_controller.dart | 6 +- .../lib/src/marker.dart | 12 +-- .../lib/src/polygon.dart | 2 +- .../lib/src/polyline.dart | 5 +- 8 files changed, 83 insertions(+), 55 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index e71b3fd089d9..e55d52fde926 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -119,21 +119,24 @@ void main() { expect(controller.marker, isNull); }); - testWidgets('cannot call update after remove', (WidgetTester tester) async { + testWidgets('cannot call update after remove', + (WidgetTester tester) async { final options = gmaps.MarkerOptions()..draggable = true; - expect((){ + expect(() { controller.update(options); }, throwsAssertionError); }); - testWidgets('cannot call showInfoWindow after remove', (WidgetTester tester) async { - expect((){ + testWidgets('cannot call showInfoWindow after remove', + (WidgetTester tester) async { + expect(() { controller.showInfoWindow(); }, throwsAssertionError); }); - testWidgets('cannot call hideInfoWindow after remove', (WidgetTester tester) async { - expect((){ + testWidgets('cannot call hideInfoWindow after remove', + (WidgetTester tester) async { + expect(() { controller.hideInfoWindow(); }, throwsAssertionError); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index c1e3a5c45e5f..9d56c3bcd51e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -65,9 +65,10 @@ void main() { expect(controller.circle, isNull); }); - testWidgets('cannot call update after remove', (WidgetTester tester) async { + testWidgets('cannot call update after remove', + (WidgetTester tester) async { final options = gmaps.CircleOptions()..draggable = true; - expect((){ + expect(() { controller.update(options); }, throwsAssertionError); }); @@ -115,9 +116,10 @@ void main() { expect(controller.polygon, isNull); }); - testWidgets('cannot call update after remove', (WidgetTester tester) async { + testWidgets('cannot call update after remove', + (WidgetTester tester) async { final options = gmaps.PolygonOptions()..draggable = true; - expect((){ + expect(() { controller.update(options); }, throwsAssertionError); }); @@ -166,9 +168,10 @@ void main() { expect(controller.line, isNull); }); - testWidgets('cannot call update after remove', (WidgetTester tester) async { + testWidgets('cannot call update after remove', + (WidgetTester tester) async { final options = gmaps.PolylineOptions()..draggable = true; - expect((){ + expect(() { controller.update(options); }, throwsAssertionError); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart index 16c9adfc6071..65057d8c869e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/circle.dart @@ -32,7 +32,7 @@ class CircleController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Circle] object. - /// + /// /// This cannot be called after [remove]. void update(gmaps.CircleOptions options) { assert(_circle != null, 'Cannot `update` Circle after calling `remove`.'); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index cc71c97d4f08..aad99e593e64 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -4,11 +4,11 @@ part of google_maps_flutter_web; -final _nullLatLng = LatLng(0, 0); -final _nullLatLngBounds = LatLngBounds( - northeast: _nullLatLng, - southwest: _nullLatLng, -); +// Default values for when the gmaps objects return null/undefined values. +final _nullGmapsLatLng = gmaps.LatLng(0, 0); +final _nullGmapsLatLngBounds = + gmaps.LatLngBounds(_nullGmapsLatLng, _nullGmapsLatLng); +final _nullZoom = 0; // Defaults taken from the Google Maps Platform SDK documentation. final _defaultCssColor = '#000000'; @@ -149,21 +149,15 @@ List _mapStyles(String? mapStyleJson) { return styles; } -gmaps.LatLng? _latLngToGmLatLng(LatLng latLng) { - if (latLng == null) return null; +gmaps.LatLng _latLngToGmLatLng(LatLng latLng) { return gmaps.LatLng(latLng.latitude, latLng.longitude); } -LatLng _gmLatLngToLatLng(gmaps.LatLng? latLng) { - if (latLng == null) return _nullLatLng; +LatLng _gmLatLngToLatLng(gmaps.LatLng latLng) { return LatLng(latLng.lat!.toDouble(), latLng.lng!.toDouble()); } -LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds? latLngBounds) { - if (latLngBounds == null) { - return _nullLatLngBounds; - } - +LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds latLngBounds) { return LatLngBounds( southwest: _gmLatLngToLatLng(latLngBounds.southWest!), northeast: _gmLatLngToLatLng(latLngBounds.northEast!), @@ -172,10 +166,10 @@ LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds? latLngBounds) { CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { return CameraPosition( - target: _gmLatLngToLatLng(map.center), + target: _gmLatLngToLatLng(map.center ?? _nullGmapsLatLng), bearing: map.heading?.toDouble() ?? 0, tilt: map.tilt?.toDouble() ?? 0, - zoom: map.zoom?.toDouble() ?? 10, + zoom: map.zoom?.toDouble() ?? 0, ); } @@ -184,8 +178,11 @@ CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { // Marker.fromMarker(anotherMarker, moreOptions); gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { - if ((marker.infoWindow.title?.isEmpty ?? true) && - (marker.infoWindow.snippet?.isEmpty ?? true)) { + final markerTitle = marker.infoWindow.title; + final markerSnippet = marker.infoWindow.snippet; + + // If both the title and the snippet are null or empty, bail out... + if ((markerTitle?.isEmpty ?? true) && (markerSnippet?.isEmpty ?? true)) { return null; } @@ -193,17 +190,18 @@ gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { // to click events... final HtmlElement container = DivElement() ..id = 'gmaps-marker-${marker.markerId.value}-infowindow'; - if (marker.infoWindow.title?.isNotEmpty ?? false) { + + if (markerTitle != null && markerTitle.isNotEmpty) { final HtmlElement title = HeadingElement.h3() ..className = 'infowindow-title' - ..innerText = marker.infoWindow.title!; + ..innerText = markerTitle; container.children.add(title); } - if (marker.infoWindow.snippet?.isNotEmpty ?? false) { + if (markerSnippet != null && markerSnippet.isNotEmpty) { final HtmlElement snippet = DivElement() ..className = 'infowindow-snippet' ..setInnerHtml( - sanitizeHtml(marker.infoWindow.snippet!), + sanitizeHtml(markerSnippet), treeSanitizer: NodeTreeSanitizer.trusted, ); container.children.add(snippet); @@ -282,14 +280,14 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( gmaps.GMap googleMap, Polygon polygon) { List path = []; polygon.points.forEach((point) { - path.add(_latLngToGmLatLng(point)!); + path.add(_latLngToGmLatLng(point)); }); final polygonDirection = _isPolygonClockwise(path); List> paths = [path]; int holeIndex = 0; polygon.holes.forEach((hole) { List holePath = - hole.map((point) => _latLngToGmLatLng(point)!).toList(); + hole.map((point) => _latLngToGmLatLng(point)).toList(); if (_isPolygonClockwise(holePath) == polygonDirection) { holePath = holePath.reversed.toList(); if (kDebugMode) { @@ -318,6 +316,13 @@ gmaps.PolygonOptions _polygonOptionsFromPolygon( /// based on: https://stackoverflow.com/a/1165943 /// /// returns [true] if clockwise [false] if counterclockwise +/// +/// This method expects that the incoming [path] is a `List` of well-formed, +/// non-null [gmaps.LatLng] objects. +/// +/// Currently, this method is only called from [_polygonOptionsFromPolygon], and +/// the `path` is a transformed version of [Polygon.points] or each of the +/// [Polygon.holes], guaranteeing that `lat` and `lng` can be accessed with `!`. bool _isPolygonClockwise(List path) { var direction = 0.0; for (var i = 0; i < path.length; i++) { @@ -332,7 +337,7 @@ gmaps.PolylineOptions _polylineOptionsFromPolyline( gmaps.GMap googleMap, Polyline polyline) { List paths = []; polyline.points.forEach((point) { - paths.add(_latLngToGmLatLng(point)!); + paths.add(_latLngToGmLatLng(point)); }); return gmaps.PolylineOptions() @@ -391,16 +396,16 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // print('Error computing new focus LatLng. JS Error: ' + e.toString()); } } - map.zoom = map.zoom! + newZoomDelta; + map.zoom = (map.zoom ?? 0) + newZoomDelta; if (focusLatLng != null) { map.panTo(focusLatLng); } break; case 'zoomIn': - map.zoom = map.zoom! + 1; + map.zoom = (map.zoom ?? 0) + 1; break; case 'zoomOut': - map.zoom = map.zoom! - 1; + map.zoom = (map.zoom ?? 0) - 1; break; case 'zoomTo': map.zoom = json[1]; @@ -412,14 +417,24 @@ void _applyCameraUpdate(gmaps.GMap map, CameraUpdate update) { // original JS by: Byron Singh (https://stackoverflow.com/a/30541162) gmaps.LatLng _pixelToLatLng(gmaps.GMap map, int x, int y) { - final ne = map.bounds!.northEast; - final sw = map.bounds!.southWest; - final projection = map.projection!; + final bounds = map.bounds; + final projection = map.projection; + final zoom = map.zoom; + + assert( + bounds != null, 'Map Bounds required to compute LatLng of screen x/y.'); + assert(projection != null, + 'Map Projection required to compute LatLng of screen x/y'); + assert(zoom != null, + 'Current map zoom level required to compute LatLng of screen x/y'); + + final ne = bounds!.northEast; + final sw = bounds.southWest; - final topRight = projection.fromLatLngToPoint!(ne)!; + final topRight = projection!.fromLatLngToPoint!(ne)!; final bottomLeft = projection.fromLatLngToPoint!(sw)!; - final scale = 1 << (map.zoom! as int); // 2 ^ zoom + final scale = 1 << (zoom! as int); // 2 ^ zoom final point = gmaps.Point((x / scale) + bottomLeft.x!, (y / scale) + topRight.y!); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index fe673bc3f7f3..fe3f42ae1f58 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -255,7 +255,8 @@ class GoogleMapController { /// Returns the [LatLngBounds] of the current viewport. Future getVisibleRegion() async { - return _gmLatLngBoundsTolatLngBounds(await _googleMap!.bounds); + return _gmLatLngBoundsTolatLngBounds( + await _googleMap!.bounds ?? _nullGmapsLatLngBounds); } /// Returns the [ScreenCoordinate] for a given viewport [LatLng]. @@ -328,6 +329,9 @@ class GoogleMapController { // Cleanup /// Disposes of this controller and its resources. + /// + /// You won't be able to call many of the methods on this controller after + /// calling `dispose`! void dispose() { _widget = null; _googleMap = null; diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index 88565a98ee7b..e73ae4a6e985 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -31,8 +31,10 @@ class MarkerController { } if (onDragEnd != null) { _marker!.onDragend.listen((event) { - _marker!.position = event.latLng; - onDragEnd.call(event.latLng!); + if (_marker != null) { + _marker!.position = event.latLng; + } + onDragEnd.call(event.latLng ?? _nullGmapsLatLng); }); } } @@ -51,7 +53,7 @@ class MarkerController { gmaps.InfoWindow? get infoWindow => _infoWindow; /// Updates the options of the wrapped [gmaps.Marker] object. - /// + /// /// This cannot be called after [remove]. void update( gmaps.MarkerOptions options, { @@ -75,7 +77,7 @@ class MarkerController { } /// Hide the associated [gmaps.InfoWindow]. - /// + /// /// This cannot be called after [remove]. void hideInfoWindow() { assert(_marker != null, 'Cannot `hideInfoWindow` on a `remove`d Marker.'); @@ -86,7 +88,7 @@ class MarkerController { } /// Show the associated [gmaps.InfoWindow]. - /// + /// /// This cannot be called after [remove]. void showInfoWindow() { assert(_marker != null, 'Cannot `showInfoWindow` on a `remove`d Marker.'); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart index c877fa8069ec..9921d2ff3876 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polygon.dart @@ -32,7 +32,7 @@ class PolygonController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polygon] object. - /// + /// /// This cannot be called after [remove]. void update(gmaps.PolygonOptions options) { assert(_polygon != null, 'Cannot `update` Polygon after calling `remove`.'); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart index ab59cfffed69..eb4b6d88b503 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/polyline.dart @@ -32,10 +32,11 @@ class PolylineController { bool get consumeTapEvents => _consumeTapEvents; /// Updates the options of the wrapped [gmaps.Polyline] object. - /// + /// /// This cannot be called after [remove]. void update(gmaps.PolylineOptions options) { - assert(_polyline != null, 'Cannot `update` Polyline after calling `remove`.'); + assert( + _polyline != null, 'Cannot `update` Polyline after calling `remove`.'); _polyline!.options = options; } From 5a08e9e80674c7d43f02df1f32786255e33120f6 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 19 Mar 2021 11:07:16 -0700 Subject: [PATCH 22/30] Remove unused _nullZoom --- .../google_maps_flutter_web/lib/src/convert.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index aad99e593e64..38fa069e4b5c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -8,7 +8,6 @@ part of google_maps_flutter_web; final _nullGmapsLatLng = gmaps.LatLng(0, 0); final _nullGmapsLatLngBounds = gmaps.LatLngBounds(_nullGmapsLatLng, _nullGmapsLatLng); -final _nullZoom = 0; // Defaults taken from the Google Maps Platform SDK documentation. final _defaultCssColor = '#000000'; From fc41b15498655c66d83b441d17333cf2cb5b41af Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 19 Mar 2021 16:40:20 -0700 Subject: [PATCH 23/30] Update to google_maps 5.1.0 --- .../integration_test/google_maps_controller_test.dart | 2 +- .../google_maps_flutter_web/example/pubspec.yaml | 2 +- .../google_maps_flutter_web/lib/src/convert.dart | 10 +++++----- .../google_maps_flutter_web/pubspec.yaml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index b6037375dd2f..768deae615cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -389,7 +389,7 @@ void main() { testWidgets('getVisibleRegion', (WidgetTester tester) async { final gmCenter = map.center!; final center = - LatLng(gmCenter.lat!.toDouble(), gmCenter.lng!.toDouble()); + LatLng(gmCenter.lat.toDouble(), gmCenter.lng.toDouble()); final bounds = await controller.getVisibleRegion(); 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 d047ae4587b6..55f66e2f4e56 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 @@ -13,7 +13,7 @@ dependencies: dev_dependencies: build_runner: ^1.11.0 - google_maps: ^5.0.1 + google_maps: ^5.1.0 http: ^0.13.0 mockito: ^5.0.0 flutter_driver: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 38fa069e4b5c..e309e00c985a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -153,13 +153,13 @@ gmaps.LatLng _latLngToGmLatLng(LatLng latLng) { } LatLng _gmLatLngToLatLng(gmaps.LatLng latLng) { - return LatLng(latLng.lat!.toDouble(), latLng.lng!.toDouble()); + return LatLng(latLng.lat.toDouble(), latLng.lng.toDouble()); } LatLngBounds _gmLatLngBoundsTolatLngBounds(gmaps.LatLngBounds latLngBounds) { return LatLngBounds( - southwest: _gmLatLngToLatLng(latLngBounds.southWest!), - northeast: _gmLatLngToLatLng(latLngBounds.northEast!), + southwest: _gmLatLngToLatLng(latLngBounds.southWest), + northeast: _gmLatLngToLatLng(latLngBounds.northEast), ); } @@ -326,8 +326,8 @@ bool _isPolygonClockwise(List path) { var direction = 0.0; for (var i = 0; i < path.length; i++) { direction = direction + - ((path[(i + 1) % path.length].lat! - path[i].lat!) * - (path[(i + 1) % path.length].lng! + path[i].lng!)); + ((path[(i + 1) % path.length].lat - path[i].lat) * + (path[(i + 1) % path.length].lng + path[i].lng)); } return direction >= 0; } 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 a129eb7f5dd8..5312a56cd14a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: sdk: flutter meta: ^1.3.0 google_maps_flutter_platform_interface: ^2.0.1 - google_maps: ^5.0.1 + google_maps: ^5.1.0 stream_transform: ^2.0.0 sanitize_html: ^2.0.0 From a6c2a7e590b8bf6f41d237378e9833d44a21b5a8 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 19 Mar 2021 17:07:15 -0700 Subject: [PATCH 24/30] Add licenses. --- .../integration_test/google_maps_controller_test.mocks.dart | 4 ++++ .../integration_test/google_maps_plugin_test.mocks.dart | 4 ++++ .../google_maps_flutter_web/example/regen_mocks.sh | 6 +++--- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart index 29557d010341..e932883ad27e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart @@ -1,3 +1,7 @@ +// 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. + // Mocks generated by Mockito 5.0.1 from annotations // in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart. // Do not manually edit this file. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart index db67e2249264..7b93a0696a90 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart @@ -1,3 +1,7 @@ +// 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. + // Mocks generated by Mockito 5.0.1 from annotations // in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart. // Do not manually edit this file. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh index 42db0e882145..274de8775833 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh @@ -1,7 +1,7 @@ #!/usr/bin/bash -# Copyright 2017 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 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. flutter pub get From 151c74f44946490e7d4ef726ee66b41c00da70b1 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 19 Mar 2021 17:13:31 -0700 Subject: [PATCH 25/30] Single hash for license header in bash scripts. --- .../google_maps_flutter_web/example/regen_mocks.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh index 274de8775833..78bcdc0f9e28 100755 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/regen_mocks.sh @@ -1,7 +1,7 @@ #!/usr/bin/bash -## 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. +# 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. flutter pub get From a991500b9b8ff395683f2f36e57296b224323515 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Mon, 22 Mar 2021 11:27:46 -0700 Subject: [PATCH 26/30] Make build work in stable, and build+test in master. --- .../google_maps_controller_test.mocks.dart | 2 +- .../integration_test/google_maps_plugin_test.mocks.dart | 2 +- .../google_maps_flutter_web/example/pubspec.yaml | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart index e932883ad27e..47933285b208 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.mocks.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Mocks generated by Mockito 5.0.1 from annotations +// Mocks generated by Mockito 5.0.2 from annotations // in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart. // Do not manually edit this file. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart index 7b93a0696a90..43150f63ef93 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_plugin_test.mocks.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Mocks generated by Mockito 5.0.1 from annotations +// Mocks generated by Mockito 5.0.2 from annotations // in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart. // Do not manually edit this file. 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 55f66e2f4e56..6774c09f857d 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 @@ -1,9 +1,10 @@ name: google_maps_flutter_web_integration_tests publish_to: none +# Tests require flutter beta or greater to run. environment: sdk: ">=2.12.0 <3.0.0" - flutter: ">=2.1.0-0" # For integration_test (with null safety) from sdk + flutter: ">=1.27.0" # For integration_test with null safety from sdk (should be >=2.1.0) dependencies: google_maps_flutter_web: @@ -22,3 +23,9 @@ dev_dependencies: sdk: flutter integration_test: sdk: flutter + +# Remove these once environment flutter is set to ">=2.1.0". +# Used to reconcile mockito ^5.0.0 with flutter 2.0.x (current stable). +dependency_overrides: + crypto: ^3.0.0 + convert: ^3.0.0 From 65b6df0abe3256618914f1b722a9a2f1c769e549 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Mon, 29 Mar 2021 19:03:14 -0700 Subject: [PATCH 27/30] Address PR comments (needs tests) --- .../google_maps_flutter_web/example/README.md | 10 +-- .../google_maps_controller_test.dart | 4 +- .../example/integration_test/marker_test.dart | 33 +++++++--- .../example/integration_test/shape_test.dart | 44 ++++++++----- .../example/pubspec.yaml | 7 ++- .../lib/src/convert.dart | 15 ++--- .../lib/src/google_maps_controller.dart | 61 ++++++++++++++++--- .../lib/src/google_maps_flutter_web.dart | 4 +- .../lib/src/marker.dart | 8 +-- 9 files changed, 130 insertions(+), 56 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md index 5753fa876909..582288a561a4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/README.md @@ -24,12 +24,8 @@ Make sure you have updated to the latest Flutter master. There's new `.mocks.dart` files next to the test files that use them. -Mocks are [auto-generated by `package:mockito`](https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#code-generation). +Mock files are [generated by `package:mockito`](https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#code-generation). The contents of these files can change with how the mocks are used within the tests, in addition to actual changes in the APIs they're mocking. -Mocks can be manually re-generated with the following command: `flutter pub run build_runner build`, or by running the `regen_mocks.sh` script. +Mock files can be updated either manually by running the following command: `flutter pub run build_runner build` (or the `regen_mocks.sh` script), or automatically on each call to the `run_test.sh` script. -Mocks may change with changes to the API of the classes they're mocking, but also by how they're used within the tests. - -Remember to regenerate the mocks often, and feel free to commit any changes in them. - -(Mocks will be auto-generated by the `run_test.sh` script as well.) +Please, add whatever changes show up in mock files to your PRs, or CI will fail. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index 768deae615cd..20362fdfc5be 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -44,7 +44,7 @@ void main() { Set polygons = const {}, Set polylines = const {}, Set circles = const {}, - Map? options, + Map options = const {}, }) { return GoogleMapController( mapId: mapId, @@ -54,7 +54,7 @@ void main() { polygons: polygons, polylines: polylines, circles: circles, - mapOptions: options ?? {}); + mapOptions: options,); } setUp(() { diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart index e55d52fde926..2bfa27b73a77 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/marker_test.dart @@ -14,20 +14,26 @@ import 'package:flutter_test/flutter_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - late Completer _called; - late Future called; + // Since onTap/DragEnd events happen asynchronously, we need to store when the event + // is fired. We use a completer so the test can wait for the future to be completed. + late Completer _methodCalledCompleter; + + /// This is the future value of the [_methodCalledCompleter]. Reinitialized + /// in the [setUp] method, and completed (as `true`) by [onTap] and [onDragEnd] + /// when those methods are called from the MarkerController. + late Future methodCalled; void onTap() { - _called.complete(true); + _methodCalledCompleter.complete(true); } void onDragEnd(gmaps.LatLng _) { - _called.complete(true); + _methodCalledCompleter.complete(true); } setUp(() { - _called = Completer(); - called = _called.future; + _methodCalledCompleter = Completer(); + methodCalled = _methodCalledCompleter.future; }); group('MarkerController', () { @@ -44,7 +50,7 @@ void main() { gmaps.Event.trigger(marker, 'click', [gmaps.MapMouseEvent()]); // The event handling is now truly async. Wait for it... - expect(await called, isTrue); + expect(await methodCalled, isTrue); }); testWidgets('onDragEnd gets called', (WidgetTester tester) async { @@ -54,7 +60,7 @@ void main() { gmaps.Event.trigger(marker, 'dragend', [gmaps.MapMouseEvent()..latLng = gmaps.LatLng(0, 0)]); - expect(await called, isTrue); + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { @@ -111,17 +117,20 @@ void main() { final map = gmaps.GMap(html.DivElement()); marker.set('map', map); controller = MarkerController(marker: marker, infoWindow: infoWindow); - - controller.remove(); }); testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + expect(controller.marker, isNull); }); testWidgets('cannot call update after remove', (WidgetTester tester) async { final options = gmaps.MarkerOptions()..draggable = true; + + controller.remove(); + expect(() { controller.update(options); }, throwsAssertionError); @@ -129,6 +138,8 @@ void main() { testWidgets('cannot call showInfoWindow after remove', (WidgetTester tester) async { + controller.remove(); + expect(() { controller.showInfoWindow(); }, throwsAssertionError); @@ -136,6 +147,8 @@ void main() { testWidgets('cannot call hideInfoWindow after remove', (WidgetTester tester) async { + controller.remove(); + expect(() { controller.hideInfoWindow(); }, throwsAssertionError); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart index 9d56c3bcd51e..547aaec6dc0a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/shape_test.dart @@ -13,15 +13,22 @@ import 'package:flutter_test/flutter_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - late Completer _called; - late Future called; + // Since onTap events happen asynchronously, we need to store when the event + // is fired. We use a completer so the test can wait for the future to be completed. + late Completer _methodCalledCompleter; + + /// This is the future value of the [_methodCalledCompleter]. Reinitialized + /// in the [setUp] method, and completed (as `true`) by [onTap], when it gets + /// called by the corresponding Shape Controller. + late Future methodCalled; + void onTap() { - _called.complete(true); + _methodCalledCompleter.complete(true); } setUp(() { - _called = Completer(); - called = _called.future; + _methodCalledCompleter = Completer(); + methodCalled = _methodCalledCompleter.future; }); group('CircleController', () { @@ -38,7 +45,7 @@ void main() { gmaps.Event.trigger(circle, 'click', [gmaps.MapMouseEvent()]); // The event handling is now truly async. Wait for it... - expect(await called, isTrue); + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { @@ -57,17 +64,20 @@ void main() { setUp(() { controller = CircleController(circle: circle); - - controller.remove(); }); testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + expect(controller.circle, isNull); }); testWidgets('cannot call update after remove', (WidgetTester tester) async { final options = gmaps.CircleOptions()..draggable = true; + + controller.remove(); + expect(() { controller.update(options); }, throwsAssertionError); @@ -89,7 +99,7 @@ void main() { gmaps.Event.trigger(polygon, 'click', [gmaps.MapMouseEvent()]); // The event handling is now truly async. Wait for it... - expect(await called, isTrue); + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { @@ -108,17 +118,20 @@ void main() { setUp(() { controller = PolygonController(polygon: polygon); - - controller.remove(); }); testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + expect(controller.polygon, isNull); }); testWidgets('cannot call update after remove', (WidgetTester tester) async { final options = gmaps.PolygonOptions()..draggable = true; + + controller.remove(); + expect(() { controller.update(options); }, throwsAssertionError); @@ -141,7 +154,7 @@ void main() { gmaps.Event.trigger(polyline, 'click', [gmaps.MapMouseEvent()]); // The event handling is now truly async. Wait for it... - expect(await called, isTrue); + expect(await methodCalled, isTrue); }); testWidgets('update', (WidgetTester tester) async { @@ -160,17 +173,20 @@ void main() { setUp(() { controller = PolylineController(polyline: polyline); - - controller.remove(); }); testWidgets('drops gmaps instance', (WidgetTester tester) async { + controller.remove(); + expect(controller.line, isNull); }); testWidgets('cannot call update after remove', (WidgetTester tester) async { final options = gmaps.PolylineOptions()..draggable = true; + + controller.remove(); + expect(() { controller.update(options); }, throwsAssertionError); 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 6774c09f857d..311f05a69dc4 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 @@ -4,7 +4,12 @@ publish_to: none # Tests require flutter beta or greater to run. environment: sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.27.0" # For integration_test with null safety from sdk (should be >=2.1.0) + flutter: ">=2.0.0" + # Actually, Flutter 2.0.0 shipped with a slightly older version of integration_test that + # did *not* support null safety. This flutter constraint should be changed to >=2.1.0 when + # that version (or greater) is shipped to the `stable` channel. + # This causes integration tests to *not* work in `stable`, for now. Please, run integration tests + # in `beta` or newer (flutter/plugins runs these tests in `master`). dependencies: google_maps_flutter_web: diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index e309e00c985a..2e71c795ff0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -177,11 +177,12 @@ CameraPosition _gmViewportToCameraPosition(gmaps.GMap map) { // Marker.fromMarker(anotherMarker, moreOptions); gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { - final markerTitle = marker.infoWindow.title; - final markerSnippet = marker.infoWindow.snippet; + final markerTitle = marker.infoWindow.title ?? ''; + final markerSnippet = marker.infoWindow.snippet ?? ''; - // If both the title and the snippet are null or empty, bail out... - if ((markerTitle?.isEmpty ?? true) && (markerSnippet?.isEmpty ?? true)) { + // If both the title and snippet of an infowindow are empty, we don't really + // want an infowindow... + if ((markerTitle.isEmpty) && (markerSnippet.isEmpty)) { return null; } @@ -190,13 +191,13 @@ gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) { final HtmlElement container = DivElement() ..id = 'gmaps-marker-${marker.markerId.value}-infowindow'; - if (markerTitle != null && markerTitle.isNotEmpty) { + if (markerTitle.isNotEmpty) { final HtmlElement title = HeadingElement.h3() ..className = 'infowindow-title' ..innerText = markerTitle; container.children.add(title); } - if (markerSnippet != null && markerSnippet.isNotEmpty) { + if (markerSnippet.isNotEmpty) { final HtmlElement snippet = DivElement() ..className = 'infowindow-snippet' ..setInnerHtml( @@ -433,7 +434,7 @@ gmaps.LatLng _pixelToLatLng(gmaps.GMap map, int x, int y) { final topRight = projection!.fromLatLngToPoint!(ne)!; final bottomLeft = projection.fromLatLngToPoint!(sw)!; - final scale = 1 << (zoom! as int); // 2 ^ zoom + final scale = 1 << (zoom!.toInt()); // 2 ^ zoom final point = gmaps.Point((x / scale) + bottomLeft.x!, (y / scale) + topRight.y!); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index fe3f42ae1f58..6a6f7b6edf59 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -142,10 +142,11 @@ class GoogleMapController { options = _applyInitialPosition(_initialCameraPosition, options); // Create the map... - _googleMap = _createMap(_div, options); + final map = _createMap(_div, options); + _googleMap = map; - _attachMapEvents(_googleMap!); - _attachGeometryControllers(_googleMap!); + _attachMapEvents(map); + _attachGeometryControllers(map); _renderInitialGeometry( markers: _markers, @@ -154,17 +155,19 @@ class GoogleMapController { polylines: _polylines, ); - _setTrafficLayer(_googleMap!, _isTrafficLayerEnabled(_rawMapOptions)); + _setTrafficLayer(map, _isTrafficLayerEnabled(_rawMapOptions)); } // Funnels map gmap events into the plugin's stream controller. void _attachMapEvents(gmaps.GMap map) { map.onClick.listen((event) { + assert(event.latLng != null); _streamController.add( MapTapEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); }); map.onRightclick.listen((event) { + assert(event.latLng != null); _streamController.add( MapLongPressEvent(_mapId, _gmLatLngToLatLng(event.latLng!)), ); @@ -188,10 +191,20 @@ class GoogleMapController { void _attachGeometryControllers(gmaps.GMap map) { // Now we can add the initial geometry. // And bind the (ready) map instance to the other geometry controllers. + // + // These controllers are either created in the constructor of this class, or + // overriden (for testing) by the [debugSetOverrides] method. They can't be + // null. + assert(_circlesController != null, 'Cannot attach a map to a null CirclesController instance.'); + assert(_polygonsController != null, 'Cannot attach a map to a null PolygonsController instance.'); + assert(_polylinesController != null, 'Cannot attach a map to a null PolylinesController instance.'); + assert(_markersController != null, 'Cannot attach a map to a null MarkersController instance.'); + _circlesController!.bindToMap(_mapId, map); _polygonsController!.bindToMap(_mapId, map); _polylinesController!.bindToMap(_mapId, map); _markersController!.bindToMap(_mapId, map); + _controllersBoundToMap = true; } @@ -206,6 +219,11 @@ class GoogleMapController { _controllersBoundToMap, 'Geometry controllers must be bound to a map before any geometry can ' + 'be added to them. Ensure _attachGeometryControllers is called first.'); + + // The above assert will only succeed if the controllers have been bound to a map + // in the [_attachGeometryControllers] method, which ensures that all these + // controllers below are *not* null. + _markersController!.addMarkers(markers); _circlesController!.addCircles(circles); _polygonsController!.addPolygons(polygons); @@ -227,6 +245,8 @@ class GoogleMapController { /// /// This method converts the map into the proper [gmaps.MapOptions] void updateRawOptions(Map optionsUpdate) { + assert(_googleMap != null, 'Cannot update options on a null map.'); + final newOptions = _mergeRawOptions(optionsUpdate); _setOptions(_rawOptionsToGmapsOptions(newOptions)); @@ -241,8 +261,7 @@ class GoogleMapController { // Attaches/detaches a Traffic Layer on the passed `map` if `attach` is true/false. void _setTrafficLayer(gmaps.GMap map, bool attach) { if (attach && _trafficLayer == null) { - _trafficLayer = gmaps.TrafficLayer(); - _trafficLayer!.set('map', map); + _trafficLayer = gmaps.TrafficLayer()..set('map', map); } if (!attach && _trafficLayer != null) { _trafficLayer!.set('map', null); @@ -255,19 +274,30 @@ class GoogleMapController { /// Returns the [LatLngBounds] of the current viewport. Future getVisibleRegion() async { + assert(_googleMap != null, 'Cannot get the visible region of a null map.'); + return _gmLatLngBoundsTolatLngBounds( - await _googleMap!.bounds ?? _nullGmapsLatLngBounds); + await _googleMap!.bounds ?? _nullGmapsLatLngBounds, + ); } /// Returns the [ScreenCoordinate] for a given viewport [LatLng]. Future getScreenCoordinate(LatLng latLng) async { + assert(_googleMap != null, 'Cannot get the screen coordinates with a null map.'); + assert(_googleMap!.projection != null, 'Cannot compute screen coordinate with a null map or projection.'); + final point = _googleMap!.projection!.fromLatLngToPoint!(_latLngToGmLatLng(latLng))!; - return ScreenCoordinate(x: point.x! as int, y: point.y! as int); + + assert(point.x != null && point.y != null, 'The x and y of a ScreenCoordinate cannot be null.'); + + return ScreenCoordinate(x: point.x!.toInt(), y: point.y!.toInt()); } /// Returns the [LatLng] for a `screenCoordinate` (in pixels) of the viewport. Future getLatLng(ScreenCoordinate screenCoordinate) async { + assert(_googleMap != null, 'Cannot get the lat, lng of a screen coordinate with a null map.'); + final gmaps.LatLng latLng = _pixelToLatLng(_googleMap!, screenCoordinate.x, screenCoordinate.y); return _gmLatLngToLatLng(latLng); @@ -275,16 +305,24 @@ class GoogleMapController { /// Applies a `cameraUpdate` to the current viewport. Future moveCamera(CameraUpdate cameraUpdate) async { + assert(_googleMap != null, 'Cannot update the camera of a null map.'); + return _applyCameraUpdate(_googleMap!, cameraUpdate); } /// Returns the zoom level of the current viewport. - Future getZoomLevel() async => _googleMap!.zoom!.toDouble(); + Future getZoomLevel() async { + assert(_googleMap != null, 'Cannot get zoom level of a null map.'); + assert(_googleMap!.zoom != null, 'Zoom level should not be null. Is the map correctly initialized?'); + + return _googleMap!.zoom!.toDouble(); + } // Geometry manipulation /// Applies [CircleUpdates] to the currently managed circles. void updateCircles(CircleUpdates updates) { + assert(_circlesController != null, 'Cannot update circles after dispose().'); _circlesController?.addCircles(updates.circlesToAdd); _circlesController?.changeCircles(updates.circlesToChange); _circlesController?.removeCircles(updates.circleIdsToRemove); @@ -292,6 +330,7 @@ class GoogleMapController { /// Applies [PolygonUpdates] to the currently managed polygons. void updatePolygons(PolygonUpdates updates) { + assert(_polygonsController != null, 'Cannot update polygons after dispose().'); _polygonsController?.addPolygons(updates.polygonsToAdd); _polygonsController?.changePolygons(updates.polygonsToChange); _polygonsController?.removePolygons(updates.polygonIdsToRemove); @@ -299,6 +338,7 @@ class GoogleMapController { /// Applies [PolylineUpdates] to the currently managed lines. void updatePolylines(PolylineUpdates updates) { + assert(_polylinesController != null, 'Cannot update polylines after dispose().'); _polylinesController?.addPolylines(updates.polylinesToAdd); _polylinesController?.changePolylines(updates.polylinesToChange); _polylinesController?.removePolylines(updates.polylineIdsToRemove); @@ -306,6 +346,7 @@ class GoogleMapController { /// Applies [MarkerUpdates] to the currently managed markers. void updateMarkers(MarkerUpdates updates) { + assert(_markersController != null, 'Cannot update markers after dispose().'); _markersController?.addMarkers(updates.markersToAdd); _markersController?.changeMarkers(updates.markersToChange); _markersController?.removeMarkers(updates.markerIdsToRemove); @@ -313,11 +354,13 @@ class GoogleMapController { /// Shows the [InfoWindow] of the marker identified by its [MarkerId]. void showInfoWindow(MarkerId markerId) { + assert(_markersController != null, 'Cannot show infowindow of marker [${markerId.value}] after dispose().'); _markersController?.showMarkerInfoWindow(markerId); } /// Hides the [InfoWindow] of the marker identified by its [MarkerId]. void hideInfoWindow(MarkerId markerId) { + assert(_markersController != null, 'Cannot hide infowindow of marker [${markerId.value}] after dispose().'); _markersController?.hideMarkerInfoWindow(markerId); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index 629c7eb3b1e6..ddb373689f83 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -288,8 +288,6 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { const >{}, Map mapOptions = const {}, }) { - assert(creationId != null, - 'buildView needs a `_webOnlyMapCreationId` in its creationParams to prevent widget reloads in web.'); // Bail fast if we've already rendered this map ID... if (_mapById[creationId]?.widget != null) { @@ -314,6 +312,8 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { onPlatformViewCreated.call(creationId); + assert(mapController.widget != null, 'The widget of a GoogleMapController cannot be null before calling dispose on it.'); + return mapController.widget!; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart index e73ae4a6e985..5b0169b565e5 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/marker.dart @@ -25,14 +25,14 @@ class MarkerController { _infoWindow = infoWindow, _consumeTapEvents = consumeTapEvents { if (onTap != null) { - _marker!.onClick.listen((event) { + marker.onClick.listen((event) { onTap.call(); }); } if (onDragEnd != null) { - _marker!.onDragend.listen((event) { - if (_marker != null) { - _marker!.position = event.latLng; + marker.onDragend.listen((event) { + if (marker != null) { + marker.position = event.latLng; } onDragEnd.call(event.latLng ?? _nullGmapsLatLng); }); From 870e7591267ec49db314ee5f53c878eebad1fa23 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 30 Mar 2021 15:00:56 -0700 Subject: [PATCH 28/30] Test latest assertions after disposal of maps controller. --- .../google_maps_flutter_web/CHANGELOG.md | 1 + .../google_maps_controller_test.dart | 110 +++++++++++++++++- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index b7f59f78ca86..fd56b64dbe57 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -5,6 +5,7 @@ * The property `icon` of a `Marker` cannot be `null`. Defaults to `BitmapDescriptor.defaultMarker` * The property `initialCameraPosition` of a `GoogleMapController` can't be `null`. It is also marked as `required`. * The parameter `creationId` of the `buildView` method cannot be `null` (this should be handled internally for users of the plugin) + * Most of the Controller methods can't be called after `remove`/`dispose`. Calling these methods now will throw an Assertion error. Before it'd be a no-op, or a null-pointer exception. ## 0.2.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index 20362fdfc5be..e920e955f30c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -79,11 +79,111 @@ void main() { expect(identical(first, again), isTrue); }); - testWidgets('dispose closes the stream and removes the widget', - (WidgetTester tester) async { - controller.dispose(); - expect(stream.isClosed, isTrue); - expect(controller.widget, isNull); + group('dispose', () { + testWidgets('closes the stream and removes the widget', + (WidgetTester tester) async { + controller.dispose(); + + expect(stream.isClosed, isTrue); + expect(controller.widget, isNull); + }); + + testWidgets('cannot call getVisibleRegion after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getVisibleRegion(); + }, throwsAssertionError); + }); + + testWidgets('cannot call getScreenCoordinate after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getScreenCoordinate(LatLng(43.3072465,-5.6918241)); + }, throwsAssertionError); + }); + + testWidgets('cannot call getLatLng after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getLatLng(ScreenCoordinate(x: 640, y: 480)); + }, throwsAssertionError); + }); + + testWidgets('cannot call moveCamera after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.moveCamera(CameraUpdate.zoomIn()); + }, throwsAssertionError); + }); + + testWidgets('cannot call getZoomLevel after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() async { + await controller.getZoomLevel(); + }, throwsAssertionError); + }); + + testWidgets('cannot updateCircles after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updateCircles(CircleUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updatePolygons after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updatePolygons(PolygonUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updatePolylines after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updatePolylines(PolylineUpdates.from({}, {})); + }, throwsAssertionError); + }); + + testWidgets('cannot updateMarkers after dispose', + (WidgetTester tester) async { + controller.dispose(); + + expect(() { + controller.updateMarkers(MarkerUpdates.from({}, {})); + }, throwsAssertionError); + + expect(() { + controller.showInfoWindow(MarkerId('any')); + }, throwsAssertionError); + + expect(() { + controller.hideInfoWindow(MarkerId('any')); + }, throwsAssertionError); + }); + + testWidgets('isInfoWindowShown defaults to false', (WidgetTester tester) async { + controller.dispose(); + + expect( + controller.isInfoWindowShown(MarkerId('any')) + , false); + }); }); }); From 52f6dbd19415cd291a04d256f4a29f0367d950b2 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 30 Mar 2021 15:08:32 -0700 Subject: [PATCH 29/30] dartfmt -w . --- .../google_maps_controller_test.dart | 32 ++++++------ .../lib/src/google_maps_controller.dart | 49 ++++++++++++------- .../lib/src/google_maps_flutter_web.dart | 4 +- 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index e920e955f30c..1d33eea4c7f3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -47,14 +47,15 @@ void main() { Map options = const {}, }) { return GoogleMapController( - mapId: mapId, - streamController: stream, - initialCameraPosition: initialCameraPosition, - markers: markers, - polygons: polygons, - polylines: polylines, - circles: circles, - mapOptions: options,); + mapId: mapId, + streamController: stream, + initialCameraPosition: initialCameraPosition, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + mapOptions: options, + ); } setUp(() { @@ -102,7 +103,9 @@ void main() { controller.dispose(); expect(() async { - await controller.getScreenCoordinate(LatLng(43.3072465,-5.6918241)); + await controller.getScreenCoordinate( + LatLng(43.3072465, -5.6918241), + ); }, throwsAssertionError); }); @@ -111,7 +114,9 @@ void main() { controller.dispose(); expect(() async { - await controller.getLatLng(ScreenCoordinate(x: 640, y: 480)); + await controller.getLatLng( + ScreenCoordinate(x: 640, y: 480), + ); }, throwsAssertionError); }); @@ -177,12 +182,11 @@ void main() { }, throwsAssertionError); }); - testWidgets('isInfoWindowShown defaults to false', (WidgetTester tester) async { + testWidgets('isInfoWindowShown defaults to false', + (WidgetTester tester) async { controller.dispose(); - expect( - controller.isInfoWindowShown(MarkerId('any')) - , false); + expect(controller.isInfoWindowShown(MarkerId('any')), false); }); }); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart index 6a6f7b6edf59..25284909d596 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_controller.dart @@ -195,10 +195,14 @@ class GoogleMapController { // These controllers are either created in the constructor of this class, or // overriden (for testing) by the [debugSetOverrides] method. They can't be // null. - assert(_circlesController != null, 'Cannot attach a map to a null CirclesController instance.'); - assert(_polygonsController != null, 'Cannot attach a map to a null PolygonsController instance.'); - assert(_polylinesController != null, 'Cannot attach a map to a null PolylinesController instance.'); - assert(_markersController != null, 'Cannot attach a map to a null MarkersController instance.'); + assert(_circlesController != null, + 'Cannot attach a map to a null CirclesController instance.'); + assert(_polygonsController != null, + 'Cannot attach a map to a null PolygonsController instance.'); + assert(_polylinesController != null, + 'Cannot attach a map to a null PolylinesController instance.'); + assert(_markersController != null, + 'Cannot attach a map to a null MarkersController instance.'); _circlesController!.bindToMap(_mapId, map); _polygonsController!.bindToMap(_mapId, map); @@ -277,26 +281,30 @@ class GoogleMapController { assert(_googleMap != null, 'Cannot get the visible region of a null map.'); return _gmLatLngBoundsTolatLngBounds( - await _googleMap!.bounds ?? _nullGmapsLatLngBounds, - ); + await _googleMap!.bounds ?? _nullGmapsLatLngBounds, + ); } /// Returns the [ScreenCoordinate] for a given viewport [LatLng]. Future getScreenCoordinate(LatLng latLng) async { - assert(_googleMap != null, 'Cannot get the screen coordinates with a null map.'); - assert(_googleMap!.projection != null, 'Cannot compute screen coordinate with a null map or projection.'); + assert(_googleMap != null, + 'Cannot get the screen coordinates with a null map.'); + assert(_googleMap!.projection != null, + 'Cannot compute screen coordinate with a null map or projection.'); final point = _googleMap!.projection!.fromLatLngToPoint!(_latLngToGmLatLng(latLng))!; - assert(point.x != null && point.y != null, 'The x and y of a ScreenCoordinate cannot be null.'); + assert(point.x != null && point.y != null, + 'The x and y of a ScreenCoordinate cannot be null.'); return ScreenCoordinate(x: point.x!.toInt(), y: point.y!.toInt()); } /// Returns the [LatLng] for a `screenCoordinate` (in pixels) of the viewport. Future getLatLng(ScreenCoordinate screenCoordinate) async { - assert(_googleMap != null, 'Cannot get the lat, lng of a screen coordinate with a null map.'); + assert(_googleMap != null, + 'Cannot get the lat, lng of a screen coordinate with a null map.'); final gmaps.LatLng latLng = _pixelToLatLng(_googleMap!, screenCoordinate.x, screenCoordinate.y); @@ -313,7 +321,8 @@ class GoogleMapController { /// Returns the zoom level of the current viewport. Future getZoomLevel() async { assert(_googleMap != null, 'Cannot get zoom level of a null map.'); - assert(_googleMap!.zoom != null, 'Zoom level should not be null. Is the map correctly initialized?'); + assert(_googleMap!.zoom != null, + 'Zoom level should not be null. Is the map correctly initialized?'); return _googleMap!.zoom!.toDouble(); } @@ -322,7 +331,8 @@ class GoogleMapController { /// Applies [CircleUpdates] to the currently managed circles. void updateCircles(CircleUpdates updates) { - assert(_circlesController != null, 'Cannot update circles after dispose().'); + assert( + _circlesController != null, 'Cannot update circles after dispose().'); _circlesController?.addCircles(updates.circlesToAdd); _circlesController?.changeCircles(updates.circlesToChange); _circlesController?.removeCircles(updates.circleIdsToRemove); @@ -330,7 +340,8 @@ class GoogleMapController { /// Applies [PolygonUpdates] to the currently managed polygons. void updatePolygons(PolygonUpdates updates) { - assert(_polygonsController != null, 'Cannot update polygons after dispose().'); + assert( + _polygonsController != null, 'Cannot update polygons after dispose().'); _polygonsController?.addPolygons(updates.polygonsToAdd); _polygonsController?.changePolygons(updates.polygonsToChange); _polygonsController?.removePolygons(updates.polygonIdsToRemove); @@ -338,7 +349,8 @@ class GoogleMapController { /// Applies [PolylineUpdates] to the currently managed lines. void updatePolylines(PolylineUpdates updates) { - assert(_polylinesController != null, 'Cannot update polylines after dispose().'); + assert(_polylinesController != null, + 'Cannot update polylines after dispose().'); _polylinesController?.addPolylines(updates.polylinesToAdd); _polylinesController?.changePolylines(updates.polylinesToChange); _polylinesController?.removePolylines(updates.polylineIdsToRemove); @@ -346,7 +358,8 @@ class GoogleMapController { /// Applies [MarkerUpdates] to the currently managed markers. void updateMarkers(MarkerUpdates updates) { - assert(_markersController != null, 'Cannot update markers after dispose().'); + assert( + _markersController != null, 'Cannot update markers after dispose().'); _markersController?.addMarkers(updates.markersToAdd); _markersController?.changeMarkers(updates.markersToChange); _markersController?.removeMarkers(updates.markerIdsToRemove); @@ -354,13 +367,15 @@ class GoogleMapController { /// Shows the [InfoWindow] of the marker identified by its [MarkerId]. void showInfoWindow(MarkerId markerId) { - assert(_markersController != null, 'Cannot show infowindow of marker [${markerId.value}] after dispose().'); + assert(_markersController != null, + 'Cannot show infowindow of marker [${markerId.value}] after dispose().'); _markersController?.showMarkerInfoWindow(markerId); } /// Hides the [InfoWindow] of the marker identified by its [MarkerId]. void hideInfoWindow(MarkerId markerId) { - assert(_markersController != null, 'Cannot hide infowindow of marker [${markerId.value}] after dispose().'); + assert(_markersController != null, + 'Cannot hide infowindow of marker [${markerId.value}] after dispose().'); _markersController?.hideMarkerInfoWindow(markerId); } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart index ddb373689f83..692917fef4da 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/google_maps_flutter_web.dart @@ -288,7 +288,6 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { const >{}, Map mapOptions = const {}, }) { - // Bail fast if we've already rendered this map ID... if (_mapById[creationId]?.widget != null) { return _mapById[creationId].widget; @@ -312,7 +311,8 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform { onPlatformViewCreated.call(creationId); - assert(mapController.widget != null, 'The widget of a GoogleMapController cannot be null before calling dispose on it.'); + assert(mapController.widget != null, + 'The widget of a GoogleMapController cannot be null before calling dispose on it.'); return mapController.widget!; } From 0f701b14bd623bd0649afec11a35b5c0f1c5250b Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 30 Mar 2021 15:28:24 -0700 Subject: [PATCH 30/30] Revert no-sound-null-safety in build_all_plugins_app --- script/build_all_plugins_app.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/build_all_plugins_app.sh b/script/build_all_plugins_app.sh index 56b05853fdcb..06566f059a54 100755 --- a/script/build_all_plugins_app.sh +++ b/script/build_all_plugins_app.sh @@ -59,7 +59,7 @@ fi for version in "${BUILD_MODES[@]}"; do echo "Building $version..." - (cd $REPO_DIR/all_plugins && flutter build $@ --$version --no-sound-null-safety) + (cd $REPO_DIR/all_plugins && flutter build $@ --$version) if [ $? -eq 0 ]; then echo "Successfully built $version all_plugins app."