// ignore_for_file: unused_local_variable import 'package:fcs/helpers/theme.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; import '../../domain/entities/cargo_type.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; import '../widgets/continue_button.dart'; import '../widgets/local_title.dart'; import '../widgets/previous_button.dart'; import 'cargo_type_addition.dart'; import 'cargo_type_addition_dialog.dart'; import 'mix_cargo_type_addition_dialog.dart'; import 'surcharge_item_addition.dart'; typedef OnPrevious = Function( List cargoTypes, List customDuties); typedef OnContinue = Function( List cargoTypes, List customDuties); class CargoWidget extends StatefulWidget { final User sender; final User consignee; final List cargoTypes; final List surchargeItems; final OnPrevious? onPrevious; final OnContinue? onContinue; const CargoWidget({ super.key, required this.cargoTypes, required this.surchargeItems, this.onPrevious, this.onContinue, required this.sender, required this.consignee, }); @override State createState() => _CargoWidgetState(); } class _CargoWidgetState extends State { List _cargoTypes = []; List _surchareItems = []; TextEditingController totalCtl = TextEditingController(); List cargoTypeControllers = []; List surchargeControllers = []; List _mixCargoTypes = []; List mixCargoTypeControllers = []; bool get isKnownTotalWeight => totalCtl.text.isNotEmpty && totalCtl.text != '0'; @override void initState() { _init(); super.initState(); } _init() { totalCtl.addListener(totalInputChangeListener); // for cargo types if (widget.cargoTypes.isNotEmpty) { List allCargoes = List.from(widget.cargoTypes); _cargoTypes = allCargoes.where((e) => !e.isMixCargo).toList(); 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(); } else { WidgetsBinding.instance.addPostFrameCallback((_) { _openCargoTypeSelection(); }); } //for surcharge items if (widget.surchargeItems.isNotEmpty) { _surchareItems = List.from(widget.surchargeItems); for (var e in _surchareItems) { var editor = TextEditingController(); editor.text = e.qty.toString(); editor.addListener(inputChangeListenerForSurchage); surchargeControllers.add(editor); } } if (mounted) { setState(() {}); } } 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(); for (var e in _cargoTypes) { var editor = TextEditingController(); editor.text = '0'; editor.addListener(inputChangeListener); 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); } } // bool isFieldEmpty(int index) { // return cargoTypeControllers[index].text.isEmpty; // } // List getEmptyFields() { // List emptyFields = []; // for (int i = 0; i < cargoTypeControllers.length; i++) { // if (isFieldEmpty(i)) { // emptyFields.add(i); // } // } // return emptyFields; // } 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); }); } @override Widget build(BuildContext context) { final senderBox = userDisplayBox(context, lableKey: "box.sender.title", icon: MaterialCommunityIcons.account_arrow_right, showLink: false, name: widget.sender.name ?? "", fcsID: widget.sender.fcsID ?? ""); final consigneeBox = userDisplayBox(context, showLink: false, lableKey: "box.consignee.title", icon: MaterialCommunityIcons.account_arrow_left, name: widget.consignee.name, fcsID: widget.consignee.fcsID); final userRow = Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(flex: 2, child: consigneeBox), Flexible(child: senderBox) ], ); final cargoTitle = LocalTitle( textKey: "box.input_cargo_weight", topPadding: 0, trailing: IconButton( icon: Icon( Icons.add_circle, color: primaryColor, ), onPressed: () async { List allCargoTypes = _cargoTypes + _mixCargoTypes; CargoType? cargoType = await Navigator.push( context, CupertinoPageRoute( builder: (context) => CargoTypeAddition(cargoTypes: allCargoTypes))); 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 { _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(); if (mounted) { setState(() {}); } }), ); final cargosBox = Padding( padding: const EdgeInsets.only(top: 10), child: Wrap( alignment: WrapAlignment.spaceBetween, runSpacing: 15, 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( children: [ InkResponse( radius: 23, onTap: () { _cargoTypes.removeAt(key); double totalWeight = double.tryParse(totalCtl.text) ?? 0; double removeWeight = (double.tryParse(cargoTypeControllers[key].text) ?? 0); if (totalWeight >= removeWeight) { double result = totalWeight - removeWeight; totalCtl.text = removeTrailingZeros(result); } 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], suffixIcon: InkResponse( radius: 23, onTap: () {}, child: Icon(Ionicons.md_refresh_circle, color: labelColor))), ), ], ), ); }).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: [ SizedBox( width: MediaQuery.of(context).size.width / 2.3, child: Row( children: [ InkResponse( radius: 25, onTap: () { setState(() { totalCtl.clear(); }); }, child: Icon(MaterialIcons.clear, color: labelColor)), const SizedBox(width: 10), 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); // }); // } // } // }, suffixIcon: InkResponse( radius: 23, child: Icon(Ionicons.md_refresh_circle, color: labelColor))), ), ], )), ], ); final subchargeItemTitleBox = LocalTitle( textKey: "box.input_surcharge_item", trailing: IconButton( icon: Icon( Icons.add_circle, color: primaryColor, ), onPressed: () async { CargoType? surchargeItem = await Navigator.push( context, CupertinoPageRoute( builder: (context) => SurchargeItemAddition(items: _surchareItems))); if (surchargeItem == null) return; _surchareItems.add(surchargeItem); surchargeControllers.clear(); _surchareItems.asMap().entries.forEach((e) { var editor = TextEditingController(); editor.text = e.value.qty.toString(); surchargeControllers.add(editor); }); if (mounted) { setState(() {}); } }), ); final subChargeItemsBox = Padding( padding: const EdgeInsets.only(top: 10), child: Wrap( alignment: WrapAlignment.spaceBetween, runSpacing: 15, children: _surchareItems.asMap().entries.map((e) { var key = e.key; var c = e.value; return SizedBox( width: MediaQuery.of(context).size.width / 2.3, child: Row( children: [ InkResponse( radius: 25, onTap: () { setState(() { _surchareItems.removeAt(key); }); }, child: Icon(Feather.minus_circle, color: labelColor)), const SizedBox(width: 10), Flexible( child: inputTextFieldWidget( context, lableText: c.name ?? "", controller: surchargeControllers[key], onChanged: (newValue) { setState(() { _surchareItems[key].qty = int.tryParse(newValue) ?? 0; }); }, ), ), ], ), ); }).toList()), ); final continueBtn = ContinueButton( onTap: () { if (widget.onContinue != null) { if (_surchareItems.isNotEmpty && _surchareItems.any((item) => item.qty == 0)) { showMsgDialog( context, "Error", "Please insert surcharge item quantity"); return; } var allCargoes = _cargoTypes + _mixCargoTypes; widget.onContinue!(allCargoes, _surchareItems); } }, ); final previousBtn = PreviousButton(onTap: () { if (widget.onPrevious != null) { var allCargoes = _cargoTypes + _mixCargoTypes; widget.onPrevious!(allCargoes, _surchareItems); } }); return Column( children: [ Expanded( child: Padding( padding: EdgeInsets.only(left: 10, right: 10), child: ListView( children: [ const SizedBox(height: 8), userRow, cargoTitle, cargosBox, _mixCargoTypes.isNotEmpty && _cargoTypes.isNotEmpty ? Padding( padding: const EdgeInsets.symmetric( horizontal: 100, vertical: 25), child: Divider(color: Colors.grey.shade300), ) : const SizedBox(), mixCargosBox, Padding( padding: const EdgeInsets.symmetric(vertical: 25), child: Divider(color: Colors.grey.shade300), ), totalWeightBox, subchargeItemTitleBox, subChargeItemsBox, const SizedBox(height: 30), ], ), ), ), widget.onContinue != null ? Padding( padding: const EdgeInsets.only(left: 15, right: 15, top: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ previousBtn, continueBtn, ], ), ) : const SizedBox(), const SizedBox(height: 20) ], ); } Widget inputTextFieldWidget(BuildContext context, {required String lableText, TextEditingController? controller, Function(String)? onChanged, bool readOnly = false, Widget? suffixIcon}) { return TextFormField( controller: controller, style: textStyle, cursorColor: primaryColor, keyboardType: TextInputType.number, onChanged: onChanged, readOnly: readOnly, decoration: InputDecoration( suffixIcon: suffixIcon, contentPadding: EdgeInsets.all(0), labelText: lableText, labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: primaryColor, width: 1.0)), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: primaryColor, width: 1.0)), disabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: primaryColor, width: 1.0)), ), ); } }