[google_maps_flutter_platform_interface] Add BitmapDescriptor.fromJson constructor. (#3263)
This is required so serialized descriptors can be synchronously re-hydrated in the Web implementation. This will be removed/deprecated once the buildWidget API gets refactored.
diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md
index dc8eddf..0586ac4 100644
--- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.0.5
+
+* Temporarily add a `fromJson` constructor to `BitmapDescriptor` so serialized descriptors can be synchronously re-hydrated. This will be removed when a fix for [this issue](https://github.com/flutter/flutter/issues/70330) lands.
+
## 1.0.4
* Add a `dispose` method to the interface, so implementations may cleanup resources acquired on `init`.
diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart
index a6fdcc1..e10481e 100644
--- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart
+++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/bitmap.dart
@@ -17,6 +17,18 @@
class BitmapDescriptor {
const BitmapDescriptor._(this._json);
+ static const String _defaultMarker = 'defaultMarker';
+ static const String _fromAsset = 'fromAsset';
+ static const String _fromAssetImage = 'fromAssetImage';
+ static const String _fromBytes = 'fromBytes';
+
+ static const Set<String> _validTypes = {
+ _defaultMarker,
+ _fromAsset,
+ _fromAssetImage,
+ _fromBytes,
+ };
+
/// Convenience hue value representing red.
static const double hueRed = 0.0;
@@ -49,14 +61,14 @@
/// Creates a BitmapDescriptor that refers to the default marker image.
static const BitmapDescriptor defaultMarker =
- BitmapDescriptor._(<dynamic>['defaultMarker']);
+ BitmapDescriptor._(<dynamic>[_defaultMarker]);
/// Creates a BitmapDescriptor that refers to a colorization of the default
/// marker image. For convenience, there is a predefined set of hue values.
/// See e.g. [hueYellow].
static BitmapDescriptor defaultMarkerWithHue(double hue) {
assert(0.0 <= hue && hue < 360.0);
- return BitmapDescriptor._(<dynamic>['defaultMarker', hue]);
+ return BitmapDescriptor._(<dynamic>[_defaultMarker, hue]);
}
/// Creates a BitmapDescriptor using the name of a bitmap image in the assets
@@ -67,9 +79,9 @@
@Deprecated("Use fromAssetImage instead")
static BitmapDescriptor fromAsset(String assetName, {String package}) {
if (package == null) {
- return BitmapDescriptor._(<dynamic>['fromAsset', assetName]);
+ return BitmapDescriptor._(<dynamic>[_fromAsset, assetName]);
} else {
- return BitmapDescriptor._(<dynamic>['fromAsset', assetName, package]);
+ return BitmapDescriptor._(<dynamic>[_fromAsset, assetName, package]);
}
}
@@ -89,7 +101,7 @@
}) async {
if (!mipmaps && configuration.devicePixelRatio != null) {
return BitmapDescriptor._(<dynamic>[
- 'fromAssetImage',
+ _fromAssetImage,
assetName,
configuration.devicePixelRatio,
]);
@@ -99,7 +111,7 @@
final AssetBundleImageKey assetBundleImageKey =
await assetImage.obtainKey(configuration);
return BitmapDescriptor._(<dynamic>[
- 'fromAssetImage',
+ _fromAssetImage,
assetBundleImageKey.name,
assetBundleImageKey.scale,
if (kIsWeb && configuration?.size != null)
@@ -113,7 +125,50 @@
/// Creates a BitmapDescriptor using an array of bytes that must be encoded
/// as PNG.
static BitmapDescriptor fromBytes(Uint8List byteData) {
- return BitmapDescriptor._(<dynamic>['fromBytes', byteData]);
+ return BitmapDescriptor._(<dynamic>[_fromBytes, byteData]);
+ }
+
+ /// The inverse of .toJson.
+ // This is needed in Web to re-hydrate BitmapDescriptors that have been
+ // transformed to JSON for transport.
+ // TODO(https://github.com/flutter/flutter/issues/70330): Clean this up.
+ BitmapDescriptor.fromJson(dynamic json) : _json = json {
+ assert(_validTypes.contains(_json[0]));
+ switch (_json[0]) {
+ case _defaultMarker:
+ assert(_json.length <= 2);
+ if (_json.length == 2) {
+ assert(_json[1] is num);
+ assert(0 <= _json[1] && _json[1] < 360);
+ }
+ break;
+ case _fromBytes:
+ assert(_json.length == 2);
+ assert(_json[1] != null && _json[1] is List<int>);
+ assert((_json[1] as List).isNotEmpty);
+ break;
+ case _fromAsset:
+ assert(_json.length <= 3);
+ assert(_json[1] != null && _json[1] is String);
+ assert((_json[1] as String).isNotEmpty);
+ if (_json.length == 3) {
+ assert(_json[2] != null && _json[2] is String);
+ assert((_json[2] as String).isNotEmpty);
+ }
+ break;
+ case _fromAssetImage:
+ assert(_json.length <= 4);
+ assert(_json[1] != null && _json[1] is String);
+ assert((_json[1] as String).isNotEmpty);
+ assert(_json[2] != null && _json[2] is double);
+ if (_json.length == 4) {
+ assert(_json[3] != null && _json[3] is List);
+ assert((_json[3] as List).length == 2);
+ }
+ break;
+ default:
+ break;
+ }
}
final dynamic _json;
diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml
index fd3a1c4..a2b5ff5 100644
--- a/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml
+++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/pubspec.yaml
@@ -3,7 +3,7 @@
homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter_platform_interface
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.4
+version: 1.0.5
dependencies:
flutter:
diff --git a/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart
new file mode 100644
index 0000000..afcf57d
--- /dev/null
+++ b/packages/google_maps_flutter/google_maps_flutter_platform_interface/test/types/bitmap_test.dart
@@ -0,0 +1,167 @@
+// Copyright 2017 The Chromium 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:typed_data';
+
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
+
+void main() {
+ TestWidgetsFlutterBinding.ensureInitialized();
+
+ group('$BitmapDescriptor', () {
+ test('toJson / fromJson', () {
+ final descriptor =
+ BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueCyan);
+ final json = descriptor.toJson();
+
+ // Rehydrate a new bitmap descriptor...
+ // ignore: deprecated_member_use_from_same_package
+ final descriptorFromJson = BitmapDescriptor.fromJson(json);
+
+ expect(descriptorFromJson, isNot(descriptor)); // New instance
+ expect(identical(descriptorFromJson.toJson(), json), isTrue); // Same JSON
+ });
+
+ group('fromJson validation', () {
+ group('type validation', () {
+ test('correct type', () {
+ expect(BitmapDescriptor.fromJson(['defaultMarker']),
+ isA<BitmapDescriptor>());
+ });
+ test('wrong type', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['bogusType']);
+ }, throwsAssertionError);
+ });
+ });
+ group('defaultMarker', () {
+ test('hue is null', () {
+ expect(BitmapDescriptor.fromJson(['defaultMarker']),
+ isA<BitmapDescriptor>());
+ });
+ test('hue is number', () {
+ expect(BitmapDescriptor.fromJson(['defaultMarker', 158]),
+ isA<BitmapDescriptor>());
+ });
+ test('hue is not number', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['defaultMarker', 'nope']);
+ }, throwsAssertionError);
+ });
+ test('hue is out of range', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['defaultMarker', -1]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(['defaultMarker', 361]);
+ }, throwsAssertionError);
+ });
+ });
+ group('fromBytes', () {
+ test('with bytes', () {
+ expect(
+ BitmapDescriptor.fromJson([
+ 'fromBytes',
+ Uint8List.fromList([1, 2, 3])
+ ]),
+ isA<BitmapDescriptor>());
+ });
+ test('without bytes', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['fromBytes', null]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(['fromBytes', []]);
+ }, throwsAssertionError);
+ });
+ });
+ group('fromAsset', () {
+ test('name is passed', () {
+ expect(BitmapDescriptor.fromJson(['fromAsset', 'some/path.png']),
+ isA<BitmapDescriptor>());
+ });
+ test('name cannot be null or empty', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAsset', null]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAsset', '']);
+ }, throwsAssertionError);
+ });
+ test('package is passed', () {
+ expect(
+ BitmapDescriptor.fromJson(
+ ['fromAsset', 'some/path.png', 'some_package']),
+ isA<BitmapDescriptor>());
+ });
+ test('package cannot be null or empty', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAsset', 'some/path.png', null]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAsset', 'some/path.png', '']);
+ }, throwsAssertionError);
+ });
+ });
+ group('fromAssetImage', () {
+ test('name and dpi passed', () {
+ expect(
+ BitmapDescriptor.fromJson(
+ ['fromAssetImage', 'some/path.png', 1.0]),
+ isA<BitmapDescriptor>());
+ });
+ test('name cannot be null or empty', () {
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAssetImage', null, 1.0]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(['fromAssetImage', '', 1.0]);
+ }, throwsAssertionError);
+ });
+ test('dpi must be number', () {
+ expect(() {
+ BitmapDescriptor.fromJson(
+ ['fromAssetImage', 'some/path.png', null]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(
+ ['fromAssetImage', 'some/path.png', 'one']);
+ }, throwsAssertionError);
+ });
+ test('with optional [width, height] List', () {
+ expect(
+ BitmapDescriptor.fromJson([
+ 'fromAssetImage',
+ 'some/path.png',
+ 1.0,
+ [640, 480]
+ ]),
+ isA<BitmapDescriptor>());
+ });
+ test(
+ 'optional [width, height] List cannot be null or not contain 2 elements',
+ () {
+ expect(() {
+ BitmapDescriptor.fromJson(
+ ['fromAssetImage', 'some/path.png', 1.0, null]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson(
+ ['fromAssetImage', 'some/path.png', 1.0, []]);
+ }, throwsAssertionError);
+ expect(() {
+ BitmapDescriptor.fromJson([
+ 'fromAssetImage',
+ 'some/path.png',
+ 1.0,
+ [640, 480, 1024]
+ ]);
+ }, throwsAssertionError);
+ });
+ });
+ });
+ });
+}