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/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/localization/app_translations.dart'; import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/main_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/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'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/length_picker.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/my_data_table.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 'cargo_type_editor.dart'; import 'model/carton_model.dart'; class CartonEditor extends StatefulWidget { final Carton box; CartonEditor({this.box}); @override _CartonEditorState createState() => _CartonEditorState(); } class _CartonEditorState extends State { TextEditingController _widthController = new TextEditingController(); TextEditingController _heightController = new TextEditingController(); TextEditingController _lengthController = new TextEditingController(); Carton _box; bool _isLoading = false; bool _isNew; DeliveryAddress _deliveryAddress = new DeliveryAddress(); User _user; String _selectedCartonType; List _packages = []; List _mixBoxes = []; double volumetricRatio = 0; double shipmentWeight = 0; FcsShipment _fcsShipment; List _fcsShipments; @override void initState() { super.initState(); //for shipment boxes var boxModel = Provider.of(context, listen: false); //for mix boxes _mixBoxes = [ boxModel.boxeList[0], boxModel.boxeList[1], boxModel.boxeList[2] ]; _mixBoxes.forEach((b) { b.isChecked = false; }); //for shipment weight volumetricRatio = Provider.of(context, listen: false) .rate .volumetricRatio; _lengthController.addListener(_calShipmentWeight); _widthController.addListener(_calShipmentWeight); _heightController.addListener(_calShipmentWeight); if (widget.box != null) { _box = widget.box; _deliveryAddress = _box.deliveryAddress; _widthController.text = _box.width.toString(); _heightController.text = _box.height.toString(); _lengthController.text = _box.length.toString(); _selectedCartonType = _box.cartonType; _isNew = false; _user = User(fcsID: _box.fcsID, name: _box.userName); } else { _box = Carton(cargoTypes: []); _lengthController.text = "12"; _widthController.text = "12"; _heightController.text = "12"; _isNew = true; _selectedCartonType = carton_from_packages; _loadFcsShipments(); } } _loadFcsShipments() async { FcsShipmentModel fcsShipmentModel = Provider.of(context, listen: false); var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); var fcsShipment = fcsShipments.firstWhere((e) => e.id == _box.fcsShipmentID, orElse: () => null); 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); 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; } }); setState(() { _packages = packages; }); _populateDeliveryAddress(); } _populateDeliveryAddress() { if (_packages == null) return; var d = _packages .firstWhere((p) => p.isChecked && p.deliveryAddress != null, orElse: () => null) ?.deliveryAddress; setState(() { _deliveryAddress = d; }); } _calShipmentWeight() { double l = double.parse(_lengthController.text, (s) => 0); double w = double.parse(_widthController.text, (s) => 0); double h = double.parse(_heightController.text, (s) => 0); setState(() { shipmentWeight = l * w * h / volumetricRatio; }); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { var boxModel = Provider.of(context); var fcsShipmentsBox = LocalDropdown( callback: (v) { setState(() { _fcsShipment = v; }); }, labelKey: "shipment.pack.fcs.shipment", iconData: MaterialCommunityIcons.worker, display: (u) => u.shipmentNumber, selectedValue: _fcsShipment, values: _fcsShipments, ); final fcsIDBox = Row( children: [ Expanded( child: DisplayText( text: _user?.fcsID ?? "", labelTextKey: "box.fcs.id", icon: FcsIDIcon(), )), IconButton( icon: Icon(Icons.search, color: primaryColor), onPressed: () => searchUser(context, callbackUserSelect: (u) { setState(() { this._user = u; _loadPackages(); }); })), ], ); final namebox = DisplayText( text: _user?.name ?? "", labelTextKey: "box.name", iconData: Icons.person, ); final packageTitle = Container( padding: EdgeInsets.only(right: 10.0, top: 20), child: Row( children: [ Container( width: 30, ), Expanded( child: LocalText(context, 'box.tracking.id', color: Colors.grey), ), LocalText(context, 'box.package.desc', color: Colors.grey), ], ), ); List getPackageRowList() { return _packages.asMap().entries.map((p) { return Container( color: p.value.isChecked ? Colors.grey.withOpacity(0.2) : Colors.grey[50].withOpacity(0.2), child: Container( padding: EdgeInsets.only(left: 0.0, right: 10.0, top: 3.0, bottom: 3.0), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: p.key == _packages.length - 1 ? Colors.white : Colors.grey[350], width: 1), ), ), child: Row( children: [ Checkbox( value: p.value.isChecked, activeColor: primaryColor, onChanged: (bool check) { if (check && _deliveryAddress != null && p.value.deliveryAddress?.id != _deliveryAddress.id) { return; } setState(() { p.value.isChecked = check; }); _populateDeliveryAddress(); }), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( p.value.trackingID, style: textStyle, ), Text( p.value.deliveryAddress?.fullName ?? "", style: textStyle, ), Text( p.value.deliveryAddress?.phoneNumber ?? "", style: textStyle, ), ], )), new Column( children: [ new Text( p.value?.desc ?? "", style: textStyle, ), new Text( "(${p.value?.market ?? ""})", style: textStyle, ) ], ) ], ), ), ); }).toList(); } final mixBoxTitle = Container( padding: EdgeInsets.only(right: 10.0, top: 20), child: Row( children: [ Container( width: 30, ), Expanded( child: LocalText(context, 'box.mix.number', color: Colors.grey), ), LocalText(context, 'box.mix.desc', color: Colors.grey), ], ), ); List getMixBoxRowList() { return _mixBoxes.asMap().entries.map((b) { return Container( color: b.value.isChecked ? Colors.grey.withOpacity(0.2) : Colors.grey[50].withOpacity(0.2), child: Container( padding: EdgeInsets.only(left: 0.0, right: 10.0, top: 3.0, bottom: 3.0), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: b.key == _mixBoxes.length - 1 ? Colors.white : Colors.grey[350], width: 1), ), ), child: Row( children: [ Checkbox( value: b.value.isChecked, activeColor: primaryColor, onChanged: (bool check) { setState(() { b.value.isChecked = check; }); }), Expanded( child: new Text( b.value.packageNumber, style: textStyle, )), new Text( b.value.desc == null ? "" : b.value.desc, style: textStyle, ), ], ), ), ); }).toList(); } final lengthBox = LengthPicker( controller: _lengthController, lableKey: "box.length", ); final widthBox = LengthPicker( controller: _widthController, lableKey: "box.width", ); final heightBox = LengthPicker( controller: _heightController, lableKey: "box.height", ); 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 shipmentWeightBox = DisplayText( text: shipmentWeight != null ? shipmentWeight.toStringAsFixed(0) : "", labelTextKey: "box.shipment_weight", iconData: MaterialCommunityIcons.weight, ); final createBtn = LocalButton( textKey: "box.create.btn", ); final completeBtn = LocalButton( textKey: "box.complete.btn", ); final deliveryBtn = LocalButton( textKey: "box.deliver.btn", ); final cartonTypeBox = LocalRadioButtons( values: boxModel.cartonTypes, selectedValue: _selectedCartonType, callback: (v) { print(v); setState(() { _selectedCartonType = v; }); }); return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( appBar: AppBar( centerTitle: true, leading: new IconButton( icon: new Icon(CupertinoIcons.back, color: primaryColor, size: 30), onPressed: () => Navigator.of(context).pop(), ), shadowColor: Colors.transparent, backgroundColor: Colors.white, title: widget.box == null ? LocalText( context, "boxes.create.title", fontSize: 20, color: primaryColor, ) : LocalText( context, "box.edit.title", fontSize: 20, color: primaryColor, ), ), body: Padding( padding: const EdgeInsets.all(8.0), child: ListView( shrinkWrap: true, children: [ LocalTitle(textKey: "box.type.title"), cartonTypeBox, LocalTitle(textKey: "box.shipment_info"), fcsShipmentsBox, SizedBox( height: 10, ), fcsIDBox, namebox, _selectedCartonType == carton_from_packages ? Column( children: [ LocalTitle(textKey: "box.packages"), packageTitle, Divider( color: Colors.grey[400], ), Column( children: getPackageRowList(), ), ], ) : _selectedCartonType == carton_mix_box ? Column( children: [ LocalTitle(textKey: "box.shipment.boxes"), mixBoxTitle, Divider( color: Colors.grey[400], ), Column( children: getMixBoxRowList(), ) ], ) : Container(), LocalTitle( textKey: "box.cargo.type", trailing: IconButton( icon: Icon( Icons.add_circle, color: primaryColor, ), onPressed: () async { CargoType cargo = await Navigator.push( context, CupertinoPageRoute( builder: (context) => CargoTypeEditor())); _addCargo(cargo); }), ), MyDataTable( headingRowHeight: 40, columns: [ MyDataColumn( label: LocalText( context, "cargo.type", color: Colors.grey, ), ), MyDataColumn( label: LocalText( context, "cargo.weight", color: Colors.grey, ), ), ], rows: getCargoRows(context), ), LocalTitle(textKey: "box.dimension"), dimBox, shipmentWeightBox, LocalTitle(textKey: "box.delivery_address"), DefaultDeliveryAddress( deliveryAddress: _deliveryAddress, labelKey: "box.delivery_address", ), widget.box == null ? createBtn : Container( child: Column( children: [ completeBtn, widget.box.status == 'Arrived' ? deliveryBtn : Container(), ], )), SizedBox( height: 20, ), ], ), ), ), ); } List getCargoRows(BuildContext context) { if (_box?.cargoTypes == null) { return []; } double total = 0; var rows = _box.cargoTypes.map((c) { total += c.weight; return MyDataRow( onSelectChanged: (bool selected) async { CargoType cargo = await Navigator.push( context, CupertinoPageRoute( builder: (context) => CargoTypeEditor( cargo: c, ))); _addCargo(cargo); }, cells: [ MyDataCell(new Text( c.name == null ? "" : c.name, style: textStyle, )), MyDataCell( Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Text(c.weight == null ? "0" : c.weight.toString(), style: textStyle), IconButton( icon: Icon( Icons.remove_circle, color: primaryColor, ), onPressed: () => {_removeCargo(c)}, ) ], ), ), ], ); }).toList(); var totalRow = MyDataRow( onSelectChanged: (bool selected) {}, cells: [ MyDataCell(Align( alignment: Alignment.centerRight, child: LocalText( context, "shipment.cargo.total", color: Colors.black87, fontWeight: FontWeight.bold, ), )), MyDataCell( Padding( padding: const EdgeInsets.only(right: 48.0), child: Align( alignment: Alignment.centerRight, child: Text(total.toString(), style: TextStyle(fontWeight: FontWeight.bold))), ), ), ], ); rows.add(totalRow); return rows; } List getAddressList( BuildContext context, List addresses) { return addresses.asMap().entries.map((s) { return InkWell( onTap: () {}, child: DeliveryAddressRow(deliveryAddress: s.value), ); }).toList(); } _addCargo(CargoType cargo) { if (cargo == null) return; setState(() { _box.cargoTypes.remove(cargo); _box.cargoTypes.add(cargo); }); } _removeCargo(CargoType cargo) { setState(() { _box.cargoTypes.remove(cargo); }); } _save() async { _box.cartonType = _selectedCartonType; _box.fcsShipmentID = _fcsShipment.id; _box.userID = _user.id; _box.packages = _packages.map((e) => e.isChecked ? e : null).toList(); double l = double.parse(_lengthController.text, (s) => 0); double w = double.parse(_widthController.text, (s) => 0); double h = double.parse(_heightController.text, (s) => 0); _box.length = l; _box.width = w; _box.height = h; _box.deliveryAddress = _deliveryAddress; setState(() { _isLoading = true; }); try { CartonModel cartonModel = Provider.of(context, listen: false); if (_isNew) { await cartonModel.createCarton(_box); } else { await cartonModel.updateCarton(_box); } Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); } finally { setState(() { _isLoading = false; }); } } }