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 'package:provider/provider.dart'; import '../../domain/entities/cargo_type.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; import '../rates/model/shipment_rate_model.dart'; import '../widgets/continue_button.dart'; import '../widgets/display_text.dart'; import '../widgets/local_title.dart'; import '../widgets/previous_button.dart'; import 'cargo_type_addition.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({ Key? key, required this.cargoTypes, required this.surchargeItems, this.onPrevious, this.onContinue, required this.sender, required this.consignee, }) : super(key: key); @override State createState() => _CargoWidgetState(); } class _CargoWidgetState extends State { List _cargoTypes = []; List _surchareItems = []; TextEditingController _totalCtl = TextEditingController(); List _cargoTypeControllers = []; List _surchargeControllers = []; @override void initState() { _init(); super.initState(); } _init() { // for cargo types if (widget.cargoTypes.isNotEmpty) { _cargoTypes = List.from(widget.cargoTypes); _cargoTypes.forEach((e) { var editor = new TextEditingController(); editor.text = removeTrailingZeros(e.weight); editor.addListener(inputChangeListener); _cargoTypeControllers.add(editor); }); _calculateTotalWeght(); } else { var model = context.read(); var cargoes = model.rate.cargoTypes.map((e) => e.clone()).toList(); _cargoTypes = cargoes.where((e) => e.isDefault).toList(); _cargoTypes.forEach((e) { var editor = new TextEditingController(); editor.text = ''; editor.addListener(inputChangeListener); _cargoTypeControllers.add(editor); }); } //for surcharge items if (widget.surchargeItems.isNotEmpty) { _surchareItems = List.from(widget.surchargeItems); _surchareItems.forEach((e) { var editor = new TextEditingController(); editor.text = e.qty.toString(); editor.addListener(inputChangeListener); _surchargeControllers.add(editor); }); } if (mounted) { setState(() {}); } } _calculateTotalWeght() { double total = _cargoTypes.fold(0, (sum, value) => sum + value.weight); _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() { List emptyFields = getEmptyFields(); if (emptyFields.isEmpty) { _cargoTypes.asMap().entries.forEach((e) { _cargoTypes[e.key].weight = double.tryParse(_cargoTypeControllers[e.key].text) ?? 0; }); double total = _cargoTypes.fold(0, (sum, value) => sum + value.weight); setState(() { _totalCtl.text = removeTrailingZeros(total); }); } } @override Widget build(BuildContext context) { final senderBox = DisplayText( text: widget.sender.name, labelTextKey: "box.sender.title", iconData: MaterialCommunityIcons.account_arrow_right, subText: Text(widget.sender.fcsID!, style: TextStyle(fontSize: 13, color: labelColor)), ); final consigneeBox = DisplayText( text: widget.consignee.name, labelTextKey: "box.consignee.title", iconData: MaterialCommunityIcons.account_arrow_left, subText: Text(widget.consignee.fcsID!, style: TextStyle(fontSize: 13, color: labelColor)), ); final userRow = Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: senderBox, flex: 2), Flexible(child: consigneeBox) ], ); final cargoTitle = LocalTitle( textKey: "box.input_cargo_weight", topPadding: 0, trailing: IconButton( icon: Icon( Icons.add_circle, color: primaryColor, ), onPressed: () async { CargoType? cargoType = await Navigator.push( context, CupertinoPageRoute( builder: (context) => CargoTypeAddition(cargoTypes: _cargoTypes))); if (cargoType == null) return; _cargoTypes.add(cargoType); _cargoTypeControllers.clear(); _cargoTypes.forEach((e) { var editor = new TextEditingController(); editor.text = removeTrailingZeros(e.weight); editor.addListener(inputChangeListener); _cargoTypeControllers.add(editor); }); _calculateTotalWeght(); if (mounted) { setState(() {}); } }), ); final cargosBox = 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: 25, 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]), ), ], ), ); }).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, readOnly: getEmptyFields().isEmpty, 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); }); } } }), ), ], )), ], ); 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 = new TextEditingController(); editor.text = e.value.qty.toString(); _surchargeControllers.add(editor); }); if (mounted) { setState(() {}); } }), ); final subChargeItemsBox = 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; } widget.onContinue!(_cargoTypes, _surchareItems); } }, ); final previousBtn = PreviousButton(onTap: () { if (widget.onPrevious != null) { widget.onPrevious!(_cargoTypes, _surchareItems); } }); return Column( children: [ Expanded( child: Padding( padding: EdgeInsets.only(left: 10, right: 10), child: ListView( children: [ const SizedBox(height: 8), userRow, cargoTitle, cargosBox, const SizedBox(height: 15), Divider(), const SizedBox(height: 5), 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}) { return TextFormField( controller: controller, style: textStyle, cursorColor: primaryColor, keyboardType: TextInputType.number, onChanged: onChanged, readOnly: readOnly, decoration: new InputDecoration( 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)), ), ); } }