diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 3a40a60..9cdab52 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -338,6 +338,7 @@ "shipment.popupmenu.delivered":"Delivered Shipments", "shipment.create":"Create shipment", "shipment.update":"Update shipment", + "shipment.info":"Shipment Info", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 0b5192c..d3b4502 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -338,6 +338,7 @@ "shipment.popupmenu.delivered":"ပို့ပြီးသော အထုပ်များ", "shipment.create":"ပို့ဆောင်ခြင်း ပြုလုပ်မည်", "shipment.update":"ပို့ဆောင်ခြင်းပြုပြင်မည်", + "shipment.info":"ပို့ဆောင်ခြင်း", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/lib/data/provider/shipment_data_provider.dart b/lib/data/provider/shipment_data_provider.dart new file mode 100644 index 0000000..d65cba4 --- /dev/null +++ b/lib/data/provider/shipment_data_provider.dart @@ -0,0 +1,43 @@ +import 'dart:async'; + +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:fcs/helpers/api_helper.dart'; +import 'package:fcs/helpers/firebase_helper.dart'; +import 'package:logging/logging.dart'; + +class ShipmentDataProvider { + final log = Logger('ShipmentDataProvider'); + + static final ShipmentDataProvider instance = ShipmentDataProvider._(); + ShipmentDataProvider._(); + + Future createShipment(Shipment shipment) async { + return await requestAPI("/shipments", "POST", + payload: shipment.toMap(), token: await getToken()); + } + + Future updateShipment(Shipment shipment) async { + return await requestAPI("/shipments", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future cancelShipment(Shipment shipment) async { + return await requestAPI("/shipment_cancel", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future confirmShipment(Shipment shipment) async { + return await requestAPI("/shipment_confirm", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future pickupShipment(Shipment shipment) async { + return await requestAPI("/shipment_pickup", "PUT", + payload: shipment.toMap(), token: await getToken()); + } + + Future receiveShipment(Shipment shipment) async { + return await requestAPI("/shipment_receive", "PUT", + payload: shipment.toMap(), token: await getToken()); + } +} diff --git a/lib/data/services/services.dart b/lib/data/services/services.dart index 7eb1d31..57e39c1 100644 --- a/lib/data/services/services.dart +++ b/lib/data/services/services.dart @@ -4,6 +4,7 @@ import 'package:fcs/data/provider/delivery_address_data_provider.dart'; import 'package:fcs/data/provider/fcs_shipment_data_provider.dart'; import 'package:fcs/data/provider/package_data_provider.dart'; import 'package:fcs/data/provider/rate_data_provider.dart'; +import 'package:fcs/data/provider/shipment_data_provider.dart'; import 'package:fcs/data/provider/user_data_provider.dart'; import 'package:fcs/data/services/delivery_address_imp.dart'; import 'package:fcs/data/services/delivery_address_service.dart'; @@ -11,6 +12,8 @@ import 'package:fcs/data/services/fcs_shipment_imp.dart'; import 'package:fcs/data/services/fcs_shipment_service.dart'; import 'package:fcs/data/services/rate_imp.dart'; import 'package:fcs/data/services/rate_service.dart'; +import 'package:fcs/data/services/shipment_imp.dart'; +import 'package:fcs/data/services/shipment_service.dart'; import 'auth_imp.dart'; import 'auth_service.dart'; @@ -34,6 +37,7 @@ class Services { FcsShipmentService _fcsShipmentService; DeliveryAddressService _deliveryAddressService; RateService _rateService; + ShipmentService _shipmentService; Services._() { _authService = AuthServiceImp( authFb: AuthFb.instance, @@ -52,6 +56,9 @@ class Services { deliveryAddressDataProvider: DeliveryAddressDataProvider()); _rateService = RateServiceImp( rateDataProvider: RateDataProvider.instance, connectivity: null); + _shipmentService = ShipmentServiceImp( + shipmentDataProvider: ShipmentDataProvider.instance, + connectivity: null); } AuthService get authService => _authService; @@ -62,4 +69,5 @@ class Services { FcsShipmentService get fcsShipmentService => _fcsShipmentService; DeliveryAddressService get deliveryAddressService => _deliveryAddressService; RateService get rateService => _rateService; + ShipmentService get shipmentService => _shipmentService; } diff --git a/lib/data/services/shipment_imp.dart b/lib/data/services/shipment_imp.dart new file mode 100644 index 0000000..05d45b5 --- /dev/null +++ b/lib/data/services/shipment_imp.dart @@ -0,0 +1,52 @@ +import 'package:fcs/data/provider/rate_data_provider.dart'; +import 'package:fcs/data/provider/shipment_data_provider.dart'; +import 'package:fcs/data/services/shipment_service.dart'; +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/connectivity.dart'; +import 'package:fcs/domain/entities/discount_by_weight.dart'; +import 'package:fcs/domain/entities/custom_duty.dart'; +import 'package:fcs/domain/entities/rate.dart'; +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:flutter/material.dart'; + +import 'rate_service.dart'; + +class ShipmentServiceImp implements ShipmentService { + ShipmentServiceImp({ + @required this.shipmentDataProvider, + @required this.connectivity, + }); + + final Connectivity connectivity; + final ShipmentDataProvider shipmentDataProvider; + + @override + Future cancelShipment(Shipment shipment) { + return shipmentDataProvider.cancelShipment(shipment); + } + + @override + Future confirmShipment(Shipment shipment) { + return shipmentDataProvider.confirmShipment(shipment); + } + + @override + Future createShipment(Shipment shipment) { + return shipmentDataProvider.createShipment(shipment); + } + + @override + Future pickupShipment(Shipment shipment) { + return shipmentDataProvider.pickupShipment(shipment); + } + + @override + Future receiveShipment(Shipment shipment) { + return shipmentDataProvider.receiveShipment(shipment); + } + + @override + Future updateShipment(Shipment shipment) { + return shipmentDataProvider.updateShipment(shipment); + } +} diff --git a/lib/data/services/shipment_service.dart b/lib/data/services/shipment_service.dart index 0a5f1ad..31b56ea 100644 --- a/lib/data/services/shipment_service.dart +++ b/lib/data/services/shipment_service.dart @@ -1,23 +1,10 @@ -import 'package:fcs/domain/entities/cargo_type.dart'; -import 'package:fcs/domain/entities/custom_duty.dart'; -import 'package:fcs/domain/entities/discount_by_weight.dart'; import 'package:fcs/domain/entities/shipment.dart'; -import 'package:fcs/domain/entities/rate.dart'; - -abstract class RateService { - Stream getRateStream(); +abstract class ShipmentService { Future createShipment(Shipment shipment); - - Future createCargoType(CargoType cargoType); - Future updateCargoType(CargoType cargoType); - Future deleteCargoType(String id); - - Future createCustomDuty(CustomDuty customDuty); - Future updateCustomDuty(CustomDuty customDuty); - Future deleteCustomDuty(String id); - - Future createDiscountByWeight(DiscountByWeight discountByWeight); - Future updateDiscountByWeight(DiscountByWeight discountByWeight); - Future deleteDiscountByWeight(String id); + Future updateShipment(Shipment shipment); + Future cancelShipment(Shipment shipment); + Future confirmShipment(Shipment shipment); + Future pickupShipment(Shipment shipment); + Future receiveShipment(Shipment shipment); } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 99c7a36..6da28e6 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -10,6 +10,7 @@ const delivery_address_collection = "delivery_addresses"; const cargo_types_collection = "cargo_types"; const custom_duties_collection = "custom_duties"; const discounts_by_weights_collection = "discounts_by_weight"; +const shipments_collection = "shipments"; // docs const setting_doc_id = "setting"; diff --git a/lib/domain/entities/box.dart b/lib/domain/entities/box.dart index 43c0798..d40974c 100644 --- a/lib/domain/entities/box.dart +++ b/lib/domain/entities/box.dart @@ -1,3 +1,5 @@ +import 'package:fcs/domain/entities/discount_by_weight.dart'; +import 'package:fcs/domain/entities/rate.dart'; import 'package:fcs/domain/vo/shipment_status.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; @@ -17,9 +19,9 @@ class Box { String status; String cargoDesc; String desc; - int width; - int height; - int length; + double width; + double height; + double length; int shipmentWeight; bool isChecked; String cartonType; @@ -38,7 +40,7 @@ class Box { List cargoTypes; - DeliveryAddress shippingAddress; + DeliveryAddress deliveryAddress; int get amount => rate != null && weight != null ? rate * weight : 0; @@ -46,6 +48,9 @@ class Box { shipmentNumber + "-" + receiverNumber + " #" + boxNumber; double get price => rate.toDouble() * weight; + double get actualWeight => + cargoTypes == null ? 0 : cargoTypes.fold(0, (p, e) => e.weight + p); + double getShipmentWeight(double volumetricRatio) { if (length == null || length <= 0 || @@ -59,6 +64,30 @@ class Box { return (length * width * height) / volumetricRatio; } + /// calAmount returns total amount + double calAmount(Rate rate) { + // get shipment weight + double volume = (length ?? 0) * (width ?? 0) * (height ?? 0); + double sw = volume / rate.volumetricRatio ?? 0; + + // get actual weight + double aw = cargoTypes.fold(0.0, (p, c) => p + c.weight); + if (aw == 0 || sw == 0) return 0; + + DiscountByWeight discountByWeight = + rate.getDiscountByWeight(sw > aw ? sw : aw); + + double total = 0; + cargoTypes.forEach((e) { + double cargoWeight = aw > sw ? e.weight : e.weight / aw * sw; + double r = + e.rate - (discountByWeight != null ? discountByWeight.discount : 0); + double amount = cargoWeight * r; + total += amount; + }); + return total; + } + List shipmentHistory; Box( @@ -91,5 +120,17 @@ class Box { this.shipmentHistory, this.packages, this.cargoTypes, - this.shippingAddress}); + this.deliveryAddress}); + + Map toMap() { + List _cargoTypes = cargoTypes.map((c) => c.toMap()).toList(); + return { + "id": id, + 'cargo_types': _cargoTypes, + 'length': length, + 'width': width, + 'height': height, + 'delivery_address': deliveryAddress.toMap(), + }; + } } diff --git a/lib/domain/entities/cargo_type.dart b/lib/domain/entities/cargo_type.dart index 69e173f..a4ca89c 100644 --- a/lib/domain/entities/cargo_type.dart +++ b/lib/domain/entities/cargo_type.dart @@ -2,6 +2,10 @@ class CargoType { String id; String name; double rate; + double weight; + + int shipmentWeight; + double amount; factory CargoType.fromMap(Map map, String id) { return CargoType( @@ -10,7 +14,6 @@ class CargoType { rate: (map['rate'] ?? 0).toDouble(), ); } - int weight; CargoType({this.id, this.name, this.rate, this.weight}); Map toMap() { @@ -18,6 +21,7 @@ class CargoType { "id": id, 'name': name, 'rate': rate, + 'weight': weight, }; } @@ -26,4 +30,9 @@ class CargoType { @override int get hashCode => id.hashCode; + + @override + String toString() { + return name; + } } diff --git a/lib/domain/entities/rate.dart b/lib/domain/entities/rate.dart index 6410f88..94a1ec4 100644 --- a/lib/domain/entities/rate.dart +++ b/lib/domain/entities/rate.dart @@ -12,6 +12,12 @@ class Rate { List customDuties; List discountByWeights; + DiscountByWeight getDiscountByWeight(double weight) { + discountByWeights.sort((d1, d2) => d2.weight.compareTo(d1.weight)); + return discountByWeights.firstWhere((e) => e.weight < weight, + orElse: () => null); + } + CargoType get defaultCargoType => cargoTypes == null ? null : cargoTypes.firstWhere((e) => e.name == "General"); diff --git a/lib/domain/entities/shipment.dart b/lib/domain/entities/shipment.dart index 2c988dd..ed75da2 100644 --- a/lib/domain/entities/shipment.dart +++ b/lib/domain/entities/shipment.dart @@ -1,54 +1,77 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/domain/entities/box.dart'; +import 'package:fcs/domain/vo/delivery_address.dart'; + import 'cargo_type.dart'; class Shipment { String id; + String shipmentNumber; + String shipmentType; + DeliveryAddress pickupAddress; + DateTime pickupDate; + String pickupTimeStart; + String pickupTimeEnd; + String userName; String phoneNumber; - String fromTime; - String toTime; int numberOfPackage; int weight; int handlingFee; String address; - String status; - DateTime date; - List cargoTypes; + String currentStatus; bool isCourier; int radioIndex; + List boxes; Shipment( {this.id, + this.shipmentNumber, + this.shipmentType, this.userName, this.phoneNumber, - this.fromTime, - this.toTime, + this.pickupTimeStart, + this.pickupTimeEnd, this.numberOfPackage, this.weight, this.handlingFee, this.address, - this.status, - this.date, - this.cargoTypes, + this.currentStatus, + this.pickupDate, this.isCourier = false, - this.radioIndex = 1}); + this.radioIndex = 1, + this.boxes}); - int get last => DateTime.now().difference(date).inDays; + int get last => DateTime.now().difference(pickupDate).inDays; factory Shipment.fromMap(Map map, String id) { + var pd = (map['pickup_date'] as Timestamp); return Shipment( id: id, userName: map['user_name'], + shipmentNumber: map['shipment_number'], phoneNumber: map['phone_number'], - fromTime: map['from_time'], - toTime: map['to_time'], - numberOfPackage: map['number_of_package'], - weight: map['weight'], - address: map['address'], - status: map['status']); + pickupDate: pd == null ? null : pd.toDate(), + pickupTimeStart: map['pickup_time_start'], + pickupTimeEnd: map['pickup_time_end'], + currentStatus: map['current_status']); + } + + Map toMap() { + List _boxes = boxes.map((l) => l.toMap()).toList(); + return { + "id": id, + 'boxes': _boxes, + 'shipment_type': shipmentType, + 'pickup_address': pickupAddress.toMap(), + "pickup_date": pickupDate?.toUtc()?.toIso8601String(), + 'pickup_time_start': pickupTimeStart, + 'pickup_time_end': pickupTimeEnd, + }; } @override String toString() { - return 'PickUp{id:$id, userName:$userName,phoneNumber:$phoneNumber,fromTime:$fromTime,toTime:$toTime,numberOfPackage:$numberOfPackage,weight:$weight,status:$status}'; + return 'PickUp{id:$id, userName:$userName,phoneNumber:$phoneNumber,numberOfPackage:$numberOfPackage,weight:$weight,currentStatus:$currentStatus}'; } } diff --git a/lib/pages/box/box_editor.dart b/lib/pages/box/box_editor.dart index 55044d4..6c63c4a 100644 --- a/lib/pages/box/box_editor.dart +++ b/lib/pages/box/box_editor.dart @@ -93,7 +93,7 @@ class _BoxEditorState extends State { if (widget.box != null) { _box = widget.box; - _deliveryAddress = _box.shippingAddress; + _deliveryAddress = _box.deliveryAddress; _cargoTypes = _box.cargoTypes; _selectShipmentNumber = _box.shipmentNumber; _widthController.text = _box.width.toString(); @@ -397,7 +397,7 @@ class _BoxEditorState extends State { if (_cargoTypes == null) { return []; } - int total = 0; + double total = 0; var rows = _cargoTypes.asMap().entries.map((c) { total += c.value.weight; diff --git a/lib/pages/box/box_info.dart b/lib/pages/box/box_info.dart index 770471f..40982c9 100644 --- a/lib/pages/box/box_info.dart +++ b/lib/pages/box/box_info.dart @@ -96,7 +96,7 @@ class _BoxInfoState extends State { _lengthController.text = _box.length.toString(); _cargoTypes = _box.cargoTypes; - _deliveryAddress = _box.shippingAddress; + _deliveryAddress = _box.deliveryAddress; } _calShipmentWeight() { @@ -324,7 +324,7 @@ class _BoxInfoState extends State { if (_cargoTypes == null) { return []; } - int total = 0; + double total = 0; var rows = _cargoTypes.asMap().entries.map((c) { total += c.value.weight; diff --git a/lib/pages/box/cargo_type_editor.dart b/lib/pages/box/cargo_type_editor.dart index c656647..697a7ae 100644 --- a/lib/pages/box/cargo_type_editor.dart +++ b/lib/pages/box/cargo_type_editor.dart @@ -75,7 +75,7 @@ class _CargoTypeEditorState extends State { context, getLocalString(context, 'box.cargo.save.btn'), callack: () { - _cargo.weight = int.parse(_weightController.text, onError: (s) => 0); + _cargo.weight = double.tryParse(_weightController.text) ?? 0; Navigator.pop(context, _cargo); }, ); diff --git a/lib/pages/box/model/box_model.dart b/lib/pages/box/model/box_model.dart index 77f4014..60ba323 100644 --- a/lib/pages/box/model/box_model.dart +++ b/lib/pages/box/model/box_model.dart @@ -47,7 +47,7 @@ class BoxModel extends BaseModel { shipmentWeight: 6, packages: packages, shipmentHistory: statusHistory, - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -79,7 +79,7 @@ class BoxModel extends BaseModel { packages: packages, receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', cartonType: carton_from_shipments, - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'Mg Myo', addressLine1: '153-154 5th Thitsar.', addressLine2: 'South Okkalapa Township', @@ -111,7 +111,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'Mg Myo', addressLine1: '153-154 5th Thitsar.', addressLine2: 'South Okkalapa Township', @@ -142,7 +142,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -172,7 +172,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -202,7 +202,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -232,7 +232,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -262,7 +262,7 @@ class BoxModel extends BaseModel { shipmentHistory: statusHistory, packages: packages, receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon', - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'U Nyi Nyi', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', diff --git a/lib/pages/invoice/invoice_shipment_list.dart b/lib/pages/invoice/invoice_shipment_list.dart index 748170a..38f65d5 100644 --- a/lib/pages/invoice/invoice_shipment_list.dart +++ b/lib/pages/invoice/invoice_shipment_list.dart @@ -1,13 +1,10 @@ import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/shipment/model/shipment_model.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; -import 'package:provider/provider.dart'; - import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'invoice_shipment_list_row.dart'; @@ -31,7 +28,7 @@ class _InvoiceShipmentListState extends State { @override Widget build(BuildContext context) { - var pickupModel = Provider.of(context); + ShipmentModel shipmentModel = Provider.of(context); return LocalProgress( inAsyncCall: _isLoading, child: DefaultTabController( @@ -64,10 +61,10 @@ class _InvoiceShipmentListState extends State { scrollDirection: Axis.vertical, padding: EdgeInsets.only(top: 15), shrinkWrap: true, - itemCount: pickupModel.pickups.length, + itemCount: shipmentModel.shipments.length, itemBuilder: (BuildContext context, int index) { return InvoiceShipmentListRow( - pickUp: pickupModel.pickups[index]); + pickUp: shipmentModel.shipments[index]); }), ), ), diff --git a/lib/pages/invoice/invoice_shipment_list_row.dart b/lib/pages/invoice/invoice_shipment_list_row.dart index a5d0eb9..4cad381 100644 --- a/lib/pages/invoice/invoice_shipment_list_row.dart +++ b/lib/pages/invoice/invoice_shipment_list_row.dart @@ -29,7 +29,6 @@ class _InvoiceShipmentListRowState extends State { @override Widget build(BuildContext context) { - print('_pickup $_pickUp'); return Container( padding: EdgeInsets.only(left: 15, right: 15), child: InkWell( @@ -83,7 +82,7 @@ class _InvoiceShipmentListRowState extends State { children: [ Padding( padding: const EdgeInsets.all(0), - child: getStatus(_pickUp.status), + child: getStatus(_pickUp.currentStatus), ), Padding( padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index 21389b6..834bf8d 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -225,7 +225,7 @@ class _HomePageState extends State { icon: Octicons.package, btnCallback: () => Navigator.of(context).push(CupertinoPageRoute( builder: (context) => PackageList( - onlyFcs: true, + forCustomer: false, )))); final receivingBtn = TaskButton("receiving.title", @@ -249,8 +249,10 @@ class _HomePageState extends State { final shipmentBtnFcs = TaskButton("shipment", icon: SimpleLineIcons.direction, - btnCallback: () => Navigator.of(context) - .push(CupertinoPageRoute(builder: (context) => ShipmentList()))); + btnCallback: () => Navigator.of(context).push(CupertinoPageRoute( + builder: (context) => ShipmentList( + forCustomer: false, + )))); final fcsShipmentBtn = TaskButton("FCSshipment.title", icon: Ionicons.ios_airplane, diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 37e73e5..00ea5fc 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -18,72 +18,55 @@ class PackageModel extends BaseModel { final log = Logger('PackageModel'); StreamSubscription listener; - StreamSubscription customerPackageListener; - List get packages => - _selectedIndex == 1 ? _packages : List.from(_delivered.values); - List get customerPackages => _selectedIndex == 1 - ? _customerPackages - : List.from(_customerDelivered.values); + List get packages => _menuSelectedIndex == 1 + ? _packages + : List.from(_delivered.values); List _packages = []; - List _customerPackages = []; Paginator _delivered; - Paginator _customerDelivered; bool isLoading = false; - bool isPackagesEnded = false; - bool isCustomerPackagesEnded = false; - int _selectedIndex = 1; - set selectedIndex(int index) { - _selectedIndex = index; + int _menuSelectedIndex = 1; + + set menuSelectedIndex(int index) { + _menuSelectedIndex = index; notifyListeners(); } - get selectedIndex => _selectedIndex; + get menuSelectedIndex => _menuSelectedIndex; - @override - void privilegeChanged() { - super.privilegeChanged(); - _loadPackages(); - _loadCustomerPackages(); - - if (_delivered != null) _delivered.close(); - _delivered = _getDeliveredExample(false); - loadMore(isCustomer: false); - if (_customerDelivered != null) _customerDelivered.close(); - _customerDelivered = _getDeliveredExample(false); - loadMore(isCustomer: true); + initData(bool forCustomer) { + logout(); + _menuSelectedIndex = 1; + _loadPackages(forCustomer); + _delivered = _getDeliveredExample(forCustomer); + _delivered.load(); } @override logout() async { if (_delivered != null) _delivered.close(); - if (_customerDelivered != null) _customerDelivered.close(); if (listener != null) await listener.cancel(); - if (customerPackageListener != null) await customerPackageListener.cancel(); _packages = []; - _customerPackages = []; } Future loadMore({bool isCustomer}) async { - if (selectedIndex == 1) + if (menuSelectedIndex == 1) return; // when delivered menu is not selected return - var p = isCustomer ? _customerDelivered : _delivered; - if (p.ended) return; + if (_delivered.ended) return; isLoading = true; notifyListeners(); - await p.load(onFinished: () { + await _delivered.load(onFinished: () { isLoading = false; notifyListeners(); }); } Future refresh({bool isCustomer}) async { - if (selectedIndex == 1) + if (menuSelectedIndex == 1) return; // when delivered menu is not selected return - var p = isCustomer ? _customerDelivered : _delivered; - await p.refresh(onFinished: () { + await _delivered.refresh(onFinished: () { notifyListeners(); }); } @@ -129,8 +112,9 @@ class PackageModel extends BaseModel { return paginator; } - Future _loadPackages() async { - if (user == null || + Future _loadPackages(bool forCustomer) async { + if (user == null) return; + if (!forCustomer && !((user.hasPackages() || user.hasReceiving() || user.hasProcessing()))) return; String path = "/$packages_collection"; @@ -143,6 +127,10 @@ class PackageModel extends BaseModel { .where("is_delivered", isEqualTo: false) .where("is_deleted", isEqualTo: false); + if (forCustomer) { + q = q.where("user_id", isEqualTo: user.id); + } + listener = q.snapshots().listen((QuerySnapshot snapshot) { _packages.clear(); _packages = snapshot.documents.map((documentSnapshot) { @@ -157,33 +145,6 @@ class PackageModel extends BaseModel { } } - Future _loadCustomerPackages() async { - if (user == null) return; - String path = "/$packages_collection"; - if (customerPackageListener != null) customerPackageListener.cancel(); - _customerPackages = []; - - try { - var q = Firestore.instance - .collection("$path") - .where("is_delivered", isEqualTo: false) - .where("is_deleted", isEqualTo: false) - .where("user_id", isEqualTo: user.id); - - customerPackageListener = q.snapshots().listen((QuerySnapshot snapshot) { - _customerPackages.clear(); - _customerPackages = snapshot.documents.map((documentSnapshot) { - var package = Package.fromMap( - documentSnapshot.data, documentSnapshot.documentID); - return package; - }).toList(); - notifyListeners(); - }); - } catch (e) { - log.warning("Error!! $e"); - } - } - Future getPackage(String id) async { if (user == null) return null; String path = "/$packages_collection"; diff --git a/lib/pages/package/package_list.dart b/lib/pages/package/package_list.dart index ad400f0..abde531 100644 --- a/lib/pages/package/package_list.dart +++ b/lib/pages/package/package_list.dart @@ -1,5 +1,4 @@ import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/helpers/paginator.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/package_info.dart'; @@ -14,9 +13,9 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class PackageList extends StatefulWidget { - final bool onlyFcs; + final bool forCustomer; - const PackageList({Key key, this.onlyFcs = false}) : super(key: key); + const PackageList({Key key, this.forCustomer = true}) : super(key: key); @override _PackageListState createState() => _PackageListState(); } @@ -32,31 +31,31 @@ class _PackageListState extends State { _controller.addListener(() async { if (_controller.position.pixels == _controller.position.maxScrollExtent) { Provider.of(context, listen: false) - .loadMore(isCustomer: !widget.onlyFcs); + .loadMore(isCustomer: widget.forCustomer); } }); + Provider.of(context, listen: false) + .initData(widget.forCustomer); } @override Widget build(BuildContext context) { var packageModel = Provider.of(context); - bool onlyFcs = widget.onlyFcs; - var packages = - onlyFcs ? packageModel.packages : packageModel.customerPackages; + var packages = packageModel.packages; final popupMenu = LocalPopupMenuButton( popmenus: [ LocalPopupMenu( id: 1, textKey: "package.popupmenu.active", - selected: packageModel.selectedIndex == 1), + selected: packageModel.menuSelectedIndex == 1), LocalPopupMenu( id: 2, textKey: "package.popupmenu.delivered", - selected: packageModel.selectedIndex == 2) + selected: packageModel.menuSelectedIndex == 2) ], popupMenuCallback: (p) => this.setState(() { - packageModel.selectedIndex = p.id; + packageModel.menuSelectedIndex = p.id; }), ); @@ -77,8 +76,9 @@ class _PackageListState extends State { color: Colors.white, ), actions: [ - onlyFcs - ? IconButton( + widget.forCustomer + ? Container() + : IconButton( icon: Icon( Icons.search, color: Colors.white, @@ -86,8 +86,7 @@ class _PackageListState extends State { iconSize: 30, onPressed: () => searchPackage(context, callbackPackageSelect: _searchCallback), - ) - : Container(), + ), popupMenu ], ), @@ -111,7 +110,7 @@ class _PackageListState extends State { ); }), onRefresh: () => - packageModel.refresh(isCustomer: !widget.onlyFcs), + packageModel.refresh(isCustomer: widget.forCustomer), ), ), packageModel.isLoading diff --git a/lib/pages/rates/shipment_rates_calculate.dart b/lib/pages/rates/shipment_rates_calculate.dart index e417432..4303005 100644 --- a/lib/pages/rates/shipment_rates_calculate.dart +++ b/lib/pages/rates/shipment_rates_calculate.dart @@ -1,17 +1,18 @@ +import 'package:fcs/domain/entities/box.dart'; +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/rate.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; import 'package:fcs/pages/widgets/display_text.dart'; +import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/length_picker.dart'; import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:fcs/pages/widgets/local_title.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:provider/provider.dart'; -import 'package:flutter/material.dart'; - class ShipmentRatesCal extends StatefulWidget { ShipmentRatesCal(); @@ -21,27 +22,52 @@ class ShipmentRatesCal extends StatefulWidget { class _ShipmentRatesCalState extends State { bool _isLoading = false; - String cargoType; + CargoType _cargoType; TextEditingController _widthController = new TextEditingController(); TextEditingController _heightController = new TextEditingController(); TextEditingController _lengthController = new TextEditingController(); - double shipmentWeight = 0; - double volumetricRatio = 0; + TextEditingController _actualWeightCtl = new TextEditingController(); + double _shipmentWeight = 0; + double _amount = 0; + double _deliveryFee = 0; @override void initState() { super.initState(); //for shipment weight - volumetricRatio = Provider.of(context, listen: false) - .rate - .volumetricRatio; - // _lengthController.addListener(_calShipmentWeight); - // _widthController.addListener(_calShipmentWeight); - // _heightController.addListener(_calShipmentWeight); - _lengthController.text = '10'; - _widthController.text = '10'; - _heightController.text = '10'; + Rate rate = Provider.of(context, listen: false).rate; + _lengthController.addListener(_calShipmentWeight); + _widthController.addListener(_calShipmentWeight); + _heightController.addListener(_calShipmentWeight); + _actualWeightCtl.addListener(_calShipmentWeight); + _cargoType = rate.defaultCargoType; + _lengthController.text = '12'; + _widthController.text = '12'; + _heightController.text = '12'; + _actualWeightCtl.text = "10"; + _calShipmentWeight(); + } + + _calShipmentWeight() { + Rate rate = Provider.of(context, listen: false).rate; + + double l = double.parse(_lengthController.text, (s) => 0); + double w = double.parse(_widthController.text, (s) => 0); + double h = double.parse(_heightController.text, (s) => 0); + _cargoType.weight = double.tryParse(_actualWeightCtl.text) ?? 0; + Box box = Box(cargoTypes: [_cargoType], length: l, width: w, height: h); + var amount = box.calAmount(rate); + var shipmentWeight = box.getShipmentWeight(rate.volumetricRatio); + var effectiveWeight = + _cargoType.weight > shipmentWeight ? _cargoType.weight : shipmentWeight; + + setState(() { + _deliveryFee = + effectiveWeight > rate.freeDeliveryWeight ? 0 : rate.deliveryFee; + _amount = amount == null ? 0 : amount + _deliveryFee; + _shipmentWeight = shipmentWeight; + }); } @override @@ -80,15 +106,16 @@ class _ShipmentRatesCalState extends State { ); final shipmentWeightBox = DisplayText( - text: shipmentWeight != null ? shipmentWeight.toStringAsFixed(0) : "6", + text: _shipmentWeight != null ? _shipmentWeight.toStringAsFixed(2) : "0", labelTextKey: "box.shipment_weight", iconData: MaterialCommunityIcons.weight, ); - final actualWeightBox = DisplayText( - text: shipmentWeight != null ? shipmentWeight.toStringAsFixed(0) : "", + final actualWeightBox = InputText( + controller: _actualWeightCtl, labelTextKey: "box.actual_weight", iconData: MaterialCommunityIcons.weight, + textInputType: TextInputType.number, ); return LocalProgress( @@ -119,17 +146,19 @@ class _ShipmentRatesCalState extends State { Container( width: 150.0, child: DropdownButtonFormField( + value: _cargoType, decoration: InputDecoration( fillColor: Colors.white, hintText: shipmentRateModel.rate.cargoTypes[0].name, hintStyle: TextStyle(color: Colors.black87)), items: shipmentRateModel.rate.cargoTypes - .map((e) => DropdownMenuItem( - child: Text(e.name), value: e.name)) + .map((e) => + DropdownMenuItem(child: Text(e.name), value: e)) .toList(), onChanged: (selected) => { setState(() { - cargoType = selected; + _cargoType = selected; + _calShipmentWeight(); }) }, ), @@ -137,51 +166,40 @@ class _ShipmentRatesCalState extends State { ], ), ), + actualWeightBox, // LocalTitle(textKey: "box.dimension"), dimBox, shipmentWeightBox, - actualWeightBox, - SizedBox(height: 50), - Center( - child: Container( - alignment: Alignment.center, - width: 150, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LocalText(context, "rate.delivery_fee", - color: primaryColor, fontSize: 16), - Text( - ':\$ 5', - style: TextStyle( - color: primaryColor, - fontSize: 16, - ), - ) - ], - ), - )), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LocalText(context, "rate.delivery_fee", + color: primaryColor, fontSize: 16), + Text( + ':\$ $_deliveryFee', + style: TextStyle( + color: primaryColor, + fontSize: 16, + ), + ) + ], + ), SizedBox(height: 20), - Center( - child: Container( - width: 220, - alignment: Alignment.center, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LocalText(context, "rate.total_estimated_amount", - color: primaryColor, fontSize: 16), - Text( - ':\$ 41', - style: TextStyle( - color: primaryColor, - fontSize: 16, - ), - ) - ], - ), - )) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LocalText(context, "rate.total_estimated_amount", + color: primaryColor, fontSize: 16), + Text( + ':\$${_amount.toStringAsFixed(2)}', + style: TextStyle( + color: primaryColor, + fontSize: 16, + ), + ) + ], + ) ], ), ), diff --git a/lib/pages/shipment/box_row.dart b/lib/pages/shipment/box_row.dart index b8c3b18..db403bb 100644 --- a/lib/pages/shipment/box_row.dart +++ b/lib/pages/shipment/box_row.dart @@ -27,9 +27,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.fullName == null + box.deliveryAddress.fullName == null ? '' - : box.shippingAddress.fullName, + : box.deliveryAddress.fullName, style: new TextStyle( fontSize: 15.0, color: Colors.black, @@ -39,9 +39,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.addressLine1 == null + box.deliveryAddress.addressLine1 == null ? '' - : box.shippingAddress.addressLine1, + : box.deliveryAddress.addressLine1, style: new TextStyle( fontSize: 14.0, color: Colors.grey), ), @@ -49,9 +49,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.addressLine2 == null + box.deliveryAddress.addressLine2 == null ? '' - : box.shippingAddress.addressLine2, + : box.deliveryAddress.addressLine2, style: new TextStyle( fontSize: 14.0, color: Colors.grey), ), @@ -59,9 +59,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.city == null + box.deliveryAddress.city == null ? '' - : box.shippingAddress.city, + : box.deliveryAddress.city, style: new TextStyle( fontSize: 14.0, color: Colors.grey), ), @@ -69,9 +69,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.state == null + box.deliveryAddress.state == null ? '' - : box.shippingAddress.state, + : box.deliveryAddress.state, style: new TextStyle( fontSize: 14.0, color: Colors.grey), ), @@ -79,9 +79,9 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.shippingAddress.phoneNumber == null + box.deliveryAddress.phoneNumber == null ? '' - : "Phone:${box.shippingAddress.phoneNumber}", + : "Phone:${box.deliveryAddress.phoneNumber}", style: new TextStyle( fontSize: 14.0, color: Colors.grey), ), @@ -99,25 +99,14 @@ class BoxRow extends StatelessWidget { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - "L${box.length}xW${box.weight}xH${box.height}", + "L${box.length}xW${box.width}xH${box.height}", style: new TextStyle(fontSize: 15.0, color: Colors.black), ), ), Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - box.weight == null - ? '' - : "Actual Weight:${box.weight.toString()}lb", - style: new TextStyle(fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - box.shipmentWeight == null - ? '' - : "Shipment Weight:${box.shipmentWeight.toString()}lb", + "Actual Weight:${box.actualWeight.toString()}lb", style: new TextStyle(fontSize: 14.0, color: Colors.grey), ), ), diff --git a/lib/pages/shipment/model/shipment_model.dart b/lib/pages/shipment/model/shipment_model.dart index 11117b2..9e59195 100644 --- a/lib/pages/shipment/model/shipment_model.dart +++ b/lib/pages/shipment/model/shipment_model.dart @@ -1,10 +1,11 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/data/services/services.dart'; import 'package:fcs/domain/constants.dart'; -import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/shipment.dart'; -import 'package:fcs/domain/vo/radio.dart'; +import 'package:fcs/domain/vo/message.dart'; +import 'package:fcs/helpers/paginator.dart'; import 'package:fcs/pages/main/model/base_model.dart'; import 'package:logging/logging.dart'; @@ -13,376 +14,145 @@ class ShipmentModel extends BaseModel { StreamSubscription listener; - List radioGroups1 = [ - RadioGroup( - text: "FCS Pickup", - index: 1, - ), - RadioGroup( - text: "Courier Pickup", - index: 2, - ), - RadioGroup( - text: "FCS Drop-off", - index: 3, - ), - RadioGroup( - text: "Courier Drop-off", - index: 4, - ), - ]; + List get shipments => _menuSelectedIndex == 1 + ? _shipments + : List.from(_delivered.values); - List pickupTypes = [ + List _shipments = []; + + Paginator _delivered; + bool isLoading = false; + int _menuSelectedIndex = 1; + + set menuSelectedIndex(int index) { + _menuSelectedIndex = index; + notifyListeners(); + } + + get menuSelectedIndex => _menuSelectedIndex; + + initData(bool forCustomer) { + logout(); + _menuSelectedIndex = 1; + _loadShipments(forCustomer); + _delivered = _getDeliveredExample(forCustomer); + _delivered.load(); + } + + @override + logout() async { + if (_delivered != null) _delivered.close(); + if (listener != null) await listener.cancel(); + _shipments = []; + } + + Future loadMore({bool isCustomer}) async { + if (menuSelectedIndex == 1) + return; // when delivered menu is not selected return + if (_delivered.ended) return; + isLoading = true; + notifyListeners(); + await _delivered.load(onFinished: () { + isLoading = false; + notifyListeners(); + }); + } + + Future refresh({bool isCustomer}) async { + if (menuSelectedIndex == 1) + return; // when delivered menu is not selected return + await _delivered.refresh(onFinished: () { + notifyListeners(); + }); + } + + Paginator _getDelivered(bool isCustomer) { + if (!isCustomer) { + if (user == null || + !((user.hasPackages() || + user.hasReceiving() || + user.hasProcessing()))) throw "No privilege"; + } + var pageQuery = Firestore.instance + .collection("/$packages_collection") + .where("is_delivered", isEqualTo: true) + .where("is_deleted", isEqualTo: false); + if (isCustomer) { + pageQuery = pageQuery.where("user_id", isEqualTo: user.id); + } + pageQuery = pageQuery.orderBy("current_status_date", descending: true); + var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { + return Shipment.fromMap(data, id); + }); + return paginator; + } + + int count = 0; + Paginator _getDeliveredExample(bool onlyFcs) { + count = 1; + var pageQuery = Firestore.instance + .collection( + "/users/8OTfsbVvsUOn1SLxy1OrKk7Y_yNKkVoGalPcIlcHnAY/messages") + .orderBy("date", descending: true); + var paginator = new Paginator(pageQuery, rowPerLoad: 20, toObj: (data, id) { + var m = Message.fromMap(data, id); + return Shipment( + id: m.id, + shipmentNumber: m.message, + currentStatus: m.senderName, + pickupDate: m.date, + ); + }); + return paginator; + } + + Future _loadShipments(bool forCustomer) async { + if (user == null) return; + if (!forCustomer && !user.hasShipment()) return; + String path = "/$shipments_collection"; + if (listener != null) listener.cancel(); + _shipments = []; + + try { + var q = Firestore.instance + .collection("$path") + .where("is_delivered", isEqualTo: false) + .where("is_deleted", isEqualTo: false); + + if (forCustomer) { + q = q.where("user_id", isEqualTo: user.id); + } + + listener = q.snapshots().listen((QuerySnapshot snapshot) { + _shipments.clear(); + _shipments = snapshot.documents.map((documentSnapshot) { + var s = Shipment.fromMap( + documentSnapshot.data, documentSnapshot.documentID); + return s; + }).toList(); + notifyListeners(); + }); + } catch (e) { + log.warning("Error!! $e"); + } + } + + List shipmentTypes = [ shipment_local_pickup, shipment_courier_pickup, shipment_local_dropoff, shipment_courier_dropoff ]; - List get radioGroups { - List radioGroups = [ - RadioGroup( - text: "Local Pickup", - index: 1, - ), - RadioGroup( - text: "Courier Pickup", - index: 2, - ), - RadioGroup( - text: "Local Drop-off", - index: 3, - ), - RadioGroup( - text: "Courier Drop-off", - index: 4, - ), - ]; - return radioGroups; - } - - List get pickups { - List pickups = [ - Shipment( - id: "S200412 - 12 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pending', - date: DateTime(2020, 5, 1), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - isCourier: true, - radioIndex: 2, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200125 - 12 May 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Confirmed', - date: DateTime(2020, 5, 6), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 13 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Pickuped", - date: DateTime(2020, 5, 9), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - radioIndex: 3, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200412 - 12 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pickuped', - date: DateTime(2020, 5, 15), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200125 - 12 May 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pickuped', - date: DateTime(2020, 5, 20), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 13 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Pickuped", - date: DateTime(2020, 5, 21), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 10 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Canceled", - date: DateTime(2020, 5, 25), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 6 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Canceled", - date: DateTime(2020, 5, 27), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - ]; - return pickups; - } - - List pickups1 = [ - Shipment( - id: "S200412 - 12 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pending', - date: DateTime(2020, 5, 1), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - isCourier: true, - radioIndex: 2, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200125 - 12 May 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Confirmed', - date: DateTime(2020, 5, 6), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 13 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Pickuped", - date: DateTime(2020, 5, 9), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - radioIndex: 3, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200412 - 12 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pickuped', - date: DateTime(2020, 5, 15), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200125 - 12 May 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: 'Pickuped', - date: DateTime(2020, 5, 20), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 13 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Pickuped", - date: DateTime(2020, 5, 21), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 10 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Canceled", - date: DateTime(2020, 5, 25), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - Shipment( - id: "S200441 - 6 Apr 2020", - userName: "Ko Kyaw Nyi", - phoneNumber: '+959111111111', - fromTime: '1PM', - toTime: '3PM', - numberOfPackage: 5, - weight: 25, - status: "Canceled", - date: DateTime(2020, 5, 27), - address: '154-19 64th Ave.\nFlushing, NY 11367', - handlingFee: 50, - cargoTypes: [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]), - ]; - - List get canceled { - List _p = pickups.where((e) => e.status == "Canceled").toList() - ..sort((e1, e2) { - return e2.date.compareTo(e1.date); - }); - return _p; - } - - List get completed { - return pickups.where((e) => e.status == "Pickuped").toList() - ..sort((e1, e2) { - return e2.date.compareTo(e1.date); - }); - } - - List get upcoming { - return pickups - .where((e) => - e.status == "Pending" || - e.status == "Confirmed" || - e.status == "Processed" || - e.status == "Rescheduled") - .toList() - ..sort((e1, e2) { - return e2.date.compareTo(e1.date); - }); - } - void initUser(user) { super.initUser(user); } - @override - logout() async { - if (listener != null) await listener.cancel(); - // pickups = []; + Future createShipment(Shipment shipment) { + return Services.instance.shipmentService.createShipment(shipment); + } + + Future updateShipment(Shipment shipment) { + return Services.instance.shipmentService.updateShipment(shipment); } } diff --git a/lib/pages/shipment/shipment_box_editor.dart b/lib/pages/shipment/shipment_box_editor.dart index 6b83b4c..1a4594c 100644 --- a/lib/pages/shipment/shipment_box_editor.dart +++ b/lib/pages/shipment/shipment_box_editor.dart @@ -4,9 +4,7 @@ import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/box/cargo_type_editor.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; -import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; import 'package:fcs/pages/widgets/delivery_address_selection.dart'; import 'package:fcs/pages/widgets/display_text.dart'; @@ -37,10 +35,8 @@ class _ShipmentBoxEditorState extends State { Box _box; bool _isLoading = false; bool _isNew; - DeliveryAddress _deliveryAddress; double volumetricRatio = 0; double shipmentWeight = 0; - List cargos = []; @override void initState() { @@ -52,22 +48,26 @@ class _ShipmentBoxEditorState extends State { if (widget.box != null) { _box = widget.box; - _deliveryAddress = _box.shippingAddress; _isNew = false; + _lengthCtl.text = _box.length.toString(); + _widthCtl.text = _box.width.toString(); + _heightCtl.text = _box.height.toString(); } else { var shipmentModel = Provider.of(context, listen: false); - _deliveryAddress = shipmentModel.defalutAddress; _isNew = true; - _box = Box(); - _lengthCtl.text = "0"; - _widthCtl.text = "0"; - _heightCtl.text = "0"; + _box = Box(cargoTypes: []); + _box.deliveryAddress = shipmentModel.defalutAddress; + + _lengthCtl.text = "12"; + _widthCtl.text = "12"; + _heightCtl.text = "12"; } _lengthCtl.addListener(_calShipmentWeight); _widthCtl.addListener(_calShipmentWeight); _heightCtl.addListener(_calShipmentWeight); + _calShipmentWeight(); } _calShipmentWeight() { @@ -75,7 +75,7 @@ class _ShipmentBoxEditorState extends State { double w = double.parse(_widthCtl.text, (s) => 0); double h = double.parse(_heightCtl.text, (s) => 0); setState(() { - shipmentWeight = l * w * h / volumetricRatio; + shipmentWeight = (l * w * h / volumetricRatio).ceilToDouble(); }); } @@ -113,6 +113,7 @@ class _ShipmentBoxEditorState extends State { ); final createBtn = LocalButton( textKey: "shipment.box.add", + callBack: _creatCarton, ); return LocalProgress( inAsyncCall: _isLoading, @@ -182,19 +183,19 @@ class _ShipmentBoxEditorState extends State { shipmentWeightBox, LocalTitle(textKey: "shipment.box.delivery"), DefaultDeliveryAddress( - deliveryAddress: _deliveryAddress, + deliveryAddress: _box.deliveryAddress, labelKey: "shipment.box.delivery", onTap: () async { DeliveryAddress d = await Navigator.push( context, CupertinoPageRoute( builder: (context) => DeliveryAddressSelection( - deliveryAddress: _deliveryAddress, + deliveryAddress: _box.deliveryAddress, )), ); if (d == null) return; setState(() { - this._deliveryAddress = d; + _box.deliveryAddress = d; }); }), createBtn @@ -206,11 +207,11 @@ class _ShipmentBoxEditorState extends State { } List getCargoRows(BuildContext context) { - if (cargos == null || cargos == null) { + if (_box.cargoTypes == null) { return []; } - int total = 0; - var rows = cargos.map((c) { + double total = 0; + var rows = _box.cargoTypes.map((c) { total += c.weight; return MyDataRow( onSelectChanged: (bool selected) async { @@ -258,7 +259,6 @@ class _ShipmentBoxEditorState extends State { color: Colors.black87, fontWeight: FontWeight.bold, ), - )), MyDataCell( Padding( @@ -278,14 +278,24 @@ class _ShipmentBoxEditorState extends State { _addCargo(CargoType cargo) { if (cargo == null) return; setState(() { - cargos.remove(cargo); - cargos.add(cargo); + _box.cargoTypes.remove(cargo); + _box.cargoTypes.add(cargo); }); } _removeCargo(CargoType cargo) { setState(() { - cargos.remove(cargo); + _box.cargoTypes.remove(cargo); }); } + + _creatCarton() { + double l = double.parse(_lengthCtl.text, (s) => 0); + double w = double.parse(_widthCtl.text, (s) => 0); + double h = double.parse(_heightCtl.text, (s) => 0); + _box.length = l; + _box.width = w; + _box.height = h; + Navigator.pop(context, _box); + } } diff --git a/lib/pages/shipment/shipment_editor.dart b/lib/pages/shipment/shipment_editor.dart index 9efd83e..c17eac9 100644 --- a/lib/pages/shipment/shipment_editor.dart +++ b/lib/pages/shipment/shipment_editor.dart @@ -1,14 +1,13 @@ import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/box.dart'; -import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/shipment.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/box/model/box_model.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/shipment/model/shipment_model.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; import 'package:fcs/pages/widgets/delivery_address_selection.dart'; import 'package:fcs/pages/widgets/display_text.dart'; @@ -21,7 +20,6 @@ import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_title.dart'; import 'package:fcs/pages/widgets/multi_img_controller.dart'; import 'package:fcs/pages/widgets/progress.dart'; -import 'package:fcs/pages/widgets/title_with_add_button.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; @@ -32,8 +30,6 @@ import 'package:provider/provider.dart'; import 'box_row.dart'; import 'shipment_box_editor.dart'; -enum SingingCharacter { lafayette, jefferson } - class ShipmentEditor extends StatefulWidget { final Shipment shipment; ShipmentEditor({this.shipment}); @@ -63,46 +59,42 @@ class _ShipmentEditorState extends State { TextEditingController _pickupDate = new TextEditingController(); TextEditingController _handlingFeeController = new TextEditingController(); - Shipment _pickUp; + Shipment _shipment; bool _isLoading = false; var now = new DateTime.now(); bool _isNew; - DeliveryAddress _pickupAddress = new DeliveryAddress(); int _currVal = 1; - String _selectedPickupType; + String _selectedShipmentType; @override void initState() { super.initState(); - _selectedPickupType = shipment_local_pickup; + _selectedShipmentType = shipment_local_pickup; if (widget.shipment != null) { _isNew = false; - _pickUp = widget.shipment; - _addressEditingController.text = _pickUp.address; - _fromTimeEditingController.text = _pickUp.fromTime; - _toTimeEditingController.text = _pickUp.toTime; - _noOfPackageEditingController.text = _pickUp.numberOfPackage.toString(); - _weightEditingController.text = _pickUp.weight.toString(); - _pickupDate.text = dateFormatter.format(now); - _handlingFeeController.text = numberFormatter.format(_pickUp.handlingFee); - _currVal = _pickUp.radioIndex; + _shipment = widget.shipment; + _addressEditingController.text = _shipment.address; + _fromTimeEditingController.text = _shipment.pickupTimeStart; + _toTimeEditingController.text = _shipment.pickupTimeEnd; + _noOfPackageEditingController.text = _shipment.numberOfPackage.toString(); + _weightEditingController.text = _shipment.weight.toString(); + _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now); + // _handlingFeeController.text = + // numberFormatter.format(_shipment.handlingFee); + _currVal = _shipment.radioIndex; } else { _isNew = true; _pickupDate.text = dateFormatter.format(now); _fromTimeEditingController.text = "${(now.hour)}:${(now.minute)}"; _toTimeEditingController.text = "${(now.hour)}:${(now.minute)}"; - List _cargoTypes = [ - CargoType(name: 'General Cargo', weight: 25), - CargoType(name: 'Medicine', weight: 20), - CargoType(name: 'Dangerous Cargo', weight: 30) - ]; - _pickUp = Shipment(cargoTypes: _cargoTypes); + _shipment = Shipment(boxes: []); + var shipmentModel = + Provider.of(context, listen: false); + _shipment.pickupAddress = shipmentModel.defalutAddress; + _pickupDate.text = dateFormatter.format(now); } - var shipmentModel = - Provider.of(context, listen: false); - _pickupAddress = shipmentModel.defalutAddress; } @override @@ -110,8 +102,6 @@ class _ShipmentEditorState extends State { super.dispose(); } - SingingCharacter _character = SingingCharacter.lafayette; - @override Widget build(BuildContext context) { MainModel mainModel = Provider.of(context); @@ -149,20 +139,20 @@ class _ShipmentEditorState extends State { backgroundColor: primaryColor, ); final pickupAddressBox = DefaultDeliveryAddress( - deliveryAddress: _pickupAddress, + deliveryAddress: _shipment.pickupAddress, iconData: Icons.location_on, labelKey: "shipment.location", onTap: () async { - DeliveryAddress d = await Navigator.push( + DeliveryAddress address = await Navigator.push( context, CupertinoPageRoute( builder: (context) => DeliveryAddressSelection( - deliveryAddress: _pickupAddress, + deliveryAddress: _shipment.pickupAddress, )), ); - if (d == null) return; + if (address == null) return; setState(() { - this._pickupAddress = d; + _shipment.pickupAddress = address; }); }, ); @@ -174,15 +164,16 @@ class _ShipmentEditorState extends State { var shipmentTypeBox = LocalDropdown( callback: (v) { setState(() { - _selectedPickupType = v; + _selectedShipmentType = v; }); }, iconData: SimpleLineIcons.direction, - selectedValue: _selectedPickupType, - values: pickupModel.pickupTypes, + selectedValue: _selectedShipmentType, + values: pickupModel.shipmentTypes, ); final createBtn = LocalButton( textKey: "shipment.create", + callBack: _create, ); final updateBtn = LocalButton( @@ -216,11 +207,11 @@ class _ShipmentEditorState extends State { children: [ LocalTitle(textKey: "shipment.type"), LocalRadioButtons( - values: pickupModel.pickupTypes, - selectedValue: _selectedPickupType, + values: pickupModel.shipmentTypes, + selectedValue: _selectedShipmentType, callback: (v) { setState(() { - _selectedPickupType = v; + _selectedShipmentType = v; }); }), // handlingFeeBox, @@ -240,17 +231,18 @@ class _ShipmentEditorState extends State { Icons.add_circle, color: primaryColor, ), - onPressed: () { - Navigator.push( + onPressed: () async { + Box box = await Navigator.push( context, CupertinoPageRoute( builder: (context) => ShipmentBoxEditor()), ); + _addBox(box); }, ), ), Column( - children: getBoxList(context, boxModel.boxes), + children: getBoxList(context, _shipment.boxes), ), _isNew ? createBtn : updateBtn, ], @@ -263,14 +255,67 @@ class _ShipmentEditorState extends State { List getBoxList(BuildContext context, List boxes) { return boxes.asMap().entries.map((_box) { return InkWell( - onTap: () { - Navigator.of(context).push(CupertinoPageRoute( + onTap: () async { + Box box = await Navigator.of(context).push(CupertinoPageRoute( builder: (context) => ShipmentBoxEditor(box: _box.value))); + _saveBox(box); }, - child: BoxRow(box: _box.value), + child: Row( + children: [ + Expanded(child: BoxRow(box: _box.value)), + InkWell( + onTap: () => _removeBox(_box.value), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon(Icons.remove, color: primaryColor), + ), + ), + ], + ), ); }).toList(); } - _addBox() {} + _addBox(Box box) { + if (box == null) return; + _shipment.boxes.add(box); + setState(() {}); + } + + _saveBox(Box box) { + if (box == null) return; + setState(() {}); + } + + _removeBox(Box box) { + if (box == null) return; + _shipment.boxes.remove(box); + setState(() {}); + } + + _create() async { + _shipment.shipmentType = this._selectedShipmentType; + _shipment.pickupDate = dateFormatter.parse(_pickupDate.text); + _shipment.pickupTimeStart = _fromTimeEditingController.text; + _shipment.pickupTimeEnd = _toTimeEditingController.text; + setState(() { + _isLoading = true; + }); + try { + ShipmentModel shipmentModel = + Provider.of(context, listen: false); + if (_isNew) { + await shipmentModel.createShipment(_shipment); + } else { + await shipmentModel.createShipment(_shipment); + } + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/shipment/shipment_info.dart b/lib/pages/shipment/shipment_info.dart new file mode 100644 index 0000000..c201d82 --- /dev/null +++ b/lib/pages/shipment/shipment_info.dart @@ -0,0 +1,248 @@ +import 'package:fcs/domain/constants.dart'; +import 'package:fcs/domain/entities/box.dart'; +import 'package:fcs/domain/entities/shipment.dart'; +import 'package:fcs/domain/vo/delivery_address.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/box/model/box_model.dart'; +import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/shipment/model/shipment_model.dart'; +import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; +import 'package:fcs/pages/widgets/delivery_address_selection.dart'; +import 'package:fcs/pages/widgets/display_text.dart'; +import 'package:fcs/pages/widgets/input_date.dart'; +import 'package:fcs/pages/widgets/input_time.dart'; +import 'package:fcs/pages/widgets/local_dropdown.dart'; +import 'package:fcs/pages/widgets/local_radio_buttons.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/local_title.dart'; +import 'package:fcs/pages/widgets/multi_img_controller.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +import 'box_row.dart'; + +class ShipmentInfo extends StatefulWidget { + final Shipment shipment; + ShipmentInfo({this.shipment}); + + @override + _ShipmentInfoState createState() => _ShipmentInfoState(); +} + +class _ShipmentInfoState extends State { + var dateFormatter = new DateFormat('dd MMM yyyy'); + final numberFormatter = new NumberFormat("#,###"); + MultiImgController multiImgController = MultiImgController(); + + TextEditingController _addressEditingController = new TextEditingController(); + TextEditingController _fromTimeEditingController = + new TextEditingController(); + TextEditingController _toTimeEditingController = new TextEditingController(); + TextEditingController _noOfPackageEditingController = + new TextEditingController(); + TextEditingController _weightEditingController = new TextEditingController(); + TextEditingController _recipientNameEditingController = + new TextEditingController(); + TextEditingController _recipientPhoneEditingController = + new TextEditingController(); + TextEditingController _recipientAddressEditingController = + new TextEditingController(); + TextEditingController _pickupDate = new TextEditingController(); + TextEditingController _handlingFeeController = new TextEditingController(); + + Shipment _shipment; + bool _isLoading = false; + var now = new DateTime.now(); + + int _currVal = 1; + String _selectedShipmentType; + + @override + void initState() { + super.initState(); + _selectedShipmentType = shipment_local_pickup; + _shipment = widget.shipment; + + if (widget.shipment != null) { + _addressEditingController.text = _shipment.address; + _fromTimeEditingController.text = _shipment.pickupTimeStart; + _toTimeEditingController.text = _shipment.pickupTimeEnd; + _noOfPackageEditingController.text = _shipment.numberOfPackage.toString(); + _weightEditingController.text = _shipment.weight.toString(); + _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now); + // _handlingFeeController.text = + // numberFormatter.format(_shipment.handlingFee); + _currVal = _shipment.radioIndex; + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + MainModel mainModel = Provider.of(context); + ShipmentModel pickupModel = Provider.of(context); + + final fromTimeBox = InputTime( + labelTextKey: 'shipment.from', + iconData: Icons.timer, + controller: _fromTimeEditingController); + + final toTimeBox = Container( + width: 150, + child: InputTime( + iconData: Icons.timer_off, + labelTextKey: 'shipment.to', + controller: _toTimeEditingController)); + + final pickupDateBox = InputDate( + labelTextKey: "shipment.date", + iconData: Icons.date_range, + controller: _pickupDate, + ); + final localDropoffAddress = DisplayText( + iconData: Icons.location_on, + labelTextKey: "Local Dropoff Address", + text: mainModel.setting.usaAddress); + final curierDropoffAddress = FloatingActionButton.extended( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + onPressed: () {}, + icon: Icon(Icons.arrow_right), + label: Text( + 'Visit courier websie for nearest drop-off', + style: TextStyle(fontSize: 12), + ), + backgroundColor: primaryColor, + ); + final pickupAddressBox = DefaultDeliveryAddress( + deliveryAddress: _shipment.pickupAddress, + iconData: Icons.location_on, + labelKey: "shipment.location", + onTap: () async { + DeliveryAddress address = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => DeliveryAddressSelection( + deliveryAddress: _shipment.pickupAddress, + )), + ); + if (address == null) return; + setState(() { + _shipment.pickupAddress = address; + }); + }, + ); + var boxModel = Provider.of(context); + var handlingFeeBox = DisplayText( + labelTextKey: "shipment.handling.fee", + text: "10", + iconData: FontAwesomeIcons.moneyBill); + var shipmentTypeBox = LocalDropdown( + callback: (v) { + setState(() { + _selectedShipmentType = v; + }); + }, + iconData: SimpleLineIcons.direction, + selectedValue: _selectedShipmentType, + values: pickupModel.shipmentTypes, + ); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon( + CupertinoIcons.back, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "shipment.info", + fontSize: 20, + color: primaryColor, + ), + actions: [ + IconButton( + icon: Icon(Icons.edit, color: primaryColor), + onPressed: _edit, + ) + ]), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( + children: [ + LocalTitle(textKey: "shipment.type"), + LocalRadioButtons( + values: pickupModel.shipmentTypes, + selectedValue: _selectedShipmentType, + callback: (v) { + setState(() { + _selectedShipmentType = v; + }); + }), + // handlingFeeBox, + // shipmentTypeBox, + LocalTitle(textKey: "shipment.location"), + pickupAddressBox, + LocalTitle(textKey: "shipment.date.time"), + pickupDateBox, + fromTimeBox, + toTimeBox, + // localDropoffAddress, + // curierDropoffAddress, + LocalTitle( + textKey: "boxes.name", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () async {}, + ), + ), + // Column( + // children: getBoxList(context, _shipment.boxes), + // ), + ], + ), + ), + ), + ); + } + + List getBoxList(BuildContext context, List boxes) { + return boxes.asMap().entries.map((_box) { + return InkWell( + onTap: () async {}, + child: Row( + children: [ + Expanded(child: BoxRow(box: _box.value)), + InkWell( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon(Icons.remove, color: primaryColor), + ), + ), + ], + ), + ); + }).toList(); + } + + _edit() {} +} diff --git a/lib/pages/shipment/shipment_list.dart b/lib/pages/shipment/shipment_list.dart index b254f55..018f36c 100644 --- a/lib/pages/shipment/shipment_list.dart +++ b/lib/pages/shipment/shipment_list.dart @@ -15,17 +15,28 @@ import 'shipment_editor.dart'; import 'shipment_list_row.dart'; class ShipmentList extends StatefulWidget { + final bool forCustomer; + + const ShipmentList({Key key, this.forCustomer = true}) : super(key: key); @override _ShipmentListState createState() => _ShipmentListState(); } class _ShipmentListState extends State { bool _isLoading = false; - bool _showDelivered = false; + var _controller = ScrollController(); @override void initState() { super.initState(); + _controller.addListener(() async { + if (_controller.position.pixels == _controller.position.maxScrollExtent) { + Provider.of(context, listen: false) + .loadMore(isCustomer: widget.forCustomer); + } + }); + + Provider.of(context, listen: false).initData(false); } @override @@ -35,7 +46,7 @@ class _ShipmentListState extends State { @override Widget build(BuildContext context) { - var pickupModel = Provider.of(context); + ShipmentModel shipmentModel = Provider.of(context); final popupMenu = LocalPopupMenuButton( popmenus: [ LocalPopupMenu( @@ -43,7 +54,7 @@ class _ShipmentListState extends State { LocalPopupMenu(id: 2, textKey: "shipment.popupmenu.delivered") ], popupMenuCallback: (p) => this.setState(() { - _showDelivered = p.id == 2; + shipmentModel.menuSelectedIndex = p.id; }), ); return LocalProgress( @@ -72,25 +83,53 @@ class _ShipmentListState extends State { popupMenu ], ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - _newPickup(); - }, - icon: Icon(Icons.add), - label: LocalText(context, "shipment.new", color: Colors.white), - backgroundColor: primaryColor, + floatingActionButton: shipmentModel.menuSelectedIndex == 1 + ? FloatingActionButton.extended( + onPressed: () { + _newPickup(); + }, + icon: Icon(Icons.add), + label: + LocalText(context, "shipment.new", color: Colors.white), + backgroundColor: primaryColor, + ) + : Container(), + body: Column( + children: [ + Expanded( + child: RefreshIndicator( + child: ListView.separated( + controller: _controller, + separatorBuilder: (context, index) => Divider( + color: Colors.black, + ), + scrollDirection: Axis.vertical, + padding: EdgeInsets.only(top: 15), + shrinkWrap: true, + itemCount: shipmentModel.shipments.length, + itemBuilder: (BuildContext context, int index) { + return ShipmentListRow( + pickUp: shipmentModel.shipments[index]); + }), + onRefresh: () => + shipmentModel.refresh(isCustomer: widget.forCustomer), + ), + ), + shipmentModel.isLoading + ? Container( + padding: EdgeInsets.all(8), + color: primaryColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Loading...", + style: TextStyle(color: Colors.white)), + ], + ), + ) + : Container(), + ], ), - body: new ListView.separated( - separatorBuilder: (context, index) => Divider( - color: Colors.black, - ), - scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), - shrinkWrap: true, - itemCount: pickupModel.pickups.length, - itemBuilder: (BuildContext context, int index) { - return ShipmentListRow(pickUp: pickupModel.pickups[index]); - }), ), ), ); diff --git a/lib/pages/shipment/shipment_list_row.dart b/lib/pages/shipment/shipment_list_row.dart index 89e7da9..df921a7 100644 --- a/lib/pages/shipment/shipment_list_row.dart +++ b/lib/pages/shipment/shipment_list_row.dart @@ -7,6 +7,7 @@ import 'package:flutter_icons/flutter_icons.dart'; import '../main/util.dart'; import 'shipment_editor.dart'; +import 'shipment_info.dart'; class ShipmentListRow extends StatefulWidget { final Shipment pickUp; @@ -36,13 +37,12 @@ class _ShipmentListRowState extends State { @override Widget build(BuildContext context) { - print('_pickup $_pickUp'); return Container( padding: EdgeInsets.only(left: 15, right: 15), child: InkWell( onTap: () { Navigator.of(context).push(CupertinoPageRoute( - builder: (context) => ShipmentEditor(shipment: _pickUp))); + builder: (context) => ShipmentInfo(shipment: _pickUp))); }, child: Row( children: [ @@ -64,7 +64,7 @@ class _ShipmentListRowState extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _pickUp.id == null ? '' : _pickUp.id, + _pickUp.shipmentNumber, style: new TextStyle( fontSize: 15.0, color: Colors.black), ), @@ -90,7 +90,7 @@ class _ShipmentListRowState extends State { children: [ Padding( padding: const EdgeInsets.all(0), - child: getStatus(_pickUp.status), + child: getStatus(_pickUp.currentStatus), ), Padding( padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), diff --git a/lib/pages/widgets/length_picker.dart b/lib/pages/widgets/length_picker.dart index 9721bef..ea11de6 100644 --- a/lib/pages/widgets/length_picker.dart +++ b/lib/pages/widgets/length_picker.dart @@ -32,9 +32,10 @@ class _LengthPickerState extends State { } _setText() { - int v = int.parse(widget.controller.text, onError: (s) => 0); - int f = (v / 12).round(); + double v = double.parse(widget.controller.text, (s) => 0); + int f = (v / 12).floor(); int ins = (v % 12).round(); + _controller.text = "$f' $ins\""; } @@ -81,8 +82,8 @@ class LengthPickerDialog extends StatefulWidget { } class _LengthPickerDialogState extends State { - double _valueFeet; - double _valueInc; + int _valueFeet; + int _valueInc; @override void initState() { super.initState(); @@ -90,8 +91,8 @@ class _LengthPickerDialogState extends State { _valueInc = 0; if (widget.controller != null) { double v = double.parse(widget.controller.text, (s) => 0); - _valueFeet = v / 12; - _valueInc = v % 12; + _valueFeet = (v / 12).floor(); + _valueInc = (v % 12).toInt(); } } @@ -106,7 +107,7 @@ class _LengthPickerDialogState extends State { fontSize: 16, )), children: [ - Center(child: Text(_getText(_valueFeet))), + Center(child: Text(_getText())), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -121,7 +122,7 @@ class _LengthPickerDialogState extends State { ), Slider( activeColor: primaryColor, - value: _valueFeet, + value: _valueFeet.toDouble(), min: 0, max: 15, divisions: 100, @@ -146,7 +147,7 @@ class _LengthPickerDialogState extends State { ), Slider( activeColor: primaryColor, - value: _valueInc, + value: _valueInc.toDouble(), min: 0, max: 11, divisions: 100, @@ -163,7 +164,7 @@ class _LengthPickerDialogState extends State { _updateFeet(double v) { setState(() { - _valueFeet = v; + _valueFeet = v.toInt(); }); if (widget.controller != null) { int _v = _valueInc.round() + _valueFeet.round() * 12; @@ -173,7 +174,7 @@ class _LengthPickerDialogState extends State { _updateInc(double v) { setState(() { - _valueInc = v; + _valueInc = v.toInt(); }); if (widget.controller != null) { int _v = _valueInc.round() + _valueFeet.round() * 12; @@ -181,7 +182,7 @@ class _LengthPickerDialogState extends State { } } - String _getText(double v) { + String _getText() { int ft = _valueFeet.round(); int ins = _valueInc.round(); return "$ft\' $ins\"";