diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index fe04696..048fa1e 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -11,6 +11,8 @@ "btn.select":"Select", "btn.cancel":"Cancel", "btn.ok": "Ok", + "btn.continue":"Continue", + "btn.previous":"Previous", "feet":"Feet", "inch":"Inch", "back.button_confirm":"Are you sure you want to continue without submitting changes?", @@ -306,6 +308,20 @@ "box.weight":"Weight", "box.mix_carton.update.btn":"Update mix carton", "box.cargo.select.btn":"Select", + "box.select.carton_type":"Select carton type", + "box.select.sender_and_consignee":"Select sender and consignee", + "box.cartion.count":"Cartons ({0})", + "box.sender.title":"Sender", + "box.consignee.title":"Consignee", + "box.bill_to_sender":"Bill to sender", + "box.bill_to.consignee":"Bill to consignee", + "box.done.btn":"Done", + "box.select_carton_size":"Select the carton size", + "box.select_shipment":"Select the shipment", + "box.shipment":"Shipment", + "box.standard_carton_size":"Standard carton size", + "box.custom_size":"Custom size", + "box.package_size":"Package", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 2371d47..c239fa6 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -10,6 +10,8 @@ "btn.select":"ရွေးချယ်ပါ", "btn.cancel":"မလုပ်နဲ့", "btn.ok": "အိုကေ", + "btn.continue":"ဆက်ရန်", + "btn.previous":"နောက်သို့", "feet":"ပေ", "inch":"လက်မ", "back.button_confirm":"Are you sure you want to continue without submitting changes?", @@ -305,6 +307,20 @@ "box.weight":"အလေးချိန်", "box.mix_carton.update.btn":"Update mix carton", "box.cargo.select.btn":"ရွေးချယ်မည်", + "box.select.carton_type":"Select carton type", + "box.select.sender_and_consignee":"Select sender and consignee", + "box.cartion.count":"Cartons ({0})", + "box.sender.title":"ပေးပို့သူ", + "box.consignee.title":"လက်ခံသူ", + "box.bill_to_sender":"ပေးပို့သူထံ ငွေတောင်းခံရန်", + "box.bill_to.consignee":"လက်ခံသူထံ ငွေတောင်းခံရန်", + "box.done.btn":"Done", + "box.select_carton_size":"Select the carton size", + "box.select_shipment":"Select the shipment", + "box.shipment":"Shipment", + "box.standard_carton_size":"Standard carton size", + "box.custom_size":"Custom size", + "box.package_size":"Package", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index a9ab54e..cb8b980 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -87,10 +87,11 @@ const shipment_local_dropoff = "Local drop off"; const shipment_courier_dropoff = "Courier drop off"; //Carton types -const carton_from_packages = "From packages"; +const carton_from_packages = "Carton for packages"; +const carton_mix_carton = "Mix carton"; + const carton_from_cartons = "From cartons"; const carton_from_shipments = "From shipments"; -const carton_mix_carton = "Mix carton"; const carton_small_bag = "Small bag"; const carton_mix_box = "Mix box"; diff --git a/lib/domain/entities/carton.dart b/lib/domain/entities/carton.dart index 7feb6fe..fdbac78 100644 --- a/lib/domain/entities/carton.dart +++ b/lib/domain/entities/carton.dart @@ -36,7 +36,7 @@ class Carton { String? mixCartonNumber; String? cartonSizeID; String? cartonSizeName; - double? cartonWeight; + double cartonWeight; int rate; int weight; @@ -158,7 +158,7 @@ class Carton { this.mixBoxType, this.mixCartons = const [], this.mixCartonIDs = const [], - this.cartonWeight}); + this.cartonWeight =0}); Map toMap() { List _cargoTypes = cargoTypes.map((c) => c.toMap()).toList(); diff --git a/lib/domain/vo/local_step.dart b/lib/domain/vo/local_step.dart new file mode 100644 index 0000000..232cf31 --- /dev/null +++ b/lib/domain/vo/local_step.dart @@ -0,0 +1,7 @@ +enum StepType { TYPE, CARTONS, SIZE, PACKAGES, CARGOS, SUBMIT } + +class LocalStep { + String lable; + StepType stepType; + LocalStep({required this.lable, required this.stepType}); +} diff --git a/lib/pages/carton/carton_editor copy.dart b/lib/pages/carton/carton_editor copy.dart new file mode 100644 index 0000000..8c3f5b2 --- /dev/null +++ b/lib/pages/carton/carton_editor copy.dart @@ -0,0 +1,976 @@ +import 'package:fcs/domain/constants.dart'; +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/domain/entities/carton_size.dart'; +import 'package:fcs/domain/entities/fcs_shipment.dart'; +import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/domain/entities/user.dart'; +import 'package:fcs/domain/vo/delivery_address.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/carton/carton_package_table.dart'; +import 'package:fcs/pages/carton_search/carton_search.dart'; +import 'package:fcs/pages/carton_size/carton_size_list.dart'; +import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/package/model/package_model.dart'; +import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; +import 'package:fcs/pages/user_search/user_serach.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/fcs_id_icon.dart'; +import 'package:fcs/pages/widgets/length_picker.dart'; +import 'package:fcs/pages/widgets/local_app_bar.dart'; +import 'package:fcs/pages/widgets/local_button.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/progress.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:provider/provider.dart'; +import 'cargo_type_addtion.dart'; +import 'carton_cargo_table.dart'; +import 'carton_row.dart'; +import 'model/carton_model.dart'; +import '../carton_size/model/carton_size_model.dart'; +import 'package_carton_editor.dart'; +import 'widgets.dart'; + +class CartonEditor extends StatefulWidget { + final Carton? carton; + CartonEditor({this.carton}); + + @override + _CartonEditorState createState() => _CartonEditorState(); +} + +class _CartonEditorState extends State { + TextEditingController _widthController = new TextEditingController(); + TextEditingController _heightController = new TextEditingController(); + TextEditingController _lengthController = new TextEditingController(); + DeliveryAddress? _deliveryAddress = new DeliveryAddress(); + List _cargoTypes = []; + + Carton? _carton; + bool _isLoading = false; + bool _isNew = false; + User? _user; + String? _selectedCartonType; + + double volumetricRatio = 0; + double shipmentWeight = 0; + FcsShipment? _fcsShipment; + List _fcsShipments = []; + List _cartons = []; + CartonSize? selectedCatonSize; + + //for mix carton + List _mixCartons = []; + String? _selectedMixBoxType; + + //for carton from cargos + User? consignee; + User? sender; + List _cartonsFromCartons = []; + + double? totalWeight; + + @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); + + if (widget.carton != null) { + _carton = widget.carton; + _deliveryAddress = _carton!.deliveryAddress; + _widthController.text = _carton!.width.toString(); + _heightController.text = _carton!.height.toString(); + _lengthController.text = _carton!.length.toString(); + _selectedCartonType = _carton!.cartonType; + + _cargoTypes = _carton!.cargoTypes.map((e) => e.clone()).toList(); + + _isNew = false; + _user = User( + id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); + consignee = User( + id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); + sender = User( + id: _carton!.senderID, + fcsID: _carton!.senderFCSID, + name: _carton!.senderName); + _selectedMixBoxType = _carton!.mixBoxType; + this._mixCartons = + // ignore: unnecessary_null_comparison + _carton!.mixCartons == null ? [] : List.from(_carton!.mixCartons); + bool isMixBox = _carton!.cartonType == carton_mix_box; + bool isFromPackages = _carton!.cartonType == carton_from_packages; + if (isFromPackages) _loadPackages(); + + if (!isMixBox) { + _getCartonSize(); + } + } else { + _carton = Carton( + cargoTypes: [], + packages: [], + ); + _lengthController.text = "0"; + _widthController.text = "0"; + _heightController.text = "0"; + _isNew = true; + _selectedCartonType = carton_from_packages; + _selectedMixBoxType = mix_delivery; + _loadFcsShipments(); + } + } + + _loadFcsShipments() async { + FcsShipmentModel fcsShipmentModel = + Provider.of(context, listen: false); + var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); + + // var fcsShipment = + // fcsShipments.firstWhere((e) => e.id == _carton?.fcsShipmentID); + + setState(() { + _fcsShipments = fcsShipments; + // _fcsShipment = fcsShipment; + }); + } + + _loadPackages() async { + if (_user == null) return; + PackageModel packageModel = + Provider.of(context, listen: false); + List packages = await packageModel.getPackages( + _user!.id!, [package_processed_status, package_packed_status]); + if (_isNew) { + String? prevCompare; + packages.forEach((p) { + String compare = (p.deliveryAddress?.fullName ?? "") + + (p.deliveryAddress?.phoneNumber ?? ""); + if (prevCompare != null && compare == prevCompare) { + p.isChecked = true; + } else { + p.isChecked = false; + } + if (prevCompare == null) { + p.isChecked = true; + prevCompare = compare; + } + }); + } else { + packages.forEach((p) { + if (_carton!.packages.contains(p)) { + p.isChecked = _carton!.packages.firstWhere((cp) => cp == p).isChecked; + } else { + p.isChecked = false; + } + }); + } + + setState(() { + _carton!.packages = packages; + }); + // _populateDeliveryAddress(); + } + + // _populateDeliveryAddress() { + // if (_carton.packages == null) return; + // var d = _carton.packages + // .firstWhere((p) => p.isChecked && p.deliveryAddress != null, + // orElse: () => null) + // ?.deliveryAddress; + // setState(() { + // _deliveryAddress = d; + // }); + // } + + _calShipmentWeight() { + double l = double.tryParse(_lengthController.text) ?? 0; + double w = double.tryParse(_widthController.text) ?? 0; + double h = double.tryParse(_heightController.text) ?? 0; + setState(() { + shipmentWeight = l * w * h / volumetricRatio; + }); + } + + _getCartonSize() { + var cartonSizeModel = Provider.of(context, listen: false); + cartonSizeModel.cartonSizes.forEach((c) { + if (c.length == _carton!.length && + c.width == _carton!.width && + c.height == _carton!.height) { + selectedCatonSize = CartonSize( + id: c.id, + name: c.name, + length: c.length, + width: c.width, + height: c.height); + } + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + var boxModel = Provider.of(context); + bool isFromPackages = _selectedCartonType == carton_from_packages; + bool isFromCartons = _selectedCartonType == carton_from_cartons; + bool isMixBox = _selectedCartonType == carton_mix_box; + + final shipmentBox = DisplayText( + text: _carton!.fcsShipmentNumber, + labelTextKey: "box.fcs_shipment_num", + iconData: Ionicons.ios_airplane, + ); + + var fcsShipmentsBox = Container( + padding: EdgeInsets.only(top: 10), + child: LocalDropdown( + callback: (v) { + setState(() { + _fcsShipment = v; + }); + }, + labelKey: "shipment.pack.fcs.shipment", + iconData: Ionicons.ios_airplane, + display: (u) => u.shipmentNumber, + selectedValue: _fcsShipment, + values: _fcsShipments, + )); + + final fcsIDBox = Container( + padding: EdgeInsets.only(top: 15), + child: Row( + children: [ + Expanded( + child: DisplayText( + text: _user?.fcsID ?? "", + labelTextKey: "box.fcs.id", + icon: FcsIDIcon(), + )), + _isNew + ? IconButton( + icon: Icon(Icons.search, color: primaryColor), + onPressed: () => searchUser(context, onUserSelect: (u) { + setState(() { + this._user = u; + _loadPackages(); + }); + }, popPage: true)) + : Container(), + ], + )); + + final namebox = DisplayText( + text: _user?.name ?? "", + labelTextKey: "box.name", + iconData: Icons.person, + ); + + final createBtn = LocalButton( + textKey: "box.complete.packaging", + callBack: () { + Navigator.pop(context); + }, + ); + + final saveBtn = LocalButton( + textKey: "box.cargo.save.btn", + callBack: _save, + ); + + final cartonTypeBox = LocalRadioButtons( + readOnly: !_isNew, + values: boxModel.cartonTypes, + selectedValue: _selectedCartonType, + callback: (String? v) { + setState(() { + _selectedCartonType = v; + }); + }); + + final cartonTitleBox = Container( + child: LocalTitle( + textKey: "boxes.title", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: _addCarton), + ), + ); + + final mixTypeBox = Container( + padding: EdgeInsets.only(top: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(left: 5), + child: LocalText( + context, + "box.mix_type", + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.bold, + )), + Row( + children: boxModel.mixBoxTypes.map((e) { + return Row( + children: [ + Radio( + value: e, + groupValue: _selectedMixBoxType, + activeColor: primaryColor, + onChanged: (String? v) { + setState(() { + _selectedMixBoxType = v; + }); + }, + ), + Text(e), + ], + ); + }).toList(), + ), + ], + ), + ); + + final mixTypeDisplayBox = Container( + padding: EdgeInsets.only(top: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(left: 5), + child: LocalText( + context, + "box.mix_type", + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.bold, + )), + Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + Icons.check, + color: primaryColor, + ), + ), + Text(_selectedMixBoxType ?? "") + ], + ) + ], + ), + ); + + final mixcartonTitleBox = Container( + child: LocalTitle( + textKey: "box.mix_caton_title", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () async { + boxModel.selectedIndexFilter = 1; + searchCarton(context, callbackCartonSelect: (c) { + _addMixCarton(c); + }); + }, + ), + ), + ); + final cargoTableTitleBox = LocalTitle( + textKey: "box.cargo.type", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () async { + List? cargos = await Navigator.push>( + context, + CupertinoPageRoute(builder: (context) => CargoTypeAddition())); + if (cargos == null) return; + setState(() { + _cargoTypes.addAll( + cargos.where((e) => !_cargoTypes.contains(e)).toList()); + }); + }), + ); + + final cargoTableBox = CargoTable( + isNew: _isNew, + cargoTypes: _cargoTypes, + onRemove: (c) => _removeCargo(c), + onUpdate: (c) => _updateCargo(c), + ); + + final lengthBox = LengthPicker( + controller: _lengthController, + lableKey: "box.length", + isReadOnly: false, + ); + final widthBox = LengthPicker( + controller: _widthController, + lableKey: "box.width", + isReadOnly: false, + ); + final heightBox = LengthPicker( + controller: _heightController, + lableKey: "box.height", + isReadOnly: false, + ); + final dimBox = Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Icon(FontAwesome.arrow_circle_right, color: primaryColor), + ), + SizedBox(child: lengthBox, width: 80), + SizedBox(child: widthBox, width: 80), + SizedBox(child: heightBox, width: 80), + ], + ); + + final createMixCarton = LocalButton( + textKey: _isNew ? "box.mix_carton_btn" : "box.mix_carton.update.btn", + callBack: _creatMixCarton, + ); + + final consigneefcsIDBox = Row( + children: [ + Expanded( + child: DisplayText( + text: consignee != null ? consignee!.fcsID : "", + labelTextKey: "processing.fcs.id", + icon: FcsIDIcon(), + )), + IconButton( + icon: Icon(Icons.search, color: primaryColor), + onPressed: () => searchUser(context, onUserSelect: (u) { + setState(() { + this.consignee = u; + }); + }, popPage: true)), + ], + ); + + final consigneeNameBox = DisplayText( + text: consignee != null ? consignee!.name : "", + labelTextKey: "processing.consignee.name", + maxLines: 2, + iconData: Icons.person, + ); + + final consigneeBox = Container( + child: Column( + children: [ + consigneefcsIDBox, + consigneeNameBox, + ], + ), + ); + + final shipperIDBox = Row( + children: [ + Expanded( + child: DisplayText( + text: sender != null ? sender!.fcsID : "", + labelTextKey: "processing.fcs.id", + icon: FcsIDIcon(), + )), + IconButton( + icon: Icon(Icons.search, color: primaryColor), + onPressed: () => searchUser(context, onUserSelect: (u) { + setState(() { + this.sender = u; + }); + }, popPage: true)), + ], + ); + + final shipperNamebox = DisplayText( + text: sender != null ? sender!.name : "", + labelTextKey: "processing.shipper.name", + maxLines: 2, + iconData: Icons.person, + ); + + final shipperBox = Container( + child: Column( + children: [ + shipperIDBox, + shipperNamebox, + ], + ), + ); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: LocalAppBar( + labelKey: _isNew ? "boxes.new" : "box.edit.title", + backgroundColor: Colors.white, + arrowColor: primaryColor, + labelColor: primaryColor), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView( + shrinkWrap: true, + children: [ + _isNew + ? Container() + : Center(child: getCartonNumberStatus(context, _carton!)), + LocalTitle(textKey: "box.type.title"), + cartonTypeBox, + LocalTitle(textKey: "box.shipment_info"), + _isNew ? fcsShipmentsBox : shipmentBox, + isMixBox + ? _isNew + ? mixTypeBox + : mixTypeDisplayBox + : Container(), + ...(isMixBox + ? [ + mixcartonTitleBox, + Column( + children: _getMixCartons(context, this._mixCartons)), + ] + : [ + isFromPackages ? fcsIDBox : Container(), + isFromPackages ? namebox : Container(), + isFromPackages + ? CartonPackageTable( + packages: _carton!.packages, + onSelect: (p, checked) { + // if (checked && + // _deliveryAddress != null && + // p.deliveryAddress?.id != + // _deliveryAddress.id) { + // return; + // } + setState(() { + p.isChecked = checked; + }); + // _populateDeliveryAddress(); + }, + ) + : Container(), + isFromCartons + ? Container( + padding: const EdgeInsets.only(top: 15), + child: Row( + children: [ + Flexible(child: consigneeBox), + Flexible(child: shipperBox) + ], + ), + ) + : Container(), + _isNew ? cartonTitleBox : Container(), + _isNew + ? Column( + children: _getCartons( + context, + isFromPackages + ? this._cartons + : this._cartonsFromCartons)) + : Container(), + _isNew ? Container() : cargoTableTitleBox, + _isNew ? Container() : cargoTableBox, + _isNew + ? Container() + : LocalTitle(textKey: "box.dimension"), + _isNew ? Container() : cartonSizeDropdown(), + _isNew ? Container() : dimBox, + _isNew + ? Container() + : LocalTitle(textKey: "box.delivery_address"), + _isNew + ? Container() + : DefaultDeliveryAddress( + deliveryAddress: _deliveryAddress, + labelKey: "box.delivery_address", + onTap: () async { + DeliveryAddress? d = + await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => + DeliveryAddressSelection( + deliveryAddress: _deliveryAddress, + user: User( + id: _carton!.userID, + name: _carton!.userName))), + ); + if (d == null) return; + setState(() { + _deliveryAddress = d; + }); + }), + ]), + SizedBox( + height: 20, + ), + isFromPackages || isFromCartons + ? _isNew + ? createBtn + : saveBtn + : Container(), + isMixBox ? createMixCarton : Container(), + SizedBox( + height: 20, + ), + ], + ), + ), + ), + ); + } + + List _getCartons(BuildContext context, List cartons) { + return cartons.asMap().entries.map((c) { + return InkWell( + onTap: () async { + bool isFromPackages = _selectedCartonType == carton_from_packages; + + if (isFromPackages) { + _loadPackages(); + c.value.packages = _carton!.packages; + Carton? _c = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => PackageCartonEditor( + carton: c.value, + isNew: false, + consignee: _user, + )), + ); + if (_c == null) return; + cartons.removeWhere((item) => item.id == _c.id); + cartons.insert(c.key, _c); + setState(() {}); + } + }, + child: CartonRow( + key: ValueKey(c.value.id), + box: c.value, + ), + ); + }).toList(); + } + + List _getMixCartons(BuildContext context, List cartons) { + return cartons.map((c) { + return CartonRow( + key: ValueKey(c.id), + box: c, + ); + }).toList(); + } + + Widget cartonSizeDropdown() { + List _cartonSizes = + Provider.of(context).getCartonSizes; + + return Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 0, right: 10), + child: Icon(AntDesign.CodeSandbox, color: primaryColor), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 18.0), + child: LocalText( + context, + "box.carton_size", + color: Colors.black54, + fontSize: 16, + ), + ), + DropdownButton( + isDense: true, + value: selectedCatonSize, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container( + height: 1, + color: Colors.grey, + ), + onChanged: (CartonSize? newValue) { + setState(() { + if (newValue!.name == MANAGE_CARTONSIZE) { + selectedCatonSize = null; + _manageCartonSize(); + return; + } + selectedCatonSize = newValue; + _widthController.text = + selectedCatonSize!.width.toString(); + _heightController.text = + selectedCatonSize!.height.toString(); + _lengthController.text = + selectedCatonSize!.length.toString(); + }); + }, + isExpanded: true, + items: _cartonSizes + .map>((CartonSize value) { + return DropdownMenuItem( + value: value, + child: Text(value.name ?? "", + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: value.name == MANAGE_CARTONSIZE + ? secondaryColor + : primaryColor)), + ); + }).toList(), + ), + ], + ), + ), + ], + ), + ); + } + + _manageCartonSize() { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => CartonSizeList()), + ); + } + + _removeCargo(CargoType cargo) { + setState(() { + _cargoTypes.remove(cargo); + }); + } + + _updateCargo(CargoType cargo) { + setState(() { + var _c = _cargoTypes.firstWhere((e) => e.id == cargo.id); + _c.weight = cargo.weight; + _c.qty = cargo.qty; + }); + } + + _addCarton() async { + bool isFromPackages = _selectedCartonType == carton_from_packages; + bool isFromCartons = _selectedCartonType == carton_from_cartons; + + if (_fcsShipment == null && _isNew) { + showMsgDialog(context, "Error", "Please select FCS shipment"); + return; + } + + if (_user == null && isFromPackages) { + showMsgDialog(context, "Error", "Please select FCS ID"); + return; + } + + if (consignee == null && isFromCartons) { + showMsgDialog(context, "Error", "Please select consignee's FCS ID"); + return; + } + + if (sender == null && isFromCartons) { + showMsgDialog(context, "Error", "Please select sender's FCS ID"); + return; + } + + double l = double.parse(_lengthController.text); + double w = double.parse(_widthController.text); + double h = double.parse(_heightController.text); + + Carton carton = Carton(); + carton.id = _carton!.id; + carton.cartonType = _selectedCartonType!; + carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; + if (isFromPackages) { + carton.userID = _user?.id ?? ''; + carton.fcsID = _user?.fcsID ?? ''; + carton.userName = _user?.name ?? ''; + carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); + } + + if (isFromCartons) { + carton.userID = consignee?.id ?? ""; + carton.fcsID = consignee?.fcsID ?? ""; + carton.userName = consignee?.name ?? ""; + carton.senderID = sender?.id ?? ""; + carton.senderFCSID = sender?.fcsID ?? ""; + carton.senderName = sender?.name ?? ""; + } + + carton.cargoTypes = _carton!.cargoTypes; + carton.length = l; + carton.width = w; + carton.height = h; + carton.deliveryAddress = _carton!.deliveryAddress; + + try { + Carton? _c = await Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => PackageCartonEditor( + carton: carton, + isNew: _isNew, + consignee: _user, + )), + ); + if (_c == null) return; + var cartonModel = Provider.of(context, listen: false); + Carton _carton = await cartonModel.getCarton(_c.id ?? ""); + if (isFromPackages) { + _cartons.add(_carton); + } + + if (isFromCartons) { + _cartonsFromCartons.add(_carton); + } + + setState(() {}); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } + } + + _addMixCarton(Carton carton) { + if (this._mixCartons.any((c) => c.id == carton.id)) return; + setState(() { + this._mixCartons.add(carton); + }); + } + + _removeMixCarton(Carton carton) { + setState(() { + this._mixCartons.removeWhere((c) => c.id == carton.id); + }); + } + + _creatMixCarton() async { + if (_fcsShipment == null && _isNew) { + showMsgDialog(context, "Error", "Please select FCS shipment"); + return; + } + if (this._mixCartons.length == 0) { + showMsgDialog(context, "Error", "Expect at least one carton"); + return; + } + Carton carton = Carton(); + carton.id = _carton!.id; + carton.cartonType = _selectedCartonType!; + carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; + carton.mixBoxType = _selectedMixBoxType!; + carton.mixCartons = this._mixCartons; + setState(() { + _isLoading = true; + }); + try { + CartonModel cartonModel = + Provider.of(context, listen: false); + if (_isNew) { + await cartonModel.createCarton(carton); + } else { + await cartonModel.updateCarton(carton); + } + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } + + _save() async { + bool isFromPackages = _selectedCartonType == carton_from_packages; + bool isFromCartons = _selectedCartonType == carton_from_cartons; + if (_cargoTypes.length == 0 && (isFromPackages || isFromCartons)) { + showMsgDialog(context, "Error", "Expect at least one cargo type"); + return; + } + if (_cargoTypes.where((c) => c.weight <= 0).isNotEmpty) { + showMsgDialog(context, "Error", "Invalid cargo weight"); + return; + } + double l = double.parse(_lengthController.text); + double w = double.parse(_widthController.text); + double h = double.parse(_heightController.text); + if ((l <= 0 || w <= 0 || h <= 0) && (isFromPackages || isFromCartons)) { + showMsgDialog(context, "Error", "Invalid dimension"); + return; + } + if (_deliveryAddress == null && (isFromPackages || isFromCartons)) { + showMsgDialog(context, "Error", "Invalid delivery address"); + return; + } + + Carton carton = Carton(); + carton.id = _carton!.id; + carton.cartonType = _selectedCartonType!; + carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; + if (isFromPackages) { + carton.userID = _user?.id ?? ""; + carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); + } + if (isFromCartons) { + carton.userID = consignee?.id ?? ""; + carton.senderID = sender?.id ?? ""; + } + + carton.cargoTypes = _cargoTypes; + carton.length = l; + carton.width = w; + carton.height = h; + carton.deliveryAddress = _deliveryAddress; + + setState(() { + _isLoading = true; + }); + try { + CartonModel cartonModel = + Provider.of(context, listen: false); + await cartonModel.updateCarton(carton); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/carton/carton_editor.dart b/lib/pages/carton/carton_editor.dart index 94ca1a6..6d18031 100644 --- a/lib/pages/carton/carton_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -1,28 +1,11 @@ import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; -import 'package:fcs/domain/entities/cargo_type.dart'; -import 'package:fcs/domain/entities/carton_size.dart'; -import 'package:fcs/domain/entities/fcs_shipment.dart'; -import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/entities/user.dart'; -import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/carton/carton_package_table.dart'; -import 'package:fcs/pages/carton_search/carton_search.dart'; -import 'package:fcs/pages/carton_size/carton_size_list.dart'; -import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; -import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; import 'package:fcs/pages/user_search/user_serach.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/fcs_id_icon.dart'; -import 'package:fcs/pages/widgets/length_picker.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; -import 'package:fcs/pages/widgets/local_button.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'; @@ -30,14 +13,8 @@ import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; -import 'package:provider/provider.dart'; -import 'cargo_type_addtion.dart'; -import 'carton_cargo_table.dart'; +import 'mix_cation/mix_cartion_editor.dart'; import 'carton_row.dart'; -import 'model/carton_model.dart'; -import '../carton_size/model/carton_size_model.dart'; -import 'package_carton_editor.dart'; -import 'widgets.dart'; class CartonEditor extends StatefulWidget { final Carton? carton; @@ -48,257 +25,88 @@ class CartonEditor extends StatefulWidget { } class _CartonEditorState extends State { - TextEditingController _widthController = new TextEditingController(); - TextEditingController _heightController = new TextEditingController(); - TextEditingController _lengthController = new TextEditingController(); - DeliveryAddress? _deliveryAddress = new DeliveryAddress(); - List _cargoTypes = []; + List cartonTypes = [carton_from_packages, carton_mix_carton]; + List _cartons = []; - Carton? _carton; bool _isLoading = false; bool _isNew = false; - User? _user; + int _billToValue = 1; String? _selectedCartonType; - double volumetricRatio = 0; - double shipmentWeight = 0; - FcsShipment? _fcsShipment; - List _fcsShipments = []; - List _cartons = []; - CartonSize? selectedCatonSize; - - //for mix carton - List _mixCartons = []; - String? _selectedMixBoxType; - - //for carton from cargos User? consignee; User? sender; - List _cartonsFromCartons = []; - - double? totalWeight; + Carton? _carton; @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); - if (widget.carton != null) { _carton = widget.carton; - _deliveryAddress = _carton!.deliveryAddress; - _widthController.text = _carton!.width.toString(); - _heightController.text = _carton!.height.toString(); - _lengthController.text = _carton!.length.toString(); _selectedCartonType = _carton!.cartonType; - _cargoTypes = _carton!.cargoTypes.map((e) => e.clone()).toList(); - _isNew = false; - _user = User( - id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); + consignee = User( id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); sender = User( id: _carton!.senderID, fcsID: _carton!.senderFCSID, name: _carton!.senderName); - _selectedMixBoxType = _carton!.mixBoxType; - this._mixCartons = - // ignore: unnecessary_null_comparison - _carton!.mixCartons == null ? [] : List.from(_carton!.mixCartons); - bool isMixBox = _carton!.cartonType == carton_mix_box; - bool isFromPackages = _carton!.cartonType == carton_from_packages; - if (isFromPackages) _loadPackages(); - - if (!isMixBox) { - _getCartonSize(); - } } else { - _carton = Carton( - cargoTypes: [], - packages: [], - ); - _lengthController.text = "0"; - _widthController.text = "0"; - _heightController.text = "0"; + _carton = Carton(cargoTypes: [], packages: []); _isNew = true; _selectedCartonType = carton_from_packages; - _selectedMixBoxType = mix_delivery; - _loadFcsShipments(); + _cartons = [ + Carton(cartonNumber: "A177(A)-3#2", cartonWeight: 35.5), + Carton(cartonNumber: "A177(A)-3#1", cartonWeight: 25.5) + ]; } } - _loadFcsShipments() async { - FcsShipmentModel fcsShipmentModel = - Provider.of(context, listen: false); - var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); - - // var fcsShipment = - // fcsShipments.firstWhere((e) => e.id == _carton?.fcsShipmentID); - - setState(() { - _fcsShipments = fcsShipments; - // _fcsShipment = fcsShipment; - }); - } - - _loadPackages() async { - if (_user == null) return; - PackageModel packageModel = - Provider.of(context, listen: false); - List packages = await packageModel.getPackages( - _user!.id!, [package_processed_status, package_packed_status]); - if (_isNew) { - String? prevCompare; - packages.forEach((p) { - String compare = (p.deliveryAddress?.fullName ?? "") + - (p.deliveryAddress?.phoneNumber ?? ""); - if (prevCompare != null && compare == prevCompare) { - p.isChecked = true; - } else { - p.isChecked = false; - } - if (prevCompare == null) { - p.isChecked = true; - prevCompare = compare; - } - }); - } else { - packages.forEach((p) { - if (_carton!.packages.contains(p)) { - p.isChecked = _carton!.packages.firstWhere((cp) => cp == p).isChecked; - } else { - p.isChecked = false; - } - }); - } - - setState(() { - _carton!.packages = packages; - }); - // _populateDeliveryAddress(); - } - - // _populateDeliveryAddress() { - // if (_carton.packages == null) return; - // var d = _carton.packages - // .firstWhere((p) => p.isChecked && p.deliveryAddress != null, - // orElse: () => null) - // ?.deliveryAddress; - // setState(() { - // _deliveryAddress = d; - // }); - // } - - _calShipmentWeight() { - double l = double.tryParse(_lengthController.text) ?? 0; - double w = double.tryParse(_widthController.text) ?? 0; - double h = double.tryParse(_heightController.text) ?? 0; - setState(() { - shipmentWeight = l * w * h / volumetricRatio; - }); - } - - _getCartonSize() { - var cartonSizeModel = Provider.of(context, listen: false); - cartonSizeModel.cartonSizes.forEach((c) { - if (c.length == _carton!.length && - c.width == _carton!.width && - c.height == _carton!.height) { - selectedCatonSize = CartonSize( - id: c.id, - name: c.name, - length: c.length, - width: c.width, - height: c.height); - } - }); - } - - @override - void dispose() { - super.dispose(); - } - @override Widget build(BuildContext context) { - var boxModel = Provider.of(context); bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - bool isMixBox = _selectedCartonType == carton_mix_box; - final shipmentBox = DisplayText( - text: _carton!.fcsShipmentNumber, - labelTextKey: "box.fcs_shipment_num", - iconData: Ionicons.ios_airplane, - ); - - var fcsShipmentsBox = Container( - padding: EdgeInsets.only(top: 10), - child: LocalDropdown( - callback: (v) { - setState(() { - _fcsShipment = v; - }); - }, - labelKey: "shipment.pack.fcs.shipment", - iconData: Ionicons.ios_airplane, - display: (u) => u.shipmentNumber, - selectedValue: _fcsShipment, - values: _fcsShipments, - )); - - final fcsIDBox = Container( - padding: EdgeInsets.only(top: 15), - child: Row( - children: [ - Expanded( - child: DisplayText( - text: _user?.fcsID ?? "", - labelTextKey: "box.fcs.id", - icon: FcsIDIcon(), + final createBtn = Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Container( + alignment: Alignment.bottomRight, + height: 45, + width: 130, + decoration: BoxDecoration( + color: primaryColor, + borderRadius: BorderRadius.circular(5), + ), + child: TextButton( + onPressed: null, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: LocalText(context, 'box.done.btn', + color: Colors.white, fontSize: 15), + ), + const SizedBox(width: 5), + const Icon( + MaterialCommunityIcons.check_circle_outline, + color: Colors.white, + ), + ], + ), + ), )), - _isNew - ? IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () => searchUser(context, onUserSelect: (u) { - setState(() { - this._user = u; - _loadPackages(); - }); - }, popPage: true)) - : Container(), - ], - )); - - final namebox = DisplayText( - text: _user?.name ?? "", - labelTextKey: "box.name", - iconData: Icons.person, - ); - - final createBtn = LocalButton( - textKey: "box.complete.packaging", - callBack: () { - Navigator.pop(context); - }, - ); - - final saveBtn = LocalButton( - textKey: "box.cargo.save.btn", - callBack: _save, + ], ); final cartonTypeBox = LocalRadioButtons( readOnly: !_isNew, - values: boxModel.cartonTypes, + values: cartonTypes, selectedValue: _selectedCartonType, callback: (String? v) { setState(() { @@ -306,171 +114,43 @@ class _CartonEditorState extends State { }); }); - final cartonTitleBox = Container( - child: LocalTitle( - textKey: "boxes.title", - trailing: IconButton( - icon: Icon( + final cartonTitleBox = LocalTitle( + textKey: _cartons.isEmpty ? "box.shipment.boxes" : "box.cartion.count", + translationVariables: _cartons.isEmpty ? null : ["${_cartons.length}"], + trailing: Padding( + padding: const EdgeInsets.only(right: 5), + child: InkResponse( + radius: 30, + onTap: () { + //for packages + if (isFromPackages) { + + } + // for mix cartion + else { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => const MixCartonEditor())); + } + }, + child: Icon( Icons.add_circle, color: primaryColor, ), - onPressed: _addCarton), - ), - ); - - final mixTypeBox = Container( - padding: EdgeInsets.only(top: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.only(left: 5), - child: LocalText( - context, - "box.mix_type", - color: primaryColor, - fontSize: 15, - fontWeight: FontWeight.bold, - )), - Row( - children: boxModel.mixBoxTypes.map((e) { - return Row( - children: [ - Radio( - value: e, - groupValue: _selectedMixBoxType, - activeColor: primaryColor, - onChanged: (String? v) { - setState(() { - _selectedMixBoxType = v; - }); - }, - ), - Text(e), - ], - ); - }).toList(), ), - ], - ), - ); + )); - final mixTypeDisplayBox = Container( - padding: EdgeInsets.only(top: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.only(left: 5), - child: LocalText( - context, - "box.mix_type", - color: primaryColor, - fontSize: 15, - fontWeight: FontWeight.bold, - )), - Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.check, - color: primaryColor, - ), - ), - Text(_selectedMixBoxType ?? "") - ], - ) - ], - ), - ); - - final mixcartonTitleBox = Container( - child: LocalTitle( - textKey: "box.mix_caton_title", - trailing: IconButton( - icon: Icon( - Icons.add_circle, - color: primaryColor, - ), - onPressed: () async { - boxModel.selectedIndexFilter = 1; - searchCarton(context, callbackCartonSelect: (c) { - _addMixCarton(c); - }); - }, - ), - ), - ); - final cargoTableTitleBox = LocalTitle( - textKey: "box.cargo.type", - trailing: IconButton( - icon: Icon( - Icons.add_circle, - color: primaryColor, - ), - onPressed: () async { - List? cargos = await Navigator.push>( - context, - CupertinoPageRoute(builder: (context) => CargoTypeAddition())); - if (cargos == null) return; - setState(() { - _cargoTypes.addAll( - cargos.where((e) => !_cargoTypes.contains(e)).toList()); - }); - }), - ); - - final cargoTableBox = CargoTable( - isNew: _isNew, - cargoTypes: _cargoTypes, - onRemove: (c) => _removeCargo(c), - onUpdate: (c) => _updateCargo(c), - ); - - final lengthBox = LengthPicker( - controller: _lengthController, - lableKey: "box.length", - isReadOnly: false, - ); - final widthBox = LengthPicker( - controller: _widthController, - lableKey: "box.width", - isReadOnly: false, - ); - final heightBox = LengthPicker( - controller: _heightController, - lableKey: "box.height", - isReadOnly: false, - ); - final dimBox = Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Icon(FontAwesome.arrow_circle_right, color: primaryColor), - ), - SizedBox(child: lengthBox, width: 80), - SizedBox(child: widthBox, width: 80), - SizedBox(child: heightBox, width: 80), - ], - ); - - final createMixCarton = LocalButton( - textKey: _isNew ? "box.mix_carton_btn" : "box.mix_carton.update.btn", - callBack: _creatMixCarton, - ); - - final consigneefcsIDBox = Row( + final consigneeSearchBox = Row( children: [ - Expanded( - child: DisplayText( - text: consignee != null ? consignee!.fcsID : "", - labelTextKey: "processing.fcs.id", - icon: FcsIDIcon(), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 2), + child: LocalText(context, "box.consignee.title", + color: Colors.black, fontSize: 15), )), IconButton( - icon: Icon(Icons.search, color: primaryColor), + icon: Icon(Icons.search, color: Colors.black), onPressed: () => searchUser(context, onUserSelect: (u) { setState(() { this.consignee = u; @@ -479,32 +159,44 @@ class _CartonEditorState extends State { ], ); - final consigneeNameBox = DisplayText( - text: consignee != null ? consignee!.name : "", - labelTextKey: "processing.consignee.name", - maxLines: 2, - iconData: Icons.person, + final consigneefcsIDBox = DisplayText( + text: consignee != null ? consignee!.fcsID : "", + labelTextKey: "processing.fcs.id", + icon: FcsIDIcon(), ); + final consigneePhoneBox = DisplayText( + text: consignee != null ? consignee!.phoneNumber : "", + labelTextKey: "processing.phone", + iconData: MaterialCommunityIcons.phone); + + final consigneeNameBox = DisplayText( + text: consignee != null ? consignee!.name : "", + labelTextKey: "processing.consignee.name", + maxLines: 2, + iconData: MaterialCommunityIcons.account_arrow_left); + final consigneeBox = Container( child: Column( children: [ + consigneeSearchBox, consigneefcsIDBox, - consigneeNameBox, + consigneePhoneBox, + consigneeNameBox ], ), ); - final shipperIDBox = Row( + final senderSearchBox = Row( children: [ - Expanded( - child: DisplayText( - text: sender != null ? sender!.fcsID : "", - labelTextKey: "processing.fcs.id", - icon: FcsIDIcon(), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 2), + child: LocalText(context, "box.sender.title", + color: Colors.black, fontSize: 15), )), IconButton( - icon: Icon(Icons.search, color: primaryColor), + icon: Icon(Icons.search, color: Colors.black), onPressed: () => searchUser(context, onUserSelect: (u) { setState(() { this.sender = u; @@ -513,18 +205,100 @@ class _CartonEditorState extends State { ], ); - final shipperNamebox = DisplayText( - text: sender != null ? sender!.name : "", - labelTextKey: "processing.shipper.name", - maxLines: 2, - iconData: Icons.person, + final senderIDBox = DisplayText( + text: sender != null ? sender!.fcsID : "", + labelTextKey: "processing.fcs.id", + icon: FcsIDIcon()); + + final senderPhoneBox = DisplayText( + text: sender != null ? sender!.phoneNumber : "", + labelTextKey: "processing.phone", + iconData: MaterialCommunityIcons.phone, ); - final shipperBox = Container( + final senderNameBox = DisplayText( + text: sender != null ? sender!.name : "", + labelTextKey: "processing.shipper.name", + maxLines: 2, + iconData: MaterialCommunityIcons.account_arrow_right); + + final senderBox = Container( child: Column( children: [ - shipperIDBox, - shipperNamebox, + senderSearchBox, + senderIDBox, + senderPhoneBox, + senderNameBox, + ], + ), + ); + + final billRadioBox = Container( + child: Row( + children: [ + Flexible( + child: InkWell( + onTap: () { + setState(() { + _billToValue = 1; + }); + }, + child: Row(children: [ + Radio( + visualDensity: const VisualDensity( + horizontal: VisualDensity.minimumDensity), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeColor: primaryColor, + groupValue: _billToValue, + value: 1, + onChanged: (value) { + setState(() { + _billToValue = 1; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.bill_to_sender', + fontSize: 14, + color: _billToValue == 1 ? primaryColor : Colors.black), + ), + ) + ]), + )), + Flexible( + child: InkWell( + onTap: () { + setState(() { + _billToValue = 2; + }); + }, + child: Row(children: [ + Radio( + visualDensity: const VisualDensity( + horizontal: VisualDensity.minimumDensity), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeColor: primaryColor, + groupValue: _billToValue, + value: 2, + onChanged: (value) { + setState(() { + _billToValue = 2; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.bill_to.consignee', + fontSize: 14, + color: _billToValue == 2 ? primaryColor : Colors.black), + ), + ) + ]), + ), + ) ], ), ); @@ -533,120 +307,36 @@ class _CartonEditorState extends State { inAsyncCall: _isLoading, child: Scaffold( appBar: LocalAppBar( - labelKey: _isNew ? "box.info.title" : "box.edit.title", + labelKey: _isNew ? "boxes.new" : "box.edit.title", backgroundColor: Colors.white, arrowColor: primaryColor, labelColor: primaryColor), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - shrinkWrap: true, - children: [ - _isNew - ? Container() - : Center(child: getCartonNumberStatus(context, _carton!)), - LocalTitle(textKey: "box.type.title"), - cartonTypeBox, - LocalTitle(textKey: "box.shipment_info"), - _isNew ? fcsShipmentsBox : shipmentBox, - isMixBox - ? _isNew - ? mixTypeBox - : mixTypeDisplayBox - : Container(), - ...(isMixBox - ? [ - mixcartonTitleBox, - Column( - children: _getMixCartons(context, this._mixCartons)), - ] - : [ - isFromPackages ? fcsIDBox : Container(), - isFromPackages ? namebox : Container(), - isFromPackages - ? CartonPackageTable( - packages: _carton!.packages, - onSelect: (p, checked) { - // if (checked && - // _deliveryAddress != null && - // p.deliveryAddress?.id != - // _deliveryAddress.id) { - // return; - // } - setState(() { - p.isChecked = checked; - }); - // _populateDeliveryAddress(); - }, - ) - : Container(), - isFromCartons - ? Container( - padding: const EdgeInsets.only(top: 15), - child: Row( - children: [ - Flexible(child: consigneeBox), - Flexible(child: shipperBox) - ], - ), - ) - : Container(), - _isNew ? cartonTitleBox : Container(), - _isNew - ? Column( - children: _getCartons( - context, - isFromPackages - ? this._cartons - : this._cartonsFromCartons)) - : Container(), - _isNew ? Container() : cargoTableTitleBox, - _isNew ? Container() : cargoTableBox, - _isNew - ? Container() - : LocalTitle(textKey: "box.dimension"), - _isNew ? Container() : cartonSizeDropdown(), - _isNew ? Container() : dimBox, - _isNew - ? Container() - : LocalTitle(textKey: "box.delivery_address"), - _isNew - ? Container() - : DefaultDeliveryAddress( - deliveryAddress: _deliveryAddress, - labelKey: "box.delivery_address", - onTap: () async { - DeliveryAddress? d = - await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - DeliveryAddressSelection( - deliveryAddress: _deliveryAddress, - user: User( - id: _carton!.userID, - name: _carton!.userName))), - ); - if (d == null) return; - setState(() { - _deliveryAddress = d; - }); - }), - ]), - SizedBox( - height: 20, - ), - isFromPackages || isFromCartons - ? _isNew - ? createBtn - : saveBtn - : Container(), - isMixBox ? createMixCarton : Container(), - SizedBox( - height: 20, - ), - ], - ), + body: ListView( + padding: EdgeInsets.only(left: 10, right: 10), + shrinkWrap: true, + children: [ + LocalTitle(textKey: "box.select.carton_type"), + cartonTypeBox, + isFromPackages + ? Column( + children: [ + LocalTitle(textKey: "box.select.sender_and_consignee"), + Row( + children: [ + Flexible(child: senderBox), + Flexible(child: consigneeBox) + ], + ), + billRadioBox + ], + ) + : Container(), + cartonTitleBox, + Column(children: _getCartons(context, _cartons)), + SizedBox(height: 20), + createBtn, + SizedBox(height: 20), + ], ), ), ); @@ -654,326 +344,7 @@ class _CartonEditorState extends State { List _getCartons(BuildContext context, List cartons) { return cartons.asMap().entries.map((c) { - return InkWell( - onTap: () async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - - if (isFromPackages) { - _loadPackages(); - c.value.packages = _carton!.packages; - Carton? _c = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => PackageCartonEditor( - carton: c.value, - isNew: false, - consignee: _user, - )), - ); - if (_c == null) return; - cartons.removeWhere((item) => item.id == _c.id); - cartons.insert(c.key, _c); - setState(() {}); - } - }, - child: CartonRow( - key: ValueKey(c.value.id), - box: c.value, - ), - ); + return InkWell(onTap: () async {}, child: CartonRow(box: c.value)); }).toList(); } - - List _getMixCartons(BuildContext context, List cartons) { - return cartons.map((c) { - return CartonRow( - key: ValueKey(c.id), - box: c, - onRemove: (carton) { - _removeMixCarton(carton); - }, - ); - }).toList(); - } - - Widget cartonSizeDropdown() { - List _cartonSizes = - Provider.of(context).getCartonSizes; - - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(left: 0, right: 10), - child: Icon(AntDesign.CodeSandbox, color: primaryColor), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(right: 18.0), - child: LocalText( - context, - "box.carton_size", - color: Colors.black54, - fontSize: 16, - ), - ), - DropdownButton( - isDense: true, - value: selectedCatonSize, - style: TextStyle(color: Colors.black, fontSize: 14), - underline: Container( - height: 1, - color: Colors.grey, - ), - onChanged: (CartonSize? newValue) { - setState(() { - if (newValue!.name == MANAGE_CARTONSIZE) { - selectedCatonSize = null; - _manageCartonSize(); - return; - } - selectedCatonSize = newValue; - _widthController.text = - selectedCatonSize!.width.toString(); - _heightController.text = - selectedCatonSize!.height.toString(); - _lengthController.text = - selectedCatonSize!.length.toString(); - }); - }, - isExpanded: true, - items: _cartonSizes - .map>((CartonSize value) { - return DropdownMenuItem( - value: value, - child: Text(value.name ?? "", - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: value.name == MANAGE_CARTONSIZE - ? secondaryColor - : primaryColor)), - ); - }).toList(), - ), - ], - ), - ), - ], - ), - ); - } - - _manageCartonSize() { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => CartonSizeList()), - ); - } - - _removeCargo(CargoType cargo) { - setState(() { - _cargoTypes.remove(cargo); - }); - } - - _updateCargo(CargoType cargo) { - setState(() { - var _c = _cargoTypes.firstWhere((e) => e.id == cargo.id); - _c.weight = cargo.weight; - _c.qty = cargo.qty; - }); - } - - _addCarton() async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - - if (_fcsShipment == null && _isNew) { - showMsgDialog(context, "Error", "Please select FCS shipment"); - return; - } - - if (_user == null && isFromPackages) { - showMsgDialog(context, "Error", "Please select FCS ID"); - return; - } - - if (consignee == null && isFromCartons) { - showMsgDialog(context, "Error", "Please select consignee's FCS ID"); - return; - } - - if (sender == null && isFromCartons) { - showMsgDialog(context, "Error", "Please select sender's FCS ID"); - return; - } - - double l = double.parse(_lengthController.text); - double w = double.parse(_widthController.text); - double h = double.parse(_heightController.text); - - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - if (isFromPackages) { - carton.userID = _user?.id ?? ''; - carton.fcsID = _user?.fcsID ?? ''; - carton.userName = _user?.name ?? ''; - carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); - } - - if (isFromCartons) { - carton.userID = consignee?.id ?? ""; - carton.fcsID = consignee?.fcsID ?? ""; - carton.userName = consignee?.name ?? ""; - carton.senderID = sender?.id ?? ""; - carton.senderFCSID = sender?.fcsID ?? ""; - carton.senderName = sender?.name ?? ""; - } - - carton.cargoTypes = _carton!.cargoTypes; - carton.length = l; - carton.width = w; - carton.height = h; - carton.deliveryAddress = _carton!.deliveryAddress; - - try { - Carton? _c = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => PackageCartonEditor( - carton: carton, - isNew: _isNew, - consignee: _user, - )), - ); - if (_c == null) return; - var cartonModel = Provider.of(context, listen: false); - Carton _carton = await cartonModel.getCarton(_c.id ?? ""); - if (isFromPackages) { - _cartons.add(_carton); - } - - if (isFromCartons) { - _cartonsFromCartons.add(_carton); - } - - setState(() {}); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } - } - - _addMixCarton(Carton carton) { - if (this._mixCartons.any((c) => c.id == carton.id)) return; - setState(() { - this._mixCartons.add(carton); - }); - } - - _removeMixCarton(Carton carton) { - setState(() { - this._mixCartons.removeWhere((c) => c.id == carton.id); - }); - } - - _creatMixCarton() async { - if (_fcsShipment == null && _isNew) { - showMsgDialog(context, "Error", "Please select FCS shipment"); - return; - } - if (this._mixCartons.length == 0) { - showMsgDialog(context, "Error", "Expect at least one carton"); - return; - } - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - carton.mixBoxType = _selectedMixBoxType!; - carton.mixCartons = this._mixCartons; - setState(() { - _isLoading = true; - }); - try { - CartonModel cartonModel = - Provider.of(context, listen: false); - if (_isNew) { - await cartonModel.createCarton(carton); - } else { - await cartonModel.updateCarton(carton); - } - Navigator.pop(context, true); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } - - _save() async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - if (_cargoTypes.length == 0 && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Expect at least one cargo type"); - return; - } - if (_cargoTypes.where((c) => c.weight <= 0).isNotEmpty) { - showMsgDialog(context, "Error", "Invalid cargo weight"); - return; - } - double l = double.parse(_lengthController.text); - double w = double.parse(_widthController.text); - double h = double.parse(_heightController.text); - if ((l <= 0 || w <= 0 || h <= 0) && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Invalid dimension"); - return; - } - if (_deliveryAddress == null && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Invalid delivery address"); - return; - } - - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - if (isFromPackages) { - carton.userID = _user?.id ?? ""; - carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); - } - if (isFromCartons) { - carton.userID = consignee?.id ?? ""; - carton.senderID = sender?.id ?? ""; - } - - carton.cargoTypes = _cargoTypes; - carton.length = l; - carton.width = w; - carton.height = h; - carton.deliveryAddress = _deliveryAddress; - - setState(() { - _isLoading = true; - }); - try { - CartonModel cartonModel = - Provider.of(context, listen: false); - await cartonModel.updateCarton(carton); - Navigator.pop(context, true); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } } diff --git a/lib/pages/carton/carton_list_row.dart b/lib/pages/carton/carton_list_row.dart index 788fdff..b587c7a 100644 --- a/lib/pages/carton/carton_list_row.dart +++ b/lib/pages/carton/carton_list_row.dart @@ -1,6 +1,5 @@ import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/main/util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; @@ -29,11 +28,11 @@ class CartonListRow extends StatelessWidget { children: [ Expanded( child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 13.0), + padding: const EdgeInsets.symmetric(vertical: 8.0), child: new Row( children: [ Container( - padding: EdgeInsets.only(left: 5, right: 10), + padding: EdgeInsets.only(left: 5), child: Icon( MaterialCommunityIcons.package, color: primaryColor, @@ -41,26 +40,33 @@ class CartonListRow extends StatelessWidget { ), ), new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - box.cartonNumber ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.black), + child: Padding( + padding: const EdgeInsets.only(left: 18.0), + child: Row( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + box.cartonNumber ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + ), + Padding( + padding: const EdgeInsets.only(top: 5), + child: new Text( + box.userName ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ), + ], ), - ), - Padding( - padding: const EdgeInsets.only(left: 10.0, top: 10), - child: new Text( - box.userName ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.grey), - ), - ) - ], + const SizedBox(width: 15), + IconButton( + onPressed: () {}, icon: Icon(AntDesign.qrcode)) + ], + ), ), ), ], @@ -68,17 +74,19 @@ class CartonListRow extends StatelessWidget { ), ), Column( + crossAxisAlignment: CrossAxisAlignment.end, children: [ + Text(box.status ?? "", + style: TextStyle( + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.bold)), Padding( - padding: const EdgeInsets.all(0), - child: getStatus(box.status ?? ""), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), + padding: const EdgeInsets.only(top: 5), child: Row( children: [ new Text( - "${box.cartonWeight?.toStringAsFixed(2)} lb", + "${box.cartonWeight.toStringAsFixed(2)} lb", style: new TextStyle(fontSize: 15.0, color: Colors.grey), ), diff --git a/lib/pages/carton/carton_row.dart b/lib/pages/carton/carton_row.dart index 13d18e1..1d4bc69 100644 --- a/lib/pages/carton/carton_row.dart +++ b/lib/pages/carton/carton_row.dart @@ -1,15 +1,11 @@ import 'package:fcs/domain/entities/carton.dart'; -import 'package:fcs/helpers/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:intl/intl.dart'; -typedef OnRemove(Carton carton); - class CartonRow extends StatelessWidget { final Carton box; - final OnRemove? onRemove; - CartonRow({Key? key, required this.box, this.onRemove}) : super(key: key); + CartonRow({Key? key, required this.box}) : super(key: key); final double dotSize = 15.0; final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); @@ -18,68 +14,34 @@ class CartonRow extends StatelessWidget { Widget build(BuildContext context) { return Container( decoration: BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.grey.shade300), - ), + border: Border(bottom: BorderSide(color: Colors.grey.shade300)), ), child: Row( children: [ Expanded( child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 13.0), + padding: const EdgeInsets.symmetric(vertical: 5.0), child: new Row( children: [ - Container( - padding: EdgeInsets.only(left: 5, right: 10), - child: Icon(MaterialCommunityIcons.package, - color: primaryColor, size: 30)), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - box.cartonNumber ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.black), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 10.0, top: 10), - child: new Text( - box.userName ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.grey), - ), - ) - ], - ), - ), + new Text(box.cartonNumber ?? "", + style: + new TextStyle(fontSize: 15.0, color: Colors.black)), + const SizedBox(width: 15), + IconButton(onPressed: () {}, icon: Icon(AntDesign.qrcode)), ], ), ), ), Column( children: [ - onRemove == null - ? Container() - : IconButton( - icon: Icon( - Icons.remove_circle, - color: primaryColor, - ), - onPressed: () { - if (onRemove != null) onRemove!(box); - }), - box.actualWeight == 0 + box.cartonWeight == 0 ? Container() : Padding( padding: const EdgeInsets.only(left: 8.0, bottom: 5), child: Row( children: [ new Text( - "${box.actualWeight.toStringAsFixed(2)} lb", + "${box.cartonWeight.toStringAsFixed(2)} lb", style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), diff --git a/lib/pages/carton/mix_cation/mix_cartion_editor.dart b/lib/pages/carton/mix_cation/mix_cartion_editor.dart new file mode 100644 index 0000000..a9eff22 --- /dev/null +++ b/lib/pages/carton/mix_cation/mix_cartion_editor.dart @@ -0,0 +1,178 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +import '../../../domain/vo/local_step.dart'; +import '../../../helpers/theme.dart'; +import '../../widgets/local_text.dart'; +import '../../widgets/progress.dart'; +import '../../widgets/step_widget.dart'; +import 'type_widget.dart'; + +class MixCartonEditor extends StatefulWidget { + const MixCartonEditor({ + Key? key, + }) : super(key: key); + + @override + State createState() => _MixCartonEditorState(); +} + +class _MixCartonEditorState extends State { + var dateFormatter = DateFormat('dd MMM yyyy'); + final NumberFormat numberFormatter = NumberFormat("#,###"); + List steps = [ + LocalStep(lable: 'Type', stepType: StepType.TYPE), + LocalStep(lable: 'Cartons', stepType: StepType.CARTONS), + LocalStep(lable: 'Submit', stepType: StepType.SUBMIT) + ]; + + bool _isLoading = false; + int currentStep = 0; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () { + if (currentStep == 0) { + Navigator.of(context).pop(); + } + if (currentStep > 0) { + setState(() { + currentStep -= 1; + }); + } + + return Future.value(false); + }, + child: LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + elevation: 0, + centerTitle: true, + leading: IconButton( + icon: const Icon(CupertinoIcons.back, + color: primaryColor, size: 25), + onPressed: () { + if (currentStep == 0) { + Navigator.of(context).pop(); + } + if (currentStep > 0) { + setState(() { + currentStep -= 1; + }); + } + }, + ), + backgroundColor: Colors.white, + title: LocalText(context, 'boxes.new', + color: primaryColor, fontSize: 20), + ), + body: Column( + children: [ + StepperWidget( + labels: steps.map((e) => e.lable).toList(), + currentStep: currentStep, + eachStepWidth: 120, + onChange: (index) { + if (index > currentStep) { + return; + } + setState(() { + currentStep = index; + }); + }, + ), + getContent(currentStep) + ], + ))), + ); + } + + Widget getContent(int index) { + var step = steps[index]; + if (step.stepType == StepType.TYPE) { + return Expanded(child: TypeWidget( + onPrevious: () { + Navigator.pop(context); + }, + // warehouse: _warehouse, + // onSelectWarehouse: (w) { + // setState(() { + // _warehouse = w; + // currentStep += 1; + // }); + // }, + )); + } else if (step.stepType == StepType.CARTONS) { + return Expanded( + child: Text("cartons"), + // child: StockAdjustmentProducts( + // products: products, + // onAdd: (ps) { + // setState(() { + // products = List.from(ps); + // }); + // }, + // onRemove: (p) { + // setState(() { + // products.removeWhere((e) => e.id == p.id); + // }); + // }, + // onRemoveAll: (ps) { + // for (var e in ps) { + // setState(() { + // products.removeWhere((p) => p.id == e.id); + // }); + // } + // }, + // onContinue: (ps) { + // if (products.isEmpty) { + // showMsgDialog(context, 'Error', "Please select product"); + // return false; + // } + // setState(() { + // products = List.from(ps); + // currentStep += 1; + // }); + // }, + // onPrevious: (ps) { + // setState(() { + // products = List.from(ps); + // currentStep -= 1; + // }); + // }, + // ), + ); + } else { + return Expanded( + child: Text("Submit"), + // child: StockAdjustmentSubmit( + // warehouse: _warehouse?.name, + // products: products, + // onCreate: () { + // if (user != null && user.hasInventoryCreate()) { + // showConfirmDialog(context, 'stock_adjustment_confirm', _create); + // } else { + // showDialog( + // context: context, + // builder: (BuildContext context) => const AuthorizedDialog( + // uiFunction: funcInventoriesCreate)); + // } + // }, + // onPrevious: () { + // setState(() { + // currentStep -= 1; + // }); + // }, + // ), + ); + } + } +} diff --git a/lib/pages/carton/mix_cation/type_widget.dart b/lib/pages/carton/mix_cation/type_widget.dart new file mode 100644 index 0000000..4095ddc --- /dev/null +++ b/lib/pages/carton/mix_cation/type_widget.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; +import 'package:provider/provider.dart'; +import '../../../domain/entities/fcs_shipment.dart'; +import '../../../helpers/theme.dart'; +import '../../fcs_shipment/model/fcs_shipment_model.dart'; +import '../../main/util.dart'; +import '../../widgets/continue_button.dart'; +import '../../widgets/local_dropdown.dart'; +import '../../widgets/local_text.dart'; +import '../../widgets/local_title.dart'; +import '../../widgets/previous_button.dart'; + +typedef OnPrevious = Function(); + +class TypeWidget extends StatefulWidget { + final OnPrevious? onPrevious; + final bool isTransferFrom; + final bool isTransferTo; + const TypeWidget( + {Key? key, + this.onPrevious, + this.isTransferFrom = false, + this.isTransferTo = false}) + : super(key: key); + + @override + State createState() => _TypeWidgetState(); +} + +class _TypeWidgetState extends State { + FcsShipment? _shipment; + List shipments = []; + List standardSizeList = [ + 'Large - 20”x20”x20”', + 'Medium - 15”x15”x15”', + 'Small - 10”x10”x10”' + ]; + int _cartinSizeValue = 1; + late String selectedValue; + + @override + void initState() { + _init(); + super.initState(); + } + + _init() async { + selectedValue = standardSizeList[1]; + var fcsShipments = + await context.read().getActiveFcsShipments(); + shipments = fcsShipments; + + if (mounted) { + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + final continueBtn = ContinueButton(onTap: () { + if (_shipment == null) { + showMsgDialog(context, "Error", "Please select shipment"); + return; + } + }); + + final previousBtn = PreviousButton(onTap: () { + if (widget.onPrevious != null) { + widget.onPrevious!(); + } + }); + + final standardSizeBox = Padding( + padding: const EdgeInsets.only(left: 35.0), + child: DropdownButton( + isDense: true, + value: selectedValue, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container( + height: 1, + color: Colors.grey, + ), + onChanged: (newValue) { + setState(() { + selectedValue = newValue!; + }); + }, + isExpanded: true, + items: standardSizeList.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value.toString(), + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Colors.black)), + ); + }).toList(), + ), + ); + + final cartonSizedBox = Column( + children: [ + // standard carton size + InkWell( + onTap: () { + setState(() { + _cartinSizeValue = 1; + }); + }, + child: Row(children: [ + Radio( + visualDensity: + const VisualDensity(horizontal: VisualDensity.minimumDensity), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeColor: primaryColor, + groupValue: _cartinSizeValue, + value: 1, + onChanged: (value) { + setState(() { + _cartinSizeValue = 1; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.standard_carton_size', + fontSize: 14, + color: _cartinSizeValue == 1 ? primaryColor : Colors.black), + ), + ) + ]), + ), + standardSizeBox, + const SizedBox(height: 10), + // custom size + InkWell( + onTap: () { + setState(() { + _cartinSizeValue = 2; + }); + }, + child: Row(children: [ + Radio( + visualDensity: + const VisualDensity(horizontal: VisualDensity.minimumDensity), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeColor: primaryColor, + groupValue: _cartinSizeValue, + value: 2, + onChanged: (value) { + setState(() { + _cartinSizeValue = 2; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.custom_size', + fontSize: 14, + color: _cartinSizeValue == 2 ? primaryColor : Colors.black), + ), + ) + ]), + ), + // not defined size + InkWell( + onTap: () { + setState(() { + _cartinSizeValue = 3; + }); + }, + child: Row(children: [ + Radio( + visualDensity: + const VisualDensity(horizontal: VisualDensity.minimumDensity), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + activeColor: primaryColor, + groupValue: _cartinSizeValue, + value: 3, + onChanged: (value) { + setState(() { + _cartinSizeValue = 3; + }); + }, + ), + Flexible( + child: Padding( + padding: const EdgeInsets.only(left: 10), + child: LocalText(context, 'box.package_size', + fontSize: 14, + color: _cartinSizeValue == 3 ? primaryColor : Colors.black), + ), + ) + ]), + ), + ], + ); + + final fcsShipmentsBox = Container( + padding: EdgeInsets.only(top: 10), + child: LocalDropdown( + callback: (v) { + setState(() { + _shipment = v; + }); + }, + labelKey: "box.shipment", + iconData: Ionicons.ios_airplane, + display: (u) => u.shipmentNumber, + selectedValue: _shipment, + values: shipments, + )); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView( + padding: EdgeInsets.only(left: 10, right: 10), + children: [ + LocalTitle(textKey: "box.select_carton_size"), + cartonSizedBox, + LocalTitle(textKey: "box.select_shipment"), + fcsShipmentsBox + ], + )), + Padding( + padding: const EdgeInsets.only(left: 15, right: 15), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + widget.onPrevious == null ? const SizedBox() : previousBtn, + continueBtn + // warehouse != null ? continueBtn : const SizedBox(), + ], + ), + ), + const SizedBox( + height: 20, + ), + ], + ); + } +} diff --git a/lib/pages/carton_search/carton_list_row.dart b/lib/pages/carton_search/carton_list_row.dart index a62d66e..1d723a8 100644 --- a/lib/pages/carton_search/carton_list_row.dart +++ b/lib/pages/carton_search/carton_list_row.dart @@ -73,7 +73,7 @@ class CartonListRow extends StatelessWidget { child: Row( children: [ new Text( - "${carton.cartonWeight?.toStringAsFixed(2)} lb", + "${carton.cartonWeight.toStringAsFixed(2)} lb", style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), diff --git a/lib/pages/fcs_shipment/fcs_shipment_list_row.dart b/lib/pages/fcs_shipment/fcs_shipment_list_row.dart index c867fd7..59a7837 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_list_row.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_list_row.dart @@ -1,6 +1,5 @@ import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/main/util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; @@ -8,9 +7,9 @@ import 'package:intl/intl.dart'; import 'fcs_shipment_info.dart'; class FcsShipmentListRow extends StatelessWidget { - final FcsShipment? shipment; + final FcsShipment shipment; final dateFormatter = new DateFormat('dd MMM yyyy'); - FcsShipmentListRow({Key? key, this.shipment}) : super(key: key); + FcsShipmentListRow({Key? key, required this.shipment}) : super(key: key); @override Widget build(BuildContext context) { @@ -29,7 +28,7 @@ class FcsShipmentListRow extends StatelessWidget { child: new Row( children: [ Container( - padding: EdgeInsets.only(left: 5, right: 10), + padding: EdgeInsets.only(left: 5), child: Icon( Ionicons.ios_airplane, color: primaryColor, @@ -38,19 +37,19 @@ class FcsShipmentListRow extends StatelessWidget { ), new Expanded( child: Padding( - padding: const EdgeInsets.only(left: 8.0), + padding: const EdgeInsets.only(left: 18.0), child: new Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ new Text( - shipment?.shipmentNumber ?? '', + shipment.shipmentNumber ?? '', style: new TextStyle( fontSize: 15.0, color: Colors.black), ), Padding( padding: const EdgeInsets.only(top: 5), child: new Text( - dateFormatter.format(shipment!.cutoffDate!), + dateFormatter.format(shipment.cutoffDate!), style: new TextStyle( fontSize: 15.0, color: Colors.grey), ), @@ -63,10 +62,11 @@ class FcsShipmentListRow extends StatelessWidget { ), ), ), - Padding( - padding: const EdgeInsets.all(0), - child: getStatus(shipment!.status ?? ''), - ), + Text(shipment.status ?? "", + style: TextStyle( + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.bold)), ], ), ), diff --git a/lib/pages/widgets/continue_button.dart b/lib/pages/widgets/continue_button.dart new file mode 100644 index 0000000..3aa78f8 --- /dev/null +++ b/lib/pages/widgets/continue_button.dart @@ -0,0 +1,46 @@ +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; + +import '../../helpers/theme.dart'; + +class ContinueButton extends StatelessWidget { + final String? labelKey; + final Function()? onTap; + const ContinueButton({Key? key, this.onTap, this.labelKey}) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Container( + alignment: Alignment.bottomRight, + height: 45, + width: 130, + decoration: BoxDecoration( + color: primaryColor, + borderRadius: BorderRadius.circular(5), + ), + child: TextButton( + onPressed: null, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Flexible( + child: LocalText( + context, labelKey == null ? 'btn.continue' : labelKey!, + color: Colors.white, fontSize: 15), + ), + const SizedBox( + width: 5, + ), + const Icon( + Feather.arrow_right_circle, + color: Colors.white, + ), + ], + ), + ), + )); + } +} diff --git a/lib/pages/widgets/display_text.dart b/lib/pages/widgets/display_text.dart index faeb06a..46b80e7 100644 --- a/lib/pages/widgets/display_text.dart +++ b/lib/pages/widgets/display_text.dart @@ -33,10 +33,8 @@ class DisplayText extends StatelessWidget { ) : TextStyle(color: Colors.black54, fontFamily: "Myanmar3"); var textStyle = languageModel.isEng - ? TextStyle( - color: primaryColor, - ) - : TextStyle(color: primaryColor, fontFamily: "Myanmar3"); + ? TextStyle(color: Colors.black) + : TextStyle(color: Colors.black, fontFamily: "Myanmar3"); return Padding( padding: const EdgeInsets.only(top: 8.0, bottom: 8), diff --git a/lib/pages/widgets/local_dropdown.dart b/lib/pages/widgets/local_dropdown.dart index 612e95d..b693aec 100644 --- a/lib/pages/widgets/local_dropdown.dart +++ b/lib/pages/widgets/local_dropdown.dart @@ -37,12 +37,12 @@ class LocalDropdown extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.only(right: 18.0), - child: LocalText( + child: labelKey!=null? LocalText( context, labelKey!, color: Colors.black54, fontSize: 16, - ), + ): const SizedBox(), ), DropdownButton( isDense: true, @@ -68,7 +68,7 @@ class LocalDropdown extends StatelessWidget { ? display!(value) : value.toString(), overflow: TextOverflow.ellipsis, - style: TextStyle(color: primaryColor)), + style: TextStyle(color: Colors.black)), ); }).toList(), ), diff --git a/lib/pages/widgets/local_radio_buttons.dart b/lib/pages/widgets/local_radio_buttons.dart index 01db508..6c2035d 100644 --- a/lib/pages/widgets/local_radio_buttons.dart +++ b/lib/pages/widgets/local_radio_buttons.dart @@ -40,7 +40,11 @@ class LocalRadioButtons extends StatelessWidget { callback!(value!); }, ), - Text(e.toString()), + Text(e.toString(), + style: TextStyle( + fontSize: 14, + color: + e == selectedValue ? primaryColor : Colors.black)), ]), ))) .toList(); diff --git a/lib/pages/widgets/local_title.dart b/lib/pages/widgets/local_title.dart index 55eb30f..2c3ce3c 100644 --- a/lib/pages/widgets/local_title.dart +++ b/lib/pages/widgets/local_title.dart @@ -5,8 +5,11 @@ import 'package:flutter/material.dart'; class LocalTitle extends StatelessWidget { final String? textKey; final Widget? trailing; + final List? translationVariables; - const LocalTitle({Key? key, this.textKey, this.trailing}) : super(key: key); + const LocalTitle( + {Key? key, this.textKey, this.trailing, this.translationVariables}) + : super(key: key); @override Widget build(BuildContext context) { @@ -17,13 +20,11 @@ class LocalTitle extends StatelessWidget { padding: EdgeInsets.only(top: 18), child: Row( children: [ - LocalText( - context, - textKey!, - fontSize: 20, - fontWeight: FontWeight.bold, - color: primaryColor, - ), + LocalText(context, textKey!, + fontSize: 20, + fontWeight: FontWeight.bold, + color: primaryColor, + translationVariables: translationVariables), trailing != null ? Spacer() : Container(), trailing != null ? trailing! : Container() ], diff --git a/lib/pages/widgets/previous_button.dart b/lib/pages/widgets/previous_button.dart new file mode 100644 index 0000000..3ac2060 --- /dev/null +++ b/lib/pages/widgets/previous_button.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; + +import '../../helpers/theme.dart'; +import 'local_text.dart'; + +class PreviousButton extends StatelessWidget { + final Function()? onTap; + const PreviousButton({Key? key, this.onTap}) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Container( + alignment: Alignment.bottomRight, + height: 45, + width: 130, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + border: Border.all(color: primaryColor)), + child: TextButton( + onPressed: null, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Feather.arrow_left_circle, + color: primaryColor, + ), + const SizedBox(width: 10), + Flexible( + child: LocalText(context, 'btn.previous', + color: primaryColor, fontSize: 15), + ) + ], + ), + ), + )); + } +} diff --git a/lib/pages/widgets/step_widget.dart b/lib/pages/widgets/step_widget.dart new file mode 100644 index 0000000..0703ff6 --- /dev/null +++ b/lib/pages/widgets/step_widget.dart @@ -0,0 +1,125 @@ +import 'package:flutter/material.dart'; + +import '../../helpers/theme.dart'; + +class StepperWidget extends StatefulWidget { + final int currentStep; + final List labels; + final double eachStepWidth; + final double height; + final ValueChanged? onChange; + + const StepperWidget( + {Key? key, + this.currentStep = 0, + required this.labels, + this.eachStepWidth = 100, + this.height = 80, + this.onChange}) + : super(key: key); + @override + State createState() => _StepperWidgetState(); +} + +class _StepperWidgetState extends State { + @override + Widget build(BuildContext context) { + var body = _body(); + return Center( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, child: body)); + } + + Widget _body() { + return SizedBox( + width: widget.eachStepWidth * widget.labels.length, + height: widget.height, + child: Stack( + children: [ + Positioned( + bottom: 13, + left: widget.eachStepWidth / 2, + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 0.0), + height: 1.0, + width: widget.eachStepWidth * (widget.labels.length - 1), + color: Colors.grey.shade400, + ), + ), + Row( + children: widget.labels.asMap().entries.map((e) { + return StepWidget( + label: e.value, + step: e.key, + stepWidth: widget.eachStepWidth, + currentStep: widget.currentStep, + onTap: () => _onTap(e.key), + end: e.key == widget.labels.length - 1, + ); + }).toList()), + ], + ), + ); + } + + _onTap(int index) { + if (widget.onChange != null) { + widget.onChange!(index); + } + } +} + +class StepWidget extends StatelessWidget { + final String label; + final int step; + final double stepWidth; + final int currentStep; + final GestureTapCallback? onTap; + final bool end; + + const StepWidget( + {Key? key, + required this.label, + required this.step, + this.stepWidth = 100, + required this.currentStep, + this.onTap, + this.end = false}) + : super(key: key); + @override + Widget build(BuildContext context) { + bool active = step == currentStep; + bool past = step < currentStep; + return InkWell( + onTap: onTap, + child: SizedBox( + width: stepWidth, + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text(label, + textAlign: TextAlign.center, + style: TextStyle( + color: active ? primaryColor : Colors.grey, + fontFamily: "Roboto")), + const SizedBox(height: 5), + CircleAvatar( + backgroundColor: end && active + ? primaryColor + : active || past + ? primaryColor + : Colors.grey, + radius: 13, + child: end + ? const Icon(Icons.check, color: Colors.white, size: 20) + : Text( + (step + 1).toString(), + style: const TextStyle(color: Colors.white), + ), + ) + ], + ), + ), + ); + } +}