diff --git a/lib/domain/entities/cargo_type.dart b/lib/domain/entities/cargo_type.dart index 22cd0dd..29a49ab 100644 --- a/lib/domain/entities/cargo_type.dart +++ b/lib/domain/entities/cargo_type.dart @@ -1,3 +1,5 @@ +import 'package:fcs/pages/main/util.dart'; + class CargoType { String? id; String? name; @@ -96,7 +98,7 @@ class CargoType { Map toMapForCarton() { return { "id": id, - 'weight': weight, + 'weight': double.tryParse(twoDecimalFormatted(weight)) ?? 0.00, "mix_cargo_type_ids": mixCargoes.map((e) => e.id).toList() }; } @@ -109,6 +111,22 @@ class CargoType { return CargoType.fromMap(toMap(), id!); } + CargoType cloneForCarton() { + return CargoType( + id: id, + name: name, + weight: weight, + isDefault: isDefault, + displayIndex: displayIndex, + isMixCargo: isMixCargo, + mixCargoIds: List.from(mixCargoIds), + mixCargoes: List.from(mixCargoes)); + } + + CargoType cloneForSurchage() { + return CargoType(id: id, name: name, qty: qty); + } + @override bool operator ==(Object other) => other is CargoType && other.id == id; diff --git a/lib/pages/carton/cargo_widget.dart b/lib/pages/carton/cargo_widget.dart index 1c7b4d5..33016d5 100644 --- a/lib/pages/carton/cargo_widget.dart +++ b/lib/pages/carton/cargo_widget.dart @@ -52,9 +52,9 @@ class _CargoWidgetState extends State { List surchargeControllers = []; bool get hasValueTotalWeight => - totalCtl.text.isNotEmpty && totalCtl.text != '0'; + totalCtl.text.isNotEmpty && totalCtl.text != '0.00'; bool get hasValueCargoes => - _cargoTypes.isNotEmpty && _cargoTypes.every((e) => e.weight != 0); + _cargoTypes.isNotEmpty && _cargoTypes.every((e) => e.weight != 0.00); double get actualTotalWeight => _cargoTypes.fold(0, (sum, value) => sum + value.weight); @@ -72,11 +72,12 @@ class _CargoWidgetState extends State { _cargoTypes = List.from(widget.cargoTypes); for (var e in _cargoTypes) { var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); + editor.text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros(e.weight)) ?? 0); editor.addListener(inputChangeListener); cargoTypeControllers.add(editor); } - onUpdated(); + _onPopulate(); } else { WidgetsBinding.instance.addPostFrameCallback((_) { _openCargoTypeSelection(); @@ -108,11 +109,14 @@ class _CargoWidgetState extends State { for (var e in _cargoTypes) { var editor = TextEditingController(); - editor.text = '0'; + editor.text = '0.00'; editor.addListener(inputChangeListener); cargoTypeControllers.add(editor); } + totalCtl.text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros(actualTotalWeight)) ?? 0); + if (mounted) { setState(() {}); } @@ -133,9 +137,10 @@ class _CargoWidgetState extends State { return emptyFields; } - void onUpdated() { + void _onPopulate() { if (!hasValueTotalWeight && hasValueCargoes) { - totalCtl.text = removeTrailingZeros(actualTotalWeight); + totalCtl.text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros(actualTotalWeight)) ?? 0); error = null; } else { // auto populate remaining value @@ -155,8 +160,8 @@ class _CargoWidgetState extends State { _cargoTypes.asMap().entries.forEach((e) { if (e.value.weight == 0) { e.value.weight = remainingWeight; - cargoTypeControllers[e.key].text = - removeTrailingZeros(e.value.weight); + cargoTypeControllers[e.key].text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros(e.value.weight)) ?? 0); } }); } @@ -168,6 +173,18 @@ class _CargoWidgetState extends State { } } + void _onCheckTotalWeight(String value) { + double totalWeight = double.tryParse(value) ?? 0; + if (totalWeight != actualTotalWeight) { + error = "Invalid total weight"; + } else { + error = null; + } + if (mounted) { + setState(() {}); + } + } + @override Widget build(BuildContext context) { final senderBox = userDisplayBox(context, @@ -208,19 +225,30 @@ class _CargoWidgetState extends State { CargoTypeAddition(cargoTypes: _cargoTypes))); if (cargoType == null) return; - if (!cargoType.isMixCargo) { - _cargoTypes.add(cargoType); - } - _cargoTypes.sort((a, b) => (a == b ? 0 : (a.isMixCargo ? 1 : -1))); - + // add cargo type if (cargoType.isMixCargo) { - _cargoTypes.add(cargoType); + int lastTrueIndex = + _cargoTypes.lastIndexWhere((e) => e.isMixCargo); + if (lastTrueIndex != -1) { + _cargoTypes.insert(lastTrueIndex + 1, cargoType); + } else { + _cargoTypes.add(cargoType); + } + } else { + int lastFalseIndex = + _cargoTypes.lastIndexWhere((e) => !e.isMixCargo); + if (lastFalseIndex != -1) { + _cargoTypes.insert(lastFalseIndex + 1, cargoType); + } else { + _cargoTypes.insert(0, cargoType); + } } cargoTypeControllers.clear(); for (var e in _cargoTypes) { var editor = TextEditingController(); - editor.text = removeTrailingZeros(e.weight); + editor.text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros(e.weight)) ?? 0); editor.addListener(inputChangeListener); cargoTypeControllers.add(editor); } @@ -230,177 +258,53 @@ class _CargoWidgetState extends State { }), ); - final cargosBox = Padding( + final totalWeightBox = Padding( padding: const EdgeInsets.only(top: 5), - child: Wrap( - alignment: WrapAlignment.spaceBetween, - runSpacing: 25, - children: _cargoTypes.asMap().entries.map((e) { - var key = e.key; - var c = e.value; - return SizedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( width: MediaQuery.of(context).size.width / 2.3, - child: Column( + child: Row( children: [ - Row( - children: [ - InkResponse( - radius: 25, - onTap: () { - double totalWeight = - double.tryParse(totalCtl.text) ?? 0; - - if (actualTotalWeight > totalWeight) { - error = "Exceed total weight"; - } else { - double result = totalWeight - c.weight; - totalCtl.text = removeTrailingZeros(result); - } - - _cargoTypes.removeAt(key); - cargoTypeControllers.removeAt(key); - - 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); - - 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 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, onFieldSubmitted: (neValue) { - if (hasValueCargoes) { - double totalWeight = double.tryParse(neValue) ?? 0; - if (totalWeight < actualTotalWeight) { + InkResponse( + radius: 25, + onTap: () { setState(() { - error = "Invalid total weight"; + totalCtl.clear(); }); + _onCheckTotalWeight(totalCtl.text); + }, + child: Icon(MaterialIcons.clear, color: labelColor)), + const SizedBox(width: 10), + Flexible( + child: inputTextFieldWidget(context, + lableText: "Total", + controller: totalCtl, onFieldSubmitted: (newValue) { + if (hasValueCargoes) { + _onCheckTotalWeight(newValue); } else { - setState(() { - error = null; - }); + _onPopulate(); } - } else { - onUpdated(); - } - }, - suffixIcon: InkResponse( - radius: 23, - onTap: () { - setState(() { - totalCtl.text = - removeTrailingZeros(actualTotalWeight); - error = null; - }); - }, - child: Icon(Ionicons.md_refresh_circle, - color: labelColor, size: 22))), - ), - ], - )), - ], + }, + suffixIcon: InkResponse( + radius: 23, + onTap: () { + setState(() { + totalCtl.text = twoDecimalFormatted( + double.tryParse(removeTrailingZeros( + actualTotalWeight)) ?? + 0); + error = null; + }); + }, + child: Icon(Ionicons.md_refresh_circle, + color: labelColor, size: 22))), + ), + ], + )), + ], + ), ); final subchargeItemTitleBox = LocalTitle( @@ -481,17 +385,161 @@ class _CargoWidgetState extends State { context, "Error", "Please insert surcharge item quantity"); return; } + + if (error != null) { + showMsgDialog( + context, "Error", "Please add the right cargo type weight"); + return; + } widget.onContinue!(_cargoTypes, _surchareItems); } }, ); final previousBtn = PreviousButton(onTap: () { + if (error != null) { + showMsgDialog( + context, "Error", "Please add the right cargo type weight"); + return; + } if (widget.onPrevious != null) { widget.onPrevious!(_cargoTypes, _surchareItems); } }); + Widget cargoesWidget(List items) { + List widgets = []; + for (int i = 0; i < items.length; i++) { + var key = i; + var c = items[i]; + + if (i > 0 && (!items[i - 1].isMixCargo && items[i].isMixCargo)) { + widgets.add(Padding( + padding: const EdgeInsets.symmetric(horizontal: 70), + child: Divider(color: Colors.grey.shade300))); + } + + widgets.add(SizedBox( + width: MediaQuery.of(context).size.width / 2.3, + child: Column( + children: [ + Row( + children: [ + InkResponse( + radius: 25, + onTap: () { + _cargoTypes.removeAt(key); + cargoTypeControllers.removeAt(key); + + _onCheckTotalWeight(totalCtl.text); + + 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[key].weight = double.tryParse(value) ?? 0; + _onPopulate(); + }, + suffixIcon: InkResponse( + radius: 23, + onTap: () { + double totalWeight = + (double.tryParse(totalCtl.text) ?? 0); + + var list = _cargoTypes + .where((e) => e.id != c.id) + .toList(); + double sum = (list.fold( + 0, (sum, value) => sum + value.weight)); + + if (sum > totalWeight) { + error = "Exceed total weight"; + } else { + error = null; + double resetValue = totalWeight - sum; + + setState(() { + c.weight = resetValue; + cargoTypeControllers[key].text = + twoDecimalFormatted(double.tryParse( + removeTrailingZeros( + resetValue)) ?? + 0); + }); + _onPopulate(); + } + }, + 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()), + ) + ], + ), + )); + } + + return Padding( + padding: const EdgeInsets.only(top: 5), + child: Wrap( + alignment: WrapAlignment.spaceBetween, + runSpacing: 25, + children: widgets), + ); + } + return Column( children: [ Expanded( @@ -502,9 +550,13 @@ class _CargoWidgetState extends State { const SizedBox(height: 8), userRow, cargoTitle, - cargosBox, + cargoesWidget(_cargoTypes), const SizedBox(height: 15), - Divider(), + _cargoTypes.isNotEmpty + ? Divider( + color: Colors.grey.shade300, + ) + : const SizedBox(), const SizedBox(height: 5), error != null ? Text( @@ -553,7 +605,11 @@ class _CargoWidgetState extends State { onFieldSubmitted: onFieldSubmitted, readOnly: readOnly, decoration: InputDecoration( - suffixIcon: suffixIcon, + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 8), + child: suffixIcon, + ), + suffixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0), contentPadding: EdgeInsets.all(0), labelText: lableText, labelStyle: newLabelStyle(color: Colors.black54, fontSize: 17), diff --git a/lib/pages/carton/carton_info.dart b/lib/pages/carton/carton_info.dart index 8bbb089..4ddbc29 100644 --- a/lib/pages/carton/carton_info.dart +++ b/lib/pages/carton/carton_info.dart @@ -7,7 +7,6 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/carton/carton_image_upload_editor.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -28,6 +27,7 @@ import 'carton_package_editor.dart'; import 'mix_carton/mix_carton_editor.dart'; import 'mix_carton_detail_list.dart'; import 'model/carton_model.dart'; +import 'model/package_selection_model.dart'; import 'package_detail_list.dart'; import 'print_qr_code_page.dart'; @@ -48,10 +48,11 @@ class _CartonInfoState extends State { List _cargoTypes = []; List _surchareItems = []; List _mixCartons = []; - List _packages = []; - double totalWeight = 0.0; - double totalSurchargeCount = 0.0; - CartonSize? standardSize; + + double _totalWeight = 0.0; + int _packageCount = 0; + + CartonSize? _standardSize; FcsShipment? _shipment; @override @@ -77,7 +78,7 @@ class _CartonInfoState extends State { bool isStandartSize = sameLength && sameWidth && sameHeight; if (isStandartSize) { _carton.cartonSizeType = standardCarton; - standardSize = cartonSizes.firstWhere((size) => + _standardSize = cartonSizes.firstWhere((size) => size.length == _carton.length && size.width == _carton.width && size.height == _carton.height); @@ -89,32 +90,11 @@ class _CartonInfoState extends State { _carton.cartonSizeType = customCarton; } - if (widget.carton.fcsShipmentID != null && - widget.carton.fcsShipmentID != '') { - var s = await context - .read() - .getFcsShipment(widget.carton.fcsShipmentID!); - _shipment = s; - } + await Future.wait( + [_loadFcsShipment(), _loadPackageCount(), _loadMixCargoes()]); - if (_carton.cartonType == carton_from_packages) { - _packages = await context - .read() - .getPackagesByIds(_carton.packageIDs); - } - - if (_carton.cartonType == mix_carton) { - _mixCartons = await context - .read() - .getCartonsByIds(_carton.cartonIDs); - _cargoTypes.sort((a, b) => a.name!.compareTo(b.name!)); - _surchareItems.sort((a, b) => a.name!.compareTo(b.name!)); - } - - totalWeight = + _totalWeight = _carton.cargoTypes.fold(0, (sum, value) => sum + value.weight); - totalSurchargeCount = - _surchareItems.fold(0, (sum, value) => sum + value.qty); } finally { _isLoading = false; } @@ -124,12 +104,50 @@ class _CartonInfoState extends State { } } + Future _loadFcsShipment() async { + if (widget.carton.fcsShipmentID != null && + widget.carton.fcsShipmentID != '') { + var s = await context + .read() + .getFcsShipment(widget.carton.fcsShipmentID!); + _shipment = s; + if (mounted) { + setState(() {}); + } + } + } + + Future _loadPackageCount() async { + if (_carton.cartonType == carton_from_packages) { + int? count = await context.read().getPackageCount( + senderId: widget.carton.senderID ?? "", + consigneeId: widget.carton.consigneeID ?? "", + shipmentId: widget.carton.fcsShipmentID ?? ""); + _packageCount = count ?? 0; + if (mounted) { + setState(() {}); + } + } + } + + Future _loadMixCargoes() async { + if (_carton.cartonType == mix_carton) { + _mixCartons = + await context.read().getCartonsByIds(_carton.cartonIDs); + _cargoTypes.sort((a, b) => a.name!.compareTo(b.name!)); + _surchareItems.sort((a, b) => a.name!.compareTo(b.name!)); + if (mounted) { + setState(() {}); + } + } + } + @override Widget build(BuildContext context) { var fromPackage = _carton.cartonType == carton_from_packages; String? boxDimension = _carton.cartonSizeType == standardCarton - ? "${standardSize?.name} - ${standardSize?.length.toInt()}”x${standardSize?.width.toInt()}”x${standardSize?.height.toInt()}”" + ? "${_standardSize?.name} - ${_standardSize?.length.toInt()}”x${_standardSize?.width.toInt()}”x${_standardSize?.height.toInt()}”" : _carton.cartonSizeType == customCarton ? "${_carton.length.toInt()}”x${_carton.width.toInt()}”x${_carton.height.toInt()}”" : null; @@ -178,15 +196,19 @@ class _CartonInfoState extends State { final packageLengthBox = DisplayText( showLabelLink: true, - subText: Text(numberFormatter.format(_packages.length)), + subText: Text(numberFormatter.format(_packageCount)), labelTextKey: "box.package", onTapLabel: () { Navigator.push( context, CupertinoPageRoute( builder: (context) => PackageDetailList( - cartonNumber: _carton.cartonNumber ?? '', - packages: _packages))); + cartonNumber: _carton.cartonNumber ?? '', + packageCount: _packageCount, + senderID: _carton.senderID ?? "", + consingeeID: _carton.consigneeID ?? "", + fcsShipmentID: _carton.fcsShipmentID ?? "", + ))); }, ); @@ -278,7 +300,8 @@ class _CartonInfoState extends State { _cargoTypes.isNotEmpty ? Padding( padding: EdgeInsets.only(right: 0), - child: Text("${removeTrailingZeros(totalWeight)} lb", + child: Text( + "${twoDecimalFormatted(double.tryParse(removeTrailingZeros(_totalWeight)) ?? 0)} lb", textAlign: TextAlign.end, style: TextStyle(color: Colors.black54, fontSize: 15))) : const SizedBox() @@ -307,7 +330,7 @@ class _CartonInfoState extends State { color: Colors.black, fontSize: 15), ), Text( - "${removeTrailingZeros(e.value.weight)} lb", + "${twoDecimalFormatted(double.tryParse(removeTrailingZeros(e.value.weight)) ?? 0)} lb", textAlign: TextAlign.end, style: TextStyle( color: Colors.black, fontSize: 15)) @@ -528,7 +551,7 @@ class _CartonInfoState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible(child: cartonSizeBox), - _packages.isEmpty + _packageCount == 0 ? const SizedBox() : Flexible(child: packageLengthBox), ], diff --git a/lib/pages/carton/carton_package_editor.dart b/lib/pages/carton/carton_package_editor.dart index c082be7..7e561e7 100644 --- a/lib/pages/carton/carton_package_editor.dart +++ b/lib/pages/carton/carton_package_editor.dart @@ -13,12 +13,10 @@ import '../../../domain/vo/local_step.dart'; import '../../../helpers/theme.dart'; import '../../domain/entities/cargo_type.dart'; import '../../domain/entities/carton.dart'; -import '../../domain/entities/package.dart'; import '../../domain/entities/user.dart'; import '../carton_size/model/carton_size_model.dart'; import '../fcs_shipment/model/fcs_shipment_model.dart'; import '../main/util.dart'; -import '../package/model/package_model.dart'; import '../widgets/local_text.dart'; import '../widgets/progress.dart'; import '../widgets/step_widget.dart'; @@ -26,7 +24,7 @@ import 'cargo_widget.dart'; import 'carton_size_widget.dart'; import 'carton_submit.dart'; import 'model/package_selection_model.dart'; -import 'packages_widget.dart'; +import 'package_selection_widget.dart'; class CartonPackageEditor extends StatefulWidget { final Carton carton; @@ -46,7 +44,7 @@ class _CartonPackageEditorState extends State { LocalStep(lable: 'Cargos', stepType: StepType.CARGOS), LocalStep(lable: 'Submit', stepType: StepType.SUBMIT) ]; - List _packages = []; + List _cargoTypes = []; List _surchareItems = []; @@ -86,8 +84,11 @@ class _CartonPackageEditorState extends State { _billToValue = widget.carton.billTo ?? billToSender; _selectedLastMile = widget.carton.lastMile ?? delivery_caton; - _cargoTypes = widget.carton.cargoTypes; - _surchareItems = widget.carton.surchareItems; + + _cargoTypes = + widget.carton.cargoTypes.map((e) => e.cloneForCarton()).toList(); + _surchareItems = + widget.carton.surchareItems.map((e) => e.cloneForSurchage()).toList(); // check carton size type List cartonSizes = context.read().cartonSizes; @@ -120,11 +121,6 @@ class _CartonPackageEditorState extends State { .read() .getFcsShipment(widget.carton.fcsShipmentID ?? ""); _shipment = s; - - _packages = await context - .read() - .getPackagesByIds(widget.carton.packageIDs); - if (mounted) { setState(() {}); } @@ -233,19 +229,17 @@ class _CartonPackageEditorState extends State { )); } else if (step.stepType == StepType.PACKAGES) { return Expanded( - child: PackagesWidget( + child: PackageSelectionWidget( sender: _sender!, consignee: _consignee!, shipment: _shipment!, - onContinue: (packages) { + onContinue: () { setState(() { - _packages = List.from(packages); currentStep += 1; }); }, - onPrevious: (packages) { + onPrevious: () { setState(() { - _packages = List.from(packages); currentStep -= 1; }); }, @@ -288,7 +282,7 @@ class _CartonPackageEditorState extends State { height: _height, lastMile: _selectedLastMile, shipment: _shipment!, - packages: _packages, + // packages: _packages, cargoTypes: _cargoTypes, surchareItems: _surchareItems, onCreate: () { @@ -340,7 +334,7 @@ class _CartonPackageEditorState extends State { length: length, width: width, height: height, - packages: _packages, + // packages: _packages, cargoTypes: _cargoTypes, surchareItems: _surchareItems); diff --git a/lib/pages/carton/carton_package_form.dart b/lib/pages/carton/carton_package_form.dart index ce911ed..5f87927 100644 --- a/lib/pages/carton/carton_package_form.dart +++ b/lib/pages/carton/carton_package_form.dart @@ -12,7 +12,6 @@ import '../../../domain/entities/fcs_shipment.dart'; import '../../../domain/vo/local_step.dart'; import '../../../helpers/theme.dart'; import '../../domain/entities/cargo_type.dart'; -import '../../domain/entities/package.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; import '../widgets/local_text.dart'; @@ -23,7 +22,7 @@ import 'carton_size_widget.dart'; import 'carton_submit.dart'; import 'model/carton_model.dart'; import 'model/package_selection_model.dart'; -import 'packages_widget.dart'; +import 'package_selection_widget.dart'; class CartonPackageForm extends StatefulWidget { final User sender; @@ -48,7 +47,7 @@ class _CartonPackageFormState extends State { LocalStep(lable: 'Cargos', stepType: StepType.CARGOS), LocalStep(lable: 'Submit', stepType: StepType.SUBMIT) ]; - List _packages = []; + List _cargoTypes = []; List _surchareItems = []; @@ -166,19 +165,17 @@ class _CartonPackageFormState extends State { )); } else if (step.stepType == StepType.PACKAGES) { return Expanded( - child: PackagesWidget( + child: PackageSelectionWidget( sender: widget.sender, consignee: widget.consignee, shipment: _shipment!, - onContinue: (packages) { + onContinue: () { setState(() { - _packages = List.from(packages); currentStep += 1; }); }, - onPrevious: (packages) { + onPrevious: () { setState(() { - _packages = List.from(packages); currentStep -= 1; }); }, @@ -220,7 +217,6 @@ class _CartonPackageFormState extends State { height: _height, lastMile: _selectedLastMile, shipment: _shipment!, - packages: _packages, cargoTypes: _cargoTypes, surchareItems: _surchareItems, onCreate: () { @@ -236,7 +232,6 @@ class _CartonPackageFormState extends State { } } - _create() async { setState(() { _isLoading = true; @@ -272,7 +267,7 @@ class _CartonPackageFormState extends State { length: length, width: width, height: height, - packages: _packages, + // packages: _packages, cargoTypes: _cargoTypes, surchareItems: _surchareItems); var c = await context.read().createCarton(carton); diff --git a/lib/pages/carton/carton_submit.dart b/lib/pages/carton/carton_submit.dart index e492562..d33f1ab 100644 --- a/lib/pages/carton/carton_submit.dart +++ b/lib/pages/carton/carton_submit.dart @@ -7,8 +7,6 @@ import '../../../domain/entities/cargo_type.dart'; import '../../../domain/entities/carton_size.dart'; import '../../../domain/entities/fcs_shipment.dart'; import '../../../helpers/theme.dart'; - -import '../../domain/entities/package.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; import '../widgets/local_text.dart'; @@ -24,7 +22,7 @@ class CartonSubmit extends StatelessWidget { final User consingee; final String billToValue; final FcsShipment shipment; - final List packages; + // final List packages; final String cartonSizeType; final CartonSize? standardSize; final double length; @@ -44,7 +42,7 @@ class CartonSubmit extends StatelessWidget { this.onCreate, this.onPrevious, required this.shipment, - this.packages = const [], + // this.packages = const [], this.standardSize, required this.cartonSizeType, required this.lastMile, @@ -196,42 +194,42 @@ class CartonSubmit extends StatelessWidget { ), ); - final packagesBox = Padding( - padding: const EdgeInsets.only(top: 10), - child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Padding( - padding: const EdgeInsets.only(left: 5, bottom: 5), - child: LocalText(context, 'box.package.count', - translationVariables: [packages.length.toString()], - 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: Wrap( - spacing: 15, - children: packages.map((e) { - return SizedBox( - width: MediaQuery.of(context).size.width / 2.5, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 3), - child: Text( - e.trackingID ?? "", - style: TextStyle(color: Colors.black, fontSize: 15), - ), - ), - ); - }).toList()), - ), - ), - ]), - ); + // final packagesBox = Padding( + // padding: const EdgeInsets.only(top: 10), + // child: Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + // Padding( + // padding: const EdgeInsets.only(left: 5, bottom: 5), + // child: LocalText(context, 'box.package.count', + // translationVariables: [packages.length.toString()], + // 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: Wrap( + // spacing: 15, + // children: packages.map((e) { + // return SizedBox( + // width: MediaQuery.of(context).size.width / 2.5, + // child: Padding( + // padding: const EdgeInsets.symmetric(vertical: 3), + // child: Text( + // e.trackingID ?? "", + // style: TextStyle(color: Colors.black, fontSize: 15), + // ), + // ), + // ); + // }).toList()), + // ), + // ), + // ]), + // ); final cargosBox = Padding( padding: const EdgeInsets.only(top: 10), @@ -245,7 +243,8 @@ class CartonSubmit extends StatelessWidget { color: primaryColor, fontSize: 16, fontWeight: FontWeight.normal), - Text("${removeTrailingZeros(totalWeight)} lb", + Text( + "${twoDecimalFormatted(double.tryParse(removeTrailingZeros(totalWeight)) ?? 0)} lb", style: TextStyle(color: Colors.black, fontSize: 15)) ], ), @@ -275,7 +274,8 @@ class CartonSubmit extends StatelessWidget { style: TextStyle( color: Colors.black, fontSize: 15), ), - Text("${removeTrailingZeros(e.weight)} lb", + Text( + "${twoDecimalFormatted(double.tryParse(removeTrailingZeros(e.weight)) ?? 0)} lb", style: TextStyle( color: Colors.black, fontSize: 15)) ], @@ -448,11 +448,11 @@ class CartonSubmit extends StatelessWidget { const SizedBox(height: 10), shipmentBox, const SizedBox(height: 10), - packages.isNotEmpty ? packagesBox : const SizedBox(), + // packages.isNotEmpty ? packagesBox : const SizedBox(), + // const SizedBox(height: 10), + cargoTypes.isNotEmpty ? cargosBox : const SizedBox(), const SizedBox(height: 10), - cargosBox, - const SizedBox(height: 10), - surChargeItemsBox, + surchareItems.isNotEmpty ? surChargeItemsBox : const SizedBox(), const SizedBox(height: 20), ], ), diff --git a/lib/pages/carton/mix_carton_detail_list.dart b/lib/pages/carton/mix_carton_detail_list.dart index 9f4b94b..cf04e28 100644 --- a/lib/pages/carton/mix_carton_detail_list.dart +++ b/lib/pages/carton/mix_carton_detail_list.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:intl/intl.dart'; +import '../main/util.dart'; import '../widgets/local_text.dart'; import 'carton_info.dart'; @@ -99,7 +100,7 @@ class MixCartonDetailList extends StatelessWidget { ), ), Text( - "${carton.cartonWeight.toStringAsFixed(2)} lb", + "${twoDecimalFormatted(carton.cartonWeight)} lb", style: TextStyle(fontSize: 14.0, color: Colors.grey), ) ], diff --git a/lib/pages/carton/model/package_selection_model.dart b/lib/pages/carton/model/package_selection_model.dart index 8e1203a..3e91adc 100644 --- a/lib/pages/carton/model/package_selection_model.dart +++ b/lib/pages/carton/model/package_selection_model.dart @@ -5,59 +5,68 @@ import 'package:logging/logging.dart'; import '../../../constants.dart'; import '../../../domain/entities/package.dart'; +import '../../../pagination/paginator_listener.dart'; import '../../main/model/base_model.dart'; class PackageSelectionModel extends BaseModel { final log = Logger("PackageSelectionModel"); - String query = ""; - List packages = []; - List selectedPackages = []; + PaginatorListener? getPackages; + List packages = []; bool isLoading = false; DocumentSnapshot? _lastDocument; bool ended = false; - Timer? t; - search(String term, - {bool imm = false, - required String shipmentId, - required String senderId, - required String consigneeId}) async { - query = term; + @override + logout() async { packages.clear(); - _lastDocument = null; - ended = false; - t?.cancel(); - t = Timer(Duration(milliseconds: imm ? 0 : 800), () async { - await refresh( - term: term, - shipmentId: shipmentId, - consigneeId: consigneeId, - senderId: senderId); - }); + getPackages?.close(); + } + + loadPackages( + {required String senderId, + required String consigneeId, + required String shipmentId}) { + if (user == null) return; + + String path = "/$packages_collection"; + Query col = FirebaseFirestore.instance + .collection(path) + .where("sender_id", isEqualTo: senderId) + .where("user_id", isEqualTo: consigneeId) + .where("fcs_shipment_id", isEqualTo: shipmentId); + Query pageQuery = FirebaseFirestore.instance + .collection(path) + .where("sender_id", isEqualTo: senderId) + .where("user_id", isEqualTo: consigneeId) + .where("fcs_shipment_id", isEqualTo: shipmentId); + + pageQuery = pageQuery.orderBy("created_date", descending: true); + getPackages?.close(); + getPackages = PaginatorListener( + col, pageQuery, (data, id) => Package.fromMap(data, id), + rowPerLoad: 30); } Future refresh( {required String shipmentId, required String senderId, - required String consigneeId, - String term = ""}) async { + required String consigneeId}) async { packages.clear(); _lastDocument = null; ended = false; await loadMoreData( - shipmentId: shipmentId, - senderId: senderId, - consigneeId: consigneeId, - term: term); + shipmentId: shipmentId, + senderId: senderId, + consigneeId: consigneeId, + ); notifyListeners(); } Future loadMoreData( {required String shipmentId, required String senderId, - required String consigneeId, - String term = ""}) async { + required String consigneeId}) async { int rowPerPage = 20; try { @@ -69,12 +78,9 @@ class PackageSelectionModel extends BaseModel { whereIn: [package_processed_status, package_packed_status]) .where("sender_id", isEqualTo: senderId) .where("user_id", isEqualTo: consigneeId) + .where("fcs_shipment_id", isEqualTo: shipmentId) .where("is_deleted", isEqualTo: false); - if (term != "") { - query = query.where("tracking_id", isEqualTo: term); - } - query = query.orderBy("created_date", descending: true); if (_lastDocument != null) { @@ -92,10 +98,6 @@ class PackageSelectionModel extends BaseModel { return p; }).toList(); - for (var p in list) { - selectedPackages.contains(p) ? p.isChecked = true : p.isChecked = false; - } - packages.addAll(list); if (list.length < rowPerPage) ended = true; notifyListeners(); @@ -106,22 +108,8 @@ class PackageSelectionModel extends BaseModel { } } - selectPackage(Package a) { - if (a.isChecked) { - selectedPackages.add(a); - } else { - selectedPackages.remove(a); - } - } - - addSelectedPackage(List list) { - selectedPackages = list; - } - clearSelection() { - selectedPackages.clear(); packages.clear(); - query = ""; } Future> getPackagesBySenderAndConsigneeId( @@ -174,4 +162,21 @@ class PackageSelectionModel extends BaseModel { } return list; } + + Future getPackageCount( + {required String senderId, + required String consigneeId, + required String shipmentId}) async { + String path = "/$packages_collection"; + + AggregateQuerySnapshot query = await FirebaseFirestore.instance + .collection(path) + .where("sender_id", isEqualTo: senderId) + .where("user_id", isEqualTo: consigneeId) + .where("fcs_shipment_id", isEqualTo: shipmentId) + .count() + .get(); + + return query.count; + } } diff --git a/lib/pages/carton/package_detail_list.dart b/lib/pages/carton/package_detail_list.dart index 4dd72f1..f3caae6 100644 --- a/lib/pages/carton/package_detail_list.dart +++ b/lib/pages/carton/package_detail_list.dart @@ -1,24 +1,54 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/carton/model/package_selection_model.dart'; import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import '../../pagination/paginator_listview.dart'; import '../widgets/local_text.dart'; -class PackageDetailList extends StatelessWidget { +class PackageDetailList extends StatefulWidget { final String cartonNumber; - final List packages; - PackageDetailList( - {super.key, required this.cartonNumber, required this.packages}); + final int packageCount; + final String senderID; + final String consingeeID; + final String fcsShipmentID; + const PackageDetailList( + {super.key, + required this.cartonNumber, + required this.packageCount, + required this.senderID, + required this.consingeeID, + required this.fcsShipmentID}); + @override + State createState() => _PackageDetailListState(); +} + +class _PackageDetailListState extends State { final NumberFormat numberFormatter = NumberFormat("#,###"); + @override + void initState() { + _init(); + super.initState(); + } + + _init() { + context.read().loadPackages( + senderId: widget.senderID, + consigneeId: widget.consingeeID, + shipmentId: widget.fcsShipmentID); + } + @override Widget build(BuildContext context) { + var packageModel = context.watch(); return Scaffold( appBar: LocalAppBar( backgroundColor: Colors.white, @@ -31,81 +61,81 @@ class PackageDetailList extends StatelessWidget { "box.package.count", fontSize: 20, color: primaryColor, - translationVariables: [numberFormatter.format(packages.length)], + translationVariables: [ + numberFormatter.format(widget.packageCount) + ], ), - Text(cartonNumber, + Text(widget.cartonNumber, style: TextStyle(fontSize: 15, color: Colors.black)) ], ), ), - body: ListView.separated( - separatorBuilder: (context, index) => - Divider(height: 1, color: dividerColor), - itemCount: packages.length, - itemBuilder: (BuildContext context, int index) { - var package = packages[index]; - return InkWell( - onTap: () { - Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => PackageInfo(package: package)), - ); - }, - child: Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: Column( - children: [ - Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Row( - children: [ - Icon(Octicons.package, color: primaryColor), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 15), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - package.id == null - ? '' - : package.trackingID!, - style: TextStyle( - fontSize: 15.0, - color: Colors.black), - ), - Padding( - padding: - const EdgeInsets.only(top: 5), - child: Text( - package.market == null + body: PaginatorListView( + paginatorListener: packageModel.getPackages!, + rowBuilder: (p) { + Package package = p; + return InkWell( + onTap: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => PackageInfo(package: package)), + ); + }, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Row( + children: [ + Icon(Octicons.package, color: primaryColor), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 15), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + package.id == null ? '' - : package.market!, + : package.trackingID!, style: TextStyle( fontSize: 15.0, - color: Colors.grey), + color: Colors.black), ), - ), - ], + Padding( + padding: + const EdgeInsets.only(top: 5), + child: Text( + package.market == null + ? '' + : package.market!, + style: TextStyle( + fontSize: 15.0, + color: Colors.grey), + ), + ), + ], + ), ), ), - ), - ], + ], + ), ), ), - ), - ], - ), - ], + ], + ), + ], + ), ), - ), - ); - }, - )); + ); + }, + color: primaryColor)); } } diff --git a/lib/pages/carton/package_selection_result.dart b/lib/pages/carton/package_selection_result.dart index 1beba25..b471118 100644 --- a/lib/pages/carton/package_selection_result.dart +++ b/lib/pages/carton/package_selection_result.dart @@ -74,32 +74,38 @@ class PackageSelectionResult extends StatelessWidget { child: Row( children: [ Expanded( - child: new Padding( + child: Padding( padding: const EdgeInsets.symmetric( vertical: 8.0), - child: new Column( + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - new Text(package.trackingID ?? "", - style: new TextStyle( + Text(package.trackingID ?? "", + style: TextStyle( fontSize: 15.0, color: Colors.black)), - new Text( - package.cartonIds.isEmpty - ? "-" - : "${numberFormatter.format(package.cartonIds.length)} Boxes", - style: new TextStyle( + Text( + package.market != null && + package.market != "" + ? "${package.market}" + : "-", + style: TextStyle( fontSize: 15.0, color: Colors.grey), ), + // Text( + // package.cartonIds.isEmpty + // ? "-" + // : "${numberFormatter.format(package.cartonIds.length)} Boxes", + // style: TextStyle( + // fontSize: 15.0, + // color: Colors.grey), + // ), ], ), ), ), - package.isChecked - ? Icon(Icons.check, color: primaryColor) - : const SizedBox() ], ), ), diff --git a/lib/pages/carton/package_selection_widget.dart b/lib/pages/carton/package_selection_widget.dart index 9fb40cc..40df1bd 100644 --- a/lib/pages/carton/package_selection_widget.dart +++ b/lib/pages/carton/package_selection_widget.dart @@ -1,5 +1,5 @@ import 'package:fcs/domain/entities/fcs_shipment.dart'; -import 'package:fcs/helpers/theme.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; @@ -8,27 +8,25 @@ import 'package:provider/provider.dart'; import '../../domain/entities/package.dart'; import '../../domain/entities/user.dart'; import '../main/util.dart'; -import '../widgets/barcode_scanner.dart'; +import '../package/package_info.dart'; import '../widgets/continue_button.dart'; import '../widgets/local_title.dart'; import '../widgets/previous_button.dart'; import 'model/package_selection_model.dart'; import 'package_selection_result.dart'; -typedef OnPrevious = Function(List packages); -typedef OnContinue = Function(List packages); +typedef OnPrevious = Function(); +typedef OnContinue = Function(); class PackageSelectionWidget extends StatefulWidget { final User sender; final User consignee; final FcsShipment shipment; - final List packages; final OnPrevious? onPrevious; final OnContinue? onContinue; const PackageSelectionWidget({ super.key, - required this.packages, this.onPrevious, this.onContinue, required this.shipment, @@ -41,8 +39,6 @@ class PackageSelectionWidget extends StatefulWidget { } class _PackageSelectionWidgetState extends State { - final TextEditingController _controller = TextEditingController(); - String _query = ""; bool _isLoadMore = false; final _scrollController = ScrollController(); bool _down = true; @@ -60,29 +56,18 @@ class _PackageSelectionWidgetState extends State { } _init() { - var searchModel = context.read(); - _controller.text = searchModel.query; - _query = searchModel.query; - - searchModel.refresh( - shipmentId: widget.shipment.id!, - consigneeId: widget.consignee.id!, - senderId: widget.sender.id!, - term: _query); - - searchModel.addSelectedPackage(widget.packages); + var packageModel = context.read(); + packageModel.refresh( + shipmentId: widget.shipment.id!, + consigneeId: widget.consignee.id!, + senderId: widget.sender.id!, + ); if (mounted) { setState(() {}); } } - // @override - // void didUpdateWidget(covariant PackageSelectionWidget oldWidget) { - // _init(); - // super.didUpdateWidget(oldWidget); - // } - Future _loadMoreData() async { if (_isLoadMore) return; var model = context.read(); @@ -92,10 +77,10 @@ class _PackageSelectionWidgetState extends State { }); await model.loadMoreData( - shipmentId: widget.shipment.id!, - consigneeId: widget.consignee.id!, - senderId: widget.sender.id!, - term: _query); + shipmentId: widget.shipment.id!, + consigneeId: widget.consignee.id!, + senderId: widget.sender.id!, + ); setState(() { _isLoadMore = false; @@ -105,8 +90,7 @@ class _PackageSelectionWidgetState extends State { @override Widget build(BuildContext context) { var model = context.watch(); - List searchResults = model.packages; - List selectedPackageList = model.selectedPackages; + List packages = model.packages; final senderBox = userDisplayBox(context, lableKey: "box.sender.title", @@ -132,103 +116,23 @@ class _PackageSelectionWidgetState extends State { final continueBtn = ContinueButton( onTap: () { - if (selectedPackageList.isEmpty || searchResults.isEmpty) { - showMsgDialog(context, 'Error', "Please select the packages"); + if (packages.isEmpty) { + showMsgDialog(context, 'Error', "Please add the packages"); return false; } if (widget.onContinue != null) { - widget.onContinue!(selectedPackageList); + widget.onContinue!(); } }, ); final previousBtn = PreviousButton(onTap: () { if (widget.onPrevious != null) { - widget.onPrevious!(selectedPackageList); + widget.onPrevious!(); } }); - final searchBox = SizedBox( - height: 40, - child: TextField( - controller: _controller, - cursorColor: primaryColor, - onSubmitted: (value) { - setState(() { - _query = value; - }); - _search(imm: true); - }, - onChanged: (v) { - setState(() { - _query = v; - }); - _search(); - }, - decoration: InputDecoration( - enabledBorder: const OutlineInputBorder( - borderSide: BorderSide(color: labelColor), - ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(5.0), - borderSide: - BorderSide(color: labelColor.withOpacity(0.3), width: 0)), - focusedBorder: const OutlineInputBorder( - borderRadius: BorderRadius.all(Radius.circular(5.0)), - borderSide: BorderSide(color: labelColor), - ), - hintText: "Search by tracking number", - hintStyle: const TextStyle( - color: Colors.grey, - fontSize: 16, - fontWeight: FontWeight.normal), - suffixIcon: Row( - mainAxisSize: MainAxisSize.min, - children: [ - InkResponse( - radius: 20, - onTap: () { - _scan(context); - }, - child: const Icon(Icons.qr_code_scanner, - color: Colors.black87)), - IconButton( - splashRadius: 20, - onPressed: () { - setState(() { - _controller.clear(); - _query = ""; - }); - _search(); - }, - icon: const Icon(Icons.close, color: Colors.black87)), - ], - ), - contentPadding: const EdgeInsets.all(10), - filled: true), - ), - ); - - final selectedPackageBox = Align( - alignment: Alignment.topLeft, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - padding: EdgeInsets.only(top: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: selectedPackageList - .map((e) => Padding( - padding: const EdgeInsets.only(right: 20), - child: Text(e.trackingID ?? "", - style: - TextStyle(color: Colors.black, fontSize: 15)), - )) - .toList())), - ); return Column( children: [ Expanded( @@ -255,8 +159,6 @@ class _PackageSelectionWidgetState extends State { LocalTitle( textKey: "box.select.package", topPadding: 5), const SizedBox(height: 10), - searchBox, - selectedPackageBox, ]) : const SizedBox(), ), @@ -273,11 +175,12 @@ class _PackageSelectionWidgetState extends State { _down = true; }); }, - onTap: (a) async { - setState(() { - a.isChecked = !a.isChecked; - }); - context.read().selectPackage(a); + onTap: (a) { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => PackageInfo(package: a)), + ); }, ), ), @@ -302,31 +205,4 @@ class _PackageSelectionWidgetState extends State { ], ); } - - _scan(BuildContext context) async { - try { - String? barcode = await scanBarcode(); - if (barcode != null) { - setState(() { - _controller.text = barcode; - _query = barcode; - }); - await _search(); - } - } catch (e) { - showMsgDialog(context, 'Error', e.toString()); - } - } - - _search({bool imm = false}) async { - try { - await context.read().search(_query, - imm: imm, - shipmentId: widget.shipment.id!, - senderId: widget.sender.id!, - consigneeId: widget.consignee.id!); - } catch (e) { - showMsgDialog(context, 'Error', e.toString()); - } - } } diff --git a/lib/pages/carton/packages_widget.dart b/lib/pages/carton/packages_widget.dart deleted file mode 100644 index 69933dc..0000000 --- a/lib/pages/carton/packages_widget.dart +++ /dev/null @@ -1,223 +0,0 @@ -import 'package:fcs/domain/entities/fcs_shipment.dart'; -import 'package:fcs/helpers/theme.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_icons_null_safety/flutter_icons_null_safety.dart'; -import 'package:provider/provider.dart'; - -import '../../domain/entities/package.dart'; -import '../../domain/entities/user.dart'; -import '../main/util.dart'; -import '../widgets/continue_button.dart'; -import '../widgets/local_text.dart'; -import '../widgets/local_title.dart'; -import '../widgets/previous_button.dart'; -import 'model/package_selection_model.dart'; -import 'package_selection_result.dart'; - -typedef OnPrevious = Function(List packages); -typedef OnContinue = Function(List packages); - -class PackagesWidget extends StatefulWidget { - final User sender; - final User consignee; - final FcsShipment shipment; - final OnPrevious? onPrevious; - final OnContinue? onContinue; - - const PackagesWidget({ - super.key, - this.onPrevious, - this.onContinue, - required this.shipment, - required this.sender, - required this.consignee, - }); - - @override - State createState() => _PackagesWidgetState(); -} - -class _PackagesWidgetState extends State { - final _scrollController = ScrollController(); - bool _down = true; - List _packages = []; - bool _isLoading = false; - - @override - void initState() { - _init(); - super.initState(); - _scrollController.addListener(() { - setState(() { - _down = _scrollController.position.userScrollDirection == - ScrollDirection.forward; - }); - }); - } - - _init() async { - _packages.clear(); - _isLoading = true; - var packageModel = context.read(); - var list = await packageModel.getActivePackages( - shipmentId: widget.shipment.id!, - senderId: widget.sender.id!, - consigneeId: widget.consignee.id!); - _packages = List.from(list); - _isLoading = false; - if (mounted) { - setState(() {}); - } - } - - @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 continueBtn = ContinueButton( - onTap: () { - if (_packages.isEmpty) { - showMsgDialog(context, 'Error', "Please add the packages"); - return false; - } - if (widget.onContinue != null) { - widget.onContinue!(_packages); - } - }, - ); - - final previousBtn = PreviousButton(onTap: () { - if (widget.onPrevious != null) { - widget.onPrevious!(_packages); - } - }); - - return Column( - children: [ - Expanded( - child: Padding( - padding: EdgeInsets.only(left: 10, right: 10), - child: Column( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: - (Widget child, Animation animation) => - FadeTransition( - opacity: animation, - child: SizeTransition( - sizeFactor: animation, - axis: Axis.vertical, - child: child, - ), - ), - child: _down - ? Column(children: [ - const SizedBox(height: 8), - userRow, - LocalTitle( - textKey: "box.select.package", topPadding: 5), - const SizedBox(height: 10), - ]) - : const SizedBox(), - ), - Expanded( - child: _packages.isEmpty && !_isLoading - ? Center( - child: LocalText(context, 'box.no_package', - color: Colors.black, fontSize: 15)) - : RefreshIndicator( - color: primaryColor, - onRefresh: () async { - _init(); - }, - child: ListView.builder( - padding: const EdgeInsets.only(top: 10), - controller: _scrollController, - shrinkWrap: true, - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (context, index) { - Package package = _packages[index]; - return packageRow(context, package); - }, - itemCount: _packages.length)), - ), - ], - ), - ), - ), - 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 packageRow(BuildContext context, Package package) { - return Padding( - padding: const EdgeInsets.only(top: 5, bottom: 5), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5)), - border: Border.all(color: Colors.grey.shade300)), - padding: EdgeInsets.only(left: 10, right: 10), - child: Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(package.trackingID ?? "", - style: TextStyle(fontSize: 15.0, color: Colors.black)), - Text( - package.cartonIds.isEmpty - ? "-" - : "${numberFormatter.format(package.cartonIds.length)} Boxes", - style: TextStyle(fontSize: 15.0, color: Colors.grey), - ), - ], - ), - ), - ), - package.isChecked - ? Icon(Icons.check, color: primaryColor) - : const SizedBox() - ], - ), - ), - ); - } -} diff --git a/lib/pages/carton/widget/carton_list_row.dart b/lib/pages/carton/widget/carton_list_row.dart index 56c1a4a..9d24565 100644 --- a/lib/pages/carton/widget/carton_list_row.dart +++ b/lib/pages/carton/widget/carton_list_row.dart @@ -4,15 +4,16 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:intl/intl.dart'; +import '../../main/util.dart'; import '../carton_info.dart'; import '../print_qr_code_page.dart'; class CartonListRow extends StatelessWidget { final Carton box; - CartonListRow({Key? key, required this.box}) : super(key: key); + CartonListRow({super.key, required this.box}); final double dotSize = 15.0; - final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); + final DateFormat dateFormat = DateFormat("dd MMM yyyy"); @override Widget build(BuildContext context) { @@ -28,9 +29,9 @@ class CartonListRow extends StatelessWidget { child: Row( children: [ Expanded( - child: new Padding( + child: Padding( padding: const EdgeInsets.symmetric(vertical: 10.0), - child: new Row( + child: Row( children: [ Container( padding: EdgeInsets.only(left: 0), @@ -40,24 +41,24 @@ class CartonListRow extends StatelessWidget { size: 30, ), ), - new Expanded( + Expanded( child: Padding( padding: const EdgeInsets.only(left: 15.0), child: Row( children: [ - new Column( + Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - new Text( + Text( box.cartonNumber ?? "", - style: new TextStyle( + style: TextStyle( fontSize: 15.0, color: Colors.black), ), Padding( padding: const EdgeInsets.only(top: 5), - child: new Text( + child: Text( box.consigneeName ?? "", - style: new TextStyle( + style: TextStyle( fontSize: 15.0, color: Colors.grey), ), ), @@ -95,10 +96,9 @@ class CartonListRow extends StatelessWidget { padding: const EdgeInsets.only(top: 5), child: Row( children: [ - new Text( - "${box.cartonWeight.toStringAsFixed(2)} lb", - style: - new TextStyle(fontSize: 14.0, color: Colors.grey), + Text( + "${twoDecimalFormatted(box.cartonWeight)} lb", + style: TextStyle(fontSize: 14.0, color: Colors.grey), ), ], ), diff --git a/lib/pages/main/util.dart b/lib/pages/main/util.dart index 98e1837..e529ac6 100644 --- a/lib/pages/main/util.dart +++ b/lib/pages/main/util.dart @@ -410,6 +410,11 @@ String removeTrailingZeros(double number) { return result; } +String twoDecimalFormatted(double number) { + String formattedString = number.toStringAsFixed(2); + return formattedString; +} + bool isValidEmail(String email) { // Define a regular expression for validating an email final emailRegex = RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$'); @@ -561,4 +566,3 @@ Widget settingRow(BuildContext context, ), ); } -