Skip to content

Commit

Permalink
[google_maps_flutter] Add style to widget (flutter#6192)
Browse files Browse the repository at this point in the history
Adds `style` to the `GoogleMap` widget construction, and internally to the `MapConfiguration` structure, wiring updates to style through the existing configuration update system instead of needing to be set via a separate channel. This makes things more consistent (style is conceptually similar to many of the other configuration options, and is not something that's likely to require frequent dynamic updates), and more importantly allows setting the style as part of creation instead of asynchronously after the map has likely already been displayed.

Because of flutter/flutter#24327, this adds a way to query for style errors after the fact. (It's possible that it's why `setMapStyle` was done that way in the first place; the initial PR doesn't explain.) While this is slightly clunky, it's unlikely that this method would actually be used in production code anyway, since presumably people are defining their styles at build time, not runtime, and thus probably don't need runtime error handling. Long term, the solution to this problem is likely to invert the widget/controller relationship, as was done in webview_flutter, but that's a major breaking change and not something we're ready to take on at this point.

Since we don't really want two recommended ways of doing the same thing, this deprecates the existing `setMapStyle` method in favor of the new approach.

Fixes flutter/flutter#66207
  • Loading branch information
stuartmorgan authored and arc-yong committed Jun 14, 2024
1 parent 6d1567c commit 621e04e
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 27 deletions.
11 changes: 8 additions & 3 deletions packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## NEXT

* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1.
## 2.6.0

* Adds `style` to the GoogleMap widget constructor. This allows setting the map
style during creation, avoiding the possibility of the default style being
displayed briefly.
* Deprecates `GoogleMapController.setMapStyle` in favor of setting the style via
the new widget `style` parameter.
* Updates minimum supported SDK version to Flutter 3.19.

## 2.5.3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,28 @@ void runTests() {
await mapIdCompleter.future;
},
);

testWidgets('getStyleError reports last error', (WidgetTester tester) async {
final Key key = GlobalKey();
final Completer<GoogleMapController> controllerCompleter =
Completer<GoogleMapController>();

await pumpMap(
tester,
GoogleMap(
key: key,
initialCameraPosition: kInitialCameraPosition,
style: '[[[this is an invalid style',
onMapCreated: (GoogleMapController controller) {
controllerCompleter.complete(controller);
},
),
);

final GoogleMapController controller = await controllerCompleter.future;
final String? error = await controller.getStyleError();
expect(error, isNotNull);
});
}

/// Repeatedly checks an asynchronous value against a test condition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

// ignore_for_file: public_member_api_docs

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:google_maps_flutter/google_maps_flutter.dart';
Expand Down Expand Up @@ -59,6 +60,7 @@ class MapUiBodyState extends State<MapUiBody> {
bool _myLocationButtonEnabled = true;
late GoogleMapController _controller;
bool _nightMode = false;
String _mapStyle = '';

@override
void initState() {
Expand Down Expand Up @@ -243,27 +245,18 @@ class MapUiBodyState extends State<MapUiBody> {
return rootBundle.loadString(path);
}

void _setMapStyle(String mapStyle) {
setState(() {
_nightMode = true;
_controller.setMapStyle(mapStyle);
});
}

// Should only be called if _isMapCreated is true.
Widget _nightModeToggler() {
assert(_isMapCreated);
return TextButton(
child: Text('${_nightMode ? 'disable' : 'enable'} night mode'),
onPressed: () {
if (_nightMode) {
setState(() {
_nightMode = false;
_controller.setMapStyle(null);
});
} else {
_getFileData('assets/night_mode.json').then(_setMapStyle);
}
onPressed: () async {
_nightMode = !_nightMode;
final String style =
_nightMode ? await _getFileData('assets/night_mode.json') : '';
setState(() {
_mapStyle = style;
});
},
);
}
Expand All @@ -278,6 +271,7 @@ class MapUiBodyState extends State<MapUiBody> {
cameraTargetBounds: _cameraTargetBounds,
minMaxZoomPreference: _minMaxZoomPreference,
mapType: _mapType,
style: _mapStyle,
rotateGesturesEnabled: _rotateGesturesEnabled,
scrollGesturesEnabled: _scrollGesturesEnabled,
tiltGesturesEnabled: _tiltGesturesEnabled,
Expand Down Expand Up @@ -352,5 +346,13 @@ class MapUiBodyState extends State<MapUiBody> {
_controller = controller;
_isMapCreated = true;
});
// Log any style errors to the console for debugging.
if (kDebugMode) {
_controller.getStyleError().then((String? error) {
if (error != null) {
debugPrint(error);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies:
# the parent directory to use the current plugin's version.
path: ../
google_maps_flutter_android: ^2.5.0
google_maps_flutter_platform_interface: ^2.4.0
google_maps_flutter_platform_interface: ^2.5.0

dev_dependencies:
build_runner: ^2.1.10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,17 @@ class GoogleMapController {
/// Also, refer [iOS](https://developers.google.com/maps/documentation/ios-sdk/style-reference)
/// and [Android](https://developers.google.com/maps/documentation/android-sdk/style-reference)
/// style reference for more information regarding the supported styles.
@Deprecated('Use GoogleMap.style instead.')
Future<void> setMapStyle(String? mapStyle) {
return GoogleMapsFlutterPlatform.instance
.setMapStyle(mapStyle, mapId: mapId);
}

/// Returns the last style error, if any.
Future<String?> getStyleError() {
return GoogleMapsFlutterPlatform.instance.getStyleError(mapId: mapId);
}

/// Return [LatLngBounds] defining the region that is visible in a map.
Future<LatLngBounds> getVisibleRegion() {
return GoogleMapsFlutterPlatform.instance.getVisibleRegion(mapId: mapId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class GoogleMap extends StatefulWidget {
const GoogleMap({
super.key,
required this.initialCameraPosition,
this.style,
this.onMapCreated,
this.gestureRecognizers = const <Factory<OneSequenceGestureRecognizer>>{},
this.webGestureHandling,
Expand Down Expand Up @@ -136,6 +137,19 @@ class GoogleMap extends StatefulWidget {
/// The initial position of the map's camera.
final CameraPosition initialCameraPosition;

/// The style for the map.
///
/// Set to null to clear any previous custom styling.
///
/// If problems were detected with the [mapStyle], including un-parsable
/// styling JSON, unrecognized feature type, unrecognized element type, or
/// invalid styler keys, the style is left unchanged, and the error can be
/// retrieved with [GoogleMapController.getStyleError].
///
/// The style string can be generated using the
/// [map style tool](https://mapstyle.withgoogle.com/).
final String? style;

/// True if the map should show a compass when rotated.
final bool compassEnabled;

Expand Down Expand Up @@ -556,5 +570,8 @@ MapConfiguration _configurationFromMapWidget(GoogleMap map) {
trafficEnabled: map.trafficEnabled,
buildingsEnabled: map.buildingsEnabled,
cloudMapId: map.cloudMapId,
// A null style in the widget means no style, which is expressed as '' in
// the configuration to distinguish from no change (null).
style: map.style ?? '',
);
}
14 changes: 7 additions & 7 deletions packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: google_maps_flutter
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
version: 2.5.3
version: 2.6.0

environment:
sdk: ^3.1.0
flutter: ">=3.13.0"
sdk: ^3.3.0
flutter: ">=3.19.0"

flutter:
plugin:
Expand All @@ -21,10 +21,10 @@ flutter:
dependencies:
flutter:
sdk: flutter
google_maps_flutter_android: ^2.5.0
google_maps_flutter_ios: ^2.3.0
google_maps_flutter_platform_interface: ^2.4.0
google_maps_flutter_web: ^0.5.2
google_maps_flutter_android: ^2.7.0
google_maps_flutter_ios: ^2.5.0
google_maps_flutter_platform_interface: ^2.5.0
google_maps_flutter_web: ^0.5.6

dev_dependencies:
flutter_test:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,4 +551,32 @@ void main() {

expect(map.mapConfiguration.buildingsEnabled, true);
});

testWidgets('Can update style', (WidgetTester tester) async {
const String initialStyle = '[]';
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
style: initialStyle,
),
),
);

final PlatformMapStateRecorder map = platform.lastCreatedMap;

expect(map.mapConfiguration.style, initialStyle);

await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: GoogleMap(
initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
),
),
);

expect(map.mapConfiguration.style, '');
});
}

0 comments on commit 621e04e

Please sign in to comment.