From 66336acd2957bd6537c773f9c2d9420d06cd5e4b Mon Sep 17 00:00:00 2001 From: nimr77 Date: Mon, 16 Dec 2024 12:50:02 +0100 Subject: [PATCH] fix issue with flutter 3.27 --- example/lib/map_click.dart | 5 +- example/lib/map_coordinates.dart | 5 +- example/lib/place_annotation.dart | 382 +++++++++++++------------- example/lib/scrolling_map.dart | 23 +- example/test_driver/test_widgets.dart | 2 +- lib/apple_maps_flutter.dart | 11 +- lib/src/annotation.dart | 336 +++++++++++----------- lib/src/annotation_updates.dart | 49 ++-- lib/src/camera.dart | 74 ++--- lib/src/circle_updates.dart | 49 ++-- lib/src/location.dart | 78 +++--- lib/src/polygon_updates.dart | 49 ++-- lib/src/polyline_updates.dart | 49 ++-- lib/src/snapshot_options.dart | 44 +-- lib/src/ui.dart | 80 +++--- pubspec.yaml | 6 +- 16 files changed, 619 insertions(+), 623 deletions(-) diff --git a/example/lib/map_click.dart b/example/lib/map_click.dart index 49510d4..6ff8eac 100644 --- a/example/lib/map_click.dart +++ b/example/lib/map_click.dart @@ -4,7 +4,6 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'page.dart'; @@ -30,11 +29,11 @@ class _MapClickBody extends StatefulWidget { } class _MapClickBodyState extends State<_MapClickBody> { - _MapClickBodyState(); - AppleMapController? mapController; + LatLng? _lastTap; LatLng? _lastLongPress; + _MapClickBodyState(); @override Widget build(BuildContext context) { diff --git a/example/lib/map_coordinates.dart b/example/lib/map_coordinates.dart index de28d54..5d63b77 100644 --- a/example/lib/map_coordinates.dart +++ b/example/lib/map_coordinates.dart @@ -4,7 +4,6 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'page.dart'; @@ -30,13 +29,13 @@ class _MapCoordinatesBody extends StatefulWidget { } class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { - _MapCoordinatesBodyState(); - AppleMapController? mapController; + LatLngBounds _visibleRegion = LatLngBounds( southwest: const LatLng(0, 0), northeast: const LatLng(0, 0), ); + _MapCoordinatesBodyState(); @override Widget build(BuildContext context) { diff --git a/example/lib/place_annotation.dart b/example/lib/place_annotation.dart index 3a3e28b..af615c7 100644 --- a/example/lib/place_annotation.dart +++ b/example/lib/place_annotation.dart @@ -4,8 +4,6 @@ import 'dart:async'; import 'dart:math'; -import 'dart:typed_data'; -import 'dart:ui'; import 'dart:ui' as ui; import 'package:apple_maps_flutter/apple_maps_flutter.dart'; @@ -14,14 +12,7 @@ import 'package:flutter/services.dart'; import 'page.dart'; -class PlaceAnnotationPage extends ExamplePage { - PlaceAnnotationPage() : super(const Icon(Icons.place), 'Place annotation'); - - @override - Widget build(BuildContext context) { - return const PlaceAnnotationBody(); - } -} +typedef Annotation AnnotationUpdateAction(Annotation annotation); class PlaceAnnotationBody extends StatefulWidget { const PlaceAnnotationBody(); @@ -30,13 +21,10 @@ class PlaceAnnotationBody extends StatefulWidget { State createState() => PlaceAnnotationBodyState(); } -typedef Annotation AnnotationUpdateAction(Annotation annotation); - class PlaceAnnotationBodyState extends State { - PlaceAnnotationBodyState(); static final LatLng center = const LatLng(-33.86711, 151.1947171); - late AppleMapController controller; + Uint8List? _imageBytes; Map annotations = {}; late AnnotationId selectedAnnotationId; @@ -44,9 +32,115 @@ class PlaceAnnotationBodyState extends State { BitmapDescriptor? _annotationIcon; late BitmapDescriptor _iconFromBytes; double _devicePixelRatio = 3.0; + PlaceAnnotationBodyState(); - void _onMapCreated(AppleMapController controller) { - this.controller = controller; + @override + Widget build(BuildContext context) { + _createAnnotationImageFromAsset(context, _devicePixelRatio); + _getBytesFromAsset('assets/creator.png', 160); + return SafeArea( + child: Column( + children: [ + Expanded( + child: AppleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11, + ), + annotations: Set.of(annotations.values), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text('add defaultAnnotation'), + onPressed: () => _add('pin'), + ), + TextButton( + child: const Text('add defaultWithHue'), + onPressed: () => _add('defaultAnnotationWithColor'), + ), + TextButton( + child: const Text('add markerAnnotation'), + onPressed: () => _add('marker'), + ), + TextButton( + child: const Text('add markerWithHue'), + onPressed: () => _add('markerAnnotationWithHue'), + ), + TextButton( + child: const Text('add customAnnotation'), + onPressed: () => _add('customAnnotation'), + ), + TextButton( + child: const Text('customAnnotation from bytes'), + onPressed: () => _add('customAnnotationFromBytes'), + ), + TextButton( + child: const Text('remove'), + onPressed: _remove, + ), + TextButton( + child: const Text('change info'), + onPressed: _changeInfo, + ), + TextButton( + child: const Text('infoWindow is shown?s'), + onPressed: _isInfoWindowShown, + ), + TextButton( + child: const Text('change alpha'), + onPressed: _changeAlpha, + ), + TextButton( + child: const Text('toggle draggable'), + onPressed: _toggleDraggable, + ), + TextButton( + child: const Text('change position'), + onPressed: _changePosition, + ), + TextButton( + child: const Text('toggle visible'), + onPressed: _toggleVisible, + ), + TextButton( + child: const Text('show infoWindow'), + onPressed: _showInfoWindow, + ), + TextButton( + child: const Text('hide infoWindow'), + onPressed: _hideInfoWindow, + ), + TextButton( + child: const Text('change zIndex'), + onPressed: () => _changeZIndex(selectedAnnotationId), + ), + TextButton( + child: Text('Take a snapshot'), + onPressed: () async { + final imageBytes = await this.controller.takeSnapshot(); + setState(() { + _imageBytes = imageBytes; + }); + }, + ), + Container( + decoration: BoxDecoration(color: Colors.blueGrey[50]), + height: 180, + child: + _imageBytes != null ? Image.memory(_imageBytes!) : null, + ), + ], + ), + ) + ], + ), + ); } @override @@ -54,20 +148,6 @@ class PlaceAnnotationBodyState extends State { super.dispose(); } - void _onAnnotationTapped(AnnotationId annotationId) { - final Annotation? tappedAnnotation = annotations[annotationId]; - if (tappedAnnotation != null) { - setState(() { - if (annotations.containsKey(tappedAnnotation)) { - final Annotation resetOld = - annotations[selectedAnnotationId]!.copyWith(); - annotations[selectedAnnotationId] = resetOld; - } - selectedAnnotationId = annotationId; - }); - } - } - void _add(String iconType) { final int annotationCount = annotations.length; @@ -124,36 +204,12 @@ class PlaceAnnotationBodyState extends State { }); } - void _remove() { - setState(() { - if (annotations.containsKey(selectedAnnotationId)) { - annotations.remove(selectedAnnotationId); - } - }); - } - - void _changePosition() { - final Annotation annotation = annotations[selectedAnnotationId]!; - final LatLng current = annotation.position; - final Offset offset = Offset( - center.latitude - current.latitude, - center.longitude - current.longitude, - ); - setState(() { - annotations[selectedAnnotationId] = annotation.copyWith( - positionParam: LatLng( - center.latitude + offset.dy, - center.longitude + offset.dx, - ), - ); - }); - } - - Future _toggleDraggable() async { + Future _changeAlpha() async { final Annotation annotation = annotations[selectedAnnotationId]!; + final double current = annotation.alpha; setState(() { annotations[selectedAnnotationId] = annotation.copyWith( - draggableParam: !annotation.draggable, + alphaParam: current < 0.1 ? 1.0 : current * 0.75, ); }); } @@ -171,21 +227,29 @@ class PlaceAnnotationBodyState extends State { }); } - Future _changeAlpha() async { + void _changePosition() { final Annotation annotation = annotations[selectedAnnotationId]!; - final double current = annotation.alpha; + final LatLng current = annotation.position; + final Offset offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); setState(() { annotations[selectedAnnotationId] = annotation.copyWith( - alphaParam: current < 0.1 ? 1.0 : current * 0.75, + positionParam: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), ); }); } - Future _toggleVisible() async { - final Annotation annotation = annotations[selectedAnnotationId]!; + Future _changeZIndex(AnnotationId annotationId) async { + final Annotation annotation = annotations[annotationId]!; + final double current = annotation.zIndex; setState(() { - annotations[selectedAnnotationId] = annotation.copyWith( - visibleParam: !annotation.visible, + annotations[annotationId] = annotation.copyWith( + zIndexParam: current >= 12.0 ? 0.0 : current + 1.0, ); }); } @@ -201,15 +265,15 @@ class PlaceAnnotationBodyState extends State { } } - void _updateBitmap(BitmapDescriptor bitmap) { - setState(() { - _annotationIcon = bitmap; - }); - } - - Future _showInfoWindow() async { - final Annotation annotation = annotations[selectedAnnotationId]!; - await this.controller.showMarkerInfoWindow(annotation.annotationId); + Future _getBytesFromAsset(String path, int width) async { + ByteData data = await rootBundle.load(path); + ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), + targetWidth: width); + ui.FrameInfo fi = await codec.getNextFrame(); + _iconFromBytes = BitmapDescriptor.fromBytes( + (await fi.image.toByteData(format: ui.ImageByteFormat.png))! + .buffer + .asUint8List()); } Future _hideInfoWindow() async { @@ -226,133 +290,67 @@ class PlaceAnnotationBodyState extends State { .isMarkerInfoWindowShown(annotation.annotationId))!; } - Future _getBytesFromAsset(String path, int width) async { - ByteData data = await rootBundle.load(path); - ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), - targetWidth: width); - ui.FrameInfo fi = await codec.getNextFrame(); - _iconFromBytes = BitmapDescriptor.fromBytes( - (await fi.image.toByteData(format: ui.ImageByteFormat.png))! - .buffer - .asUint8List()); + void _onAnnotationTapped(AnnotationId annotationId) { + final Annotation? tappedAnnotation = annotations[annotationId]; + if (tappedAnnotation != null) { + setState(() { + if (annotations.containsKey(tappedAnnotation)) { + final Annotation resetOld = + annotations[selectedAnnotationId]!.copyWith(); + annotations[selectedAnnotationId] = resetOld; + } + selectedAnnotationId = annotationId; + }); + } } - Future _changeZIndex(AnnotationId annotationId) async { - final Annotation annotation = annotations[annotationId]!; - final double current = annotation.zIndex; + void _onMapCreated(AppleMapController controller) { + this.controller = controller; + } + + void _remove() { setState(() { - annotations[annotationId] = annotation.copyWith( - zIndexParam: current >= 12.0 ? 0.0 : current + 1.0, + if (annotations.containsKey(selectedAnnotationId)) { + annotations.remove(selectedAnnotationId); + } + }); + } + + Future _showInfoWindow() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + await this.controller.showMarkerInfoWindow(annotation.annotationId); + } + + Future _toggleDraggable() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + setState(() { + annotations[selectedAnnotationId] = annotation.copyWith( + draggableParam: !annotation.draggable, ); }); } + Future _toggleVisible() async { + final Annotation annotation = annotations[selectedAnnotationId]!; + setState(() { + annotations[selectedAnnotationId] = annotation.copyWith( + visibleParam: !annotation.visible, + ); + }); + } + + void _updateBitmap(BitmapDescriptor bitmap) { + setState(() { + _annotationIcon = bitmap; + }); + } +} + +class PlaceAnnotationPage extends ExamplePage { + PlaceAnnotationPage() : super(const Icon(Icons.place), 'Place annotation'); + @override Widget build(BuildContext context) { - _createAnnotationImageFromAsset(context, _devicePixelRatio); - _getBytesFromAsset('assets/creator.png', 160); - return SafeArea( - child: Column( - children: [ - Expanded( - child: AppleMap( - onMapCreated: _onMapCreated, - initialCameraPosition: const CameraPosition( - target: LatLng(-33.852, 151.211), - zoom: 11, - ), - annotations: Set.of(annotations.values), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Wrap( - alignment: WrapAlignment.spaceEvenly, - children: [ - TextButton( - child: const Text('add defaultAnnotation'), - onPressed: () => _add('pin'), - ), - TextButton( - child: const Text('add defaultWithHue'), - onPressed: () => _add('defaultAnnotationWithColor'), - ), - TextButton( - child: const Text('add markerAnnotation'), - onPressed: () => _add('marker'), - ), - TextButton( - child: const Text('add markerWithHue'), - onPressed: () => _add('markerAnnotationWithHue'), - ), - TextButton( - child: const Text('add customAnnotation'), - onPressed: () => _add('customAnnotation'), - ), - TextButton( - child: const Text('customAnnotation from bytes'), - onPressed: () => _add('customAnnotationFromBytes'), - ), - TextButton( - child: const Text('remove'), - onPressed: _remove, - ), - TextButton( - child: const Text('change info'), - onPressed: _changeInfo, - ), - TextButton( - child: const Text('infoWindow is shown?s'), - onPressed: _isInfoWindowShown, - ), - TextButton( - child: const Text('change alpha'), - onPressed: _changeAlpha, - ), - TextButton( - child: const Text('toggle draggable'), - onPressed: _toggleDraggable, - ), - TextButton( - child: const Text('change position'), - onPressed: _changePosition, - ), - TextButton( - child: const Text('toggle visible'), - onPressed: _toggleVisible, - ), - TextButton( - child: const Text('show infoWindow'), - onPressed: _showInfoWindow, - ), - TextButton( - child: const Text('hide infoWindow'), - onPressed: _hideInfoWindow, - ), - TextButton( - child: const Text('change zIndex'), - onPressed: () => _changeZIndex(selectedAnnotationId), - ), - TextButton( - child: Text('Take a snapshot'), - onPressed: () async { - final imageBytes = await this.controller.takeSnapshot(); - setState(() { - _imageBytes = imageBytes; - }); - }, - ), - Container( - decoration: BoxDecoration(color: Colors.blueGrey[50]), - height: 180, - child: - _imageBytes != null ? Image.memory(_imageBytes!) : null, - ), - ], - ), - ) - ], - ), - ); + return const PlaceAnnotationBody(); } } diff --git a/example/lib/scrolling_map.dart b/example/lib/scrolling_map.dart index 4b6143a..3e043c7 100644 --- a/example/lib/scrolling_map.dart +++ b/example/lib/scrolling_map.dart @@ -8,24 +8,14 @@ import 'package:apple_maps_flutter/apple_maps_flutter.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'page.dart'; -class ScrollingMapPage extends ExamplePage { - ScrollingMapPage() : super(const Icon(Icons.map), 'Scrolling map'); - - @override - Widget build(BuildContext context) { - return const ScrollingMapBody(); - } -} - class ScrollingMapBody extends StatelessWidget { - const ScrollingMapBody(); - final LatLng center = const LatLng(32.080664, 34.9563837); + const ScrollingMapBody(); + @override Widget build(BuildContext context) { return SafeArea( @@ -113,3 +103,12 @@ class ScrollingMapBody extends StatelessWidget { ); } } + +class ScrollingMapPage extends ExamplePage { + ScrollingMapPage() : super(const Icon(Icons.map), 'Scrolling map'); + + @override + Widget build(BuildContext context) { + return const ScrollingMapBody(); + } +} diff --git a/example/test_driver/test_widgets.dart b/example/test_driver/test_widgets.dart index d2c27fd..5656c9f 100644 --- a/example/test_driver/test_widgets.dart +++ b/example/test_driver/test_widgets.dart @@ -8,5 +8,5 @@ import 'package:flutter/widgets.dart'; Future pumpWidget(Widget widget) { runApp(widget); - return WidgetsBinding.instance!.endOfFrame; + return WidgetsBinding.instance.endOfFrame; } diff --git a/lib/apple_maps_flutter.dart b/lib/apple_maps_flutter.dart index dccdfc8..84aff66 100644 --- a/lib/apple_maps_flutter.dart +++ b/lib/apple_maps_flutter.dart @@ -5,31 +5,28 @@ library apple_maps_flutter; import 'dart:async'; -import 'dart:typed_data'; -import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; part 'src/annotation.dart'; part 'src/annotation_updates.dart'; part 'src/apple_map.dart'; part 'src/bitmap.dart'; -part 'src/cap.dart'; part 'src/callbacks.dart'; part 'src/camera.dart'; +part 'src/cap.dart'; part 'src/circle.dart'; part 'src/circle_updates.dart'; part 'src/controller.dart'; part 'src/joint_type.dart'; part 'src/location.dart'; part 'src/pattern_item.dart'; -part 'src/polyline.dart'; -part 'src/polyline_updates.dart'; part 'src/polygon.dart'; part 'src/polygon_updates.dart'; -part 'src/ui.dart'; +part 'src/polyline.dart'; +part 'src/polyline_updates.dart'; part 'src/snapshot_options.dart'; +part 'src/ui.dart'; diff --git a/lib/src/annotation.dart b/lib/src/annotation.dart index 17d61cf..5f2e48c 100644 --- a/lib/src/annotation.dart +++ b/lib/src/annotation.dart @@ -4,6 +4,16 @@ part of apple_maps_flutter; +Map _keyByAnnotationId( + Iterable? annotations) { + if (annotations == null) { + return {}; + } + return Map.fromEntries(annotations.map( + (Annotation annotation) => MapEntry( + annotation.annotationId, annotation))); +} + dynamic _offsetToJson(Offset? offset) { if (offset == null) { return null; @@ -11,117 +21,14 @@ dynamic _offsetToJson(Offset? offset) { return [offset.dx, offset.dy]; } -/// Text labels for a [Annotation] info window. -class InfoWindow { - const InfoWindow({ - this.title, - this.snippet, - this.anchor = const Offset(0.5, 0.0), - this.onTap, - }); - - /// Text labels specifying that no text is to be displayed. - static const InfoWindow noText = InfoWindow(); - - /// Text displayed in an info window when the user taps the annotation. - /// - /// A null value means no title. - final String? title; - - /// Additional text displayed below the [title]. - /// - /// A null value means no additional text. - final String? snippet; - - /// The icon image point that will be the anchor of the info window when - /// displayed. - /// - /// The image point is specified in normalized coordinates: An anchor of - /// (0.0, 0.0) means the top left corner of the image. An anchor - /// of (1.0, 1.0) means the bottom right corner of the image. - final Offset anchor; - - /// onTap callback for this [InfoWindow]. - final VoidCallback? onTap; - - /// Creates a new [InfoWindow] object whose values are the same as this instance, - /// unless overwritten by the specified parameters. - InfoWindow copyWith({ - String? titleParam, - String? snippetParam, - Offset? anchorParam, - VoidCallback? onTapParam, - }) { - return InfoWindow( - title: titleParam ?? title, - snippet: snippetParam ?? snippet, - anchor: anchorParam ?? anchor, - onTap: onTapParam ?? onTap, - ); - } - - dynamic _toJson() { - final Map json = {}; - - void addIfPresent(String fieldName, dynamic value) { - if (value != null) { - json[fieldName] = value; - } - } - - addIfPresent('title', title); - addIfPresent('snippet', snippet); - addIfPresent('anchor', _offsetToJson(anchor)); - addIfPresent('consumesTapEvents', onTap != null); - - return json; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! InfoWindow) return false; - final InfoWindow typedOther = other; - return title == typedOther.title && - snippet == typedOther.snippet && - anchor == typedOther.anchor && - onTap == typedOther.onTap; - } - - @override - int get hashCode => hashValues(title.hashCode, snippet, anchor); - - @override - String toString() { - return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor, consumesTapEvents: ${onTap != null}}'; - } -} - -/// Uniquely identifies a [Annotation] among [AppleMap] annotations. -/// -/// This does not have to be globally unique, only unique among the list. -@immutable -class AnnotationId { - AnnotationId(this.value); - - /// value of the [AnnotationId]. - final String value; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! AnnotationId) return false; - final AnnotationId typedOther = other; - return value == typedOther.value; - } - - @override - int get hashCode => value.hashCode; - - @override - String toString() { - return 'AnnotationId{value: $value}'; +List>? _serializeAnnotationSet( + Set? annotations) { + if (annotations == null) { + return null; } + return annotations + .map>((Annotation m) => m._toJson()) + .toList(); } /// Marks a geographical location on the map. @@ -131,32 +38,6 @@ class AnnotationId { /// due to map rotations, tilting, or zooming. @immutable class Annotation { - /// Creates a set of annotation configuration options. - /// - /// Default annotation options. - /// - /// Specifies a annotation that - /// * is fully opaque; [alpha] is 1.0 - /// * has default tap handling; [consumeTapEvents] is false - /// * is stationary; [draggable] is false - /// * has a default icon; [icon] is default Pin Annotation - /// * has no info window text; [infoWindowText] is `InfoWindowText.noText` - /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)` - /// * is visible; [visible] is true - Annotation({ - required this.annotationId, - this.alpha = 1.0, - this.anchor = const Offset(0.5, 1.0), - this.draggable = false, - this.icon = BitmapDescriptor.defaultAnnotation, - this.infoWindow = InfoWindow.noText, - this.position = const LatLng(0.0, 0.0), - this.onTap, - this.visible = true, - this.zIndex = -1, - this.onDragEnd, - }) : assert(0.0 <= alpha && alpha <= 1.0); - /// Uniquely identifies a [Annotation]. final AnnotationId annotationId; @@ -201,6 +82,51 @@ class Annotation { /// earlier, and thus appearing to be closer to the surface of the Earth. double zIndex; + /// Creates a set of annotation configuration options. + /// + /// Default annotation options. + /// + /// Specifies a annotation that + /// * is fully opaque; [alpha] is 1.0 + /// * has default tap handling; [consumeTapEvents] is false + /// * is stationary; [draggable] is false + /// * has a default icon; [icon] is default Pin Annotation + /// * has no info window text; [infoWindowText] is `InfoWindowText.noText` + /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)` + /// * is visible; [visible] is true + Annotation({ + required this.annotationId, + this.alpha = 1.0, + this.anchor = const Offset(0.5, 1.0), + this.draggable = false, + this.icon = BitmapDescriptor.defaultAnnotation, + this.infoWindow = InfoWindow.noText, + this.position = const LatLng(0.0, 0.0), + this.onTap, + this.visible = true, + this.zIndex = -1, + this.onDragEnd, + }) : assert(0.0 <= alpha && alpha <= 1.0); + + @override + int get hashCode => annotationId.hashCode; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! Annotation) return false; + final Annotation typedOther = other; + return annotationId == typedOther.annotationId && + alpha == typedOther.alpha && + anchor == typedOther.anchor && + draggable == typedOther.draggable && + icon == typedOther.icon && + infoWindow == typedOther.infoWindow && + position == typedOther.position && + visible == typedOther.visible && + zIndex == typedOther.zIndex; + } + /// Creates a new [Annotation] object whose values are the same as this instance, /// unless overwritten by the specified parameters. Annotation copyWith({ @@ -231,6 +157,13 @@ class Annotation { ); } + @override + String toString() { + return 'Annotation{annotationId: $annotationId, alpha: $alpha, draggable: $draggable, ' + 'icon: $icon, infoWindow: $infoWindow, position: $position ,visible: $visible, ' + 'onTap: $onTap}, zIndex: $zIndex, onTap: $onTap}'; + } + Map _toJson() { final Map json = {}; @@ -251,50 +184,117 @@ class Annotation { addIfPresent('zIndex', zIndex); return json; } +} + +/// Uniquely identifies a [Annotation] among [AppleMap] annotations. +/// +/// This does not have to be globally unique, only unique among the list. +@immutable +class AnnotationId { + /// value of the [AnnotationId]. + final String value; + + AnnotationId(this.value); + + @override + int get hashCode => value.hashCode; @override bool operator ==(Object other) { if (identical(this, other)) return true; - if (other is! Annotation) return false; - final Annotation typedOther = other; - return annotationId == typedOther.annotationId && - alpha == typedOther.alpha && - anchor == typedOther.anchor && - draggable == typedOther.draggable && - icon == typedOther.icon && - infoWindow == typedOther.infoWindow && - position == typedOther.position && - visible == typedOther.visible && - zIndex == typedOther.zIndex; + if (other is! AnnotationId) return false; + final AnnotationId typedOther = other; + return value == typedOther.value; } - @override - int get hashCode => annotationId.hashCode; - @override String toString() { - return 'Annotation{annotationId: $annotationId, alpha: $alpha, draggable: $draggable, ' - 'icon: $icon, infoWindow: $infoWindow, position: $position ,visible: $visible, ' - 'onTap: $onTap}, zIndex: $zIndex, onTap: $onTap}'; + return 'AnnotationId{value: $value}'; } } -Map _keyByAnnotationId( - Iterable? annotations) { - if (annotations == null) { - return {}; +/// Text labels for a [Annotation] info window. +class InfoWindow { + /// Text labels specifying that no text is to be displayed. + static const InfoWindow noText = InfoWindow(); + + /// Text displayed in an info window when the user taps the annotation. + /// + /// A null value means no title. + final String? title; + + /// Additional text displayed below the [title]. + /// + /// A null value means no additional text. + final String? snippet; + + /// The icon image point that will be the anchor of the info window when + /// displayed. + /// + /// The image point is specified in normalized coordinates: An anchor of + /// (0.0, 0.0) means the top left corner of the image. An anchor + /// of (1.0, 1.0) means the bottom right corner of the image. + final Offset anchor; + + /// onTap callback for this [InfoWindow]. + final VoidCallback? onTap; + + const InfoWindow({ + this.title, + this.snippet, + this.anchor = const Offset(0.5, 0.0), + this.onTap, + }); + + @override + int get hashCode => Object.hash(title.hashCode, snippet, anchor); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! InfoWindow) return false; + final InfoWindow typedOther = other; + return title == typedOther.title && + snippet == typedOther.snippet && + anchor == typedOther.anchor && + onTap == typedOther.onTap; } - return Map.fromEntries(annotations.map( - (Annotation annotation) => MapEntry( - annotation.annotationId, annotation))); -} -List>? _serializeAnnotationSet( - Set? annotations) { - if (annotations == null) { - return null; + /// Creates a new [InfoWindow] object whose values are the same as this instance, + /// unless overwritten by the specified parameters. + InfoWindow copyWith({ + String? titleParam, + String? snippetParam, + Offset? anchorParam, + VoidCallback? onTapParam, + }) { + return InfoWindow( + title: titleParam ?? title, + snippet: snippetParam ?? snippet, + anchor: anchorParam ?? anchor, + onTap: onTapParam ?? onTap, + ); + } + + @override + String toString() { + return 'InfoWindow{title: $title, snippet: $snippet, anchor: $anchor, consumesTapEvents: ${onTap != null}}'; + } + + dynamic _toJson() { + final Map json = {}; + + void addIfPresent(String fieldName, dynamic value) { + if (value != null) { + json[fieldName] = value; + } + } + + addIfPresent('title', title); + addIfPresent('snippet', snippet); + addIfPresent('anchor', _offsetToJson(anchor)); + addIfPresent('consumesTapEvents', onTap != null); + + return json; } - return annotations - .map>((Annotation m) => m._toJson()) - .toList(); } diff --git a/lib/src/annotation_updates.dart b/lib/src/annotation_updates.dart index be0f13a..6f3eec9 100644 --- a/lib/src/annotation_updates.dart +++ b/lib/src/annotation_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _AnnotationUpdates { + late Set annotationsToAdd; + + late Set annotationIdsToRemove; + late Set annotationsToChange; + /// Computes [_AnnotationUpdates] given previous and current [Annotation]s. _AnnotationUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -50,9 +55,26 @@ class _AnnotationUpdates { annotationsToChange = _annotationsToChange; } - late Set annotationsToAdd; - late Set annotationIdsToRemove; - late Set annotationsToChange; + @override + int get hashCode => + Object.hash(annotationsToAdd, annotationIdsToRemove, annotationsToChange); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (other is! _AnnotationUpdates) return false; + final _AnnotationUpdates typedOther = other; + return setEquals(annotationsToAdd, typedOther.annotationsToAdd) && + setEquals(annotationIdsToRemove, typedOther.annotationIdsToRemove) && + setEquals(annotationsToChange, typedOther.annotationsToChange); + } + + @override + String toString() { + return '_AnnotationUpdates{annotationsToAdd: $annotationsToAdd, ' + 'annotationIdsToRemove: $annotationIdsToRemove, ' + 'annotationsToChange: $annotationsToChange}'; + } Map _toMap() { final Map updateMap = {}; @@ -74,25 +96,4 @@ class _AnnotationUpdates { return updateMap; } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! _AnnotationUpdates) return false; - final _AnnotationUpdates typedOther = other; - return setEquals(annotationsToAdd, typedOther.annotationsToAdd) && - setEquals(annotationIdsToRemove, typedOther.annotationIdsToRemove) && - setEquals(annotationsToChange, typedOther.annotationsToChange); - } - - @override - int get hashCode => - hashValues(annotationsToAdd, annotationIdsToRemove, annotationsToChange); - - @override - String toString() { - return '_AnnotationUpdates{annotationsToAdd: $annotationsToAdd, ' - 'annotationIdsToRemove: $annotationIdsToRemove, ' - 'annotationsToChange: $annotationsToChange}'; - } } diff --git a/lib/src/camera.dart b/lib/src/camera.dart index 09bc24f..8dd827e 100644 --- a/lib/src/camera.dart +++ b/lib/src/camera.dart @@ -8,13 +8,6 @@ part of apple_maps_flutter; /// shown in the map view. Aggregates the camera's [target] geographical /// location, its [zoom] level, [pitch] angle, and [heading]. class CameraPosition { - const CameraPosition({ - required this.target, - this.heading = 0.0, - this.pitch = 0.0, - this.zoom = 0, - }); - /// The camera's bearing in degrees, measured clockwise from north. /// /// A bearing of 0.0, the default, means the camera points north. @@ -41,6 +34,31 @@ class CameraPosition { /// will be silently clamped to the supported range. final double zoom; + const CameraPosition({ + required this.target, + this.heading = 0.0, + this.pitch = 0.0, + this.zoom = 0, + }); + + @override + int get hashCode => Object.hash(heading, target, pitch, zoom); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (runtimeType != other.runtimeType) return false; + final CameraPosition typedOther = other; + return heading == typedOther.heading && + target == typedOther.target && + pitch == typedOther.pitch && + zoom == typedOther.zoom; + } + + @override + String toString() => + 'CameraPosition(bearing: $heading, target: $target, tilt: $pitch, zoom: $zoom)'; + dynamic _toMap() => { 'target': target._toJson(), 'heading': heading, @@ -60,31 +78,17 @@ class CameraPosition { zoom: json['zoom'], ); } - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) return true; - if (runtimeType != other.runtimeType) return false; - final CameraPosition typedOther = other; - return heading == typedOther.heading && - target == typedOther.target && - pitch == typedOther.pitch && - zoom == typedOther.zoom; - } - - @override - int get hashCode => hashValues(heading, target, pitch, zoom); - - @override - String toString() => - 'CameraPosition(bearing: $heading, target: $target, tilt: $pitch, zoom: $zoom)'; } /// Defines a camera move, supporting absolute moves as well as moves relative /// the current position. class CameraUpdate { + final dynamic _json; + CameraUpdate._(this._json); + dynamic _toJson() => _json; + /// Returns a camera update that moves the camera to the specified position. static CameraUpdate newCameraPosition(CameraPosition cameraPosition) { return CameraUpdate._( @@ -98,14 +102,6 @@ class CameraUpdate { return CameraUpdate._(['newLatLng', latLng._toJson()]); } - /// Returns a camera update that moves the camera target to the specified - /// geographical location and zoom level. - static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) { - return CameraUpdate._( - ['newLatLngZoom', latLng._toJson(), zoom], - ); - } - /// Returns a camera update that transforms the camera so that the specified /// geographical bounding box is centered in the map view at the greatest /// possible zoom level. A non-zero [padding] insets the bounding box from the @@ -118,6 +114,14 @@ class CameraUpdate { ]); } + /// Returns a camera update that moves the camera target to the specified + /// geographical location and zoom level. + static CameraUpdate newLatLngZoom(LatLng latLng, double zoom) { + return CameraUpdate._( + ['newLatLngZoom', latLng._toJson(), zoom], + ); + } + /// Returns a camera update that modifies the camera zoom level by the /// specified amount. The optional [focus] is a screen point whose underlying /// geographical location should be invariant, if possible, by the movement. @@ -153,8 +157,4 @@ class CameraUpdate { static CameraUpdate zoomTo(double zoom) { return CameraUpdate._(['zoomTo', zoom]); } - - final dynamic _json; - - dynamic _toJson() => _json; } diff --git a/lib/src/circle_updates.dart b/lib/src/circle_updates.dart index a7282cd..4e00a9c 100644 --- a/lib/src/circle_updates.dart +++ b/lib/src/circle_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _CircleUpdates { + late Set circlesToAdd; + + late Set circleIdsToRemove; + late Set circlesToChange; + /// Computes [_CircleUpdates] given previous and current [Circle]s. _CircleUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -54,26 +59,9 @@ class _CircleUpdates { circlesToChange = _circlesToChange; } - late Set circlesToAdd; - late Set circleIdsToRemove; - late Set circlesToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('circlesToAdd', _serializeCircleSet(circlesToAdd)); - addIfNonNull('circlesToChange', _serializeCircleSet(circlesToChange)); - addIfNonNull('circleIdsToRemove', - circleIdsToRemove.map((CircleId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(circlesToAdd, circleIdsToRemove, circlesToChange); @override bool operator ==(Object other) { @@ -85,14 +73,27 @@ class _CircleUpdates { setEquals(circlesToChange, typedOther.circlesToChange); } - @override - int get hashCode => - hashValues(circlesToAdd, circleIdsToRemove, circlesToChange); - @override String toString() { return '_CircleUpdates{circlesToAdd: $circlesToAdd, ' 'circleIdsToRemove: $circleIdsToRemove, ' 'circlesToChange: $circlesToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('circlesToAdd', _serializeCircleSet(circlesToAdd)); + addIfNonNull('circlesToChange', _serializeCircleSet(circlesToChange)); + addIfNonNull('circleIdsToRemove', + circleIdsToRemove.map((CircleId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/location.dart b/lib/src/location.dart index f8360d0..2e25c0f 100644 --- a/lib/src/location.dart +++ b/lib/src/location.dart @@ -6,6 +6,12 @@ part of apple_maps_flutter; /// A pair of latitude and longitude coordinates, stored as degrees. class LatLng { + /// The latitude in degrees between -90.0 and 90.0, both inclusive. + final double latitude; + + /// The longitude in degrees between -180.0 (inclusive) and 180.0 (exclusive). + final double longitude; + /// Creates a geographical location specified in degrees [latitude] and /// [longitude]. /// @@ -18,11 +24,16 @@ class LatLng { (latitude < -90.0 ? -90.0 : (90.0 < latitude ? 90.0 : latitude)), longitude = (longitude + 180.0) % 360.0 - 180.0; - /// The latitude in degrees between -90.0 and 90.0, both inclusive. - final double latitude; + @override + int get hashCode => Object.hash(latitude, longitude); - /// The longitude in degrees between -180.0 (inclusive) and 180.0 (exclusive). - final double longitude; + @override + bool operator ==(Object o) { + return o is LatLng && o.latitude == latitude && o.longitude == longitude; + } + + @override + String toString() => '$runtimeType($latitude, $longitude)'; dynamic _toJson() { return [latitude, longitude]; @@ -34,17 +45,6 @@ class LatLng { } return LatLng(json[0], json[1]); } - - @override - String toString() => '$runtimeType($latitude, $longitude)'; - - @override - bool operator ==(Object o) { - return o is LatLng && o.latitude == latitude && o.longitude == longitude; - } - - @override - int get hashCode => hashValues(latitude, longitude); } /// A latitude/longitude aligned rectangle. @@ -56,6 +56,12 @@ class LatLng { /// * lng ∈ [-180, `northeast.longitude`] ∪ [`southwest.longitude`, 180[, /// if `northeast.longitude` < `southwest.longitude` class LatLngBounds { + /// The southwest corner of the rectangle. + final LatLng southwest; + + /// The northeast corner of the rectangle. + final LatLng northeast; + /// Creates geographical bounding box with the specified corners. /// /// The latitude of the southwest corner cannot be larger than the @@ -63,11 +69,15 @@ class LatLngBounds { LatLngBounds({required this.southwest, required this.northeast}) : assert(southwest.latitude <= northeast.latitude); - /// The southwest corner of the rectangle. - final LatLng southwest; + @override + int get hashCode => Object.hash(southwest, northeast); - /// The northeast corner of the rectangle. - final LatLng northeast; + @override + bool operator ==(Object o) { + return o is LatLngBounds && + o.southwest == southwest && + o.northeast == northeast; + } /// Returns whether this rectangle contains the given [LatLng]. bool contains(LatLng point) { @@ -75,6 +85,11 @@ class LatLngBounds { _containsLongitude(point.longitude); } + @override + String toString() { + return '$runtimeType($southwest, $northeast)'; + } + bool _containsLatitude(double lat) { return (southwest.latitude <= lat) && (lat <= northeast.latitude); } @@ -87,6 +102,11 @@ class LatLngBounds { } } + /// Converts this object to something serializable in JSON. + dynamic _toJson() { + return [southwest._toJson(), northeast._toJson()]; + } + @visibleForTesting static LatLngBounds? fromList(dynamic json) { if (json == null) { @@ -97,24 +117,4 @@ class LatLngBounds { northeast: LatLng._fromJson(json[1])!, ); } - - @override - String toString() { - return '$runtimeType($southwest, $northeast)'; - } - - @override - bool operator ==(Object o) { - return o is LatLngBounds && - o.southwest == southwest && - o.northeast == northeast; - } - - /// Converts this object to something serializable in JSON. - dynamic _toJson() { - return [southwest._toJson(), northeast._toJson()]; - } - - @override - int get hashCode => hashValues(southwest, northeast); } diff --git a/lib/src/polygon_updates.dart b/lib/src/polygon_updates.dart index 76eea3f..3c4b985 100644 --- a/lib/src/polygon_updates.dart +++ b/lib/src/polygon_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _PolygonUpdates { + late Set polygonsToAdd; + + late Set polygonIdsToRemove; + late Set polygonsToChange; + /// Computes [_PolygonUpdates] given previous and current [Polygon]s. _PolygonUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -54,26 +59,9 @@ class _PolygonUpdates { polygonsToChange = _polygonsToChange; } - late Set polygonsToAdd; - late Set polygonIdsToRemove; - late Set polygonsToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polygonsToAdd', _serializePolygonSet(polygonsToAdd)); - addIfNonNull('polygonsToChange', _serializePolygonSet(polygonsToChange)); - addIfNonNull('polygonIdsToRemove', - polygonIdsToRemove.map((PolygonId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(polygonsToAdd, polygonIdsToRemove, polygonsToChange); @override bool operator ==(Object other) { @@ -85,14 +73,27 @@ class _PolygonUpdates { setEquals(polygonsToChange, typedOther.polygonsToChange); } - @override - int get hashCode => - hashValues(polygonsToAdd, polygonIdsToRemove, polygonsToChange); - @override String toString() { return '_PolygonUpdates{polygonsToAdd: $polygonsToAdd, ' 'polygonIdsToRemove: $polygonIdsToRemove, ' 'polygonsToChange: $polygonsToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('polygonsToAdd', _serializePolygonSet(polygonsToAdd)); + addIfNonNull('polygonsToChange', _serializePolygonSet(polygonsToChange)); + addIfNonNull('polygonIdsToRemove', + polygonIdsToRemove.map((PolygonId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/polyline_updates.dart b/lib/src/polyline_updates.dart index b22ba3e..baf813a 100644 --- a/lib/src/polyline_updates.dart +++ b/lib/src/polyline_updates.dart @@ -8,6 +8,11 @@ part of apple_maps_flutter; /// /// Used in [AppleMapController] when the map is updated. class _PolylineUpdates { + late Set polylinesToAdd; + + late Set polylineIdsToRemove; + late Set polylinesToChange; + /// Computes [_PolylineUpdates] given previous and current [Polyline]s. _PolylineUpdates.from(Set? previous, Set? current) { if (previous == null) { @@ -48,26 +53,9 @@ class _PolylineUpdates { polylinesToChange = _polylinesToChange; } - late Set polylinesToAdd; - late Set polylineIdsToRemove; - late Set polylinesToChange; - - Map _toMap() { - final Map updateMap = {}; - - void addIfNonNull(String fieldName, dynamic value) { - if (value != null) { - updateMap[fieldName] = value; - } - } - - addIfNonNull('polylinesToAdd', _serializePolylineSet(polylinesToAdd)); - addIfNonNull('polylinesToChange', _serializePolylineSet(polylinesToChange)); - addIfNonNull('polylineIdsToRemove', - polylineIdsToRemove.map((PolylineId m) => m.value).toList()); - - return updateMap; - } + @override + int get hashCode => + Object.hash(polylinesToAdd, polylineIdsToRemove, polylinesToChange); @override bool operator ==(Object other) { @@ -79,14 +67,27 @@ class _PolylineUpdates { setEquals(polylinesToChange, typedOther.polylinesToChange); } - @override - int get hashCode => - hashValues(polylinesToAdd, polylineIdsToRemove, polylinesToChange); - @override String toString() { return '_PolylineUpdates{polylinesToAdd: $polylinesToAdd, ' 'polylineIdsToRemove: $polylineIdsToRemove, ' 'polylinesToChange: $polylinesToChange}'; } + + Map _toMap() { + final Map updateMap = {}; + + void addIfNonNull(String fieldName, dynamic value) { + if (value != null) { + updateMap[fieldName] = value; + } + } + + addIfNonNull('polylinesToAdd', _serializePolylineSet(polylinesToAdd)); + addIfNonNull('polylinesToChange', _serializePolylineSet(polylinesToChange)); + addIfNonNull('polylineIdsToRemove', + polylineIdsToRemove.map((PolylineId m) => m.value).toList()); + + return updateMap; + } } diff --git a/lib/src/snapshot_options.dart b/lib/src/snapshot_options.dart index 222c46d..b7a8eb4 100644 --- a/lib/src/snapshot_options.dart +++ b/lib/src/snapshot_options.dart @@ -1,6 +1,11 @@ part of apple_maps_flutter; class SnapshotOptions { + final bool showBuildings; + + final bool showPointsOfInterest; + final bool showAnnotations; + final bool showOverlays; const SnapshotOptions({ this.showBuildings = true, this.showPointsOfInterest = true, @@ -8,10 +13,23 @@ class SnapshotOptions { this.showOverlays = true, }); - final bool showBuildings; - final bool showPointsOfInterest; - final bool showAnnotations; - final bool showOverlays; + @override + int get hashCode => Object.hash(showBuildings, showPointsOfInterest); + + @override + bool operator ==(dynamic other) { + if (identical(this, other)) return true; + if (runtimeType != other.runtimeType) return false; + final SnapshotOptions typedOther = other; + return showBuildings == typedOther.showBuildings && + showPointsOfInterest == typedOther.showPointsOfInterest && + showAnnotations == typedOther.showAnnotations && + showOverlays == typedOther.showOverlays; + } + + @override + String toString() => + 'SnapshotOptions(showBuildings: $showBuildings, showPointsOfInterest: $showPointsOfInterest, showAnnotations: $showAnnotations, showOverlays: $showOverlays)'; dynamic _toMap() => { 'showBuildings': showBuildings, @@ -32,22 +50,4 @@ class SnapshotOptions { showOverlays: json['showOverlays'], ); } - - @override - bool operator ==(dynamic other) { - if (identical(this, other)) return true; - if (runtimeType != other.runtimeType) return false; - final SnapshotOptions typedOther = other; - return showBuildings == typedOther.showBuildings && - showPointsOfInterest == typedOther.showPointsOfInterest && - showAnnotations == typedOther.showAnnotations && - showOverlays == typedOther.showOverlays; - } - - @override - int get hashCode => hashValues(showBuildings, showPointsOfInterest); - - @override - String toString() => - 'SnapshotOptions(showBuildings: $showBuildings, showPointsOfInterest: $showPointsOfInterest, showAnnotations: $showAnnotations, showOverlays: $showOverlays)'; } diff --git a/lib/src/ui.dart b/lib/src/ui.dart index d650a2a..1dc577f 100644 --- a/lib/src/ui.dart +++ b/lib/src/ui.dart @@ -4,45 +4,25 @@ part of apple_maps_flutter; -/// Type of map tiles to display. -enum MapType { - /// Normal tiles (traffic and labels, subtle terrain information). - standard, - - /// Satellite imaging tiles (aerial photos) - satellite, - - /// Hybrid tiles (satellite images with some labels/overlays) - hybrid, -} - -enum TrackingMode { - // the user's location is not followed - none, - - // the map follows the user's location - follow, - - // the map follows the user's location and heading - followWithHeading, -} - /// Bounds for the map camera target. // Used with [AppleMapOptions] to wrap a [LatLngBounds] value. This allows // distinguishing between specifying an unbounded target (null `LatLngBounds`) // from not specifying anything (null `CameraTargetBounds`). class CameraTargetBounds { - /// Creates a camera target bounds with the specified bounding box, or null - /// to indicate that the camera target is not bounded. - const CameraTargetBounds(this.bounds); + /// Unbounded camera target. + static const CameraTargetBounds unbounded = CameraTargetBounds(null); /// The geographical bounding box for the map camera target. /// /// A null value means the camera target is unbounded. final LatLngBounds? bounds; - /// Unbounded camera target. - static const CameraTargetBounds unbounded = CameraTargetBounds(null); + /// Creates a camera target bounds with the specified bounding box, or null + /// to indicate that the camera target is not bounded. + const CameraTargetBounds(this.bounds); + + @override + int get hashCode => bounds.hashCode; @override bool operator ==(dynamic other) { @@ -52,18 +32,28 @@ class CameraTargetBounds { return bounds == typedOther.bounds; } - @override - int get hashCode => bounds.hashCode; - @override String toString() { return 'CameraTargetBounds(bounds: $bounds)'; } } +/// Type of map tiles to display. +enum MapType { + /// Normal tiles (traffic and labels, subtle terrain information). + standard, + + /// Satellite imaging tiles (aerial photos) + satellite, + + /// Hybrid tiles (satellite images with some labels/overlays) + hybrid, +} + class MinMaxZoomPreference { - const MinMaxZoomPreference(this.minZoom, this.maxZoom) - : assert(minZoom == null || maxZoom == null || minZoom <= maxZoom); + /// Unbounded zooming. + static const MinMaxZoomPreference unbounded = + MinMaxZoomPreference(null, null); /// The preferred minimum zoom level or null, if unbounded from below. final double? minZoom; @@ -71,11 +61,11 @@ class MinMaxZoomPreference { /// The preferred maximum zoom level or null, if unbounded from above. final double? maxZoom; - /// Unbounded zooming. - static const MinMaxZoomPreference unbounded = - MinMaxZoomPreference(null, null); + const MinMaxZoomPreference(this.minZoom, this.maxZoom) + : assert(minZoom == null || maxZoom == null || minZoom <= maxZoom); - dynamic _toJson() => [minZoom, maxZoom]; + @override + int get hashCode => Object.hash(minZoom, maxZoom); @override bool operator ==(dynamic other) { @@ -85,11 +75,21 @@ class MinMaxZoomPreference { return minZoom == typedOther.minZoom && maxZoom == typedOther.maxZoom; } - @override - int get hashCode => hashValues(minZoom, maxZoom); - @override String toString() { return 'MinMaxZoomPreference(minZoom: $minZoom, maxZoom: $maxZoom)'; } + + dynamic _toJson() => [minZoom, maxZoom]; +} + +enum TrackingMode { + // the user's location is not followed + none, + + // the map follows the user's location + follow, + + // the map follows the user's location and heading + followWithHeading, } diff --git a/pubspec.yaml b/pubspec.yaml index ff7ca9e..a0a6e5b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,13 @@ name: apple_maps_flutter description: This plugin uses the Flutter platform view to display an Apple Maps widget. -version: 1.3.0 +version: 1.4.0 homepage: https://luisthein.de repository: https://github.com/LuisThein/apple_maps_flutter issue_tracker: https://github.com/LuisThein/apple_maps_flutter/issues environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" + sdk: '>=2.17.0 <4.0.0' + flutter: ">=3.7.0" dependencies: flutter: