Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions packages/google_maps_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## NEXT

* Update code format.
## 0.1.14

* Update google_maps_flutter to 2.16.0.
* Update google_maps_flutter_platform_interface to 2.15.0.
* Add support for ground overlays (bounds-based) using
`google.maps.GroundOverlay`.
* Forward the `colorScheme` map option to `google.maps.ColorScheme`.
* * Update code format.

## 0.1.13

Expand Down
4 changes: 2 additions & 2 deletions packages/google_maps_flutter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ This package is not an _endorsed_ implementation of `google_maps_flutter`. There

```yaml
dependencies:
google_maps_flutter: ^2.10.0
google_maps_flutter_tizen: ^0.1.13
google_maps_flutter: ^2.16.0
google_maps_flutter_tizen: ^0.1.14
```

For detailed usage, see https://pub.dev/packages/google_maps_flutter#sample-usage.
Expand Down
156 changes: 156 additions & 0 deletions packages/google_maps_flutter/example/lib/ground_overlay.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// 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_for_file: public_member_api_docs

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

import 'page.dart';

class GroundOverlayPage extends GoogleMapExampleAppPage {
const GroundOverlayPage({Key? key})
: super(const Icon(Icons.map), 'Ground overlay', key: key);

@override
Widget build(BuildContext context) {
return const GroundOverlayBody();
}
}

class GroundOverlayBody extends StatefulWidget {
const GroundOverlayBody({super.key});

@override
State<StatefulWidget> createState() => GroundOverlayBodyState();
}

class GroundOverlayBodyState extends State<GroundOverlayBody> {
GoogleMapController? controller;
GroundOverlay? _groundOverlay;
int _groundOverlayIndex = 0;

static const LatLng _mapCenter = LatLng(37.422026, -122.085329);

final LatLngBounds _bounds1 = LatLngBounds(
southwest: const LatLng(37.42, -122.09),
northeast: const LatLng(37.423, -122.084),
);
final LatLngBounds _bounds2 = LatLngBounds(
southwest: const LatLng(37.421, -122.091),
northeast: const LatLng(37.424, -122.08),
);

late LatLngBounds _currentBounds = _bounds1;

// ignore: use_setters_to_change_properties
void _onMapCreated(GoogleMapController controller) {
this.controller = controller;
}

Future<void> _addGroundOverlay() async {
final AssetMapBitmap image = await AssetMapBitmap.create(
createLocalImageConfiguration(context),
'assets/red_square.png',
bitmapScaling: MapBitmapScaling.none,
);

_groundOverlayIndex += 1;

final GroundOverlay overlay = GroundOverlay.fromBounds(
groundOverlayId: GroundOverlayId('ground_overlay_$_groundOverlayIndex'),
image: image,
bounds: _currentBounds,
onTap: _toggleBounds,
);

setState(() {
_groundOverlay = overlay;
});
}

void _removeGroundOverlay() {
setState(() {
_groundOverlay = null;
});
}

void _toggleTransparency() {
if (_groundOverlay == null) {
return;
}
setState(() {
final double transparency =
_groundOverlay!.transparency == 0.0 ? 0.5 : 0.0;
_groundOverlay =
_groundOverlay!.copyWith(transparencyParam: transparency);
});
}

void _toggleVisible() {
if (_groundOverlay == null) {
return;
}
setState(() {
_groundOverlay =
_groundOverlay!.copyWith(visibleParam: !_groundOverlay!.visible);
});
}

Future<void> _toggleBounds() async {
setState(() {
_currentBounds = _currentBounds == _bounds1 ? _bounds2 : _bounds1;
});
await _addGroundOverlay();
}

@override
Widget build(BuildContext context) {
final Set<GroundOverlay> overlays = <GroundOverlay>{
if (_groundOverlay != null) _groundOverlay!,
};
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: GoogleMap(
initialCameraPosition: const CameraPosition(
target: _mapCenter,
zoom: 14.0,
),
groundOverlays: overlays,
onMapCreated: _onMapCreated,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
TextButton(
onPressed: _groundOverlay == null ? _addGroundOverlay : null,
child: const Text('Add'),
),
TextButton(
onPressed: _groundOverlay != null ? _removeGroundOverlay : null,
child: const Text('Remove'),
),
TextButton(
onPressed: _groundOverlay == null ? null : _toggleTransparency,
child: const Text('Toggle transparency'),
),
TextButton(
onPressed: _groundOverlay == null ? null : _toggleVisible,
child: const Text('Toggle visible'),
),
TextButton(
onPressed: _groundOverlay == null ? null : _toggleBounds,
child: const Text('Change bounds'),
),
],
),
],
);
}
}
2 changes: 2 additions & 0 deletions packages/google_maps_flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:flutter/material.dart';

import 'animate_camera.dart';
import 'clustering.dart';
import 'ground_overlay.dart';
import 'heatmap.dart';
import 'lite_mode.dart';
import 'map_click.dart';
Expand Down Expand Up @@ -40,6 +41,7 @@ final List<GoogleMapExampleAppPage> _allPages = <GoogleMapExampleAppPage>[
const SnapshotPage(),
const LiteModePage(),
const TileOverlayPage(),
const GroundOverlayPage(),
const ClusteringPage(),
const MapIdPage(),
const HeatmapPage(),
Expand Down
4 changes: 2 additions & 2 deletions packages/google_maps_flutter/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ environment:
dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.10.0
google_maps_flutter_platform_interface: ^2.10.0
google_maps_flutter: ^2.16.0
google_maps_flutter_platform_interface: ^2.15.0
google_maps_flutter_tizen:
path: ../

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ part 'src/circles.dart';
part 'src/convert.dart';
part 'src/google_maps_controller.dart';
part 'src/google_maps_flutter_tizen.dart';
part 'src/ground_overlay.dart';
part 'src/ground_overlays.dart';
part 'src/marker.dart';
part 'src/markers.dart';
part 'src/marker_clustering.dart';
Expand Down
133 changes: 133 additions & 0 deletions packages/google_maps_flutter/lib/src/convert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,62 @@ Map<int, String> _mapTypeToMapTypeId = <int, String>{
4: 'hybrid',
};

// Builds the raw map options map from a [MapConfiguration].
//
// This mirrors the platform interface's `jsonForMapConfiguration` helper
// (which is not exported), plus [MapConfiguration.colorScheme].
//
// Intentionally omitted:
// * `cloudMapId` — deprecated alias for `mapId`, which is already serialized.
// * `markerType` — only relevant to advanced markers, which are not supported
// on Tizen.
Map<String, dynamic> _mapOptionsFromConfiguration(MapConfiguration config) {
final EdgeInsets? padding = config.padding;
return <String, dynamic>{
if (config.compassEnabled != null) 'compassEnabled': config.compassEnabled,
if (config.mapToolbarEnabled != null)
'mapToolbarEnabled': config.mapToolbarEnabled,
if (config.cameraTargetBounds != null)
'cameraTargetBounds': config.cameraTargetBounds!.toJson(),
if (config.mapType != null) 'mapType': config.mapType!.index,
if (config.minMaxZoomPreference != null)
'minMaxZoomPreference': config.minMaxZoomPreference!.toJson(),
if (config.rotateGesturesEnabled != null)
'rotateGesturesEnabled': config.rotateGesturesEnabled,
if (config.scrollGesturesEnabled != null)
'scrollGesturesEnabled': config.scrollGesturesEnabled,
if (config.tiltGesturesEnabled != null)
'tiltGesturesEnabled': config.tiltGesturesEnabled,
if (config.zoomControlsEnabled != null)
'zoomControlsEnabled': config.zoomControlsEnabled,
if (config.zoomGesturesEnabled != null)
'zoomGesturesEnabled': config.zoomGesturesEnabled,
if (config.liteModeEnabled != null)
'liteModeEnabled': config.liteModeEnabled,
if (config.trackCameraPosition != null)
'trackCameraPosition': config.trackCameraPosition,
if (config.myLocationEnabled != null)
'myLocationEnabled': config.myLocationEnabled,
if (config.myLocationButtonEnabled != null)
'myLocationButtonEnabled': config.myLocationButtonEnabled,
if (padding != null)
'padding': <double>[
padding.top,
padding.left,
padding.bottom,
padding.right,
],
if (config.indoorViewEnabled != null)
'indoorEnabled': config.indoorViewEnabled,
if (config.trafficEnabled != null) 'trafficEnabled': config.trafficEnabled,
if (config.buildingsEnabled != null)
'buildingsEnabled': config.buildingsEnabled,
if (config.mapId != null) 'mapId': config.mapId,
if (config.style != null) 'style': config.style,
if (config.colorScheme != null) 'colorScheme': config.colorScheme!.index,
};
}

String? _getCameraBounds(dynamic option) {
if (option is! List<Object?> || option.first == null) {
return null;
Expand Down Expand Up @@ -90,9 +146,33 @@ String _rawOptionsToString(Map<String, dynamic> rawOptions) {
options += ", gestureHandling: 'auto'";
}

final String? colorScheme = _colorSchemeToJs(rawOptions['colorScheme']);
if (colorScheme != null) {
options += ', colorScheme: $colorScheme';
}

return options;
}

// Maps a serialized MapColorScheme value from the platform interface to the
// JavaScript google.maps.ColorScheme enum.
String? _colorSchemeToJs(Object? value) {
if (value is! int) {
return null;
}
// The platform interface serializes MapColorScheme as its enum index:
// 0 = light, 1 = dark, 2 = followSystem.
switch (value) {
case 0:
return 'google.maps.ColorScheme.LIGHT';
case 1:
return 'google.maps.ColorScheme.DARK';
case 2:
return 'google.maps.ColorScheme.FOLLOW_SYSTEM';
}
return null;
}

String _applyInitialPosition(CameraPosition initialPosition, String options) {
options += ', zoom: ${initialPosition.zoom}';
options +=
Expand Down Expand Up @@ -400,3 +480,56 @@ util.GCircleOptions _circleOptionsFromCircle(Circle circle) {
..visible = circle.visible
..zIndex = circle.zIndex;
}

util.GGroundOverlayOptions? _groundOverlayOptionsFromGroundOverlay(
GroundOverlay groundOverlay,
) {
// The JS Maps GroundOverlay only supports bounds-based positioning. Skip
// position-only overlays — the platform interface allows the field but the
// JS API has no equivalent.
final LatLngBounds? bounds = groundOverlay.bounds;
if (bounds == null) {
debugPrint(
'GroundOverlay ${groundOverlay.groundOverlayId.value} skipped: '
'the Google Maps JavaScript API only supports bounds-based '
'ground overlays.',
);
return null;
}
final String? imageUrl = _imageUrlFromMapBitmap(groundOverlay.image);
if (imageUrl == null) {
debugPrint(
'GroundOverlay ${groundOverlay.groundOverlayId.value} skipped: '
'unsupported image source.',
);
return null;
}
return util.GGroundOverlayOptions()
..url = "'$imageUrl'"
..bounds = '{south:${bounds.southwest.latitude},'
' west:${bounds.southwest.longitude},'
' north:${bounds.northeast.latitude},'
' east:${bounds.northeast.longitude}}'
..clickable = groundOverlay.clickable
..opacity = 1.0 - groundOverlay.transparency
..visible = groundOverlay.visible;
}

String? _imageUrlFromMapBitmap(MapBitmap bitmap) {
final List<Object?> iconConfig = bitmap.toJson() as List<Object?>;
if (iconConfig.isEmpty) {
return null;
}
if (iconConfig[0] == 'asset' && iconConfig.length >= 2) {
final Map<String, Object?> assetConfig =
iconConfig[1]! as Map<String, Object?>;
return '../${assetConfig['assetName']}';
}
if (iconConfig[0] == 'bytes' && iconConfig.length >= 2) {
final Map<String, Object?> assetConfig =
iconConfig[1]! as Map<String, Object?>;
final List<int> bytes = assetConfig['byteData']! as List<int>;
return 'data:image/png;base64,${base64Encode(bytes)}';
}
return null;
}
Loading
Loading