|
|
|
|
@ -1,12 +1,19 @@
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
|
|
|
|
import 'package:async/async.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/config/config.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/core/model/pharmacies/order_model.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart';
|
|
|
|
|
import 'package:diplomaticquarterapp/locator.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_animarker/lat_lng_interpolation.dart';
|
|
|
|
|
import 'package:flutter_animarker/models/lat_lng_delta.dart';
|
|
|
|
|
import 'package:flutter_animarker/models/lat_lng_info.dart';
|
|
|
|
|
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
|
|
|
|
|
import 'package:geolocator/geolocator.dart';
|
|
|
|
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
|
|
|
import 'package:location/location.dart';
|
|
|
|
|
|
|
|
|
|
import 'package:flutter_animarker/streams/lat_lng_stream.dart';
|
|
|
|
|
|
|
|
|
|
class TrackDriver extends StatefulWidget {
|
|
|
|
|
final OrderModel order;
|
|
|
|
|
@ -17,12 +24,13 @@ class TrackDriver extends StatefulWidget {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
OrderPreviewService _orderServices = locator<OrderPreviewService>();
|
|
|
|
|
OrderModel _order;
|
|
|
|
|
|
|
|
|
|
Completer<GoogleMapController> _controller = Completer();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double CAMERA_ZOOM = 16;
|
|
|
|
|
double CAMERA_ZOOM = 14;
|
|
|
|
|
double CAMERA_TILT = 0;
|
|
|
|
|
double CAMERA_BEARING = 30;
|
|
|
|
|
LatLng SOURCE_LOCATION = null;
|
|
|
|
|
@ -39,17 +47,63 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
BitmapDescriptor destinationIcon; // for my custom marker pins
|
|
|
|
|
Location location;// wrapper around the location API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int locationUpdateFreq = 2;
|
|
|
|
|
LatLngInterpolationStream _latLngStream;
|
|
|
|
|
StreamGroup<LatLngDelta> subscriptions;
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void initState() {
|
|
|
|
|
|
|
|
|
|
_order = widget.order;
|
|
|
|
|
DEST_LOCATION = _order.shippingAddress.getLocation();
|
|
|
|
|
location = new Location();
|
|
|
|
|
polylinePoints = PolylinePoints();
|
|
|
|
|
setSourceAndDestinationIcons();
|
|
|
|
|
|
|
|
|
|
initMarkerUpdateStream();
|
|
|
|
|
startUpdatingDriverLocation();
|
|
|
|
|
|
|
|
|
|
super.initState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
super.dispose();
|
|
|
|
|
subscriptions.close();
|
|
|
|
|
_latLngStream.cancel();
|
|
|
|
|
stopUpdatingDriverLocation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initMarkerUpdateStream(){
|
|
|
|
|
_latLngStream = LatLngInterpolationStream(movementDuration: Duration(seconds: locationUpdateFreq+1));
|
|
|
|
|
subscriptions = StreamGroup<LatLngDelta>();
|
|
|
|
|
|
|
|
|
|
subscriptions.add(_latLngStream.getAnimatedPosition('sourcePin'));
|
|
|
|
|
subscriptions.stream.listen((LatLngDelta delta) {
|
|
|
|
|
//Update the marker with animation
|
|
|
|
|
setState(() {
|
|
|
|
|
//Get the marker Id for this animation
|
|
|
|
|
var markerId = MarkerId(delta.markerId);
|
|
|
|
|
Marker sourceMarker = Marker(
|
|
|
|
|
markerId: markerId,
|
|
|
|
|
// rotation: delta.rotation,
|
|
|
|
|
icon: sourceIcon,
|
|
|
|
|
position: LatLng(
|
|
|
|
|
delta.from.latitude,
|
|
|
|
|
delta.from.longitude,
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
_markers.removeWhere((m) => m.markerId.value == 'sourcePin');
|
|
|
|
|
_markers.add(sourceMarker);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
|
|
|
|
|
|
return new Scaffold(
|
|
|
|
|
body: GoogleMap(
|
|
|
|
|
myLocationEnabled: true,
|
|
|
|
|
@ -63,11 +117,11 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
showPinsOnMap();
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
floatingActionButton: FloatingActionButton.extended(
|
|
|
|
|
onPressed: _goToDriver,
|
|
|
|
|
label: Text('To the lake!'),
|
|
|
|
|
icon: Icon(Icons.directions_boat),
|
|
|
|
|
),
|
|
|
|
|
// floatingActionButton: FloatingActionButton.extended(
|
|
|
|
|
// onPressed: _goToDriver,
|
|
|
|
|
// label: Text('To the lake!'),
|
|
|
|
|
// icon: Icon(Icons.directions_boat),
|
|
|
|
|
// ),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -130,6 +184,7 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
if(SOURCE_LOCATION != null){
|
|
|
|
|
setState(() {
|
|
|
|
|
var pinPosition = SOURCE_LOCATION;
|
|
|
|
|
_markers.removeWhere((m) => m.markerId.value == 'sourcePin');
|
|
|
|
|
_markers.add(Marker(
|
|
|
|
|
markerId: MarkerId('sourcePin'),
|
|
|
|
|
position: pinPosition,
|
|
|
|
|
@ -142,6 +197,7 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
if(DEST_LOCATION != null){
|
|
|
|
|
setState(() {
|
|
|
|
|
var destPosition = DEST_LOCATION;
|
|
|
|
|
_markers.removeWhere((m) => m.markerId.value == 'destPin');
|
|
|
|
|
_markers.add(Marker(
|
|
|
|
|
markerId: MarkerId('destPin'),
|
|
|
|
|
position: destPosition,
|
|
|
|
|
@ -166,21 +222,26 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
);
|
|
|
|
|
final GoogleMapController controller = await _controller.future;
|
|
|
|
|
controller.animateCamera(CameraUpdate.newCameraPosition(cPosition));
|
|
|
|
|
|
|
|
|
|
_latLngStream.addLatLng(LatLngInfo(SOURCE_LOCATION.latitude, SOURCE_LOCATION.longitude, "sourcePin"));
|
|
|
|
|
|
|
|
|
|
// do this inside the setState() so Flutter gets notified
|
|
|
|
|
// that a widget update is due
|
|
|
|
|
setState(() {
|
|
|
|
|
// updated position
|
|
|
|
|
var pinPosition = SOURCE_LOCATION;
|
|
|
|
|
|
|
|
|
|
// the trick is to remove the marker (by id)
|
|
|
|
|
// and add it again at the updated location
|
|
|
|
|
_markers.removeWhere((m) => m.markerId.value == 'sourcePin');
|
|
|
|
|
_markers.add(Marker(
|
|
|
|
|
markerId: MarkerId('sourcePin'),
|
|
|
|
|
position: pinPosition, // updated position
|
|
|
|
|
icon: sourceIcon
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
// setState(() {
|
|
|
|
|
// // updated position
|
|
|
|
|
// var pinPosition = SOURCE_LOCATION;
|
|
|
|
|
//
|
|
|
|
|
// // the trick is to remove the marker (by id)
|
|
|
|
|
// // and add it again at the updated location
|
|
|
|
|
// _markers.removeWhere((m) => m.markerId.value == 'sourcePin');
|
|
|
|
|
// _markers.add(Marker(
|
|
|
|
|
// markerId: MarkerId('sourcePin'),
|
|
|
|
|
// position: pinPosition, // updated position
|
|
|
|
|
// icon: sourceIcon
|
|
|
|
|
// ));
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
drawRoute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void drawRoute() async {
|
|
|
|
|
@ -208,4 +269,33 @@ class _TrackDriverState extends State<TrackDriver> {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isLocationUpdating = false;
|
|
|
|
|
startUpdatingDriverLocation({int frequencyInSeconds = 2}) async{
|
|
|
|
|
isLocationUpdating = true;
|
|
|
|
|
int driverId = int.tryParse(_order.driverID);
|
|
|
|
|
|
|
|
|
|
Future.doWhile(() async{
|
|
|
|
|
await Future.delayed(Duration(seconds: frequencyInSeconds));
|
|
|
|
|
if(isLocationUpdating){
|
|
|
|
|
LatLng driverLocation = (await _orderServices.getDriverLocation(driverId));
|
|
|
|
|
if(driverLocation != null){
|
|
|
|
|
if(SOURCE_LOCATION == null || DEST_LOCATION == null){
|
|
|
|
|
SOURCE_LOCATION = driverLocation;
|
|
|
|
|
DEST_LOCATION = _order.shippingAddress.getLocation();
|
|
|
|
|
showPinsOnMap();
|
|
|
|
|
}
|
|
|
|
|
SOURCE_LOCATION = driverLocation;
|
|
|
|
|
updatePinOnMap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return isLocationUpdating;
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stopUpdatingDriverLocation(){
|
|
|
|
|
isLocationUpdating = false;
|
|
|
|
|
}
|
|
|
|
|
}
|