Skip to content

Commit

Permalink
[google_maps_flutter] Switch web to structured options (flutter#5965)
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartmorgan authored and mauricioluz committed Jan 26, 2023
1 parent 1b00257 commit 7e76960
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## NEXT
## 0.4.0

* Implements the new platform interface versions of `buildView` and
`updateOptions` with structured option types.
* **BREAKING CHANGE**: No longer implements the unstructured option dictionary
versions of those methods, so this version can only be used with
`google_maps_flutter` 2.1.8 or later.
* Adds `const` constructor parameters in example tests.

## 0.3.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,17 @@ void main() {
GoogleMapController _createController({
CameraPosition initialCameraPosition =
const CameraPosition(target: LatLng(0, 0)),
Set<Marker> markers = const <Marker>{},
Set<Polygon> polygons = const <Polygon>{},
Set<Polyline> polylines = const <Polyline>{},
Set<Circle> circles = const <Circle>{},
Map<String, dynamic> options = const <String, dynamic>{},
MapObjects mapObjects = const MapObjects(),
MapConfiguration mapConfiguration = const MapConfiguration(),
}) {
return GoogleMapController(
mapId: mapId,
streamController: stream,
initialCameraPosition: initialCameraPosition,
markers: markers,
polygons: polygons,
polylines: polylines,
circles: circles,
mapOptions: options,
widgetConfiguration: MapWidgetConfiguration(
initialCameraPosition: initialCameraPosition,
textDirection: TextDirection.ltr),
mapObjects: mapObjects,
mapConfiguration: mapConfiguration,
);
}

Expand Down Expand Up @@ -284,7 +280,8 @@ void main() {
});

testWidgets('renders initial geometry', (WidgetTester tester) async {
controller = _createController(circles: <Circle>{
controller = _createController(
mapObjects: MapObjects(circles: <Circle>{
const Circle(
circleId: CircleId('circle-1'),
zIndex: 1234,
Expand Down Expand Up @@ -327,7 +324,7 @@ void main() {
LatLng(43.354469, -5.851318),
LatLng(43.354762, -5.850824),
])
});
}));

controller.debugSetOverrides(
circles: circles,
Expand Down Expand Up @@ -363,9 +360,10 @@ void main() {

testWidgets('empty infoWindow does not create InfoWindow instance.',
(WidgetTester tester) async {
controller = _createController(markers: <Marker>{
controller = _createController(
mapObjects: MapObjects(markers: <Marker>{
const Marker(markerId: MarkerId('marker-1')),
});
}));

controller.debugSetOverrides(
markers: markers,
Expand All @@ -385,10 +383,11 @@ void main() {
capturedOptions = null;
});
testWidgets('translates initial options', (WidgetTester tester) async {
controller = _createController(options: <String, dynamic>{
'mapType': 2,
'zoomControlsEnabled': true,
});
controller = _createController(
mapConfiguration: const MapConfiguration(
mapType: MapType.satellite,
zoomControlsEnabled: true,
));
controller.debugSetOverrides(
createMap: (_, gmaps.MapOptions options) {
capturedOptions = options;
Expand All @@ -407,9 +406,10 @@ void main() {

testWidgets('disables gestureHandling with scrollGesturesEnabled false',
(WidgetTester tester) async {
controller = _createController(options: <String, dynamic>{
'scrollGesturesEnabled': false,
});
controller = _createController(
mapConfiguration: const MapConfiguration(
scrollGesturesEnabled: false,
));
controller.debugSetOverrides(
createMap: (_, gmaps.MapOptions options) {
capturedOptions = options;
Expand All @@ -426,9 +426,10 @@ void main() {

testWidgets('disables gestureHandling with zoomGesturesEnabled false',
(WidgetTester tester) async {
controller = _createController(options: <String, dynamic>{
'zoomGesturesEnabled': false,
});
controller = _createController(
mapConfiguration: const MapConfiguration(
zoomGesturesEnabled: false,
));
controller.debugSetOverrides(
createMap: (_, gmaps.MapOptions options) {
capturedOptions = options;
Expand Down Expand Up @@ -477,9 +478,10 @@ void main() {

testWidgets('initializes with traffic layer',
(WidgetTester tester) async {
controller = _createController(options: <String, dynamic>{
'trafficEnabled': true,
});
controller = _createController(
mapConfiguration: const MapConfiguration(
trafficEnabled: true,
));
controller.debugSetOverrides(createMap: (_, __) => map);
controller.init();
expect(controller.trafficLayer, isNotNull);
Expand All @@ -505,25 +507,25 @@ void main() {

group('updateRawOptions', () {
testWidgets('can update `options`', (WidgetTester tester) async {
controller.updateRawOptions(<String, dynamic>{
'mapType': 2,
});
controller.updateMapConfiguration(const MapConfiguration(
mapType: MapType.satellite,
));

expect(map.mapTypeId, gmaps.MapTypeId.SATELLITE);
});

testWidgets('can turn on/off traffic', (WidgetTester tester) async {
expect(controller.trafficLayer, isNull);

controller.updateRawOptions(<String, dynamic>{
'trafficEnabled': true,
});
controller.updateMapConfiguration(const MapConfiguration(
trafficEnabled: true,
));

expect(controller.trafficLayer, isNotNull);

controller.updateRawOptions(<String, dynamic>{
'trafficEnabled': false,
});
controller.updateMapConfiguration(const MapConfiguration(
trafficEnabled: false,
));

expect(controller.trafficLayer, isNull);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,13 @@ void main() {
<int, GoogleMapController>{};
plugin.debugSetMapById(cache);

final Widget widget = plugin.buildView(
final Widget widget = plugin.buildViewWithConfiguration(
testMapId,
onPlatformViewCreated,
initialCameraPosition: initialCameraPosition,
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition: initialCameraPosition,
textDirection: TextDirection.ltr,
),
);

expect(widget, isA<HtmlElementView>());
Expand Down Expand Up @@ -114,10 +117,13 @@ void main() {
testMapId: controller,
});

final Widget widget = plugin.buildView(
final Widget widget = plugin.buildViewWithConfiguration(
testMapId,
onPlatformViewCreated,
initialCameraPosition: initialCameraPosition,
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition: initialCameraPosition,
textDirection: TextDirection.ltr,
),
);

expect(widget, equals(expected));
Expand All @@ -130,10 +136,13 @@ void main() {
<int, GoogleMapController>{};
plugin.debugSetMapById(cache);

plugin.buildView(
plugin.buildViewWithConfiguration(
testMapId,
onPlatformViewCreated,
initialCameraPosition: initialCameraPosition,
widgetConfiguration: const MapWidgetConfiguration(
initialCameraPosition: initialCameraPosition,
textDirection: TextDirection.ltr,
),
);

// Simulate Google Maps JS SDK being "ready"
Expand Down Expand Up @@ -176,11 +185,10 @@ void main() {
await plugin.setMapStyle(mapStyle, mapId: 0);

final dynamic captured =
verify(controller.updateRawOptions(captureThat(isMap))).captured[0];
verify(controller.updateStyles(captureThat(isList))).captured[0];

expect(captured, contains('styles'));
final List<gmaps.MapTypeStyle> styles =
captured['styles'] as List<gmaps.MapTypeStyle>;
captured as List<gmaps.MapTypeStyle>;
expect(styles.length, 1);
// Let's peek inside the styles...
final gmaps.MapTypeStyle style = styles[0];
Expand Down Expand Up @@ -221,14 +229,13 @@ void main() {
plugin.debugSetMapById(<int, GoogleMapController>{mapId: controller});
});
// Options
testWidgets('updateMapOptions', (WidgetTester tester) async {
final Map<String, dynamic> expectedMapOptions = <String, dynamic>{
'someOption': 12345
};
testWidgets('updateMapConfiguration', (WidgetTester tester) async {
const MapConfiguration configuration =
MapConfiguration(mapType: MapType.satellite);

await plugin.updateMapOptions(expectedMapOptions, mapId: mapId);
await plugin.updateMapConfiguration(configuration, mapId: mapId);

verify(controller.updateRawOptions(expectedMapOptions));
verify(controller.updateMapConfiguration(configuration));
});
// Geometry
testWidgets('updateMarkers', (WidgetTester tester) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async' as _i2;

import 'package:google_maps/google_maps.dart' as _i5;
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'
as _i3;
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i4;
Expand Down Expand Up @@ -68,8 +69,12 @@ class MockGoogleMapController extends _i1.Mock
void init() => super.noSuchMethod(Invocation.method(#init, []),
returnValueForMissingStub: null);
@override
void updateRawOptions(Map<String, dynamic>? optionsUpdate) =>
super.noSuchMethod(Invocation.method(#updateRawOptions, [optionsUpdate]),
void updateMapConfiguration(_i3.MapConfiguration? update) =>
super.noSuchMethod(Invocation.method(#updateMapConfiguration, [update]),
returnValueForMissingStub: null);
@override
void updateStyles(List<_i5.MapTypeStyle>? styles) =>
super.noSuchMethod(Invocation.method(#updateStyles, [styles]),
returnValueForMissingStub: null);
@override
_i2.Future<_i3.LatLngBounds> getVisibleRegion() => (super.noSuchMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import 'dart:html';
import 'dart:js_util';

import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@ final gmaps.LatLngBounds _nullGmapsLatLngBounds =
const String _defaultCssColor = '#000000';
const double _defaultCssOpacity = 0.0;

// Indices in the plugin side don't match with the ones
// in the gmaps lib. This translates from plugin -> gmaps.
final Map<int, gmaps.MapTypeId> _mapTypeToMapTypeId = <int, gmaps.MapTypeId>{
0: gmaps.MapTypeId.ROADMAP, // "none" in the plugin
1: gmaps.MapTypeId.ROADMAP,
2: gmaps.MapTypeId.SATELLITE,
3: gmaps.MapTypeId.TERRAIN,
4: gmaps.MapTypeId.HYBRID,
};

// Converts a [Color] into a valid CSS value #RRGGBB.
String _getCssColor(Color color) {
if (color == null) {
Expand Down Expand Up @@ -55,49 +45,64 @@ double _getCssOpacity(Color color) {
// indoorViewEnabled seems to not have an equivalent in web
// buildingsEnabled seems to not have an equivalent in web
// padding seems to behave differently in web than mobile. You can't move UI elements in web.
gmaps.MapOptions _rawOptionsToGmapsOptions(Map<String, Object?> rawOptions) {
gmaps.MapOptions _configurationAndStyleToGmapsOptions(
MapConfiguration configuration, List<gmaps.MapTypeStyle> styles) {
final gmaps.MapOptions options = gmaps.MapOptions();

if (_mapTypeToMapTypeId.containsKey(rawOptions['mapType'])) {
options.mapTypeId = _mapTypeToMapTypeId[rawOptions['mapType']];
if (configuration.mapType != null) {
options.mapTypeId = _gmapTypeIDForPluginType(configuration.mapType!);
}

if (rawOptions['minMaxZoomPreference'] != null) {
final List<Object?> minMaxPreference =
rawOptions['minMaxZoomPreference']! as List<Object?>;
final MinMaxZoomPreference? zoomPreference =
configuration.minMaxZoomPreference;
if (zoomPreference != null) {
options
..minZoom = minMaxPreference[0] as num?
..maxZoom = minMaxPreference[1] as num?;
..minZoom = zoomPreference.minZoom
..maxZoom = zoomPreference.maxZoom;
}

if (rawOptions['cameraTargetBounds'] != null) {
if (configuration.cameraTargetBounds != null) {
// Needs gmaps.MapOptions.restriction and gmaps.MapRestriction
// see: https://developers.google.com/maps/documentation/javascript/reference/map#MapOptions.restriction
}

if (rawOptions['zoomControlsEnabled'] != null) {
options.zoomControl = rawOptions['zoomControlsEnabled'] as bool?;
}

if (rawOptions['styles'] != null) {
options.styles = rawOptions['styles'] as List<gmaps.MapTypeStyle?>?;
if (configuration.zoomControlsEnabled != null) {
options.zoomControl = configuration.zoomControlsEnabled;
}

if (rawOptions['scrollGesturesEnabled'] == false ||
rawOptions['zoomGesturesEnabled'] == false) {
if (configuration.scrollGesturesEnabled == false ||
configuration.zoomGesturesEnabled == false) {
options.gestureHandling = 'none';
} else {
options.gestureHandling = 'auto';
}

// These don't have any rawOptions entry, but they seem to be off in the native maps.
// These don't have any configuration entries, but they seem to be off in the
// native maps.
options.mapTypeControl = false;
options.fullscreenControl = false;
options.streetViewControl = false;

options.styles = styles;

return options;
}

gmaps.MapTypeId _gmapTypeIDForPluginType(MapType type) {
switch (type) {
case MapType.satellite:
return gmaps.MapTypeId.SATELLITE;
case MapType.terrain:
return gmaps.MapTypeId.TERRAIN;
case MapType.hybrid:
return gmaps.MapTypeId.HYBRID;
case MapType.normal:
case MapType.none:
default:
return gmaps.MapTypeId.ROADMAP;
}
}

gmaps.MapOptions _applyInitialPosition(
CameraPosition initialPosition,
gmaps.MapOptions options,
Expand All @@ -111,11 +116,6 @@ gmaps.MapOptions _applyInitialPosition(
return options;
}

// Extracts the status of the traffic layer from the rawOptions map.
bool _isTrafficLayerEnabled(Map<String, Object?> rawOptions) {
return rawOptions['trafficEnabled'] as bool? ?? false;
}

// The keys we'd expect to see in a serialized MapTypeStyle JSON object.
final Set<String> _mapStyleKeys = <String>{
'elementType',
Expand Down
Loading

0 comments on commit 7e76960

Please sign in to comment.