import ' dart:async ' ;
import ' dart:typed_data ' ;
import ' dart:ui ' as ui ;
import ' package:async/async.dart ' ;
import ' package:diplomaticquarterapp/config/config.dart ' ;
import ' package:diplomaticquarterapp/core/model/pharmacies/order_detail.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:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart ' ;
import ' package:diplomaticquarterapp/uitl/translations_delegate_base.dart ' ;
import ' package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:flutter/services.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 OrderDetailModel order ;
TrackDriver ( { this . order } ) ;
@ override
State < TrackDriver > createState ( ) = > _TrackDriverState ( ) ;
}
class _TrackDriverState extends State < TrackDriver > {
OrderPreviewService _orderServices = locator < OrderPreviewService > ( ) ;
OrderDetailModel _order ;
Completer < GoogleMapController > _controller = Completer ( ) ;
double CAMERA_ZOOM = 14 ;
double CAMERA_TILT = 0 ;
double CAMERA_BEARING = 30 ;
LatLng SOURCE_LOCATION = null ;
LatLng DEST_LOCATION = null ;
// for my drawn routes on the map
Set < Polyline > _polylines = Set < Polyline > ( ) ;
List < LatLng > polylineCoordinates = [ ] ;
PolylinePoints polylinePoints ;
Set < Marker > _markers = Set < Marker > ( ) ;
BitmapDescriptor sourceIcon ; // for my custom marker pins
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 ( ) {
super . initState ( ) ;
_order = widget . order ;
DEST_LOCATION = _order . shippingAddress . getLocation ( ) ;
location = new Location ( ) ;
polylinePoints = PolylinePoints ( ) ;
setSourceAndDestinationIcons ( ) ;
initMarkerUpdateStream ( ) ;
startUpdatingDriverLocation ( ) ;
}
@ 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 ,
) ,
onTap: onSourceMarkerTap
) ;
_markers . removeWhere ( ( m ) = > m . markerId . value = = ' sourcePin ' ) ;
_markers . add ( sourceMarker ) ;
} ) ;
} ) ;
}
@ override
Widget build ( BuildContext context ) {
return AppScaffold (
appBarTitle: TranslationBase . of ( context ) . deliveryDriverTrack ,
isShowAppBar: true ,
isPharmacy: true ,
showPharmacyCart: false ,
showHomeAppBarIcon: false ,
body: GoogleMap (
myLocationEnabled: true ,
compassEnabled: true ,
markers: _markers ,
polylines: _polylines ,
mapType: MapType . normal ,
initialCameraPosition: CameraPosition ( target: DEST_LOCATION , zoom: 4 ) ,
onMapCreated: ( GoogleMapController controller ) {
_controller . complete ( controller ) ;
// showPinsOnMap();
} ,
) ,
// floatingActionButton: FloatingActionButton.extended(
// onPressed: _goToDriver,
// label: Text('To the lake!'),
// icon: Icon(Icons.directions_boat),
// ),
) ;
}
void setSourceAndDestinationIcons ( ) async {
final Uint8List srcMarkerBytes = await getBytesFromAsset ( ' assets/images/map_markers/source_map_marker.png ' , getMarkerIconSize ( ) ) ;
final Uint8List destMarkerBytes = await getBytesFromAsset ( ' assets/images/map_markers/destination_map_marker.png ' , getMarkerIconSize ( ) ) ;
sourceIcon = await BitmapDescriptor . fromBytes ( srcMarkerBytes ) ;
destinationIcon = await BitmapDescriptor . fromBytes ( destMarkerBytes ) ;
}
CameraPosition _orderDeliveryLocationCamera ( ) {
if ( DEST_LOCATION ! = null ) {
final CameraPosition orderDeliveryLocCamera = CameraPosition (
bearing: CAMERA_BEARING ,
target: DEST_LOCATION ,
tilt: CAMERA_TILT ,
zoom: CAMERA_ZOOM ) ;
return orderDeliveryLocCamera ;
}
return null ;
}
CameraPosition _driverLocationCamera ( ) {
if ( DEST_LOCATION ! = null ) {
final CameraPosition driverLocCamera = CameraPosition (
bearing: CAMERA_BEARING ,
target: SOURCE_LOCATION ,
tilt: CAMERA_TILT ,
zoom: CAMERA_ZOOM ) ;
return driverLocCamera ;
}
return null ;
}
Future < void > _goToOrderDeliveryLocation ( ) async {
final GoogleMapController controller = await _controller . future ;
final CameraPosition orderDeliveryLocCamera = _orderDeliveryLocationCamera ( ) ;
controller . animateCamera ( CameraUpdate . newCameraPosition ( orderDeliveryLocCamera ) ) ;
}
Future < void > _goToDriver ( ) async {
final GoogleMapController controller = await _controller . future ;
final CameraPosition driverLocCamera = _driverLocationCamera ( ) ;
controller . animateCamera ( CameraUpdate . newCameraPosition ( driverLocCamera ) ) ;
}
void showPinsOnMap ( ) {
// source pin
if ( SOURCE_LOCATION ! = null ) {
setState ( ( ) {
var pinPosition = SOURCE_LOCATION ;
_markers . removeWhere ( ( m ) = > m . markerId . value = = ' sourcePin ' ) ;
_markers . add ( Marker (
markerId: MarkerId ( ' sourcePin ' ) ,
position: pinPosition ,
icon: sourceIcon ,
infoWindow: InfoWindow ( title: TranslationBase . of ( context ) . driver ) ,
onTap: onSourceMarkerTap
) ) ;
} ) ;
}
// destination pin
if ( DEST_LOCATION ! = null ) {
setState ( ( ) {
var destPosition = DEST_LOCATION ;
_markers . removeWhere ( ( m ) = > m . markerId . value = = ' destPin ' ) ;
_markers . add ( Marker (
markerId: MarkerId ( ' destPin ' ) ,
position: destPosition ,
icon: destinationIcon ,
infoWindow: InfoWindow ( title: TranslationBase . of ( context ) . deliveryLocation ) ,
onTap: onDestinationMarkerTap
) ) ;
} ) ;
}
// set the route lines on the map from source to destination
// for more info follow this tutorial
// drawRoute();
}
void updatePinOnMap ( ) async {
_latLngStream . addLatLng ( LatLngInfo ( SOURCE_LOCATION . latitude , SOURCE_LOCATION . longitude , " sourcePin " ) ) ;
drawRoute ( ) ;
}
void drawRoute ( ) async {
return ; // Ignore draw Route
List < PointLatLng > result = await polylinePoints . getRouteBetweenCoordinates (
GOOGLE_API_KEY ,
SOURCE_LOCATION . latitude ,
SOURCE_LOCATION . longitude ,
DEST_LOCATION . latitude ,
DEST_LOCATION . longitude ) ;
if ( result . isNotEmpty ) {
result . forEach ( ( PointLatLng point ) {
polylineCoordinates . add (
LatLng ( point . latitude , point . longitude )
) ;
} ) ;
setState ( ( ) {
_polylines . add ( Polyline (
width: 5 , // set the width of the polylines
polylineId: PolylineId ( ' poly ' ) ,
color: Color . fromARGB ( 255 , 40 , 122 , 198 ) ,
points: polylineCoordinates
) ) ;
} ) ;
}
}
bool isLocationUpdating = false ;
startUpdatingDriverLocation ( { int frequencyInSeconds = 2 } ) async {
isLocationUpdating = true ;
int driverId = int . tryParse ( _order . driverID ) ;
Future . doWhile ( ( ) async {
if ( isLocationUpdating ) {
await Future . delayed ( Duration ( seconds: frequencyInSeconds ) ) ;
showLoading ( ) ;
LatLng driverLocation = ( await _orderServices . getDriverLocation ( driverId ) ) ;
hideLoading ( ) ;
if ( driverLocation ! = null ) {
if ( SOURCE_LOCATION = = null | | DEST_LOCATION = = null ) {
SOURCE_LOCATION = driverLocation ;
DEST_LOCATION = _order . shippingAddress . getLocation ( ) ;
showPinsOnMap ( ) ;
}
SOURCE_LOCATION = driverLocation ;
updatePinOnMap ( ) ;
updateMapCamera ( ) ;
} else {
GifLoaderDialogUtils . hideDialog ( context ) ;
}
}
return isLocationUpdating ;
} ) ;
}
showLoading ( ) {
if ( SOURCE_LOCATION = = null ) {
GifLoaderDialogUtils . showMyDialog ( context ) ;
}
}
hideLoading ( ) {
if ( SOURCE_LOCATION = = null ) {
GifLoaderDialogUtils . hideDialog ( context ) ;
}
}
stopUpdatingDriverLocation ( ) {
isLocationUpdating = false ;
}
Future < Uint8List > 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 ( ) ;
return ( await fi . image . toByteData ( format: ui . ImageByteFormat . png ) ) . buffer . asUint8List ( ) ;
}
int getMarkerIconSize ( ) {
return 140 ;
}
updateMapCamera ( ) async {
if ( SOURCE_LOCATION ! = null & & DEST_LOCATION ! = null ) {
// 'package:google_maps_flutter_platform_interface/src/types/location.dart': Failed assertion: line 72 pos 16: 'southwest.latitude <= northeast.latitude': is not true.
LatLngBounds bound ;
if ( SOURCE_LOCATION . latitude < = DEST_LOCATION . latitude ) {
bound = LatLngBounds ( southwest: SOURCE_LOCATION , northeast: DEST_LOCATION ) ;
} else {
bound = LatLngBounds ( southwest: DEST_LOCATION , northeast: SOURCE_LOCATION ) ;
}
if ( bound = = null )
return ;
CameraUpdate camera = CameraUpdate . newLatLngBounds ( bound , 50 ) ;
final GoogleMapController controller = await _controller . future ;
controller . animateCamera ( camera ) ;
}
}
bool showSrcMarkerTitle = false ;
onSourceMarkerTap ( ) async {
// showSrcMarkerTitle = !showSrcMarkerTitle;
}
bool showDestMarkerTitle = false ;
onDestinationMarkerTap ( ) async {
// showDestMarkerTitle = !showDestMarkerTitle;
// Marker m = _markers.firstWhere((m) => m.markerId.value == 'destPin');
// if(showDestMarkerTitle){
// }
}
}