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 1d40d67ccdf2..e4918ab1d5ca 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,10 @@ +## 0.1.0+5 + +* Update `package:google_maps` to `^3.4.5`. +* Fix `GoogleMapController.getLatLng()`. [Issue](https://github.com/flutter/flutter/issues/67606). +* Make `InfoWindow` contents clickable so `onTap` works as advertised. [Issue](https://github.com/flutter/flutter/issues/67289). +* Fix `InfoWindow` snippets when converting initial markers. [Issue](https://github.com/flutter/flutter/issues/67854). + ## 0.1.0+4 * Update `package:sanitize_html` to `^1.4.1` to prevent [a crash](https://github.com/flutter/flutter/issues/67854) when InfoWindow title/snippet have links. 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 3e1b1f182fc9..e8847fdd7b84 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 @@ -270,14 +270,15 @@ Set _rawOptionsToInitialMarkers(Map rawOptions) { if (rawMarker['position'] != null) { position = LatLng.fromJson(rawMarker['position']); } - if (rawMarker['infoWindow'] != null || rawMarker['snippet'] != null) { - String title = rawMarker['infoWindow'] != null - ? rawMarker['infoWindow']['title'] - : null; - infoWindow = InfoWindow( - title: title ?? '', - snippet: rawMarker['snippet'] ?? '', - ); + if (rawMarker['infoWindow'] != null) { + final String title = rawMarker['infoWindow']['title']; + final String snippet = rawMarker['infoWindow']['snippet']; + if (title != null || snippet != null) { + infoWindow = InfoWindow( + title: title ?? '', + snippet: snippet ?? '', + ); + } } return Marker( markerId: MarkerId(rawMarker['markerId']), @@ -378,13 +379,28 @@ gmaps.InfoWindowOptions _infoWindowOptionsFromMarker(Marker marker) { return null; } - final content = '

' + - sanitizeHtml(marker.infoWindow.title ?? "") + - '

' + - sanitizeHtml(marker.infoWindow.snippet ?? ""); + // Add an outer wrapper to the contents of the infowindow, we need it to listen + // to click events... + final HtmlElement container = DivElement() + ..id = 'gmaps-marker-${marker.markerId.value}-infowindow'; + if (marker.infoWindow.title?.isNotEmpty ?? false) { + final HtmlElement title = HeadingElement.h3() + ..className = '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), + treeSanitizer: NodeTreeSanitizer.trusted, + ); + container.children.add(snippet); + } return gmaps.InfoWindowOptions() - ..content = content + ..content = container ..zIndex = marker.zIndex; // TODO: Compute the pixelOffset of the infoWindow, from the size of the Marker, // and the marker.infoWindow.anchor property. 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 707af828e2c6..8195473ee6ba 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 @@ -256,9 +256,8 @@ class GoogleMapController { /// Returns the [LatLng] for a `screenCoordinate` (in pixels) of the viewport. Future getLatLng(ScreenCoordinate screenCoordinate) async { - final latLng = _googleMap.projection.fromPointToLatLng( - gmaps.Point(screenCoordinate.x, screenCoordinate.y), - ); + final gmaps.LatLng latLng = + _pixelToLatLng(_googleMap, screenCoordinate.x, screenCoordinate.y); return _gmLatLngToLatLng(latLng); } 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 a067e352732f..30db477ee5f4 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 @@ -46,6 +46,10 @@ class MarkerController { /// Returns the [gmaps.Marker] associated to this controller. gmaps.Marker get marker => _marker; + /// Returns the [gmaps.InfoWindow] associated to the marker. + @visibleForTesting + gmaps.InfoWindow get infoWindow => _infoWindow; + /// Updates the options of the wrapped [gmaps.Marker] object. void update( gmaps.MarkerOptions options, { 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 ebb478d20b06..a0428adcdc2e 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 @@ -38,10 +38,14 @@ class MarkersController extends GeometryController { gmaps.InfoWindow gmInfoWindow; if (infoWindowOptions != null) { - gmInfoWindow = gmaps.InfoWindow(infoWindowOptions) - ..addListener('click', () { + 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((_) { _onInfoWindowTap(marker.markerId); }); + } } final currentMarker = _markerIdToController[marker.markerId]?.marker; 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 6d0c917631bd..a44d5c185c1f 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.1.0+4 +version: 0.1.0+5 flutter: plugin: @@ -17,7 +17,7 @@ dependencies: sdk: flutter meta: ^1.1.7 google_maps_flutter_platform_interface: ^1.0.4 - google_maps: ^3.0.0 + google_maps: ^3.4.5 stream_transform: ^1.2.0 sanitize_html: ^1.4.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart index 625ecb355a31..dfd01c6faf55 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/google_maps_controller_integration.dart @@ -146,7 +146,13 @@ void main() { {'circleId': 'circle-1'} ], 'markersToAdd': [ - {'markerId': 'marker-1'} + { + 'markerId': 'marker-1', + 'infoWindow': { + 'title': 'title for test', + 'snippet': 'snippet for test', + }, + }, ], 'polygonsToAdd': [ { @@ -191,10 +197,34 @@ void main() { expect(capturedCircles.first.circleId.value, 'circle-1'); expect(capturedMarkers.first.markerId.value, 'marker-1'); + expect(capturedMarkers.first.infoWindow.snippet, 'snippet for test'); + expect(capturedMarkers.first.infoWindow.title, 'title for test'); expect(capturedPolygons.first.polygonId.value, 'polygon-1'); expect(capturedPolylines.first.polylineId.value, 'polyline-1'); }); + testWidgets('empty infoWindow does not create InfoWindow instance.', + (WidgetTester tester) async { + controller = _createController(options: { + 'markersToAdd': [ + { + 'markerId': 'marker-1', + 'infoWindow': {}, + }, + ], + }); + controller.debugSetOverrides( + markers: markers, + ); + + controller.init(); + + final capturedMarkers = + verify(markers.addMarkers(captureAny)).captured[0] as Set; + + expect(capturedMarkers.first.infoWindow, isNull); + }); + group('Initialization options', () { gmaps.MapOptions capturedOptions; setUp(() { @@ -390,6 +420,8 @@ void main() { group('map.projection methods', () { // These are too much for dart mockito, can't mock: // map.projection.method() (in Javascript ;) ) + + // Caused https://github.com/flutter/flutter/issues/67606 }); }); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart index 75e1af708010..a813ff86188e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/test/test_driver/markers_integration.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:html'; import 'package:integration_test/integration_test.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -127,8 +128,39 @@ void main() { controller.addMarkers(markers); expect(controller.markers.length, 1); - expect(controller.markers[MarkerId('1')].marker.title, - equals('title for test')); + final content = + controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + expect(content.innerHtml, contains('title for test')); + expect( + content.innerHtml, + contains( + 'Go to Google >>>')); + }); + + // https://github.com/flutter/flutter/issues/67289 + testWidgets('InfoWindow content is clickable', (WidgetTester tester) async { + final markers = { + Marker( + markerId: MarkerId('1'), + infoWindow: InfoWindow( + title: 'title for test', + snippet: 'some snippet', + ), + ), + }; + + controller.addMarkers(markers); + + expect(controller.markers.length, 1); + final content = + controller.markers[MarkerId('1')].infoWindow.content as HtmlElement; + + content.click(); + + final event = await stream.stream.first; + + expect(event, isA()); + expect((event as InfoWindowTapEvent).value, equals(MarkerId('1'))); }); }); }