diff --git a/lib/domain/entities/carton.dart b/lib/domain/entities/carton.dart index 5182116..74235d7 100644 --- a/lib/domain/entities/carton.dart +++ b/lib/domain/entities/carton.dart @@ -167,8 +167,8 @@ class Carton { Map toMap() { var _types = cargoTypes.where((t) => t.weight != 0).toList(); var _cargoTypes = _types.map((c) => c.toMapForCarton()).toList(); - - var _packagesIds = packages.map((c) => c.id).toList(); + + // var _packagesIds = packages.map((c) => c.id).toList(); var _surchareItems = surchareItems.map((c) => c.toMapForSurcharge()).toList(); @@ -184,7 +184,7 @@ class Carton { 'length': length, 'width': width, 'height': height, - 'package_ids': _packagesIds, + // 'package_ids': _packagesIds, 'cargo_types': _cargoTypes, 'surcharge_items': _surchareItems, }; diff --git a/lib/pages/carton/cargo_widget.dart b/lib/pages/carton/cargo_widget.dart index bedc1d5..1c7b4d5 100644 --- a/lib/pages/carton/cargo_widget.dart +++ b/lib/pages/carton/cargo_widget.dart @@ -47,14 +47,18 @@ class _CargoWidgetState extends State { List _cargoTypes = []; List _surchareItems = []; TextEditingController totalCtl = TextEditingController(); + List cargoTypeControllers = []; List surchargeControllers = []; - List _mixCargoTypes = []; - List mixCargoTypeControllers = []; - - bool get isKnownTotalWeight => + bool get hasValueTotalWeight => totalCtl.text.isNotEmpty && totalCtl.text != '0'; + bool get hasValueCargoes => + _cargoTypes.isNotEmpty && _cargoTypes.every((e) => e.weight != 0); + + double get actualTotalWeight => + _cargoTypes.fold(0, (sum, value) => sum + value.weight); + String? error; @override void initState() { @@ -63,25 +67,16 @@ class _CargoWidgetState extends State { } _init() { - totalCtl.addListener(totalInputChangeListener); // for cargo types if (widget.cargoTypes.isNotEmpty) { - List allCargoes = List.from(widget.cargoTypes); - _cargoTypes = allCargoes.where((e) => !e.isMixCargo).toList(); + _cargoTypes = List.from(widget.cargoTypes); for (var e in _cargoTypes) { var editor = TextEditingController(); editor.text = removeTrailingZeros(e.weight); editor.addListener(inputChangeListener); cargoTypeControllers.add(editor); } - _mixCargoTypes = allCargoes.where((e) => e.isMixCargo).toList(); - for (var e in _mixCargoTypes) { - var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); - editor.addListener(inputChangeListener); - mixCargoTypeControllers.add(editor); - } - _calculateTotalWeght(); + onUpdated(); } else { WidgetsBinding.instance.addPostFrameCallback((_) { _openCargoTypeSelection(); @@ -94,7 +89,7 @@ class _CargoWidgetState extends State { for (var e in _surchareItems) { var editor = TextEditingController(); editor.text = e.qty.toString(); - editor.addListener(inputChangeListenerForSurchage); + editor.addListener(inputChangeListener); surchargeControllers.add(editor); } } @@ -104,21 +99,12 @@ class _CargoWidgetState extends State { } } - totalInputChangeListener() { - print("Listen isKnownTotalWeight:$isKnownTotalWeight"); - setState(() {}); - } - - inputChangeListenerForSurchage() { - setState(() {}); - } - _openCargoTypeSelection() async { List? cargoes = await showDialog( context: context, builder: (_) => const CargoTypeAdditionDialog()); if (cargoes == null) return; - _cargoTypes = cargoes.where((e) => !e.isMixCargo).toList(); - _mixCargoTypes = cargoes.where((e) => e.isMixCargo).toList(); + _cargoTypes = cargoes; + _cargoTypes.sort((a, b) => (a == b ? 0 : (a.isMixCargo ? 1 : -1))); for (var e in _cargoTypes) { var editor = TextEditingController(); @@ -127,62 +113,59 @@ class _CargoWidgetState extends State { cargoTypeControllers.add(editor); } - for (var e in _mixCargoTypes) { - var editor = TextEditingController(); - editor.text = '0'; - editor.addListener(inputChangeListener); - mixCargoTypeControllers.add(editor); - } - _calculateTotalWeght(); if (mounted) { setState(() {}); } } - _calculateTotalWeght() { - print("_calculateTotalWeght isKnownTotalWeight:$isKnownTotalWeight"); - double notMixTotal = - _cargoTypes.fold(0, (sum, value) => sum + value.weight); - double mixTotal = - _mixCargoTypes.fold(0, (sum, value) => sum + value.weight); - double total = notMixTotal + mixTotal; - if (isKnownTotalWeight) { - } else { - totalCtl.text = removeTrailingZeros(total); - } + inputChangeListener() { + setState(() {}); } - // bool isFieldEmpty(int index) { - // return cargoTypeControllers[index].text.isEmpty; - // } + List getEmptyFields() { + List emptyFields = []; + for (int i = 0; i < cargoTypeControllers.length; i++) { + if (cargoTypeControllers[i].text.trim().isEmpty || + cargoTypeControllers[i].text.trim() == "0") { + emptyFields.add(i); + } + } + return emptyFields; + } - // List getEmptyFields() { - // List emptyFields = []; - // for (int i = 0; i < cargoTypeControllers.length; i++) { - // if (isFieldEmpty(i)) { - // emptyFields.add(i); - // } - // } - // return emptyFields; - // } + void onUpdated() { + if (!hasValueTotalWeight && hasValueCargoes) { + totalCtl.text = removeTrailingZeros(actualTotalWeight); + error = null; + } else { + // auto populate remaining value + double totalWeight = (double.tryParse(totalCtl.text) ?? 0); - inputChangeListener() { - _cargoTypes.asMap().entries.forEach((e) { - _cargoTypes[e.key].weight = - double.tryParse(cargoTypeControllers[e.key].text) ?? 0; - }); - _mixCargoTypes.asMap().entries.forEach((e) { - _mixCargoTypes[e.key].weight = - double.tryParse(mixCargoTypeControllers[e.key].text) ?? 0; - }); - double notMixTotal = - _cargoTypes.fold(0, (sum, value) => sum + value.weight); - double mixTotal = - _mixCargoTypes.fold(0, (sum, value) => sum + value.weight); - double total = notMixTotal + mixTotal; - setState(() { - totalCtl.text = removeTrailingZeros(total); - }); + if (actualTotalWeight > totalWeight) { + error = "Exceed total weight"; + } else { + error = null; + double remainingWeight = + (totalWeight - actualTotalWeight).clamp(0, totalWeight); + + List emptyFieldIndexes = getEmptyFields(); + + if (emptyFieldIndexes.isNotEmpty) { + if (emptyFieldIndexes.length == 1) { + _cargoTypes.asMap().entries.forEach((e) { + if (e.value.weight == 0) { + e.value.weight = remainingWeight; + cargoTypeControllers[e.key].text = + removeTrailingZeros(e.value.weight); + } + }); + } + } + } + } + if (mounted) { + setState(() {}); + } } @override @@ -218,35 +201,29 @@ class _CargoWidgetState extends State { color: primaryColor, ), onPressed: () async { - List allCargoTypes = _cargoTypes + _mixCargoTypes; CargoType? cargoType = await Navigator.push( context, CupertinoPageRoute( builder: (context) => - CargoTypeAddition(cargoTypes: allCargoTypes))); + CargoTypeAddition(cargoTypes: _cargoTypes))); if (cargoType == null) return; - if (cargoType.isMixCargo) { - _mixCargoTypes.add(cargoType); - mixCargoTypeControllers.clear(); - for (var e in _mixCargoTypes) { - var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); - editor.addListener(inputChangeListener); - mixCargoTypeControllers.add(editor); - } - } else { + if (!cargoType.isMixCargo) { _cargoTypes.add(cargoType); - cargoTypeControllers.clear(); - - for (var e in _cargoTypes) { - var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); - editor.addListener(inputChangeListener); - cargoTypeControllers.add(editor); - } } - _calculateTotalWeght(); + _cargoTypes.sort((a, b) => (a == b ? 0 : (a.isMixCargo ? 1 : -1))); + + if (cargoType.isMixCargo) { + _cargoTypes.add(cargoType); + } + + cargoTypeControllers.clear(); + for (var e in _cargoTypes) { + var editor = TextEditingController(); + editor.text = removeTrailingZeros(e.weight); + editor.addListener(inputChangeListener); + cargoTypeControllers.add(editor); + } if (mounted) { setState(() {}); } @@ -254,154 +231,126 @@ class _CargoWidgetState extends State { ); final cargosBox = Padding( - padding: const EdgeInsets.only(top: 10), + padding: const EdgeInsets.only(top: 5), child: Wrap( alignment: WrapAlignment.spaceBetween, - runSpacing: 15, + runSpacing: 25, children: _cargoTypes.asMap().entries.map((e) { var key = e.key; var c = e.value; return SizedBox( width: MediaQuery.of(context).size.width / 2.3, - child: Row( + child: Column( children: [ - InkResponse( - radius: 23, - onTap: () { - _cargoTypes.removeAt(key); + Row( + children: [ + InkResponse( + radius: 25, + onTap: () { + double totalWeight = + double.tryParse(totalCtl.text) ?? 0; - double totalWeight = - double.tryParse(totalCtl.text) ?? 0; - double removeWeight = - (double.tryParse(cargoTypeControllers[key].text) ?? - 0); + if (actualTotalWeight > totalWeight) { + error = "Exceed total weight"; + } else { + double result = totalWeight - c.weight; + totalCtl.text = removeTrailingZeros(result); + } - if (totalWeight >= removeWeight) { - double result = totalWeight - removeWeight; - totalCtl.text = removeTrailingZeros(result); - } + _cargoTypes.removeAt(key); + cargoTypeControllers.removeAt(key); - cargoTypeControllers[key].clear(); + if (mounted) { + setState(() {}); + } + }, + child: Icon(Feather.minus_circle, color: labelColor)), + const SizedBox(width: 10), + Flexible( + child: inputTextFieldWidget(context, + lableText: c.name ?? "", + controller: cargoTypeControllers[key], + onFieldSubmitted: (value) { + _cargoTypes[e.key].weight = + double.tryParse(value) ?? 0; + onUpdated(); + }, + suffixIcon: InkResponse( + radius: 23, + onTap: () { + double totalWeight = + (double.tryParse(totalCtl.text) ?? 0); - if (mounted) { - setState(() {}); - } - }, - child: Icon(Feather.minus_circle, color: labelColor)), - const SizedBox(width: 10), - Flexible( - child: inputTextFieldWidget(context, - lableText: c.name ?? "", - controller: cargoTypeControllers[key], - suffixIcon: InkResponse( - radius: 23, - onTap: () {}, - child: Icon(Ionicons.md_refresh_circle, - color: labelColor))), + var list = _cargoTypes + .where((e) => e.id != c.id) + .toList(); + double resetValue = totalWeight - + (list.fold(0, + (sum, value) => sum + value.weight)); + setState(() { + e.value.weight = resetValue; + cargoTypeControllers[e.key].text = + removeTrailingZeros(resetValue); + }); + + onUpdated(); + }, + child: Icon(Ionicons.md_refresh_circle, + color: labelColor, size: 22))), + ), + c.isMixCargo + ? InkResponse( + radius: 23, + onTap: () async { + List? cargoes = await showDialog( + context: context, + builder: (_) => MixCargoTypeAdditionDialog( + cargoTypes: c.mixCargoes)); + if (cargoes == null) return; + setState(() { + c.mixCargoes = List.from(cargoes); + }); + }, + child: Icon(Icons.add_circle, + color: labelColor, size: 22)) + : const SizedBox() + ], ), + c.mixCargoes.isEmpty + ? const SizedBox() + : Padding( + padding: const EdgeInsets.only(top: 5), + child: Column( + children: c.mixCargoes.map((e) { + return Padding( + padding: const EdgeInsets.only(top: 12), + child: Row( + children: [ + const SizedBox(width: 25), + InkResponse( + radius: 23, + onTap: () { + setState(() { + c.mixCargoes.remove(e); + }); + }, + child: Icon(Feather.minus_circle, + color: labelColor, size: 20)), + Padding( + padding: const EdgeInsets.only(left: 10), + child: Text(e.name ?? ""), + ), + ], + ), + ); + }).toList()), + ) ], ), ); }).toList()), ); - final mixCargosBox = Wrap( - alignment: WrapAlignment.spaceBetween, - runSpacing: 15, - children: _mixCargoTypes.asMap().entries.map((e) { - var key = e.key; - var c = e.value; - return SizedBox( - width: MediaQuery.of(context).size.width / 2.3, - child: Column( - children: [ - Row( - children: [ - InkResponse( - radius: 23, - onTap: () { - _mixCargoTypes.removeAt(key); - - double totalWeight = - double.tryParse(totalCtl.text) ?? 0; - double removeWeight = (double.tryParse( - mixCargoTypeControllers[key].text) ?? - 0); - - if (totalWeight >= removeWeight) { - double result = totalWeight - removeWeight; - totalCtl.text = removeTrailingZeros(result); - } - - mixCargoTypeControllers[key].clear(); - - if (mounted) { - setState(() {}); - } - }, - child: Icon(Feather.minus_circle, - color: labelColor, size: 20)), - const SizedBox(width: 10), - Flexible( - child: inputTextFieldWidget(context, - lableText: c.name ?? "", - controller: mixCargoTypeControllers[key], - suffixIcon: InkResponse( - radius: 23, - onTap: () {}, - child: Icon(Ionicons.md_refresh_circle, - color: labelColor, size: 22))), - ), - InkResponse( - radius: 23, - onTap: () async { - List? cargoes = await showDialog( - context: context, - builder: (_) => MixCargoTypeAdditionDialog( - cargoTypes: c.mixCargoes)); - if (cargoes == null) return; - setState(() { - c.mixCargoes = List.from(cargoes); - }); - }, - child: - Icon(Icons.add_circle, color: labelColor, size: 22)) - ], - ), - c.mixCargoes.isEmpty - ? const SizedBox() - : Padding( - padding: const EdgeInsets.only(top: 5), - child: Column( - children: c.mixCargoes.map((e) { - return Padding( - padding: const EdgeInsets.only(top: 12), - child: Row( - children: [ - const SizedBox(width: 25), - InkResponse( - radius: 23, - onTap: () { - setState(() { - c.mixCargoes.remove(e); - }); - }, - child: Icon(Feather.minus_circle, - color: labelColor, size: 20)), - Padding( - padding: const EdgeInsets.only(left: 10), - child: Text(e.name ?? ""), - ), - ], - ), - ); - }).toList()), - ) - ], - ), - ); - }).toList()); - final totalWeightBox = Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -421,33 +370,33 @@ class _CargoWidgetState extends State { Flexible( child: inputTextFieldWidget(context, lableText: "Total", - controller: totalCtl, - // onChanged: (neValue) { - // List emptyFields = getEmptyFields(); - // if (emptyFields.length == 1) { - // double totalWeight = double.tryParse(neValue) ?? 0; - - // _cargoTypes.asMap().entries.forEach((e) { - // _cargoTypes[e.key].weight = - // double.tryParse(cargoTypeControllers[e.key].text) ?? - // 0; - // }); - // double result = _cargoTypes.fold( - // 0, (sum, value) => sum + value.weight); - - // if (totalWeight >= result) { - // double remaining = totalWeight - result; - // setState(() { - // cargoTypeControllers[emptyFields.first].text = - // removeTrailingZeros(remaining); - // }); - // } - // } - // }, + controller: totalCtl, onFieldSubmitted: (neValue) { + if (hasValueCargoes) { + double totalWeight = double.tryParse(neValue) ?? 0; + if (totalWeight < actualTotalWeight) { + setState(() { + error = "Invalid total weight"; + }); + } else { + setState(() { + error = null; + }); + } + } else { + onUpdated(); + } + }, suffixIcon: InkResponse( radius: 23, + onTap: () { + setState(() { + totalCtl.text = + removeTrailingZeros(actualTotalWeight); + error = null; + }); + }, child: Icon(Ionicons.md_refresh_circle, - color: labelColor))), + color: labelColor, size: 22))), ), ], )), @@ -485,10 +434,10 @@ class _CargoWidgetState extends State { ); final subChargeItemsBox = Padding( - padding: const EdgeInsets.only(top: 10), + padding: const EdgeInsets.only(top: 5), child: Wrap( alignment: WrapAlignment.spaceBetween, - runSpacing: 15, + runSpacing: 25, children: _surchareItems.asMap().entries.map((e) { var key = e.key; var c = e.value; @@ -532,18 +481,14 @@ class _CargoWidgetState extends State { context, "Error", "Please insert surcharge item quantity"); return; } - - var allCargoes = _cargoTypes + _mixCargoTypes; - - widget.onContinue!(allCargoes, _surchareItems); + widget.onContinue!(_cargoTypes, _surchareItems); } }, ); final previousBtn = PreviousButton(onTap: () { if (widget.onPrevious != null) { - var allCargoes = _cargoTypes + _mixCargoTypes; - widget.onPrevious!(allCargoes, _surchareItems); + widget.onPrevious!(_cargoTypes, _surchareItems); } }); @@ -558,18 +503,15 @@ class _CargoWidgetState extends State { userRow, cargoTitle, cargosBox, - _mixCargoTypes.isNotEmpty && _cargoTypes.isNotEmpty - ? Padding( - padding: const EdgeInsets.symmetric( - horizontal: 100, vertical: 25), - child: Divider(color: Colors.grey.shade300), + const SizedBox(height: 15), + Divider(), + const SizedBox(height: 5), + error != null + ? Text( + error!, + style: TextStyle(color: dangerColor), ) : const SizedBox(), - mixCargosBox, - Padding( - padding: const EdgeInsets.symmetric(vertical: 25), - child: Divider(color: Colors.grey.shade300), - ), totalWeightBox, subchargeItemTitleBox, subChargeItemsBox, @@ -599,6 +541,7 @@ class _CargoWidgetState extends State { {required String lableText, TextEditingController? controller, Function(String)? onChanged, + Function(String)? onFieldSubmitted, bool readOnly = false, Widget? suffixIcon}) { return TextFormField( @@ -607,6 +550,7 @@ class _CargoWidgetState extends State { cursorColor: primaryColor, keyboardType: TextInputType.number, onChanged: onChanged, + onFieldSubmitted: onFieldSubmitted, readOnly: readOnly, decoration: InputDecoration( suffixIcon: suffixIcon, diff --git a/lib/pages/carton/carton_info.dart b/lib/pages/carton/carton_info.dart index 5754636..8bbb089 100644 --- a/lib/pages/carton/carton_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -294,7 +294,7 @@ class _CartonInfoState extends State { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Container( - color: e.key.isEven ? Colors.grey.shade300 : oddColor, + color: e.key.isEven ? Colors.grey.shade200 : oddColor, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -325,7 +325,9 @@ class _CartonInfoState extends State { vertical: 2), child: Text( "- ${c.name}", - style: TextStyle(fontSize: 14), + style: TextStyle( + fontSize: 14, + color: labelColor), ), ); }).toList()), @@ -357,7 +359,7 @@ class _CartonInfoState extends State { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Container( - color: e.key.isEven ? Colors.grey.shade300 : oddColor, + color: e.key.isEven ? Colors.grey.shade200 : oddColor, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/pages/carton/carton_submit.dart b/lib/pages/carton/carton_submit.dart index 2ac3efc..e492562 100644 --- a/lib/pages/carton/carton_submit.dart +++ b/lib/pages/carton/carton_submit.dart @@ -264,37 +264,120 @@ class CartonSubmit extends StatelessWidget { children: cargoTypes.map((e) { return Padding( padding: const EdgeInsets.symmetric(vertical: 3), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - e.name ?? "", - style: - TextStyle(color: Colors.black, fontSize: 15), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e.name ?? "", + style: TextStyle( + color: Colors.black, fontSize: 15), + ), + Text("${removeTrailingZeros(e.weight)} lb", + style: TextStyle( + color: Colors.black, fontSize: 15)) + ], ), - Text("${removeTrailingZeros(e.weight)} lb", - style: TextStyle( - color: Colors.black, fontSize: 15)) + e.isMixCargo + ? Padding( + padding: const EdgeInsets.only(left: 20), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: e.mixCargoes.map((c) { + return Padding( + padding: const EdgeInsets.symmetric( + vertical: 2), + child: Text( + "- ${c.name}", + style: TextStyle( + fontSize: 14, + color: labelColor), + ), + ); + }).toList()), + ) + : const SizedBox() ], ), ); }).toList()), - const SizedBox(height: 10), + // const SizedBox(height: 10), + // Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: surchareItems.map((e) { + // return Padding( + // padding: const EdgeInsets.symmetric(vertical: 3), + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // e.name ?? "", + // style: TextStyle(color: labelColor, fontSize: 15), + // ), + // Text("${numberFormatter.format(e.qty)} pc", + // style: + // TextStyle(color: labelColor, fontSize: 15)) + // ], + // ), + // ); + // }).toList()), + ], + ), + ), + ), + ]), + ); + + final surChargeItemsBox = Padding( + padding: const EdgeInsets.only(top: 10), + child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + Padding( + padding: const EdgeInsets.only(left: 5, bottom: 5, right: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LocalText(context, 'box.input_surcharge_item', + color: primaryColor, + fontSize: 16, + fontWeight: FontWeight.normal), + ], + ), + ), + Container( + decoration: BoxDecoration( + border: Border.all(color: primaryColor), + borderRadius: BorderRadius.circular(5), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: surchareItems.map((e) { return Padding( padding: const EdgeInsets.symmetric(vertical: 3), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - e.name ?? "", - style: TextStyle(color: labelColor, fontSize: 15), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + e.name ?? "", + style: TextStyle( + color: Colors.black, fontSize: 15), + ), + Text( + "${removeTrailingZeros((e.qty).toDouble())} pc", + textAlign: TextAlign.end, + style: TextStyle( + color: Colors.black, fontSize: 15)) + ], ), - Text("${numberFormatter.format(e.qty)} pc", - style: - TextStyle(color: labelColor, fontSize: 15)) ], ), ); @@ -368,6 +451,8 @@ class CartonSubmit extends StatelessWidget { packages.isNotEmpty ? packagesBox : const SizedBox(), const SizedBox(height: 10), cargosBox, + const SizedBox(height: 10), + surChargeItemsBox, const SizedBox(height: 20), ], ),