diff --git a/android/app/build.gradle b/android/app/build.gradle index dfa5b98..5829cfb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -57,3 +57,7 @@ android { flutter { source '../..' } + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a170f52..2a79e4e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/drop_marker.png b/assets/images/drop_marker.png new file mode 100644 index 0000000..ae03626 Binary files /dev/null and b/assets/images/drop_marker.png differ diff --git a/assets/images/pickup_marker.png b/assets/images/pickup_marker.png new file mode 100644 index 0000000..793b7b1 Binary files /dev/null and b/assets/images/pickup_marker.png differ diff --git a/lib/app_colors.dart b/lib/app_colors.dart new file mode 100644 index 0000000..a470502 --- /dev/null +++ b/lib/app_colors.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'helper.dart'; + +class AppColors { + AppColors._(); + + static const Color primaryColor = Color(0xffed1846); + static const Color secondaryColor = Color(0xff5bcb84); + static const Color tColor = Color(0xfff087ca); + static const Color rColor = Color(0xfff08c87); + static const Color statusColorPending = Color(0xfff8c942); + static const Color statusColorInProgress = Color(0xff587add); + static const Color statusColorConfirm = Color(0xff30d300); + static const Color pageBgColor = Color(0xFFF6F6F6); + static const Color grey100Color = Color(0xFFEEEEEE); + static const Color grey200Color = Color(0xFFEEEEEE); + static const Color grey300Color = Color(0xFFE0E0E0); + static const Color grey400Color = Color(0xFFBDBDBD); + static const Color grey500Color = Color(0xFF9E9E9E); + static const Color grey600Color = Color(0xFF757575); + static const Color grey700Color = Color(0xFF616161); + static const Color grey800Color = Color(0xFF424242); + static const Color grey900Color = Color(0xFF212121); + static const Color errorColor = Color(0xFFD50000); + static const Color error100Color = Color(0xffFF5252); + static const Color mainBgColor = Color(0xfff7f7f7); + static const Color logoColor = Color(0xfff1ea0c); + + static MaterialColor primaryMaterialColor = getSwatch(primaryColor); + static MaterialColor errorMaterialColor = getSwatch(errorColor); + static MaterialColor tableRowMaterialColor = getSwatch(grey500Color); +} diff --git a/lib/app_images.dart b/lib/app_images.dart new file mode 100644 index 0000000..a1d2af5 --- /dev/null +++ b/lib/app_images.dart @@ -0,0 +1,4 @@ +class AppImages { + static const String pickupMarker = "assets/images/pickup_marker.png"; + static const String dropMarker = "assets/images/drop_marker.png"; +} diff --git a/lib/app_sizes.dart b/lib/app_sizes.dart new file mode 100644 index 0000000..2fb593a --- /dev/null +++ b/lib/app_sizes.dart @@ -0,0 +1,23 @@ +import 'dart:ui'; + +import 'package:get/get.dart'; + +class AppSizes { + // get height and width from getX + static final double deviceHeight = Get.height; + static final double deviceWidth = Get.width; + + static const int height1060 = 1060; + static const int height880 = 880; + static const int height740 = 740; + static const int height490 = 490; + + static const int width1060 = 1060; + static const int width880 = 880; + static const int width740 = 740; + static const int width490 = 490; + + static const int screen720x1280 = 490; + + static final double mapPinSize = (deviceWidth * window.devicePixelRatio); +} diff --git a/lib/delivrybookingdata.dart b/lib/delivrybookingdata.dart index b95f08b..f89294d 100644 --- a/lib/delivrybookingdata.dart +++ b/lib/delivrybookingdata.dart @@ -10,6 +10,8 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:watermanagement/model/getdeliveryboy_model.dart'; import 'package:watermanagement/settings.dart'; +import 'order_tracking_page.dart'; + class DelivryBookingData extends StatefulWidget { const DelivryBookingData({Key? key}) : super(key: key); @@ -393,8 +395,18 @@ class _DelivryBookingDataState extends State with TickerProv color: primaryColor, ), onPressed: () { - /* showTankerBookingDialog( - tankersList[index]);*/ + + Navigator.push( + context, + new MaterialPageRoute( + builder: (__) => new OrderTrackingPage(lat:activeOrdersList[index].lat,lng:activeOrdersList[index].lng))); + + /* Navigator.push( + context, + MaterialPageRoute(builder: (context) => OrderTrackingPage()), + );*/ + + }, ), Text( diff --git a/lib/helper.dart b/lib/helper.dart new file mode 100644 index 0000000..635611e --- /dev/null +++ b/lib/helper.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +MaterialColor getSwatch(Color color) { + final hslColor = HSLColor.fromColor(color); + final lightness = hslColor.lightness; + + /// if [500] is the default color, there are at LEAST five + /// steps below [500]. (i.e. 400, 300, 200, 100, 50.) A + /// divisor of 5 would mean [50] is a lightness of 1.0 or + /// a color of #ffffff. A value of six would be near white + /// but not quite. + const lowDivisor = 6; + + /// if [500] is the default color, there are at LEAST four + /// steps above [500]. A divisor of 4 would mean [900] is + /// a lightness of 0.0 or color of #000000 + const highDivisor = 5; + + final lowStep = (1.0 - lightness) / lowDivisor; + final highStep = lightness / highDivisor; + + return MaterialColor(color.value, { + 50: (hslColor.withLightness(lightness + (lowStep * 5))).toColor(), + 100: (hslColor.withLightness(lightness + (lowStep * 4))).toColor(), + 200: (hslColor.withLightness(lightness + (lowStep * 3))).toColor(), + 300: (hslColor.withLightness(lightness + (lowStep * 2))).toColor(), + 400: (hslColor.withLightness(lightness + lowStep)).toColor(), + 500: (hslColor.withLightness(lightness)).toColor(), + 600: (hslColor.withLightness(lightness - highStep)).toColor(), + 700: (hslColor.withLightness(lightness - (highStep * 2))).toColor(), + 800: (hslColor.withLightness(lightness - (highStep * 3))).toColor(), + 900: (hslColor.withLightness(lightness - (highStep * 4))).toColor(), + }); +} diff --git a/lib/location_controller.dart b/lib/location_controller.dart new file mode 100644 index 0000000..1df954f --- /dev/null +++ b/lib/location_controller.dart @@ -0,0 +1,118 @@ +import 'dart:developer'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:location/location.dart'; + +import 'app_images.dart'; +import 'app_sizes.dart'; +import 'permission_alert.dart'; + +class LocationController extends GetxController { + Location location = Location(); + + // final Rx locationPosition = const LatLng(0.0, 0.0).obs; + final Rx locationPosition = + const LatLng(12.90618717, 77.5844983).obs; + + bool locationServiceActive = true; + + BitmapDescriptor? pickupMarker; + BitmapDescriptor? dropMarker; + + @override + void onInit() async { + + await _getBytesFromAsset(AppImages.pickupMarker, AppSizes.mapPinSize * 0.2); + await _getBytesFromAsset(AppImages.dropMarker, AppSizes.mapPinSize * 0.2); + + super.onInit(); + refreshToLiveLocation(); + } + + Future _getBytesFromAsset(String path, double size) async { + ByteData data = await rootBundle.load(path); + ui.Codec codec = await ui.instantiateImageCodec( + data.buffer.asUint8List(), + targetWidth: size.toInt(), + allowUpscaling: true, + ); + ui.FrameInfo fi = await codec.getNextFrame(); + if (path == AppImages.pickupMarker) { + pickupMarker = BitmapDescriptor.fromBytes( + (await fi.image.toByteData(format: ui.ImageByteFormat.png))! + .buffer + .asUint8List()); + } else if (path == AppImages.dropMarker) { + dropMarker = BitmapDescriptor.fromBytes( + (await fi.image.toByteData(format: ui.ImageByteFormat.png))! + .buffer + .asUint8List()); + } else {} + } + + refreshToLiveLocation() async { + log("initiating"); + bool serviceEnabled; + + PermissionStatus permissionGranted; + + serviceEnabled = await location.serviceEnabled(); + + if (!serviceEnabled) { + serviceEnabled = await location.requestService(); + locationPosition.value = null; + return; + } + log("permission check"); + permissionGranted = await location.hasPermission(); + + if (permissionGranted == PermissionStatus.denied) { + permissionGranted = await location.requestPermission(); + if (permissionGranted != PermissionStatus.granted) { + showPermissionAlertDialog( + requestMsg: + "Location access needed. Go to Android settings, tap App permissions and tap Allow.", + barrierDismissible: false, + ); + } else { + await location.changeSettings( + accuracy: LocationAccuracy.balanced, + interval: 5000, + distanceFilter: 2); + + location.onLocationChanged.listen((LocationData currentLocation) async { + var lat = currentLocation.latitude; + var long = currentLocation.longitude; + if (lat != null && long != null) { + locationPosition.value = LatLng( + lat, + long, + ); + log("live location ${locationPosition.value}"); + } + }); + } + } else { + await location.changeSettings( + accuracy: LocationAccuracy.balanced, + interval: 5000, + distanceFilter: 2); + + location.onLocationChanged.listen((LocationData currentLocation) async { + var lat = currentLocation.latitude; + var long = currentLocation.longitude; + if (lat != null && long != null) { + locationPosition.value = LatLng( + lat, + long, + ); + log("live location ${locationPosition.value}"); + } + }); + } + } +} diff --git a/lib/model/getdeliveryboy_model.dart b/lib/model/getdeliveryboy_model.dart index 312e813..e1ab483 100644 --- a/lib/model/getdeliveryboy_model.dart +++ b/lib/model/getdeliveryboy_model.dart @@ -23,6 +23,8 @@ class GetDeliveryboyDetailsModel { String paymentMode = ''; String deliverdWater = ''; var tankerRunningStatus ; + double lat=0; + double lng=0; @@ -59,7 +61,8 @@ class GetDeliveryboyDetailsModel { rtvm.paymentMode = json['payment_mode'] ??''; rtvm.deliverdWater = json['quantityDelivered'] ??''; rtvm.tankerRunningStatus = json['tankerRunningStatus'] ??''; - + rtvm.lat = json['latitude'] ??0; + rtvm.lng = json['longitude'] ??0; return rtvm; } diff --git a/lib/order_tracking_page.dart b/lib/order_tracking_page.dart new file mode 100644 index 0000000..1eb6f40 --- /dev/null +++ b/lib/order_tracking_page.dart @@ -0,0 +1,149 @@ +import 'dart:async'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:flutter_polyline_points/flutter_polyline_points.dart'; +import 'package:get/get.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import 'location_controller.dart'; + + +class OrderTrackingPage extends StatefulWidget { + + var lat; + var lng; + OrderTrackingPage({ + this.lat,this.lng + }); + + @override + OrderTrackingPageState createState() => OrderTrackingPageState(); +} + +class OrderTrackingPageState extends State { + final Completer mapController = Completer(); + PolylinePoints polylinePoints = PolylinePoints(); + double latitude=0; + double longitude=0; + + String googleAPiKey = "AIzaSyBOigf-qg4v_aD0Jrx2wFOMNzObxXrfDEM"; + + Set markers = {}; + Map polylines = {}; + + LatLng startLocation = const LatLng(0,0); + + + LocationController locationController = Get.put(LocationController()); + + @override + void initState() { + super.initState(); + latitude=widget.lat; + longitude=widget.lng; + LatLng endLocation = LatLng(widget.lat,widget.lng); + + ever(locationController.locationPosition, (value) { + if (value != null) { + log("${value.latitude} ${value.longitude}"); + var latitude = value.latitude; + var longitude = value.longitude; + startLocation = LatLng(latitude, longitude); + getDirections(endLocation); + } + }); + + getDirections(endLocation); //fetch direction polylines from Google API + } + + getDirections(endLocation) async { + markers.clear(); + + markers.add(Marker( + markerId: MarkerId(startLocation.toString()), + position: startLocation, + infoWindow: const InfoWindow( + title: 'Starting Point ', + snippet: 'Start Marker', + ), + icon: locationController.pickupMarker ?? BitmapDescriptor.defaultMarker, + )); + + markers.add(Marker( + markerId: MarkerId(endLocation.toString()), + position: endLocation, //position of marker + infoWindow: const InfoWindow( + title: 'Destination Point ', + snippet: 'Destination Marker', + ), + icon: locationController.dropMarker ?? BitmapDescriptor.defaultMarker, + )); + + List polylineCoordinates = []; + + PolylineResult result = await polylinePoints.getRouteBetweenCoordinates( + googleAPiKey, + PointLatLng(startLocation.latitude, startLocation.longitude), + PointLatLng(endLocation.latitude, endLocation.longitude), + travelMode: TravelMode.driving, + ); + + if (result.points.isNotEmpty) { + for (var point in result.points) { + polylineCoordinates.add(LatLng(point.latitude, point.longitude)); + } + } else { + log(result.errorMessage ?? "Something went wrong"); + } + addPolyLine(polylineCoordinates); + } + + addPolyLine(List polylineCoordinates) async { + PolylineId id = const PolylineId("poly"); + Polyline polyline = Polyline( + polylineId: id, + color: Colors.blueAccent, + points: polylineCoordinates, + width: 8, + ); + polylines[id] = polyline; + + var position = CameraPosition( + target: LatLng(startLocation.latitude, startLocation.longitude), + zoom: 21); + + final GoogleMapController controller = await mapController.future; + controller.animateCamera(CameraUpdate.newCameraPosition(position)); + + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: GoogleMap( + //Map widget from google_maps_flutter package + zoomGesturesEnabled: true, + //enable Zoom in, out on map + initialCameraPosition: CameraPosition( + //innital position in map + target: startLocation, //initial position + zoom: 5.0, //initial zoom level + ), + markers: markers, + //markers to show on map + polylines: Set.of(polylines.values), + //polylines + mapType: MapType.normal, + //map type + onMapCreated: (controller) { + //method called when map is created + if (!mapController.isCompleted) { + mapController.complete(controller); + } + }, + ), + ); + } +} diff --git a/lib/padding_type_enum.dart b/lib/padding_type_enum.dart new file mode 100644 index 0000000..dd8ab72 --- /dev/null +++ b/lib/padding_type_enum.dart @@ -0,0 +1 @@ +enum PaddingType { symmetric, only } diff --git a/lib/permission_alert.dart b/lib/permission_alert.dart new file mode 100644 index 0000000..7a1fb34 --- /dev/null +++ b/lib/permission_alert.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:get/get_core/src/get_main.dart'; +import 'package:get/get_navigation/get_navigation.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import 'app_colors.dart'; +import 'primary_button.dart'; +import 'primary_text.dart'; + +void showPermissionAlertDialog({ + String title = "Need Permission", + required String requestMsg, + bool barrierDismissible = true, +}) { + Get.defaultDialog( + title: title, + middleText: "", + backgroundColor: Colors.white, + contentPadding: const EdgeInsets.only(top: 30, bottom: 30.0), + radius: 10, + barrierDismissible: barrierDismissible, + titlePadding: const EdgeInsets.only(top: 15), + titleStyle: const TextStyle( + color: AppColors.grey900Color, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + /*cancel: PrimaryButton( + title: "DISMISS", + onPressed: () {}, + textSize: AppSizes.font_13, + bgColor: AppColors.grey500Color, + ),*/ + confirm: PrimaryButton( + title: "GO TO SETTINGS", + onPressed: () { + openAppSettings(); + Get.back(); + }, + textSize: 13, + ), + content: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: PrimaryText( + requestMsg, + textAlign: TextAlign.center, + fontColor: AppColors.grey800Color, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ); +} diff --git a/lib/primary_button.dart b/lib/primary_button.dart new file mode 100644 index 0000000..cfe2beb --- /dev/null +++ b/lib/primary_button.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; + +import 'app_colors.dart'; +import 'primary_text.dart'; + + +class PrimaryButton extends StatelessWidget { + final String title; + final VoidCallback onPressed; + final double verticalPadding; + final bool textAllCaps; + final double textSize; + final FontWeight textWeight; + final Color textColor; + final TextDecoration textDecoration; + final int letterSpacing; + final bool isResponsive; + final Color bgColor; + final double horizontalPadding; + + const PrimaryButton({ + Key? key, + required this.title, + required this.onPressed, + this.verticalPadding = 10.0, + this.textAllCaps = true, + this.textSize = 14, + this.textWeight = FontWeight.w500, + this.textColor = Colors.white, + this.textDecoration = TextDecoration.none, + this.letterSpacing = 1, + this.isResponsive = true, + this.bgColor = AppColors.primaryColor, + this.horizontalPadding = 25.0, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(40), + ), + color: bgColor, + child: InkWell( + onTap: onPressed, + child: Padding( + padding: EdgeInsets.symmetric( + vertical: verticalPadding, + horizontal: horizontalPadding, + ), + child: PrimaryText( + textAllCaps ? title.toUpperCase() : title, + // title.toUpperCase(), + textAlign: TextAlign.center, + fontSize: textSize, + fontWeight: textWeight, + fontColor: textColor, + textDecoration: textDecoration, + isResponsive: isResponsive, + ), + ), + ), + ); + } +} diff --git a/lib/primary_text.dart b/lib/primary_text.dart new file mode 100644 index 0000000..ec70048 --- /dev/null +++ b/lib/primary_text.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +import 'app_sizes.dart'; +import 'padding_type_enum.dart'; + + +class PrimaryText extends StatelessWidget { + final String text; + final Color? fontColor; + final double fontSize; + final FontWeight fontWeight; + final double horizontalPadding; + final double verticalPadding; + final TextAlign textAlign; + final bool isResponsive; + final TextDecoration? textDecoration; + final PaddingType paddingType; + final double leftPadding; + final double rightPadding; + final double lineHeight; + final FontStyle fontStyle; + final TextOverflow textOverflow; + final bool textAllCaps; + final double letterSpacing; + + const PrimaryText( + this.text, { + Key? key, + this.fontColor = Colors.black, + this.fontSize = 16, + this.fontWeight = FontWeight.w600, + this.horizontalPadding = 0.0, + this.verticalPadding = 0.0, + this.textAlign = TextAlign.start, + this.isResponsive = true, + this.textDecoration, + this.paddingType = PaddingType.symmetric, + this.leftPadding = 0.0, + this.rightPadding = 0.0, + this.lineHeight = 1.5, + this.fontStyle = FontStyle.normal, + this.textOverflow = TextOverflow.visible, + this.textAllCaps = false, + this.letterSpacing = 0, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: paddingType == PaddingType.symmetric + ? EdgeInsets.symmetric( + horizontal: horizontalPadding, + vertical: verticalPadding, + ) + : EdgeInsets.only( + left: leftPadding, + right: rightPadding, + ), + child: Text( + textAllCaps ? text.toUpperCase() : text, + style: TextStyle( + fontSize: responsiveTextSize(), + fontWeight: fontWeight, + color: fontColor, + decoration: textDecoration, + height: lineHeight, + fontStyle: fontStyle, + letterSpacing: letterSpacing, + ), + textScaleFactor: 1, + textAlign: textAlign, + ), + ); + } + + double responsiveTextSize() { + if (isResponsive) { + if (AppSizes.deviceHeight < AppSizes.height490) { + return fontSize - 3; + } else if (AppSizes.deviceHeight < AppSizes.height740) { + return fontSize - 2; + } else if (AppSizes.deviceHeight < AppSizes.height880) { + return fontSize - 1; + } + } + return fontSize; + } +} diff --git a/pubspec.lock b/pubspec.lock index d02cf85..517ba11 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -172,6 +172,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.9" + flutter_polyline_points: + dependency: "direct main" + description: + name: flutter_polyline_points + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter_styled_toast: dependency: "direct dev" description: @@ -280,6 +287,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.1" + get: + dependency: "direct main" + description: + name: get + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.5" google_api_headers: dependency: "direct main" description: @@ -518,6 +532,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.5" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.dartlang.org" + source: hosted + version: "10.2.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + url: "https://pub.dartlang.org" + source: hosted + version: "10.2.0" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.8" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "3.9.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d27e58f..148dea6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,9 @@ dependencies: cupertino_icons: ^1.0.2 location: ^4.4.0 + flutter_polyline_points: ^1.0.0 + get: ^4.6.5 + permission_handler: ^10.2.0 geolocator: ^9.0.2 google_api_headers: ^1.5.0+1 google_maps_flutter: ^2.2.3 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 94586cc..ce843bc 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,14 @@ #include "generated_plugin_registrant.h" #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f0bcafd..b3ea692 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST geolocator_windows + permission_handler_windows url_launcher_windows )