From d7ce7f375dc515eb575921020527cf3c8c482fd1 Mon Sep 17 00:00:00 2001 From: Rithik Bhandari Date: Sat, 10 Sep 2022 02:19:21 +0530 Subject: [PATCH 1/5] fix: fix bug --- lib/src/main_widget.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/src/main_widget.dart b/lib/src/main_widget.dart index 213c0f7..cfb6490 100644 --- a/lib/src/main_widget.dart +++ b/lib/src/main_widget.dart @@ -357,8 +357,7 @@ class GoogleMapsWidget extends StatefulWidget { class _GoogleMapsWidgetState extends State { final _mapsService = MapsService(); - @override - void initState() { + void _initialize() { _mapsService.initialize( setState: setState, apiKey: widget.apiKey, @@ -389,7 +388,6 @@ class _GoogleMapsWidgetState extends State { showDriverMarker: widget.showDriverMarker, showPolyline: widget.showPolyline, ); - super.initState(); } @override @@ -409,6 +407,7 @@ class _GoogleMapsWidgetState extends State { polylines: {..._mapsService.polylines, ...widget.polylines}, onMapCreated: (controller) { _mapsService.setController(controller); + _initialize(); if (widget.onMapCreated != null) { return widget.onMapCreated!(controller); } From 3a1a35860eda69480c434431cac98300be48920d Mon Sep 17 00:00:00 2001 From: Rithik Bhandari Date: Tue, 25 Oct 2022 17:58:36 +0530 Subject: [PATCH 2/5] * Changed internal implementation of the widget * Added `layoutDirection` property * `MarkerIconInfo` inputs are now non-nullable * Exposed state class to allow updating source/destination lat lng, or interacting with google maps con directly * Updated example app * Updated README.md --- CHANGELOG.md | 8 +- README.md | 24 ++ .../android/app/src/main/AndroidManifest.xml | 2 +- example/lib/main.dart | 123 ++++-- lib/src/main_widget.dart | 251 ++++++++--- lib/src/models/direction.dart | 8 +- lib/src/models/marker_icon_info.dart | 4 + lib/src/services/maps_service.dart | 388 ------------------ lib/src/utils/constants.dart | 3 +- 9 files changed, 332 insertions(+), 479 deletions(-) delete mode 100644 lib/src/services/maps_service.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 184b0d8..1bf662f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ -## [1.0.5] - 29/09/2022 +## [1.0.5] - 25/10/2022 +* Changed internal implementation of the widget +* Added `layoutDirection` property +* `MarkerIconInfo` inputs are now non-nullable +* Exposed state class to allow updating source/destination lat lng, or interacting with google maps con directly * Updated a dependency to the latest release +* Updated example app +* Updated README.md ## [1.0.4] - 15/06/2022 diff --git a/README.md b/README.md index 6eda2d2..96bf728 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,30 @@ GoogleMapsWidget( ), ``` +One can create a controller and interact with the google maps controller, or update the source and destination LatLng's. +```dart +// can create a controller, and call methods to update source loc, +// destination loc, interact with the google maps controller to +// show/hide markers programmatically etc. +final mapsWidgetController = GlobalKey(); +``` +Pass this controller to the `key` param in `GoogleMapsWidget` widget, and then +```dart + +// call like this to update source or destination, this will also rebuild the route. +mapsWidgetController.currentState!.setSourceLatLng( + LatLng( + 40.484000837597925 * (Random().nextDouble()), + -3.369978368282318, + ), +); + +// or, can interact with the google maps controller directly to focus on a marker etc.. + +final googleMapsCon = await mapsWidgetController.currentState!.getGoogleMapsController(); +googleMapsCon.showMarkerInfoWindow(MarkerIconInfo.sourceMarkerId); +``` + Sample Usage ```dart import 'package:flutter/material.dart'; diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 50dd4d4..2977496 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -6,7 +6,7 @@ + android:value="YOUR GOOGLE MAPS API KEY HERE" /> (); + @override Widget build(BuildContext context) { return MaterialApp( home: SafeArea( child: Scaffold( - body: GoogleMapsWidget( - apiKey: "YOUR KEY HERE", - sourceLatLng: LatLng(40.484000837597925, -3.369978368282318), - destinationLatLng: LatLng(40.48017307700204, -3.3618026599287987), + body: Column( + children: [ + Expanded( + child: GoogleMapsWidget( + apiKey: "YOUR GOOGLE MAPS API KEY HERE", + key: mapsWidgetController, + sourceLatLng: LatLng( + 40.484000837597925, + -3.369978368282318, + ), + destinationLatLng: LatLng( + 40.48017307700204, + -3.3618026599287987, + ), - /////////////////////////////////////////////////////// - ////////////// OPTIONAL PARAMETERS ////////////// - /////////////////////////////////////////////////////// + /////////////////////////////////////////////////////// + ////////////// OPTIONAL PARAMETERS ////////////// + /////////////////////////////////////////////////////// - routeWidth: 2, - sourceMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/house-marker-icon.png", - ), - destinationMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/restaurant-marker-icon.png", - ), - driverMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/driver-marker-icon.png", - assetMarkerSize: Size.square(125), - rotation: 90, - ), - updatePolylinesOnDriverLocUpdate: true, - // mock stream - driverCoordinatesStream: Stream.periodic( - Duration(milliseconds: 500), - (i) => LatLng( - 40.47747872288886 + i / 10000, - -3.368043154478073 - i / 10000, + routeWidth: 2, + sourceMarkerIconInfo: MarkerIconInfo( + assetPath: "assets/images/house-marker-icon.png", + ), + destinationMarkerIconInfo: MarkerIconInfo( + assetPath: "assets/images/restaurant-marker-icon.png", + ), + driverMarkerIconInfo: MarkerIconInfo( + assetPath: "assets/images/driver-marker-icon.png", + assetMarkerSize: Size.square(125), + rotation: 90, + ), + updatePolylinesOnDriverLocUpdate: true, + // mock stream + driverCoordinatesStream: Stream.periodic( + Duration(milliseconds: 500), + (i) => LatLng( + 40.47747872288886 + i / 10000, + -3.368043154478073 - i / 10000, + ), + ), + sourceName: "This is source name", + driverName: "Alex", + onTapDriverMarker: (currentLocation) { + print("Driver is currently at $currentLocation"); + }, + totalTimeCallback: (time) => print(time), + totalDistanceCallback: (distance) => print(distance), + ), + ), + // demonstrates how to interact with the controller + Padding( + padding: const EdgeInsets.all(10), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + mapsWidgetController.currentState!.setSourceLatLng( + LatLng( + 40.484000837597925 * (Random().nextDouble()), + -3.369978368282318, + ), + ); + }, + child: Text('Update source'), + ), + ), + const SizedBox(width: 10), + Expanded( + child: ElevatedButton( + onPressed: () async { + final googleMapsCon = await mapsWidgetController + .currentState! + .getGoogleMapsController(); + googleMapsCon.showMarkerInfoWindow( + MarkerIconInfo.sourceMarkerId, + ); + }, + child: Text('Show source info'), + ), + ), + ], + ), ), - ), - sourceName: "This is source name", - driverName: "Alex", - onTapDriverMarker: (currentLocation) { - print("Driver is currently at $currentLocation"); - }, - totalTimeCallback: (time) => print(time), - totalDistanceCallback: (distance) => print(distance), + ], ), ), ), diff --git a/lib/src/main_widget.dart b/lib/src/main_widget.dart index cfb6490..0bff935 100644 --- a/lib/src/main_widget.dart +++ b/lib/src/main_widget.dart @@ -4,8 +4,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:google_maps_widget/src/models/direction.dart'; import 'package:google_maps_widget/src/models/marker_icon_info.dart'; -import 'package:google_maps_widget/src/services/maps_service.dart'; import 'package:google_maps_widget/src/utils/constants.dart'; /// A [GoogleMapsWidget] which can be used to make polylines(route) @@ -20,9 +20,9 @@ class GoogleMapsWidget extends StatefulWidget { this.totalDistanceCallback, this.totalTimeCallback, this.onMapCreated, - this.sourceMarkerIconInfo, - this.destinationMarkerIconInfo, - this.driverMarkerIconInfo, + this.sourceMarkerIconInfo = const MarkerIconInfo(), + this.destinationMarkerIconInfo = const MarkerIconInfo(), + this.driverMarkerIconInfo = const MarkerIconInfo(), this.onTapSourceMarker, this.onTapDestinationMarker, this.onTapDriverMarker, @@ -47,6 +47,7 @@ class GoogleMapsWidget extends StatefulWidget { // other google maps params this.gestureRecognizers = const >{}, + this.layoutDirection, this.compassEnabled = true, this.mapToolbarEnabled = true, this.cameraTargetBounds = CameraTargetBounds.unbounded, @@ -161,17 +162,17 @@ class GoogleMapsWidget extends StatefulWidget { final int routeWidth; /// The marker which is rendered on the location [sourceLatLng]. - final MarkerIconInfo? sourceMarkerIconInfo; + final MarkerIconInfo sourceMarkerIconInfo; /// The marker which is rendered on the location [destinationLatLng]. - final MarkerIconInfo? destinationMarkerIconInfo; + final MarkerIconInfo destinationMarkerIconInfo; /// The marker which is rendered on the driver's current location /// provided by [driverCoordinatesStream]. /// /// See also: /// * [driverCoordinatesStream] parameter. - final MarkerIconInfo? driverMarkerIconInfo; + final MarkerIconInfo driverMarkerIconInfo; /// Whether to show the source marker at [sourceLatLng]. /// @@ -273,6 +274,12 @@ class GoogleMapsWidget extends StatefulWidget { /// Enables or disables showing 3D buildings where available final bool buildingsEnabled; + /// The layout direction to use for the embedded view. + /// + /// If this is null, the ambient [Directionality] is used instead. If there is + /// no ambient [Directionality], [TextDirection.ltr] is used. + final TextDirection? layoutDirection; + /// True if the map should show a compass when rotated. final bool compassEnabled; @@ -350,49 +357,195 @@ class GoogleMapsWidget extends StatefulWidget { final CameraTargetBounds cameraTargetBounds; @override - // ignore: library_private_types_in_public_api - _GoogleMapsWidgetState createState() => _GoogleMapsWidgetState(); + GoogleMapsWidgetState createState() => GoogleMapsWidgetState(); } -class _GoogleMapsWidgetState extends State { - final _mapsService = MapsService(); - - void _initialize() { - _mapsService.initialize( - setState: setState, - apiKey: widget.apiKey, - sourceLatLng: widget.sourceLatLng, - destinationLatLng: widget.destinationLatLng, - onTapSourceMarker: widget.onTapSourceMarker, - onTapDestinationMarker: widget.onTapDestinationMarker, - onTapDriverMarker: widget.onTapDriverMarker, - onTapSourceInfoWindow: widget.onTapSourceInfoWindow, - onTapDestinationInfoWindow: widget.onTapDestinationInfoWindow, - onTapDriverInfoWindow: widget.onTapDriverInfoWindow, - driverCoordinatesStream: widget.driverCoordinatesStream, - updatePolylinesOnDriverLocUpdate: widget.updatePolylinesOnDriverLocUpdate, - sourceName: widget.sourceName, - destinationName: widget.destinationName, - driverName: widget.driverName, - routeColor: widget.routeColor, - routeWidth: widget.routeWidth, - defaultCameraLocation: widget.defaultCameraLocation, - defaultCameraZoom: widget.defaultCameraZoom, - sourceMarkerIconInfo: widget.sourceMarkerIconInfo, - destinationMarkerIconInfo: widget.destinationMarkerIconInfo, - driverMarkerIconInfo: widget.driverMarkerIconInfo, - totalTimeCallback: widget.totalTimeCallback, - totalDistanceCallback: widget.totalDistanceCallback, - showSourceMarker: widget.showSourceMarker, - showDestinationMarker: widget.showDestinationMarker, - showDriverMarker: widget.showDriverMarker, - showPolyline: widget.showPolyline, +class GoogleMapsWidgetState extends State { + /// Markers to be placed on the map. + final _markersMap = {}; + + /// Polylines to be placed on the map. + final _polylines = {}; + + final _mapsControllerCompleter = Completer(); + + Future getGoogleMapsController() => + _mapsControllerCompleter.future; + + void setSourceLatLng(LatLng sourceLatLng) async { + if (_sourceLatLng == sourceLatLng) return; + + _sourceLatLng = sourceLatLng; + await _buildPolyLines(); + _setSourceDestinationMarkers(); + setState(() {}); + } + + void setDestinationLatLng(LatLng destinationLatLng) async { + if (_destinationLatLng == destinationLatLng) return; + + _destinationLatLng = destinationLatLng; + await _buildPolyLines(); + _setSourceDestinationMarkers(); + setState(() {}); + } + + StreamSubscription? _driverCoordinatesStreamSubscription; + + late LatLng _sourceLatLng; + late LatLng _destinationLatLng; + + /// setting source and destination markers + void _setSourceDestinationMarkers() async { + _markersMap.remove(MarkerIconInfo.sourceMarkerId); + + if (widget.showSourceMarker) { + _markersMap[MarkerIconInfo.sourceMarkerId] = Marker( + markerId: MarkerIconInfo.sourceMarkerId, + position: _sourceLatLng, + anchor: widget.sourceMarkerIconInfo.anchor, + rotation: widget.sourceMarkerIconInfo.rotation, + icon: await widget.sourceMarkerIconInfo.bitmapDescriptor, + onTap: widget.onTapSourceMarker == null + ? null + : () => widget.onTapSourceMarker!(_sourceLatLng), + infoWindow: InfoWindow( + onTap: widget.onTapSourceInfoWindow == null + ? null + : () => widget.onTapSourceInfoWindow!(_sourceLatLng), + title: widget.sourceName, + ), + ); + } + + _markersMap.remove(MarkerIconInfo.destinationMarkerId); + + if (widget.showDestinationMarker) { + _markersMap[MarkerIconInfo.destinationMarkerId] = Marker( + markerId: MarkerIconInfo.destinationMarkerId, + position: _destinationLatLng, + anchor: widget.destinationMarkerIconInfo.anchor, + rotation: widget.destinationMarkerIconInfo.rotation, + icon: await widget.destinationMarkerIconInfo.bitmapDescriptor, + onTap: widget.onTapDestinationMarker == null + ? null + : () => widget.onTapDestinationMarker!(_destinationLatLng), + infoWindow: InfoWindow( + onTap: widget.onTapDestinationInfoWindow == null + ? null + : () => widget.onTapDestinationInfoWindow!(_destinationLatLng), + title: widget.destinationName, + ), + ); + } + + setState(() {}); + } + + /// Build polylines from [_sourceLatLng] to [_destinationLatLng]. + Future _buildPolyLines({LatLng? driverLoc}) async { + if (!widget.showPolyline) return; + + final result = await Direction.getDirections( + googleMapsApiKey: widget.apiKey, + origin: driverLoc ?? _sourceLatLng, + destination: _destinationLatLng, ); + + final polylineCoordinates = []; + + if (result != null && result.polylinePoints.isNotEmpty) { + polylineCoordinates.addAll(result.polylinePoints); + } + + final polyline = Polyline( + polylineId: const PolylineId("poly_line"), + color: widget.routeColor, + width: widget.routeWidth, + points: polylineCoordinates, + ); + + if (driverLoc != null) _polylines.clear(); + _polylines.add(polyline); + + // setting map such as both source and + // destinations markers can be seen + if (result != null) { + final controller = await getGoogleMapsController(); + + controller.animateCamera( + CameraUpdate.newLatLngBounds(result.bounds, 32), + ); + + widget.totalTimeCallback?.call(result.totalDuration); + widget.totalDistanceCallback?.call(result.totalDistance); + } + + setState(() {}); + } + + /// This function uses [GoogleMapsWidget.driverCoordinatesStream] which + /// is a [Stream] of [LatLng]-[coordinates] and renders + /// [GoogleMapsWidget.driverMarkerIconInfo] marker to show + /// driver's location in realtime. + Future _listenToDriverCoordinates() async { + final driverStream = widget.driverCoordinatesStream; + if (driverStream == null) return; + + final driverMarker = await widget.driverMarkerIconInfo.bitmapDescriptor; + + _driverCoordinatesStreamSubscription = driverStream.listen((coordinate) { + if (widget.updatePolylinesOnDriverLocUpdate) { + _buildPolyLines(driverLoc: coordinate); + } + + if (!widget.showDriverMarker) return; + + _markersMap.remove(MarkerIconInfo.driverMarkerId); + + _markersMap[MarkerIconInfo.driverMarkerId] = Marker( + markerId: MarkerIconInfo.driverMarkerId, + position: coordinate, + anchor: widget.driverMarkerIconInfo.anchor, + rotation: widget.driverMarkerIconInfo.rotation, + icon: driverMarker, + onTap: widget.onTapDriverMarker == null + ? null + : () => widget.onTapDriverMarker!(coordinate), + infoWindow: InfoWindow( + onTap: widget.onTapDriverInfoWindow == null + ? null + : () => widget.onTapDriverInfoWindow!(coordinate), + title: widget.driverName, + ), + ); + + setState(() {}); + }); + } + + @override + void initState() { + _sourceLatLng = widget.sourceLatLng; + _destinationLatLng = widget.destinationLatLng; + + _setSourceDestinationMarkers(); + _buildPolyLines(); + _listenToDriverCoordinates(); + + super.initState(); } @override void dispose() { - _mapsService.clear(); + _driverCoordinatesStreamSubscription?.cancel(); + + if (_mapsControllerCompleter.isCompleted) { + _mapsControllerCompleter.future.then( + (controller) => controller.dispose(), + ); + } + super.dispose(); } @@ -400,14 +553,13 @@ class _GoogleMapsWidgetState extends State { Widget build(BuildContext context) { return GoogleMap( initialCameraPosition: CameraPosition( - target: _mapsService.defaultCameraLocation, - zoom: _mapsService.defaultCameraZoom, + target: widget.defaultCameraLocation ?? _sourceLatLng, + zoom: widget.defaultCameraZoom, ), - markers: {..._mapsService.markers, ...widget.markers}, - polylines: {..._mapsService.polylines, ...widget.polylines}, + markers: {..._markersMap.values, ...widget.markers}, + polylines: {..._polylines, ...widget.polylines}, onMapCreated: (controller) { - _mapsService.setController(controller); - _initialize(); + _mapsControllerCompleter.complete(controller); if (widget.onMapCreated != null) { return widget.onMapCreated!(controller); } @@ -417,6 +569,7 @@ class _GoogleMapsWidgetState extends State { ///////////////////////////////////////////////// gestureRecognizers: widget.gestureRecognizers, compassEnabled: widget.compassEnabled, + layoutDirection: widget.layoutDirection, mapToolbarEnabled: widget.mapToolbarEnabled, cameraTargetBounds: widget.cameraTargetBounds, mapType: widget.mapType, diff --git a/lib/src/models/direction.dart b/lib/src/models/direction.dart index d880d28..a617fbc 100644 --- a/lib/src/models/direction.dart +++ b/lib/src/models/direction.dart @@ -1,6 +1,5 @@ import 'package:dio/dio.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:google_maps_widget/src/services/maps_service.dart'; /// A class containing information required by [GoogleMap] to /// draw polylines on the map widget. @@ -31,18 +30,19 @@ class Direction { static const String _baseUrl = 'https://maps.googleapis.com/maps/api/directions/json?'; - /// Receives [origin] and [destination] coordinates and calls - /// the Google Maps API. + /// Receives [origin], [destination], [googleMapsApiKey] coordinates + /// and calls the Google Maps API. static Future getDirections({ + required String googleMapsApiKey, required LatLng origin, required LatLng destination, }) async { final response = await Dio().get( _baseUrl, queryParameters: { + 'key': googleMapsApiKey, 'origin': '${origin.latitude},${origin.longitude}', 'destination': '${destination.latitude},${destination.longitude}', - 'key': MapsService.apiKey, }, ); diff --git a/lib/src/models/marker_icon_info.dart b/lib/src/models/marker_icon_info.dart index 4735780..24f2115 100644 --- a/lib/src/models/marker_icon_info.dart +++ b/lib/src/models/marker_icon_info.dart @@ -20,6 +20,10 @@ class MarkerIconInfo { this.anchor = const Offset(0.5, 1.0), }); + static const sourceMarkerId = MarkerId('source'); + static const destinationMarkerId = MarkerId('destination'); + static const driverMarkerId = MarkerId('driver'); + /// Material icon that can be passed which can be used /// in place of a default [Marker]. final Icon? icon; diff --git a/lib/src/services/maps_service.dart b/lib/src/services/maps_service.dart deleted file mode 100644 index b9ec948..0000000 --- a/lib/src/services/maps_service.dart +++ /dev/null @@ -1,388 +0,0 @@ -import 'dart:async'; -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:google_maps_widget/src/main_widget.dart'; -import 'package:google_maps_widget/src/models/direction.dart'; -import 'package:google_maps_widget/src/models/marker_icon_info.dart'; -import 'package:google_maps_widget/src/utils/constants.dart'; - -/// The underline class for [GoogleMapsWidget] which -/// contains all the implementations. -class MapsService { - /// setState function - late void Function(Function() fn) _setState; - - /// source [LatLng] - late LatLng _sourceLatLng; - - /// destination [LatLng] - late LatLng _destinationLatLng; - - /// If true, Updates the polylines everytime a new event is pushed to - /// the driver stream, i.e. the driver location changes.. - /// - /// Valid only if [GoogleMapsWidget.driverCoordinatesStream] is not null. - late bool _updatePolylinesOnDriverLocUpdate; - - /// Google maps controller - GoogleMapController? _mapController; - - /// source marker info - MarkerIconInfo? _sourceMarkerIconInfo; - - /// destination marker info - MarkerIconInfo? _destinationMarkerIconInfo; - - /// driver marker info - MarkerIconInfo? _driverMarkerIconInfo; - - /// A [Stream] of [LatLng] objects for the driver - /// used to render [_driverMarkerIconInfo] on the map - /// with the provided [LatLng] objects. - /// - /// See also: - /// * [_onTapDriverInfoWindow] parameter. - /// * [_onTapDriverMarker] parameter. - /// * [_driverName] parameter. - /// - /// If null, the [_driverMarkerIconInfo] is not rendered. - StreamSubscription? _driverCoordinates; - - /// The initial location of the map's camera. - LatLng? _defaultCameraLocation; - - /// The initial zoom of the map's camera. - double? _defaultCameraZoom; - - /// Markers to be placed on the map. - final _markers = {}; - - /// Polylines to be placed on the map. - final _polylines = {}; - - /// Displays source [Marker]'s [InfoWindow] displaying [_sourceName] - /// when tapped on [_sourceMarkerIconInfo]. - String? _sourceName; - - /// Displays destination [Marker]'s [InfoWindow] displaying [_destinationName] - /// when tapped on [_destinationMarkerIconInfo]. - String? _destinationName; - - /// Displays driver's [Marker]'s [InfoWindow] displaying [_driverName] - /// when tapped on [_driverMarkerIconInfo]. - String? _driverName; - - /// Called every time source [Marker] is tapped. - void Function(LatLng)? _onTapSourceMarker; - - /// Called every time destination [Marker] is tapped. - void Function(LatLng)? _onTapDestinationMarker; - - /// Called every time driver [Marker] is tapped. - void Function(LatLng)? _onTapDriverMarker; - - /// Called every time source [Marker]'s [InfoWindow] is tapped. - void Function(LatLng)? _onTapSourceInfoWindow; - - /// Called every time destination [Marker]'s [InfoWindow] is tapped. - void Function(LatLng)? _onTapDestinationInfoWindow; - - /// Called every time driver [Marker]'s [InfoWindow] is tapped. - void Function(LatLng)? _onTapDriverInfoWindow; - - /// Called after polylines are created for the given - /// [_sourceLatLng] and [_destinationLatLng] and - /// totalDistance is initialized. - void Function(String?)? _totalDistanceCallback; - - /// Called after polylines are created for the given - /// [_sourceLatLng] and [_destinationLatLng] and - /// totalTime is initialized. - void Function(String?)? _totalTimeCallback; - - /// Color of the route made between [_sourceLatLng] and [_destinationLatLng]. - Color? _routeColor; - - /// Width of the route made between [_sourceLatLng] and [_destinationLatLng]. - int? _routeWidth; - - /// The total distance between the source and the destination. - String? totalDistance; - - /// The total time between the source and the destination. - String? totalTime; - - /// Google maps API Key - static late String _apiKey; - - /// Returns the Google Maps API Key passed to the [GoogleMapsWidget]. - static String get apiKey => _apiKey; - - /// Returns the [_defaultCameraLocation]. - /// If [_defaultCameraLocation] is null, returns [_sourceLatLng]. - LatLng get defaultCameraLocation => _defaultCameraLocation ?? _sourceLatLng; - - /// Returns the [_defaultCameraZoom]. - /// If [_defaultCameraZoom] is null, returns [Constants.kDefaultCameraZoom]. - double get defaultCameraZoom => - _defaultCameraZoom ?? Constants.kDefaultCameraZoom; - - /// Returns markers to be placed on the map. - Set get markers => _markers; - - /// Returns polylines to be placed on the map. - Set get polylines => _polylines; - - /// Sets [GoogleMapController] from [GoogleMap] callback to [_mapController]. - void setController(GoogleMapController controller) { - _mapController = controller; - } - - /// Whether to show the source marker at [_sourceLatLng]. - /// - /// Defaults to true. - late bool _showSourceMarker; - - /// Whether to show the destination marker at [_destinationLatLng]. - /// - /// Defaults to true. - late bool _showDestinationMarker; - - /// Whether to show the driver marker. - /// - /// Defaults to true. - late bool _showDriverMarker; - - /// Whether to show the generated polyline from [_sourceLatLng] - /// to [_destinationLatLng]. - /// - /// Defaults to true. - late bool _showPolyline; - - /// setting source and destination markers - void _setSourceDestinationMarkers() async { - _markers.addAll([ - if (_showSourceMarker) - Marker( - markerId: const MarkerId("source"), - position: _sourceLatLng, - anchor: _sourceMarkerIconInfo!.anchor, - rotation: _sourceMarkerIconInfo!.rotation, - icon: await _sourceMarkerIconInfo!.bitmapDescriptor, - onTap: _onTapSourceMarker == null - ? null - : () => _onTapSourceMarker!(_sourceLatLng), - infoWindow: InfoWindow( - onTap: _onTapSourceInfoWindow == null - ? null - : () => _onTapSourceInfoWindow!(_sourceLatLng), - title: _sourceName, - ), - ), - if (_showDestinationMarker) - Marker( - markerId: const MarkerId("destination"), - position: _destinationLatLng, - anchor: _destinationMarkerIconInfo!.anchor, - rotation: _destinationMarkerIconInfo!.rotation, - icon: await _destinationMarkerIconInfo!.bitmapDescriptor, - onTap: _onTapDestinationMarker == null - ? null - : () => _onTapDestinationMarker!(_destinationLatLng), - infoWindow: InfoWindow( - onTap: _onTapDestinationInfoWindow == null - ? null - : () => _onTapDestinationInfoWindow!(_destinationLatLng), - title: _destinationName, - ), - ) - ]); - - _setState(() {}); - } - - /// Build polylines from [_sourceLatLng] to [_destinationLatLng]. - Future _buildPolyLines({LatLng? driverLoc}) async { - final result = await Direction.getDirections( - origin: driverLoc ?? _sourceLatLng, - destination: _destinationLatLng, - ); - - final polylineCoordinates = []; - - if (result != null && result.polylinePoints.isNotEmpty) { - polylineCoordinates.addAll(result.polylinePoints); - } - - final polyline = Polyline( - polylineId: const PolylineId("poly_line"), - color: _routeColor ?? Constants.kRouteColor, - width: _routeWidth ?? Constants.kRouteWidth, - points: polylineCoordinates, - ); - - if (driverLoc != null) _polylines.clear(); - _polylines.add(polyline); - - // setting map such as both source and - // destinations markers can be seen - if (result != null) { - _mapController?.animateCamera( - CameraUpdate.newLatLngBounds(result.bounds, 32), - ); - - totalDistance = result.totalDistance; - totalTime = result.totalDuration; - - if (_totalDistanceCallback != null) { - _totalDistanceCallback!(totalDistance); - } - - if (_totalTimeCallback != null) _totalTimeCallback!(totalTime); - } - - _setState(() {}); - } - - /// This function takes in a [Stream] of [LatLng]-[coordinates] - /// and renders [_driverMarkerIconInfo] marker to show - /// driver's location in realtime. - Future _listenToDriverCoordinates(Stream coordinates) async { - final driverMarker = await _driverMarkerIconInfo!.bitmapDescriptor; - - _driverCoordinates = coordinates.listen((coordinate) { - if (_updatePolylinesOnDriverLocUpdate) { - _buildPolyLines(driverLoc: coordinate); - } - - if (!_showDriverMarker) return; - - _markers.removeWhere( - (element) => element.markerId == const MarkerId('driver'), - ); - - _markers.add( - Marker( - markerId: const MarkerId('driver'), - position: coordinate, - anchor: _driverMarkerIconInfo!.anchor, - rotation: _driverMarkerIconInfo!.rotation, - icon: driverMarker, - onTap: _onTapDriverMarker == null - ? null - : () => _onTapDriverMarker!(coordinate), - infoWindow: InfoWindow( - onTap: _onTapDriverInfoWindow == null - ? null - : () => _onTapDriverInfoWindow!(coordinate), - title: _driverName, - ), - ), - ); - - _setState(() {}); - }); - } - - /// Initialize all the parameters. - void initialize({ - required void Function(void Function() fn) setState, - required String apiKey, - required LatLng sourceLatLng, - required LatLng destinationLatLng, - void Function(LatLng)? onTapSourceInfoWindow, - void Function(LatLng)? onTapDestinationInfoWindow, - void Function(LatLng)? onTapDriverInfoWindow, - void Function(LatLng)? onTapSourceMarker, - void Function(LatLng)? onTapDestinationMarker, - void Function(LatLng)? onTapDriverMarker, - void Function(String?)? totalTimeCallback, - void Function(String?)? totalDistanceCallback, - Stream? driverCoordinatesStream, - bool updatePolylinesOnDriverLocUpdate = true, - LatLng? defaultCameraLocation, - double? defaultCameraZoom, - String? sourceName, - String? destinationName, - String? driverName, - Color? routeColor, - int? routeWidth, - MarkerIconInfo? sourceMarkerIconInfo, - MarkerIconInfo? destinationMarkerIconInfo, - MarkerIconInfo? driverMarkerIconInfo, - bool showSourceMarker = true, - bool showDestinationMarker = true, - bool showDriverMarker = true, - bool showPolyline = true, - }) { - _defaultCameraLocation = defaultCameraLocation; - _sourceLatLng = sourceLatLng; - _destinationLatLng = destinationLatLng; - _apiKey = apiKey; - _setState = setState; - _defaultCameraZoom = defaultCameraZoom; - _sourceName = sourceName; - _destinationName = destinationName; - _driverName = driverName; - _onTapSourceMarker = onTapSourceMarker; - _onTapDestinationMarker = onTapDestinationMarker; - _onTapDriverMarker = onTapDriverMarker; - _onTapSourceInfoWindow = onTapSourceInfoWindow; - _onTapDestinationInfoWindow = onTapDestinationInfoWindow; - _onTapDriverInfoWindow = onTapDriverInfoWindow; - _totalTimeCallback = totalTimeCallback; - _totalDistanceCallback = totalDistanceCallback; - _routeColor = routeColor; - _routeWidth = routeWidth; - _updatePolylinesOnDriverLocUpdate = updatePolylinesOnDriverLocUpdate; - _sourceMarkerIconInfo = sourceMarkerIconInfo ?? const MarkerIconInfo(); - _destinationMarkerIconInfo = - destinationMarkerIconInfo ?? const MarkerIconInfo(); - _driverMarkerIconInfo = driverMarkerIconInfo ?? const MarkerIconInfo(); - _showSourceMarker = showSourceMarker; - _showDestinationMarker = showDestinationMarker; - _showDriverMarker = showDriverMarker; - _showPolyline = showPolyline; - - _setState(() { - _setSourceDestinationMarkers(); - - if (_showPolyline) _buildPolyLines(); - - if (driverCoordinatesStream != null) { - _listenToDriverCoordinates(driverCoordinatesStream); - } - }); - } - - /// Clear all the fields. - /// Dispose off controllers. - void clear() { - // _apiKey = null; - // _sourceLatLng = null; - // _destinationLatLng = null; - _sourceMarkerIconInfo = null; - _destinationMarkerIconInfo = null; - _driverMarkerIconInfo = null; - _defaultCameraLocation = null; - _defaultCameraZoom = null; - _mapController = null; - _sourceName = null; - _destinationName = null; - _driverName = null; - _onTapSourceMarker = null; - _onTapDestinationMarker = null; - _onTapDriverMarker = null; - _routeColor = null; - _routeWidth = null; - totalDistance = null; - totalTime = null; - - _mapController?.dispose(); - _driverCoordinates?.cancel(); - _markers.clear(); - _polylines.clear(); - } -} diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index 2a36c47..6d4e411 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:google_maps_widget/google_maps_widget.dart'; -import 'package:google_maps_widget/src/services/maps_service.dart'; -/// Defines all the constants used by [GoogleMapsWidget] & [MapsService]. +/// Defines all the constants used by [GoogleMapsWidget]. class Constants { Constants._(); From 3fe849de6aa11368d9fce8535e11a84df3166996 Mon Sep 17 00:00:00 2001 From: Rithik Bhandari Date: Tue, 25 Oct 2022 18:31:52 +0530 Subject: [PATCH 3/5] feat: added properties `onTapMarker`, `onTapInfoWindow`, `infoWindowTitle` and `isVisible` to `MarkerIconInfo`, and removed corresponding params for source, destination, driver from `GoogleMapsWidget` --- CHANGELOG.md | 3 +- example/lib/main.dart | 13 +-- lib/src/main_widget.dart | 126 ++++++++------------------- lib/src/models/marker_icon_info.dart | 25 +++++- lib/src/utils/constants.dart | 3 - 5 files changed, 69 insertions(+), 101 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf662f..3a3805c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## [1.0.5] - 25/10/2022 +* BREAKING: `MarkerIconInfo` inputs are now non-nullable +* BREAKING: Added properties `onTapMarker`, `onTapInfoWindow`, `infoWindowTitle` and `isVisible` to `MarkerIconInfo`, and removed corresponding params for source, destination, driver from `GoogleMapsWidget` * Changed internal implementation of the widget * Added `layoutDirection` property -* `MarkerIconInfo` inputs are now non-nullable * Exposed state class to allow updating source/destination lat lng, or interacting with google maps con directly * Updated a dependency to the latest release * Updated example app diff --git a/example/lib/main.dart b/example/lib/main.dart index d9bec32..c211fa6 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -39,13 +39,21 @@ class MyApp extends StatelessWidget { routeWidth: 2, sourceMarkerIconInfo: MarkerIconInfo( + infoWindowTitle: "This is source name", + onTapInfoWindow: (_) { + print("Tapped on source info window"); + }, assetPath: "assets/images/house-marker-icon.png", ), destinationMarkerIconInfo: MarkerIconInfo( assetPath: "assets/images/restaurant-marker-icon.png", ), driverMarkerIconInfo: MarkerIconInfo( + infoWindowTitle: "Alex", assetPath: "assets/images/driver-marker-icon.png", + onTapMarker: (currentLocation) { + print("Driver is currently at $currentLocation"); + }, assetMarkerSize: Size.square(125), rotation: 90, ), @@ -58,11 +66,6 @@ class MyApp extends StatelessWidget { -3.368043154478073 - i / 10000, ), ), - sourceName: "This is source name", - driverName: "Alex", - onTapDriverMarker: (currentLocation) { - print("Driver is currently at $currentLocation"); - }, totalTimeCallback: (time) => print(time), totalDistanceCallback: (distance) => print(distance), ), diff --git a/lib/src/main_widget.dart b/lib/src/main_widget.dart index 0bff935..0eed7e6 100644 --- a/lib/src/main_widget.dart +++ b/lib/src/main_widget.dart @@ -23,24 +23,12 @@ class GoogleMapsWidget extends StatefulWidget { this.sourceMarkerIconInfo = const MarkerIconInfo(), this.destinationMarkerIconInfo = const MarkerIconInfo(), this.driverMarkerIconInfo = const MarkerIconInfo(), - this.onTapSourceMarker, - this.onTapDestinationMarker, - this.onTapDriverMarker, - this.onTapSourceInfoWindow, - this.onTapDestinationInfoWindow, - this.onTapDriverInfoWindow, this.driverCoordinatesStream, this.defaultCameraLocation, this.markers = const {}, this.polylines = const {}, this.showPolyline = true, - this.showSourceMarker = true, - this.showDestinationMarker = true, - this.showDriverMarker = true, this.defaultCameraZoom = Constants.kDefaultCameraZoom, - this.sourceName = Constants.kDefaultSourceName, - this.destinationName = Constants.kDefaultDestinationName, - this.driverName = Constants.kDefaultDriverName, this.routeColor = Constants.kRouteColor, this.routeWidth = Constants.kRouteWidth, this.updatePolylinesOnDriverLocUpdate = true, @@ -84,24 +72,6 @@ class GoogleMapsWidget extends StatefulWidget { /// The destination [LatLng]. final LatLng destinationLatLng; - /// Called every time source [Marker]'s [InfoWindow] is tapped. - final void Function(LatLng)? onTapSourceInfoWindow; - - /// Called every time destination [Marker]'s [InfoWindow] is tapped. - final void Function(LatLng)? onTapDestinationInfoWindow; - - /// Called every time driver [Marker]'s [InfoWindow] is tapped. - final void Function(LatLng)? onTapDriverInfoWindow; - - /// Called every time source [Marker] is tapped. - final void Function(LatLng)? onTapSourceMarker; - - /// Called every time destination [Marker] is tapped. - final void Function(LatLng)? onTapDestinationMarker; - - /// Called every time driver [Marker] is tapped. - final void Function(LatLng)? onTapDriverMarker; - /// If true, Updates the polylines everytime a new event is pushed to /// the driver stream, i.e. the driver location changes.. /// @@ -138,21 +108,6 @@ class GoogleMapsWidget extends StatefulWidget { /// Defaults to [Constants.kDefaultCameraZoom]. final double defaultCameraZoom; - /// Displays source [Marker]'s [InfoWindow] displaying [sourceName] - /// when tapped on [sourceMarkerIconInfo]. - /// Defaults to [Constants.kDefaultSourceName]. - final String sourceName; - - /// Displays destination [Marker]'s [InfoWindow] displaying [destinationName] - /// when tapped on [destinationMarkerIconInfo]. - /// Defaults to [Constants.kDefaultDestinationName]. - final String destinationName; - - /// Displays driver's [Marker]'s [InfoWindow] displaying [driverName] - /// when tapped on [driverMarkerIconInfo]. - /// Defaults to [Constants.kDefaultDriverName]. - final String driverName; - /// Color of the route made between [sourceLatLng] and [destinationLatLng]. /// Defaults to [Constants.kRouteColor]. final Color routeColor; @@ -174,21 +129,6 @@ class GoogleMapsWidget extends StatefulWidget { /// * [driverCoordinatesStream] parameter. final MarkerIconInfo driverMarkerIconInfo; - /// Whether to show the source marker at [sourceLatLng]. - /// - /// Defaults to true. - final bool showSourceMarker; - - /// Whether to show the destination marker at [destinationLatLng]. - /// - /// Defaults to true. - final bool showDestinationMarker; - - /// Whether to show the driver marker. - /// - /// Defaults to true. - final bool showDriverMarker; - /// Whether to show the generated polyline from [sourceLatLng] /// to [destinationLatLng]. /// @@ -372,7 +312,7 @@ class GoogleMapsWidgetState extends State { Future getGoogleMapsController() => _mapsControllerCompleter.future; - void setSourceLatLng(LatLng sourceLatLng) async { + Future setSourceLatLng(LatLng sourceLatLng) async { if (_sourceLatLng == sourceLatLng) return; _sourceLatLng = sourceLatLng; @@ -381,7 +321,7 @@ class GoogleMapsWidgetState extends State { setState(() {}); } - void setDestinationLatLng(LatLng destinationLatLng) async { + Future setDestinationLatLng(LatLng destinationLatLng) async { if (_destinationLatLng == destinationLatLng) return; _destinationLatLng = destinationLatLng; @@ -399,42 +339,44 @@ class GoogleMapsWidgetState extends State { void _setSourceDestinationMarkers() async { _markersMap.remove(MarkerIconInfo.sourceMarkerId); - if (widget.showSourceMarker) { + final sourceMarker = widget.sourceMarkerIconInfo; + if (sourceMarker.isVisible) { _markersMap[MarkerIconInfo.sourceMarkerId] = Marker( markerId: MarkerIconInfo.sourceMarkerId, position: _sourceLatLng, - anchor: widget.sourceMarkerIconInfo.anchor, - rotation: widget.sourceMarkerIconInfo.rotation, - icon: await widget.sourceMarkerIconInfo.bitmapDescriptor, - onTap: widget.onTapSourceMarker == null + anchor: sourceMarker.anchor, + rotation: sourceMarker.rotation, + icon: await sourceMarker.bitmapDescriptor, + onTap: sourceMarker.onTapMarker == null ? null - : () => widget.onTapSourceMarker!(_sourceLatLng), + : () => sourceMarker.onTapMarker!(_sourceLatLng), infoWindow: InfoWindow( - onTap: widget.onTapSourceInfoWindow == null + onTap: sourceMarker.onTapInfoWindow == null ? null - : () => widget.onTapSourceInfoWindow!(_sourceLatLng), - title: widget.sourceName, + : () => sourceMarker.onTapInfoWindow!(_sourceLatLng), + title: sourceMarker.infoWindowTitle, ), ); } _markersMap.remove(MarkerIconInfo.destinationMarkerId); - if (widget.showDestinationMarker) { + final destinationMarker = widget.destinationMarkerIconInfo; + if (destinationMarker.isVisible) { _markersMap[MarkerIconInfo.destinationMarkerId] = Marker( markerId: MarkerIconInfo.destinationMarkerId, position: _destinationLatLng, - anchor: widget.destinationMarkerIconInfo.anchor, - rotation: widget.destinationMarkerIconInfo.rotation, - icon: await widget.destinationMarkerIconInfo.bitmapDescriptor, - onTap: widget.onTapDestinationMarker == null + anchor: destinationMarker.anchor, + rotation: destinationMarker.rotation, + icon: await destinationMarker.bitmapDescriptor, + onTap: destinationMarker.onTapMarker == null ? null - : () => widget.onTapDestinationMarker!(_destinationLatLng), + : () => destinationMarker.onTapMarker!(_destinationLatLng), infoWindow: InfoWindow( - onTap: widget.onTapDestinationInfoWindow == null + onTap: destinationMarker.onTapInfoWindow == null ? null - : () => widget.onTapDestinationInfoWindow!(_destinationLatLng), - title: widget.destinationName, + : () => destinationMarker.onTapInfoWindow!(_destinationLatLng), + title: destinationMarker.infoWindowTitle, ), ); } @@ -459,7 +401,7 @@ class GoogleMapsWidgetState extends State { } final polyline = Polyline( - polylineId: const PolylineId("poly_line"), + polylineId: const PolylineId('default-polyline'), color: widget.routeColor, width: widget.routeWidth, points: polylineCoordinates, @@ -492,31 +434,33 @@ class GoogleMapsWidgetState extends State { final driverStream = widget.driverCoordinatesStream; if (driverStream == null) return; - final driverMarker = await widget.driverMarkerIconInfo.bitmapDescriptor; + final driverMarkerBitmapDescriptor = + await widget.driverMarkerIconInfo.bitmapDescriptor; _driverCoordinatesStreamSubscription = driverStream.listen((coordinate) { if (widget.updatePolylinesOnDriverLocUpdate) { _buildPolyLines(driverLoc: coordinate); } - if (!widget.showDriverMarker) return; + if (!widget.driverMarkerIconInfo.isVisible) return; _markersMap.remove(MarkerIconInfo.driverMarkerId); + final driverMarker = widget.driverMarkerIconInfo; _markersMap[MarkerIconInfo.driverMarkerId] = Marker( markerId: MarkerIconInfo.driverMarkerId, position: coordinate, - anchor: widget.driverMarkerIconInfo.anchor, - rotation: widget.driverMarkerIconInfo.rotation, - icon: driverMarker, - onTap: widget.onTapDriverMarker == null + anchor: driverMarker.anchor, + rotation: driverMarker.rotation, + icon: driverMarkerBitmapDescriptor, + onTap: driverMarker.onTapMarker == null ? null - : () => widget.onTapDriverMarker!(coordinate), + : () => driverMarker.onTapMarker!(coordinate), infoWindow: InfoWindow( - onTap: widget.onTapDriverInfoWindow == null + onTap: driverMarker.onTapInfoWindow == null ? null - : () => widget.onTapDriverInfoWindow!(coordinate), - title: widget.driverName, + : () => driverMarker.onTapInfoWindow!(coordinate), + title: driverMarker.infoWindowTitle, ), ); diff --git a/lib/src/models/marker_icon_info.dart b/lib/src/models/marker_icon_info.dart index 24f2115..04f87f5 100644 --- a/lib/src/models/marker_icon_info.dart +++ b/lib/src/models/marker_icon_info.dart @@ -6,7 +6,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_widget/src/utils/constants.dart'; /// Class used to provide information about the marker on the [GoogleMap] widget. -/// Pass either an asset image [assetPath] or a material [icon]. +/// Pass either an asset image [assetPath] or a material [icon] to change the appearance of the icon. /// [assetMarkerSize] can be provided to resize image at [assetPath]. /// /// See also: @@ -16,6 +16,10 @@ class MarkerIconInfo { this.icon, this.assetPath, this.assetMarkerSize, + this.onTapMarker, + this.onTapInfoWindow, + this.infoWindowTitle, + this.isVisible = true, this.rotation = 0.0, this.anchor = const Offset(0.5, 1.0), }); @@ -47,6 +51,25 @@ class MarkerIconInfo { /// Rotation of the marker image in degrees clockwise from the [anchor] point. final double rotation; + /// Displays [Marker]'s [InfoWindow] displaying [infoWindowTitle] + /// when tapped on [MarkerIconInfo]. + /// + /// The info window is not rendered if [infoWindowTitle] is null. + /// + /// Defaults to null. + final String? infoWindowTitle; + + /// Whether to show the marker or the map or not. + /// + /// Defaults to true. + final bool isVisible; + + /// Called every time the [Marker] is tapped. + final void Function(LatLng)? onTapMarker; + + /// Called every time the [InfoWindow] is tapped. + final void Function(LatLng)? onTapInfoWindow; + /// This getter is used to get the [BitmapDescriptor] required /// by the [Marker]. /// diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index 6d4e411..8ea6e6f 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -6,9 +6,6 @@ class Constants { Constants._(); static const kDefaultCameraZoom = 15.0; - static const kDefaultSourceName = "Source"; - static const kDefaultDestinationName = "Destination"; - static const kDefaultDriverName = "Driver"; static const kRouteWidth = 5; static const kRouteColor = Colors.indigo; static const kDefaultMarkerSize = Size.square(150); From 864efa080409a57b1cf32d8dcf6d3acca4a751cd Mon Sep 17 00:00:00 2001 From: Rithik Bhandari Date: Tue, 25 Oct 2022 18:32:22 +0530 Subject: [PATCH 4/5] feat: updated README.md --- README.md | 135 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 96bf728..08547e4 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,8 @@ googleMapsCon.showMarkerInfoWindow(MarkerIconInfo.sourceMarkerId); Sample Usage ```dart +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:google_maps_widget/google_maps_widget.dart'; @@ -159,59 +161,110 @@ void main() { } class MyApp extends StatelessWidget { + // can create a controller, and call methods to update source loc, + // destination loc, interact with the google maps controller to + // show/hide markers programmatically etc. + final mapsWidgetController = GlobalKey(); + @override Widget build(BuildContext context) { return MaterialApp( home: SafeArea( child: Scaffold( - body: GoogleMapsWidget( - apiKey: "YOUR KEY HERE", - sourceLatLng: LatLng(40.484000837597925, -3.369978368282318), - destinationLatLng: LatLng(40.48017307700204, -3.3618026599287987), - - /////////////////////////////////////////////////////// - ////////////// OPTIONAL PARAMETERS ////////////// - /////////////////////////////////////////////////////// - - routeWidth: 2, - sourceMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/house-marker-icon.png", - ), - destinationMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/restaurant-marker-icon.png", - ), - driverMarkerIconInfo: MarkerIconInfo( - assetPath: "assets/images/driver-marker-icon.png", - assetMarkerSize: Size.square(125), - rotation: 15.0, - - // ... and more - ), - // mock stream - driverCoordinatesStream: Stream.periodic( - Duration(milliseconds: 500), - (i) => LatLng( - 40.47747872288886 + i / 10000, - -3.368043154478073 - i / 10000, + body: Column( + children: [ + Expanded( + child: GoogleMapsWidget( + apiKey: "YOUR GOOGLE MAPS API KEY HERE", + key: mapsWidgetController, + sourceLatLng: LatLng( + 40.484000837597925, + -3.369978368282318, + ), + destinationLatLng: LatLng( + 40.48017307700204, + -3.3618026599287987, + ), + + /////////////////////////////////////////////////////// + ////////////// OPTIONAL PARAMETERS ////////////// + /////////////////////////////////////////////////////// + + routeWidth: 2, + sourceMarkerIconInfo: MarkerIconInfo( + infoWindowTitle: "This is source name", + onTapInfoWindow: (_) { + print("Tapped on source info window"); + }, + assetPath: "assets/images/house-marker-icon.png", + ), + destinationMarkerIconInfo: MarkerIconInfo( + assetPath: "assets/images/restaurant-marker-icon.png", + ), + driverMarkerIconInfo: MarkerIconInfo( + infoWindowTitle: "Alex", + assetPath: "assets/images/driver-marker-icon.png", + onTapMarker: (currentLocation) { + print("Driver is currently at $currentLocation"); + }, + assetMarkerSize: Size.square(125), + rotation: 90, + ), + updatePolylinesOnDriverLocUpdate: true, + // mock stream + driverCoordinatesStream: Stream.periodic( + Duration(milliseconds: 500), + (i) => LatLng( + 40.47747872288886 + i / 10000, + -3.368043154478073 - i / 10000, + ), + ), + totalTimeCallback: (time) => print(time), + totalDistanceCallback: (distance) => print(distance), + ), ), - ), - updatePolylinesOnDriverLocUpdate: true, - sourceName: "This is source name", - driverName: "Alex", - onTapDriverMarker: (currentLocation) { - print("Driver is currently at $currentLocation"); - }, - totalTimeCallback: (time) => print(time), - totalDistanceCallback: (distance) => print(distance), - - /// and a lot more... + // demonstrates how to interact with the controller + Padding( + padding: const EdgeInsets.all(10), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + mapsWidgetController.currentState!.setSourceLatLng( + LatLng( + 40.484000837597925 * (Random().nextDouble()), + -3.369978368282318, + ), + ); + }, + child: Text('Update source'), + ), + ), + const SizedBox(width: 10), + Expanded( + child: ElevatedButton( + onPressed: () async { + final googleMapsCon = await mapsWidgetController + .currentState! + .getGoogleMapsController(); + googleMapsCon.showMarkerInfoWindow( + MarkerIconInfo.sourceMarkerId, + ); + }, + child: Text('Show source info'), + ), + ), + ], + ), + ), + ], ), ), ), ); } } - ``` See the [`example`](https://github.com/rithik-dev/google_maps_widget/blob/master/example) directory for a complete sample app. From 0752a586826ad86c277f7d44c3afbdb2253dc3ca Mon Sep 17 00:00:00 2001 From: Rithik Bhandari Date: Tue, 25 Oct 2022 18:45:43 +0530 Subject: [PATCH 5/5] feat: added `onPolylineUpdate` callback --- CHANGELOG.md | 1 + README.md | 3 +++ example/lib/main.dart | 3 +++ lib/src/main_widget.dart | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3805c..6a0af36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * BREAKING: Added properties `onTapMarker`, `onTapInfoWindow`, `infoWindowTitle` and `isVisible` to `MarkerIconInfo`, and removed corresponding params for source, destination, driver from `GoogleMapsWidget` * Changed internal implementation of the widget * Added `layoutDirection` property +* Added `onPolylineUpdate` callback * Exposed state class to allow updating source/destination lat lng, or interacting with google maps con directly * Updated a dependency to the latest release * Updated example app diff --git a/README.md b/README.md index 08547e4..584a36d 100644 --- a/README.md +++ b/README.md @@ -211,6 +211,9 @@ class MyApp extends StatelessWidget { rotation: 90, ), updatePolylinesOnDriverLocUpdate: true, + onPolylineUpdate: (_) { + print("Polyline updated"); + }, // mock stream driverCoordinatesStream: Stream.periodic( Duration(milliseconds: 500), diff --git a/example/lib/main.dart b/example/lib/main.dart index c211fa6..2864d68 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -57,6 +57,9 @@ class MyApp extends StatelessWidget { assetMarkerSize: Size.square(125), rotation: 90, ), + onPolylineUpdate: (p) { + print("Polyline updated: ${p.points}"); + }, updatePolylinesOnDriverLocUpdate: true, // mock stream driverCoordinatesStream: Stream.periodic( diff --git a/lib/src/main_widget.dart b/lib/src/main_widget.dart index 0eed7e6..7b369d8 100644 --- a/lib/src/main_widget.dart +++ b/lib/src/main_widget.dart @@ -25,6 +25,7 @@ class GoogleMapsWidget extends StatefulWidget { this.driverMarkerIconInfo = const MarkerIconInfo(), this.driverCoordinatesStream, this.defaultCameraLocation, + this.onPolylineUpdate, this.markers = const {}, this.polylines = const {}, this.showPolyline = true, @@ -116,6 +117,9 @@ class GoogleMapsWidget extends StatefulWidget { /// Defaults to [Constants.kRouteWidth]. final int routeWidth; + /// Called when the polyline is updated i.e. route is updated. + final void Function(Polyline)? onPolylineUpdate; + /// The marker which is rendered on the location [sourceLatLng]. final MarkerIconInfo sourceMarkerIconInfo; @@ -407,6 +411,8 @@ class GoogleMapsWidgetState extends State { points: polylineCoordinates, ); + widget.onPolylineUpdate?.call(polyline); + if (driverLoc != null) _polylines.clear(); _polylines.add(polyline);