diff --git a/android/app/build.gradle b/android/app/build.gradle index 204fc49..a8fc6a7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -43,6 +43,8 @@ android { targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + + multiDexEnabled true } buildTypes { diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/assets/fonts/icomoon.ttf b/assets/fonts/icomoon.ttf new file mode 100644 index 0000000..831c363 Binary files /dev/null and b/assets/fonts/icomoon.ttf differ diff --git a/assets/images/car-accident-icon.png b/assets/images/car-accident-icon.png new file mode 100644 index 0000000..d837377 Binary files /dev/null and b/assets/images/car-accident-icon.png differ diff --git a/assets/images/car-have-fault.png b/assets/images/car-have-fault.png new file mode 100644 index 0000000..b6f6c0d Binary files /dev/null and b/assets/images/car-have-fault.png differ diff --git a/assets/images/check.png b/assets/images/check.png new file mode 100644 index 0000000..88a96a1 Binary files /dev/null and b/assets/images/check.png differ diff --git a/assets/images/delivered_logo.png b/assets/images/delivered_logo.png new file mode 100644 index 0000000..bca1193 Binary files /dev/null and b/assets/images/delivered_logo.png differ diff --git a/lib/config/config.dart b/lib/config/config.dart index 3e3a45b..7bb0cca 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -3,22 +3,26 @@ import 'package:flutter/material.dart'; /// End points const isUAT = true; -const BASE_URL = 'https://${isUAT ? "uat." : ""}hmgwebservices.com/Services'; +const BASE_URL = 'https://${isUAT ? "uat." : ""}hmgwebservices.com/'; + const PING_SERVICE = '/Services/Weather.svc/REST/CheckConnectivity'; -const GET_PROJECT = '/Lists.svc/REST/GetProject'; -const LOGIN = "/Authentication.svc/REST/CheckDriverAuthentication"; -const GET_OPT = "/Patients.svc/REST/PatientER_Delivery_SendSMSForForgetPassword"; -const CHECK_ACTIVATION_CODE = "/Patients.svc/REST/PatientER_Delivery_CheckActivationCodeForForgetPassword"; -const CHANGE_FORGOT_PASSWORD = "/Patients.svc/REST/PatientER_Delivery_ChangeForgetedPasswordForDriver"; +const GET_PROJECT = '/Services/Lists.svc/REST/GetProject'; +const LOGIN = "/Services/Authentication.svc/REST/CheckDriverAuthentication"; +const GET_OPT = "/Services/Patients.svc/REST/PatientER_Delivery_SendSMSForForgetPassword"; +const CHECK_ACTIVATION_CODE = "/Services/Patients.svc/REST/PatientER_Delivery_CheckActivationCodeForForgetPassword"; +const CHANGE_FORGOT_PASSWORD = "/Services/Patients.svc/REST/PatientER_Delivery_ChangeForgetedPasswordForDriver"; + +const GET_ALL_ORDERS = '/Services/Patients.svc/REST/PatientER_Delivery_GetAllOrder'; +const SCAN_QR = '/Services/Patients.svc/REST/PatientER_Delivery_OrderInsert'; +const UPDATE_ORDER_STATUS = '/Services/Patients.svc/REST/PatientER_Delivery_UpdateOrderStatus'; +const NEXT_ORDER = "/Services/Patients.svc/REST/PatientER_Delivery_NextOrder"; +const UPDATE_DRIVER_LOCATION = "/Services/Patients.svc/REST/PatientER_DriverLocation_Insert"; +const INITIATE_DELIVERY = "/epharmacy/api/sendsmstocustomerfordriver"; +const VERIFY_DELIVERY = "/Services/Patients.svc/REST/PatientER_ValidateSentOutForDeliveryOTPCode"; -const GET_ALL_ORDERS = '/Patients.svc/REST/PatientER_Delivery_GetAllOrder'; -const SCAN_QR = '/Patients.svc/REST/PatientER_Delivery_OrderInsert'; -const UPDATE_ORDER_STATUS = '/Patients.svc/REST/PatientER_Delivery_UpdateOrderStatus'; -const NEXT_ORDER = "/Patients.svc/REST/PatientER_Delivery_NextOrder"; -const UPDATE_DRIVER_LOCATION = "/Patients.svc/REST/PatientER_DriverLocation_Insert"; +const GET_ALL_DELIVERD_ORDER = '/Services/Patients.svc/REST/PatientER_Delivery_GetAllDeliverdOrder'; +const GET_ALL_ORDERS_STATUS = '/Services/Patients.svc/REST/PatientER_Delivery_GetAllOrderstatus'; -const GET_ALL_DELIVERD_ORDER = '/Patients.svc/REST/PatientER_Delivery_GetAllDeliverdOrder'; -const GET_ALL_ORDERS_STATUS = '/Patients.svc/REST/PatientER_Delivery_GetAllOrderstatus'; /// Body Constant const CHANNEL = 9; @@ -38,3 +42,11 @@ const LINEAR_GRADIENT = LinearGradient( ], // stops: [0.0, 1.0], ); + +abstract class DeliveryStatus{ + static final int pending = 1; + static final int delivered = 2; + static final int rejected = 3; + static final int cancel = 4; +} + diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 0303269..75bc0c0 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -82,8 +82,45 @@ const Map> localizedValues = { 'en': 'Please Enter your OPT code sent to your phone', 'ar': 'الرجاء إدخال رمز OPT الخاص بك المرسل إلى هاتفك' }, + 'enterCustomerVerificationCodeMsg': { + 'en': 'Please enter OTP sent to customer phone', + 'ar': 'Please enter OTP sent to customer phone' + }, 'startDelivery': { 'en': 'Start Delivery', 'ar': 'Start Delivery' }, + 'deliveryOption': { + 'en': 'Delivery Option', + 'ar': 'Delivery Option' + }, + 'selectReason': { + 'en': 'Select Reason', + 'ar': 'Select Reason' + }, + + 'accident': { + 'en': 'Got accident', + 'ar': 'Got accident' + }, + + 'notReachableOnPhoneCall': { + 'en': 'Not reachable on phone call', + 'ar': 'Not reachable on phone call' + }, + + 'notAvailableAtlocation': { + 'en': 'Not available at location', + 'ar': 'Not available at location' + }, + + 'deliverLater': { + 'en': 'Deliver later', + 'ar': 'Deliver later' + }, + + 'other': { + 'en': 'Other...', + 'ar': 'Other...' + }, }; diff --git a/lib/config/shared_pref_kay.dart b/lib/config/shared_pref_kay.dart index b1bfbc9..857ce5b 100644 --- a/lib/config/shared_pref_kay.dart +++ b/lib/config/shared_pref_kay.dart @@ -1,5 +1,6 @@ const TOKEN = 'token'; const APP_LANGUAGE = 'language'; const USER_PROFILE = 'user-profile'; +const ACTIVE_DELIVERIES = 'active-order-deliveries'; diff --git a/lib/core/model/StatusModel.dart b/lib/core/model/StatusModel.dart new file mode 100644 index 0000000..7337954 --- /dev/null +++ b/lib/core/model/StatusModel.dart @@ -0,0 +1,11 @@ +class ResponseModel{ + bool isSuccessful = false; + String message; + T data; + + isSuccessfull(Function(bool) callback){ + callback(isSuccessful); + } + + ResponseModel({this.message, this.isSuccessful, this.data}); +} \ No newline at end of file diff --git a/lib/core/model/initiate_order_delivey/request_initiate_order_delivery.dart b/lib/core/model/initiate_order_delivey/request_initiate_order_delivery.dart deleted file mode 100644 index fcddad1..0000000 --- a/lib/core/model/initiate_order_delivey/request_initiate_order_delivery.dart +++ /dev/null @@ -1,10 +0,0 @@ -class RequestInitiateOrderDelivery{ - int orderID = 0; - RequestInitiateOrderDelivery({this.orderID}); - - Map toJson() { - final Map data = new Map(); - data['OrderID'] = this.orderID; - return data; - } -} \ No newline at end of file diff --git a/lib/core/model/order_delivey/request_initiate_order_delivery.dart b/lib/core/model/order_delivey/request_initiate_order_delivery.dart new file mode 100644 index 0000000..b15407a --- /dev/null +++ b/lib/core/model/order_delivey/request_initiate_order_delivery.dart @@ -0,0 +1,12 @@ +class RequestInitiateOrderDelivery{ + int orderNo = 0; + String mobileNumber = ""; + RequestInitiateOrderDelivery({this.orderNo, this.mobileNumber}); + + Map toJson() { + final Map data = new Map(); + data['OrderNo'] = this.orderNo; + data['MobileNumber'] = this.mobileNumber; + return data; + } +} \ No newline at end of file diff --git a/lib/core/model/order_delivey/request_validate_delivery.dart b/lib/core/model/order_delivey/request_validate_delivery.dart new file mode 100644 index 0000000..6c2827b --- /dev/null +++ b/lib/core/model/order_delivey/request_validate_delivery.dart @@ -0,0 +1,12 @@ +class RequestValidateDelivery{ + String pinCode; + int orderNo; + RequestValidateDelivery({this.orderNo,this.pinCode}); + + Map toJson() { + final Map data = new Map(); + data['Password'] = this.pinCode; + data['OrderNo'] = this.orderNo; + return data; + } +} \ No newline at end of file diff --git a/lib/core/model/initiate_order_delivey/response_initiate_order_delivery.dart b/lib/core/model/order_delivey/response_initiate_order_delivery.dart similarity index 100% rename from lib/core/model/initiate_order_delivey/response_initiate_order_delivery.dart rename to lib/core/model/order_delivey/response_initiate_order_delivery.dart diff --git a/lib/core/model/orders/pending_orders_res_model.dart b/lib/core/model/orders/pending_orders_res_model.dart index 5df7082..ccf6870 100644 --- a/lib/core/model/orders/pending_orders_res_model.dart +++ b/lib/core/model/orders/pending_orders_res_model.dart @@ -27,6 +27,11 @@ class PendingOrdersRes { dynamic distanceInKilometers; List itemsQuantitiesList; + String receiverFullName(){ + var fullName = "${firstName ?? ''} ${middleName ?? ''} ${lastName ?? ''}"; + return fullName; + } + PendingOrdersRes( {this.rowID, this.orderID, diff --git a/lib/core/model/update_driver_location/request_update_driver_location.dart b/lib/core/model/update_driver_location/request_update_driver_location.dart index 64fbbf1..4cbfcc7 100644 --- a/lib/core/model/update_driver_location/request_update_driver_location.dart +++ b/lib/core/model/update_driver_location/request_update_driver_location.dart @@ -1,3 +1,6 @@ +import 'package:driverapp/config/shared_pref_kay.dart'; +import 'package:driverapp/core/model/authentication/authenticated_user.dart'; +import 'package:driverapp/uitl/app_shared_preferences.dart'; import 'package:location/location.dart'; class RequestUpdateDriverLocation{ @@ -5,11 +8,16 @@ class RequestUpdateDriverLocation{ LocationData location; RequestUpdateDriverLocation({this.orderID,this.location}); - Map toJson() { + Future> toJson() async{ final Map data = new Map(); data['OrderID'] = this.orderID; data['Latitude'] = "${this.location.latitude}"; data['Longitude'] = "${this.location.longitude}"; + + Map profile = await AppSharedPreferences().getObject(USER_PROFILE); + AuthenticatedUser doctorProfile = AuthenticatedUser.fromJson(profile); + data['DriverID'] = doctorProfile?.iD; + data['UserID'] = '${doctorProfile?.iD}'; return data; } } \ No newline at end of file diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index 8c3602b..969118c 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -16,21 +16,23 @@ AppSharedPreferences sharedPref = new AppSharedPreferences(); /// body: null); class BaseAppClient { - post( - String endPoint, { - Map body, - Function(dynamic response, int statusCode) onSuccess, - Function(String error, int statusCode) onFailure, - }) async { + String _Statictoken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; + post( + String endPoint, { + Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure}) async { String url = BASE_URL + endPoint; try { Map profile = await sharedPref.getObject(USER_PROFILE); String token = await sharedPref.getString(TOKEN); if (profile != null) { AuthenticatedUser doctorProfile = AuthenticatedUser.fromJson(profile); - body['DriverID'] = doctorProfile?.userID; + if(!body.keys.contains('DriverID') || body['DriverID'] == null) + body['DriverID'] = doctorProfile?.userID; + if(!body.keys.contains('UserID') || body['UserID'] == null) + body['UserID'] = '${doctorProfile?.userID}'; body['CreatedBy'] = doctorProfile?.userID; - body['UserID'] = '${doctorProfile?.userID}'; body['TokenID'] = token; body['MobileNo'] = doctorProfile?.mobileNumber; } @@ -45,7 +47,8 @@ class BaseAppClient { body: json.encode(body), headers: { 'Content-Type': 'application/json', - 'Accept': 'application/json' + 'Accept': 'application/json', + 'Statictoken': _Statictoken }); final int statusCode = response.statusCode; if (statusCode < 200 || statusCode >= 400 || json == null) { @@ -56,11 +59,11 @@ class BaseAppClient { // await helpers.logout(); //helpers.showErrorToast('Your session expired Please login agian'); // TODO create logout fun + onFailure("Unauthorized", 401); } else if (parsed['MessageStatus'] == 1) { onSuccess(parsed, statusCode); } else { - onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], - statusCode); + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); } } } else { @@ -71,4 +74,66 @@ class BaseAppClient { onFailure(e.toString(), -1); } } + + get( + String endPoint, { + Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure}) async { + String url = BASE_URL + endPoint; + try { + if (await Utils.checkConnection()) { + final response = await http.get(url, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Statictoken': _Statictoken + }); + final int statusCode = response.statusCode; + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + var parsed = json.decode(response.body.toString()); + if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode); + } else { + onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], statusCode); + } + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } catch (e) { + print(e); + onFailure(e.toString(), -1); + } + } + + + simpleGet( + String url, + { Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure}) async { + try { + if (await Utils.checkConnection()) { + final response = await http.get(url, + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Statictoken': _Statictoken + }); + final int statusCode = response.statusCode; + if (statusCode < 200 || statusCode >= 400) { + onFailure('Error While Fetching data', statusCode); + } else { + onSuccess(response.body, statusCode); + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } catch (e) { + print(e); + onFailure(e.toString(), -1); + } + } } diff --git a/lib/core/service/delivery_tracking_services.dart b/lib/core/service/delivery_tracking_services.dart index 4a7c389..65fbb5d 100644 --- a/lib/core/service/delivery_tracking_services.dart +++ b/lib/core/service/delivery_tracking_services.dart @@ -1,100 +1,141 @@ import 'dart:collection'; +import 'dart:math'; import 'package:driverapp/config/config.dart'; -import 'package:driverapp/core/model/initiate_order_delivey/request_initiate_order_delivery.dart'; -import 'package:driverapp/core/model/orders/deliverd_order_res_model.dart'; -import 'package:driverapp/core/model/orders/next_order_request_model.dart'; -import 'package:driverapp/core/model/orders/pending_orders_req_model.dart'; +import 'package:driverapp/config/shared_pref_kay.dart'; +import 'package:driverapp/core/model/StatusModel.dart'; +import 'package:driverapp/core/model/order_delivey/request_initiate_order_delivery.dart'; +import 'package:driverapp/core/model/order_delivey/request_validate_delivery.dart'; import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; -import 'package:driverapp/core/model/orders/update_order_status_request_model.dart'; -import 'package:driverapp/core/model/scan_qr/scan_qr_request_model.dart'; import 'package:driverapp/core/model/update_driver_location/request_update_driver_location.dart'; import 'package:driverapp/core/service/base_service.dart'; +import 'package:driverapp/uitl/app_shared_preferences.dart'; import 'package:driverapp/uitl/utils.dart'; import 'package:flutter/cupertino.dart'; import 'package:latlong/latlong.dart'; import 'package:location/location.dart'; +import 'package:shared_preferences/shared_preferences.dart'; class DeliveryTrackingServices extends BaseService { - var _distanceFilter = 5; // [Meters] (Call update API if distance covered from last location is greater then 'value' ) + var _distanceFilter = 20; // [Meters] (Call update API if distance covered from last location is greater then 'value' ) - var initiateOrderDeliveryResponse = null; - Future initiateOrderDelivery(int orderID) async { + Future initiateOrderDelivery(PendingOrdersRes order) async { hasError = false; - var order = RequestInitiateOrderDelivery(orderID: orderID); + var testNumber = ""; + ResponseModel result; + // var orderRequest = RequestInitiateOrderDelivery(orderNo: order.ePharmacyOrderNo, mobileNumber: testNumber == "" ? order.mobileNumber : testNumber); + var fullUrl = BASE_URL + INITIATE_DELIVERY + "/${order.ePharmacyOrderNo}/${user.iD}"; + await baseAppClient.simpleGet(fullUrl, + onSuccess: (dynamic response, int statusCode) { + result = ResponseModel(isSuccessful: true,message: null, data: response); + startLocationUpdate(order.ePharmacyOrderNo); - try { - await baseAppClient.post(PING_SERVICE, - onSuccess: (dynamic response, int statusCode) { - initiateOrderDeliveryResponse = response; + }, onFailure: (String error, int statusCode) { + result = ResponseModel(isSuccessful: false,message: error,data: null); + }); - }, onFailure: (String error, int statusCode) { - super.hasError = true; - super.error = error; - }, body: order.toJson()); + return result; + } - } catch (e) { - hasError = true; - super.error = error; - throw e; - } + Future validateDelivery(PendingOrdersRes order, String pinCode) async{ + hasError = false; + var request = RequestValidateDelivery(orderNo: order.ePharmacyOrderNo, pinCode: pinCode); - return initiateOrderDeliveryResponse; + ResponseModel result; + await baseAppClient.post(VERIFY_DELIVERY, + onSuccess: (dynamic response, int statusCode) { + result = ResponseModel(isSuccessful: true,message: null, data: response); + }, onFailure: (String error, int statusCode) { + result = ResponseModel(isSuccessful: false,message: error,data: null); + }, body: request.toJson()); + + return result; } _updateDriverLocation(int orderID, LocationData location) async { if(location != null){ debugPrint("Updating driver location"); - var order = RequestUpdateDriverLocation(orderID: orderID, location: location); + var jsonBody = await RequestUpdateDriverLocation(orderID: orderID, location: location).toJson(); await baseAppClient.post(UPDATE_DRIVER_LOCATION, onSuccess: (dynamic response, int statusCode) { }, onFailure: (String errorMessage, int statusCode) { - if(statusCode == 200){ + if(statusCode == 200){ // Server responded but check failed (stop updating location) // stopLocationUpdate(orderID); // Show error message that you received in response } - }, body: order.toJson()); + }, body: jsonBody); } } - List _currentRunnings = List(); + Map _currentRunnings = Map(); Future startLocationUpdate(int orderID, {int frequencyInSeconds = 3}) async { - _currentRunnings.remove(orderID); // remove existing if its already running - _currentRunnings.add(orderID); - - while(_currentRunnings.contains(orderID)){ - await Future.delayed(Duration(seconds: frequencyInSeconds)); - Utils.possibleToGetLocation((value) async{ - if(value){ - var location = await Utils.getLocation(); - if (_haveEnoughLocationUpdate(location)) - await _updateDriverLocation(orderID, location); + if (_currentRunnings[orderID.toString()] == null){ + _currentRunnings[orderID.toString()] = Future.doWhile(() async{ + + await Future.delayed(Duration(seconds: frequencyInSeconds)); + var valid = _currentRunnings.containsKey(orderID.toString()); + if(valid){ + Utils.possibleToGetLocation((value) async{ + if(value){ + var location = await Utils.getLocation(); + if (_haveEnoughLocationUpdate(location)) + await _updateDriverLocation(orderID, location); + } + }); } + return valid; }); } + + SharedPreferences.getInstance().then((pref){ + pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList()); + }); + } + + bool isActiveDeliveringOrder(int ePharmacyOrderNo){ + return _currentRunnings.containsKey(ePharmacyOrderNo.toString()); + } + + List getActiveDeliveringOrders(){ + return _currentRunnings.keys.toList(growable: false); + } + + setActiveDeliveringOrders(List orders){ + orders.forEach((element) { + if(!_currentRunnings.containsKey(element)){ + _currentRunnings[element] = null; + } + }); + } + + clearActiveDeliveringOrders(){ + _currentRunnings.clear(); + SharedPreferences.getInstance().then((pref){ + pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList()); + }); } stopLocationUpdate(int orderID){ - _currentRunnings.remove(orderID); + _currentRunnings.remove(orderID.toString()); + SharedPreferences.getInstance().then((pref){ + pref.setStringList(ACTIVE_DELIVERIES, _currentRunnings.keys.toList()); + }); } LocationData _lastLocation; bool _haveEnoughLocationUpdate(LocationData location){ - if(_lastLocation == null) { - _lastLocation = location; - return true; - }else{ - var distanceCovered = Utils.distanceBetween(_lastLocation, location, LengthUnit.Meter); - return (distanceCovered > _distanceFilter); - } + _lastLocation = _lastLocation ?? location; + var distanceCovered = Utils.distanceBetween(_lastLocation, location, LengthUnit.Meter); + // debugPrint("distance: $distanceCovered"); + return (distanceCovered > _distanceFilter); } } diff --git a/lib/core/service/orders_service.dart b/lib/core/service/orders_service.dart index 9fb9c24..33e073d 100644 --- a/lib/core/service/orders_service.dart +++ b/lib/core/service/orders_service.dart @@ -79,11 +79,11 @@ class OrdersService extends BaseService { try { await baseAppClient.post(GET_ALL_ORDERS_STATUS, onSuccess: (dynamic response, int statusCode) { - listCountDelivered = + listCountDelivered = response["PatientER_CountOrderList"][0]["NumberOfDeliveredOrder"]; - listCountUnDelivered = + listCountUnDelivered = response["PatientER_CountOrderList"][0]["NumberOfUnDeliveredOrder"]; - }, onFailure: (String error, int statusCode) { + }, onFailure: (String error, int statusCode) { hasError = true; super.error = error; }, body: {}); @@ -100,10 +100,9 @@ class OrdersService extends BaseService { try { await baseAppClient.post(UPDATE_ORDER_STATUS, onSuccess: (dynamic response, int statusCode) { - isOrderStatusUpdated = - response["PatientER_Delivery_IsOrderUpdated"]; - listCountUnDelivered --; - listCountDelivered ++; + isOrderStatusUpdated = response["PatientER_Delivery_IsOrderUpdated"]; + listCountUnDelivered--; + listCountDelivered++; }, onFailure: (String error, int statusCode) { hasError = true; super.error = error; @@ -137,13 +136,12 @@ class OrdersService extends BaseService { Future getDeliveredList() async { LocationData loc = await Utils.getLocation(); PendingOrders _requestGetPendingOrders = PendingOrders( - searchKey: "", - pageSize: 0, - pageIndex: 0, - latitude: loc.latitude.toString(), - longitude: loc.longitude.toString(), - driverAppPageID: 0 - ); + searchKey: "", + pageSize: 0, + pageIndex: 0, + latitude: loc.latitude.toString(), + longitude: loc.longitude.toString(), + driverAppPageID: 0); if (loc != null) { hasError = false; try { diff --git a/lib/core/viewModels/orders_view_model.dart b/lib/core/viewModels/orders_view_model.dart index e584374..c2ef2e3 100644 --- a/lib/core/viewModels/orders_view_model.dart +++ b/lib/core/viewModels/orders_view_model.dart @@ -1,16 +1,20 @@ import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/StatusModel.dart'; import 'package:driverapp/core/model/orders/deliverd_order_res_model.dart'; import 'package:driverapp/core/model/orders/next_order_request_model.dart'; import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; import 'package:driverapp/core/model/orders/update_order_status_request_model.dart'; import 'package:driverapp/core/model/scan_qr/scan_qr_request_model.dart'; +import 'package:driverapp/core/service/delivery_tracking_services.dart'; import 'package:driverapp/core/service/orders_service.dart'; +import 'package:flutter/cupertino.dart'; import '../../locator.dart'; import 'base_view_model.dart'; class OrdersViewModel extends BaseViewModel { OrdersService _ordersService = locator(); + DeliveryTrackingServices deliveryService = locator(); List get orders => _ordersService.orders; @@ -64,15 +68,37 @@ class OrdersViewModel extends BaseViewModel { setState(ViewState.Idle); } - Future updateOrderStatus( - UpdateOrderStatusRequestModel updateOrderStatusRequestModel) async { + Future updateOrderStatus({@required int orderNo, @required int status, String rejectionReason}) async { + var updateOrderStatusRequestModel + = UpdateOrderStatusRequestModel( + deliveryOrderID: orderNo, + deliveryOrderStatus: status, + rejectionReason: rejectionReason, + cancleReason: rejectionReason); + setState(ViewState.BusyLocal); await _ordersService.updateOrderStatus(updateOrderStatusRequestModel); if (_ordersService.hasError) { error = _ordersService.error; setState(ViewState.ErrorLocal); - } else + return ResponseModel(isSuccessful: false, message: error); + } else { setState(ViewState.Idle); + if(status == 2) + moveOrderFromPendingToDelivered(orderNo); + return ResponseModel(isSuccessful: true, message: "Successful"); + } + } + + + moveOrderFromPendingToDelivered(int orderNo) async{ + var idx = orders.indexWhere((element) => element.ePharmacyOrderNo == orderNo); + var order = orders[idx]; + orders.removeAt(idx); + var order_delivered = DeliverdOrderResModel.fromJson(order.toJson()); + order_delivered.description = "Delivered"; + order_delivered.descriptionN = "Delivered"; + deliverdOrders.add(order_delivered); } Future nextOrder(NextOrderRequestModel nextOrderRequestModel) async { @@ -85,6 +111,31 @@ class OrdersViewModel extends BaseViewModel { setState(ViewState.Idle); } + Future initDelivery(PendingOrdersRes order, {Function(@required ResponseModel response) completion}) async{ + var response = await deliveryService.initiateOrderDelivery(order); + completion(response ?? ResponseModel(isSuccessful: false,message: "Something went wrong, Please try again later.")); + + return response; + // (true, response['ErrorEndUserMessage'] ?? response['ErrorMessage'] ?? "Successfully, Please start navigation.") + } + + Future validateDelivery(PendingOrdersRes order, String pinCode) async{ + return await deliveryService.validateDelivery(order, pinCode); + } + + Future resendOtpToReceiver(PendingOrdersRes order) async{ + // return await _deliveryService.validateDelivery(order, pinCode); + } + + bool isActiveDeliveringOrder(int index){ + return deliveryService.isActiveDeliveringOrder(orders[index].ePharmacyOrderNo); + } + + Future> getActiveDeliveringOrders() async{ + return deliveryService.getActiveDeliveringOrders(); + } + + showBottomSheet() { isBottomSheetAppear = true; setState(ViewState.Idle); diff --git a/lib/main.dart b/lib/main.dart index 1a9a040..b6abcd1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,14 @@ +import 'package:driverapp/core/service/delivery_tracking_services.dart'; +import 'package:driverapp/core/viewModels/orders_view_model.dart'; import 'package:driverapp/pages/splash_screen_page.dart'; +import 'package:driverapp/uitl/app_shared_preferences.dart'; import 'package:driverapp/uitl/translations_delegate_base.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'config/shared_pref_kay.dart'; import 'config/size_config.dart'; import 'core/viewModels/authentication_view_model.dart'; import 'core/viewModels/project_view_model.dart'; @@ -14,9 +19,30 @@ void main() { runApp(MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatelessWidget with WidgetsBindingObserver{ + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + + if(state == AppLifecycleState.paused){ + debugPrint("....App paused...."); + + }else if(state == AppLifecycleState.resumed){ + debugPrint("....App resumed...."); + } + } + @override Widget build(BuildContext context) { + + WidgetsBinding.instance.addObserver(this); + + SharedPreferences.getInstance().then((value){ + var activeOrders = value.getStringList(ACTIVE_DELIVERIES) ?? []; + locator().setActiveDeliveringOrders(activeOrders); + }); + return LayoutBuilder( builder: (context, constraints) { return OrientationBuilder( @@ -30,6 +56,9 @@ class MyApp extends StatelessWidget { ChangeNotifierProvider( create: (context) => AuthenticationViewModel(), ), + ChangeNotifierProvider( + create: (context) => OrdersViewModel(), + ), ], child: Consumer( builder: (context, projectProvider, child) => MaterialApp( diff --git a/lib/pages/authentication/delivery_verification_page.dart b/lib/pages/authentication/delivery_verification_page.dart new file mode 100644 index 0000000..b6ededd --- /dev/null +++ b/lib/pages/authentication/delivery_verification_page.dart @@ -0,0 +1,453 @@ +import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/config/config.dart'; +import 'package:driverapp/config/size_config.dart'; +import 'package:driverapp/core/model/authentication/login_request.dart'; +import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; +import 'package:driverapp/core/service/delivery_tracking_services.dart'; +import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/core/viewModels/orders_view_model.dart'; +import 'package:driverapp/core/viewModels/project_view_model.dart'; +import 'package:driverapp/locator.dart'; +import 'package:driverapp/pages/authentication/reset_password_page.dart'; +import 'package:driverapp/pages/delivery/delivery_confirmed_page.dart'; +import 'package:driverapp/uitl/app_toast.dart'; +import 'package:driverapp/uitl/translations_delegate_base.dart'; +import 'package:driverapp/uitl/utils.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; +import 'package:sweetalert/sweetalert.dart'; + +import 'forget_password_page.dart'; + +// ignore: must_be_immutable +class DeliveryVerificationPage extends StatelessWidget { + + final PendingOrdersRes order; + DeliveryVerificationPage({this.order}); + + ProjectViewModel _projectViewModel; + OrdersViewModel _ordersViewModel; + final formKey = GlobalKey(); + Map formValues = { + 'digit1': null, + 'digit2': null, + 'digit3': null, + 'digit4': null, + }; + + FocusNode focusD1 = FocusNode(); + FocusNode focusD2 = FocusNode(); + FocusNode focusD3 = FocusNode(); + FocusNode focusD4 = FocusNode(); + var model; + TextEditingController digit1 = TextEditingController(text: ""); + TextEditingController digit2 = TextEditingController(text: ""); + TextEditingController digit3 = TextEditingController(text: ""); + TextEditingController digit4 = TextEditingController(text: ""); + + bool _isLoading = false; + + SizedBox buildSizedBox([double height = 20]) { + return SizedBox( + height: height, + ); + } + + BuildContext _context; + @override + Widget build(BuildContext context) { + _context = context; + _projectViewModel = Provider.of(context); + _ordersViewModel = Provider.of(context); + + String validateCodeDigit(value) { + if (value.isEmpty) { + return 'Please enter your Password'; + } + + return null; + } + + return AnimatedSwitcher( + duration: Duration(milliseconds: 2000), + child: AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FractionallySizedBox( + widthFactor: 0.80, + child: Column( + children: [ + SizedBox( + height: 30, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Icon( + DriverApp.deliverd_icon, + size: 150, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + top: 20, + ), + ), + ], + ), + SizedBox( + height: 20, + ), + Column( + children: [ + Center( + child: Text( + "Verification", + style: TextStyle( + fontSize: 25, + letterSpacing: 1, + fontWeight: FontWeight.w600), + ), + ), + ], + ), + SizedBox( + height: 30, + ), + SizedBox( + height: 10, + ), + Form( + key: formKey, + child: Container( + width: SizeConfig.realScreenWidth * 0.90, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20), + child: Row( + mainAxisAlignment: + MainAxisAlignment.end, + children: [ + Expanded( + child: Text( + TranslationBase.of(context) + .enterCustomerVerificationCodeMsg, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 13, + color: Colors.grey), + ), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + buildSizedBox(30), + Center( + child: FractionallySizedBox( + widthFactor: 0.80, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + Container( + width: 55, + height: 55, + color: Colors.transparent, + child: Center( + child: TextFormField( + textInputAction: + TextInputAction.next, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + focusNode: focusD1, + controller: digit1, + enableInteractiveSelection: false, + showCursor: false, + maxLength: 1, + textAlign: TextAlign.center, + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + onSaved: (val) { + formValues[ + 'digit1'] = val; + }, + validator: validateCodeDigit, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD2); + }, + onChanged: (val) => val.isNotEmpty + ? FocusScope.of(context).requestFocus(focusD2) + : FocusScope.of(context).requestFocus(focusD1) + ), + ), + ), + Container( + width: 55, + height: 55, + color: Colors.transparent, + child: Center( + child: TextFormField( + focusNode: focusD2, + controller: digit2, + enableInteractiveSelection: false, + showCursor: false, + maxLength: 1, + textInputAction: + TextInputAction.next, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + formValues[ + 'digit2'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD3); + }, + onChanged: (val) => val.isNotEmpty + ? FocusScope.of(context).requestFocus(focusD3) + : FocusScope.of(context).requestFocus(focusD1) + ), + ), + ), + Container( + width: 55, + height: 55, + color: Colors.transparent, + child: Center( + child: TextFormField( + focusNode: focusD3, + controller: digit3, + enableInteractiveSelection: false, + showCursor: false, + maxLength: 1, + textInputAction: TextInputAction.next, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + formValues[ + 'digit3'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) => val.isNotEmpty + ? FocusScope.of(context).requestFocus(focusD4) + : FocusScope.of(context).requestFocus(focusD2), + ), + )), + Container( + width: 55, + height: 55, + color: Colors.transparent, + child: Center( + child: TextFormField( + focusNode: focusD4, + controller: digit4, + enableInteractiveSelection: false, + showCursor: false, + maxLength: 1, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + formValues[ + 'digit4'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) => val.isNotEmpty + ? FocusScope.of(context).requestFocus(focusD4) + : FocusScope.of(context).requestFocus(focusD3) + ), + ), + ) + ], + ), + ), + ), + buildSizedBox(20), + // ShowTimerText(model: model), + ]))) + ], + ), + ), + SizedBox( + height: 20, + ), + SizedBox( + height: 10, + ), + Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.22, + child: Column( + children: [ + SecondaryButton( + label: "Verify Receiver", + onTap: () { + _verifyCustomer(); + }, + disabled: _isLoading, + loading: _isLoading, + ), + SizedBox( + height: 10, + ), + // Row( + // mainAxisAlignment: MainAxisAlignment.end, + // children: [ + // InkWell( + // onTap: () { + // Navigator.pushReplacement( + // context, + // MaterialPageRoute( + // builder: (context) => + // ForgetPasswordPage()), + // ); + // }, + // child: InkWell( + // onTap: () async { + // await _ordersViewModel.resendOtpToReceiver(order); + // }, + // child: Text( + // "Resend OPT?", + // style: TextStyle( + // fontSize: 14, + // color: Theme.of(context).primaryColor), + // ), + // ), + // ), + // ], + // ), + ], + )) + ], + ), + ), + ), + ); + } + + TextStyle buildTextStyle() { + return TextStyle( + fontSize: SizeConfig.textMultiplier * 3, + ); + } + + InputDecoration buildInputDecoration(BuildContext context) { + return InputDecoration( + filled: true, + fillColor: Colors.white, + // ts/images/password_icon.png + contentPadding: EdgeInsets.only(top: 30, bottom: 30), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(color: Colors.grey), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).primaryColor, width: 2), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor, width: 2), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor, width: 2), + ), + counterText: "", + errorStyle: TextStyle(height: 0.0) + ); + } + + + + _verifyCustomer() async { + if (formKey.currentState.validate()) { + final pinCode = digit1.text + digit2.text + digit3.text + digit4.text; + formKey.currentState.save(); + + SweetAlert.show(_context, subtitle: "Please wait...", style: SweetAlertStyle.loading); + var results = await _ordersViewModel.validateDelivery(order, pinCode); + if (results != null && results.isSuccessful) { + results = await _ordersViewModel.updateOrderStatus(orderNo: order.orderID, status: DeliveryStatus.delivered); + popWithDelay(context: _context, seconds: 0.2, callback: (){ + if(results.isSuccessful){ + _goToDeliveryDoneConfirmation(); + }else{ + Utils.showErrorToast(results.message); + } + }); + + }else{ + Navigator.of(_context).pop(); + Utils.showErrorToast(results.message); + } + } + } + + + _goToDeliveryDoneConfirmation(){ + locator().stopLocationUpdate(order.ePharmacyOrderNo); // Stop Driver Location update for Order + Navigator.pushReplacement( + _context, + MaterialPageRoute( + builder: (context) => DeliveryConfirmedPage(order), + ), + ); + } +} diff --git a/lib/pages/dashboard/dashboard_screen.dart b/lib/pages/dashboard/dashboard_screen.dart index 7ea3f09..1b57561 100644 --- a/lib/pages/dashboard/dashboard_screen.dart +++ b/lib/pages/dashboard/dashboard_screen.dart @@ -2,8 +2,10 @@ import 'package:driverapp/config/config.dart'; import 'package:driverapp/config/size_config.dart'; import 'package:driverapp/core/enum/viewstate.dart'; import 'package:driverapp/core/model/scan_qr/scan_qr_request_model.dart'; +import 'package:driverapp/core/service/delivery_tracking_services.dart'; import 'package:driverapp/core/viewModels/authentication_view_model.dart'; import 'package:driverapp/core/viewModels/orders_view_model.dart'; +import 'package:driverapp/locator.dart'; import 'package:driverapp/pages/delivery/information_page.dart'; import 'package:driverapp/pages/orders/deliverd_orders_page.dart'; import 'package:driverapp/pages/orders/pending_orders_page.dart'; @@ -20,6 +22,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart'; import 'package:hexcolor/hexcolor.dart'; import 'package:provider/provider.dart'; +import 'package:sweetalert/sweetalert.dart'; import '../base/base_view.dart'; @@ -31,6 +34,7 @@ class DashboardScreen extends StatefulWidget { class _DashboardScreenState extends State { bool _isInit = false; AuthenticationViewModel _authenticationViewModel; + OrdersViewModel _ordersViewModel; @override void didChangeDependencies() { @@ -49,513 +53,548 @@ class _DashboardScreenState extends State { Utils.getLocation(); } + checkActiveDelivery() async{ + if(_ordersViewModel.orders.isNotEmpty){ + await Future.delayed(Duration(milliseconds: 200)); + var orderNos = await _ordersViewModel.getActiveDeliveringOrders(); + if(orderNos.isEmpty) return; + + int orderNo = int.parse(orderNos.first); + var order = _ordersViewModel.orders.firstWhere((element) => element.ePharmacyOrderNo == orderNo, orElse: (){ }); + if(order == null){ + // clear active deliveries if accidentally mismatched during some activity + _ordersViewModel.deliveryService.clearActiveDeliveringOrders(); + return; + } + delay(300, (){ + SweetAlert.show(context, subtitle: "You already have active delivery", confirmButtonText: "Continue Delivery", onPress: (isConfirm){ + pop(context, (){ + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InformationPage( + item: order, + ))); + }); + return false; + }); + }); + } + } + @override Widget build(BuildContext context) { - int orderId; + return BaseView( onModelReady: (model) async { - await model.getPendingOrders(1); + _ordersViewModel = model; + await model.getPendingOrders(1); + checkActiveDelivery(); }, builder: (BuildContext context, OrdersViewModel model, Widget child) => AppScaffold( - body: SingleChildScrollView( - child: Container( - height: MediaQuery.of(context).orientation == Orientation.landscape - ? MediaQuery.of(context).size.height * 1.6 - : MediaQuery.of(context).size.height * 1.0, - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + body: SingleChildScrollView( + child: Container( + height: MediaQuery.of(context).orientation == Orientation.landscape + ? MediaQuery.of(context).size.height * 1.6 + : MediaQuery.of(context).size.height * 1.0, + child: Column( children: [ - Padding( - padding: EdgeInsets.all(16.0), - child: Column( - children: [ - SafeArea( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.all(16.0), + child: Column( + children: [ + SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + TranslationBase.of(context).haveGreatDay, + style: TextStyle( + fontSize: 14.5, + color: Color(0xff636363), + fontWeight: FontWeight.w300), + ), + Padding( + padding: EdgeInsets.only(top: 4.5), + child: Text( + _authenticationViewModel.user.userName, + style: TextStyle( + fontSize: 22.0, + color: HexColor("#343333"), + fontWeight: FontWeight.bold), + ), + ), + ], + ), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.all(16.0), + child: SafeArea( child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - TranslationBase.of(context).haveGreatDay, - style: TextStyle( - fontSize: 14.5, - color: Color(0xff636363), - fontWeight: FontWeight.w300), - ), - Padding( - padding: EdgeInsets.only(top: 4.5), - child: Text( - _authenticationViewModel.user.userName, - style: TextStyle( - fontSize: 22.0, - color: HexColor("#343333"), - fontWeight: FontWeight.bold), + InkWell( + child: CircleAvatar( + radius: 25.5, + backgroundColor: Color(0xff30B7B9), + child: CircleAvatar( + backgroundColor: Color(0xff30B7B9), + maxRadius: 26.0, + child: Image.asset( + 'assets/images/driver.png', + fit: BoxFit.contain, + ), + ), ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SettingPage( + driverName: _authenticationViewModel + .user.userName, + driverID: _authenticationViewModel + .user.userID))); + }, ), ], ), ), - ], - ), - ), - Padding( - padding: EdgeInsets.all(16.0), - child: SafeArea( - child: Column( - children: [ - InkWell( - child: CircleAvatar( - radius: 25.5, - backgroundColor: Color(0xff30B7B9), - child: CircleAvatar( - backgroundColor: Color(0xff30B7B9), - maxRadius: 26.0, - child: Image.asset( - 'assets/images/driver.png', - fit: BoxFit.contain, - ), - ), - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SettingPage( - driverName: _authenticationViewModel - .user.userName, - driverID: _authenticationViewModel - .user.userID))); - }, - ), - ], ), - ), + ], ), - ], - ), - Row( - children: [ - Expanded( - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0), - child: Container( - height: MediaQuery.of(context).orientation == + Row( + children: [ + Expanded( + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Container( + height: MediaQuery.of(context).orientation == Orientation.portrait - ? MediaQuery.of(context).size.height * 0.16 - : MediaQuery.of(context).size.height * 0.30, - width: MediaQuery.of(context).size.width * 0.44, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15.0), - gradient: LINEAR_GRADIENT, - ), - child: InkWell( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - OrdersListScreen())), - child: Row( - mainAxisAlignment: + ? MediaQuery.of(context).size.height * 0.16 + : MediaQuery.of(context).size.height * 0.30, + width: MediaQuery.of(context).size.width * 0.44, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15.0), + gradient: LINEAR_GRADIENT, + ), + child: InkWell( + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + OrdersListScreen())), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.all(2.0), - child: Column( - mainAxisAlignment: + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.all(2.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Text( - TranslationBase.of(context) - .youHave, - style: TextStyle( - color: Colors.white, - fontSize: MediaQuery.of(context) - .orientation == + children: [ + Text( + TranslationBase.of(context) + .youHave, + style: TextStyle( + color: Colors.white, + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig - .textMultiplier * + ? SizeConfig + .textMultiplier * 2.2 - : SizeConfig - .textMultiplier * + : SizeConfig + .textMultiplier * 1.3, - ), - ), - Text( - model.listCountUnDelivered - .toString(), - style: TextStyle( - color: Colors.white, - fontSize: SizeConfig + ), + ), + Text( + model.listCountUnDelivered + .toString(), + style: TextStyle( + color: Colors.white, + fontSize: SizeConfig .textMultiplier * - 3.0), - ), - Text( - TranslationBase.of(context) - .undeliveredPackages, - style: TextStyle( - color: Colors.white, - fontSize: MediaQuery.of(context) - .orientation == + 3.0), + ), + Text( + TranslationBase.of(context) + .undeliveredPackages, + style: TextStyle( + color: Colors.white, + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig - .textMultiplier * + ? SizeConfig + .textMultiplier * 2.2 - : SizeConfig - .textMultiplier * + : SizeConfig + .textMultiplier * 1.3, - ), - ) - ], + ), + ) + ], + ), + ), ), - ), - ), - Padding( - padding: EdgeInsets.only(right: 9.5), - child: Container( - width: 100, - height: 100, - decoration: BoxDecoration( - color: Colors.white10, - shape: BoxShape.circle), - child: Column( - mainAxisAlignment: + Padding( + padding: EdgeInsets.only(right: 9.5), + child: Container( + width: 100, + height: 100, + decoration: BoxDecoration( + color: Colors.white10, + shape: BoxShape.circle), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/closed_box.png', - height: MediaQuery.of(context) - .orientation == + children: [ + Image.asset( + 'assets/images/closed_box.png', + height: MediaQuery.of(context) + .orientation == Orientation.portrait - ? MediaQuery.of(context) - .size - .height * + ? MediaQuery.of(context) + .size + .height * 0.09 - : MediaQuery.of(context) - .size - .height * + : MediaQuery.of(context) + .size + .height * 0.20, - width: MediaQuery.of(context) + width: MediaQuery.of(context) .size .width * - 0.20, - scale: 0.9, - fit: BoxFit.contain, + 0.20, + scale: 0.9, + fit: BoxFit.contain, + ), + ], ), - ], + ), ), - ), + ], ), - ], + ), ), - ), - ), - ) - ], - ), - ), - Expanded( - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0), - child: Container( - height: MediaQuery.of(context).orientation == + ) + ], + ), + ), + Expanded( + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Container( + height: MediaQuery.of(context).orientation == Orientation.portrait - ? MediaQuery.of(context).size.height * 0.16 - : MediaQuery.of(context).size.height * 0.30, - width: MediaQuery.of(context).size.width * 0.45, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15.0), - gradient: LINEAR_GRADIENT, - ), - child: InkWell( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - DeliverdOrdersPage())), - child: Row( - mainAxisAlignment: + ? MediaQuery.of(context).size.height * 0.16 + : MediaQuery.of(context).size.height * 0.30, + width: MediaQuery.of(context).size.width * 0.45, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15.0), + gradient: LINEAR_GRADIENT, + ), + child: InkWell( + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + DeliverdOrdersPage())), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.all(2.0), - child: Column( - mainAxisAlignment: + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.all(2.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Text( - TranslationBase.of(context) - .youHave, - style: TextStyle( - color: Colors.white, - fontSize: MediaQuery.of(context) - .orientation == + children: [ + Text( + TranslationBase.of(context) + .youHave, + style: TextStyle( + color: Colors.white, + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig - .textMultiplier * + ? SizeConfig + .textMultiplier * 2.2 - : SizeConfig - .textMultiplier * + : SizeConfig + .textMultiplier * 1.3, - ), - ), - Text( - - model.listCountDelivered - .toString(), - style: TextStyle( - color: Colors.white, - fontSize: SizeConfig - .textMultiplier * - 3.0), - ), - Text( - TranslationBase.of(context) - .deliveredPackages, - style: TextStyle( - color: Colors.white, - fontSize: MediaQuery.of(context) - .orientation == + ), + ), + Text( + model.listCountDelivered + .toString(), + style: TextStyle( + color: Colors.white, + fontSize: SizeConfig + .textMultiplier * + 3.0), + ), + Text( + TranslationBase.of(context) + .deliveredPackages, + style: TextStyle( + color: Colors.white, + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig - .textMultiplier * + ? SizeConfig + .textMultiplier * 2.2 - : SizeConfig - .textMultiplier * + : SizeConfig + .textMultiplier * 1.3, - ), - ) - ], - ), - ), - ), - Padding( - padding: EdgeInsets.only(right: 9.5), - child: Container( - width: 100, - height: 100, - decoration: BoxDecoration( - color: Colors.white10, - shape: BoxShape.circle, + ), + ) + ], + ), + ), ), - child: Column( - mainAxisAlignment: + Padding( + padding: EdgeInsets.only(right: 9.5), + child: Container( + width: 100, + height: 100, + decoration: BoxDecoration( + color: Colors.white10, + shape: BoxShape.circle, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/opend_box.png', - height: MediaQuery.of(context) - .orientation == + children: [ + Image.asset( + 'assets/images/opend_box.png', + height: MediaQuery.of(context) + .orientation == Orientation.portrait - ? MediaQuery.of(context) - .size - .height * + ? MediaQuery.of(context) + .size + .height * 0.09 - : MediaQuery.of(context) - .size - .height * + : MediaQuery.of(context) + .size + .height * 0.20, - width: MediaQuery.of(context) + width: MediaQuery.of(context) .size .width * - 0.20, - scale: 0.9, - fit: BoxFit.contain, + 0.20, + scale: 0.9, + fit: BoxFit.contain, + ), + ], ), - ], + ), ), - ), + ], ), - ], + ), ), - ), - ), - ) - ], - ), + ) + ], + ), + ), + ], ), - ], - ), - Padding( - padding: + Padding( + padding: EdgeInsets.symmetric(vertical: 16.0, horizontal: 15.0), - child: Row( - children: [ - Expanded( - child: InkWell( - onTap: () { - _scanQrAndGetPatient(context, model); - }, - child: Container( - height: MediaQuery.of(context).orientation == + child: Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + _scanQrAndGetPatient(context, model); + }, + child: Container( + height: MediaQuery.of(context).orientation == Orientation.portrait - ? MediaQuery.of(context).size.height * 0.18 - : MediaQuery.of(context).size.height * 0.30, - width: MediaQuery.of(context).size.width * 0.50, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15.0), - gradient: LINEAR_GRADIENT, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, + ? MediaQuery.of(context).size.height * 0.18 + : MediaQuery.of(context).size.height * 0.30, + width: MediaQuery.of(context).size.width * 0.50, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15.0), + gradient: LINEAR_GRADIENT, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Image.asset( - 'assets/images/qr_code.png', - width: MediaQuery.of(context).size.width * - 0.26, - height: MediaQuery.of(context) - .orientation == + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/qr_code.png', + width: MediaQuery.of(context).size.width * + 0.26, + height: MediaQuery.of(context) + .orientation == Orientation.portrait - ? MediaQuery.of(context).size.height * + ? MediaQuery.of(context).size.height * 0.14 - : MediaQuery.of(context).size.height * + : MediaQuery.of(context).size.height * 0.28, - fit: BoxFit.contain, - ) - ], - ), - Column( - mainAxisAlignment: + fit: BoxFit.contain, + ) + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(top: 8.0), - child: Text( - TranslationBase.of(context).scan, - style: TextStyle( - fontSize: MediaQuery.of(context) - .orientation == + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + TranslationBase.of(context).scan, + style: TextStyle( + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig.textMultiplier * 6.0 - : SizeConfig.textMultiplier * 4.0, - color: Colors.white, - fontWeight: FontWeight.w400, + ? SizeConfig.textMultiplier * 6.0 + : SizeConfig.textMultiplier * 4.0, + color: Colors.white, + fontWeight: FontWeight.w400, + ), + ), ), - ), - ), - Padding( - padding: EdgeInsets.only(top: 0.0), - child: Text( - TranslationBase.of(context) - .toAddPackageToQue, - style: TextStyle( - fontSize: MediaQuery.of(context) - .orientation == + Padding( + padding: EdgeInsets.only(top: 0.0), + child: Text( + TranslationBase.of(context) + .toAddPackageToQue, + style: TextStyle( + fontSize: MediaQuery.of(context) + .orientation == Orientation.landscape - ? SizeConfig.textMultiplier * 3.0 - : SizeConfig.textMultiplier * 2.0, - color: Colors.white, - letterSpacing: 0.2, - wordSpacing: 0.5, + ? SizeConfig.textMultiplier * 3.0 + : SizeConfig.textMultiplier * 2.0, + color: Colors.white, + letterSpacing: 0.2, + wordSpacing: 0.5, + ), + ), ), - ), - ), + ], + ) ], - ) - ], + ), + ), ), - ), - ), - ) - ], - ), - ), - Padding( - padding: - EdgeInsets.symmetric(horizontal: 20.0, vertical: 1.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - children: [ - Text(TranslationBase.of(context).nearestDropOffs, - style: TextStyle( - fontSize: 18.0, - color: HexColor("#343333"), - fontWeight: FontWeight.bold)), + ) ], ), - if (model.state == ViewState.Idle) - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - child: Row( - children: [ - Text( - TranslationBase.of(context).seeAll, - style: TextStyle( - fontSize: 14.5, - color: Color(0xff42B6AD)), + ), + Padding( + padding: + EdgeInsets.symmetric(horizontal: 20.0, vertical: 1.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + Text(TranslationBase.of(context).nearestDropOffs, + style: TextStyle( + fontSize: 18.0, + color: HexColor("#343333"), + fontWeight: FontWeight.bold)), + ], + ), + if (model.state == ViewState.Idle) + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + child: Row( + children: [ + Text( + TranslationBase.of(context).seeAll, + style: TextStyle( + fontSize: 14.5, + color: Color(0xff42B6AD)), + ), + Icon( + Icons.arrow_forward_ios, + size: 15.0, + color: Color(0xff42B6AD), + ), + ], ), - Icon( - Icons.arrow_forward_ios, - size: 15.0, - color: Color(0xff42B6AD), + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => OrdersListScreen()), ), - ], - ), - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => OrdersListScreen()), - ), + ), + ], ), - ], - ), - ], - ), - ), - if (model.state == ViewState.Idle) - model.orders.length == 0 - ? Text("There's No Orders To deliver") - : SizedBox(), - NetworkBaseView( - baseViewModel: model, - child: Expanded( - child: ListView.builder( - shrinkWrap: true, - scrollDirection: Axis.vertical, - itemCount: model.orders == null - ? 0 - : model.orders.length < 3 - ? model.orders.length - : 3, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 0.2), - child: OrderInfoCard( - order: model.orders[index], - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => InformationPage( - item: model.orders[index], - ))); + ], + ), + ), + if (model.state == ViewState.Idle && model.orders.length == 0) + Padding(padding: EdgeInsets.only(top:20), child: Text("There's No Orders To deliver"),), + + NetworkBaseView( + baseViewModel: model, + child: Expanded( + child: RefreshIndicator( + onRefresh: () async { + return await _ordersViewModel.getPendingOrders(1); + }, + child: ListView.builder( + shrinkWrap: true, + scrollDirection: Axis.vertical, + itemCount: model.orders == null + ? 0 + : model.orders.length < 3 + ? model.orders.length + : 3, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 0.2), + child: OrderInfoCard( + order: model.orders[index], + isActiveToDeliver: _ordersViewModel.isActiveDeliveringOrder(index), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InformationPage( + item: model.orders[index], + ))); + }, + ), + ); }, ), - ); - }, + ), + ), ), - ), + ], ), - ], + ), ), ), - ), - ), ); } @@ -582,5 +621,5 @@ class _DashboardScreenState extends State { Utils.showErrorToast("Failed to get platform version."); // barcodeScanRes = 'Failed to get platform version.'; } - } + } } diff --git a/lib/pages/delivery/delivery_cancel_page.dart b/lib/pages/delivery/delivery_cancel_page.dart new file mode 100644 index 0000000..340ee15 --- /dev/null +++ b/lib/pages/delivery/delivery_cancel_page.dart @@ -0,0 +1,242 @@ +import 'package:driverapp/config/config.dart'; +import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/orders/next_order_request_model.dart'; +import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; +import 'package:driverapp/core/service/orders_service.dart'; +import 'package:driverapp/core/viewModels/orders_view_model.dart'; +import 'package:driverapp/locator.dart'; +import 'package:driverapp/pages/base/base_view.dart'; +import 'package:driverapp/root_page.dart'; +import 'package:driverapp/uitl/utils.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/delivery/customer_brief_card.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:location/location.dart'; + +import '../../uitl/translations_delegate_base.dart'; +import '../../widgets/others/app_scaffold_widget.dart'; +import 'information_page.dart'; + +class DeliveryCancelRejectedPage extends StatelessWidget { + final PendingOrdersRes item; + + DeliveryCancelRejectedPage(this.item); + + @override + Widget build(BuildContext context) { + return BaseView( + builder: (_, model, w) => AppScaffold( + isAppBarGradient: true, + isShowAppBar: true, + appBarColor: Theme.of(context).primaryColor, + arrowColor: Colors.white, + titleColor: Colors.white, + body: SafeArea( + child: Container( + // + child: ListView( + children: [ + Stack( + children: [ + Container( + decoration: BoxDecoration(gradient: LINEAR_GRADIENT), + height: MediaQuery.of(context).orientation == + Orientation.portrait + ? MediaQuery.of(context).size.width * 1 + : MediaQuery.of(context).size.width * 1, + child: Stack( + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).orientation == + Orientation.portrait + ? MediaQuery.of(context).size.width * 0.7 + : MediaQuery.of(context).size.width * 0.5, + padding: EdgeInsets.only( + top: MediaQuery.of(context).size.width * 0.14, + ), + decoration: BoxDecoration( + color: Colors.white10, shape: BoxShape.circle), + child: Column( + children: [ + Icon( + Icons.check_circle, + color: Colors.white, + size: 75, + ), + SizedBox( + height: + MediaQuery.of(context).size.width * 0.03, + ), + Text( + 'Delivery Confirmed', + style: TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: + MediaQuery.of(context).size.width * 0.01, + ), + Text( + TranslationBase.of(context).confirmationSent, + style: TextStyle( + color: Colors.white, + fontSize: 13, + ), + ), + ], + ), + ), + ], + ), + ), +// Container( +// width: MediaQuery.of(context).size.width, +// height: MediaQuery.of(context).size.width, +// ), + Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).orientation == + Orientation.landscape + ? MediaQuery.of(context).size.width * 0.6 + : MediaQuery.of(context).size.width * 1.0, + margin: EdgeInsets.only( + top: MediaQuery.of(context).orientation == + Orientation.portrait + ? MediaQuery.of(context).size.width * 0.70 + : MediaQuery.of(context).size.width * 0.60, + ), + decoration: BoxDecoration( + color: Theme + .of(context) + .scaffoldBackgroundColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(80), + topRight: Radius.circular(80)), + ), + child: Column( + mainAxisAlignment: MediaQuery.of(context).orientation == + Orientation.landscape + ? MainAxisAlignment.center + : MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.width * 0.00, + ), + child: Padding( + padding: MediaQuery.of(context).orientation == + Orientation.landscape + ? EdgeInsets.only(top: 60.0) + : EdgeInsets.only(top: 30.0), + child: Column( + children: [ + // TODO return add note when its needed + // FlatButton.icon( + // padding: EdgeInsets.all(14.0), + // color: Colors.orangeAccent, + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(10.0), + // ), + // label: Text( + // TranslationBase.of(context).addNoteBtn, + // style: TextStyle( + // color: Colors.white, fontSize: 20.0), + // ), + // icon: Icon( + // Icons.mode_edit, + // color: Colors.white, + // ), + // onPressed: () {}, + // ), + // SizedBox( + // height: MediaQuery.of(context).size.width * + // 0.00, //20, + // ), + Padding( + padding: const EdgeInsets.only(top: 30.0), + child: Container( + margin: EdgeInsets.all(10), + child: SecondaryButton( + label: TranslationBase.of(context) + .nextDelivery, + loading: + model.state == ViewState.BusyLocal, + onTap: () { + getNextOrder(context, model); + }, + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + Container( + margin: EdgeInsets.only( + top: MediaQuery.of(context).orientation == + Orientation.portrait + ? MediaQuery.of(context).size.width * 0.6 + : MediaQuery.of(context).size.width * 0.4, + ), + child: CustomerBriefCard( + customerOrderId: item.orderID, + pharmacyOrderId: item.ePharmacyOrderNo, + customerFirstName: item.firstName, + customerLastName: item.lastName, + mobileNo: item.mobileNumber, + totalPayment: item.amount, + distanceInKilometers: item.distanceInKilometers, + showDistance: false, + deliveryTime: item.orderCreatedOn), + ), + ], + ), + ], + ), + ), + ), + ), + ); + } + + getNextOrder(BuildContext context, OrdersViewModel model) async { + model.setState(ViewState.BusyLocal); + LocationData loc = await Utils.getLocation(); + NextOrderRequestModel nextOrderRequestModel = NextOrderRequestModel( + pageIndex: 0, + pageSize: 0, + latitude: loc.latitude.toString(), // "46.621730", + longitude: loc.longitude.toString(), // "24.797682", + searchKey: ""); + await model.nextOrder(nextOrderRequestModel); + if (model.state == ViewState.ErrorLocal) { + Utils.showErrorToast(model.error); + } else { + if (model.nextOrdersList != null && model.nextOrdersList.length == 0) { + Utils.showErrorToast("No Items in the list"); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => RootPage(), + ), + ); + } else { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + InformationPage(item: model.nextOrdersList[0]), + ), + ); + } + } + } +} diff --git a/lib/pages/delivery/delivery_confirmed_page.dart b/lib/pages/delivery/delivery_confirmed_page.dart index f8f48ee..f377e41 100644 --- a/lib/pages/delivery/delivery_confirmed_page.dart +++ b/lib/pages/delivery/delivery_confirmed_page.dart @@ -2,7 +2,9 @@ import 'package:driverapp/config/config.dart'; import 'package:driverapp/core/enum/viewstate.dart'; import 'package:driverapp/core/model/orders/next_order_request_model.dart'; import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; +import 'package:driverapp/core/service/orders_service.dart'; import 'package:driverapp/core/viewModels/orders_view_model.dart'; +import 'package:driverapp/locator.dart'; import 'package:driverapp/pages/base/base_view.dart'; import 'package:driverapp/root_page.dart'; import 'package:driverapp/uitl/utils.dart'; @@ -211,10 +213,8 @@ class DeliveryConfirmedPage extends StatelessWidget { NextOrderRequestModel nextOrderRequestModel = NextOrderRequestModel( pageIndex: 0, pageSize: 0, - latitude: loc.latitude.toString(), - //"46.621730", - longitude: loc.longitude.toString(), - //"24.797682", + latitude: loc.latitude.toString(), // "46.621730", + longitude: loc.longitude.toString(), // "24.797682", searchKey: ""); await model.nextOrder(nextOrderRequestModel); if (model.state == ViewState.ErrorLocal) { diff --git a/lib/pages/delivery/information_page.dart b/lib/pages/delivery/information_page.dart index 0b064d2..8b030e6 100644 --- a/lib/pages/delivery/information_page.dart +++ b/lib/pages/delivery/information_page.dart @@ -5,14 +5,18 @@ import 'package:android_intent/android_intent.dart'; import 'package:driverapp/app-icons/driver_app_icons.dart'; import 'package:driverapp/config/config.dart'; import 'package:driverapp/core/enum/viewstate.dart'; +import 'package:driverapp/core/model/StatusModel.dart'; import 'package:driverapp/core/model/orders/pending_orders_req_model.dart'; import 'package:driverapp/core/model/orders/pending_orders_res_model.dart'; import 'package:driverapp/core/model/orders/update_order_status_request_model.dart'; import 'package:driverapp/core/service/delivery_tracking_services.dart'; import 'package:driverapp/core/viewModels/orders_view_model.dart'; import 'package:driverapp/locator.dart'; +import 'package:driverapp/pages/authentication/delivery_verification_page.dart'; +import 'package:driverapp/pages/authentication/verification_page.dart'; import 'package:driverapp/pages/base/base_view.dart'; import 'package:driverapp/uitl/app_shared_preferences.dart'; +import 'package:driverapp/uitl/app_toast.dart'; import 'package:driverapp/uitl/translations_delegate_base.dart'; import 'package:driverapp/uitl/utils.dart'; import 'package:driverapp/widgets/bottom_sheet/action_sheet_button.dart'; @@ -25,11 +29,13 @@ import 'package:driverapp/widgets/delivery/package_content.dart'; import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_material_pickers/flutter_material_pickers.dart'; import 'package:hexcolor/hexcolor.dart'; -import 'package:maps_launcher/maps_launcher.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:map_launcher/map_launcher.dart'; +import 'package:sweetalert/sweetalert.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'delivery_cancel_page.dart'; import 'delivery_confirmed_page.dart'; @@ -44,16 +50,23 @@ class InformationPage extends StatefulWidget { // ignore: must_be_immutable class _InformationPageState extends State { - int _orderStatus; + var _deliveryService = locator(); PendingOrdersRes _item; - bool _isDeliveryStarted = false; + bool _isDeliveryStarted; + OrdersViewModel _viewModel; + @override + void initState() { + super.initState(); + _item = widget.item; + _isDeliveryStarted = _deliveryService.getActiveDeliveringOrders().contains(_item.ePharmacyOrderNo.toString()); + } @override Widget build(BuildContext context) { - _item = widget.item; return BaseView( + onModelReady: (model) => _viewModel = model, builder: (_, model, w) => AppScaffold( isShowAppBar: true, isShowHomeIcon: true, @@ -117,7 +130,7 @@ class _InformationPageState extends State { btnName: TranslationBase.of(context).location, btnFunction: () { - openMapIntent(_item); + _openMapDirection(_item); // MapsLauncher.launchCoordinates( // _item.latitude, _item.longitude); }, @@ -196,15 +209,11 @@ class _InformationPageState extends State { ? EdgeInsets.all(8.0) : EdgeInsets.symmetric(horizontal: 12.0), child: SecondaryButton( - label: - TranslationBase.of(context).clientReached, + label: _isDeliveryStarted + ? TranslationBase.of(context).deliveryOption + : TranslationBase.of(context).startDelivery, onTap: () { - locator() - .initiateOrderDelivery(_item.orderID) - .then((results){ - setState(() => _isDeliveryStarted = true); - // showDeliveryOptions(model); - }); + takeAction(); }, ), ), @@ -234,8 +243,69 @@ class _InformationPageState extends State { ); } + void takeAction(){ + if(_isDeliveryStarted) { + showDeliveryOptions(_viewModel); + }else{ + if(_deliveryService.getActiveDeliveringOrders().isEmpty){ + SweetAlert.show(context,subtitle: "Initializing delivery...", style: SweetAlertStyle.loading); + _viewModel.initDelivery(_item, completion: (response) { + if (response.isSuccessful) { + setState(() => _isDeliveryStarted = true); + Navigator.pop(context); + AppToast.showSuccessToast(message: "Start navigation by clicking icon [${response.data}]"); + + }else{ + SweetAlert.show(context,subtitle: response.message, style: SweetAlertStyle.error); + } + }); + }else{ + SweetAlert.show(context,subtitle: "Complete the last delivery first.",style: SweetAlertStyle.error); + } + } + } + + cancelDelivery() { + List speedOptions = [ + TranslationBase.of(context).notReachableOnPhoneCall, + TranslationBase.of(context).notAvailableAtlocation, + TranslationBase.of(context).accident, + TranslationBase.of(context).deliverLater, + // TranslationBase.of(context).other, + ]; + + List speedIcons = [ + Icon(IconData(0xe901, fontFamily: 'HMGIcon1')), + Icon(IconData(0xe900, fontFamily: 'HMGIcon1')), + Icon(IconData(0xe902, fontFamily: 'HMGIcon1')), + Icon(IconData(0xe903, fontFamily: 'HMGIcon1')), + ]; + showMaterialSelectionPicker( + context: context, + title: TranslationBase.of(context).selectReason, + items: speedOptions, + selectedItem: speedOptions.first, + icons: speedIcons, + onChanged: (value) async { + SweetAlert.show(context,subtitle: "Canceling delivery...", style: SweetAlertStyle.loading); + var result = await _viewModel.updateOrderStatus(orderNo: _item.orderID, status: DeliveryStatus.cancel); + Navigator.pop(context); + if(result.isSuccessful){ + _viewModel.deliveryService.stopLocationUpdate(_item.ePharmacyOrderNo); + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => DeliveryCancelRejectedPage(_item), // Replace with Delivery Cancel Screen + ), + ); + }else{ + SweetAlert.show(context,subtitle: result.message,style: SweetAlertStyle.error); + } + }, + ); + } showDeliveryOptions(OrdersViewModel model) { showModalBottomSheet( @@ -250,7 +320,7 @@ class _InformationPageState extends State { context: context, builder: (BuildContext bc) { return FractionallySizedBox( - heightFactor: 0.35, + heightFactor: 0.40, child: ListView( children: [ Container( @@ -278,8 +348,7 @@ class _InformationPageState extends State { height: 10, ), FractionallySizedBox( - widthFactor: MediaQuery.of(context).orientation == - Orientation.portrait + widthFactor: MediaQuery.of(context).orientation == Orientation.portrait ? 0.9 : 0.98, child: Container( @@ -310,7 +379,11 @@ class _InformationPageState extends State { TranslationBase.of(context).delivered, icon: DriverApp.deliverd_icon, onTap: () { - selectAction(context, 2, model); + Navigator.of(context).pop(); // Pop Bottom Action Sheet + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => DeliveryVerificationPage(order: _item)), + ); }, ), SizedBox(height: 15), @@ -328,18 +401,19 @@ class _InformationPageState extends State { .deliveredRejected, icon: DriverApp.rejected_icon, onTap: () { - selectAction(context, 3, model); + Navigator.of(context).pop(); // Pop Bottom Action Sheet + rejectDelivery(); + } + ), + SizedBox(height: 15), + ActionSheetButton( + label: TranslationBase.of(context).cancel, + icon: DriverApp.not_reachable_icon, + onTap: () { + cancelDelivery(); }, ), SizedBox(height: 15), - // ActionSheetButton( - // label: TranslationBase.of(context).canceled, - // icon: DriverApp.not_reachable_icon, - // onTap: () { - // selectAction(context, 6, model); - // }, - // ), - // SizedBox(height: 15), ], ), ], @@ -355,88 +429,50 @@ class _InformationPageState extends State { }); } + rejectDelivery(){ + SweetAlert.show(context,title: "Are you sure?",style: SweetAlertStyle.confirm, showCancelButton: true,onPress: (bool isConfirm) { + if (isConfirm) { + _viewModel.updateOrderStatus(orderNo: _item.orderID, status: DeliveryStatus.rejected).then((results){ - selectAction(BuildContext context, orderStatus, OrdersViewModel model) { - String orderStatusText; - this._orderStatus = orderStatus; - switch (orderStatus) { - case 2: - orderStatusText = TranslationBase - .of(context) - .delivered; - break; - // case 4: - // orderStatusText = TranslationBase.of(context).deliveredAccepted; - // break; - case 3: - orderStatusText = TranslationBase - .of(context) - .deliveredRejected; - break; - // case 6: - // orderStatusText = TranslationBase.of(context).canceled; - // break; - } - showDialog( - context: context, - builder: (BuildContext context) { - return CustomDialog( - orderStatusText: orderStatusText, - callService: () { - updateOrderStatus(context, model); - }, - model: model, - ); }); + } + return true; + }); } - updateOrderStatus(BuildContext context, OrdersViewModel model) async { - UpdateOrderStatusRequestModel updateOrderStatusRequestModel = - UpdateOrderStatusRequestModel( - deliveryOrderID: _item.orderID, - deliveryOrderStatus: _orderStatus, - rejectionReason: "NO Reason", - cancleReason: ""); - await model.updateOrderStatus(updateOrderStatusRequestModel); - if (model.state == ViewState.ErrorLocal) { - Utils.showErrorToast(model.error); - Navigator.of(context).pop(); - model.hideBottomSheet(); - } else { - /// to hide the dialog - Navigator.of(context).pop(); - model.hideBottomSheet(); - - /// to remove this page from the stack please no one remove this line. - Navigator.of(context).pop(); - - - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => - DeliveryConfirmedPage(_item), - ), - ); - } - } - - openMapIntent(PendingOrdersRes order) async{ + _openMapDirection(PendingOrdersRes order) async{ Utils.getLocation().then((locationData){ if(locationData != null){ - var url = "https://www.google.com/maps/dir/?api=1&destination=24.701833,46.697642&travelmode=driving&dir_action=navigate"; - if (Platform.isAndroid) { - var intent = AndroidIntent(action: 'action_view',data: url,package: 'com.google.android.apps.maps'); - intent.launch(); - }else { - print(url); - } + // MapLauncher.isMapAvailable(MapType.google).then((value){ + // if (value) { + // MapLauncher.showDirections( + // mapType: MapType.google, + // destination: Coords(order.latitude, order.longitude), + // directionsMode: DirectionsMode.driving, + // destinationTitle: order.receiverFullName()) + // .then((value) { + // + // }); + // }else{ + // // Google Map Not installed show error + // } + // }); + + /* Directly start navigation */ + MapLauncher.isMapAvailable(MapType.google).then((value){ + var url = "https://www.google.com/maps/dir/?api=1&destination=${order.latitude},${order.longitude}&travelmode=driving&dir_action=navigate"; + if (Platform.isAndroid) { + var intent = AndroidIntent(action: 'action_view',data: url,package: 'com.google.android.apps.maps'); + intent.launch(); + }else if (Platform.isIOS) { + launch(url); + } + }); // Start updating server wit your current location - locator().startLocationUpdate(order.orderID); + _deliveryService.startLocationUpdate(order.ePharmacyOrderNo); } }); - } } diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 07c8737..54020af 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -62,6 +62,9 @@ class TranslationBase { String get enterVerificationMsg => localizedValues['enterVerificationMsg'][locale.languageCode]; + String get enterCustomerVerificationCodeMsg => + localizedValues['enterCustomerVerificationCodeMsg'][locale.languageCode]; + String get forgotPassword => localizedValues['forgotPassword'][locale.languageCode]; @@ -111,6 +114,10 @@ class TranslationBase { String get startDelivery => localizedValues['startDelivery'][locale.languageCode]; + String get deliveryOption => + localizedValues['deliveryOption'][locale.languageCode]; + + String get addNoteBtn => localizedValues['addNoteBtn'][locale.languageCode]; String get nextDelivery => @@ -136,6 +143,24 @@ class TranslationBase { String get selectAction => localizedValues['selectAction'][locale.languageCode]; + String get selectReason => + localizedValues['selectReason'][locale.languageCode]; + + String get other => + localizedValues['other'][locale.languageCode]; + + String get notReachableOnPhoneCall => + localizedValues['notReachableOnPhoneCall'][locale.languageCode]; + + String get deliverLater => + localizedValues['deliverLater'][locale.languageCode]; + + String get notAvailableAtlocation => + localizedValues['notAvailableAtlocation'][locale.languageCode]; + + String get accident => + localizedValues['accident'][locale.languageCode]; + String get youHaveSelected => localizedValues['youHaveSelected'][locale.languageCode]; diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 074b97f..07a5532 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -13,6 +13,22 @@ import 'app_toast.dart'; AppSharedPreferences sharedPref = new AppSharedPreferences(); +popWithDelay({@required BuildContext context, @required num seconds, @required VoidCallback callback}){ + Navigator.of(context).pop(); + Future.delayed(Duration(milliseconds: (seconds*1000).toInt())).then((value){ + callback(); + }); +} + +pop(BuildContext context, VoidCallback callBack){ + Navigator.of(context).pop(); + callBack(); +} + +delay(int milliseconds, VoidCallback callback){ + Future.delayed(Duration(milliseconds: milliseconds)).then((value) => callback()); +} + class Utils { ///show custom Error Toast /// [message] to show for user @@ -138,3 +154,4 @@ class Utils { return formattedNamesList.join(' '); } } + diff --git a/lib/widgets/order/order_info_card.dart b/lib/widgets/order/order_info_card.dart index 7b9147d..f51a25b 100644 --- a/lib/widgets/order/order_info_card.dart +++ b/lib/widgets/order/order_info_card.dart @@ -6,140 +6,157 @@ import 'package:hexcolor/hexcolor.dart'; class OrderInfoCard extends StatelessWidget { const OrderInfoCard( - {Key key, this.order, this.onTap, this.showStatus = false}) + {Key key, this.order, this.onTap, this.showStatus = false, this.isActiveToDeliver = false}) : super(key: key); final dynamic order; final Function onTap; final bool showStatus; + final bool isActiveToDeliver; @override Widget build(BuildContext context) { return InkWell( - child: Container( + child: + Container( child: RoundedContainer( showShadow: true, raduis: 25.0, height: MediaQuery.of(context).orientation == Orientation.portrait ? MediaQuery.of(context).size.height * (showStatus ? 0.22 : 0.160) : MediaQuery.of(context).size.height * - (showStatus ? 0.359 : 0.269), + (showStatus ? 0.359 : 0.269), child: FractionallySizedBox( widthFactor: 0.98, - child: Column( - // mainAxisAlignment: MainAxisAlignment.start, + child: Stack( + children:[ + if(isActiveToDeliver) + Padding( + padding: const EdgeInsets.all(10.0), + child: Align( + alignment: Alignment.bottomRight, + child:Image.asset( + 'assets/images/check.png', + height: 20, + width: 20, + ), + ), + ), + Column( + // mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Column( - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: - EdgeInsets.only(left: 15.0, top: 14.0), - child: Image.asset( - 'assets/images/location.png', - height: MediaQuery.of(context) - .orientation == - Orientation.portrait - ? MediaQuery.of(context).size.height * - 0.06 - : MediaQuery.of(context).size.height * - 0.11, - width: MediaQuery.of(context).orientation == - Orientation.portrait - ? MediaQuery.of(context).size.width * - 0.05 - : MediaQuery.of(context).size.width * - 0.09, - ), - ), - SizedBox( - width: 13, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(top: 20.0), - child: Text( - Utils.formatStringToPascalCase( - order.firstName + - ' ' + - order.lastName), - style: TextStyle( - fontSize: 18.0, - color: HexColor("#343333"), - fontWeight: FontWeight.bold), + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: + EdgeInsets.only(left: 15.0, top: 14.0), + child: Image.asset( + 'assets/images/location.png', + height: MediaQuery.of(context) + .orientation == + Orientation.portrait + ? MediaQuery.of(context).size.height * + 0.06 + : MediaQuery.of(context).size.height * + 0.11, + width: MediaQuery.of(context).orientation == + Orientation.portrait + ? MediaQuery.of(context).size.width * + 0.05 + : MediaQuery.of(context).size.width * + 0.09, + ), ), - ), - Text( - order.mobileNumber, - style: TextStyle( - color: Color(0xff30B7B9), - fontWeight: FontWeight.w600, - fontSize: 15.0, + SizedBox( + width: 13, ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 20.0), + child: Text( + Utils.formatStringToPascalCase( + order.firstName + + ' ' + + order.lastName), + style: TextStyle( + fontSize: 18.0, + color: HexColor("#343333"), + fontWeight: FontWeight.bold), + ), + ), + Text( + order.mobileNumber, + style: TextStyle( + color: Color(0xff30B7B9), + fontWeight: FontWeight.w600, + fontSize: 15.0, + ), + ), + Text( + order.orderID.toString(), + style: TextStyle( + fontSize: 15.0, + fontWeight: FontWeight.w400, + letterSpacing: 8.0), + ), + ], + ), + ], + ), + ], + ) + ], + ), + Padding( + padding: EdgeInsets.all(8.0), + child: DistanceInKilometers( + distanceInKilometers: order.distanceInKilometers, + ), + ), + ], + ), + if (showStatus) + Row( + children: [ + Container( + margin: EdgeInsets.only(bottom: 12, left: 10), + child: RoundedContainer( + margin: 4, + showShadow: false, + backgroundColor: + order.statusID == 2 ? Colors.green : Colors.red, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 5, horizontal: 15), + child: Text( + order.description, + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 15.0, ), - Text( - order.orderID.toString(), - style: TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.w400, - letterSpacing: 8.0), - ), - ], + ), ), - ], + ), ), ], ) - ], - ), - Padding( - padding: EdgeInsets.all(8.0), - child: DistanceInKilometers( - distanceInKilometers: order.distanceInKilometers, - ), - ), - ], - ), - if (showStatus) - Row( - children: [ - Container( - margin: EdgeInsets.only(bottom: 12, left: 10), - child: RoundedContainer( - margin: 4, - showShadow: false, - backgroundColor: - order.statusID == 2 ? Colors.green : Colors.red, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 5, horizontal: 15), - child: Text( - order.description, - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 15.0, - ), - ), - ), - ), - ), ], - ) - ], - ), + ), + ]), ), ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 5cf6f1a..571f86f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,11 +86,11 @@ dependencies: #android_intent android_intent: any + # Alerts Dailogs + sweetalert: any - - - - + # flutter_material_pickers + flutter_material_pickers: 1.7.4 @@ -126,3 +126,7 @@ flutter: - asset: assets/fonts/Metropolis/Metropolis-Regular.otf - asset: assets/fonts/Metropolis/Metropolis-Bold.otf - asset: assets/fonts/Metropolis/Metropolis-Light.otf + + - family: HMGIcon1 + fonts: + - asset: assets/fonts/icomoon.ttf