From caf20f4e677522eaaff79257dd9ad358a7a884af Mon Sep 17 00:00:00 2001 From: tzw Date: Wed, 7 Feb 2024 17:26:29 +0630 Subject: [PATCH] add cartion filter and search --- assets/local/localization_en.json | 4 + assets/local/localization_mu.json | 4 + lib/app.dart | 14 +- lib/data/provider/carton_data_provider.dart | 8 +- lib/domain/constants.dart | 2 + .../vo}/local_popupmenu.dart | 0 lib/pages/carton/carton_editor copy.dart | 976 ------------------ lib/pages/carton/carton_editor.dart | 2 +- lib/pages/carton/carton_filter.dart | 441 ++++++++ lib/pages/carton/carton_list.dart | 259 ++++- lib/pages/carton/carton_list_row.dart | 4 +- .../mix_carton/carton_selection_widget.dart | 9 +- lib/pages/carton/model/carton_model.dart | 126 ++- .../model/consignee_selection_model.dart | 132 +++ .../carton/model/sender_selection_model.dart | 132 +++ lib/pages/carton/user_search_result.dart | 103 ++ lib/pages/carton_search/carton_list_row.dart | 125 ++- lib/pages/carton_search/carton_search.dart | 40 +- lib/pages/customer/customer_list.dart | 2 +- lib/pages/delivery/delivery_list.dart | 2 +- lib/pages/discount/discount_editor.dart | 2 +- lib/pages/discount/discount_list.dart | 2 +- lib/pages/fcs_shipment/fcs_shipment_list.dart | 20 +- .../model/fcs_shipment_model.dart | 18 + lib/pages/invoice/editor/invoice_editor.dart | 2 +- lib/pages/invoice/invoice_list.dart | 2 +- lib/pages/package/package_list.dart | 4 +- lib/pages/package/package_new.dart | 2 +- ...ackage_serach.dart => package_search.dart} | 0 lib/pages/processing/package_editor.dart | 2 +- .../processing/processing_edit_editor.dart | 2 +- lib/pages/processing/processing_editor.dart | 2 +- lib/pages/processing/processing_list.dart | 2 +- lib/pages/receiving/receiving_editor.dart | 2 +- lib/pages/receiving/receiving_list.dart | 2 +- lib/pages/shipment/shipment_info.dart | 2 +- lib/pages/user_search/user_list_row.dart | 2 +- .../{user_serach.dart => user_search.dart} | 0 .../widgets/local_popup_menu_button.dart | 2 +- 39 files changed, 1274 insertions(+), 1181 deletions(-) rename lib/{pages/widgets => domain/vo}/local_popupmenu.dart (100%) delete mode 100644 lib/pages/carton/carton_editor copy.dart create mode 100644 lib/pages/carton/carton_filter.dart create mode 100644 lib/pages/carton/model/consignee_selection_model.dart create mode 100644 lib/pages/carton/model/sender_selection_model.dart create mode 100644 lib/pages/carton/user_search_result.dart rename lib/pages/package_search/{package_serach.dart => package_search.dart} (100%) rename lib/pages/user_search/{user_serach.dart => user_search.dart} (100%) diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 855390e..dd848fe 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -16,6 +16,8 @@ "feet":"Feet", "inch":"Inch", "back.button_confirm":"Are you sure you want to continue without submitting changes?", + "btn.clear":"Clear Filter", + "btn.filter":"Filter", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -116,6 +118,8 @@ "user.fcs_id":"MY FCS_ID", "user.shipping_address":"USA SHIPPING ADDRESS", "user.deliveryAddress":"My delivery address", + "user.no_consignee":"No consignees", + "user.no_sender":"No senders", "User End ================================================================":"", "Customer Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 3270107..1ebe612 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -15,6 +15,8 @@ "feet":"ပေ", "inch":"လက်မ", "back.button_confirm":"Are you sure you want to continue without submitting changes?", + "btn.clear":"Clear Filter", + "btn.filter":"Filter", "Buttons End ================================================================":"", "Offline Start ================================================================":"", @@ -116,6 +118,8 @@ "user.fcs_id":"My FCS_ID", "user.shipping_address":"My USA shipping address", "user.deliveryAddress":"My delivery address", + "user.no_consignee":"လက်ခံသူမရှိပါ။", + "user.no_sender":"ပေးပို့သူများမရှိပါ။", "User End ================================================================":"", "Customer Start ================================================================":"", diff --git a/lib/app.dart b/lib/app.dart index ce6c735..7a2085b 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -30,7 +30,9 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'pages/carton/model/carton_selection_model.dart'; +import 'pages/carton/model/consignee_selection_model.dart'; import 'pages/carton/model/package_selection_model.dart'; +import 'pages/carton/model/sender_selection_model.dart'; import 'pages/delivery/model/delivery_model.dart'; class App extends StatefulWidget { @@ -65,7 +67,11 @@ class _AppState extends State { final ProcessingModel processingModel = new ProcessingModel(); final PickupModel pickupModel = new PickupModel(); final CartonSelectionModel cartonSelectionModel = new CartonSelectionModel(); - final PackageSelectionModel packageSelectionModel = new PackageSelectionModel(); + final PackageSelectionModel packageSelectionModel = + new PackageSelectionModel(); + final ConsigneeSelectionModel consigneeSelectionModel = + new ConsigneeSelectionModel(); + final SenderSelectionModel senderSelectionModel = new SenderSelectionModel(); late AppTranslationsDelegate _newLocaleDelegate; @@ -90,7 +96,9 @@ class _AppState extends State { ..addModel(processingModel) ..addModel(pickupModel) ..addModel(cartonSelectionModel) - ..addModel(packageSelectionModel); + ..addModel(packageSelectionModel) + ..addModel(consigneeSelectionModel) + ..addModel(senderSelectionModel); _newLocaleDelegate = AppTranslationsDelegate( newLocale: Translation().supportedLocales().first); @@ -141,6 +149,8 @@ class _AppState extends State { ChangeNotifierProvider.value(value: pickupModel), ChangeNotifierProvider.value(value: cartonSelectionModel), ChangeNotifierProvider.value(value: packageSelectionModel), + ChangeNotifierProvider.value(value: consigneeSelectionModel), + ChangeNotifierProvider.value(value: senderSelectionModel), ], child: Consumer( builder: (context, value, child) { diff --git a/lib/data/provider/carton_data_provider.dart b/lib/data/provider/carton_data_provider.dart index 601059c..93e02a4 100644 --- a/lib/data/provider/carton_data_provider.dart +++ b/lib/data/provider/carton_data_provider.dart @@ -1,5 +1,4 @@ import 'dart:async'; - import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; @@ -40,18 +39,15 @@ class CartonDataProvider { // var bytes = utf8.encode(term); // var base64Str = base64.encode(bytes); // HtmlEscape htmlEscape = const HtmlEscape(); - // String escapeBuyer = htmlEscape.convert(base64Str); + // String escapeTerm = htmlEscape.convert(base64Str); try { String path = "/$cartons_collection"; var querySnap = await FirebaseFirestore.instance .collection(path) .where("carton_number", isEqualTo: term) - .where("carton_type", - whereIn: [carton_from_packages, carton_from_cartons]) - .where("status", isEqualTo: carton_packed_status) .where("is_deleted", isEqualTo: false) - .orderBy("user_name") + .orderBy("created_at",descending: true) .get(); return querySnap.docs.map((e) => Carton.fromMap(e.data(), e.id)).toList(); } catch (e) { diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 56f8ceb..a96f1fe 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -112,6 +112,8 @@ const carton_processing_status = "processing"; const carton_arrived_status = "arrived"; const carton_invoiced_status = "invoiced"; const carton_canceled_status = "canceled"; +const all_status= "All stauts"; +const all ="All"; // shipment status const shipment_pending_status = "pending"; diff --git a/lib/pages/widgets/local_popupmenu.dart b/lib/domain/vo/local_popupmenu.dart similarity index 100% rename from lib/pages/widgets/local_popupmenu.dart rename to lib/domain/vo/local_popupmenu.dart diff --git a/lib/pages/carton/carton_editor copy.dart b/lib/pages/carton/carton_editor copy.dart deleted file mode 100644 index 8c3f5b2..0000000 --- a/lib/pages/carton/carton_editor copy.dart +++ /dev/null @@ -1,976 +0,0 @@ -import 'package:fcs/domain/constants.dart'; -import 'package:fcs/domain/entities/carton.dart'; -import 'package:fcs/domain/entities/cargo_type.dart'; -import 'package:fcs/domain/entities/carton_size.dart'; -import 'package:fcs/domain/entities/fcs_shipment.dart'; -import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/domain/entities/user.dart'; -import 'package:fcs/domain/vo/delivery_address.dart'; -import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/carton/carton_package_table.dart'; -import 'package:fcs/pages/carton_search/carton_search.dart'; -import 'package:fcs/pages/carton_size/carton_size_list.dart'; -import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; -import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/rates/model/shipment_rate_model.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; -import 'package:fcs/pages/widgets/defalut_delivery_address.dart'; -import 'package:fcs/pages/widgets/delivery_address_selection.dart'; -import 'package:fcs/pages/widgets/display_text.dart'; -import 'package:fcs/pages/widgets/fcs_id_icon.dart'; -import 'package:fcs/pages/widgets/length_picker.dart'; -import 'package:fcs/pages/widgets/local_app_bar.dart'; -import 'package:fcs/pages/widgets/local_button.dart'; -import 'package:fcs/pages/widgets/local_dropdown.dart'; -import 'package:fcs/pages/widgets/local_radio_buttons.dart'; -import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:fcs/pages/widgets/local_title.dart'; -import 'package:fcs/pages/widgets/progress.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_vector_icons/flutter_vector_icons.dart'; -import 'package:provider/provider.dart'; -import 'cargo_type_addtion.dart'; -import 'carton_cargo_table.dart'; -import 'carton_row.dart'; -import 'model/carton_model.dart'; -import '../carton_size/model/carton_size_model.dart'; -import 'package_carton_editor.dart'; -import 'widgets.dart'; - -class CartonEditor extends StatefulWidget { - final Carton? carton; - CartonEditor({this.carton}); - - @override - _CartonEditorState createState() => _CartonEditorState(); -} - -class _CartonEditorState extends State { - TextEditingController _widthController = new TextEditingController(); - TextEditingController _heightController = new TextEditingController(); - TextEditingController _lengthController = new TextEditingController(); - DeliveryAddress? _deliveryAddress = new DeliveryAddress(); - List _cargoTypes = []; - - Carton? _carton; - bool _isLoading = false; - bool _isNew = false; - User? _user; - String? _selectedCartonType; - - double volumetricRatio = 0; - double shipmentWeight = 0; - FcsShipment? _fcsShipment; - List _fcsShipments = []; - List _cartons = []; - CartonSize? selectedCatonSize; - - //for mix carton - List _mixCartons = []; - String? _selectedMixBoxType; - - //for carton from cargos - User? consignee; - User? sender; - List _cartonsFromCartons = []; - - double? totalWeight; - - @override - void initState() { - super.initState(); - - //for shipment weight - volumetricRatio = Provider.of(context, listen: false) - .rate - .volumetricRatio; - _lengthController.addListener(_calShipmentWeight); - _widthController.addListener(_calShipmentWeight); - _heightController.addListener(_calShipmentWeight); - - if (widget.carton != null) { - _carton = widget.carton; - _deliveryAddress = _carton!.deliveryAddress; - _widthController.text = _carton!.width.toString(); - _heightController.text = _carton!.height.toString(); - _lengthController.text = _carton!.length.toString(); - _selectedCartonType = _carton!.cartonType; - - _cargoTypes = _carton!.cargoTypes.map((e) => e.clone()).toList(); - - _isNew = false; - _user = User( - id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); - consignee = User( - id: _carton!.userID, fcsID: _carton!.fcsID, name: _carton!.userName); - sender = User( - id: _carton!.senderID, - fcsID: _carton!.senderFCSID, - name: _carton!.senderName); - _selectedMixBoxType = _carton!.mixBoxType; - this._mixCartons = - // ignore: unnecessary_null_comparison - _carton!.mixCartons == null ? [] : List.from(_carton!.mixCartons); - bool isMixBox = _carton!.cartonType == carton_mix_box; - bool isFromPackages = _carton!.cartonType == carton_from_packages; - if (isFromPackages) _loadPackages(); - - if (!isMixBox) { - _getCartonSize(); - } - } else { - _carton = Carton( - cargoTypes: [], - packages: [], - ); - _lengthController.text = "0"; - _widthController.text = "0"; - _heightController.text = "0"; - _isNew = true; - _selectedCartonType = carton_from_packages; - _selectedMixBoxType = mix_delivery; - _loadFcsShipments(); - } - } - - _loadFcsShipments() async { - FcsShipmentModel fcsShipmentModel = - Provider.of(context, listen: false); - var fcsShipments = await fcsShipmentModel.getActiveFcsShipments(); - - // var fcsShipment = - // fcsShipments.firstWhere((e) => e.id == _carton?.fcsShipmentID); - - setState(() { - _fcsShipments = fcsShipments; - // _fcsShipment = fcsShipment; - }); - } - - _loadPackages() async { - if (_user == null) return; - PackageModel packageModel = - Provider.of(context, listen: false); - List packages = await packageModel.getPackages( - _user!.id!, [package_processed_status, package_packed_status]); - if (_isNew) { - String? prevCompare; - packages.forEach((p) { - String compare = (p.deliveryAddress?.fullName ?? "") + - (p.deliveryAddress?.phoneNumber ?? ""); - if (prevCompare != null && compare == prevCompare) { - p.isChecked = true; - } else { - p.isChecked = false; - } - if (prevCompare == null) { - p.isChecked = true; - prevCompare = compare; - } - }); - } else { - packages.forEach((p) { - if (_carton!.packages.contains(p)) { - p.isChecked = _carton!.packages.firstWhere((cp) => cp == p).isChecked; - } else { - p.isChecked = false; - } - }); - } - - setState(() { - _carton!.packages = packages; - }); - // _populateDeliveryAddress(); - } - - // _populateDeliveryAddress() { - // if (_carton.packages == null) return; - // var d = _carton.packages - // .firstWhere((p) => p.isChecked && p.deliveryAddress != null, - // orElse: () => null) - // ?.deliveryAddress; - // setState(() { - // _deliveryAddress = d; - // }); - // } - - _calShipmentWeight() { - double l = double.tryParse(_lengthController.text) ?? 0; - double w = double.tryParse(_widthController.text) ?? 0; - double h = double.tryParse(_heightController.text) ?? 0; - setState(() { - shipmentWeight = l * w * h / volumetricRatio; - }); - } - - _getCartonSize() { - var cartonSizeModel = Provider.of(context, listen: false); - cartonSizeModel.cartonSizes.forEach((c) { - if (c.length == _carton!.length && - c.width == _carton!.width && - c.height == _carton!.height) { - selectedCatonSize = CartonSize( - id: c.id, - name: c.name, - length: c.length, - width: c.width, - height: c.height); - } - }); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - var boxModel = Provider.of(context); - bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - bool isMixBox = _selectedCartonType == carton_mix_box; - - final shipmentBox = DisplayText( - text: _carton!.fcsShipmentNumber, - labelTextKey: "box.fcs_shipment_num", - iconData: Ionicons.ios_airplane, - ); - - var fcsShipmentsBox = Container( - padding: EdgeInsets.only(top: 10), - child: LocalDropdown( - callback: (v) { - setState(() { - _fcsShipment = v; - }); - }, - labelKey: "shipment.pack.fcs.shipment", - iconData: Ionicons.ios_airplane, - display: (u) => u.shipmentNumber, - selectedValue: _fcsShipment, - values: _fcsShipments, - )); - - final fcsIDBox = Container( - padding: EdgeInsets.only(top: 15), - child: Row( - children: [ - Expanded( - child: DisplayText( - text: _user?.fcsID ?? "", - labelTextKey: "box.fcs.id", - icon: FcsIDIcon(), - )), - _isNew - ? IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () => searchUser(context, onUserSelect: (u) { - setState(() { - this._user = u; - _loadPackages(); - }); - }, popPage: true)) - : Container(), - ], - )); - - final namebox = DisplayText( - text: _user?.name ?? "", - labelTextKey: "box.name", - iconData: Icons.person, - ); - - final createBtn = LocalButton( - textKey: "box.complete.packaging", - callBack: () { - Navigator.pop(context); - }, - ); - - final saveBtn = LocalButton( - textKey: "box.cargo.save.btn", - callBack: _save, - ); - - final cartonTypeBox = LocalRadioButtons( - readOnly: !_isNew, - values: boxModel.cartonTypes, - selectedValue: _selectedCartonType, - callback: (String? v) { - setState(() { - _selectedCartonType = v; - }); - }); - - final cartonTitleBox = Container( - child: LocalTitle( - textKey: "boxes.title", - trailing: IconButton( - icon: Icon( - Icons.add_circle, - color: primaryColor, - ), - onPressed: _addCarton), - ), - ); - - final mixTypeBox = Container( - padding: EdgeInsets.only(top: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.only(left: 5), - child: LocalText( - context, - "box.mix_type", - color: primaryColor, - fontSize: 15, - fontWeight: FontWeight.bold, - )), - Row( - children: boxModel.mixBoxTypes.map((e) { - return Row( - children: [ - Radio( - value: e, - groupValue: _selectedMixBoxType, - activeColor: primaryColor, - onChanged: (String? v) { - setState(() { - _selectedMixBoxType = v; - }); - }, - ), - Text(e), - ], - ); - }).toList(), - ), - ], - ), - ); - - final mixTypeDisplayBox = Container( - padding: EdgeInsets.only(top: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.only(left: 5), - child: LocalText( - context, - "box.mix_type", - color: primaryColor, - fontSize: 15, - fontWeight: FontWeight.bold, - )), - Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - Icons.check, - color: primaryColor, - ), - ), - Text(_selectedMixBoxType ?? "") - ], - ) - ], - ), - ); - - final mixcartonTitleBox = Container( - child: LocalTitle( - textKey: "box.mix_caton_title", - trailing: IconButton( - icon: Icon( - Icons.add_circle, - color: primaryColor, - ), - onPressed: () async { - boxModel.selectedIndexFilter = 1; - searchCarton(context, callbackCartonSelect: (c) { - _addMixCarton(c); - }); - }, - ), - ), - ); - final cargoTableTitleBox = LocalTitle( - textKey: "box.cargo.type", - trailing: IconButton( - icon: Icon( - Icons.add_circle, - color: primaryColor, - ), - onPressed: () async { - List? cargos = await Navigator.push>( - context, - CupertinoPageRoute(builder: (context) => CargoTypeAddition())); - if (cargos == null) return; - setState(() { - _cargoTypes.addAll( - cargos.where((e) => !_cargoTypes.contains(e)).toList()); - }); - }), - ); - - final cargoTableBox = CargoTable( - isNew: _isNew, - cargoTypes: _cargoTypes, - onRemove: (c) => _removeCargo(c), - onUpdate: (c) => _updateCargo(c), - ); - - final lengthBox = LengthPicker( - controller: _lengthController, - lableKey: "box.length", - isReadOnly: false, - ); - final widthBox = LengthPicker( - controller: _widthController, - lableKey: "box.width", - isReadOnly: false, - ); - final heightBox = LengthPicker( - controller: _heightController, - lableKey: "box.height", - isReadOnly: false, - ); - final dimBox = Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Icon(FontAwesome.arrow_circle_right, color: primaryColor), - ), - SizedBox(child: lengthBox, width: 80), - SizedBox(child: widthBox, width: 80), - SizedBox(child: heightBox, width: 80), - ], - ); - - final createMixCarton = LocalButton( - textKey: _isNew ? "box.mix_carton_btn" : "box.mix_carton.update.btn", - callBack: _creatMixCarton, - ); - - final consigneefcsIDBox = Row( - children: [ - Expanded( - child: DisplayText( - text: consignee != null ? consignee!.fcsID : "", - labelTextKey: "processing.fcs.id", - icon: FcsIDIcon(), - )), - IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () => searchUser(context, onUserSelect: (u) { - setState(() { - this.consignee = u; - }); - }, popPage: true)), - ], - ); - - final consigneeNameBox = DisplayText( - text: consignee != null ? consignee!.name : "", - labelTextKey: "processing.consignee.name", - maxLines: 2, - iconData: Icons.person, - ); - - final consigneeBox = Container( - child: Column( - children: [ - consigneefcsIDBox, - consigneeNameBox, - ], - ), - ); - - final shipperIDBox = Row( - children: [ - Expanded( - child: DisplayText( - text: sender != null ? sender!.fcsID : "", - labelTextKey: "processing.fcs.id", - icon: FcsIDIcon(), - )), - IconButton( - icon: Icon(Icons.search, color: primaryColor), - onPressed: () => searchUser(context, onUserSelect: (u) { - setState(() { - this.sender = u; - }); - }, popPage: true)), - ], - ); - - final shipperNamebox = DisplayText( - text: sender != null ? sender!.name : "", - labelTextKey: "processing.shipper.name", - maxLines: 2, - iconData: Icons.person, - ); - - final shipperBox = Container( - child: Column( - children: [ - shipperIDBox, - shipperNamebox, - ], - ), - ); - - return LocalProgress( - inAsyncCall: _isLoading, - child: Scaffold( - appBar: LocalAppBar( - labelKey: _isNew ? "boxes.new" : "box.edit.title", - backgroundColor: Colors.white, - arrowColor: primaryColor, - labelColor: primaryColor), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - shrinkWrap: true, - children: [ - _isNew - ? Container() - : Center(child: getCartonNumberStatus(context, _carton!)), - LocalTitle(textKey: "box.type.title"), - cartonTypeBox, - LocalTitle(textKey: "box.shipment_info"), - _isNew ? fcsShipmentsBox : shipmentBox, - isMixBox - ? _isNew - ? mixTypeBox - : mixTypeDisplayBox - : Container(), - ...(isMixBox - ? [ - mixcartonTitleBox, - Column( - children: _getMixCartons(context, this._mixCartons)), - ] - : [ - isFromPackages ? fcsIDBox : Container(), - isFromPackages ? namebox : Container(), - isFromPackages - ? CartonPackageTable( - packages: _carton!.packages, - onSelect: (p, checked) { - // if (checked && - // _deliveryAddress != null && - // p.deliveryAddress?.id != - // _deliveryAddress.id) { - // return; - // } - setState(() { - p.isChecked = checked; - }); - // _populateDeliveryAddress(); - }, - ) - : Container(), - isFromCartons - ? Container( - padding: const EdgeInsets.only(top: 15), - child: Row( - children: [ - Flexible(child: consigneeBox), - Flexible(child: shipperBox) - ], - ), - ) - : Container(), - _isNew ? cartonTitleBox : Container(), - _isNew - ? Column( - children: _getCartons( - context, - isFromPackages - ? this._cartons - : this._cartonsFromCartons)) - : Container(), - _isNew ? Container() : cargoTableTitleBox, - _isNew ? Container() : cargoTableBox, - _isNew - ? Container() - : LocalTitle(textKey: "box.dimension"), - _isNew ? Container() : cartonSizeDropdown(), - _isNew ? Container() : dimBox, - _isNew - ? Container() - : LocalTitle(textKey: "box.delivery_address"), - _isNew - ? Container() - : DefaultDeliveryAddress( - deliveryAddress: _deliveryAddress, - labelKey: "box.delivery_address", - onTap: () async { - DeliveryAddress? d = - await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => - DeliveryAddressSelection( - deliveryAddress: _deliveryAddress, - user: User( - id: _carton!.userID, - name: _carton!.userName))), - ); - if (d == null) return; - setState(() { - _deliveryAddress = d; - }); - }), - ]), - SizedBox( - height: 20, - ), - isFromPackages || isFromCartons - ? _isNew - ? createBtn - : saveBtn - : Container(), - isMixBox ? createMixCarton : Container(), - SizedBox( - height: 20, - ), - ], - ), - ), - ), - ); - } - - List _getCartons(BuildContext context, List cartons) { - return cartons.asMap().entries.map((c) { - return InkWell( - onTap: () async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - - if (isFromPackages) { - _loadPackages(); - c.value.packages = _carton!.packages; - Carton? _c = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => PackageCartonEditor( - carton: c.value, - isNew: false, - consignee: _user, - )), - ); - if (_c == null) return; - cartons.removeWhere((item) => item.id == _c.id); - cartons.insert(c.key, _c); - setState(() {}); - } - }, - child: CartonRow( - key: ValueKey(c.value.id), - box: c.value, - ), - ); - }).toList(); - } - - List _getMixCartons(BuildContext context, List cartons) { - return cartons.map((c) { - return CartonRow( - key: ValueKey(c.id), - box: c, - ); - }).toList(); - } - - Widget cartonSizeDropdown() { - List _cartonSizes = - Provider.of(context).getCartonSizes; - - return Padding( - padding: const EdgeInsets.only(top: 10), - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(left: 0, right: 10), - child: Icon(AntDesign.CodeSandbox, color: primaryColor), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(right: 18.0), - child: LocalText( - context, - "box.carton_size", - color: Colors.black54, - fontSize: 16, - ), - ), - DropdownButton( - isDense: true, - value: selectedCatonSize, - style: TextStyle(color: Colors.black, fontSize: 14), - underline: Container( - height: 1, - color: Colors.grey, - ), - onChanged: (CartonSize? newValue) { - setState(() { - if (newValue!.name == MANAGE_CARTONSIZE) { - selectedCatonSize = null; - _manageCartonSize(); - return; - } - selectedCatonSize = newValue; - _widthController.text = - selectedCatonSize!.width.toString(); - _heightController.text = - selectedCatonSize!.height.toString(); - _lengthController.text = - selectedCatonSize!.length.toString(); - }); - }, - isExpanded: true, - items: _cartonSizes - .map>((CartonSize value) { - return DropdownMenuItem( - value: value, - child: Text(value.name ?? "", - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: value.name == MANAGE_CARTONSIZE - ? secondaryColor - : primaryColor)), - ); - }).toList(), - ), - ], - ), - ), - ], - ), - ); - } - - _manageCartonSize() { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => CartonSizeList()), - ); - } - - _removeCargo(CargoType cargo) { - setState(() { - _cargoTypes.remove(cargo); - }); - } - - _updateCargo(CargoType cargo) { - setState(() { - var _c = _cargoTypes.firstWhere((e) => e.id == cargo.id); - _c.weight = cargo.weight; - _c.qty = cargo.qty; - }); - } - - _addCarton() async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - - if (_fcsShipment == null && _isNew) { - showMsgDialog(context, "Error", "Please select FCS shipment"); - return; - } - - if (_user == null && isFromPackages) { - showMsgDialog(context, "Error", "Please select FCS ID"); - return; - } - - if (consignee == null && isFromCartons) { - showMsgDialog(context, "Error", "Please select consignee's FCS ID"); - return; - } - - if (sender == null && isFromCartons) { - showMsgDialog(context, "Error", "Please select sender's FCS ID"); - return; - } - - double l = double.parse(_lengthController.text); - double w = double.parse(_widthController.text); - double h = double.parse(_heightController.text); - - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - if (isFromPackages) { - carton.userID = _user?.id ?? ''; - carton.fcsID = _user?.fcsID ?? ''; - carton.userName = _user?.name ?? ''; - carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); - } - - if (isFromCartons) { - carton.userID = consignee?.id ?? ""; - carton.fcsID = consignee?.fcsID ?? ""; - carton.userName = consignee?.name ?? ""; - carton.senderID = sender?.id ?? ""; - carton.senderFCSID = sender?.fcsID ?? ""; - carton.senderName = sender?.name ?? ""; - } - - carton.cargoTypes = _carton!.cargoTypes; - carton.length = l; - carton.width = w; - carton.height = h; - carton.deliveryAddress = _carton!.deliveryAddress; - - try { - Carton? _c = await Navigator.push( - context, - CupertinoPageRoute( - builder: (context) => PackageCartonEditor( - carton: carton, - isNew: _isNew, - consignee: _user, - )), - ); - if (_c == null) return; - var cartonModel = Provider.of(context, listen: false); - Carton _carton = await cartonModel.getCarton(_c.id ?? ""); - if (isFromPackages) { - _cartons.add(_carton); - } - - if (isFromCartons) { - _cartonsFromCartons.add(_carton); - } - - setState(() {}); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } - } - - _addMixCarton(Carton carton) { - if (this._mixCartons.any((c) => c.id == carton.id)) return; - setState(() { - this._mixCartons.add(carton); - }); - } - - _removeMixCarton(Carton carton) { - setState(() { - this._mixCartons.removeWhere((c) => c.id == carton.id); - }); - } - - _creatMixCarton() async { - if (_fcsShipment == null && _isNew) { - showMsgDialog(context, "Error", "Please select FCS shipment"); - return; - } - if (this._mixCartons.length == 0) { - showMsgDialog(context, "Error", "Expect at least one carton"); - return; - } - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - carton.mixBoxType = _selectedMixBoxType!; - carton.mixCartons = this._mixCartons; - setState(() { - _isLoading = true; - }); - try { - CartonModel cartonModel = - Provider.of(context, listen: false); - if (_isNew) { - await cartonModel.createCarton(carton); - } else { - await cartonModel.updateCarton(carton); - } - Navigator.pop(context, true); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } - - _save() async { - bool isFromPackages = _selectedCartonType == carton_from_packages; - bool isFromCartons = _selectedCartonType == carton_from_cartons; - if (_cargoTypes.length == 0 && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Expect at least one cargo type"); - return; - } - if (_cargoTypes.where((c) => c.weight <= 0).isNotEmpty) { - showMsgDialog(context, "Error", "Invalid cargo weight"); - return; - } - double l = double.parse(_lengthController.text); - double w = double.parse(_widthController.text); - double h = double.parse(_heightController.text); - if ((l <= 0 || w <= 0 || h <= 0) && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Invalid dimension"); - return; - } - if (_deliveryAddress == null && (isFromPackages || isFromCartons)) { - showMsgDialog(context, "Error", "Invalid delivery address"); - return; - } - - Carton carton = Carton(); - carton.id = _carton!.id; - carton.cartonType = _selectedCartonType!; - carton.fcsShipmentID = _isNew ? _fcsShipment!.id : _carton!.fcsShipmentID; - if (isFromPackages) { - carton.userID = _user?.id ?? ""; - carton.packages = _carton!.packages.where((e) => e.isChecked).toList(); - } - if (isFromCartons) { - carton.userID = consignee?.id ?? ""; - carton.senderID = sender?.id ?? ""; - } - - carton.cargoTypes = _cargoTypes; - carton.length = l; - carton.width = w; - carton.height = h; - carton.deliveryAddress = _deliveryAddress; - - setState(() { - _isLoading = true; - }); - try { - CartonModel cartonModel = - Provider.of(context, listen: false); - await cartonModel.updateCarton(carton); - Navigator.pop(context, true); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } -} diff --git a/lib/pages/carton/carton_editor.dart b/lib/pages/carton/carton_editor.dart index d2c5938..7f975cf 100644 --- a/lib/pages/carton/carton_editor.dart +++ b/lib/pages/carton/carton_editor.dart @@ -2,7 +2,7 @@ import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; diff --git a/lib/pages/carton/carton_filter.dart b/lib/pages/carton/carton_filter.dart new file mode 100644 index 0000000..27b687d --- /dev/null +++ b/lib/pages/carton/carton_filter.dart @@ -0,0 +1,441 @@ +import 'package:fcs/pages/carton/model/sender_selection_model.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../domain/constants.dart'; +import '../../domain/entities/user.dart'; +import '../../helpers/theme.dart'; +import '../../localization/app_translations.dart'; +import '../main/util.dart'; +import '../widgets/local_text.dart'; +import 'user_search_result.dart'; +import 'model/carton_model.dart'; +import 'model/consignee_selection_model.dart'; + +class CartonFilter extends StatefulWidget { + final ScrollController controller; + const CartonFilter({Key? key, required this.controller}) : super(key: key); + + @override + _CartonFilterState createState() => _CartonFilterState(); +} + +class _CartonFilterState extends State { + String? _selectedStatus; + User? _selectedSender; + User? _selectedConsignee; + + List statusList = [ + all_status, + carton_processing_status, + carton_shipped_status, + carton_arrived_status, + carton_invoiced_status, + carton_canceled_status + ]; + + final TextEditingController _consigneeCtl = TextEditingController(); + String _consigneeQuery = ""; + bool _isLoadMoreConsignee = false; + + final TextEditingController _senderCtl = TextEditingController(); + String _senderQuery = ""; + bool _isLoadMoreSender = false; + + @override + void initState() { + var model = Provider.of(context, listen: false); + _selectedStatus = model.filterByStatus ?? all_status; + _selectedConsignee = model.filterByConsingee ?? User(id: all, name: "All"); + _selectedSender = model.filterBySender ?? User(id: all, name: "All"); + init(); + super.initState(); + } + + init() async { + _initConsignee(); + _initSender(); + if (mounted) { + setState(() {}); + } + } + + _initConsignee() { + var model = context.read(); + _consigneeCtl.text = model.query; + _consigneeQuery = model.query; + if (_consigneeQuery != "") { + _searchConsignee(); + } else { + model.addDefaultConsginees(); + } + + if (mounted) { + setState(() {}); + } + } + + _initSender() { + var model = context.read(); + + _senderCtl.text = model.query; + _senderQuery = model.query; + if (_senderQuery != "") { + _searchSender(); + } else { + model.addDefaultSenders(); + } + + if (mounted) { + setState(() {}); + } + } + + Future _loadMoreConsignee() async { + if (_isLoadMoreConsignee) return; + var model = context.read(); + if (model.reachEnd || model.ended) return; + setState(() { + _isLoadMoreConsignee = true; + }); + if (_consigneeQuery != "") { + await model.loadMoreSearch(term: _consigneeQuery); + } else { + await model.loadMoreData(); + } + + setState(() { + _isLoadMoreConsignee = false; + }); + } + + Future _loadMoreSender() async { + if (_isLoadMoreSender) return; + var model = context.read(); + if (model.reachEnd || model.ended) return; + setState(() { + _isLoadMoreSender = true; + }); + if (_senderQuery != "") { + await model.loadMoreSearch(term: _senderQuery); + } else { + await model.loadMoreData(); + } + + setState(() { + _isLoadMoreSender = false; + }); + } + + @override + Widget build(BuildContext context) { + var consigneeModel = context.watch(); + List consignees = consigneeModel.getConsginees; + var senderModel = context.watch(); + List senders = senderModel.getSenders; + + final _titleWidget = SizedBox( + height: 30, + child: TabBar( + unselectedLabelColor: Colors.grey, + labelColor: primaryColor, + indicatorColor: primaryColor, + indicatorSize: TabBarIndicatorSize.tab, + labelPadding: const EdgeInsets.all(0), + indicatorPadding: const EdgeInsets.all(0), + tabs: [ + Tab( + text: AppTranslations.of(context)?.text("box.consignee.title"), + ), + Tab( + text: AppTranslations.of(context)?.text("box.sender.title"), + ), + Tab( + text: AppTranslations.of(context)?.text("box.status"), + ), + ], + ), + ); + + final _consingeeWidget = Column( + children: [ + const SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only(left: 20, right: 20), + child: searchBox( + context, + controller: _consigneeCtl, + onSubmitted: (value) { + setState(() { + _consigneeQuery = value; + }); + _searchConsignee(imm: true); + }, + onChanged: (v) { + setState(() { + _consigneeQuery = v; + }); + _searchConsignee(); + }, + onClear: () { + setState(() { + _consigneeCtl.clear(); + _consigneeQuery = ""; + }); + _searchConsignee(); + }, + )), + Expanded( + child: UserSearchResult( + searchResults: consignees, + isLoading: consigneeModel.isLoading, + noDataLabelKey: 'user.no_consignee', + selectedUser: _selectedConsignee, + controller: widget.controller, + isLoadingMore: _isLoadMoreConsignee, + onLoadMore: _loadMoreConsignee, + onRefresh: () async { + _initConsignee(); + }, + onTap: (a) async { + setState(() { + _selectedConsignee = a; + }); + }, + ), + ) + ], + ); + + final _senderWidget = Column( + children: [ + const SizedBox(height: 15), + Padding( + padding: const EdgeInsets.only(left: 20, right: 20), + child: searchBox( + context, + controller: _senderCtl, + onSubmitted: (value) { + setState(() { + _senderQuery = value; + }); + _searchSender(imm: true); + }, + onChanged: (v) { + setState(() { + _senderQuery = v; + }); + _searchSender(); + }, + onClear: () { + setState(() { + _senderCtl.clear(); + _senderQuery = ""; + }); + _searchSender(); + }, + )), + Expanded( + child: UserSearchResult( + searchResults: senders, + isLoading: senderModel.isLoading, + noDataLabelKey: 'user.no_sender', + selectedUser: _selectedSender, + controller: widget.controller, + isLoadingMore: _isLoadMoreSender, + onLoadMore: _loadMoreSender, + onRefresh: () async { + _initSender(); + }, + onTap: (a) async { + setState(() { + _selectedSender = a; + }); + }, + ), + ) + ], + ); + + final _statusWidget = ListView( + controller: widget.controller, + children: statusList.map((b) { + return ListTile( + onTap: () => _changeStatus(b), + title: Row( + children: [ + Text(b, style: const TextStyle(fontSize: 15)), + const SizedBox( + width: 20, + ), + _selectedStatus != null && _selectedStatus == b + ? const Icon( + Icons.check, + color: Colors.grey, + ) + : const SizedBox() + ], + ), + ); + }).toList(), + ); + + return Material( + color: Colors.transparent, + child: Column( + children: [ + const SizedBox(height: 3), + Padding( + padding: const EdgeInsets.only(right: 10, left: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: () => _backAction(), + icon: const Icon( + Icons.arrow_back, + color: primaryColor, + )), + Row( + children: [ + OutlinedButton( + style: OutlinedButton.styleFrom( + padding: EdgeInsets.only(left: 10, right: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0)), + side: BorderSide(color: Colors.grey), + ), + onPressed: () => _clearFilter(), + child: LocalText( + context, + 'btn.clear', + color: primaryColor, + fontSize: 14, + ), + ), + const SizedBox(width: 15), + OutlinedButton( + style: OutlinedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5.0)), + backgroundColor: primaryColor, + ), + onPressed: () => _filter(), + child: LocalText( + context, + 'btn.filter', + color: Colors.white, + fontSize: 14, + ), + ), + ], + ) + ], + ), + ), + Expanded( + child: DefaultTabController( + length: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _titleWidget, + Expanded( + child: TabBarView(children: [ + _consingeeWidget, + _senderWidget, + _statusWidget + ])) + ], + ), + ), + ), + ], + ), + ); + } + + Widget searchBox(BuildContext context, + {TextEditingController? controller, + Function(String)? onSubmitted, + Function(String)? onChanged, + Function()? onClear}) { + return SizedBox( + height: 40, + child: TextField( + controller: controller, + cursorColor: primaryColor, + onSubmitted: onSubmitted, + onChanged: onChanged, + 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 FCS ID or Name", + hintStyle: const TextStyle( + color: Colors.grey, + fontSize: 16, + fontWeight: FontWeight.normal), + suffixIcon: IconButton( + splashRadius: 20, + onPressed: onClear, + icon: const Icon(Icons.close, color: Colors.black87)), + contentPadding: const EdgeInsets.all(10), + filled: true), + ), + ); + } + + _searchConsignee({bool imm = false}) async { + try { + await context + .read() + .search(_consigneeQuery, imm: imm); + } catch (e) { + showMsgDialog(context, 'Error', e.toString()); + } + } + + _searchSender({bool imm = false}) async { + try { + await context.read().search(_senderQuery, imm: imm); + } catch (e) { + showMsgDialog(context, 'Error', e.toString()); + } + } + + _changeStatus(status) async { + _selectedStatus = status; + + if (mounted) { + setState(() {}); + } + } + + _backAction() { + context.read().clear(); + context.read().clear(); + Navigator.pop(context); + } + + _clearFilter() async { + await context.read().filterCarton( + User(id: all, name: "All"), User(id: all, name: "All"), all_status); + Navigator.pop(context); + } + + _filter() async { + await context + .read() + .filterCarton(_selectedConsignee, _selectedSender, _selectedStatus); + Navigator.pop(context); + } +} diff --git a/lib/pages/carton/carton_list.dart b/lib/pages/carton/carton_list.dart index 1cf133d..0802189 100644 --- a/lib/pages/carton/carton_list.dart +++ b/lib/pages/carton/carton_list.dart @@ -1,17 +1,22 @@ +import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/carton/model/carton_model.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; -import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:provider/provider.dart'; +import '../../domain/constants.dart'; import '../../domain/entities/carton.dart'; import '../../pagination/paginator_listview.dart'; +import '../carton_search/carton_search.dart'; +import '../fcs_shipment/model/fcs_shipment_model.dart'; import 'carton_editor.dart'; +import 'carton_filter.dart'; +import 'carton_info.dart'; import 'carton_list_row.dart'; class CartonList extends StatefulWidget { @@ -21,7 +26,8 @@ class CartonList extends StatefulWidget { class _CartonListState extends State { bool _isLoading = false; - int _selectedIndex = 1; + List _shipments = []; + FcsShipment? _selectedShipment; @override void initState() { @@ -29,10 +35,14 @@ class _CartonListState extends State { _init(); } - _init() { + _init() async { var model = context.read(); - _selectedIndex = model.selectedIndex; - model.loadPaginationBoxes(_selectedIndex); + _shipments = await context.read().getAllShipments(); + _shipments.insert(0, FcsShipment(shipmentNumber: "All Shipments", id: all)); + _selectedShipment = + model.shipment ?? FcsShipment(shipmentNumber: "All Shipments", id: all); + model.loadPaginationCartons(); + if (mounted) { setState(() {}); } @@ -40,29 +50,66 @@ class _CartonListState extends State { @override Widget build(BuildContext context) { - var boxModel = Provider.of(context); + var cartonModel = Provider.of(context); + + final shipmentFilterBox = Align( + alignment: Alignment.topLeft, + child: SingleChildScrollView( + padding: const EdgeInsets.only(left: 15, right: 15), + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: _shipments.map((g) { + return Padding( + padding: const EdgeInsets.all(5.0), + child: ActionChip( + shape: StadiumBorder( + side: BorderSide( + color: _selectedShipment?.id == g.id + ? primaryColor + : Colors.grey.shade300)), + padding: const EdgeInsets.all(8), + onPressed: () { + _filterShipment(g); + }, + label: Text(g.shipmentNumber ?? "", + style: TextStyle( + color: _selectedShipment?.id == g.id + ? primaryColor + : labelColor, + fontWeight: FontWeight.normal, + fontSize: 14, + fontFamily: "Poppins")), + ), + ); + }).toList()), + ), + ); - final popupMenu = LocalPopupMenuButton( - popmenus: [ - LocalPopupMenu( - id: 1, - textKey: "box.popupmenu.active", - selected: boxModel.selectedIndex == 1), - LocalPopupMenu( - id: 2, - textKey: "box.popupmenu.delivered", - selected: boxModel.selectedIndex == 2) - ], - popupMenuCallback: (p) { - setState(() { - _selectedIndex = p.id; - }); - context.read().onChanged(_selectedIndex); - }); return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( - appBar: LocalAppBar(labelKey: "boxes.name", actions: [popupMenu]), + appBar: LocalAppBar(labelKey: "boxes.name", actions: [ + IconButton( + icon: Icon( + Icons.search, + color: Colors.white, + ), + iconSize: 30, + onPressed: () { + searchCarton(context, callbackCartonSelect: (c) { + Navigator.push( + context, + CupertinoPageRoute( + builder: (context) => CartonInfo(box: c)), + ); + }); + }), + _filterWidget(context) + ]), floatingActionButton: FloatingActionButton.extended( onPressed: () { _newBox(); @@ -71,10 +118,110 @@ class _CartonListState extends State { label: LocalText(context, "boxes.new", color: Colors.white), backgroundColor: primaryColor, ), - body: PaginatorListView( - paginatorListener: boxModel.getBoxes!, - rowBuilder: (p) => CartonListRow(box: p), - color: primaryColor), + body: Column( + children: [ + shipmentFilterBox, + Wrap( + runSpacing: 8, + children: [ + cartonModel.filterByConsingee != null + ? Padding( + padding: const EdgeInsets.only(left: 15), + child: Row( + children: [ + Wrap( + children: [ + Row( + children: [ + const Text("Consignee: ", + style: TextStyle( + fontSize: 12, color: Colors.grey)), + Text( + cartonModel.filterByConsingee!.name ?? + "", + style: const TextStyle( + fontSize: 12, color: Colors.black)), + const SizedBox(width: 3), + Text( + cartonModel.filterByConsingee!.fcsID ?? + "", + style: const TextStyle( + fontSize: 12, color: labelColor)), + ], + ) + ], + ), + Padding( + padding: const EdgeInsets.only(left: 5), + child: InkResponse( + radius: 30, + onTap: () { + context + .read() + .clearFilterConsignee(); + }, + child: const Icon(AntDesign.closecircleo, + size: 20, color: dangerColor), + ), + ) + ], + ), + ) + : const SizedBox(), + cartonModel.filterBySender != null + ? Padding( + padding: const EdgeInsets.only(left: 15), + child: Row( + children: [ + Wrap( + children: [ + Row( + children: [ + const Text("Sender: ", + style: TextStyle( + fontSize: 12, color: Colors.grey)), + Text(cartonModel.filterBySender!.name ?? "", + style: const TextStyle( + fontSize: 12, color: Colors.black)), + const SizedBox(width: 3), + Text( + cartonModel.filterBySender!.fcsID ?? "", + style: const TextStyle( + fontSize: 12, color: labelColor)), + ], + ) + ], + ), + Padding( + padding: const EdgeInsets.only(left: 5), + child: InkResponse( + radius: 30, + onTap: () { + context + .read() + .clearFilterSender(); + }, + child: const Icon(AntDesign.closecircleo, + size: 20, color: dangerColor), + ), + ) + ], + ), + ) + : const SizedBox(), + ], + ), + Divider(color: Colors.grey.shade400), + Expanded( + child: cartonModel.getBoxes == null + ? const SizedBox() + : PaginatorListView( + paginatorListener: cartonModel.getBoxes!, + rowBuilder: (p) => CartonListRow(box: p), + color: primaryColor), + ), + ], + ), ), ); } @@ -85,4 +232,58 @@ class _CartonListState extends State { CupertinoPageRoute(builder: (context) => CartonEditor()), ); } + + Widget _filterWidget(BuildContext context) { + var model = Provider.of(context); + return IconButton( + icon: Stack( + alignment: Alignment.center, + children: [ + const Icon( + Icons.filter_list, + color: Colors.white, + ), + model.filterByStatus != null || + model.filterBySender != null || + model.filterByConsingee != null + ? Positioned( + bottom: 15, + right: 0, + child: Container( + width: 10, + height: 10, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.red, + ), + ), + ) + : Container() + ], + ), + onPressed: () async { + await showModalBottomSheet( + context: context, + useRootNavigator: true, + isScrollControlled: true, + useSafeArea: true, + shape: const RoundedRectangleBorder( + borderRadius: + BorderRadius.vertical(top: Radius.circular(10))), + builder: (ctx) => DraggableScrollableSheet( + initialChildSize: 0.6, + minChildSize: 0.6, + expand: false, + builder: (_, controller) => + CartonFilter(controller: controller))); + }); + } + + _filterShipment(FcsShipment shipment) async { + setState(() { + _selectedShipment = shipment; + }); + + await context.read().filterCartonByShipment(_selectedShipment); + } } diff --git a/lib/pages/carton/carton_list_row.dart b/lib/pages/carton/carton_list_row.dart index b587c7a..fe0627e 100644 --- a/lib/pages/carton/carton_list_row.dart +++ b/lib/pages/carton/carton_list_row.dart @@ -28,7 +28,7 @@ class CartonListRow extends StatelessWidget { children: [ Expanded( child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), + padding: const EdgeInsets.symmetric(vertical: 10.0), child: new Row( children: [ Container( @@ -64,7 +64,7 @@ class CartonListRow extends StatelessWidget { ), const SizedBox(width: 15), IconButton( - onPressed: () {}, icon: Icon(AntDesign.qrcode)) + onPressed: () {}, icon: Icon(AntDesign.qrcode,color: Colors.black)) ], ), ), diff --git a/lib/pages/carton/mix_carton/carton_selection_widget.dart b/lib/pages/carton/mix_carton/carton_selection_widget.dart index 6e7c9d8..dbfcff6 100644 --- a/lib/pages/carton/mix_carton/carton_selection_widget.dart +++ b/lib/pages/carton/mix_carton/carton_selection_widget.dart @@ -47,11 +47,11 @@ class _CartonSelectionWidgetState extends State { } _init() { - var searchModel = context.read(); - searchModel.addDefaultCartons(widget.shipment.id!); + var model = context.read(); + model.addDefaultCartons(widget.shipment.id!); - _controller.text = searchModel.query; - _query = searchModel.query; + _controller.text = model.query; + _query = model.query; if (mounted) { setState(() {}); } @@ -89,7 +89,6 @@ class _CartonSelectionWidgetState extends State { final continueBtn = ContinueButton( onTap: () { - if (selectedCartonList.isEmpty || searchResults.isEmpty) { showMsgDialog(context, 'Error', "Please select the cartons"); return false; diff --git a/lib/pages/carton/model/carton_model.dart b/lib/pages/carton/model/carton_model.dart index d2bc72b..abb86e2 100644 --- a/lib/pages/carton/model/carton_model.dart +++ b/lib/pages/carton/model/carton_model.dart @@ -4,26 +4,24 @@ import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/data/services/services.dart'; import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/carton.dart'; +import 'package:fcs/domain/entities/fcs_shipment.dart'; import 'package:fcs/pages/main/model/base_model.dart'; import 'package:fcs/pagination/paginator_listener.dart'; import 'package:logging/logging.dart'; +import '../../../domain/entities/user.dart'; + class CartonModel extends BaseModel { final log = Logger('CartonModel'); PaginatorListener? cartonsByFilter; PaginatorListener? getBoxes; - int selectedIndex = 1; - int _selectedIndexFilter = 1; - bool isLoading = false; + String? filterByStatus; + User? filterBySender; + User? filterByConsingee; + FcsShipment? shipment; - List cartonTypes = [ - carton_from_packages, - carton_from_cartons, - carton_mix_box - ]; - List mixBoxTypes = [mix_delivery, mix_pickup]; List cartonTypesInfo = [ carton_from_packages, carton_from_cartons, @@ -32,15 +30,6 @@ class CartonModel extends BaseModel { carton_small_bag ]; - int get selectedIndexFilter => _selectedIndexFilter; - - set selectedIndexFilter(int index) { - _selectedIndexFilter = index; - _loadPaginationCartons( - _selectedIndexFilter == 1 ? "carton_weight" : "user_name"); - notifyListeners(); - } - @override void privilegeChanged() { if (user != null || !user!.hasCarton()) { @@ -60,34 +49,83 @@ class CartonModel extends BaseModel { Future _initData() async { logout(); - _selectedIndexFilter = 1; - _loadPaginationCartons( - _selectedIndexFilter == 1 ? "carton_weight" : "user_name"); + + _loadPaginationCartons(); } - onChanged(int index) { - selectedIndex = index; - loadPaginationBoxes(selectedIndex); + filterCarton(User? consignee, User? sender, String? status) async { + filterByStatus = status; + + if (status == all_status) { + filterByStatus = null; + } else { + filterByStatus = status; + } + + if (consignee?.id == all) { + filterByConsingee = null; + } else { + filterByConsingee = consignee; + } + + if (sender?.id == all) { + filterBySender = null; + } else { + filterBySender = sender; + } + + loadPaginationCartons(); notifyListeners(); } - Future loadPaginationBoxes(int index) async { + filterCartonByShipment(FcsShipment? fcsShipment) { + if (fcsShipment?.id == all) { + shipment = null; + } else { + shipment = fcsShipment; + } + + loadPaginationCartons(); + notifyListeners(); + } + + clearFilterSender() async { + filterBySender = null; + loadPaginationCartons(); + notifyListeners(); + } + + clearFilterConsignee() async { + filterByConsingee = null; + loadPaginationCartons(); + notifyListeners(); + } + + Future loadPaginationCartons() async { if (user == null || !user!.hasCarton()) return; String path = "/$cartons_collection"; Query col = FirebaseFirestore.instance.collection(path); Query pageQuery = FirebaseFirestore.instance.collection(path); - if (index == 1) { - col = col.where("status", - whereIn: [carton_packed_status, carton_shipped_status]); - pageQuery = pageQuery.where("status", - whereIn: [carton_packed_status, carton_shipped_status]); + if (filterByConsingee != null) { + col = col.where("user_id", isEqualTo: filterByConsingee!.id); + pageQuery = pageQuery.where("user_id", isEqualTo: filterByConsingee!.id); } - if (index == 2) { - col = col.where("is_delivered", isEqualTo: true); - pageQuery = pageQuery.where("is_delivered", isEqualTo: true); + if (filterBySender != null) { + col = col.where("sender_id", isEqualTo: filterBySender!.id); + pageQuery = pageQuery.where("sender_id", isEqualTo: filterBySender!.id); + } + + if (filterByStatus != null) { + col = col.where("status", isEqualTo: filterByStatus); + pageQuery = pageQuery.where("status", isEqualTo: filterByStatus); + } + + if (shipment != null) { + col = col.where("fcs_shipment_id", isEqualTo: shipment!.id); + pageQuery = pageQuery.where("fcs_shipment_id", isEqualTo: shipment!.id); } pageQuery = pageQuery.orderBy("created_at", descending: true); @@ -98,21 +136,23 @@ class CartonModel extends BaseModel { rowPerLoad: 30); } - _loadPaginationCartons(String orderName) { + _loadPaginationCartons() { if (user == null || !user!.hasCarton()) return null; String path = "/$cartons_collection"; - Query col = FirebaseFirestore.instance.collection(path).where("carton_type", - whereIn: [ - carton_from_packages, - carton_from_cartons - ]).where("status", isEqualTo: carton_packed_status); + Query col = FirebaseFirestore.instance.collection(path); + // .where("carton_type", + // whereIn: [ + // carton_from_packages, + // carton_from_cartons + // ]).where("status", isEqualTo: carton_packed_status) + // ; Query pageQuery = FirebaseFirestore.instance .collection(path) - .where("carton_type", - whereIn: [carton_from_packages, carton_from_cartons]) - .where("status", isEqualTo: carton_packed_status) - .orderBy(orderName, descending: true); + // .where("carton_type", + // whereIn: [carton_from_packages, carton_from_cartons]) + // .where("status", isEqualTo: carton_packed_status) + .orderBy("created_at", descending: true); cartonsByFilter?.close(); cartonsByFilter = PaginatorListener( diff --git a/lib/pages/carton/model/consignee_selection_model.dart b/lib/pages/carton/model/consignee_selection_model.dart new file mode 100644 index 0000000..db136f8 --- /dev/null +++ b/lib/pages/carton/model/consignee_selection_model.dart @@ -0,0 +1,132 @@ +import 'dart:async'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:logging/logging.dart'; + +import '../../../domain/constants.dart'; +import '../../../domain/entities/user.dart'; +import '../../main/model/base_model.dart'; + +class ConsigneeSelectionModel extends BaseModel { + final log = Logger("ConsigneeSearchModel"); + // for search + String query = ""; + int offset = 0; + bool reachEnd = false; + List _consignees = []; + + List get getConsginees { + var users = new List.from(_consignees); + return users..insert(0, User(id: all, name: "All")); + } + + bool isLoading = false; + + // for default user + DocumentSnapshot? _lastDocument; + bool ended = false; + + Timer? t; + search(String term, {bool imm = false}) async { + query = term; + _consignees.clear(); + offset = 0; + reachEnd = false; + t?.cancel(); + t = Timer(Duration(milliseconds: imm ? 0 : 800), () async { + await loadMoreSearch(term: term); + }); + } + + Future loadMoreSearch({required String term}) async { + if (term == "") { + await _refresh(); + return; + } + // int rowPerPage = 21; + // List list = []; + // SearchPara searchPara = SearchPara(filters: [], term: term); + // isLoading = true; + + // var path = + // "/search/$cartons_collection/${searchPara.escapeTerm}/$rowPerPage/$offset/${searchPara.escapeFilters}"; + + // var result = await requestAPI(path, "GET", + // token: await getToken(), url: Config.instance.searchURL); + + // if (result != null) { + // for (var row in result) { + // var item = ArtistExt.fromMapForSearch(row); + // list.add(item); + // } + // } + + // for (var p in list) { + // selectedArtistList.contains(p) + // ? p.isSelected = true + // : p.isSelected = false; + // } + + // artists.addAll(list); + // offset += rowPerPage; + // if (list.length < rowPerPage) { + // reachEnd = true; + // } + notifyListeners(); + } + + addDefaultConsginees() async { + _consignees.clear(); + await _refresh(); + } + + Future _refresh() async { + _consignees.clear(); + _lastDocument = null; + ended = false; + await loadMoreData(); + notifyListeners(); + } + + Future loadMoreData() async { + int rowPerPage = 20; + + try { + isLoading = true; + String path = "/$user_collection"; + Query query = FirebaseFirestore.instance + .collection(path) + .where("is_sys_admin", isEqualTo: false) + .where("is_deleted", isEqualTo: false) + .orderBy("message_time", descending: true); + + if (_lastDocument != null) { + query = query.startAfterDocument(_lastDocument!); + } + + QuerySnapshot querySnap = await query.limit(rowPerPage).get(); + + if (querySnap.docs.isEmpty) return; + _lastDocument = querySnap.docs[querySnap.docs.length - 1]; + + List list = querySnap.docs.map((documentSnapshot) { + var p = User.fromMap(documentSnapshot.data() as Map, + documentSnapshot.id); + return p; + }).toList(); + + _consignees.addAll(list); + if (list.length < rowPerPage) ended = true; + notifyListeners(); + } catch (e) { + log.warning("error:$e"); + } finally { + isLoading = false; + } + } + + clear() { + _consignees.clear(); + query = ""; + } +} diff --git a/lib/pages/carton/model/sender_selection_model.dart b/lib/pages/carton/model/sender_selection_model.dart new file mode 100644 index 0000000..705ed6b --- /dev/null +++ b/lib/pages/carton/model/sender_selection_model.dart @@ -0,0 +1,132 @@ +import 'dart:async'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:logging/logging.dart'; + +import '../../../domain/constants.dart'; +import '../../../domain/entities/user.dart'; +import '../../main/model/base_model.dart'; + +class SenderSelectionModel extends BaseModel { + final log = Logger("SenderSelectionModel"); + // for search + String query = ""; + int offset = 0; + bool reachEnd = false; + List _senders = []; + + List get getSenders { + var users = new List.from(_senders); + return users..insert(0, User(id: all, name: "All")); + } + + bool isLoading = false; + + // for default user + DocumentSnapshot? _lastDocument; + bool ended = false; + + Timer? t; + search(String term, {bool imm = false}) async { + query = term; + _senders.clear(); + offset = 0; + reachEnd = false; + t?.cancel(); + t = Timer(Duration(milliseconds: imm ? 0 : 800), () async { + await loadMoreSearch(term: term); + }); + } + + Future loadMoreSearch({required String term}) async { + if (term == "") { + await _refresh(); + return; + } + // int rowPerPage = 21; + // List list = []; + // SearchPara searchPara = SearchPara(filters: [], term: term); + // isLoading = true; + + // var path = + // "/search/$cartons_collection/${searchPara.escapeTerm}/$rowPerPage/$offset/${searchPara.escapeFilters}"; + + // var result = await requestAPI(path, "GET", + // token: await getToken(), url: Config.instance.searchURL); + + // if (result != null) { + // for (var row in result) { + // var item = ArtistExt.fromMapForSearch(row); + // list.add(item); + // } + // } + + // for (var p in list) { + // selectedArtistList.contains(p) + // ? p.isSelected = true + // : p.isSelected = false; + // } + + // artists.addAll(list); + // offset += rowPerPage; + // if (list.length < rowPerPage) { + // reachEnd = true; + // } + notifyListeners(); + } + + addDefaultSenders() async { + _senders.clear(); + await _refresh(); + } + + Future _refresh() async { + _senders.clear(); + _lastDocument = null; + ended = false; + await loadMoreData(); + notifyListeners(); + } + + Future loadMoreData() async { + int rowPerPage = 20; + + try { + isLoading = true; + String path = "/$user_collection"; + Query query = FirebaseFirestore.instance + .collection(path) + .where("is_sys_admin", isEqualTo: false) + .where("is_deleted", isEqualTo: false) + .orderBy("message_time", descending: true); + + if (_lastDocument != null) { + query = query.startAfterDocument(_lastDocument!); + } + + QuerySnapshot querySnap = await query.limit(rowPerPage).get(); + + if (querySnap.docs.isEmpty) return; + _lastDocument = querySnap.docs[querySnap.docs.length - 1]; + + List list = querySnap.docs.map((documentSnapshot) { + var p = User.fromMap(documentSnapshot.data() as Map, + documentSnapshot.id); + return p; + }).toList(); + + _senders.addAll(list); + if (list.length < rowPerPage) ended = true; + notifyListeners(); + } catch (e) { + log.warning("error:$e"); + } finally { + isLoading = false; + } + } + + clear() { + _senders.clear(); + query = ""; + } +} diff --git a/lib/pages/carton/user_search_result.dart b/lib/pages/carton/user_search_result.dart new file mode 100644 index 0000000..1155b6e --- /dev/null +++ b/lib/pages/carton/user_search_result.dart @@ -0,0 +1,103 @@ +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:flutter/material.dart'; + +import '../../../helpers/theme.dart'; +import '../../domain/entities/user.dart'; + +typedef OnAction = Future Function(); + +class UserSearchResult extends StatelessWidget { + final bool isLoadingMore; + final OnAction onLoadMore; + final OnAction onRefresh; + final Function(User)? onTap; + final ScrollController controller; + final User? selectedUser; + final List searchResults; + final String? noDataLabelKey; + final bool isLoading; + + const UserSearchResult( + {super.key, + required this.isLoadingMore, + required this.onLoadMore, + required this.onRefresh, + this.onTap, + required this.controller, + this.selectedUser, + this.searchResults = const [], + this.noDataLabelKey, + this.isLoading = false}); + + bool _scrollNotification(ScrollNotification scrollInfo) { + if (!isLoadingMore && + scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { + onLoadMore(); + } + return true; + } + + @override + Widget build(BuildContext context) { + return searchResults.isEmpty && !isLoading + ? noDataLabelKey== null? const SizedBox(): Center( + child: LocalText(context, noDataLabelKey!, + color: Colors.black, fontSize: 15)) + : Column(children: [ + Expanded( + child: NotificationListener( + onNotification: _scrollNotification, + child: RefreshIndicator( + color: primaryColor, + onRefresh: () => onRefresh(), + child: ListView.builder( + controller: controller, + shrinkWrap: true, + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (context, index) { + User user = searchResults[index]; + + return ListTile( + onTap: () { + if (onTap != null) { + onTap!(user); + } + }, + title: Row( + children: [ + Text(user.name ?? "", + style: const TextStyle( + fontSize: 15, color: Colors.black)), + user.fcsID == null + ? const SizedBox() + : Padding( + padding: const EdgeInsets.only(left: 8), + child: Text(user.fcsID!, + style: const TextStyle( + fontSize: 15, color: labelColor)), + ), + const SizedBox( + width: 20, + ), + selectedUser?.id == user.id + ? const Icon( + Icons.check, + color: Colors.grey, + ) + : const SizedBox() + ], + ), + ); + }, + itemCount: searchResults.length)), + )), + Container( + height: isLoadingMore ? 50.0 : 0, + color: Colors.transparent, + child: const Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(primaryColor)), + )), + ]); + } +} diff --git a/lib/pages/carton_search/carton_list_row.dart b/lib/pages/carton_search/carton_list_row.dart index 1d723a8..c816ea3 100644 --- a/lib/pages/carton_search/carton_list_row.dart +++ b/lib/pages/carton_search/carton_list_row.dart @@ -9,7 +9,6 @@ class CartonListRow extends StatelessWidget { final CallbackCartonSelect? callbackCartonSelect; final Carton carton; - // const CartonListRow({this.carton, this.callbackCartonSelect}); CartonListRow({Key? key, required this.carton, this.callbackCartonSelect}) : super(key: key); @@ -28,63 +27,83 @@ class CartonListRow extends StatelessWidget { Navigator.pop(context); if (callbackCartonSelect != null) callbackCartonSelect!(carton); }, - child: Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: new Row( - children: [ - new Padding( - padding: new EdgeInsets.symmetric( - horizontal: 25.0 - dotSize / 2), - child: Icon( - MaterialCommunityIcons.package, - color: primaryColor, - size: 30, + child: Container( + padding: EdgeInsets.only(left: 15, right: 15), + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 7.0), + child: new Row( + children: [ + Container( + padding: EdgeInsets.only(left: 5), + child: Icon( + MaterialCommunityIcons.package, + color: primaryColor, + size: 30, + ), ), - ), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - carton.cartonNumber ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.black), - ), + new Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 18.0), + child: Row( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + carton.cartonNumber ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + ), + Padding( + padding: const EdgeInsets.only(top: 5), + child: new Text( + carton.userName ?? "", + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ), + ], + ), + const SizedBox(width: 15), + IconButton( + onPressed: () {}, + icon: Icon(AntDesign.qrcode, + color: Colors.black)) + ], ), - Padding( - padding: const EdgeInsets.only(left: 10.0, top: 10), - child: new Text( - carton.userName ?? "", - style: new TextStyle( - fontSize: 15.0, color: Colors.grey), - ), - ) - ], + ), ), - ), - Padding( - padding: const EdgeInsets.only( - left: 8.0, bottom: 5, right: 10), - child: Row( - children: [ - new Text( - "${carton.cartonWeight.toStringAsFixed(2)} lb", - style: new TextStyle( - fontSize: 15.0, color: Colors.grey), - ), - ], - ), - ), - ], + ], + ), ), ), - ), - ], + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text(carton.status ?? "", + style: TextStyle( + color: primaryColor, + fontSize: 15, + fontWeight: FontWeight.bold)), + Padding( + padding: const EdgeInsets.only(top: 5), + child: Row( + children: [ + new Text( + "${carton.cartonWeight.toStringAsFixed(2)} lb", + style: + new TextStyle(fontSize: 15.0, color: Colors.grey), + ), + ], + ), + ), + ], + ) + ], + ), ), ), ); diff --git a/lib/pages/carton_search/carton_search.dart b/lib/pages/carton_search/carton_search.dart index aa78500..10d39c3 100644 --- a/lib/pages/carton_search/carton_search.dart +++ b/lib/pages/carton_search/carton_search.dart @@ -2,9 +2,6 @@ import 'package:fcs/domain/entities/carton.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/carton/model/carton_model.dart'; import 'package:fcs/pages/widgets/barcode_scanner.dart'; -import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; -import 'package:fcs/pagination/paginator_listview.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_vector_icons/flutter_vector_icons.dart'; @@ -50,32 +47,12 @@ class PartSearchDelegate extends SearchDelegate { @override List buildActions(BuildContext context) { - var boxModel = Provider.of(context); - final popupMenu = - StatefulBuilder(builder: (BuildContext context, StateSetter setState) { - return LocalPopupMenuButton( - popmenus: [ - LocalPopupMenu( - id: 1, - textKey: "box.weight", - selected: boxModel.selectedIndexFilter == 1), - LocalPopupMenu( - id: 2, - textKey: "box.name", - selected: boxModel.selectedIndexFilter == 2) - ], - popupMenuCallback: (p) => setState(() { - boxModel.selectedIndexFilter = p.id; - })); - }); - return [ IconButton( icon: Icon(MaterialCommunityIcons.barcode_scan, size: 30, color: Colors.white), onPressed: () => _scan(context), ), - popupMenu, IconButton( icon: Icon(Icons.clear), onPressed: () => query = '', @@ -113,7 +90,6 @@ class PartSearchDelegate extends SearchDelegate { child: ListView( children: snapshot.data! .map((u) => CartonListRow( - key: ValueKey(u.id), carton: u, callbackCartonSelect: callbackCartonSelect, )) @@ -143,18 +119,12 @@ class PartSearchDelegate extends SearchDelegate { @override Widget buildSuggestions(BuildContext context) { - final cartonModel = Provider.of(context); - return Container( - padding: EdgeInsets.only(top: 5), - child: PaginatorListView( - paginatorListener: cartonModel.cartonsByFilter!, - rowBuilder: (c) => CartonListRow( - key: ValueKey(c.id), - carton: c, - callbackCartonSelect: callbackCartonSelect, - ), - color: primaryColor, + child: Center( + child: Opacity( + opacity: 0.2, + child: Icon(MaterialCommunityIcons.package, + size: 200, color: primaryColor)), ), ); } diff --git a/lib/pages/customer/customer_list.dart b/lib/pages/customer/customer_list.dart index 2a12c69..6225afc 100644 --- a/lib/pages/customer/customer_list.dart +++ b/lib/pages/customer/customer_list.dart @@ -6,7 +6,7 @@ import 'package:fcs/pages/chat/model/message_model.dart'; import 'package:fcs/pages/customer/customer_editor.dart'; import 'package:fcs/pages/customer/model/customer_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; diff --git a/lib/pages/delivery/delivery_list.dart b/lib/pages/delivery/delivery_list.dart index bebe5f3..0f5e73d 100644 --- a/lib/pages/delivery/delivery_list.dart +++ b/lib/pages/delivery/delivery_list.dart @@ -1,7 +1,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/pages/discount/discount_editor.dart b/lib/pages/discount/discount_editor.dart index 32333f0..4511576 100644 --- a/lib/pages/discount/discount_editor.dart +++ b/lib/pages/discount/discount_editor.dart @@ -3,7 +3,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; diff --git a/lib/pages/discount/discount_list.dart b/lib/pages/discount/discount_list.dart index 39419ed..e789ce7 100644 --- a/lib/pages/discount/discount_list.dart +++ b/lib/pages/discount/discount_list.dart @@ -3,7 +3,7 @@ import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/discount/discount_list_row.dart'; import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/pages/fcs_shipment/fcs_shipment_list.dart b/lib/pages/fcs_shipment/fcs_shipment_list.dart index 15fe6cd..72cac2f 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_list.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_list.dart @@ -1,13 +1,12 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pagination/paginator_listview.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_vector_icons/flutter_vector_icons.dart'; import 'package:provider/provider.dart'; import '../../domain/entities/fcs_shipment.dart'; import 'fcs_shipment_editor.dart'; @@ -41,14 +40,12 @@ class _FcsShipmentListState extends State { Widget build(BuildContext context) { var shipmentModel = Provider.of(context); - return LocalProgress( + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( - appBar: LocalAppBar( - labelKey: "FCSshipment.list.title", actions: [ - //popupMenu, - _menuFilteringWidget(context), - ]), + appBar: LocalAppBar(labelKey: "FCSshipment.list.title", actions: [ + _menuFilteringWidget(context), + ]), floatingActionButton: FloatingActionButton.extended( onPressed: () { _newShipment(); @@ -67,7 +64,8 @@ class _FcsShipmentListState extends State { Navigator.of(context) .push(CupertinoPageRoute(builder: (context) => FcsShipmentEditor())); } - Widget _menuFilteringWidget(BuildContext context) { + + Widget _menuFilteringWidget(BuildContext context) { return PopupMenuButton( splashRadius: 25, padding: const EdgeInsets.only(right: 15), @@ -81,10 +79,10 @@ class _FcsShipmentListState extends State { await context.read().onChanged(choice.id); }, icon: Stack( - alignment: Alignment.center, + alignment: Alignment.center, children: [ const Icon( - Ionicons.filter, + Icons.filter_list, color: Colors.white, ), _selectedIndex != 0 diff --git a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart index 9d6a6d5..5c5f764 100644 --- a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart +++ b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart @@ -153,4 +153,22 @@ class FcsShipmentModel extends BaseModel { Future report(FcsShipment fcsShipment) { return Services.instance.fcsShipmentService.report(fcsShipment); } + + Future> getAllShipments() async { + List fcsShipments = []; + try { + var snaps = await FirebaseFirestore.instance + .collection("/$fcs_shipment_collection") + .where("is_deleted", isEqualTo: false) + .get(const GetOptions(source: Source.server)); + fcsShipments = snaps.docs.map((documentSnapshot) { + var fcs = + FcsShipment.fromMap(documentSnapshot.data(), documentSnapshot.id); + return fcs; + }).toList(); + } catch (e) { + log.warning("Error!! $e"); + } + return fcsShipments; + } } diff --git a/lib/pages/invoice/editor/invoice_editor.dart b/lib/pages/invoice/editor/invoice_editor.dart index 1449dc1..35b9c34 100644 --- a/lib/pages/invoice/editor/invoice_editor.dart +++ b/lib/pages/invoice/editor/invoice_editor.dart @@ -29,7 +29,7 @@ import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_dropdown.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; diff --git a/lib/pages/invoice/invoice_list.dart b/lib/pages/invoice/invoice_list.dart index 2bc0115..063d0e1 100644 --- a/lib/pages/invoice/invoice_list.dart +++ b/lib/pages/invoice/invoice_list.dart @@ -3,7 +3,7 @@ import 'package:fcs/pages/invoice/invoice_shipment_list.dart'; import 'package:fcs/pages/invoice/model/invoice_model.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/pages/package/package_list.dart b/lib/pages/package/package_list.dart index 0702d07..7de1f57 100644 --- a/lib/pages/package/package_list.dart +++ b/lib/pages/package/package_list.dart @@ -3,10 +3,10 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/package/package_list_row.dart'; -import 'package:fcs/pages/package_search/package_serach.dart'; +import 'package:fcs/pages/package_search/package_search.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pagination/paginator_listview.dart'; import 'package:flutter/cupertino.dart'; diff --git a/lib/pages/package/package_new.dart b/lib/pages/package/package_new.dart index 00bcbdb..9b91118 100644 --- a/lib/pages/package/package_new.dart +++ b/lib/pages/package/package_new.dart @@ -2,7 +2,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/package/tracking_id_page.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; diff --git a/lib/pages/package_search/package_serach.dart b/lib/pages/package_search/package_search.dart similarity index 100% rename from lib/pages/package_search/package_serach.dart rename to lib/pages/package_search/package_search.dart diff --git a/lib/pages/processing/package_editor.dart b/lib/pages/processing/package_editor.dart index 0847c88..d499c1c 100644 --- a/lib/pages/processing/package_editor.dart +++ b/lib/pages/processing/package_editor.dart @@ -8,7 +8,7 @@ import 'package:fcs/pages/market/model/market_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/tracking_id_page.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/package_search/package_serach.dart'; +import 'package:fcs/pages/package_search/package_search.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; diff --git a/lib/pages/processing/processing_edit_editor.dart b/lib/pages/processing/processing_edit_editor.dart index ee68b96..ca21d0a 100644 --- a/lib/pages/processing/processing_edit_editor.dart +++ b/lib/pages/processing/processing_edit_editor.dart @@ -7,7 +7,7 @@ import 'package:fcs/pages/market/model/market_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/tracking_id_page.dart'; import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/input_text.dart'; diff --git a/lib/pages/processing/processing_editor.dart b/lib/pages/processing/processing_editor.dart index fa0d5a5..3c4f637 100644 --- a/lib/pages/processing/processing_editor.dart +++ b/lib/pages/processing/processing_editor.dart @@ -4,7 +4,7 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/package/package_info.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; diff --git a/lib/pages/processing/processing_list.dart b/lib/pages/processing/processing_list.dart index 38816bc..3aa686a 100644 --- a/lib/pages/processing/processing_list.dart +++ b/lib/pages/processing/processing_list.dart @@ -1,7 +1,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/package_search/package_serach.dart'; +import 'package:fcs/pages/package_search/package_search.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; diff --git a/lib/pages/receiving/receiving_editor.dart b/lib/pages/receiving/receiving_editor.dart index c3f66a0..2529530 100644 --- a/lib/pages/receiving/receiving_editor.dart +++ b/lib/pages/receiving/receiving_editor.dart @@ -3,7 +3,7 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:fcs/pages/widgets/barcode_scanner.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; diff --git a/lib/pages/receiving/receiving_list.dart b/lib/pages/receiving/receiving_list.dart index 3a5ee8f..6a60840 100644 --- a/lib/pages/receiving/receiving_list.dart +++ b/lib/pages/receiving/receiving_list.dart @@ -1,7 +1,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/package_search/package_serach.dart'; +import 'package:fcs/pages/package_search/package_search.dart'; import 'package:fcs/pages/widgets/local_app_bar.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; diff --git a/lib/pages/shipment/shipment_info.dart b/lib/pages/shipment/shipment_info.dart index 97b66cd..8a1906d 100644 --- a/lib/pages/shipment/shipment_info.dart +++ b/lib/pages/shipment/shipment_info.dart @@ -12,7 +12,7 @@ import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_button.dart'; import 'package:fcs/pages/widgets/local_popup_menu_button.dart'; -import 'package:fcs/pages/widgets/local_popupmenu.dart'; +import 'package:fcs/domain/vo/local_popupmenu.dart'; import 'package:fcs/pages/widgets/local_radio_buttons.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/local_title.dart'; diff --git a/lib/pages/user_search/user_list_row.dart b/lib/pages/user_search/user_list_row.dart index d7758c7..ffdc859 100644 --- a/lib/pages/user_search/user_list_row.dart +++ b/lib/pages/user_search/user_list_row.dart @@ -1,6 +1,6 @@ import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; +import 'package:fcs/pages/user_search/user_search.dart'; import 'package:flutter/material.dart'; class UserListRow extends StatelessWidget { diff --git a/lib/pages/user_search/user_serach.dart b/lib/pages/user_search/user_search.dart similarity index 100% rename from lib/pages/user_search/user_serach.dart rename to lib/pages/user_search/user_search.dart diff --git a/lib/pages/widgets/local_popup_menu_button.dart b/lib/pages/widgets/local_popup_menu_button.dart index 1493eda..904eb98 100644 --- a/lib/pages/widgets/local_popup_menu_button.dart +++ b/lib/pages/widgets/local_popup_menu_button.dart @@ -2,7 +2,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:flutter/material.dart'; -import 'local_popupmenu.dart'; +import '../../domain/vo/local_popupmenu.dart'; typedef PopupMenuCallback = Function(LocalPopupMenu popupMenu);