diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 5ed4227..3845365 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -296,6 +296,9 @@ "box.new_carton_btn":"Create new carton", "box.select.cargo.title":"Select cargos", "box.complete.packaging":"Complete Packaging", + "box.mix_caton_title":"Mix cartons", + "box.min_caton.form.title":"Mix Carton", + "box.mix_carton_btn":"Create mix carton", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 1fa9c3e..e8f5154 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -296,6 +296,9 @@ "box.new_carton_btn":"သေတ္တာ အသစ်ပြုလုပ်မည်", "box.select.cargo.title":"Sကုန်ပစ္စည်းများ ရွေးခြင်း", "box.complete.packaging":"ထုပ်ပိုးခြင်း ပြီးဆုံးမည်", + "box.mix_caton_title":"Mix cartons", + "box.min_caton.form.title":"Mix Carton", + "box.mix_carton_btn":"Create mix carton", "Boxes End ================================================================":"", "Delivery Start ================================================================":"", diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index ffb49c2..69ab4fc 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -79,8 +79,13 @@ const shipment_courier_dropoff = "Courier drop off"; //Carton types const carton_from_packages = "From packages"; const carton_from_shipments = "From shipments"; -const carton_mix_box = "Mix carton"; +const carton_mix_carton = "Mix carton"; const carton_small_bag = "Small bag"; +const carton_mix_box = "Mix box"; + +//Mix types +const mix_delivery = "Mix Delivery"; +const mix_pickup = "Mix Pickup"; //Carton status const carton_packed_status = "packed"; diff --git a/lib/domain/vo/shipment_status.dart b/lib/domain/vo/shipment_status.dart index 7180de7..ed4549c 100644 --- a/lib/domain/vo/shipment_status.dart +++ b/lib/domain/vo/shipment_status.dart @@ -4,14 +4,18 @@ class ShipmentStatus { String status; DateTime date; bool done; - ShipmentStatus({this.status, this.date, this.done}); + String staffId; + String staffName; + ShipmentStatus( + {this.status, this.date, this.done, this.staffId, this.staffName}); factory ShipmentStatus.fromMap(Map map) { var _date = (map['date'] as Timestamp); return ShipmentStatus( - status: map['status'], - date: _date == null ? null : _date.toDate(), - done: map['done'], - ); + status: map['status'], + date: _date == null ? null : _date.toDate(), + done: map['done'], + staffId: map['staff_id'], + staffName: map['staff_name']); } } diff --git a/lib/pages/carton/cargo_table.dart b/lib/pages/carton/cargo_table.dart new file mode 100644 index 0000000..fc684a0 --- /dev/null +++ b/lib/pages/carton/cargo_table.dart @@ -0,0 +1,97 @@ +import 'package:fcs/domain/entities/cargo_type.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/my_data_table.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CargoTable extends StatefulWidget { + final List cargoTypes; + + const CargoTable({ + Key key, + this.cargoTypes, + }) : super(key: key); + + @override + _CargoTableState createState() => _CargoTableState(); +} + +class _CargoTableState extends State { + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: MyDataTable( + headingRowHeight: 40, + columnSpacing: 140, + columns: [ + MyDataColumn( + label: LocalText( + context, + "cargo.type", + color: Colors.grey, + ), + ), + MyDataColumn( + label: LocalText( + context, + "cargo.weight", + color: Colors.grey, + ), + ), + ], + rows: getCargoRows(context), + ), + ); + } + + List getCargoRows(BuildContext context) { + if (widget.cargoTypes == null) { + return []; + } + double total = 0; + var rows = widget.cargoTypes.map((c) { + total += c.weight; + return MyDataRow( + onSelectChanged: (bool selected) async {}, + cells: [ + MyDataCell(new Text( + c.name == null ? "" : c.name, + style: textStyle, + )), + MyDataCell( + Text(c.weight == null ? "0" : c.weight.toStringAsFixed(2), + style: textStyle), + ), + ], + ); + }).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.toStringAsFixed(2), + style: TextStyle(fontWeight: FontWeight.bold))), + ), + ), + ], + ); + rows.add(totalRow); + return rows; + } +} diff --git a/lib/pages/carton/cargo_type_addtion.dart b/lib/pages/carton/cargo_type_addtion.dart index 7dbf934..7c0d966 100644 --- a/lib/pages/carton/cargo_type_addtion.dart +++ b/lib/pages/carton/cargo_type_addtion.dart @@ -76,6 +76,46 @@ class _CargoTypeAdditionState extends State { ); List getCargoRowList() { + return cargos.map((c) { + return Container( + child: Container( + padding: + EdgeInsets.only(left: 10.0, right: 5.0, top: 3.0, bottom: 3.0), + child: Row( + children: [ + Checkbox( + value: c.isChecked, + activeColor: primaryColor, + onChanged: (bool check) { + setState(() { + c.isChecked = check; + }); + }), + new Text(c.name, style: textStyle), + c.isCutomDuty + ? Padding( + padding: const EdgeInsets.only(left: 15), + child: IconButton( + onPressed: () { + setState(() { + cargos.removeWhere((t) => t.name == c.name); + }); + }, + icon: Icon( + Icons.remove_circle, + color: Colors.black45, + ), + ), + ) + : Container(), + ], + ), + ), + ); + }).toList(); + } + + List _getCargoRowList() { return cargos.map((c) { return Container( child: Container( @@ -206,10 +246,10 @@ class _CargoTypeAdditionState extends State { _addCustom(customDuty); }), ), - cargoTableTitleBox, - Divider( - color: Colors.grey[400], - ), + // cargoTableTitleBox, + // Divider( + // color: Colors.grey[400], + // ), Column( children: getCargoRowList(), ), @@ -229,7 +269,8 @@ class _CargoTypeAdditionState extends State { if (cargos.any((c) => c.name == customDuty.productType)) return; setState(() { - cargos.add(CargoType(name: customDuty.productType, isCutomDuty: true)); + cargos.add( + CargoType(name: customDuty.productType, isCutomDuty: true, qty: 1)); }); } } diff --git a/lib/pages/carton/carton_cargo_table.dart b/lib/pages/carton/carton_cargo_table.dart index e820133..a69557a 100644 --- a/lib/pages/carton/carton_cargo_table.dart +++ b/lib/pages/carton/carton_cargo_table.dart @@ -1,13 +1,13 @@ import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/widgets/dialog_input.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/my_data_table.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'cargo_type_editor.dart'; -import 'total_weight_edit.dart'; typedef OnAdd(CargoType cargoType); typedef OnRemove(CargoType cargoType); @@ -28,6 +28,8 @@ class _CargoTableState extends State { double totalWeight = 0; List _cargos = []; double remainingWeight = 0; + List _list = []; + List _types = []; @override Widget build(BuildContext context) { @@ -35,25 +37,36 @@ class _CargoTableState extends State { widget.cargoTypes.length == 0 ? this.totalWeight : remainingWeight; this._cargos = widget.cargoTypes.length == 0 ? [] : this._cargos; - return MyDataTable( - headingRowHeight: 40, - columns: [ - MyDataColumn( - label: LocalText( - context, - "cargo.type", - color: Colors.grey, + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: MyDataTable( + headingRowHeight: 40, + columnSpacing: 40, + columns: [ + MyDataColumn( + label: LocalText( + context, + "cargo.type", + color: Colors.grey, + ), ), - ), - MyDataColumn( - label: LocalText( - context, - "cargo.weight", - color: Colors.grey, + MyDataColumn( + label: LocalText( + context, + "cargo.qty", + color: Colors.grey, + ), ), - ), - ], - rows: getCargoRows(context), + MyDataColumn( + label: LocalText( + context, + "cargo.weight", + color: Colors.grey, + ), + ), + ], + rows: getCargoRows(context), + ), ); } @@ -61,49 +74,51 @@ class _CargoTableState extends State { if (widget.cargoTypes == null) { return []; } - List _list = []; - List _types = []; + + CargoType cargo; + + print("copy remainingWeight>>>${this.remainingWeight}"); var rows = widget.cargoTypes.map((c) { return MyDataRow( onSelectChanged: (bool selected) async { - if (this.totalWeight <= 0) { - showMsgDialog(context, "Error", "Please insert total weight"); - return; - } + // if (this.totalWeight <= 0) { + // showMsgDialog(context, "Error", "Please insert total weight"); + // return; + // } - if (c.isCutomDuty) return; - CargoType cargo = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => CargoTypeEditor( - cargo: c, - ))); - if (widget.onAdd != null) widget.onAdd(cargo); - if (cargo == null) return; + // if (c.isCutomDuty) return; + // CargoType cargo = await Navigator.push( + // context, + // CupertinoPageRoute( + // builder: (context) => CargoTypeEditor( + // cargo: c, + // ))); + // if (widget.onAdd != null) widget.onAdd(cargo); + // if (cargo == null) return; - this._cargos.add(cargo); - if (this.remainingWeight <= 0) return; - this.remainingWeight -= cargo.weight; + // this._cargos.add(cargo); + // if (this.remainingWeight <= 0) return; + // this.remainingWeight -= cargo.weight; - this._cargos.forEach((c) { - _list.add(c.name); - }); - widget.cargoTypes.forEach((c) { - _types.add(c.name); - }); + // this._cargos.forEach((c) { + // _list.add(c.name); + // }); + // widget.cargoTypes.forEach((c) { + // _types.add(c.name); + // }); - if (this._cargos.length == widget.cargoTypes.length - 1) { - _types.forEach((t) { - if (!_list.contains(t)) { - widget.cargoTypes.forEach((c) { - if (c.name == t) { - c.weight = this.remainingWeight; - } - }); - } - }); - } + // if (this._cargos.length == widget.cargoTypes.length - 1) { + // _types.forEach((t) { + // if (!_list.contains(t)) { + // widget.cargoTypes.forEach((c) { + // if (c.name == t) { + // c.weight = this.remainingWeight; + // } + // }); + // } + // }); + // } }, cells: [ MyDataCell(Row( @@ -118,12 +133,106 @@ class _CargoTableState extends State { ), ], )), + MyDataCell( + c.isCutomDuty + ? InkWell( + onTap: () async { + String _t = await showDialog( + context: context, + builder: (_) => DialogInput( + label: "cargo.qty", value: c.qty.toString())); + + if (_t == null) return; + setState(() { + c.qty = int.parse(_t); + }); + }, + child: Center( + child: Container( + width: 40, + padding: const EdgeInsets.all(7.0), + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.all(Radius.circular(5.0)), + ), + child: new Text( + c.qty == null ? "" : c.qty.toString(), + style: textStyle, + textAlign: TextAlign.center, + ), + ), + ), + ) + : Center( + child: new Text( + "-", + style: textStyle, + ), + ), + ), MyDataCell( Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(c.weight == null ? "0.00" : c.weight.toStringAsFixed(2), - style: textStyle), + GestureDetector( + onTap: () async { + if (this.totalWeight <= 0) { + showMsgDialog( + context, "Error", "Please insert total weight"); + return; + } + + String _t = await showDialog( + context: context, + builder: (_) => DialogInput( + label: "cargo.weight", + value: c.weight.toStringAsFixed(2))); + + if (_t == null) return; + setState(() { + c.weight = double.parse(_t); + }); + + cargo = c; + this._cargos.add(cargo); + if (this.remainingWeight <= 0) return; + this.remainingWeight -= cargo.weight; + + this._cargos.forEach((c) { + _list.add(c.name); + }); + + widget.cargoTypes.forEach((c) { + _types.add(c.name); + }); + + if (this._cargos.length == widget.cargoTypes.length - 1) { + _types.forEach((t) { + if (!_list.contains(t)) { + widget.cargoTypes.forEach((c) { + if (c.name == t) { + c.weight = this.remainingWeight; + setState(() { + this._cargos = []; + }); + } + }); + } + }); + this.remainingWeight = this.totalWeight; + } + }, + child: Container( + padding: const EdgeInsets.all(7.0), + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.all(Radius.circular(5.0)), + ), + child: Text( + c.weight == null ? "0.00" : c.weight.toStringAsFixed(2), + style: textStyle), + ), + ), widget.onRemove == null ? SizedBox( width: 50, @@ -155,20 +264,23 @@ class _CargoTableState extends State { fontWeight: FontWeight.bold, ), )), + MyDataCell(Text("")), MyDataCell( Padding( - padding: const EdgeInsets.only(right: 40.0), + padding: const EdgeInsets.only(right: 48.0), child: Align( alignment: Alignment.centerRight, child: InkWell( onTap: () async { - double _t = await Navigator.of(context).push( - CupertinoPageRoute( - builder: (context) => - TotalWeightEdit(totalWeight: totalWeight))); + String _t = await showDialog( + context: context, + builder: (_) => DialogInput( + label: "shipment.cargo.total", + value: totalWeight.toStringAsFixed(2))); + if (_t == null) return; setState(() { - totalWeight = _t; + totalWeight = double.parse(_t); remainingWeight = totalWeight; }); }, @@ -190,11 +302,6 @@ class _CargoTableState extends State { return rows; } - double getRemainBalance(double total) { - double _r = this.totalWeight < total ? 0 : this.totalWeight - total; - return _r; - } - List _getCargoRows(BuildContext context) { if (widget.cargoTypes == null) { return []; diff --git a/lib/pages/carton/carton_cargo_table_old.dart b/lib/pages/carton/carton_cargo_table_old.dart index 9333dae..8e0d6f9 100644 --- a/lib/pages/carton/carton_cargo_table_old.dart +++ b/lib/pages/carton/carton_cargo_table_old.dart @@ -79,7 +79,7 @@ class _CargoTableState extends State { style: textStyle, ), new Text( - c.qty == null ? "" : " x ${c.qty.toString()}", + c.qty == null || c.qty == 0 ? "" : " x ${c.qty.toString()}", style: TextStyle(color: Colors.grey), ), ], diff --git a/lib/pages/carton/carton_editor.dart b/lib/pages/carton/carton_editor.dart index f6ebfdd..464f66b 100644 --- a/lib/pages/carton/carton_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -7,20 +7,16 @@ 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_cargo_table.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/delivery_address/delivery_address_list.dart'; -import 'package:fcs/pages/delivery_address/delivery_address_row.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/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'; @@ -31,8 +27,9 @@ 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_addtion.dart'; -import 'cargo_type_editor.dart'; +import 'carton_list_row.dart'; +import 'carton_row.dart'; +import 'mix_carton_editor.dart'; import 'model/carton_model.dart'; import '../carton_size/model/carton_size_model.dart'; import 'package_carton_editor.dart'; @@ -57,14 +54,14 @@ class _CartonEditorState extends State { DeliveryAddress _deliveryAddress = new DeliveryAddress(); User _user; String _selectedCartonType; + String _selectedMixType; double volumetricRatio = 0; double shipmentWeight = 0; FcsShipment _fcsShipment; List _fcsShipments; Carton _mixCarton; - List _mixCartons; - List _cartons = []; + List _mixCartons = []; @override void initState() { @@ -98,12 +95,14 @@ class _CartonEditorState extends State { _heightController.text = ""; _isNew = true; _selectedCartonType = carton_from_packages; + _selectedMixType = mix_delivery; _loadFcsShipments(); - // _cartons = [ - // Carton(cartonNumber: "A100B-1#1"), - // Carton(cartonNumber: "A100B-1#2"), - // Carton(cartonNumber: "A100B-1#3") - // ]; + _cartons = [Carton(cartonNumber: "A100B-1#3", userName: "Seven 7")]; + + _mixCartons = [ + Carton(cartonNumber: "A100B-1#1", userName: "Seven 7"), + Carton(cartonNumber: "A100B-1#2", userName: "Seven 7"), + ]; } } @@ -167,18 +166,6 @@ class _CartonEditorState extends State { }); } - _loadMixCartons() async { - if (_fcsShipment == null || _fcsShipment.id == null) return; - if (_selectedCartonType != carton_small_bag) return; - - CartonModel cartonModel = Provider.of(context, listen: false); - List cartons = - await cartonModel.getMixCartonsByFcsShipment(_fcsShipment.id); - setState(() { - _mixCartons = cartons; - }); - } - _calShipmentWeight() { double l = double.parse(_lengthController.text, (s) => 0); double w = double.parse(_widthController.text, (s) => 0); @@ -197,17 +184,13 @@ class _CartonEditorState extends State { Widget build(BuildContext context) { var boxModel = Provider.of(context); bool isMixBox = _selectedCartonType == carton_mix_box; - bool isSmallBag = _selectedCartonType == carton_small_bag; + final shipmentBox = DisplayText( text: _carton.fcsShipmentNumber, labelTextKey: "box.fcs_shipment_num", iconData: Ionicons.ios_airplane, ); - final mixCartonNumberBox = DisplayText( - text: _carton.mixCartonNumber, - labelTextKey: "box.mix.carton", - iconData: MaterialCommunityIcons.package, - ); + var fcsShipmentsBox = Container( padding: EdgeInsets.only(top: 10), child: LocalDropdown( @@ -215,7 +198,6 @@ class _CartonEditorState extends State { setState(() { _fcsShipment = v; }); - _loadMixCartons(); }, labelKey: "shipment.pack.fcs.shipment", iconData: Ionicons.ios_airplane, @@ -224,21 +206,6 @@ class _CartonEditorState extends State { values: _fcsShipments, )); - var mixCartonsBox = Container( - padding: EdgeInsets.only(top: 10), - child: LocalDropdown( - callback: (v) { - setState(() { - _mixCarton = v; - }); - }, - labelKey: "box.mix.carton", - iconData: MaterialCommunityIcons.package, - display: (u) => u.cartonNumber, - selectedValue: _mixCarton, - values: _mixCartons, - )); - final fcsIDBox = Container( padding: EdgeInsets.only(top: 10), child: Row( @@ -269,41 +236,6 @@ class _CartonEditorState extends State { iconData: Icons.person, ); - final lengthBox = LengthPicker( - controller: _lengthController, - lableKey: "box.length", - isReadOnly: true, - ); - final widthBox = LengthPicker( - controller: _widthController, - lableKey: "box.width", - isReadOnly: true, - ); - final heightBox = LengthPicker( - controller: _heightController, - lableKey: "box.height", - isReadOnly: true, - ); - - 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(2) : "", - labelTextKey: "box.shipment_weight", - iconData: MaterialCommunityIcons.weight, - ); - final createBtn = LocalButton( textKey: "box.complete.packaging", callBack: _save, @@ -324,35 +256,7 @@ class _CartonEditorState extends State { }); }); - final cargoTableTitleBox = 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); - List cargos = await Navigator.push>( - context, - CupertinoPageRoute(builder: (context) => CargoTypeAddition())); - if (cargos == null) return; - setState(() { - _carton.cargoTypes.clear(); - _carton.cargoTypes.addAll(cargos); - }); - }), - ); - - final cargoTableBox = CargoTable( - cargoTypes: _carton.cargoTypes, - onAdd: (c) => _addCargo(c), - onRemove: (c) => _removeCargo(c), - ); - - final cartonTitleBox = Container( + final _cartonTitleBox = Container( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -374,6 +278,54 @@ class _CartonEditorState extends State { ), ); + final cartonTitleBox = Container( + child: LocalTitle( + textKey: "boxes.title", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () async { + Carton _carton = await Navigator.push( + context, + CupertinoPageRoute(builder: (context) => PackageCartonEditor()), + ); + _addCarton(_carton); + }), + ), + ); + + final mixTypeBox = Container( + padding: EdgeInsets.only(top: 10), + child: LocalRadioButtons( + readOnly: !_isNew, + values: boxModel.mixTypes, + selectedValue: _selectedMixType, + callback: (v) { + setState(() { + _selectedMixType = v; + }); + })); + + final mixcartonTitleBox = Container( + child: LocalTitle( + textKey: "box.mix_caton_title", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () async { + Carton _carton = await Navigator.push( + context, + CupertinoPageRoute(builder: (context) => MixCartonEditor()), + ); + }, + ), + ), + ); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( @@ -399,19 +351,6 @@ class _CartonEditorState extends State { fontSize: 20, color: primaryColor, ), - // title: _isNew - // ? 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), @@ -425,21 +364,15 @@ class _CartonEditorState extends State { cartonTypeBox, LocalTitle(textKey: "box.shipment_info"), _isNew ? fcsShipmentsBox : shipmentBox, - isSmallBag - ? _isNew - ? mixCartonsBox - : mixCartonNumberBox - : Container(), + isMixBox ? mixTypeBox : Container(), ...(isMixBox ? [ - // CartonMixTable( - // cartons: _carton.cartons, - // onSelect: (c, check) { - // setState(() { - // c.isChecked = check; - // }); - // }, - // ) + mixcartonTitleBox, + Column( + children: _getMixCartons( + context, + this._mixCartons, + )), ] : [ fcsIDBox, @@ -464,31 +397,6 @@ class _CartonEditorState extends State { context, this._cartons, )), - // cargoTableTitleBox, - // cargoTableBox, - // isSmallBag - // ? Container() - // : LocalTitle(textKey: "box.dimension"), - // isSmallBag ? Container() : cartonSizeDropdown(), - // isSmallBag ? Container() : dimBox, - // isSmallBag ? Container() : shipmentWeightBox, - // LocalTitle(textKey: "box.delivery_address"), - // DefaultDeliveryAddress( - // deliveryAddress: _deliveryAddress, - // labelKey: "box.delivery_address", - // onTap: () async { - // DeliveryAddress _address = await Navigator.push( - // context, - // CupertinoPageRoute( - // builder: (context) => DeliveryAddressList( - // isAdminCreation: true, - // deliveryAddress: _deliveryAddress))); - // if (_address == null) return; - // setState(() { - // _deliveryAddress = _address; - // }); - // }, - // ), ]), SizedBox( height: 20, @@ -512,52 +420,23 @@ class _CartonEditorState extends State { List _getCartons(BuildContext context, List cartons) { return cartons.map((c) { - return Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.grey[300]), - ), + return InkWell( + onTap: () {}, + child: CartonRow( + key: ValueKey(c.id), + box: c, ), - child: InkWell( - onTap: () {}, - child: Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: new Row( - children: [ - new Padding( - padding: - new EdgeInsets.symmetric(horizontal: 15.0 - 5 / 2), - child: Stack( - alignment: AlignmentDirectional.bottomEnd, - children: [ - Icon( - MaterialCommunityIcons.package, - color: primaryColor, - size: 30, - ), - ], - ), - ), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Text( - c.cartonNumber == null ? "" : c.cartonNumber, - style: new TextStyle(fontSize: 15.0), - ), - ], - ), - ), - ], - ), - ), - ), - ], - ), + ); + }).toList(); + } + + List _getMixCartons(BuildContext context, List cartons) { + return cartons.map((c) { + return InkWell( + onTap: () {}, + child: CartonRow( + key: ValueKey(c.id), + box: c, ), ); }).toList(); @@ -642,30 +521,6 @@ class _CartonEditorState extends State { ); } - 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(() { - _carton.cargoTypes.remove(cargo); - _carton.cargoTypes.add(cargo); - }); - } - - _removeCargo(CargoType cargo) { - setState(() { - _carton.cargoTypes.remove(cargo); - }); - } - _save() async { bool isFromShipment = _selectedCartonType == carton_from_shipments; bool isSmallBag = _selectedCartonType == carton_small_bag; @@ -733,7 +588,10 @@ class _CartonEditorState extends State { isDataChanged() { if (_isNew) { - return _fcsShipment != null || _user != null || _cartons.isNotEmpty; + return _fcsShipment != null || + _user != null || + _cartons.isNotEmpty || + this._mixCartons.isNotEmpty; } else { return true; } diff --git a/lib/pages/carton/carton_info.dart b/lib/pages/carton/carton_info.dart index 0cea278..900c426 100644 --- a/lib/pages/carton/carton_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -20,7 +20,7 @@ import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; -import 'carton_cargo_table.dart'; +import 'cargo_table.dart'; import 'carton_editor.dart'; import 'carton_package_table.dart'; import 'model/carton_model.dart'; diff --git a/lib/pages/carton/carton_row.dart b/lib/pages/carton/carton_row.dart new file mode 100644 index 0000000..0c8eb21 --- /dev/null +++ b/lib/pages/carton/carton_row.dart @@ -0,0 +1,100 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; + +typedef OnRemove(Carton carton); + +class CartonRow extends StatelessWidget { + final Carton box; + final OnRemove onRemove; + CartonRow({Key key, this.box, this.onRemove}) : super(key: key); + + final double dotSize = 15.0; + final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.grey[300]), + ), + ), + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 13.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), + ), + ) + ], + ), + ), + ], + ), + ), + ), + Column( + children: [ + onRemove == null + ? Container() + : IconButton( + icon: Icon( + Icons.remove_circle, + color: primaryColor, + ), + onPressed: () { + if (onRemove != null) onRemove(box); + }), + box.actualWeight == 0 + ? Container() + : Padding( + padding: const EdgeInsets.only(left: 8.0, bottom: 5), + child: Row( + children: [ + new Text( + "${box.actualWeight?.toStringAsFixed(2) ?? ''} lb", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ], + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/pages/carton/mix_carton_editor.dart b/lib/pages/carton/mix_carton_editor.dart new file mode 100644 index 0000000..7092d75 --- /dev/null +++ b/lib/pages/carton/mix_carton_editor.dart @@ -0,0 +1,128 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/carton_search/carton_search.dart'; +import 'package:fcs/pages/widgets/local_button.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 'carton_row.dart'; + +class MixCartonEditor extends StatefulWidget { + final Carton box; + MixCartonEditor({this.box}); + + @override + _MixCartonEditorState createState() => _MixCartonEditorState(); +} + +class _MixCartonEditorState extends State { + Carton _box; + bool _isLoading = false; + bool _isNew; + List _cartons = []; + + @override + void initState() { + super.initState(); + + if (widget.box != null) { + _box = widget.box; + _isNew = false; + } else { + _isNew = true; + _box = Carton(cargoTypes: []); + } + } + + @override + Widget build(BuildContext context) { + final createBtn = LocalButton( + textKey: "box.mix_carton_btn", + callBack: _creatCarton, + ); + + final cargoTableTitleBox = LocalTitle( + textKey: "boxes.title", + trailing: IconButton( + icon: Icon( + Icons.add_circle, + color: primaryColor, + ), + onPressed: () => searchCarton(context, callbackCartonSelect: (c) { + _addMixCarton(c); + }), + ), + ); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon( + CupertinoIcons.back, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "box.min_caton.form.title", + fontSize: 20, + color: primaryColor, + ), + ), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView( + children: [ + cargoTableTitleBox, + Column( + children: _getCartons( + context, + this._cartons, + )), + SizedBox( + height: 20, + ), + createBtn + ], + ), + ), + ), + ); + } + + List _getCartons(BuildContext context, List cartons) { + return cartons.map((c) { + return CartonRow( + key: ValueKey(c.id), + box: c, + onRemove: (carton) { + _removeMixCarton(carton); + }, + ); + }).toList(); + } + + _addMixCarton(Carton carton) { + if (carton == null) return; + if (this._cartons.any((c) => c.cartonNumber == carton.cartonNumber)) return; + setState(() { + this._cartons.add(carton); + }); + } + + _removeMixCarton(Carton carton) { + setState(() { + this._cartons.remove(carton); + }); + } + + _creatCarton() {} +} diff --git a/lib/pages/carton/model/carton_model.dart b/lib/pages/carton/model/carton_model.dart index c503249..4d07acf 100644 --- a/lib/pages/carton/model/carton_model.dart +++ b/lib/pages/carton/model/carton_model.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/data/services/services.dart'; import 'package:fcs/domain/constants.dart'; +import 'package:fcs/domain/entities/cargo_type.dart'; import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/vo/message.dart'; import 'package:fcs/domain/vo/shipment_status.dart'; @@ -55,11 +56,8 @@ class CartonModel extends BaseModel { }); } - List cartonTypes = [ - carton_from_packages, - carton_mix_box, - carton_small_bag - ]; + List cartonTypes = [carton_from_packages, carton_mix_box]; + List mixTypes = [mix_delivery, mix_pickup]; List cartonTypesInfo = [ carton_from_packages, carton_mix_box, @@ -220,4 +218,40 @@ class CartonModel extends BaseModel { Future deleteCarton(Carton carton) { return Services.instance.cartonService.deleteCarton(carton); } + + Future> searchCarton(String term) async { + if (term == null || term == '') return List(); + + List _cartons = []; + + try { + _cartons = [ + Carton( + cartonNumber: "A100B-1#1", + cargoTypes: [CargoType(name: "General", weight: 12)], + userName: "Seven 7"), + Carton( + cartonNumber: "A100B-1#2", + cargoTypes: [CargoType(name: "General", weight: 12)], + userName: "Seven 7"), + Carton( + cartonNumber: "A100B-1#3", + cargoTypes: [CargoType(name: "General", weight: 12)], + userName: "Seven 7"), + Carton( + cartonNumber: "A100B-1#4", + cargoTypes: [CargoType(name: "General", weight: 12)], + userName: "Seven 7"), + Carton( + cartonNumber: "A100B-1#5", + cargoTypes: [CargoType(name: "General", weight: 12)], + userName: "Seven 7"), + ]; + } catch (e) { + // permission error + log.warning("user error:" + e.toString()); + return null; + } + return _cartons; + } } diff --git a/lib/pages/carton/package_carton_editor.dart b/lib/pages/carton/package_carton_editor.dart index b54e62f..ddf92a3 100644 --- a/lib/pages/carton/package_carton_editor.dart +++ b/lib/pages/carton/package_carton_editor.dart @@ -86,12 +86,6 @@ class _PackageCartonEditorState extends State { @override Widget build(BuildContext context) { - final shipmentWeightBox = DisplayText( - labelTextKey: "box.shipment_weight", - text: shipmentWeight == null ? "" : shipmentWeight.toStringAsFixed(0), - iconData: MaterialCommunityIcons.weight, - ); - final lengthBox = LengthPicker( controller: _lengthCtl, lableKey: "box.length", @@ -179,7 +173,6 @@ class _PackageCartonEditorState extends State { LocalTitle(textKey: "box.dimension"), cartonSizeDropdown(), dimBox, - shipmentWeightBox, LocalTitle(textKey: "box.delivery_address"), DefaultDeliveryAddress( deliveryAddress: _box.deliveryAddress, diff --git a/lib/pages/carton_search/carton_list_row.dart b/lib/pages/carton_search/carton_list_row.dart new file mode 100644 index 0000000..facdb06 --- /dev/null +++ b/lib/pages/carton_search/carton_list_row.dart @@ -0,0 +1,101 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; + +import 'carton_search.dart'; + +class CartonListRow extends StatefulWidget { + final CallbackCartonSelect callbackCartonSelect; + final Carton carton; + const CartonListRow({this.carton, this.callbackCartonSelect}); + + @override + _CartonListRowState createState() => _CartonListRowState(); +} + +class _CartonListRowState extends State { + final double dotSize = 15.0; + Carton _carton; + @override + void initState() { + super.initState(); + this._carton = widget.carton; + } + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.grey[300]), + ), + ), + child: InkWell( + onTap: () { + Navigator.pop(context); + if (widget.callbackCartonSelect != null) + widget.callbackCartonSelect(widget.carton); + }, + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 13.0), + child: new Row( + children: [ + new Padding( + padding: new EdgeInsets.symmetric( + horizontal: 25.0 - dotSize / 2), + 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( + _carton.cartonNumber ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10.0, top: 10), + child: new Text( + _carton.userName ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ) + ], + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 8.0, bottom: 5, right: 10), + child: Row( + children: [ + new Text( + "${_carton.actualWeight?.toStringAsFixed(2) ?? ''} lb", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/carton_search/carton_search.dart b/lib/pages/carton_search/carton_search.dart new file mode 100644 index 0000000..741fc83 --- /dev/null +++ b/lib/pages/carton_search/carton_search.dart @@ -0,0 +1,122 @@ +import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/carton/model/carton_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:provider/provider.dart'; + +import 'carton_list_row.dart'; + +typedef CallbackCartonSelect(Carton carton); + +Future searchCarton(BuildContext context, + {CallbackCartonSelect callbackCartonSelect}) async => + await showSearch( + context: context, + delegate: PartSearchDelegate(callbackCartonSelect: callbackCartonSelect), + ); + +class PartSearchDelegate extends SearchDelegate { + final CallbackCartonSelect callbackCartonSelect; + PartSearchDelegate({this.callbackCartonSelect}); + + @override + String get searchFieldLabel => 'Search by Carton Number/Customer Name'; + + @override + ThemeData appBarTheme(BuildContext context) { + final ThemeData theme = Theme.of(context); + return theme.copyWith( + inputDecorationTheme: InputDecorationTheme( + hintStyle: TextStyle( + color: theme.primaryTextTheme.caption.color, fontSize: 14)), + textTheme: theme.textTheme.copyWith( + title: theme.textTheme.title.copyWith( + color: theme.primaryTextTheme.title.color, fontSize: 16)), + primaryColor: primaryColor, + ); + } + + @override + List buildActions(BuildContext context) { + return [ + IconButton( + icon: Icon(Icons.clear), + onPressed: () => query = '', + ), + ]; + } + + @override + Widget buildLeading(BuildContext context) { + return IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () => close(context, null), + ); + } + + @override + Widget buildResults(BuildContext context) { + final cartonModel = Provider.of(context); + return FutureBuilder( + future: cartonModel.searchCarton(query), + builder: (context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + if (snapshot.data.length == 0) { + return Container( + child: Center( + child: Text( + "No result found", + textAlign: TextAlign.center, + ), + ), + ); + } + return Container( + padding: EdgeInsets.only(top: 15), + child: ListView( + children: snapshot.data + .map((u) => CartonListRow( + carton: u, + callbackCartonSelect: callbackCartonSelect, + )) + .toList(), + ), + ); + } else if (snapshot.hasError) { + return Container( + child: Center( + child: Text( + '${snapshot.error}', + textAlign: TextAlign.center, + ), + ), + ); + } else { + return Container( + child: Center( + child: CircularProgressIndicator( + valueColor: + new AlwaysStoppedAnimation(primaryColor)), + ), + ); + } + }); + } + + @override + Widget buildSuggestions(BuildContext context) { + return Container( + child: Center( + child: Opacity( + opacity: 0.2, + child: Icon( + MaterialCommunityIcons.package, + color: primaryColor, + size: 200, + ), + ), + ), + ); + } +} diff --git a/lib/pages/rates/custom_list.dart b/lib/pages/rates/custom_list.dart index cf24223..dc65fed 100644 --- a/lib/pages/rates/custom_list.dart +++ b/lib/pages/rates/custom_list.dart @@ -10,8 +10,6 @@ import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; - -import 'custom_row.dart'; import 'model/shipment_rate_model.dart'; class CustomList extends StatefulWidget { @@ -88,7 +86,11 @@ class _CustomListState extends State { }, child: Container( child: _row( - custom.productType, "\$ " + custom.fee.toStringAsFixed(2)), + custom.productType, + "\$ " + custom.fee.toStringAsFixed(2), + custom.shipmentRate == null + ? "" + : "\$ " + custom.shipmentRate.toStringAsFixed(2)), ), ); }), @@ -96,7 +98,7 @@ class _CustomListState extends State { ); } - _row(String desc, String price) { + _row(String desc, String fee, String shipmentRate) { return Container( padding: EdgeInsets.only(left: 25, top: 5, bottom: 5), child: Row( @@ -109,10 +111,19 @@ class _CustomListState extends State { Padding( padding: const EdgeInsets.only(bottom: 3.0), child: Text( - '$price', + '$fee', style: TextStyle(color: primaryColor, fontSize: 14), ), ), + shipmentRate == "" + ? Container() + : Padding( + padding: const EdgeInsets.only(top: 3.0), + child: Text( + "\$ " + "$shipmentRate", + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + ) ], ), SizedBox( diff --git a/lib/pages/widgets/dialog_input.dart b/lib/pages/widgets/dialog_input.dart new file mode 100644 index 0000000..0edb5b5 --- /dev/null +++ b/lib/pages/widgets/dialog_input.dart @@ -0,0 +1,92 @@ +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/material.dart'; +import 'local_text.dart'; + +class DialogInput extends StatefulWidget { + final String value; + final String label; + const DialogInput({Key key, this.label, this.value}) : super(key: key); + @override + _DialogInputState createState() => _DialogInputState(); +} + +class _DialogInputState extends State { + final _formKey = GlobalKey(); + TextEditingController _controller = new TextEditingController(); + + bool _isLoading = false; + + @override + void initState() { + super.initState(); + if (widget.value != null) { + _controller.text = widget.value; + } + } + + @override + Widget build(BuildContext context) { + return LocalProgress( + inAsyncCall: _isLoading, + child: AlertDialog( + title: LocalText( + context, + widget.label, + fontSize: 20, + color: primaryColor, + ), + content: Form( + key: _formKey, + child: TextField( + controller: _controller, + keyboardType: TextInputType.number, + decoration: new InputDecoration( + focusedBorder: UnderlineInputBorder( + borderSide: BorderSide(color: primaryColor, width: 1.0))), + ), + ), + actions: [ + FlatButton( + child: LocalText( + context, + 'btn.cancel', + color: labelColor, + ), + onPressed: () { + _controller.clear(); + Navigator.of(context).pop(); + }), + FlatButton( + color: primaryColor, + child: LocalText( + context, + 'btn.ok', + color: Colors.white, + fontWeight: FontWeight.bold, + ), + onPressed: () async { + if (!_formKey.currentState.validate()) return; + _save(); + }) + ], + ), + ); + } + + _save() { + setState(() { + _isLoading = true; + }); + try { + Navigator.pop(context, _controller.text); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/widgets/status_tree.dart b/lib/pages/widgets/status_tree.dart index 234cba3..27e2e49 100644 --- a/lib/pages/widgets/status_tree.dart +++ b/lib/pages/widgets/status_tree.dart @@ -54,6 +54,7 @@ class StatusTree extends StatelessWidget { e.done || isPacked ? Text(dateFormatter.format(e.date)) : Container(), + e.staffName == null ? Container() : Text(e.staffName) ], ), ),