mirror of
https://github.com/flutter/packages.git
synced 2025-06-30 23:03:11 +08:00
[google_maps] Prepares packages to endorse web. (#4064)
Prepares the google_maps packages to endorse the Web platform: * `[google_maps_flutter]` Changes `example/integration_test` to run in the web. * Splits the only file there in 3 for them to be slightly more manageable. * (Does not require publishing) * `[google_maps_flutter_platform_interface]` Adds a test coming from the core plugin to the unit tests of this package. * (Does not require publishing) * `[google_maps_flutter_web]` Changes to add an "inspector" object, and to conform with the tests in the core package. * Implements a `GoogleMapsInspectorPlatform` to allow integration tests to inspect parts of the internal state of a gmap. * Fires a `MapStyleException` when an invalid JSON is used in `setMapStyle` (was `FormatException` previously), to conform with the expected behavior in the core plugin tests. * (Requires publishing) ## Issues * Part of: https://github.com/flutter/flutter/issues/80688
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,439 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'shared.dart';
|
||||
|
||||
/// Integration Tests that only need a standard [GoogleMapController].
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
runTests();
|
||||
}
|
||||
|
||||
void runTests() {
|
||||
testWidgets('testInitialCenterLocationAtCenter', (WidgetTester tester) async {
|
||||
await tester.binding.setSurfaceSize(const Size(800, 600));
|
||||
|
||||
final Completer<GoogleMapController> mapControllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
final Key key = GlobalKey();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapControllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
final GoogleMapController mapController =
|
||||
await mapControllerCompleter.future;
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
|
||||
// in `mapRendered`.
|
||||
// https://github.com/flutter/flutter/issues/54758
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final ScreenCoordinate coordinate =
|
||||
await mapController.getScreenCoordinate(kInitialCameraPosition.target);
|
||||
final Rect rect = tester.getRect(find.byKey(key));
|
||||
if (isIOS || isWeb) {
|
||||
// On iOS, the coordinate value from the GoogleMapSdk doesn't include the devicePixelRatio`.
|
||||
// So we don't need to do the conversion like we did below for other platforms.
|
||||
expect(coordinate.x, (rect.center.dx - rect.topLeft.dx).round());
|
||||
expect(coordinate.y, (rect.center.dy - rect.topLeft.dy).round());
|
||||
} else {
|
||||
expect(
|
||||
coordinate.x,
|
||||
((rect.center.dx - rect.topLeft.dx) *
|
||||
// TODO(pdblasi-google): Update `window` usages to new API after 3.9.0 is in stable. https://github.com/flutter/flutter/issues/122912
|
||||
// ignore: deprecated_member_use
|
||||
tester.binding.window.devicePixelRatio)
|
||||
.round());
|
||||
expect(
|
||||
coordinate.y,
|
||||
((rect.center.dy - rect.topLeft.dy) *
|
||||
// TODO(pdblasi-google): Update `window` usages to new API after 3.9.0 is in stable. https://github.com/flutter/flutter/issues/122912
|
||||
// ignore: deprecated_member_use
|
||||
tester.binding.window.devicePixelRatio)
|
||||
.round());
|
||||
}
|
||||
await tester.binding.setSurfaceSize(null);
|
||||
},
|
||||
// Android doesn't like the layout required for the web, so we skip web in this test.
|
||||
// The equivalent web test already exists here:
|
||||
// https://github.com/flutter/packages/blob/c43cc13498a1a1c4f3d1b8af2add9ce7c15bd6d0/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/projection_test.dart#L78
|
||||
skip: isWeb);
|
||||
|
||||
testWidgets('testGetVisibleRegion', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final LatLngBounds zeroLatLngBounds = LatLngBounds(
|
||||
southwest: const LatLng(0, 0), northeast: const LatLng(0, 0));
|
||||
|
||||
final Completer<GoogleMapController> mapControllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapControllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final GoogleMapController mapController =
|
||||
await mapControllerCompleter.future;
|
||||
|
||||
// Wait for the visible region to be non-zero.
|
||||
final LatLngBounds firstVisibleRegion =
|
||||
await waitForValueMatchingPredicate<LatLngBounds>(
|
||||
tester,
|
||||
() => mapController.getVisibleRegion(),
|
||||
(LatLngBounds bounds) => bounds != zeroLatLngBounds) ??
|
||||
zeroLatLngBounds;
|
||||
expect(firstVisibleRegion, isNot(zeroLatLngBounds));
|
||||
expect(firstVisibleRegion.contains(kInitialMapCenter), isTrue);
|
||||
|
||||
// Making a new `LatLngBounds` about (10, 10) distance south west to the `firstVisibleRegion`.
|
||||
// The size of the `LatLngBounds` is 10 by 10.
|
||||
final LatLng southWest = LatLng(firstVisibleRegion.southwest.latitude - 20,
|
||||
firstVisibleRegion.southwest.longitude - 20);
|
||||
final LatLng northEast = LatLng(firstVisibleRegion.southwest.latitude - 10,
|
||||
firstVisibleRegion.southwest.longitude - 10);
|
||||
final LatLng newCenter = LatLng(
|
||||
(northEast.latitude + southWest.latitude) / 2,
|
||||
(northEast.longitude + southWest.longitude) / 2,
|
||||
);
|
||||
|
||||
expect(firstVisibleRegion.contains(northEast), isFalse);
|
||||
expect(firstVisibleRegion.contains(southWest), isFalse);
|
||||
|
||||
final LatLngBounds latLngBounds =
|
||||
LatLngBounds(southwest: southWest, northeast: northEast);
|
||||
|
||||
// TODO(iskakaushik): non-zero padding is needed for some device configurations
|
||||
// https://github.com/flutter/flutter/issues/30575
|
||||
const double padding = 0;
|
||||
await mapController
|
||||
.moveCamera(CameraUpdate.newLatLngBounds(latLngBounds, padding));
|
||||
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||
|
||||
final LatLngBounds secondVisibleRegion =
|
||||
await mapController.getVisibleRegion();
|
||||
|
||||
expect(secondVisibleRegion, isNot(zeroLatLngBounds));
|
||||
|
||||
expect(firstVisibleRegion, isNot(secondVisibleRegion));
|
||||
expect(secondVisibleRegion.contains(newCenter), isTrue);
|
||||
});
|
||||
|
||||
testWidgets('testSetMapStyle valid Json String', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
const String mapStyle =
|
||||
'[{"elementType":"geometry","stylers":[{"color":"#242f3e"}]}]';
|
||||
await controller.setMapStyle(mapStyle);
|
||||
});
|
||||
|
||||
testWidgets('testSetMapStyle invalid Json String',
|
||||
(WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
try {
|
||||
await controller.setMapStyle('invalid_value');
|
||||
fail('expected MapStyleException');
|
||||
} on MapStyleException catch (e) {
|
||||
expect(e.cause, isNotNull);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('testSetMapStyle null string', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
await controller.setMapStyle(null);
|
||||
});
|
||||
|
||||
testWidgets('testGetLatLng', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
// TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
|
||||
// in `mapRendered`.
|
||||
// https://github.com/flutter/flutter/issues/54758
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final LatLngBounds visibleRegion = await controller.getVisibleRegion();
|
||||
final LatLng topLeft =
|
||||
await controller.getLatLng(const ScreenCoordinate(x: 0, y: 0));
|
||||
final LatLng northWest = LatLng(
|
||||
visibleRegion.northeast.latitude,
|
||||
visibleRegion.southwest.longitude,
|
||||
);
|
||||
|
||||
expect(topLeft, northWest);
|
||||
});
|
||||
|
||||
testWidgets('testGetZoomLevel', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
// TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
|
||||
// in `mapRendered`.
|
||||
// https://github.com/flutter/flutter/issues/54758
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
double zoom = await controller.getZoomLevel();
|
||||
expect(zoom, kInitialZoomLevel);
|
||||
|
||||
await controller.moveCamera(CameraUpdate.zoomTo(7));
|
||||
await tester.pumpAndSettle();
|
||||
zoom = await controller.getZoomLevel();
|
||||
expect(zoom, equals(7));
|
||||
});
|
||||
|
||||
testWidgets('testScreenCoordinate', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
// TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
|
||||
// in `mapRendered`.
|
||||
// https://github.com/flutter/flutter/issues/54758
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
final LatLngBounds visibleRegion = await controller.getVisibleRegion();
|
||||
final LatLng northWest = LatLng(
|
||||
visibleRegion.northeast.latitude,
|
||||
visibleRegion.southwest.longitude,
|
||||
);
|
||||
final ScreenCoordinate topLeft =
|
||||
await controller.getScreenCoordinate(northWest);
|
||||
expect(topLeft, const ScreenCoordinate(x: 0, y: 0));
|
||||
});
|
||||
|
||||
testWidgets('testResizeWidget', (WidgetTester tester) async {
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) async {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
const Size(100, 100),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) async {
|
||||
// fail!
|
||||
fail('The map should not get recreated!');
|
||||
// controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
const Size(400, 400),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
// TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen
|
||||
// in `mapRendered`.
|
||||
// https://github.com/flutter/flutter/issues/54758
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
|
||||
// Simple call to make sure that the app hasn't crashed.
|
||||
final LatLngBounds bounds1 = await controller.getVisibleRegion();
|
||||
final LatLngBounds bounds2 = await controller.getVisibleRegion();
|
||||
expect(bounds1, bounds2);
|
||||
});
|
||||
|
||||
testWidgets('testToggleInfoWindow', (WidgetTester tester) async {
|
||||
const Marker marker = Marker(
|
||||
markerId: MarkerId('marker'),
|
||||
infoWindow: InfoWindow(title: 'InfoWindow'));
|
||||
final Set<Marker> markers = <Marker>{marker};
|
||||
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)),
|
||||
markers: markers,
|
||||
onMapCreated: (GoogleMapController googleMapController) {
|
||||
controllerCompleter.complete(googleMapController);
|
||||
},
|
||||
),
|
||||
);
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
bool iwVisibleStatus =
|
||||
await controller.isMarkerInfoWindowShown(marker.markerId);
|
||||
expect(iwVisibleStatus, false);
|
||||
|
||||
await controller.showMarkerInfoWindow(marker.markerId);
|
||||
// The Maps SDK doesn't always return true for whether it is shown
|
||||
// immediately after showing it, so wait for it to report as shown.
|
||||
iwVisibleStatus = await waitForValueMatchingPredicate<bool>(
|
||||
tester,
|
||||
() => controller.isMarkerInfoWindowShown(marker.markerId),
|
||||
(bool visible) => visible) ??
|
||||
false;
|
||||
expect(iwVisibleStatus, true);
|
||||
|
||||
await controller.hideMarkerInfoWindow(marker.markerId);
|
||||
iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId);
|
||||
expect(iwVisibleStatus, false);
|
||||
});
|
||||
|
||||
testWidgets('testTakeSnapshot', (WidgetTester tester) async {
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
controllerCompleter.complete(controller);
|
||||
},
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
final Uint8List? bytes = await controller.takeSnapshot();
|
||||
expect(bytes?.isNotEmpty, true);
|
||||
},
|
||||
// TODO(cyanglaz): un-skip the test when we can test this on CI with API key enabled.
|
||||
// https://github.com/flutter/flutter/issues/57057
|
||||
skip: isAndroid || isWeb);
|
||||
}
|
||||
|
||||
/// Repeatedly checks an asynchronous value against a test condition.
|
||||
///
|
||||
/// This function waits one frame between each check, returning the value if it
|
||||
/// passes the predicate before [maxTries] is reached.
|
||||
///
|
||||
/// Returns null if the predicate is never satisfied.
|
||||
///
|
||||
/// This is useful for cases where the Maps SDK has some internally
|
||||
/// asynchronous operation that we don't have visibility into (e.g., native UI
|
||||
/// animations).
|
||||
Future<T?> waitForValueMatchingPredicate<T>(WidgetTester tester,
|
||||
Future<T> Function() getValue, bool Function(T) predicate,
|
||||
{int maxTries = 100}) async {
|
||||
for (int i = 0; i < maxTries; i++) {
|
||||
final T value = await getValue();
|
||||
if (predicate(value)) {
|
||||
return value;
|
||||
}
|
||||
await tester.pump();
|
||||
}
|
||||
return null;
|
||||
}
|
@ -0,0 +1,536 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'shared.dart';
|
||||
|
||||
/// Integration Tests that use the [GoogleMapsInspectorPlatform].
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
runTests();
|
||||
}
|
||||
|
||||
void runTests() {
|
||||
GoogleMapsFlutterPlatform.instance.enableDebugInspection();
|
||||
|
||||
final GoogleMapsInspectorPlatform inspector =
|
||||
GoogleMapsInspectorPlatform.instance!;
|
||||
|
||||
testWidgets('testCompassToggle', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
compassEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool compassEnabled = await inspector.isCompassEnabled(mapId: mapId);
|
||||
expect(compassEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
compassEnabled = await inspector.isCompassEnabled(mapId: mapId);
|
||||
expect(compassEnabled, !kIsWeb);
|
||||
});
|
||||
|
||||
testWidgets('testMapToolbarToggle', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
mapToolbarEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool mapToolbarEnabled = await inspector.isMapToolbarEnabled(mapId: mapId);
|
||||
expect(mapToolbarEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
mapToolbarEnabled = await inspector.isMapToolbarEnabled(mapId: mapId);
|
||||
expect(mapToolbarEnabled, isAndroid);
|
||||
});
|
||||
|
||||
testWidgets('updateMinMaxZoomLevels', (WidgetTester tester) async {
|
||||
// The behaviors of setting min max zoom level on iOS and Android are different.
|
||||
// On iOS, when we get the min or max zoom level after setting the preference, the
|
||||
// min and max will be exactly the same as the value we set; on Android however,
|
||||
// the values we get do not equal to the value we set.
|
||||
//
|
||||
// Also, when we call zoomTo to set the zoom, on Android, it usually
|
||||
// honors the preferences that we set and the zoom cannot pass beyond the boundary.
|
||||
// On iOS, on the other hand, zoomTo seems to override the preferences.
|
||||
//
|
||||
// Thus we test iOS and Android a little differently here.
|
||||
final Key key = GlobalKey();
|
||||
final Completer<GoogleMapController> controllerCompleter =
|
||||
Completer<GoogleMapController>();
|
||||
|
||||
const MinMaxZoomPreference initialZoomLevel = MinMaxZoomPreference(4, 8);
|
||||
const MinMaxZoomPreference finalZoomLevel = MinMaxZoomPreference(6, 10);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
minMaxZoomPreference: initialZoomLevel,
|
||||
onMapCreated: (GoogleMapController c) async {
|
||||
controllerCompleter.complete(c);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final GoogleMapController controller = await controllerCompleter.future;
|
||||
|
||||
if (isIOS) {
|
||||
final MinMaxZoomPreference zoomLevel =
|
||||
await inspector.getMinMaxZoomLevels(mapId: controller.mapId);
|
||||
expect(zoomLevel, equals(initialZoomLevel));
|
||||
} else if (isAndroid) {
|
||||
await controller.moveCamera(CameraUpdate.zoomTo(15));
|
||||
await tester.pumpAndSettle();
|
||||
double? zoomLevel = await controller.getZoomLevel();
|
||||
expect(zoomLevel, equals(initialZoomLevel.maxZoom));
|
||||
|
||||
await controller.moveCamera(CameraUpdate.zoomTo(1));
|
||||
await tester.pumpAndSettle();
|
||||
zoomLevel = await controller.getZoomLevel();
|
||||
expect(zoomLevel, equals(initialZoomLevel.minZoom));
|
||||
}
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
minMaxZoomPreference: finalZoomLevel,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (isIOS) {
|
||||
final MinMaxZoomPreference zoomLevel =
|
||||
await inspector.getMinMaxZoomLevels(mapId: controller.mapId);
|
||||
expect(zoomLevel, equals(finalZoomLevel));
|
||||
} else {
|
||||
await controller.moveCamera(CameraUpdate.zoomTo(15));
|
||||
await tester.pumpAndSettle();
|
||||
double? zoomLevel = await controller.getZoomLevel();
|
||||
expect(zoomLevel, equals(finalZoomLevel.maxZoom));
|
||||
|
||||
await controller.moveCamera(CameraUpdate.zoomTo(1));
|
||||
await tester.pumpAndSettle();
|
||||
zoomLevel = await controller.getZoomLevel();
|
||||
expect(zoomLevel, equals(finalZoomLevel.minZoom));
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('testZoomGesturesEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
zoomGesturesEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool zoomGesturesEnabled =
|
||||
await inspector.areZoomGesturesEnabled(mapId: mapId);
|
||||
expect(zoomGesturesEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
zoomGesturesEnabled = await inspector.areZoomGesturesEnabled(mapId: mapId);
|
||||
expect(zoomGesturesEnabled, true);
|
||||
});
|
||||
|
||||
testWidgets('testZoomControlsEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool zoomControlsEnabled =
|
||||
await inspector.areZoomControlsEnabled(mapId: mapId);
|
||||
expect(zoomControlsEnabled, !isIOS);
|
||||
|
||||
/// Zoom Controls functionality is not available on iOS at the moment.
|
||||
if (!isIOS) {
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
zoomControlsEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
zoomControlsEnabled =
|
||||
await inspector.areZoomControlsEnabled(mapId: mapId);
|
||||
expect(zoomControlsEnabled, false);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('testLiteModeEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool liteModeEnabled = await inspector.isLiteModeEnabled(mapId: mapId);
|
||||
expect(liteModeEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
liteModeEnabled: true,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
liteModeEnabled = await inspector.isLiteModeEnabled(mapId: mapId);
|
||||
expect(liteModeEnabled, true);
|
||||
}, skip: !isAndroid);
|
||||
|
||||
testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
rotateGesturesEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool rotateGesturesEnabled =
|
||||
await inspector.areRotateGesturesEnabled(mapId: mapId);
|
||||
expect(rotateGesturesEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
rotateGesturesEnabled =
|
||||
await inspector.areRotateGesturesEnabled(mapId: mapId);
|
||||
expect(rotateGesturesEnabled, !isWeb);
|
||||
});
|
||||
|
||||
testWidgets('testTiltGesturesEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
tiltGesturesEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool tiltGesturesEnabled =
|
||||
await inspector.areTiltGesturesEnabled(mapId: mapId);
|
||||
expect(tiltGesturesEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
tiltGesturesEnabled = await inspector.areTiltGesturesEnabled(mapId: mapId);
|
||||
expect(tiltGesturesEnabled, !isWeb);
|
||||
});
|
||||
|
||||
testWidgets('testScrollGesturesEnabled', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
scrollGesturesEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool scrollGesturesEnabled =
|
||||
await inspector.areScrollGesturesEnabled(mapId: mapId);
|
||||
expect(scrollGesturesEnabled, false);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
scrollGesturesEnabled =
|
||||
await inspector.areScrollGesturesEnabled(mapId: mapId);
|
||||
expect(scrollGesturesEnabled, true);
|
||||
});
|
||||
|
||||
testWidgets('testTraffic', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
trafficEnabled: true,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId);
|
||||
expect(isTrafficEnabled, true);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId);
|
||||
expect(isTrafficEnabled, false);
|
||||
});
|
||||
|
||||
testWidgets('testBuildings', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
final bool isBuildingsEnabled =
|
||||
await inspector.areBuildingsEnabled(mapId: mapId);
|
||||
expect(isBuildingsEnabled, !isWeb);
|
||||
});
|
||||
|
||||
// Location button tests are skipped in Android because we don't have location permission to test.
|
||||
// Location button tests are skipped in Web because the functionality is not implemented.
|
||||
group('MyLocationButton', () {
|
||||
testWidgets('testMyLocationButtonToggle', (WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
bool myLocationButtonEnabled =
|
||||
await inspector.isMyLocationButtonEnabled(mapId: mapId);
|
||||
expect(myLocationButtonEnabled, true);
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
myLocationButtonEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
myLocationButtonEnabled =
|
||||
await inspector.isMyLocationButtonEnabled(mapId: mapId);
|
||||
expect(myLocationButtonEnabled, false);
|
||||
});
|
||||
|
||||
testWidgets('testMyLocationButton initial value false',
|
||||
(WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
myLocationButtonEnabled: false,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
final bool myLocationButtonEnabled =
|
||||
await inspector.isMyLocationButtonEnabled(mapId: mapId);
|
||||
expect(myLocationButtonEnabled, false);
|
||||
});
|
||||
|
||||
testWidgets('testMyLocationButton initial value true',
|
||||
(WidgetTester tester) async {
|
||||
final Key key = GlobalKey();
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
|
||||
await pumpMap(
|
||||
tester,
|
||||
GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
);
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
final bool myLocationButtonEnabled =
|
||||
await inspector.isMyLocationButtonEnabled(mapId: mapId);
|
||||
expect(myLocationButtonEnabled, true);
|
||||
});
|
||||
}, skip: !isIOS);
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
// 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.
|
||||
|
||||
// This file contains shared definitions used across multiple test scenarios.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
/// Initial map center
|
||||
const LatLng kInitialMapCenter = LatLng(0, 0);
|
||||
|
||||
/// Initial zoom level
|
||||
const double kInitialZoomLevel = 5;
|
||||
|
||||
/// Initial camera position
|
||||
const CameraPosition kInitialCameraPosition =
|
||||
CameraPosition(target: kInitialMapCenter, zoom: kInitialZoomLevel);
|
||||
|
||||
/// True if the test is running in an iOS device
|
||||
final bool isIOS = defaultTargetPlatform == TargetPlatform.iOS;
|
||||
|
||||
/// True if the test is running in an Android device
|
||||
final bool isAndroid =
|
||||
defaultTargetPlatform == TargetPlatform.android && !kIsWeb;
|
||||
|
||||
/// True if the test is running in a web browser.
|
||||
const bool isWeb = kIsWeb;
|
||||
|
||||
/// Pumps a [map] widget in [tester] of a certain [size], then waits until it settles.
|
||||
Future<void> pumpMap(WidgetTester tester, GoogleMap map,
|
||||
[Size size = const Size.square(200)]) async {
|
||||
await tester.pumpWidget(wrapMap(map, size));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
/// Wraps a [map] in a bunch of widgets so it renders in all platforms.
|
||||
///
|
||||
/// An optional [size] can be passed.
|
||||
Widget wrapMap(GoogleMap map, [Size size = const Size.square(200)]) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: SizedBox.fromSize(
|
||||
size: size,
|
||||
child: map,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@ -0,0 +1,251 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
import 'shared.dart';
|
||||
|
||||
/// Integration Tests for the Tiles feature. These also use the [GoogleMapsInspectorPlatform].
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
runTests();
|
||||
}
|
||||
|
||||
void runTests() {
|
||||
GoogleMapsFlutterPlatform.instance.enableDebugInspection();
|
||||
|
||||
final GoogleMapsInspectorPlatform inspector =
|
||||
GoogleMapsInspectorPlatform.instance!;
|
||||
|
||||
group('Tiles', () {
|
||||
testWidgets(
|
||||
'set tileOverlay correctly',
|
||||
(WidgetTester tester) async {
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
final TileOverlay tileOverlay1 = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_1'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 2,
|
||||
transparency: 0.2,
|
||||
);
|
||||
|
||||
final TileOverlay tileOverlay2 = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_2'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 1,
|
||||
visible: false,
|
||||
transparency: 0.3,
|
||||
fadeIn: false,
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
tileOverlays: <TileOverlay>{tileOverlay1, tileOverlay2},
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
final TileOverlay tileOverlayInfo1 = (await inspector
|
||||
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId))!;
|
||||
final TileOverlay tileOverlayInfo2 = (await inspector
|
||||
.getTileOverlayInfo(tileOverlay2.mapsId, mapId: mapId))!;
|
||||
|
||||
expect(tileOverlayInfo1.visible, isTrue);
|
||||
expect(tileOverlayInfo1.fadeIn, isTrue);
|
||||
expect(tileOverlayInfo1.transparency,
|
||||
moreOrLessEquals(0.2, epsilon: 0.001));
|
||||
expect(tileOverlayInfo1.zIndex, 2);
|
||||
|
||||
expect(tileOverlayInfo2.visible, isFalse);
|
||||
expect(tileOverlayInfo2.fadeIn, isFalse);
|
||||
expect(tileOverlayInfo2.transparency,
|
||||
moreOrLessEquals(0.3, epsilon: 0.001));
|
||||
expect(tileOverlayInfo2.zIndex, 1);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'update tileOverlays correctly',
|
||||
(WidgetTester tester) async {
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
final Key key = GlobalKey();
|
||||
final TileOverlay tileOverlay1 = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_1'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 2,
|
||||
transparency: 0.2,
|
||||
);
|
||||
|
||||
final TileOverlay tileOverlay2 = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_2'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 3,
|
||||
transparency: 0.5,
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
tileOverlays: <TileOverlay>{tileOverlay1, tileOverlay2},
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
final TileOverlay tileOverlay1New = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_1'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 1,
|
||||
visible: false,
|
||||
transparency: 0.3,
|
||||
fadeIn: false,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
tileOverlays: <TileOverlay>{tileOverlay1New},
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('update: OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||
|
||||
final TileOverlay tileOverlayInfo1 = (await inspector
|
||||
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId))!;
|
||||
final TileOverlay? tileOverlayInfo2 = await inspector
|
||||
.getTileOverlayInfo(tileOverlay2.mapsId, mapId: mapId);
|
||||
|
||||
expect(tileOverlayInfo1.visible, isFalse);
|
||||
expect(tileOverlayInfo1.fadeIn, isFalse);
|
||||
expect(tileOverlayInfo1.transparency,
|
||||
moreOrLessEquals(0.3, epsilon: 0.001));
|
||||
expect(tileOverlayInfo1.zIndex, 1);
|
||||
|
||||
expect(tileOverlayInfo2, isNull);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'remove tileOverlays correctly',
|
||||
(WidgetTester tester) async {
|
||||
final Completer<int> mapIdCompleter = Completer<int>();
|
||||
final Key key = GlobalKey();
|
||||
final TileOverlay tileOverlay1 = TileOverlay(
|
||||
tileOverlayId: const TileOverlayId('tile_overlay_1'),
|
||||
tileProvider: _DebugTileProvider(),
|
||||
zIndex: 2,
|
||||
transparency: 0.2,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
tileOverlays: <TileOverlay>{tileOverlay1},
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
mapIdCompleter.complete(controller.mapId);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final int mapId = await mapIdCompleter.future;
|
||||
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: GoogleMap(
|
||||
key: key,
|
||||
initialCameraPosition: kInitialCameraPosition,
|
||||
onMapCreated: (GoogleMapController controller) {
|
||||
fail('OnMapCreated should get called only once.');
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle(const Duration(seconds: 3));
|
||||
final TileOverlay? tileOverlayInfo1 = await inspector
|
||||
.getTileOverlayInfo(tileOverlay1.mapsId, mapId: mapId);
|
||||
|
||||
expect(tileOverlayInfo1, isNull);
|
||||
},
|
||||
);
|
||||
}, skip: isWeb /* Tiles not supported on the web */);
|
||||
}
|
||||
|
||||
class _DebugTileProvider implements TileProvider {
|
||||
_DebugTileProvider() {
|
||||
boxPaint.isAntiAlias = true;
|
||||
boxPaint.color = Colors.blue;
|
||||
boxPaint.strokeWidth = 2.0;
|
||||
boxPaint.style = PaintingStyle.stroke;
|
||||
}
|
||||
|
||||
static const int width = 100;
|
||||
static const int height = 100;
|
||||
static final Paint boxPaint = Paint();
|
||||
static const TextStyle textStyle = TextStyle(
|
||||
color: Colors.red,
|
||||
fontSize: 20,
|
||||
);
|
||||
|
||||
@override
|
||||
Future<Tile> getTile(int x, int y, int? zoom) async {
|
||||
final ui.PictureRecorder recorder = ui.PictureRecorder();
|
||||
final Canvas canvas = Canvas(recorder);
|
||||
final TextSpan textSpan = TextSpan(
|
||||
text: '$x,$y',
|
||||
style: textStyle,
|
||||
);
|
||||
final TextPainter textPainter = TextPainter(
|
||||
text: textSpan,
|
||||
textDirection: TextDirection.ltr,
|
||||
);
|
||||
textPainter.layout(
|
||||
maxWidth: width.toDouble(),
|
||||
);
|
||||
textPainter.paint(canvas, Offset.zero);
|
||||
canvas.drawRect(
|
||||
Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint);
|
||||
final ui.Picture picture = recorder.endRecording();
|
||||
final Uint8List byteData = await picture
|
||||
.toImage(width, height)
|
||||
.then((ui.Image image) =>
|
||||
image.toByteData(format: ui.ImageByteFormat.png))
|
||||
.then((ByteData? byteData) => byteData!.buffer.asUint8List());
|
||||
return Tile(width, height, byteData);
|
||||
}
|
||||
}
|
22
packages/google_maps_flutter/google_maps_flutter/example/run_test.sh
Executable file
22
packages/google_maps_flutter/google_maps_flutter/example/run_test.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/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.
|
||||
|
||||
if pgrep -lf chromedriver > /dev/null; then
|
||||
echo "chromedriver is running."
|
||||
|
||||
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='{}'
|
||||
else
|
||||
echo "Running test target: $1..."
|
||||
set -x
|
||||
flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1
|
||||
fi
|
||||
|
||||
else
|
||||
echo "chromedriver is not running."
|
||||
echo "Please, check the README.md for instructions on how to use run_test.sh"
|
||||
fi
|
||||
|
@ -1,12 +1,8 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// ignore:unnecessary_import
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||
@ -171,6 +167,26 @@ void main() {
|
||||
<dynamic>['fromAssetImage', 'some/path.png', 1.0]),
|
||||
isA<BitmapDescriptor>());
|
||||
});
|
||||
|
||||
test('mipmaps determines dpi', () async {
|
||||
const ImageConfiguration imageConfiguration = ImageConfiguration(
|
||||
devicePixelRatio: 3,
|
||||
);
|
||||
|
||||
final BitmapDescriptor mip = await BitmapDescriptor.fromAssetImage(
|
||||
imageConfiguration,
|
||||
'red_square.png',
|
||||
);
|
||||
final BitmapDescriptor scaled = await BitmapDescriptor.fromAssetImage(
|
||||
imageConfiguration,
|
||||
'red_square.png',
|
||||
mipmaps: false,
|
||||
);
|
||||
|
||||
expect((mip.toJson() as List<dynamic>)[2], 1);
|
||||
expect((scaled.toJson() as List<dynamic>)[2], 3);
|
||||
});
|
||||
|
||||
test('name cannot be null or empty', () {
|
||||
expect(() {
|
||||
BitmapDescriptor.fromJson(<dynamic>['fromAssetImage', null, 1.0]);
|
||||
|
@ -1,3 +1,10 @@
|
||||
## 0.5.0
|
||||
|
||||
* **BREAKING CHANGE:** Fires a `MapStyleException` when an invalid JSON is used
|
||||
in `setMapStyle` (was `FormatException` previously).
|
||||
* Implements a `GoogleMapsInspectorPlatform` to allow integration tests to inspect
|
||||
parts of the internal state of a map.
|
||||
|
||||
## 0.4.0+9
|
||||
|
||||
* Removes obsolete null checks on non-nullable values.
|
||||
|
@ -1,7 +1,9 @@
|
||||
// Mocks generated by Mockito 5.4.0 from annotations
|
||||
// Mocks generated by Mockito 5.4.1 from annotations
|
||||
// in google_maps_flutter_web_integration_tests/integration_test/google_maps_controller_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// @dart=2.19
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'package:google_maps/google_maps.dart' as _i2;
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'
|
||||
|
@ -197,6 +197,15 @@ void main() {
|
||||
expect(style.stylers?.length, 1);
|
||||
expect(getProperty<String>(style.stylers![0]!, 'color'), '#6b9a76');
|
||||
});
|
||||
|
||||
testWidgets('throws MapStyleException for invalid styles',
|
||||
(WidgetTester tester) async {
|
||||
plugin.debugSetMapById(<int, GoogleMapController>{0: controller});
|
||||
|
||||
expect(() async {
|
||||
await plugin.setMapStyle('invalid_style', mapId: 0);
|
||||
}, throwsA(isA<MapStyleException>()));
|
||||
});
|
||||
});
|
||||
|
||||
group('Noop methods:', () {
|
||||
|
@ -1,13 +1,15 @@
|
||||
// Mocks generated by Mockito 5.4.0 from annotations
|
||||
// Mocks generated by Mockito 5.4.1 from annotations
|
||||
// in google_maps_flutter_web_integration_tests/integration_test/google_maps_plugin_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// @dart=2.19
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i2;
|
||||
import 'dart:async' as _i3;
|
||||
|
||||
import 'package:google_maps/google_maps.dart' as _i5;
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'
|
||||
as _i3;
|
||||
as _i2;
|
||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart' as _i4;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
|
||||
@ -22,9 +24,9 @@ import 'package:mockito/mockito.dart' as _i1;
|
||||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeStreamController_0<T> extends _i1.SmartFake
|
||||
implements _i2.StreamController<T> {
|
||||
_FakeStreamController_0(
|
||||
class _FakeMapConfiguration_0 extends _i1.SmartFake
|
||||
implements _i2.MapConfiguration {
|
||||
_FakeMapConfiguration_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@ -33,8 +35,9 @@ class _FakeStreamController_0<T> extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeLatLngBounds_1 extends _i1.SmartFake implements _i3.LatLngBounds {
|
||||
_FakeLatLngBounds_1(
|
||||
class _FakeStreamController_1<T> extends _i1.SmartFake
|
||||
implements _i3.StreamController<T> {
|
||||
_FakeStreamController_1(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@ -43,9 +46,8 @@ class _FakeLatLngBounds_1 extends _i1.SmartFake implements _i3.LatLngBounds {
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeScreenCoordinate_2 extends _i1.SmartFake
|
||||
implements _i3.ScreenCoordinate {
|
||||
_FakeScreenCoordinate_2(
|
||||
class _FakeLatLngBounds_2 extends _i1.SmartFake implements _i2.LatLngBounds {
|
||||
_FakeLatLngBounds_2(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@ -54,8 +56,19 @@ class _FakeScreenCoordinate_2 extends _i1.SmartFake
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeLatLng_3 extends _i1.SmartFake implements _i3.LatLng {
|
||||
_FakeLatLng_3(
|
||||
class _FakeScreenCoordinate_3 extends _i1.SmartFake
|
||||
implements _i2.ScreenCoordinate {
|
||||
_FakeScreenCoordinate_3(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
parent,
|
||||
parentInvocation,
|
||||
);
|
||||
}
|
||||
|
||||
class _FakeLatLng_4 extends _i1.SmartFake implements _i2.LatLng {
|
||||
_FakeLatLng_4(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
@ -70,24 +83,36 @@ class _FakeLatLng_3 extends _i1.SmartFake implements _i3.LatLng {
|
||||
class MockGoogleMapController extends _i1.Mock
|
||||
implements _i4.GoogleMapController {
|
||||
@override
|
||||
_i2.StreamController<_i3.MapEvent<Object?>> get stream => (super.noSuchMethod(
|
||||
_i2.MapConfiguration get configuration => (super.noSuchMethod(
|
||||
Invocation.getter(#configuration),
|
||||
returnValue: _FakeMapConfiguration_0(
|
||||
this,
|
||||
Invocation.getter(#configuration),
|
||||
),
|
||||
returnValueForMissingStub: _FakeMapConfiguration_0(
|
||||
this,
|
||||
Invocation.getter(#configuration),
|
||||
),
|
||||
) as _i2.MapConfiguration);
|
||||
@override
|
||||
_i3.StreamController<_i2.MapEvent<Object?>> get stream => (super.noSuchMethod(
|
||||
Invocation.getter(#stream),
|
||||
returnValue: _FakeStreamController_0<_i3.MapEvent<Object?>>(
|
||||
returnValue: _FakeStreamController_1<_i2.MapEvent<Object?>>(
|
||||
this,
|
||||
Invocation.getter(#stream),
|
||||
),
|
||||
returnValueForMissingStub:
|
||||
_FakeStreamController_0<_i3.MapEvent<Object?>>(
|
||||
_FakeStreamController_1<_i2.MapEvent<Object?>>(
|
||||
this,
|
||||
Invocation.getter(#stream),
|
||||
),
|
||||
) as _i2.StreamController<_i3.MapEvent<Object?>>);
|
||||
) as _i3.StreamController<_i2.MapEvent<Object?>>);
|
||||
@override
|
||||
_i2.Stream<_i3.MapEvent<Object?>> get events => (super.noSuchMethod(
|
||||
_i3.Stream<_i2.MapEvent<Object?>> get events => (super.noSuchMethod(
|
||||
Invocation.getter(#events),
|
||||
returnValue: _i2.Stream<_i3.MapEvent<Object?>>.empty(),
|
||||
returnValueForMissingStub: _i2.Stream<_i3.MapEvent<Object?>>.empty(),
|
||||
) as _i2.Stream<_i3.MapEvent<Object?>>);
|
||||
returnValue: _i3.Stream<_i2.MapEvent<Object?>>.empty(),
|
||||
returnValueForMissingStub: _i3.Stream<_i2.MapEvent<Object?>>.empty(),
|
||||
) as _i3.Stream<_i2.MapEvent<Object?>>);
|
||||
@override
|
||||
bool get isInitialized => (super.noSuchMethod(
|
||||
Invocation.getter(#isInitialized),
|
||||
@ -125,7 +150,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void updateMapConfiguration(_i3.MapConfiguration? update) =>
|
||||
void updateMapConfiguration(_i2.MapConfiguration? update) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateMapConfiguration,
|
||||
@ -142,12 +167,12 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i2.Future<_i3.LatLngBounds> getVisibleRegion() => (super.noSuchMethod(
|
||||
_i3.Future<_i2.LatLngBounds> getVisibleRegion() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getVisibleRegion,
|
||||
[],
|
||||
),
|
||||
returnValue: _i2.Future<_i3.LatLngBounds>.value(_FakeLatLngBounds_1(
|
||||
returnValue: _i3.Future<_i2.LatLngBounds>.value(_FakeLatLngBounds_2(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getVisibleRegion,
|
||||
@ -155,23 +180,23 @@ class MockGoogleMapController extends _i1.Mock
|
||||
),
|
||||
)),
|
||||
returnValueForMissingStub:
|
||||
_i2.Future<_i3.LatLngBounds>.value(_FakeLatLngBounds_1(
|
||||
_i3.Future<_i2.LatLngBounds>.value(_FakeLatLngBounds_2(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getVisibleRegion,
|
||||
[],
|
||||
),
|
||||
)),
|
||||
) as _i2.Future<_i3.LatLngBounds>);
|
||||
) as _i3.Future<_i2.LatLngBounds>);
|
||||
@override
|
||||
_i2.Future<_i3.ScreenCoordinate> getScreenCoordinate(_i3.LatLng? latLng) =>
|
||||
_i3.Future<_i2.ScreenCoordinate> getScreenCoordinate(_i2.LatLng? latLng) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getScreenCoordinate,
|
||||
[latLng],
|
||||
),
|
||||
returnValue:
|
||||
_i2.Future<_i3.ScreenCoordinate>.value(_FakeScreenCoordinate_2(
|
||||
_i3.Future<_i2.ScreenCoordinate>.value(_FakeScreenCoordinate_3(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getScreenCoordinate,
|
||||
@ -179,57 +204,57 @@ class MockGoogleMapController extends _i1.Mock
|
||||
),
|
||||
)),
|
||||
returnValueForMissingStub:
|
||||
_i2.Future<_i3.ScreenCoordinate>.value(_FakeScreenCoordinate_2(
|
||||
_i3.Future<_i2.ScreenCoordinate>.value(_FakeScreenCoordinate_3(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getScreenCoordinate,
|
||||
[latLng],
|
||||
),
|
||||
)),
|
||||
) as _i2.Future<_i3.ScreenCoordinate>);
|
||||
) as _i3.Future<_i2.ScreenCoordinate>);
|
||||
@override
|
||||
_i2.Future<_i3.LatLng> getLatLng(_i3.ScreenCoordinate? screenCoordinate) =>
|
||||
_i3.Future<_i2.LatLng> getLatLng(_i2.ScreenCoordinate? screenCoordinate) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getLatLng,
|
||||
[screenCoordinate],
|
||||
),
|
||||
returnValue: _i2.Future<_i3.LatLng>.value(_FakeLatLng_3(
|
||||
returnValue: _i3.Future<_i2.LatLng>.value(_FakeLatLng_4(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getLatLng,
|
||||
[screenCoordinate],
|
||||
),
|
||||
)),
|
||||
returnValueForMissingStub: _i2.Future<_i3.LatLng>.value(_FakeLatLng_3(
|
||||
returnValueForMissingStub: _i3.Future<_i2.LatLng>.value(_FakeLatLng_4(
|
||||
this,
|
||||
Invocation.method(
|
||||
#getLatLng,
|
||||
[screenCoordinate],
|
||||
),
|
||||
)),
|
||||
) as _i2.Future<_i3.LatLng>);
|
||||
) as _i3.Future<_i2.LatLng>);
|
||||
@override
|
||||
_i2.Future<void> moveCamera(_i3.CameraUpdate? cameraUpdate) =>
|
||||
_i3.Future<void> moveCamera(_i2.CameraUpdate? cameraUpdate) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#moveCamera,
|
||||
[cameraUpdate],
|
||||
),
|
||||
returnValue: _i2.Future<void>.value(),
|
||||
returnValueForMissingStub: _i2.Future<void>.value(),
|
||||
) as _i2.Future<void>);
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
@override
|
||||
_i2.Future<double> getZoomLevel() => (super.noSuchMethod(
|
||||
_i3.Future<double> getZoomLevel() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getZoomLevel,
|
||||
[],
|
||||
),
|
||||
returnValue: _i2.Future<double>.value(0.0),
|
||||
returnValueForMissingStub: _i2.Future<double>.value(0.0),
|
||||
) as _i2.Future<double>);
|
||||
returnValue: _i3.Future<double>.value(0.0),
|
||||
returnValueForMissingStub: _i3.Future<double>.value(0.0),
|
||||
) as _i3.Future<double>);
|
||||
@override
|
||||
void updateCircles(_i3.CircleUpdates? updates) => super.noSuchMethod(
|
||||
void updateCircles(_i2.CircleUpdates? updates) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateCircles,
|
||||
[updates],
|
||||
@ -237,7 +262,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void updatePolygons(_i3.PolygonUpdates? updates) => super.noSuchMethod(
|
||||
void updatePolygons(_i2.PolygonUpdates? updates) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updatePolygons,
|
||||
[updates],
|
||||
@ -245,7 +270,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void updatePolylines(_i3.PolylineUpdates? updates) => super.noSuchMethod(
|
||||
void updatePolylines(_i2.PolylineUpdates? updates) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updatePolylines,
|
||||
[updates],
|
||||
@ -253,7 +278,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void updateMarkers(_i3.MarkerUpdates? updates) => super.noSuchMethod(
|
||||
void updateMarkers(_i2.MarkerUpdates? updates) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateMarkers,
|
||||
[updates],
|
||||
@ -261,7 +286,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void showInfoWindow(_i3.MarkerId? markerId) => super.noSuchMethod(
|
||||
void showInfoWindow(_i2.MarkerId? markerId) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#showInfoWindow,
|
||||
[markerId],
|
||||
@ -269,7 +294,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
void hideInfoWindow(_i3.MarkerId? markerId) => super.noSuchMethod(
|
||||
void hideInfoWindow(_i2.MarkerId? markerId) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#hideInfoWindow,
|
||||
[markerId],
|
||||
@ -277,7 +302,7 @@ class MockGoogleMapController extends _i1.Mock
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
bool isInfoWindowShown(_i3.MarkerId? markerId) => (super.noSuchMethod(
|
||||
bool isInfoWindowShown(_i2.MarkerId? markerId) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#isInfoWindowShown,
|
||||
[markerId],
|
||||
|
@ -22,7 +22,7 @@ dev_dependencies:
|
||||
google_maps: ^6.1.0
|
||||
google_maps_flutter: # Used for projection_test.dart
|
||||
path: ../../google_maps_flutter
|
||||
http: ^0.13.0
|
||||
http: ^1.0.0
|
||||
integration_test:
|
||||
sdk: flutter
|
||||
mockito: 5.4.1
|
||||
|
@ -19,6 +19,7 @@ import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf
|
||||
import 'package:sanitize_html/sanitize_html.dart';
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
import 'src/google_maps_inspector_web.dart';
|
||||
import 'src/shims/dart_ui.dart' as ui; // Conditionally imports dart:ui in web
|
||||
import 'src/third_party/to_screen_location/to_screen_location.dart';
|
||||
import 'src/types.dart';
|
||||
|
@ -126,25 +126,30 @@ bool _isJsonMapStyle(Map<String, Object?> value) {
|
||||
List<gmaps.MapTypeStyle> _mapStyles(String? mapStyleJson) {
|
||||
List<gmaps.MapTypeStyle> styles = <gmaps.MapTypeStyle>[];
|
||||
if (mapStyleJson != null) {
|
||||
styles = (json.decode(mapStyleJson, reviver: (Object? key, Object? value) {
|
||||
if (value is Map && _isJsonMapStyle(value as Map<String, Object?>)) {
|
||||
List<Object?> stylers = <Object?>[];
|
||||
if (value['stylers'] != null) {
|
||||
stylers = (value['stylers']! as List<Object?>)
|
||||
.map<Object?>((Object? e) => e != null ? jsify(e) : null)
|
||||
.toList();
|
||||
try {
|
||||
styles =
|
||||
(json.decode(mapStyleJson, reviver: (Object? key, Object? value) {
|
||||
if (value is Map && _isJsonMapStyle(value as Map<String, Object?>)) {
|
||||
List<Object?> stylers = <Object?>[];
|
||||
if (value['stylers'] != null) {
|
||||
stylers = (value['stylers']! as List<Object?>)
|
||||
.map<Object?>((Object? e) => e != null ? jsify(e) : null)
|
||||
.toList();
|
||||
}
|
||||
return gmaps.MapTypeStyle()
|
||||
..elementType = value['elementType'] as String?
|
||||
..featureType = value['featureType'] as String?
|
||||
..stylers = stylers;
|
||||
}
|
||||
return gmaps.MapTypeStyle()
|
||||
..elementType = value['elementType'] as String?
|
||||
..featureType = value['featureType'] as String?
|
||||
..stylers = stylers;
|
||||
}
|
||||
return value;
|
||||
}) as List<Object?>)
|
||||
.where((Object? element) => element != null)
|
||||
.cast<gmaps.MapTypeStyle>()
|
||||
.toList();
|
||||
// .toList calls are required so the JS API understands the underlying data structure.
|
||||
return value;
|
||||
}) as List<Object?>)
|
||||
.where((Object? element) => element != null)
|
||||
.cast<gmaps.MapTypeStyle>()
|
||||
.toList();
|
||||
// .toList calls are required so the JS API understands the underlying data structure.
|
||||
} on FormatException catch (e) {
|
||||
throw MapStyleException(e.message);
|
||||
}
|
||||
}
|
||||
return styles;
|
||||
}
|
||||
|
@ -53,11 +53,19 @@ class GoogleMapController {
|
||||
final Set<Polygon> _polygons;
|
||||
final Set<Polyline> _polylines;
|
||||
final Set<Circle> _circles;
|
||||
// The configuraiton passed by the user, before converting to gmaps.
|
||||
// The configuration passed by the user, before converting to gmaps.
|
||||
// Caching this allows us to re-create the map faithfully when needed.
|
||||
MapConfiguration _lastMapConfiguration = const MapConfiguration();
|
||||
List<gmaps.MapTypeStyle> _lastStyles = const <gmaps.MapTypeStyle>[];
|
||||
|
||||
/// Configuration accessor for the [GoogleMapsInspectorWeb].
|
||||
///
|
||||
/// Returns the latest value of [MapConfiguration] set by the programmer.
|
||||
///
|
||||
/// This should only be used by an inspector instance created when a test
|
||||
/// calls [GoogleMapsPlugin.enableDebugInspection].
|
||||
MapConfiguration get configuration => _lastMapConfiguration;
|
||||
|
||||
// Creates the 'viewType' for the _widget
|
||||
String _getViewType(int mapId) => 'plugins.flutter.io/google_maps_$mapId';
|
||||
|
||||
|
@ -26,7 +26,7 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform {
|
||||
// Convenience getter for a stream of events filtered by their mapId.
|
||||
Stream<MapEvent<Object?>> _events(int mapId) => _map(mapId).events;
|
||||
|
||||
// Convenience getter for a map controller by its mapId.
|
||||
/// Retrieve a map controller by its mapId.
|
||||
GoogleMapController _map(int mapId) {
|
||||
final GoogleMapController? controller = _mapById[mapId];
|
||||
assert(controller != null,
|
||||
@ -327,4 +327,13 @@ class GoogleMapsPlugin extends GoogleMapsFlutterPlatform {
|
||||
|
||||
return mapController.widget!;
|
||||
}
|
||||
|
||||
/// Populates [GoogleMapsFlutterInspectorPlatform.instance] to allow
|
||||
/// inspecting the platform map state.
|
||||
@override
|
||||
void enableDebugInspection() {
|
||||
GoogleMapsInspectorPlatform.instance = GoogleMapsInspectorWeb(
|
||||
(int mapId) => _map(mapId).configuration,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||
|
||||
/// Function that gets the [MapConfiguration] for a given `mapId`.
|
||||
typedef ConfigurationProvider = MapConfiguration Function(int mapId);
|
||||
|
||||
/// This platform implementation allows inspecting the running maps.
|
||||
class GoogleMapsInspectorWeb extends GoogleMapsInspectorPlatform {
|
||||
/// Build an "inspector" that is able to look into maps.
|
||||
GoogleMapsInspectorWeb(ConfigurationProvider configurationProvider)
|
||||
: _configurationProvider = configurationProvider;
|
||||
|
||||
final ConfigurationProvider _configurationProvider;
|
||||
|
||||
@override
|
||||
Future<bool> areBuildingsEnabled({required int mapId}) async {
|
||||
return false; // Not supported on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> areRotateGesturesEnabled({required int mapId}) async {
|
||||
return false; // Not supported on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> areScrollGesturesEnabled({required int mapId}) async {
|
||||
return _configurationProvider(mapId).scrollGesturesEnabled ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> areTiltGesturesEnabled({required int mapId}) async {
|
||||
return false; // Not supported on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> areZoomControlsEnabled({required int mapId}) async {
|
||||
return _configurationProvider(mapId).zoomControlsEnabled ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> areZoomGesturesEnabled({required int mapId}) async {
|
||||
return _configurationProvider(mapId).zoomGesturesEnabled ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MinMaxZoomPreference> getMinMaxZoomLevels({required int mapId}) async {
|
||||
final MapConfiguration config = _configurationProvider(mapId);
|
||||
assert(config.minMaxZoomPreference != null);
|
||||
|
||||
return config.minMaxZoomPreference!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TileOverlay?> getTileOverlayInfo(
|
||||
TileOverlayId tileOverlayId, {
|
||||
required int mapId,
|
||||
}) async {
|
||||
return null; // Custom tiles not supported on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isCompassEnabled({required int mapId}) async {
|
||||
return false; // There's no compass on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isLiteModeEnabled({required int mapId}) async {
|
||||
return false; // There's no lite mode on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isMapToolbarEnabled({required int mapId}) async {
|
||||
return false; // There's no Map Toolbar on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isMyLocationButtonEnabled({required int mapId}) async {
|
||||
return false; // My Location widget not supported on the web
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isTrafficEnabled({required int mapId}) async {
|
||||
return _configurationProvider(mapId).trafficEnabled ?? false;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ name: google_maps_flutter_web
|
||||
description: Web platform implementation of google_maps_flutter
|
||||
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_web
|
||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
|
||||
version: 0.4.0+9
|
||||
version: 0.5.0
|
||||
|
||||
environment:
|
||||
sdk: ">=2.18.0 <4.0.0"
|
||||
|
Reference in New Issue
Block a user