From 32e6be2abd49b06ecbf572b4cf33b8182c6d9c10 Mon Sep 17 00:00:00 2001 From: Sai Naw Wun Date: Sun, 11 Oct 2020 02:17:23 +0630 Subject: [PATCH 1/4] fix profile --- assets/local/localization_en.json | 7 +- assets/local/localization_mu.json | 9 +- lib/data/provider/auth_fb.dart | 7 +- .../delivery_address_data_provider.dart | 6 + lib/data/provider/package_data_provider.dart | 7 +- lib/data/services/auth_imp.dart | 9 +- lib/data/services/auth_service.dart | 3 +- lib/data/services/delivery_address_imp.dart | 6 + .../services/delivery_address_service.dart | 1 + lib/data/services/package_imp.dart | 5 + lib/data/services/package_service.dart | 1 + lib/domain/constants.dart | 21 + lib/domain/entities/role.dart | 67 ---- lib/domain/entities/user.dart | 5 +- lib/domain/vo/delivery_address.dart | 9 +- lib/domain/vo/privilege.dart | 54 +++ lib/pages/box/box_editor.dart | 4 +- .../delivery_address_editor.dart | 122 +++--- .../delivery_address_list.dart | 112 ++++-- .../delivery_address_row.dart | 188 +++------ .../model/delivery_address_model.dart | 8 + lib/pages/main/home_page.dart | 6 +- lib/pages/main/model/main_model.dart | 9 +- lib/pages/package/model/package_model.dart | 20 +- lib/pages/package/package_info.dart | 8 +- lib/pages/package/tracking_id_page.dart | 8 +- lib/pages/package_search/package_serach.dart | 8 +- lib/pages/profile/profile_currency_edit.dart | 129 ++++++ lib/pages/profile/profile_edit.dart | 2 +- lib/pages/profile/profile_page.dart | 370 ++++++------------ lib/pages/receiving/receiving_info.dart | 162 ++++++++ lib/pages/receiving/receiving_list.dart | 10 +- lib/pages/receiving/receiving_list_row.dart | 5 +- lib/pages/receiving/receiving_new.dart | 33 +- lib/pages/shipment/pickup_box_editor.dart | 2 +- lib/pages/shipment/shipment_editor.dart | 4 +- lib/pages/staff/model/staff_model.dart | 4 +- lib/pages/staff/staff_editor.dart | 33 +- lib/pages/staff/staff_list.dart | 6 +- lib/pages/widgets/barcode_scanner.dart | 18 + lib/pages/widgets/display_text.dart | 10 +- lib/pages/widgets/status_tree.dart | 66 ++++ 42 files changed, 938 insertions(+), 626 deletions(-) delete mode 100644 lib/domain/entities/role.dart create mode 100644 lib/domain/vo/privilege.dart create mode 100644 lib/pages/profile/profile_currency_edit.dart create mode 100644 lib/pages/receiving/receiving_info.dart create mode 100644 lib/pages/widgets/barcode_scanner.dart create mode 100644 lib/pages/widgets/status_tree.dart diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index cad7714..af2569e 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -109,7 +109,6 @@ "user.fcs_id":"MY FCS_ID", "user.shipping_address":"USA SHIPPING ADDRESS", "user.deliveryAddress":"My delivery address", - "user.form.shipping_address":"ADDRESS", "User End ================================================================":"", "Customer Start ================================================================":"", @@ -142,15 +141,17 @@ "Profile Start ================================================================":"", "profile.title": "My Profile", "profile.edit_title": "Edit My Profile", + "profile.edit.currency.title":"Preferred Currency", "profile.name": "Name", "profile.phone": "Phone", "profile.language": "Languages", "profile.logout": "logout", + "profile.currency":"Preferred Currency", "profile.usa.shipping.address": "USA Shipping Address", "profile.logout.confirm":"Are you sure want to logout?", "profile.devices":"Devices", "profile.email":"Email", - "profile.privilege":"Privilege", + "profile.privileges":"Privileges", "Profile End ================================================================":"", "Package Start ================================================================":"", @@ -375,6 +376,7 @@ "delivery_address.update": "Update Delivery Address", "delivery_address.new_address":"Add New\nAddress", "delivery_address.change_address": "Change Address", + "delivery_address.delete.confirm":"Delete this Delivery Address?", "delivery_addresses End ================================================================":"", "Receiving Start ================================================================":"", @@ -386,6 +388,7 @@ "receiving.name":"Customer Name", "receiving.phone":"Phone Number", "receiving.create_btn":"Complete receiving", + "receiving.delete.confirm":"Delete this receiving?", "Receiving End ================================================================":"", "Processing Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 0fd1a9d..e43679f 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -109,7 +109,6 @@ "user.fcs_id":"My FCS_ID", "user.shipping_address":"My USA shipping address", "user.deliveryAddress":"My delivery address", - "user.form.shipping_address":"ကုန်ပစ္စည်းပို့ဆောင်ရမည့်လိပ်စာ", "User End ================================================================":"", "Customer Start ================================================================":"", @@ -142,15 +141,17 @@ "Profile Start ================================================================":"", "profile.title":"ကျွန်ုပ် ပရိုဖိုင်", "profile.edit_title":"ကျွန်ုပ် ပရိုဖိုင်ကိုပြုပြင်ရန်", + "profile.edit.currency.title":"နှစ်သက်သော ငွေအမျိုးအစား", "profile.name":"နာမည်", "profile.phone": "ဖုန်းနံပါတ်", "profile.language": "ဘာသာစကားများ", "profile.logout": "အကောင့်ထွက်ရန်", - "profile.usa.shipping.address": "အမေရိကား ပစည်းပို့ရန်လိပ်စာ", + "profile.currency":"နှစ်သက်သော ငွေအမျိုးအစား", + "profile.usa.shipping.address": "အမေရိကား ပစ္စည်းပို့ရန်လိပ်စာ", "profile.logout.confirm":"အကောင့်ထွက်ရန်သေချာပြီလား?", "profile.devices":"ဖုန်းမော်ဒယ်အမျိုးအစားများ", "profile.email":"အီးမေးလ်", - "profile.privilege":"လုပ်ပိုင်ခွင့်", + "profile.privileges":"လုပ်ပိုင်ခွင့်များ", "Profile End ================================================================":"", "Package Start ================================================================":"", @@ -375,6 +376,7 @@ "delivery_address.update": "ပြုပြင်ရန်", "delivery_address.new_address":"လိပ်စာအသစ်", "delivery_address.change_address": "လိပ်စာပြောင်းပါ", + "delivery_address.delete.confirm":"ပို့ဆောင်ရမည့်လိပ်စာကို ဖျက်မလား?", "delivery_addresses End ================================================================":"", "Receiving Start ================================================================":"", @@ -386,6 +388,7 @@ "receiving.name":"နာမည်", "receiving.phone":"ဖုန်းနံပါတ်", "receiving.create_btn":"လက်ခံမည်", + "receiving.delete.confirm":"လက်ခံခြင်းကို ဖျက်မလား?", "Receiving End ================================================================":"", "Processing Start ================================================================":"", diff --git a/lib/data/provider/auth_fb.dart b/lib/data/provider/auth_fb.dart index 11a4d14..bea0d16 100644 --- a/lib/data/provider/auth_fb.dart +++ b/lib/data/provider/auth_fb.dart @@ -182,11 +182,16 @@ class AuthFb { return invited["invited"]; } - Future updateProfile(String newUserName) async { + Future updateProfileName(String newUserName) async { return await requestAPI("/profile", "PUT", payload: {"user_name": newUserName}, token: await getToken()); } + Future updatePreferredCurrency(String currency) async { + return await requestAPI("/currency", "PUT", + payload: {"preferred_currency": currency}, token: await getToken()); + } + Future getToken() async { FirebaseUser firebaseUser = await _fb.currentUser(); IdTokenResult token = await firebaseUser.getIdToken(); diff --git a/lib/data/provider/delivery_address_data_provider.dart b/lib/data/provider/delivery_address_data_provider.dart index 94fa841..70e620b 100644 --- a/lib/data/provider/delivery_address_data_provider.dart +++ b/lib/data/provider/delivery_address_data_provider.dart @@ -21,4 +21,10 @@ class DeliveryAddressDataProvider { return await requestAPI("/delivery_address", "DELETE", payload: deliveryAddress.toMap(), token: await getToken()); } + + Future selectDefalutDeliveryAddress( + DeliveryAddress deliveryAddress) async { + return await requestAPI("/delivery_address/defalut", "PUT", + payload: deliveryAddress.toMap(), token: await getToken()); + } } diff --git a/lib/data/provider/package_data_provider.dart b/lib/data/provider/package_data_provider.dart index a89ea54..9eec0c7 100644 --- a/lib/data/provider/package_data_provider.dart +++ b/lib/data/provider/package_data_provider.dart @@ -16,8 +16,13 @@ class PackageDataProvider { payload: {"packages": json, "fcs_id": fcsID}, token: await getToken()); } + Future createPackage(Package package) async { + return await requestAPI("/package", "POST", + payload: package.toJson(), token: await getToken()); + } + Future deletePackage(Package package) async { - return await requestAPI("/packages", "DELETE", + return await requestAPI("/package", "DELETE", payload: {"id": package.id}, token: await getToken()); } diff --git a/lib/data/services/auth_imp.dart b/lib/data/services/auth_imp.dart index cb33ec9..27d0376 100644 --- a/lib/data/services/auth_imp.dart +++ b/lib/data/services/auth_imp.dart @@ -62,7 +62,12 @@ class AuthServiceImp implements AuthService { } @override - Future updateProfile(String newUserName) { - return authFb.updateProfile(newUserName); + Future updateProfileName(String newUserName) { + return authFb.updateProfileName(newUserName); + } + + @override + Future updatePreferredCurrency(String currency) { + return authFb.updatePreferredCurrency(currency); } } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index 3c2797a..412c498 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -8,7 +8,8 @@ abstract class AuthService { Future signout(); Future signup(String userName); Future joinInvite(String userName); - Future updateProfile(String newUserName); + Future updateProfileName(String newUserName); + Future updatePreferredCurrency(String currency); Future hasInvite(); Stream getUserStream(); Stream getSetting(); diff --git a/lib/data/services/delivery_address_imp.dart b/lib/data/services/delivery_address_imp.dart index fe74fd2..96d8a36 100644 --- a/lib/data/services/delivery_address_imp.dart +++ b/lib/data/services/delivery_address_imp.dart @@ -28,4 +28,10 @@ class DeliveryAddressImp implements DeliveryAddressService { Future deleteDeliveryAddress(DeliveryAddress deliveryAddress) { return deliveryAddressDataProvider.deleteDeliveryAddress(deliveryAddress); } + + @override + Future selectDefalutDeliveryAddress(DeliveryAddress deliveryAddress) { + return deliveryAddressDataProvider + .selectDefalutDeliveryAddress(deliveryAddress); + } } diff --git a/lib/data/services/delivery_address_service.dart b/lib/data/services/delivery_address_service.dart index 3630390..e638daf 100644 --- a/lib/data/services/delivery_address_service.dart +++ b/lib/data/services/delivery_address_service.dart @@ -4,4 +4,5 @@ abstract class DeliveryAddressService { Future createDeliveryAddress(DeliveryAddress deliveryAddress); Future updateDeliveryAddress(DeliveryAddress deliveryAddress); Future deleteDeliveryAddress(DeliveryAddress deliveryAddress); + Future selectDefalutDeliveryAddress(DeliveryAddress deliveryAddress); } diff --git a/lib/data/services/package_imp.dart b/lib/data/services/package_imp.dart index a0614a8..9e33dff 100644 --- a/lib/data/services/package_imp.dart +++ b/lib/data/services/package_imp.dart @@ -19,6 +19,11 @@ class PackageServiceImp implements PackageService { return packageDataProvider.createPackages(packages, fcsID); } + @override + Future createPackage(Package package) { + return packageDataProvider.createPackage(package); + } + @override Future> searchPackage(String term) { return packageDataProvider.searchPackage(term); diff --git a/lib/data/services/package_service.dart b/lib/data/services/package_service.dart index cd79eb2..93ac51d 100644 --- a/lib/data/services/package_service.dart +++ b/lib/data/services/package_service.dart @@ -2,6 +2,7 @@ import 'package:fcs/domain/entities/package.dart'; abstract class PackageService { Future createPackages(List packages, String fcsID); + Future createPackage(Package package); Future deletePackage(Package package); Future> searchPackage(String term); } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 80a7990..690fa9b 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -26,3 +26,24 @@ const message_type_profile = "t_profile"; const fcs_shipment_confirmed_status = "confirmed"; const fcs_shipment_shipped_status = "shipped"; const fcs_shipment_delivered_status = "delivered"; + +// Package status +const package_received_status = "received"; +const package_processed_status = "processed"; +const package_packed_status = "packed"; +const package_shipped_status = "shipped"; +const package_delivered_status = "delivered"; + +// Privileges +const privilege_admin = "admin"; +const privilege_support = "sp"; +const privilege_package = "pkg"; +const privilege_shipment = "sh"; +const privilege_fcs_shipment = "fsh"; +const privilege_staff = "st"; +const privilege_carton = "ca"; +const privilege_customer = "cu"; +const privilege_delivery = "deli"; +const privilege_invoice = "inv"; +const privilege_processing = "pr"; +const privilege_receiving = "rc"; diff --git a/lib/domain/entities/role.dart b/lib/domain/entities/role.dart deleted file mode 100644 index d0e5aae..0000000 --- a/lib/domain/entities/role.dart +++ /dev/null @@ -1,67 +0,0 @@ -class Role { - String roleID; - String roleName; - String privileges; - Role({this.roleName, this.roleID, this.privileges}); - - Role.fromJson(Map json) { - roleName = json['role_name']; - roleID = json['role_id']; - privileges = json['privileges']; - } -} - -class Parser { - String status; - String message; - Role data; - Parser({this.status, this.message, this.data}); - - Parser.fromJson(Map json) { - status = json['status']; - message = json['message']; - if (json['status'] == 'Ok') { - data = Role.fromJson(json['data']); - } - } -} - -class StatusParser { - String status; - String message; - StatusParser(this.status, this.message); - - StatusParser.fromJson(Map json) { - status = json['status']; - message = json['message']; - } -} - -class Privilege { - String id; - String name; - String desc; - bool sysAdminOnly = true; - bool isChecked = false; - - Privilege({this.id, this.name, this.desc, this.isChecked, this.sysAdminOnly}); - - factory Privilege.fromMap(Map map, String docID) { - return Privilege( - id: docID, - name: map['name'], - desc: map['desc'], - sysAdminOnly: map['sys_admin_only']); - } -} - -class UserLevel { - String id; - String name; - int level; - UserLevel({this.id, this.name, this.level}); - - factory UserLevel.fromMap(Map map, String docID) { - return UserLevel(id: docID, name: map['name'], level: map['level']); - } -} diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index 6dbc119..2c43357 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -17,6 +17,7 @@ class User { String lastMessage; int userUnseenCount; int fcsUnseenCount; + String preferCurrency; String get initial => name != null && name != "" ? name.substring(0, 1) : "?"; @@ -64,7 +65,8 @@ class User { this.lastMessage, this.lastMessageTime, this.userUnseenCount, - this.fcsUnseenCount}); + this.fcsUnseenCount, + this.preferCurrency}); factory User.fromJson(Map json) { return User( @@ -106,6 +108,7 @@ class User { lastMessage: map['last_message'], userUnseenCount: map['user_unseen_count'], fcsUnseenCount: map['fcs_unseen_count'], + preferCurrency: map['preferred_currency'], lastMessageTime: _date == null ? null : _date.toDate()); } diff --git a/lib/domain/vo/delivery_address.dart b/lib/domain/vo/delivery_address.dart index ab98533..b7157bb 100644 --- a/lib/domain/vo/delivery_address.dart +++ b/lib/domain/vo/delivery_address.dart @@ -5,8 +5,8 @@ class DeliveryAddress { String addressLine2; String city; String state; - String country; String phoneNumber; + bool isDefault; DeliveryAddress( {this.id, this.fullName, @@ -14,8 +14,8 @@ class DeliveryAddress { this.addressLine2, this.city, this.state, - this.country, - this.phoneNumber}); + this.phoneNumber, + this.isDefault = false}); factory DeliveryAddress.fromMap(Map map, String docID) { return DeliveryAddress( @@ -25,8 +25,8 @@ class DeliveryAddress { addressLine2: map['address_line2'], city: map['city'], state: map['state'], - country: map['country'], phoneNumber: map['phone_number'], + isDefault: map['is_defalut'] ?? false, ); } @@ -39,7 +39,6 @@ class DeliveryAddress { 'city': city, 'state': state, 'phone_number': phoneNumber, - 'country': country, }; } } diff --git a/lib/domain/vo/privilege.dart b/lib/domain/vo/privilege.dart new file mode 100644 index 0000000..5b913b2 --- /dev/null +++ b/lib/domain/vo/privilege.dart @@ -0,0 +1,54 @@ +import 'package:fcs/domain/constants.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class Privilege { + String id; + String name; + String desc; + bool sysAdminOnly = true; + bool isChecked = false; + + IconData iconData; + + Privilege( + {this.id, this.name, this.desc, this.isChecked, this.sysAdminOnly}) { + if (this.id == privilege_admin) { + iconData = MaterialCommunityIcons.account_tie; + } else if (this.id == privilege_support) { + iconData = SimpleLineIcons.support; + } else if (this.id == privilege_package) { + iconData = Octicons.package; + } else if (this.id == privilege_shipment) { + iconData = SimpleLineIcons.direction; + } else if (this.id == privilege_fcs_shipment) { + iconData = Ionicons.ios_airplane; + } else if (this.id == privilege_staff) { + iconData = MaterialCommunityIcons.worker; + } else if (this.id == privilege_carton) { + iconData = MaterialCommunityIcons.package; + } else if (this.id == privilege_customer) { + iconData = Feather.users; + } else if (this.id == privilege_delivery) { + iconData = MaterialCommunityIcons.truck_fast; + } else if (this.id == privilege_invoice) { + iconData = FontAwesomeIcons.fileInvoice; + } else if (this.id == privilege_processing) { + iconData = FontAwesome.dropbox; + } else if (this.id == privilege_receiving) { + iconData = MaterialCommunityIcons.inbox_arrow_down; + } else { + iconData = MaterialCommunityIcons.account_question; + } + } + + factory Privilege.fromMap(Map map, String docID) { + return Privilege( + id: docID, + name: map['name'], + desc: map['desc'], + sysAdminOnly: map['sys_admin_only']); + } +} diff --git a/lib/pages/box/box_editor.dart b/lib/pages/box/box_editor.dart index 4458c8c..8d48fff 100644 --- a/lib/pages/box/box_editor.dart +++ b/lib/pages/box/box_editor.dart @@ -570,7 +570,7 @@ class _BoxEditorState extends State { ), Column( children: [ - DeliveryAddressRow(shippingAddress: _deliveryAddress), + DeliveryAddressRow(deliveryAddress: _deliveryAddress), Container( padding: EdgeInsets.only(top: 20, bottom: 15, right: 15), child: Align( @@ -659,7 +659,7 @@ class _BoxEditorState extends State { return addresses.asMap().entries.map((s) { return InkWell( onTap: () {}, - child: DeliveryAddressRow(shippingAddress: s.value, index: s.key), + child: DeliveryAddressRow(deliveryAddress: s.value), ); }).toList(); } diff --git a/lib/pages/delivery_address/delivery_address_editor.dart b/lib/pages/delivery_address/delivery_address_editor.dart index 2bf7338..7c29891 100644 --- a/lib/pages/delivery_address/delivery_address_editor.dart +++ b/lib/pages/delivery_address/delivery_address_editor.dart @@ -23,25 +23,28 @@ class _DeliveryAddressEditorState extends State { TextEditingController _address2Controller = new TextEditingController(); TextEditingController _cityController = new TextEditingController(); TextEditingController _stateController = new TextEditingController(); - TextEditingController _countryController = new TextEditingController(); TextEditingController _phoneController = new TextEditingController(); DeliveryAddress _deliveryAddress = new DeliveryAddress(); bool _isLoading = false; + bool _isNew = true; @override void initState() { super.initState(); if (widget.deliveryAddress != null) { + _isNew = false; _deliveryAddress = widget.deliveryAddress; _nameController.text = _deliveryAddress.fullName; _address1Controller.text = _deliveryAddress.addressLine1; _address2Controller.text = _deliveryAddress.addressLine2; _cityController.text = _deliveryAddress.city; _stateController.text = _deliveryAddress.state; - _countryController.text = _deliveryAddress.country; _phoneController.text = _deliveryAddress.phoneNumber; + } else { + _cityController.text = "Yangon"; + _stateController.text = "Yangon"; } } @@ -52,9 +55,9 @@ class _DeliveryAddressEditorState extends State { @override Widget build(BuildContext context) { - final usaAddress = InputText( + final fullName = InputText( labelTextKey: 'delivery_address.full_name', - iconData: Icons.text_format, + iconData: MaterialCommunityIcons.account_arrow_left, controller: _nameController); final addressLine1 = InputText( @@ -77,14 +80,10 @@ class _DeliveryAddressEditorState extends State { iconData: Entypo.location, controller: _stateController); - final countryBox = InputText( - labelTextKey: 'delivery_address.country', - iconData: Entypo.flag, - controller: _countryController); - final phoneNumberBox = InputText( labelTextKey: 'delivery_address.phonenumber', iconData: Icons.phone, + textInputType: TextInputType.phone, controller: _phoneController); final createBtn = fcsButton( @@ -100,52 +99,43 @@ class _DeliveryAddressEditorState extends State { ); return LocalProgress( - inAsyncCall: _isLoading, - child: Scaffold( - appBar: AppBar( - centerTitle: true, - leading: new IconButton( - icon: new Icon(Icons.close), - onPressed: () => Navigator.of(context).pop(), + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + ), + backgroundColor: primaryColor, + title: LocalText( + context, + 'delivery_address', + color: Colors.white, + fontSize: 20, + ), + actions: [IconButton(icon: Icon(Icons.delete), onPressed: _delete)], ), - backgroundColor: primaryColor, - title: LocalText( - context, - 'user.form.shipping_address', - color: Colors.white, - fontSize: 20, - ), - ), - body: Card( - child: Column( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 10.0, right: 10), - child: ListView(children: [ - usaAddress, - SizedBox(height: 5), - addressLine1, - SizedBox(height: 5), - addressLine2, - SizedBox(height: 5), - cityBox, - SizedBox(height: 5), - regionBox, - SizedBox(height: 5), - countryBox, - SizedBox(height: 5), - phoneNumberBox, - SizedBox(height: 10), - ]), - )), - widget.deliveryAddress == null ? createBtn : updateBtn, + body: Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10), + child: ListView(children: [ + fullName, + SizedBox(height: 5), + phoneNumberBox, + SizedBox(height: 10), + addressLine1, + SizedBox(height: 5), + addressLine2, + SizedBox(height: 5), + cityBox, + SizedBox(height: 5), + regionBox, + SizedBox(height: 5), + _isNew ? createBtn : updateBtn, SizedBox(height: 10) - ], + ]), ), - ), - ), - ); + )); } DeliveryAddress _getPayload() { @@ -158,7 +148,6 @@ class _DeliveryAddressEditorState extends State { deliveryAddress.addressLine2 = _address2Controller.text; deliveryAddress.city = _cityController.text; deliveryAddress.state = _stateController.text; - deliveryAddress.country = _countryController.text; deliveryAddress.phoneNumber = _phoneController.text; } catch (e) { showMsgDialog(context, "Error", e.toString()); // shold never happen @@ -180,10 +169,6 @@ class _DeliveryAddressEditorState extends State { await showMsgDialog(context, "Error", "Invalid state!"); return false; } - if (deliveryAddress.country == null) { - await showMsgDialog(context, "Error", "Invalid country!"); - return false; - } if (deliveryAddress.phoneNumber == null) { await showMsgDialog(context, "Error", "Invalid phone number!"); return false; @@ -216,7 +201,6 @@ class _DeliveryAddressEditorState extends State { Future _update() async { DeliveryAddress deliveryAddress = _getPayload(); - print('deliveryAddress => ${deliveryAddress.country}'); bool valid = await _validate(deliveryAddress); if (!valid) { return; @@ -237,4 +221,26 @@ class _DeliveryAddressEditorState extends State { }); } } + + _delete() { + showConfirmDialog(context, "delivery_address.delete.confirm", _deleteDA); + } + + _deleteDA() async { + setState(() { + _isLoading = true; + }); + try { + DeliveryAddressModel deliveryAddressModel = + Provider.of(context, listen: false); + await deliveryAddressModel.deleteDeliveryAddress(_deliveryAddress); + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/delivery_address/delivery_address_list.dart b/lib/pages/delivery_address/delivery_address_list.dart index bcd94df..b2c967d 100644 --- a/lib/pages/delivery_address/delivery_address_list.dart +++ b/lib/pages/delivery_address/delivery_address_list.dart @@ -53,53 +53,79 @@ class _DeliveryAddressListState extends State { color: Colors.white, ), ), - body: Column( - children: [ - Expanded( - child: Column( - children: - getAddressList(context, shipmentModel.deliveryAddresses), - ), - ), - Container( - padding: EdgeInsets.only(top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.bottomRight, - child: Container( - width: 130, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - onPressed: () { - Navigator.push( - context, - BottomUpPageRoute(DeliveryAddressEditor()), - ); - }, - icon: Icon(Icons.add), - label: Text( - getLocalString(context, 'delivery_address.new_address'), - style: TextStyle(fontSize: 12), - ), - backgroundColor: primaryColor, + floatingActionButton: FloatingActionButton.extended( + onPressed: () { + Navigator.of(context) + .push(BottomUpPageRoute(DeliveryAddressEditor())); + }, + icon: Icon(Icons.add), + label: LocalText(context, "delivery_address.new_address", + color: Colors.white), + backgroundColor: primaryColor, + ), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView.separated( + separatorBuilder: (c, i) => Divider( + color: primaryColor, ), - ), - ), - ), - ], + itemCount: shipmentModel.deliveryAddresses.length, + itemBuilder: (context, index) { + return _row(context, shipmentModel.deliveryAddresses[index]); + }), )), ); } - List getAddressList( - BuildContext context, List addresses) { - return addresses.asMap().entries.map((s) { - return InkWell( - onTap: () { - // Navigator.pop(context, s.value); - }, - child: DeliveryAddressRow(shippingAddress: s.value, index: s.key), - ); - }).toList(); + _row(BuildContext context, DeliveryAddress deliveryAddress) { + return Row( + children: [ + InkWell( + onTap: () => _select(deliveryAddress), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Icon(Icons.check, + color: + deliveryAddress.isDefault ? primaryColor : Colors.black26), + ), + ), + Expanded( + child: DeliveryAddressRow( + key: ValueKey(deliveryAddress.id), + deliveryAddress: deliveryAddress, + selectionCallback: (d) => _edit(context, deliveryAddress)), + ), + ], + ); + } + + _edit(BuildContext context, DeliveryAddress deliveryAddress) { + Navigator.push( + context, + BottomUpPageRoute( + DeliveryAddressEditor(deliveryAddress: deliveryAddress)), + ); + } + + Future _select(DeliveryAddress deliveryAddress) async { + if (deliveryAddress.isDefault) { + Navigator.pop(context); + return; + } + setState(() { + _isLoading = true; + }); + var deliveryAddressModel = + Provider.of(context, listen: false); + try { + await deliveryAddressModel.selectDefalutDeliveryAddress(deliveryAddress); + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } } } diff --git a/lib/pages/delivery_address/delivery_address_row.dart b/lib/pages/delivery_address/delivery_address_row.dart index 2fd254b..b601d0b 100644 --- a/lib/pages/delivery_address/delivery_address_row.dart +++ b/lib/pages/delivery_address/delivery_address_row.dart @@ -1,146 +1,78 @@ import 'package:fcs/domain/vo/delivery_address.dart'; -import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; +import 'package:flutter_icons/flutter_icons.dart'; -import 'delivery_address_editor.dart'; +typedef SelectionCallback(DeliveryAddress deliveryAddress); class DeliveryAddressRow extends StatelessWidget { - final DeliveryAddress shippingAddress; - final int index; - - const DeliveryAddressRow({Key key, this.shippingAddress, this.index}) + final DeliveryAddress deliveryAddress; + final SelectionCallback selectionCallback; + const DeliveryAddressRow( + {Key key, this.deliveryAddress, this.selectionCallback}) : super(key: key); @override Widget build(BuildContext context) { - var deliveryAddressModel = Provider.of(context); - return Container( - padding: EdgeInsets.only(left: 10, right: 10), - child: Column( + return InkWell( + onTap: selectionCallback == null + ? null + : () => this.selectionCallback(deliveryAddress), + child: Row( children: [ - Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: Row( - children: [ - InkWell( - onTap: () { - Navigator.pop(context, shippingAddress); - }, - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.fullName == null - ? '' - : shippingAddress.fullName, - style: new TextStyle( - fontSize: 15.0, - color: Colors.black, - fontWeight: FontWeight.bold), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.addressLine1 == null - ? '' - : shippingAddress.addressLine1, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.addressLine2 == null - ? '' - : shippingAddress.addressLine2, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.city == null - ? '' - : shippingAddress.city, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.state == null - ? '' - : shippingAddress.state, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.country == null - ? '' - : shippingAddress.country, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - shippingAddress.phoneNumber == null - ? '' - : "Phone:${shippingAddress.phoneNumber}", - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - ], - ), - ), - ], - ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + line(context, deliveryAddress.fullName, + iconData: MaterialCommunityIcons.account_arrow_left, + color: primaryColor, + fontSize: 16), + line(context, deliveryAddress.phoneNumber, + iconData: Icons.phone, color: primaryColor, fontSize: 16), + SizedBox( + height: 5, ), - ), - IconButton( - padding: EdgeInsets.only(right: 30), - icon: Icon(Icons.edit, color: Colors.black45), - onPressed: () { - Navigator.push( - context, - BottomUpPageRoute(DeliveryAddressEditor( - deliveryAddress: shippingAddress)), - ); - }), - IconButton( - padding: EdgeInsets.only(right: 30), - icon: Icon(Icons.delete, color: Colors.black45), - onPressed: () async { - await deliveryAddressModel - .deleteDeliveryAddress(shippingAddress); - }) - ], + line(context, deliveryAddress.addressLine1, + iconData: Icons.location_on), + line( + context, + deliveryAddress.addressLine2, + ), + line( + context, + deliveryAddress.city, + ), + line(context, deliveryAddress.state), + ], + ), ), - index == null - ? Container() - : index == deliveryAddressModel.deliveryAddresses.length - 1 - ? Container() - : Divider(color: Colors.black) ], ), ); } + + Widget line(BuildContext context, String text, + {IconData iconData, Color color, double fontSize}) { + return Row( + children: [ + iconData == null + ? SizedBox(width: 40) + : Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8), + child: Icon(iconData, color: Colors.black38), + ), + Flexible( + child: TextLocalStyle( + context, + text ?? "", + fontSize: fontSize ?? 14, + color: color, + ), + ), + ], + ); + } } diff --git a/lib/pages/delivery_address/model/delivery_address_model.dart b/lib/pages/delivery_address/model/delivery_address_model.dart index 99f472c..73df666 100644 --- a/lib/pages/delivery_address/model/delivery_address_model.dart +++ b/lib/pages/delivery_address/model/delivery_address_model.dart @@ -12,6 +12,9 @@ class DeliveryAddressModel extends BaseModel { StreamSubscription listener; + DeliveryAddress get defalutAddress => + deliveryAddresses.firstWhere((e) => e.isDefault, orElse: () => null); + @override void privilegeChanged() { super.privilegeChanged(); @@ -61,4 +64,9 @@ class DeliveryAddressModel extends BaseModel { return Services.instance.deliveryAddressService .deleteDeliveryAddress(deliveryAddress); } + + Future selectDefalutDeliveryAddress(DeliveryAddress deliveryAddress) { + return Services.instance.deliveryAddressService + .selectDefalutDeliveryAddress(deliveryAddress); + } } diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index 39fd1ae..c7d4b8a 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -206,12 +206,12 @@ class _HomePageState extends State { CupertinoPageRoute(builder: (context) => PackageList()))); final receivingBtn = TaskButton("receiving.title", - icon: Octicons.package, + icon: MaterialCommunityIcons.inbox_arrow_down, btnCallback: () => Navigator.of(context).push( CupertinoPageRoute(builder: (context) => ReceivingList()))); final processingBtn = TaskButton("processing.title", - icon: Octicons.package, + icon: FontAwesome.dropbox, btnCallback: () => Navigator.of(context).push( CupertinoPageRoute(builder: (context) => ProcessingList()))); final boxesBtn = TaskButton("boxes.name", @@ -287,7 +287,7 @@ class _HomePageState extends State { List widgets = []; if (user != null) { - // true ? widgets.add(pickUpBtn) : ""; + true ? widgets.add(pickUpBtn) : ""; !customer ? widgets.add(fcsShipmentBtn) : ""; customer ? widgets.add(notiBtn) : ""; user.hasStaffs() ? widgets.add(staffBtn) : ""; diff --git a/lib/pages/main/model/main_model.dart b/lib/pages/main/model/main_model.dart index fc219d4..14a7846 100644 --- a/lib/pages/main/model/main_model.dart +++ b/lib/pages/main/model/main_model.dart @@ -162,8 +162,13 @@ class MainModel extends ChangeNotifier { notifyListeners(); } - Future updateProfile(String newUserName) async { - await Services.instance.authService.updateProfile(newUserName); + Future updateProfileName(String newUserName) async { + await Services.instance.authService.updateProfileName(newUserName); + notifyListeners(); + } + + Future updatePreferredCurrency(String currency) async { + await Services.instance.authService.updatePreferredCurrency(currency); notifyListeners(); } } diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 9c2f9e0..4633a5a 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -93,6 +93,24 @@ class PackageModel extends BaseModel { .createPackages(packages, user.fcsID); } + Future createPackage(User user, Package package, List files, + List deletedUrls) async { + if (user != null) { + package.fcsID = user.fcsID; + } + if (files != null) { + if (files.length > 5) throw Exception("Exceed number of file upload"); + package.photoUrls = package.photoUrls == null ? [] : package.photoUrls; + for (File f in files) { + String path = Path.join(pkg_files_path); + String url = await uploadStorage(path, f); + package.photoUrls.add(url); + } + package.photoUrls.removeWhere((e) => deletedUrls.contains(e)); + } + return Services.instance.packageService.createPackage(package); + } + Future completeProcessing( Package package, List files, List deletedUrls) async { if (files != null) { @@ -105,7 +123,7 @@ class PackageModel extends BaseModel { } package.photoUrls.removeWhere((e) => deletedUrls.contains(e)); } - await request("/packages", "PUT", + await request("/package", "PUT", payload: package.toJson(), token: await getToken()); } diff --git a/lib/pages/package/package_info.dart b/lib/pages/package/package_info.dart index 1a0ec6c..0e635ff 100644 --- a/lib/pages/package/package_info.dart +++ b/lib/pages/package/package_info.dart @@ -185,9 +185,11 @@ class _PackageInfoState extends State { ? Ionicons.ios_airplane : e.status == "delivered" ? MaterialCommunityIcons.truck_fast - : e.status == "processed" - ? MaterialIcons.check - : Octicons.package, + : e.status == "packed" + ? MaterialCommunityIcons.package + : e.status == "processed" + ? FontAwesome.dropbox + : MaterialCommunityIcons.inbox_arrow_down, color: Colors.white, ))) .toList(); diff --git a/lib/pages/package/tracking_id_page.dart b/lib/pages/package/tracking_id_page.dart index 182fc2b..2918b5e 100644 --- a/lib/pages/package/tracking_id_page.dart +++ b/lib/pages/package/tracking_id_page.dart @@ -5,6 +5,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/market/market_editor.dart'; import 'package:fcs/pages/market/model/market_model.dart'; import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/widgets/barcode_scanner.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/input_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -163,13 +164,8 @@ class _TrackingIDPageState extends State { } try { - String barcode = await BarcodeScanner.scan(); + String barcode = await scanBarcode(); if (barcode != null) { - String gs = String.fromCharCode(29); - if (barcode.contains(gs)) { - var codes = barcode.split(gs); - barcode = codes.length >= 2 ? codes[1] : barcode; - } setState(() { _transcationIDCtl.text = barcode; }); diff --git a/lib/pages/package_search/package_serach.dart b/lib/pages/package_search/package_serach.dart index ac9804e..2ee5ccf 100644 --- a/lib/pages/package_search/package_serach.dart +++ b/lib/pages/package_search/package_serach.dart @@ -4,6 +4,7 @@ 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/package/package_list_row.dart'; +import 'package:fcs/pages/widgets/barcode_scanner.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -147,13 +148,8 @@ class PackageSearchDelegate extends SearchDelegate { // Barcode bc = barcodes.firstWhere((element) => true); // String barcode; // if (bc != null) barcode = bc.rawValue; - String barcode = await BarcodeScanner.scan(); + String barcode = await scanBarcode(); if (barcode != null) { - String gs = String.fromCharCode(29); - if (barcode.contains(gs)) { - var codes = barcode.split(gs); - barcode = codes.length >= 2 ? codes[1] : barcode; - } query = barcode; showResults(context); } diff --git a/lib/pages/profile/profile_currency_edit.dart b/lib/pages/profile/profile_currency_edit.dart new file mode 100644 index 0000000..6d91664 --- /dev/null +++ b/lib/pages/profile/profile_currency_edit.dart @@ -0,0 +1,129 @@ +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/pages/main/model/language_model.dart'; +import 'package:fcs/pages/main/model/main_model.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:provider/provider.dart'; +import 'package:fcs/pages/main/util.dart'; + +typedef void ProfileCallback(); + +enum Currency { USD, MMK } + +class ProfileCurrencyEdit extends StatefulWidget { + @override + _ProfileCurrencyEditState createState() => _ProfileCurrencyEditState(); +} + +class _ProfileCurrencyEditState extends State { + final TextEditingController nameController = new TextEditingController(); + bool _loading = false; + + @override + void initState() { + super.initState(); + MainModel mainModel = Provider.of(context, listen: false); + if (mainModel.user.preferCurrency == "MMK") { + _currency = Currency.MMK; + } else { + _currency = Currency.USD; + } + } + + Currency _currency = Currency.USD; + + @override + Widget build(BuildContext context) { + final saveBtn = + fcsButton(context, getLocalString(context, "btn.save"), callack: _save); + + return LocalProgress( + inAsyncCall: _loading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + title: LocalText( + context, + "profile.edit.currency.title", + fontSize: 20, + color: primaryColor, + ), + backgroundColor: Colors.white, + shadowColor: Colors.transparent, + leading: IconButton( + icon: Icon( + CupertinoIcons.back, + size: 35, + color: primaryColor, + ), + onPressed: () => Navigator.of(context).pop(), + ), + ), + body: Column( + children: [ + InkWell( + onTap: () => setState(() { + _currency = Currency.USD; + }), + child: ListTile( + title: Text('USD'), + leading: Radio( + activeColor: primaryColor, + value: Currency.USD, + groupValue: _currency, + onChanged: (Currency value) { + setState(() { + _currency = value; + }); + }, + ), + ), + ), + InkWell( + onTap: () => setState(() { + _currency = Currency.MMK; + }), + child: ListTile( + title: const Text('MMK'), + leading: Radio( + activeColor: primaryColor, + value: Currency.MMK, + groupValue: _currency, + onChanged: (Currency value) { + setState(() { + _currency = value; + }); + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(18.0), + child: saveBtn, + ), + ], + ), + ), + ); + } + + _save() async { + setState(() { + _loading = true; + }); + try { + await Provider.of(context, listen: false) + .updatePreferredCurrency(_currency.toString().split(".").last); + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _loading = false; + }); + } + } +} diff --git a/lib/pages/profile/profile_edit.dart b/lib/pages/profile/profile_edit.dart index 58f1ed5..23f4a37 100644 --- a/lib/pages/profile/profile_edit.dart +++ b/lib/pages/profile/profile_edit.dart @@ -96,7 +96,7 @@ class _ProfileEditState extends State { }); try { await Provider.of(context, listen: false) - .updateProfile(nameController.text); + .updateProfileName(nameController.text); Navigator.pop(context); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/profile/profile_page.dart b/lib/pages/profile/profile_page.dart index b08ed79..5b9b454 100644 --- a/lib/pages/profile/profile_page.dart +++ b/lib/pages/profile/profile_page.dart @@ -1,21 +1,25 @@ -import 'package:fcs/domain/entities/role.dart'; +import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; -import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/domain/vo/privilege.dart'; import 'package:fcs/localization/transalation.dart'; import 'package:fcs/pages/delivery_address/delivery_address_list.dart'; +import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/profile/profile_currency_edit.dart'; import 'package:fcs/pages/profile/profile_edit.dart'; +import 'package:fcs/pages/staff/model/staff_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/fcs_id_icon.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; -import 'package:fcs/pages/main/util.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:provider/provider.dart'; import '../../helpers/theme.dart'; @@ -33,8 +37,6 @@ class _ProfileState extends State { String selectedLanguage; TextEditingController bizNameController = new TextEditingController(); - DeliveryAddress _deliveryAddress = new DeliveryAddress(); - static final List languagesList = Translation().supportedLanguages; static final List languageCodesList = Translation().supportedLanguagesCodes; @@ -56,12 +58,6 @@ class _ProfileState extends State { @override void initState() { super.initState(); - var shipmentModel = - Provider.of(context, listen: false); - - if (shipmentModel.deliveryAddresses.length != 0) { - _deliveryAddress = shipmentModel.deliveryAddresses[0]; - } } @override @@ -70,11 +66,19 @@ class _ProfileState extends State { if (mainModel.user == null) { return Container(); } + DeliveryAddressModel deliveryAddressModel = + Provider.of(context); + final namebox = DisplayText( - text: mainModel.user.name, + text: mainModel.user.name + " (${mainModel.user.status})", labelTextKey: "profile.name", iconData: Icons.person, ); + final currencyBox = DisplayText( + text: mainModel.user.preferCurrency, + labelTextKey: "profile.currency", + iconData: FontAwesome5.money_bill_alt, + ); final phonenumberbox = DisplayText( text: mainModel.user.phone, @@ -142,42 +146,40 @@ class _ProfileState extends State { ), shadowColor: Colors.transparent, backgroundColor: Colors.white, - actions: [], ), body: Padding( padding: const EdgeInsets.all(8.0), - child: Column( + child: ListView( children: [ - Expanded( - child: ListView( - shrinkWrap: true, - children: [ - Row( - children: [ - Expanded(child: namebox), - Padding( - padding: const EdgeInsets.only(right: 0), - child: IconButton( - icon: Icon(Icons.edit, color: Colors.grey), - onPressed: _editName), - ) - ], - ), - mainModel.isCustomer() - ? Container() - : getPrivilegeBox(context), - getShippingAddressList(context), - phonenumberbox, - fcsIDBox, - usaShippingAddressBox, - DisplayText( - text: mainModel.user.status, - labelTextKey: "customer.status", - iconData: Icons.add_alarm, - ), - ], - ), + Row( + children: [ + Expanded(child: namebox), + Padding( + padding: const EdgeInsets.only(right: 0), + child: IconButton( + icon: Icon(Icons.edit, color: Colors.grey), + onPressed: _editName), + ) + ], ), + phonenumberbox, + fcsIDBox, + usaShippingAddressBox, + Row( + children: [ + Expanded(child: currencyBox), + Padding( + padding: const EdgeInsets.only(right: 0), + child: IconButton( + icon: Icon(Icons.edit, color: Colors.grey), + onPressed: _editCurrency), + ) + ], + ), + defalutDeliveryAddress( + context, deliveryAddressModel.defalutAddress), + getPrivilegeBox(context), + SizedBox(height: 15), logoutbutton, SizedBox(height: 25) ], @@ -187,221 +189,104 @@ class _ProfileState extends State { ); } - Widget getShippingAddressList(BuildContext context) { - var languageModel = Provider.of(context); - return ListTileTheme( - contentPadding: EdgeInsets.all(10), - child: ExpansionTile( - title: Text( - getLocalString(context, 'delivery_addresses'), - style: languageModel.isEng - ? TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - fontStyle: FontStyle.normal, - ) - : TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.bold, - fontStyle: FontStyle.normal, - fontFamily: "Myanmar3"), - ), - children: [ - showDeliveryAddress(_deliveryAddress), - Container( - padding: EdgeInsets.only(top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.bottomRight, - child: Container( - width: 130, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, - onPressed: () async { - DeliveryAddress deliveryAddress = await Navigator.push( - context, - BottomUpPageRoute(DeliveryAddressList( - deliveryAddress: _deliveryAddress)), - ); - setState(() { - _deliveryAddress = deliveryAddress; - }); - }, - label: LocalText(context, - 'delivery_address.change_address', - fontSize: 12, - color: Colors.white, - ), - backgroundColor: primaryColor, - ), + Widget defalutDeliveryAddress( + BuildContext context, DeliveryAddress deliveryAddress) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: DisplayText( + labelTextKey: "delivery_address", + iconData: MaterialCommunityIcons.truck_fast, ), ), - ) - ], - ), - ); - } - - Widget showDeliveryAddress(DeliveryAddress deliveryAddress) { - return Container( - padding: EdgeInsets.only(left: 10, right: 10), - child: Column( - children: [ - Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 10.0), - child: Row( - children: [ - new Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.fullName == null - ? '' - : deliveryAddress.fullName, - style: new TextStyle( - fontSize: 15.0, - color: Colors.black, - fontWeight: FontWeight.bold), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.addressLine1 == null - ? '' - : deliveryAddress.addressLine1, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.addressLine2 == null - ? '' - : deliveryAddress.addressLine2, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.city == null - ? '' - : deliveryAddress.city, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.state == null - ? '' - : deliveryAddress.state, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.country == null - ? '' - : deliveryAddress.country, - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: new Text( - deliveryAddress.phoneNumber == null - ? '' - : "Phone:${deliveryAddress.phoneNumber}", - style: new TextStyle( - fontSize: 14.0, color: Colors.grey), - ), - ), - ], - ), - ], - ), - ), + Chip( + label: InkWell( + onTap: () => Navigator.push( + context, + BottomUpPageRoute(DeliveryAddressList()), ), - ], - ), - ], - ), + child: LocalText(context, "delivery_address.change_address", + color: primaryColor), + )) + ], + ), + Padding( + padding: const EdgeInsets.only(left: 28.0), + child: deliveryAddress == null + ? Container() + : DeliveryAddressRow( + key: ValueKey(deliveryAddress.id), + deliveryAddress: deliveryAddress), + ), + ], ); } - List privileges = [ - Privilege(name: 'Manage shipment'), - Privilege(name: 'Manage pickups'), - Privilege(name: 'Manage packages'), - Privilege(name: 'Manage deliveries'), - Privilege(name: 'Admin') - ]; - Widget getPrivilegeBox(BuildContext context) { - var languageModel = Provider.of(context); + User user = Provider.of(context, listen: false).user; + List _privileges = + Provider.of(context, listen: false).privileges; - return ListTileTheme( - contentPadding: EdgeInsets.all(10), - child: ExpansionTile( - title: Text( - AppTranslations.of(context).text("profile.privilege"), - style: languageModel.isEng - ? TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.bold, - fontStyle: FontStyle.normal, - ) - : TextStyle( - fontSize: 15.0, - fontWeight: FontWeight.bold, - fontStyle: FontStyle.normal, - fontFamily: "Myanmar3"), + if (user == null || user.isCustomer()) return Container(); + List privileges = []; + user.privileges.forEach((e) { + var p = _privileges.firstWhere((p) => p.id == e, orElse: () => null); + if (p != null) { + privileges.add(p); + } + }); + + return Column( + children: [ + DisplayText( + labelTextKey: "profile.privileges", + iconData: MaterialCommunityIcons.clipboard_check_outline, ), - children: [ - Align( - alignment: Alignment.topLeft, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: getRowPrivilegeWidget(privileges)), - ), - ) - ], - ), + Padding( + padding: const EdgeInsets.only(left: 30.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: getRowPrivilegeWidget(privileges)), + ) + ], ); } List getRowPrivilegeWidget(List privileges) { return privileges.map((p) { return Container( - padding: EdgeInsets.all(8.0), + padding: EdgeInsets.all(3.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(p.name, - style: TextStyle(fontSize: 16.0, fontStyle: FontStyle.normal)), - SizedBox( - width: 30, + Icon( + p.iconData, + color: Colors.black38, ), - Container( - child: Text( - "- ${p.desc}", - style: TextStyle(fontSize: 16.0, fontStyle: FontStyle.normal), + SizedBox( + width: 10, + ), + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("${p.name}", + style: TextStyle( + fontSize: 16.0, + fontStyle: FontStyle.normal, + color: primaryColor, + )), + Text( + "${p.desc}", + style: TextStyle( + fontSize: 14.0, + fontStyle: FontStyle.normal, + color: Colors.black38), + ), + ], ), ) ], @@ -415,7 +300,7 @@ class _ProfileState extends State { _showToast(title); } - void _showToast(String title) { + _showToast(String title) { final ScaffoldState scaffold = key.currentState; scaffold.showSnackBar( SnackBar( @@ -431,6 +316,11 @@ class _ProfileState extends State { .push(CupertinoPageRoute(builder: (context) => ProfileEdit())); } + _editCurrency() { + Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => ProfileCurrencyEdit())); + } + _logout() { showConfirmDialog(context, "profile.logout.confirm", () async { setState(() { diff --git a/lib/pages/receiving/receiving_info.dart b/lib/pages/receiving/receiving_info.dart new file mode 100644 index 0000000..dbaac71 --- /dev/null +++ b/lib/pages/receiving/receiving_info.dart @@ -0,0 +1,162 @@ +import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/package/model/package_model.dart'; +import 'package:fcs/pages/package/package_editor.dart'; +import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; +import 'package:fcs/pages/widgets/display_text.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/multi_img_controller.dart'; +import 'package:fcs/pages/widgets/multi_img_file.dart'; +import 'package:fcs/pages/widgets/progress.dart'; +import 'package:fcs/pages/widgets/status_tree.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:timeline_list/timeline.dart'; +import 'package:timeline_list/timeline_model.dart'; + +final DateFormat dateFormat = DateFormat("d MMM yyyy"); + +class ReceivingInfo extends StatefulWidget { + final Package package; + ReceivingInfo({this.package}); + + @override + _ReceivingInfoState createState() => _ReceivingInfoState(); +} + +class _ReceivingInfoState extends State { + Package _package; + bool _isLoading = false; + MultiImgController multiImgController = MultiImgController(); + + @override + void initState() { + super.initState(); + initPackage(widget.package); + } + + initPackage(Package package) { + setState(() { + _package = package; + multiImgController.setImageUrls = package.photoUrls; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + bool isCustomer = Provider.of(context).isCustomer(); + + final trackingIdBox = DisplayText( + text: _package.trackingID, + labelTextKey: "package.tracking.id", + iconData: MaterialCommunityIcons.barcode_scan, + ); + final customerNameBox = DisplayText( + text: _package.userName, + labelTextKey: "package.create.name", + iconData: Icons.perm_identity, + ); + final remarkBox = DisplayText( + text: _package.remark ?? "-", + labelTextKey: "package.edit.remark", + iconData: Entypo.new_message, + ); + final img = MultiImageFile( + enabled: false, + controller: multiImgController, + title: "Receipt File", + ); + + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon(Icons.close, color: primaryColor, size: 30), + onPressed: () => Navigator.of(context).pop(), + ), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + "package.info.title", + fontSize: 20, + color: primaryColor, + ), + actions: [ + isCustomer + ? Container() + : IconButton( + icon: Icon(Icons.delete, color: primaryColor), + onPressed: _delete, + ) + ], + ), + body: Card( + child: Column( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView(children: [ + trackingIdBox, + _package.userID != null ? customerNameBox : Container(), + _package.photoUrls.length == 0 ? Container() : img, + remarkBox, + ExpansionTile( + initiallyExpanded: true, + title: Text( + 'Status', + style: TextStyle( + color: primaryColor, fontWeight: FontWeight.bold), + ), + children: [ + StatusTree( + shipmentHistory: _package.shipmentHistory, + currentStatus: _package.currentStatus), + ], + ), + SizedBox( + height: 20, + ) + ]), + )), + ], + ), + ), + ), + ); + } + + _delete() { + showConfirmDialog(context, "receiving.delete.confirm", _deleteReceiving); + } + + _deleteReceiving() async { + setState(() { + _isLoading = true; + }); + try { + PackageModel packageModel = + Provider.of(context, listen: false); + await packageModel.deletePackage(_package); + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } +} diff --git a/lib/pages/receiving/receiving_list.dart b/lib/pages/receiving/receiving_list.dart index 402f10f..e145d9a 100644 --- a/lib/pages/receiving/receiving_list.dart +++ b/lib/pages/receiving/receiving_list.dart @@ -1,10 +1,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; -import 'package:fcs/pages/package/package_info.dart'; -import 'package:fcs/pages/package/package_new.dart'; import 'package:fcs/pages/package_search/package_serach.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -13,6 +10,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'receiving_info.dart'; import 'receiving_list_row.dart'; import 'receiving_new.dart'; @@ -76,8 +74,8 @@ class _ReceivingListState extends State { _newReceiving(); }, icon: Icon(Icons.add), - label: Text( - AppTranslations.of(context).text("receiving.new")), + label: + LocalText(context, "receiving.new", color: Colors.white), backgroundColor: primaryColor, ), body: new ListView.separated( @@ -110,7 +108,7 @@ class _ReceivingListState extends State { if (_package == null) return; Navigator.push( context, - BottomUpPageRoute(PackageInfo(package: _package)), + BottomUpPageRoute(ReceivingInfo(package: _package)), ); } } diff --git a/lib/pages/receiving/receiving_list_row.dart b/lib/pages/receiving/receiving_list_row.dart index 435622d..5f8812c 100644 --- a/lib/pages/receiving/receiving_list_row.dart +++ b/lib/pages/receiving/receiving_list_row.dart @@ -1,10 +1,11 @@ import 'package:fcs/domain/entities/package.dart'; -import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; +import 'receiving_info.dart'; + typedef CallbackPackageSelect(Package package); class ReceivingListRow extends StatelessWidget { @@ -28,7 +29,7 @@ class ReceivingListRow extends StatelessWidget { } Navigator.push( context, - BottomUpPageRoute(PackageInfo(package: package)), + BottomUpPageRoute(ReceivingInfo(package: package)), ); }, child: Row( diff --git a/lib/pages/receiving/receiving_new.dart b/lib/pages/receiving/receiving_new.dart index d0b0e5e..0a0af86 100644 --- a/lib/pages/receiving/receiving_new.dart +++ b/lib/pages/receiving/receiving_new.dart @@ -2,8 +2,10 @@ import 'package:barcode_scan/barcode_scan.dart'; import 'package:fcs/domain/entities/package.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/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/widgets/barcode_scanner.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'; @@ -29,7 +31,7 @@ class _ReceivingNewState extends State { User user; TextEditingController _transcationIDCtl = new TextEditingController(); TextEditingController _remarkCtl = new TextEditingController(); - MultiImgController multiImgController = MultiImgController(); + MultiImgController _multiImgController = MultiImgController(); @override void initState() { @@ -80,8 +82,8 @@ class _ReceivingNewState extends State { controller: _remarkCtl); final img = MultiImageFile( enabled: true, - controller: multiImgController, - title: "Receipt File", + controller: _multiImgController, + title: "Receiving", ); final namebox = DisplayText( text: user != null ? user.name : "", @@ -161,14 +163,8 @@ class _ReceivingNewState extends State { } try { - String barcode = await BarcodeScanner.scan(); + String barcode = await scanBarcode(); if (barcode != null) { - String gs = String.fromCharCode(29); - if (barcode.contains(gs)) { - var codes = barcode.split(gs); - barcode = codes.length >= 2 ? codes[1] : barcode; - } - setState(() { _transcationIDCtl.text = barcode; }); @@ -179,17 +175,22 @@ class _ReceivingNewState extends State { } _create() async { - if (user == null) { - showMsgDialog(context, "Error", "Invalid user!"); + Package package = Package(); + package.trackingID = _transcationIDCtl.text; + package.remark = _remarkCtl.text; + + if (package.trackingID == null || package.trackingID == "") { + showMsgDialog(context, "Error", "Invalid tracking ID!"); return; } setState(() { _isLoading = true; }); - // PackageModel packageModel = - // Provider.of(context, listen: false); + PackageModel packageModel = + Provider.of(context, listen: false); try { - // await packageModel.createPackages(user, packages); + await packageModel.createPackage(user, package, + _multiImgController.getAddedFile, _multiImgController.getDeletedUrl); Navigator.pop(context); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/shipment/pickup_box_editor.dart b/lib/pages/shipment/pickup_box_editor.dart index 8048534..0d53b96 100644 --- a/lib/pages/shipment/pickup_box_editor.dart +++ b/lib/pages/shipment/pickup_box_editor.dart @@ -222,7 +222,7 @@ class _PickupBoxEditorState extends State { color: primaryColor, fontWeight: FontWeight.bold), ), children: [ - DeliveryAddressRow(shippingAddress: _shippingAddress), + DeliveryAddressRow(deliveryAddress: _shippingAddress), Container( padding: EdgeInsets.only(top: 20, bottom: 15, right: 15), diff --git a/lib/pages/shipment/shipment_editor.dart b/lib/pages/shipment/shipment_editor.dart index 768f9f5..bc412b9 100644 --- a/lib/pages/shipment/shipment_editor.dart +++ b/lib/pages/shipment/shipment_editor.dart @@ -304,7 +304,7 @@ class _ShipmentEditorState extends State { _currVal == 3 ? Container( child: DeliveryAddressRow( - shippingAddress: DeliveryAddress( + deliveryAddress: DeliveryAddress( fullName: 'FCS Office', addressLine1: '154-19 64th Ave.', addressLine2: 'Flushing', @@ -412,7 +412,7 @@ class _ShipmentEditorState extends State { Padding( padding: const EdgeInsets.only(left: 10.0), child: DeliveryAddressRow( - shippingAddress: _shippingAddress), + deliveryAddress: _shippingAddress), ), Container( padding: EdgeInsets.only( diff --git a/lib/pages/staff/model/staff_model.dart b/lib/pages/staff/model/staff_model.dart index e7ba735..79f92df 100644 --- a/lib/pages/staff/model/staff_model.dart +++ b/lib/pages/staff/model/staff_model.dart @@ -3,8 +3,8 @@ import 'dart:async'; 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/role.dart'; import 'package:fcs/domain/entities/user.dart'; +import 'package:fcs/domain/vo/privilege.dart'; import 'package:fcs/helpers/firebase_helper.dart'; import 'package:fcs/pages/main/model/base_model.dart'; import 'package:logging/logging.dart'; @@ -58,8 +58,6 @@ class StaffModel extends BaseModel { } Future _loadPrivileges() async { - if (user == null || !user.hasStaffs()) return; - try { privilegeListener = Firestore.instance .collection("/$privilege_collection") diff --git a/lib/pages/staff/staff_editor.dart b/lib/pages/staff/staff_editor.dart index 5c2af22..b86baf0 100644 --- a/lib/pages/staff/staff_editor.dart +++ b/lib/pages/staff/staff_editor.dart @@ -1,10 +1,10 @@ -import 'package:fcs/domain/entities/role.dart'; import 'package:fcs/domain/entities/user.dart'; +import 'package:fcs/domain/vo/privilege.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/language_model.dart'; -import 'package:fcs/pages/staff/model/staff_model.dart'; import 'package:fcs/pages/main/util.dart'; +import 'package:fcs/pages/staff/model/staff_model.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; @@ -68,16 +68,22 @@ class _StaffEditorState extends State { p.isChecked = value; }); }), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Text( - p.name, - style: TextStyle(fontSize: 15.0, color: primaryColor), - ), - Text(p.desc, - style: TextStyle(fontSize: 13, color: Colors.grey[600])) - ], + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Icon(p.iconData, size: 50, color: Colors.black38), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + p.name, + style: TextStyle(fontSize: 15.0, color: primaryColor), + ), + Text(p.desc, + style: TextStyle(fontSize: 13, color: Colors.grey[600])) + ], + ), ), ], ), @@ -192,6 +198,9 @@ class _StaffEditorState extends State { Column( children: showprivilegeList(context), ), + SizedBox( + height: 10, + ), Container( child: isNew ? addButton : updateButton, ), diff --git a/lib/pages/staff/staff_list.dart b/lib/pages/staff/staff_list.dart index d022236..fbae2b2 100644 --- a/lib/pages/staff/staff_list.dart +++ b/lib/pages/staff/staff_list.dart @@ -1,17 +1,15 @@ import 'package:fcs/domain/entities/user.dart'; -import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/staff/model/staff_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; -import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/cupertino.dart'; - import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; - import 'package:provider/provider.dart'; + import 'staff_editor.dart'; class StaffList extends StatefulWidget { diff --git a/lib/pages/widgets/barcode_scanner.dart b/lib/pages/widgets/barcode_scanner.dart new file mode 100644 index 0000000..3bbed5d --- /dev/null +++ b/lib/pages/widgets/barcode_scanner.dart @@ -0,0 +1,18 @@ +import 'package:barcode_scan/barcode_scan.dart'; + +Future scanBarcode() async { + try { + String barcode = await BarcodeScanner.scan(); + if (barcode == null) return null; + + String gs = String.fromCharCode(29); + if (barcode.contains(gs)) { + var codes = barcode.split(gs); + barcode = codes.length >= 2 ? codes[1] : barcode; + } + return barcode; + } catch (e) { + print('error: $e'); + return null; + } +} diff --git a/lib/pages/widgets/display_text.dart b/lib/pages/widgets/display_text.dart index 8b3bf37..8d36a9f 100644 --- a/lib/pages/widgets/display_text.dart +++ b/lib/pages/widgets/display_text.dart @@ -63,10 +63,12 @@ class DisplayText extends StatelessWidget { AppTranslations.of(context).text(labelTextKey), style: labelStyle, ), - Text( - text, - style: textStyle, - ), + text == null + ? Container() + : Text( + text, + style: textStyle, + ), ], ), ), diff --git a/lib/pages/widgets/status_tree.dart b/lib/pages/widgets/status_tree.dart new file mode 100644 index 0000000..fb89a54 --- /dev/null +++ b/lib/pages/widgets/status_tree.dart @@ -0,0 +1,66 @@ +import 'package:fcs/domain/constants.dart'; +import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/domain/vo/shipment_status.dart'; +import 'package:fcs/helpers/theme.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:intl/intl.dart'; +import 'package:timeline_list/timeline.dart'; +import 'package:timeline_list/timeline_model.dart'; + +var dateFormatter = new DateFormat('dd MMM yyyy'); + +class StatusTree extends StatelessWidget { + final List shipmentHistory; + final String currentStatus; + + const StatusTree({Key key, this.shipmentHistory, this.currentStatus}) + : super(key: key); + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 20), + height: 400, + child: Timeline(children: _models(), position: TimelinePosition.Left), + ); + } + + List _models() { + if (shipmentHistory == null || currentStatus == null) return []; + bool isPacked = currentStatus != package_received_status && + currentStatus != package_processed_status; + return shipmentHistory + .map((e) => TimelineModel( + Padding( + padding: const EdgeInsets.all(18.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(e.status, + style: TextStyle( + color: e.done ? primaryColor : Colors.grey, + fontSize: 16, + fontWeight: FontWeight.bold)), + e.done || isPacked + ? Text(dateFormatter.format(e.date)) + : Container(), + ], + ), + ), + iconBackground: e.done ? primaryColor : Colors.grey, + icon: Icon( + e.status == "shipped" + ? Ionicons.ios_airplane + : e.status == "delivered" + ? MaterialCommunityIcons.truck_fast + : e.status == "packed" + ? MaterialCommunityIcons.package + : e.status == "processed" + ? FontAwesome.dropbox + : MaterialCommunityIcons.inbox_arrow_down, + color: Colors.white, + ))) + .toList(); + } +} From b13dc69161acf7a5f80dd2197c142e6ab17596bb Mon Sep 17 00:00:00 2001 From: Sai Naw Wun Date: Mon, 12 Oct 2020 03:34:05 +0630 Subject: [PATCH 2/4] add packages, receiving & processing --- assets/local/localization_en.json | 15 +- assets/local/localization_mu.json | 29 +- lib/data/provider/package_data_provider.dart | 23 +- lib/data/services/package_imp.dart | 23 +- lib/data/services/package_service.dart | 7 +- lib/domain/constants.dart | 1 + lib/domain/entities/user.dart | 55 ++- lib/helpers/firebase_helper.dart | 17 + lib/helpers/pagination.dart | 70 ++++ lib/helpers/pagination_model.dart | 152 ------- lib/helpers/shared_pref.dart | 10 + lib/pages/box/box_list.dart | 3 +- lib/pages/chat/message_detail.dart | 6 + lib/pages/delivery/delivery_list.dart | 3 +- .../model/delivery_address_model.dart | 6 + lib/pages/discount/discount_list.dart | 3 +- .../model/fcs_shipment_model.dart | 3 +- lib/pages/invoice/invoce_list.dart | 3 +- lib/pages/main/home_page.dart | 390 ++++++++++++------ lib/pages/package/model/package_model.dart | 207 ++++++++-- lib/pages/package/package_editor.dart | 6 +- lib/pages/package/package_info.dart | 62 +-- lib/pages/package/package_list.dart | 109 +++-- lib/pages/processing/processing_editor.dart | 203 +++++---- lib/pages/processing/processing_info.dart | 94 ++--- lib/pages/processing/processing_list.dart | 5 +- ...ceiving_new.dart => receiving_editor.dart} | 60 ++- lib/pages/receiving/receiving_info.dart | 51 ++- lib/pages/receiving/receiving_list.dart | 4 +- lib/pages/shipment/shipment_list.dart | 5 +- lib/pages/widgets/badge.dart | 1 - .../widgets/local_popup_menu_button.dart | 120 ++++++ lib/pages/widgets/local_popupmenu.dart | 8 + lib/pages/widgets/popupmenu.dart | 2 - lib/pages/widgets/status_tree.dart | 17 +- lib/pages/widgets/task_button.dart | 5 +- 36 files changed, 1110 insertions(+), 668 deletions(-) create mode 100644 lib/helpers/pagination.dart delete mode 100644 lib/helpers/pagination_model.dart rename lib/pages/receiving/{receiving_new.dart => receiving_editor.dart} (77%) create mode 100644 lib/pages/widgets/local_popup_menu_button.dart create mode 100644 lib/pages/widgets/local_popupmenu.dart diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index af2569e..08d0ae9 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -92,6 +92,8 @@ "Home Start ================================================================":"", "home.invitation.request.msg":"We are working on your invitation request!", + "home.search":"Enter tracking number", + "home.search.btn":"Search", "Home End ================================================================":"", "Invite Start ================================================================":"", @@ -177,6 +179,8 @@ "package.rate":"Rate", "package.weight":"Weight", "package.amount":"Amount", + "package.popupmenu.active":"Active Packages", + "package.popupmenu.delivered":"Delivered Packages", "Package End ================================================================":"", "Market Start ================================================================":"", @@ -380,27 +384,32 @@ "delivery_addresses End ================================================================":"", "Receiving Start ================================================================":"", - "receiving.title":"Receiving", + "receiving.title":"Receivings", + "receiving.info":"Receiving", "receiving.new":"New Receiving", + "receiving.update":"Update Reveiving", "receiving.tracking.id":"Tracking ID", "receiving.remark":"Remark", "receiving.fcs.id":"FCS ID", "receiving.name":"Customer Name", "receiving.phone":"Phone Number", "receiving.create_btn":"Complete receiving", + "receiving.update_btn":"Update reveiving", "receiving.delete.confirm":"Delete this receiving?", "Receiving End ================================================================":"", "Processing Start ================================================================":"", "processing.title":"Processing", - "processing.info.title":"Package", + "processing.info.title":"Processing", "processing.tracking.id":"Tracking ID", "processing.name":"Customer Name", + "processing.phone":"Phone Number", + "processing.fcs.id":"FCS ID", "processing.market":"Market", "processing.status":"Status", "processing.desc":"Description", "processing.remark":"Remark", - "processing.edit.title":"Edit Package", + "processing.edit.title":"Processing", "processing.delete.confirm":"Delete this package?", "processing.edit.sub_title":"Processing", "processing.edit.complete.btn":"Complete processing", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index e43679f..6219dbb 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -92,6 +92,8 @@ "Home Start ================================================================":"", "home.invitation.request.msg":"ဖိတ်ကြားမှု တောင်းဆိုသည်ကို လုပ်ဆောင်နေပါသည်!", + "home.search":"Tracking number ရိုက်ထဲ့ပါ", + "home.search.btn":"ရှာမည်", "Home End ================================================================":"", "Invite Start ================================================================":"", @@ -177,6 +179,8 @@ "package.rate":"Rate", "package.weight":"Weight", "package.amount":"Amount", + "package.popupmenu.active":"လာမည့် အထုပ်များ", + "package.popupmenu.delivered":"ပို့ပြီးသော အထုပ်များ", "Package End ================================================================":"", "Market Start ================================================================":"", @@ -195,7 +199,7 @@ "Payment Start ================================================================":"", "pm.title":"ငွေပေးချေစနစ်များ", - "pm.new":"ငွေပေးချေစနစ်အသစ်", + "pm.new":"ငွေပေးချေစနစ် အသစ်", "pm.update":"ငွေပေးချေစနစ် ပြင်ဆင်ခြင်း", "pm.btn":"ငွေပေးချေစနစ်များ", "pm.name":"အမည်", @@ -225,7 +229,7 @@ "Boxes Start ================================================================":"", "boxes.name":"သေတ္တာများ", "boxes.title":"Boxes", - "boxes.new":"သေတ္တာအသစ်", + "boxes.new":"သေတ္တာ အသစ်", "box.edit.title":"သေတ္တာ ပြင်ဆင်ခြင်း", "box.package.id":"Package ID", "box.package.desc":"Description", @@ -286,9 +290,9 @@ "FCS Shipment End ================================================================":"", "Shipment Start ================================================================":"", - "shipment": "Shipments", - "shipment.title": "SHIPMENTS", - "shipment.new": "New Shipment", + "shipment": "ပို့ဆောင်ခြင်းများ", + "shipment.title": "ပို့ဆောင်ခြင်းများ", + "shipment.new": "ပို့ဆောင်ခြင်း အသစ်", "shipment.edit.title": "PICKUP", "shipment.date": "Pickup Date", "shipment.location_time": "Pickup Location / Time", @@ -374,33 +378,38 @@ "delivery_address.phonenumber": "ဖုန်းနံပါတ်", "delivery_address.create": "ပြုလုပ်ရန်", "delivery_address.update": "ပြုပြင်ရန်", - "delivery_address.new_address":"လိပ်စာအသစ်", + "delivery_address.new_address":"လိပ်စာ အသစ်", "delivery_address.change_address": "လိပ်စာပြောင်းပါ", "delivery_address.delete.confirm":"ပို့ဆောင်ရမည့်လိပ်စာကို ဖျက်မလား?", "delivery_addresses End ================================================================":"", "Receiving Start ================================================================":"", "receiving.title":"လက်ခံခြင်းများ", - "receiving.new":"လက်ခံခြင်းအသစ်", + "receiving.info":"လက်ခံခြင်း", + "receiving.new":"လက်ခံခြင်း အသစ်", + "receiving.update":"လက်ခံခြင်း ပြင်ဆင်ခြင်း", "receiving.tracking.id":"Tracking ID", "receiving.remark":"မှတ်ချက်", "receiving.fcs.id":"FCS ID", "receiving.name":"နာမည်", "receiving.phone":"ဖုန်းနံပါတ်", "receiving.create_btn":"လက်ခံမည်", + "receiving.update_btn":"ပြင်ဆင်မည်", "receiving.delete.confirm":"လက်ခံခြင်းကို ဖျက်မလား?", "Receiving End ================================================================":"", "Processing Start ================================================================":"", - "processing.title":"မွမ်းမံခြင်းများ", - "processing.info.title":"အထုပ်", + "processing.title":"လုပ်ဆောင်ခြင်းများ", + "processing.info.title":"လုပ်ဆောင်ခြင်း", "processing.tracking.id":"Tracking ID", "processing.name":"နာမည်", + "processing.phone":"ဖုန်းနံပါတ်", + "processing.fcs.id":"FCS ID", "processing.market":"အွန်လိုင်စျေးဆိုင်", "processing.status":"အခြေအနေ", "processing.desc":"ဖော်ပြချက်", "processing.remark":"မှတ်ချက်", - "processing.edit.title":"အထုပ် ပြင်ဆင်ခြင်း", + "processing.edit.title":"လုပ်ဆောင်ခြင်း", "processing.delete.confirm":"အထုပ်ကို ဖျက်မလား?", "processing.edit.sub_title":"မွမ်းမံခြင်း", "processing.edit.complete.btn":"မွမ်းမံခြင်း ပြီးဆုံးသည်", diff --git a/lib/data/provider/package_data_provider.dart b/lib/data/provider/package_data_provider.dart index 9eec0c7..4ccf220 100644 --- a/lib/data/provider/package_data_provider.dart +++ b/lib/data/provider/package_data_provider.dart @@ -16,13 +16,28 @@ class PackageDataProvider { payload: {"packages": json, "fcs_id": fcsID}, token: await getToken()); } - Future createPackage(Package package) async { - return await requestAPI("/package", "POST", + Future createReceiving(Package package) async { + return await requestAPI("/receiving", "POST", payload: package.toJson(), token: await getToken()); } - Future deletePackage(Package package) async { - return await requestAPI("/package", "DELETE", + Future updateReceiving(Package package) async { + return await requestAPI("/receiving", "PUT", + payload: package.toJson(), token: await getToken()); + } + + Future deleteReceiving(Package package) async { + return await requestAPI("/receiving", "DELETE", + payload: {"id": package.id}, token: await getToken()); + } + + Future updateProcessing(Package package) async { + return await requestAPI("/processing", "PUT", + payload: package.toJson(), token: await getToken()); + } + + Future deleteProcessing(Package package) async { + return await requestAPI("/processing", "DELETE", payload: {"id": package.id}, token: await getToken()); } diff --git a/lib/data/services/package_imp.dart b/lib/data/services/package_imp.dart index 9e33dff..db8ae62 100644 --- a/lib/data/services/package_imp.dart +++ b/lib/data/services/package_imp.dart @@ -20,8 +20,13 @@ class PackageServiceImp implements PackageService { } @override - Future createPackage(Package package) { - return packageDataProvider.createPackage(package); + Future createReceiving(Package package) { + return packageDataProvider.createReceiving(package); + } + + @override + Future updateReceiving(Package package) { + return packageDataProvider.updateReceiving(package); } @override @@ -30,7 +35,17 @@ class PackageServiceImp implements PackageService { } @override - Future deletePackage(Package package) { - return packageDataProvider.deletePackage(package); + Future deleteReceiving(Package package) { + return packageDataProvider.deleteReceiving(package); + } + + @override + Future updateProcessing(Package package) { + return packageDataProvider.updateProcessing(package); + } + + @override + Future deleteProcessing(Package package) { + return packageDataProvider.deleteProcessing(package); } } diff --git a/lib/data/services/package_service.dart b/lib/data/services/package_service.dart index 93ac51d..c16dced 100644 --- a/lib/data/services/package_service.dart +++ b/lib/data/services/package_service.dart @@ -2,7 +2,10 @@ import 'package:fcs/domain/entities/package.dart'; abstract class PackageService { Future createPackages(List packages, String fcsID); - Future createPackage(Package package); - Future deletePackage(Package package); + Future createReceiving(Package package); + Future updateReceiving(Package package); + Future deleteReceiving(Package package); + Future updateProcessing(Package package); + Future deleteProcessing(Package package); Future> searchPackage(String term); } diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 690fa9b..10f6be1 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -35,6 +35,7 @@ const package_shipped_status = "shipped"; const package_delivered_status = "delivered"; // Privileges +const privilege_sys_admin = "sa"; const privilege_admin = "admin"; const privilege_support = "sp"; const privilege_package = "pkg"; diff --git a/lib/domain/entities/user.dart b/lib/domain/entities/user.dart index 2c43357..d3f6eb0 100644 --- a/lib/domain/entities/user.dart +++ b/lib/domain/entities/user.dart @@ -3,6 +3,8 @@ import 'package:fcs/helpers/const.dart'; import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; +import '../constants.dart'; + DateFormat dayFormat = DateFormat("MMM dd yyyy"); DateFormat timeFormat = DateFormat("HH:mm"); final DateFormat dateFormat = DateFormat("d MMM yyyy"); @@ -123,36 +125,59 @@ class User { } bool hasSysAdmin() { - return privileges != null ? privileges.contains('sa') : false; + return _has(privilege_sys_admin); } bool hasAdmin() { - return privileges != null ? privileges.contains('admin') : false; + return _has(privilege_admin); } bool hasCustomers() { - return hasSysAdmin() || - hasAdmin() || - (privileges != null ? privileges.contains('c') : false); + return hasSysAdmin() || hasAdmin() || _has(privilege_customer); + } + + bool hasFcsShipments() { + return hasSysAdmin() || hasAdmin() || _has(privilege_fcs_shipment); } bool hasStaffs() { - return hasSysAdmin() || - hasAdmin() || - (privileges != null ? privileges.contains('s') : false); + return hasSysAdmin() || hasAdmin() || _has(privilege_staff); } bool hasSupport() { - return hasSysAdmin() || - hasAdmin() || - (privileges != null ? privileges.contains('sp') : false); + return hasSysAdmin() || hasAdmin() || _has(privilege_support); } bool hasPackages() { - return hasSysAdmin() || - hasAdmin() || - status == userStatusJoined || - (privileges != null ? privileges.contains('p') : false); + return hasSysAdmin() || hasAdmin() || _has(privilege_package); + } + + bool hasReceiving() { + return hasSysAdmin() || hasAdmin() || _has(privilege_receiving); + } + + bool hasProcessing() { + return hasSysAdmin() || hasAdmin() || _has(privilege_processing); + } + + bool hasDeliveries() { + return hasSysAdmin() || hasAdmin() || _has(privilege_delivery); + } + + bool hasInvoices() { + return hasSysAdmin() || hasAdmin() || _has(privilege_invoice); + } + + bool hasShipment() { + return hasSysAdmin() || hasAdmin() || _has(privilege_shipment); + } + + bool hasCarton() { + return hasSysAdmin() || hasAdmin() || _has(privilege_carton); + } + + bool _has(String privilege) { + return (privileges != null ? privileges.contains(privilege) : false); } @override diff --git a/lib/helpers/firebase_helper.dart b/lib/helpers/firebase_helper.dart index bf72b7f..3a04030 100644 --- a/lib/helpers/firebase_helper.dart +++ b/lib/helpers/firebase_helper.dart @@ -30,3 +30,20 @@ Future uploadStorage(String path, File file, {String fileName}) async { print("meta:${await storageReference.getMetadata()}"); return downloadUrl; } + +Future deleteStorageFromUrls(List urls) async { + if (urls == null) return; + for (int i = 0; i < urls.length; i++) { + await deleteStorageFromUrl(urls[i]); + } +} + +Future deleteStorageFromUrl(String url) async { + try { + StorageReference storageReference = + await FirebaseStorage.instance.getReferenceFromUrl(url); + await storageReference.delete(); + } catch (e) { + log.warning("deleteStorage:$e"); + } +} diff --git a/lib/helpers/pagination.dart b/lib/helpers/pagination.dart new file mode 100644 index 0000000..56a60d8 --- /dev/null +++ b/lib/helpers/pagination.dart @@ -0,0 +1,70 @@ +import 'dart:async'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:logging/logging.dart'; + +/* + * Pagination load data in page + */ +class Pagination { + final log = Logger('PaginationModel'); + + final int rowPerLoad; + DocumentSnapshot prev; + bool ended = false; + + Query pageQuery; + + Pagination(Query pageQuery, {this.rowPerLoad = 20}) { + this.pageQuery = pageQuery; + initData(); + } + + void initData() async { + _clearState(); + load(); + } + + void _clearState() { + prev = null; + ended = false; + if (controller != null) controller.close(); + } + + StreamController controller; + Stream get stream { + if (controller != null) { + controller.close(); + } + controller = StreamController(onCancel: _clearState); + return controller.stream; + } + + void close() { + _clearState(); + } + + Future load() async { + Query _query = + prev != null ? pageQuery.startAfterDocument(prev) : pageQuery; + try { + await _query + .limit(rowPerLoad) + .getDocuments(source: Source.server) + .then((QuerySnapshot snapshot) { + int count = snapshot.documents.length; + ended = count < rowPerLoad; + prev = count > 0 ? snapshot.documents[count - 1] : prev; + snapshot.documents.forEach((e) { + controller.add(e); + }); + if (ended) { + controller.add(null); + } + }); + } catch (e) { + log.warning("Error!! $e"); + } + return ended; + } +} diff --git a/lib/helpers/pagination_model.dart b/lib/helpers/pagination_model.dart deleted file mode 100644 index ce0d192..0000000 --- a/lib/helpers/pagination_model.dart +++ /dev/null @@ -1,152 +0,0 @@ -import 'dart:async'; - -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:logging/logging.dart'; - -/* - * PaginationModel load data in page - * and listen to document change based on 'update_time' and 'delete_time' fields - * of the document - */ -class PaginationModel { - final log = Logger('PaginationModel'); - - List ids = []; - DocumentSnapshot prev; - int rowPerLoad = 10; - bool ended = false; - - StreamSubscription listener; - CollectionReference listeningCol; - Query pageQuery; - - PaginationModel(CollectionReference listeningCol, Query pageQuery, - {this.rowPerLoad = 10}) { - this.listeningCol = listeningCol; - this.pageQuery = pageQuery; - initData(); - } - - void initData() async { - _clearState(); - _initListener(); - load(); - } - - void _clearState() { - prev = null; - ids = []; - ended = false; - if (listener != null) listener.cancel(); - listener = null; - if (controller != null) controller.close(); - } - - StreamController controller; - Stream listen() { - if (controller != null) { - controller.close(); - } - controller = StreamController(onCancel: _clearState); - return controller.stream; - } - - void close() { - _clearState(); - } - - final String updateTimeField = 'update_time'; - final String deleteTimeField = 'delete_time'; - void _initListener() { - Query _query = - listeningCol.orderBy(updateTimeField, descending: true).limit(1); - _query.getDocuments(source: Source.server).then((QuerySnapshot snapshot) { - int count = snapshot.documents.length; - int updateTime = 0; - if (count == 1) { - updateTime = snapshot.documents[0].data[updateTimeField]; - } - - Query _queryListener = listeningCol - .where(updateTimeField, isGreaterThan: updateTime) - .orderBy(updateTimeField, descending: true); - - listener = - _queryListener.snapshots(includeMetadataChanges: true).listen((qs) { - qs.documentChanges.forEach((c) { - switch (c.type) { - case DocumentChangeType.added: - log.info("added!! $c"); - _update(c.document.documentID, c.document.data); - break; - case DocumentChangeType.modified: - log.info("modified!! $c"); - _update(c.document.documentID, c.document.data); - break; - default: - } - }); - }); - }); - } - - void _update(String id, Map data) { - if (ids.contains(id)) { - var deleted = data[deleteTimeField]; - if (deleted > 0) { - ids.remove(id); - controller.add(Result( - id: id, - data: data, - documentChangeType: DocumentChangeType.removed)); - } else { - controller.add(Result( - id: id, - data: data, - documentChangeType: DocumentChangeType.modified)); - } - } else { - ids.add(id); - controller.add(Result( - id: id, data: data, documentChangeType: DocumentChangeType.added)); - } - } - - Future load() async { - Query _query = - prev != null ? pageQuery.startAfterDocument(prev) : pageQuery; - try { - await _query - .where(deleteTimeField, isEqualTo: 0) - .limit(rowPerLoad) - .getDocuments(source: Source.server) - .then((QuerySnapshot snapshot) { - int count = snapshot.documents.length; - ended = count < rowPerLoad; - prev = count > 0 ? snapshot.documents[count - 1] : prev; - snapshot.documents.forEach((e) { - if (!ids.contains(e.documentID)) log.shout("load!! $e"); - ids.add(e.documentID); - controller.add(Result( - id: e.documentID, - data: e.data, - documentChangeType: DocumentChangeType.added)); - }); - if (ended) { - controller.add(Result(isEnded: true)); - } - }); - } catch (e) { - log.warning("Error!! $e"); - } - return ended; - } -} - -class Result { - String id; - Map data; - DocumentChangeType documentChangeType; - bool isEnded; - Result({this.id, this.data, this.documentChangeType, this.isEnded = false}); -} diff --git a/lib/helpers/shared_pref.dart b/lib/helpers/shared_pref.dart index c82fdb6..d2f26f8 100644 --- a/lib/helpers/shared_pref.dart +++ b/lib/helpers/shared_pref.dart @@ -27,6 +27,16 @@ class SharedPref { prefs.setString('language', lang); } + static Future getStaffMode() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + return prefs.getBool('staff_mode_on'); + } + + static Future saveStaffMode(bool staffMode) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + prefs.setBool('staff_mode_on', staffMode); + } + static Future saveUser(User user) async { await _save("user", user.toJson()); } diff --git a/lib/pages/box/box_list.dart b/lib/pages/box/box_list.dart index 485e455..3447982 100644 --- a/lib/pages/box/box_list.dart +++ b/lib/pages/box/box_list.dart @@ -4,6 +4,7 @@ import 'package:fcs/pages/box/model/box_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.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:provider/provider.dart'; @@ -38,7 +39,7 @@ class _BoxListState extends State { appBar: AppBar( centerTitle: true, leading: new IconButton( - icon: new Icon(Icons.close), + icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, diff --git a/lib/pages/chat/message_detail.dart b/lib/pages/chat/message_detail.dart index 3a85b61..14f884b 100644 --- a/lib/pages/chat/message_detail.dart +++ b/lib/pages/chat/message_detail.dart @@ -12,6 +12,7 @@ import 'package:fcs/pages/package/package_info.dart'; import 'package:fcs/pages/profile/profile_page.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -45,6 +46,10 @@ class MessageDetail extends StatelessWidget { return Scaffold( appBar: AppBar( + leading: new IconButton( + icon: new Icon(CupertinoIcons.back), + onPressed: () => Navigator.of(context).pop(), + ), backgroundColor: primaryColor, elevation: .9, title: Text( @@ -170,6 +175,7 @@ class MessageDetail extends StatelessWidget { PackageModel packageModel = Provider.of(context, listen: false); Package p = await packageModel.getPackage(message.messageID); + if (p == null) return; Navigator.push(context, BottomUpPageRoute(PackageInfo(package: p))); } if (message.messageType == message_type_profile && diff --git a/lib/pages/delivery/delivery_list.dart b/lib/pages/delivery/delivery_list.dart index 1e958b6..2314714 100644 --- a/lib/pages/delivery/delivery_list.dart +++ b/lib/pages/delivery/delivery_list.dart @@ -2,6 +2,7 @@ import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/box/model/box_model.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -35,7 +36,7 @@ class _DeliverListState extends State { appBar: AppBar( centerTitle: true, leading: new IconButton( - icon: new Icon(Icons.close), + icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, diff --git a/lib/pages/delivery_address/model/delivery_address_model.dart b/lib/pages/delivery_address/model/delivery_address_model.dart index 73df666..2609061 100644 --- a/lib/pages/delivery_address/model/delivery_address_model.dart +++ b/lib/pages/delivery_address/model/delivery_address_model.dart @@ -21,6 +21,12 @@ class DeliveryAddressModel extends BaseModel { _loadDeliveryAddresses(); } + @override + logout() async { + if (listener != null) await listener.cancel(); + deliveryAddresses = []; + } + Future _loadDeliveryAddresses() async { if (user == null) return; String path = "$delivery_address_collection/"; diff --git a/lib/pages/discount/discount_list.dart b/lib/pages/discount/discount_list.dart index 0a1a9f6..e9e636a 100644 --- a/lib/pages/discount/discount_list.dart +++ b/lib/pages/discount/discount_list.dart @@ -4,6 +4,7 @@ import 'package:fcs/pages/discount/model/discount_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -29,7 +30,7 @@ class _DiscountListState extends State { AppTranslations.of(context).text("discount.title"), ), leading: new IconButton( - icon: new Icon(Icons.close), + icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, diff --git a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart index 2ec6051..d0da185 100644 --- a/lib/pages/fcs_shipment/model/fcs_shipment_model.dart +++ b/lib/pages/fcs_shipment/model/fcs_shipment_model.dart @@ -20,7 +20,7 @@ class FcsShipmentModel extends BaseModel { } Future _loadFcsShipments() async { - if (user == null) return; + if (user == null || !user.hasFcsShipments()) return; String path = "/$fcs_shipment_collection/"; if (listener != null) listener.cancel(); fcsShipments = []; @@ -49,6 +49,7 @@ class FcsShipmentModel extends BaseModel { @override logout() async { + if (listener != null) await listener.cancel(); fcsShipments = []; } diff --git a/lib/pages/invoice/invoce_list.dart b/lib/pages/invoice/invoce_list.dart index 0133dfc..4ae1884 100644 --- a/lib/pages/invoice/invoce_list.dart +++ b/lib/pages/invoice/invoce_list.dart @@ -8,6 +8,7 @@ import 'package:fcs/pages/user_search/user_serach.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; @@ -45,7 +46,7 @@ class _InvoiceListState extends State { appBar: AppBar( centerTitle: true, leading: new IconButton( - icon: new Icon(Icons.close), + icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index c7d4b8a..d0d18fa 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -2,7 +2,9 @@ import 'dart:async'; import 'dart:io'; import 'package:fcs/data/services/services.dart'; +import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/entities/user.dart'; +import 'package:fcs/helpers/shared_pref.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/transalation.dart'; import 'package:fcs/pages/box/box_list.dart'; @@ -17,23 +19,27 @@ import 'package:fcs/pages/fcs_shipment/fcs_shipment_list.dart'; import 'package:fcs/pages/invoice/invoce_list.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/main/util.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.dart'; import 'package:fcs/pages/processing/processing_list.dart'; import 'package:fcs/pages/rates/shipment_rates.dart'; import 'package:fcs/pages/receiving/receiving_list.dart'; import 'package:fcs/pages/shipment/shipment_list.dart'; import 'package:fcs/pages/staff/staff_list.dart'; -import 'package:fcs/pages/widgets/task_button.dart'; import 'package:fcs/pages/widgets/badge.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/bottom_widgets.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:fcs/pages/widgets/progress.dart'; import 'package:fcs/pages/widgets/right_left_page_rout.dart'; +import 'package:fcs/pages/widgets/task_button.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:intl/intl.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; @@ -52,10 +58,12 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { final log = Logger('_HomePageState'); bool login = false; - bool customer = true; + bool _isLoading = false; List isSelected = [true, false]; static FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); + TextEditingController _searchCtl = TextEditingController(); + List isFcs = [false]; @override void initState() { @@ -73,6 +81,18 @@ class _HomePageState extends State { mainModel.setMessaginToken = token; }); _initLocalNotifications(); + _loadStaffMode(mainModel.isCustomer()); + } + + _loadStaffMode(bool isCustomer) async { + bool staffMode = await SharedPref.getStaffMode(); + setState(() { + if (isCustomer) { + isFcs[0] = false; + } else { + isFcs[0] = staffMode; + } + }); } String notiUserID, notiUserName; @@ -189,7 +209,6 @@ class _HomePageState extends State { if (user == null) { return Container(); } - customer = Provider.of(context).isCustomer(); login = Provider.of(context).isLogin(); LanguageModel languageModel = Provider.of(context); @@ -204,6 +223,12 @@ class _HomePageState extends State { icon: Octicons.package, btnCallback: () => Navigator.of(context).push( CupertinoPageRoute(builder: (context) => PackageList()))); + final packagesBtnFcs = TaskButton("package.btn.name", + icon: Octicons.package, + btnCallback: () => Navigator.of(context).push(CupertinoPageRoute( + builder: (context) => PackageList( + onlyFcs: true, + )))); final receivingBtn = TaskButton("receiving.title", icon: MaterialCommunityIcons.inbox_arrow_down, @@ -214,15 +239,20 @@ class _HomePageState extends State { icon: FontAwesome.dropbox, btnCallback: () => Navigator.of(context).push( CupertinoPageRoute(builder: (context) => ProcessingList()))); - final boxesBtn = TaskButton("boxes.name", + final cartonBtn = TaskButton("boxes.name", icon: MaterialCommunityIcons.package, - btnCallback: () => - Navigator.of(context).push(BottomUpPageRoute(BoxList()))); + btnCallback: () => Navigator.of(context) + .push(CupertinoPageRoute(builder: (context) => BoxList()))); - final pickUpBtn = TaskButton("shipment", + final shipmentBtn = TaskButton("shipment", icon: SimpleLineIcons.direction, - btnCallback: () => - Navigator.of(context).push(BottomUpPageRoute(ShipmentList()))); + btnCallback: () => Navigator.of(context) + .push(CupertinoPageRoute(builder: (context) => ShipmentList()))); + + final shipmentBtnFcs = TaskButton("shipment", + icon: SimpleLineIcons.direction, + btnCallback: () => Navigator.of(context) + .push(CupertinoPageRoute(builder: (context) => ShipmentList()))); final shipmentCostBtn = TaskButton("rate", icon: FontAwesomeIcons.calculator, @@ -231,21 +261,19 @@ class _HomePageState extends State { final fcsShipmentBtn = TaskButton("FCSshipment.title", icon: Ionicons.ios_airplane, - btnCallback: () => Navigator.of(context).push(CupertinoPageRoute( + btnCallback: () => Navigator.of(context).push(CupertinoPageRoute( builder: (context) => FcsShipmentList(), ))); - final notiBtnOrg = TaskButton("message.btn", icon: Icons.message, btnCallback: () { MessageModel messageModel = Provider.of(context, listen: false); messageModel.initQuery(user.id); - Navigator.push( - context, - BottomUpPageRoute(MessageDetail( - messageModel: messageModel, - )), - ).then((value) { + Navigator.of(context) + .push(CupertinoPageRoute( + builder: (context) => MessageDetail(messageModel: messageModel), + )) + .then((value) { if (user.userUnseenCount > 0) { messageModel.seenMessages(user.id, true); } @@ -272,128 +300,204 @@ class _HomePageState extends State { final invoicesBtn = TaskButton("invoices.btn", icon: FontAwesomeIcons.fileInvoice, - btnCallback: () => - Navigator.of(context).push(BottomUpPageRoute(InvoiceList()))); + btnCallback: () => Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => InvoiceList()))); + final invoicesBtnFcs = TaskButton("invoices.btn", + icon: FontAwesomeIcons.fileInvoice, + btnCallback: () => Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => InvoiceList()))); final discountBtn = TaskButton("discount.btn", icon: Entypo.price_ribbon, - btnCallback: () => - Navigator.of(context).push(BottomUpPageRoute(DiscountList()))); + btnCallback: () => Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => DiscountList()))); final deliveryBtn = TaskButton("delivery.title", icon: MaterialCommunityIcons.truck_fast, - btnCallback: () => - Navigator.of(context).push(BottomUpPageRoute(DeliverList()))); + btnCallback: () => Navigator.of(context).push( + CupertinoPageRoute(builder: (context) => DeliverList()))); List widgets = []; - if (user != null) { - true ? widgets.add(pickUpBtn) : ""; - !customer ? widgets.add(fcsShipmentBtn) : ""; - customer ? widgets.add(notiBtn) : ""; - user.hasStaffs() ? widgets.add(staffBtn) : ""; - widgets.add(shipmentCostBtn); - user.hasPackages() ? widgets.add(packagesBtn) : ""; - user.hasPackages() ? widgets.add(receivingBtn) : ""; - user.hasPackages() ? widgets.add(processingBtn) : ""; - true ? widgets.add(boxesBtn) : ""; - true ? widgets.add(deliveryBtn) : ""; - user.hasCustomers() ? widgets.add(customersBtn) : ""; - true ? widgets.add(invoicesBtn) : ""; - // true ? widgets.add(discountBtn) : ""; - } + widgets.add(notiBtn); + widgets.add(packagesBtn); + widgets.add(shipmentBtn); + widgets.add(invoicesBtn); widgets.add(faqBtn); - return OfflineRedirect( - child: FlavorBanner( - child: Scaffold( - appBar: AppBar( - elevation: 0, - backgroundColor: primaryColor, - title: ClipRRect( - child: Image.asset("assets/logo.jpg", height: 40), - borderRadius: new BorderRadius.circular(30.0), - ), - actions: login - ? [ - ToggleButtons( - children: [ - Image.asset( - 'icons/flags/png/us.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ), - Image.asset( - 'icons/flags/png/mm.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ) - ], - onPressed: _langChange, - isSelected: languageModel.currentState, - selectedBorderColor: Colors.white24, - ), - IconButton( - onPressed: () { - Navigator.of(context) - .push(RightLeftPageRoute(Profile())); - }, - iconSize: 30, - icon: Icon(Icons.account_circle), - ), - ] - : [ - ToggleButtons( - children: [ - Image.asset( - 'icons/flags/png/us.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ), - Image.asset( - 'icons/flags/png/mm.png', - package: 'country_icons', - fit: BoxFit.fitWidth, - width: 25, - ) - ], - onPressed: _langChange, - isSelected: languageModel.currentState, - ), - FlatButton( - onPressed: () { - Navigator.of(context) - .push(BottomUpPageRoute(SigninPage())); - }, - child: Text( - "Sign In", - style: siginButtonStyle, - ), + widgets.add(shipmentCostBtn); + + List widgetsFcs = []; + if (user.hasPackages()) widgetsFcs.add(packagesBtnFcs); + if (user.hasShipment()) widgetsFcs.add(shipmentBtnFcs); + if (user.hasInvoices()) widgetsFcs.add(invoicesBtnFcs); + + if (user.hasFcsShipments()) widgetsFcs.add(fcsShipmentBtn); + if (user.hasReceiving()) widgetsFcs.add(receivingBtn); + if (user.hasProcessing()) widgetsFcs.add(processingBtn); + if (user.hasCarton()) widgetsFcs.add(cartonBtn); + if (user.hasDeliveries()) widgetsFcs.add(deliveryBtn); + if (user.hasCustomers()) widgetsFcs.add(customersBtn); + if (user.hasAdmin()) widgetsFcs.add(discountBtn); + if (user.hasStaffs()) widgetsFcs.add(staffBtn); + + final fcsToggle = ToggleButtons( + selectedColor: Colors.white, + children: [ + Icon(MaterialCommunityIcons.worker), + ], + onPressed: (i) => this.setState(() { + isFcs[0] = !isFcs[0]; + SharedPref.saveStaffMode(isFcs[0]); + }), + isSelected: isFcs, + selectedBorderColor: Colors.white24, + ); + final langToggle = ToggleButtons( + children: [ + Image.asset( + 'icons/flags/png/us.png', + package: 'country_icons', + fit: BoxFit.fitWidth, + width: 25, + ), + Image.asset( + 'icons/flags/png/mm.png', + package: 'country_icons', + fit: BoxFit.fitWidth, + width: 25, + ) + ], + onPressed: _langChange, + isSelected: languageModel.currentState, + selectedBorderColor: Colors.white24, + ); + final signinBtn = FlatButton( + onPressed: () { + Navigator.of(context).push(BottomUpPageRoute(SigninPage())); + }, + child: Text( + "Sign In", + style: siginButtonStyle, + ), + ); + final profileBtn = IconButton( + onPressed: () { + Navigator.of(context).push(RightLeftPageRoute(Profile())); + }, + iconSize: 30, + icon: Icon(Icons.account_circle), + ); + + var searchInput = Row(children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only(bottom: 3, left: 5, right: 5, top: 3), + child: Theme( + data: new ThemeData( + primaryColor: primaryColor, + primaryColorDark: primaryColor, + ), + child: TextField( + style: TextStyle(color: Colors.white), + controller: _searchCtl, + scrollPadding: EdgeInsets.all(0), + decoration: new InputDecoration( + enabledBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(30)), + borderSide: + const BorderSide(color: Colors.white, width: 1.5), + ), + focusedBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(30)), + borderSide: + const BorderSide(color: Colors.white, width: 1.5), + ), + contentPadding: EdgeInsets.only(top: 1, bottom: 1), + isDense: true, + hintText: getLocalString(context, "home.search"), + hintStyle: languageModel.isEng + ? newLabelStyle(color: Colors.white60) + : newLabelStyleMM(color: Colors.white60), + prefixIcon: const Icon( + Icons.search, + color: Colors.grey, + ), + suffixIcon: InkWell( + onTap: () => {_searchCtl.clear()}, + child: const Icon( + Icons.close, + color: Colors.grey, + ), + ), + suffixStyle: const TextStyle(color: primaryColor)), + ), + ), + ), + ), + InkWell( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: LocalText( + context, + "home.search.btn", + color: Colors.white, + ), + ), + onTap: _lookup, + ) + ]); + widgets.insert(0, searchInput); + + return LocalProgress( + inAsyncCall: _isLoading, + child: OfflineRedirect( + child: FlavorBanner( + child: Scaffold( + appBar: AppBar( + elevation: 0, + backgroundColor: primaryColor, + title: ClipRRect( + child: Image.asset("assets/logo.jpg", height: 40), + borderRadius: new BorderRadius.circular(30.0), + ), + actions: login + ? user.isCustomer() + ? [ + langToggle, + profileBtn, + ] + : [ + fcsToggle, + langToggle, + profileBtn, + ] + : [ + langToggle, + signinBtn, + ]), + body: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color(0xd0272262), + Color(0xfa272262), + ], + ), + ), + child: ListView( + children: [ + Column(children: [ + Wrap( + alignment: WrapAlignment.center, + children: isFcs[0] ? widgetsFcs : widgets, ), ]), - body: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xd0272262), - Color(0xfa272262), + SizedBox(height: 50), + BottomWidgets(), ], - ), - ), - child: ListView( - children: [ - Column(children: [ - Wrap( - alignment: WrapAlignment.center, - children: widgets, - ), - ]), - BottomWidgets(), - ], - ))), + ))), + ), ), ); } @@ -408,4 +512,34 @@ class _HomePageState extends State { isSelected[index] = !isSelected[index]; }); } + + _lookup() async { + setState(() { + _isLoading = true; + }); + + try { + String term = _searchCtl.text; + if (term == null || term.trim() == "") return; + var packageModel = Provider.of(context, listen: false); + Package package = await packageModel.lookupPackage(term); + if (package == null) { + showMsgDialog(context, "Not found", "Tracking ID - '$term' not found!"); + return; + } + Navigator.push( + context, + BottomUpPageRoute(PackageInfo( + package: package, + isSearchResult: true, + )), + ); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 4633a5a..5411e5c 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -1,6 +1,8 @@ import 'dart:async'; import 'dart:io'; import 'package:fcs/data/services/services.dart'; +import 'package:fcs/domain/vo/message.dart'; +import 'package:fcs/helpers/pagination.dart'; import 'package:path/path.dart' as Path; import 'package:cloud_firestore/cloud_firestore.dart'; @@ -15,37 +17,97 @@ class PackageModel extends BaseModel { final log = Logger('PackageModel'); StreamSubscription listener; + StreamSubscription customerPackageListener; + Pagination pagination; + List packages = []; + List customerPackages = []; + List deliveredPackages = []; + + bool endOfDeliveredPackages = false; + bool isLoading = false; @override void privilegeChanged() { super.privilegeChanged(); _loadPackages(); + _loadCustomerPackages(); } @override logout() async { if (listener != null) await listener.cancel(); + if (customerPackageListener != null) await customerPackageListener.cancel(); + if (pagination != null) pagination.close(); packages = []; + customerPackages = []; + deliveredPackages = []; + } + + Future initDeliveredPackages() { + if (pagination != null) pagination.close(); + deliveredPackages = []; + endOfDeliveredPackages = false; + isLoading = false; + + var pageQuery = Firestore.instance + .collection("/$packages_collection") + // .collection( + // "/users/8OTfsbVvsUOn1SLxy1OrKk7Y_yNKkVoGalPcIlcHnAY/messages") + // .orderBy("date", descending: true); + .where("is_delivered", isEqualTo: true) + .where("is_deleted", isEqualTo: false); + if (user.isCustomer()) { + pageQuery = pageQuery.where("user_id", isEqualTo: user.id); + } + pageQuery = pageQuery.orderBy("current_status_date", descending: true); + pagination = new Pagination(pageQuery, rowPerLoad: 20); + pagination.stream.listen((doc) { + if (doc == null) { + endOfDeliveredPackages = true; + } else { + deliveredPackages.add(Package.fromMap(doc.data, doc.documentID)); + // var m = Message.fromMap(doc.data, doc.documentID); + // deliveredPackages.add(Package( + // id: m.id, + // status: package_delivered_status, + // currentStatus: package_delivered_status, + // currentStatusDate: m.date, + // trackingID: (count++).toString(), + // market: m.message)); + } + }); + return null; + } + + Future loadMoreDeliveredPackages() { + if (pagination != null && !isLoading && !endOfDeliveredPackages) { + isLoading = true; + notifyListeners(); + pagination.load().then((value) { + isLoading = false; + notifyListeners(); + }); + } + return null; } Future _loadPackages() async { - if (user == null) return; - String path = ""; - if (user.isCustomer()) { - path = "/$user_collection/${user.id}/$packages_collection"; - } else { - path = "/$packages_collection"; - } + if (user == null || + !user.hasPackages() || + !user.hasReceiving() || + !user.hasProcessing()) return; + String path = "/$packages_collection"; if (listener != null) listener.cancel(); packages = []; try { - listener = Firestore.instance + var q = Firestore.instance .collection("$path") .where("is_delivered", isEqualTo: false) - .snapshots() - .listen((QuerySnapshot snapshot) { + .where("is_deleted", isEqualTo: false); + + listener = q.snapshots().listen((QuerySnapshot snapshot) { packages.clear(); packages = snapshot.documents.map((documentSnapshot) { var package = Package.fromMap( @@ -59,14 +121,36 @@ class PackageModel extends BaseModel { } } + Future _loadCustomerPackages() async { + if (user == null) return; + String path = "/$packages_collection"; + if (customerPackageListener != null) customerPackageListener.cancel(); + customerPackages = []; + + try { + var q = Firestore.instance + .collection("$path") + .where("is_delivered", isEqualTo: false) + .where("is_deleted", isEqualTo: false) + .where("user_id", isEqualTo: user.id); + + customerPackageListener = q.snapshots().listen((QuerySnapshot snapshot) { + customerPackages.clear(); + customerPackages = snapshot.documents.map((documentSnapshot) { + var package = Package.fromMap( + documentSnapshot.data, documentSnapshot.documentID); + return package; + }).toList(); + notifyListeners(); + }); + } catch (e) { + log.warning("Error!! $e"); + } + } + Future getPackage(String id) async { if (user == null) return null; - String path = ""; - if (user.isCustomer()) { - path = "/$user_collection/${user.id}/$packages_collection"; - } else { - path = "/$packages_collection"; - } + String path = "/$packages_collection"; try { DocumentSnapshot snap = await Firestore.instance.collection("$path").document(id).get(); @@ -80,6 +164,42 @@ class PackageModel extends BaseModel { return null; } + Future lookupPackage(String trackingID) async { + if (user == null) return null; + String path = "/$packages_collection"; + + try { + var qsnap = await Firestore.instance + .collection("$path") + .where("tracking_id", isEqualTo: trackingID) + .where("has_user_id", isEqualTo: false) + .getDocuments(source: Source.server); + if (qsnap.documents.length > 0) { + var snap = qsnap.documents[0]; + if (snap.exists) { + var package = Package.fromMap(snap.data, snap.documentID); + return package; + } + } + + qsnap = await Firestore.instance + .collection("$path") + .where("tracking_id", isEqualTo: trackingID) + .where("user_id", isEqualTo: user.id) + .getDocuments(source: Source.server); + if (qsnap.documents.length > 0) { + var snap = qsnap.documents[0]; + if (snap.exists) { + var package = Package.fromMap(snap.data, snap.documentID); + return package; + } + } + } catch (e) { + log.warning("Error!! $e"); + } + return null; + } + Future> searchUser(String term) { return Services.instance.userService.searchUser(term); } @@ -93,8 +213,8 @@ class PackageModel extends BaseModel { .createPackages(packages, user.fcsID); } - Future createPackage(User user, Package package, List files, - List deletedUrls) async { + Future createReceiving( + User user, Package package, List files) async { if (user != null) { package.fcsID = user.fcsID; } @@ -106,28 +226,61 @@ class PackageModel extends BaseModel { String url = await uploadStorage(path, f); package.photoUrls.add(url); } - package.photoUrls.removeWhere((e) => deletedUrls.contains(e)); } - return Services.instance.packageService.createPackage(package); + return Services.instance.packageService.createReceiving(package); } - Future completeProcessing( - Package package, List files, List deletedUrls) async { + Future updateReceiving(User user, Package package, List files, + List deletedUrls) async { + if (user != null) { + package.fcsID = user.fcsID; + } + if (deletedUrls != null) { + for (String url in deletedUrls) { + package.photoUrls.remove(url); + } + await deleteStorageFromUrls(deletedUrls); + } + if (files != null) { if (files.length > 5) throw Exception("Exceed number of file upload"); package.photoUrls = package.photoUrls == null ? [] : package.photoUrls; for (File f in files) { - String path = Path.join(pkg_files_path, package.userID, package.id); + String path = Path.join(pkg_files_path); + String url = await uploadStorage(path, f); + package.photoUrls.add(url); + } + } + await Services.instance.packageService.updateReceiving(package); + } + + Future deleteReceiving(Package package) { + return Services.instance.packageService.deleteReceiving(package); + } + + Future updateProcessing( + Package package, List files, List deletedUrls) async { + if (deletedUrls != null) { + for (String url in deletedUrls) { + package.photoUrls.remove(url); + } + await deleteStorageFromUrls(deletedUrls); + } + + if (files != null) { + if (files.length > 5) throw Exception("Exceed number of file upload"); + package.photoUrls = package.photoUrls == null ? [] : package.photoUrls; + for (File f in files) { + String path = Path.join(pkg_files_path); String url = await uploadStorage(path, f); package.photoUrls.add(url); } package.photoUrls.removeWhere((e) => deletedUrls.contains(e)); } - await request("/package", "PUT", - payload: package.toJson(), token: await getToken()); + await Services.instance.packageService.updateProcessing(package); } - Future deletePackage(Package package) { - return Services.instance.packageService.deletePackage(package); + Future deleteProcessing(Package package) { + return Services.instance.packageService.deleteProcessing(package); } } diff --git a/lib/pages/package/package_editor.dart b/lib/pages/package/package_editor.dart index b6b48db..06bbf07 100644 --- a/lib/pages/package/package_editor.dart +++ b/lib/pages/package/package_editor.dart @@ -228,8 +228,8 @@ class _PackageEditorPageState extends State { _package.desc = _descCtl.text; _package.remark = _remarkCtl.text; _package.market = selectedMarket; - await packageModel.completeProcessing(_package, - multiImgController.getAddedFile, multiImgController.getDeletedUrl); + // await packageModel.completeProcessing(_package, + // multiImgController.getAddedFile, multiImgController.getDeletedUrl); Navigator.pop(context); } catch (e) { showMsgDialog(context, "Error", e.toString()); @@ -251,7 +251,7 @@ class _PackageEditorPageState extends State { PackageModel packageModel = Provider.of(context, listen: false); try { - await packageModel.deletePackage(_package); + // await packageModel.deletePackage(_package); Navigator.pop(context, true); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/package/package_info.dart b/lib/pages/package/package_info.dart index 0e635ff..9134a8a 100644 --- a/lib/pages/package/package_info.dart +++ b/lib/pages/package/package_info.dart @@ -1,28 +1,24 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/model/main_model.dart'; -import 'package:fcs/pages/package/package_editor.dart'; -import 'package:fcs/pages/main/util.dart'; -import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/multi_img_controller.dart'; import 'package:fcs/pages/widgets/multi_img_file.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:fcs/pages/widgets/status_tree.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; -import 'package:timeline_list/timeline.dart'; import 'package:timeline_list/timeline_model.dart'; -import 'model/package_model.dart'; - final DateFormat dateFormat = DateFormat("d MMM yyyy"); class PackageInfo extends StatefulWidget { + final isSearchResult; final Package package; - PackageInfo({this.package}); + PackageInfo({this.package, this.isSearchResult = false}); @override _PackageInfoState createState() => _PackageInfoState(); @@ -54,8 +50,6 @@ class _PackageInfoState extends State { @override Widget build(BuildContext context) { - bool isCustomer = Provider.of(context).isCustomer(); - final trackingIdBox = DisplayText( text: _package.trackingID, labelTextKey: "package.tracking.id", @@ -109,14 +103,6 @@ class _PackageInfoState extends State { fontSize: 20, color: primaryColor, ), - actions: [ - isCustomer - ? Container() - : IconButton( - icon: Icon(Icons.edit, color: primaryColor), - onPressed: _gotoEditor, - ) - ], ), body: Card( child: Column( @@ -126,29 +112,15 @@ class _PackageInfoState extends State { padding: const EdgeInsets.all(10.0), child: ListView(children: [ trackingIdBox, - customerNameBox, - marketBox, + widget.isSearchResult ? Container() : customerNameBox, + widget.isSearchResult ? Container() : marketBox, statusBox, _package.photoUrls.length == 0 ? Container() : img, - descBox, + widget.isSearchResult ? Container() : descBox, remarkBox, - ExpansionTile( - initiallyExpanded: true, - title: Text( - 'Status', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Container( - padding: EdgeInsets.only(left: 20), - height: 400, - child: Timeline( - children: _models(), - position: TimelinePosition.Left), - ), - ], - ), + StatusTree( + shipmentHistory: _package.shipmentHistory, + currentStatus: _package.currentStatus), SizedBox( height: 20, ) @@ -194,20 +166,4 @@ class _PackageInfoState extends State { ))) .toList(); } - - _gotoEditor() async { - bool deleted = await Navigator.push( - context, - BottomUpPageRoute(PackageEditorPage( - package: widget.package, - ))); - if (deleted ?? false) { - Navigator.pop(context); - } else { - PackageModel packageModel = - Provider.of(context, listen: false); - Package p = await packageModel.getPackage(_package.id); - initPackage(p); - } - } } diff --git a/lib/pages/package/package_list.dart b/lib/pages/package/package_list.dart index b0613e9..8bad4bd 100644 --- a/lib/pages/package/package_list.dart +++ b/lib/pages/package/package_list.dart @@ -1,14 +1,12 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; -import 'package:fcs/pages/main/model/main_model.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/package_new.dart'; import 'package:fcs/pages/package_search/package_serach.dart'; -import 'package:fcs/pages/user_search/user_serach.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.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'; @@ -16,16 +14,29 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class PackageList extends StatefulWidget { + final bool onlyFcs; + + const PackageList({Key key, this.onlyFcs = false}) : super(key: key); @override _PackageListState createState() => _PackageListState(); } class _PackageListState extends State { bool _isLoading = false; + bool _showDelivered = false; + var _controller = ScrollController(); @override void initState() { super.initState(); + Provider.of(context, listen: false).initDeliveredPackages(); + _controller.addListener(() { + if (_showDelivered && + _controller.position.pixels == _controller.position.maxScrollExtent) { + Provider.of(context, listen: false) + .loadMoreDeliveredPackages(); + } + }); } @override @@ -36,7 +47,20 @@ class _PackageListState extends State { @override Widget build(BuildContext context) { var packageModel = Provider.of(context); - bool isCustomer = context.select((MainModel m) => m.isCustomer()); + bool onlyFcs = widget.onlyFcs; + var packages = _showDelivered + ? packageModel.deliveredPackages + : onlyFcs ? packageModel.packages : packageModel.customerPackages; + final popupMenu = LocalPopupMenuButton( + popmenus: [ + LocalPopupMenu( + id: 1, textKey: "package.popupmenu.active", selected: true), + LocalPopupMenu(id: 2, textKey: "package.popupmenu.delivered") + ], + popupMenuCallback: (p) => this.setState(() { + _showDelivered = p.id == 2; + }), + ); return LocalProgress( inAsyncCall: _isLoading, @@ -55,9 +79,8 @@ class _PackageListState extends State { color: Colors.white, ), actions: [ - isCustomer - ? Container() - : IconButton( + onlyFcs + ? IconButton( icon: Icon( Icons.search, color: Colors.white, @@ -65,41 +88,45 @@ class _PackageListState extends State { iconSize: 30, onPressed: () => searchPackage(context, callbackPackageSelect: _searchCallback), - ), + ) + : Container(), + popupMenu ], ), - floatingActionButton: isCustomer - ? Container() - : FloatingActionButton.extended( - onPressed: () { - _newPackage(); - }, - icon: Icon(Icons.add), - label: Text( - AppTranslations.of(context).text("package.create.title")), - backgroundColor: primaryColor, - ), - body: new ListView.separated( - separatorBuilder: (context, index) => Divider( - color: Colors.black, - ), - scrollDirection: Axis.vertical, - padding: EdgeInsets.only(top: 15), - shrinkWrap: true, - itemCount: packageModel.packages.length, - itemBuilder: (BuildContext context, int index) { - return PackageListRow( - key: ValueKey(packageModel.packages[index].id), - package: packageModel.packages[index], - ); - })), - ); - } - - _newPackage() { - Navigator.push( - context, - BottomUpPageRoute(PackageNew()), + body: Column( + children: [ + Expanded( + child: ListView.separated( + controller: _controller, + separatorBuilder: (context, index) => Divider( + color: Colors.black, + ), + scrollDirection: Axis.vertical, + padding: EdgeInsets.only(top: 15), + shrinkWrap: true, + itemCount: packages.length, + itemBuilder: (BuildContext context, int index) { + return PackageListRow( + key: ValueKey(packages[index].id), + package: packages[index], + ); + }), + ), + packageModel.isLoading + ? Container( + padding: EdgeInsets.all(8), + color: primaryColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text("Loading...", + style: TextStyle(color: Colors.white)), + ], + ), + ) + : Container(), + ], + )), ); } diff --git a/lib/pages/processing/processing_editor.dart b/lib/pages/processing/processing_editor.dart index 8cab244..70f38a4 100644 --- a/lib/pages/processing/processing_editor.dart +++ b/lib/pages/processing/processing_editor.dart @@ -1,13 +1,16 @@ import 'package:fcs/domain/entities/market.dart'; import 'package:fcs/domain/entities/package.dart'; +import 'package:fcs/domain/entities/user.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/market/market_editor.dart'; 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/widgets/bottom_up_page_route.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'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/multi_img_controller.dart'; @@ -31,6 +34,7 @@ class _ProcessingEditorState extends State { TextEditingController _descCtl = new TextEditingController(); Package _package; + User _user; bool _isLoading = false; @override @@ -41,6 +45,10 @@ class _ProcessingEditorState extends State { _descCtl.text = _package.desc; _remarkCtl.text = _package.remark; multiImgController.setImageUrls = _package.photoUrls; + _user = User( + fcsID: _package.fcsID ?? "", + name: _package.userName ?? "", + phoneNumber: _package.phoneNumber ?? ""); } final DateFormat dateFormat = DateFormat("d MMM yyyy"); @@ -50,21 +58,39 @@ class _ProcessingEditorState extends State { @override Widget build(BuildContext context) { + var fcsIDBox = Row( + children: [ + Expanded( + child: DisplayText( + text: _user.fcsID, + labelTextKey: "processing.fcs.id", + icon: FcsIDIcon(), + )), + IconButton( + icon: Icon(Icons.search, color: primaryColor), + onPressed: () => searchUser(context, callbackUserSelect: (u) { + setState(() { + this._user = u; + }); + })), + ], + ); + final namebox = DisplayText( + text: _user.name, + labelTextKey: "processing.name", + iconData: Icons.person, + ); + final phoneNumberBox = DisplayText( + text: _user.phoneNumber, + labelTextKey: "processing.phone", + iconData: Icons.phone, + ); + final trackingIdBox = DisplayText( text: _package.trackingID, labelTextKey: "processing.tracking.id", iconData: MaterialCommunityIcons.barcode_scan, ); - final statusBox = DisplayText( - text: _package.currentStatus, - labelTextKey: "processing.status", - iconData: AntDesign.exclamationcircleo, - ); - final customerNameBox = DisplayText( - text: _package.userName, - labelTextKey: "processing.name", - iconData: Icons.perm_identity, - ); final completeProcessingBtn = fcsButton( context, getLocalString(context, 'processing.edit.complete.btn'), @@ -101,44 +127,19 @@ class _ProcessingEditorState extends State { fontSize: 20, color: primaryColor, ), - actions: [ - IconButton( - icon: Icon(Icons.delete, color: primaryColor), - onPressed: _delete, - ) - ], ), body: Padding( padding: const EdgeInsets.all(8.0), child: ListView( children: [ trackingIdBox, - customerNameBox, - statusBox, - Divider(), - Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: LocalText( - context, - "processing.edit.sub_title", - color: primaryColor, - fontSize: 16, - fontWeight: FontWeight.w700, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 18.0, right: 10), - child: Column( - children: [ - marketDropdown(), - descBox, - remarkBox, - img, - ], - ), - ), + fcsIDBox, + namebox, + phoneNumberBox, + marketDropdown(), + descBox, + remarkBox, + img, completeProcessingBtn, SizedBox( height: 20, @@ -159,51 +160,54 @@ class _ProcessingEditorState extends State { markets.insert(0, selectedMarket); } - return Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 18.0), - child: LocalText( - context, - "processing.market", - color: primaryColor, - fontSize: 16, - ), - ), - Container( - width: 150, - child: DropdownButton( - value: selectedMarket, - style: TextStyle(color: Colors.black, fontSize: 14), - underline: Container( - height: 1, - color: Colors.grey, + return Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 18.0), + child: LocalText( + context, + "processing.market", + color: primaryColor, + fontSize: 16, ), - onChanged: (String newValue) { - setState(() { - if (newValue == MANAGE_MARKET) { - selectedMarket = null; - _manageMarket(); - return; - } - selectedMarket = newValue; - }); - }, - isExpanded: true, - items: markets.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value ?? "", - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: value == MANAGE_MARKET - ? secondaryColor - : primaryColor)), - ); - }).toList(), ), - ), - ], + Container( + width: 150, + child: DropdownButton( + value: selectedMarket, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container( + height: 1, + color: Colors.grey, + ), + onChanged: (String newValue) { + setState(() { + if (newValue == MANAGE_MARKET) { + selectedMarket = null; + _manageMarket(); + return; + } + selectedMarket = newValue; + }); + }, + isExpanded: true, + items: markets.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value ?? "", + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: value == MANAGE_MARKET + ? secondaryColor + : primaryColor)), + ); + }).toList(), + ), + ), + ], + ), ); } @@ -219,16 +223,21 @@ class _ProcessingEditorState extends State { showMsgDialog(context, "Error", "Expected some description"); return; } + if (_user.fcsID == null || _user.fcsID == "") { + showMsgDialog(context, "Error", "Expected FCS-ID"); + return; + } setState(() { _isLoading = true; }); PackageModel packageModel = Provider.of(context, listen: false); try { + _package.fcsID = _user.fcsID; _package.desc = _descCtl.text; _package.remark = _remarkCtl.text; _package.market = selectedMarket; - await packageModel.completeProcessing(_package, + await packageModel.updateProcessing(_package, multiImgController.getAddedFile, multiImgController.getDeletedUrl); Navigator.pop(context); } catch (e) { @@ -239,26 +248,4 @@ class _ProcessingEditorState extends State { }); } } - - _delete() { - showConfirmDialog(context, "processing.delete.confirm", _deletePackage); - } - - _deletePackage() async { - setState(() { - _isLoading = true; - }); - PackageModel packageModel = - Provider.of(context, listen: false); - try { - await packageModel.deletePackage(_package); - Navigator.pop(context, true); - } catch (e) { - showMsgDialog(context, "Error", e.toString()); - } finally { - setState(() { - _isLoading = false; - }); - } - } } diff --git a/lib/pages/processing/processing_info.dart b/lib/pages/processing/processing_info.dart index 38e740a..b3783b7 100644 --- a/lib/pages/processing/processing_info.dart +++ b/lib/pages/processing/processing_info.dart @@ -1,6 +1,7 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/pages/main/model/main_model.dart'; +import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/display_text.dart'; @@ -8,6 +9,7 @@ import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/multi_img_controller.dart'; import 'package:fcs/pages/widgets/multi_img_file.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:fcs/pages/widgets/status_tree.dart'; import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; @@ -53,8 +55,6 @@ class _ProcessingInfoState extends State { @override Widget build(BuildContext context) { - bool isCustomer = Provider.of(context).isCustomer(); - final trackingIdBox = DisplayText( text: _package.trackingID, labelTextKey: "processing.tracking.id", @@ -65,11 +65,6 @@ class _ProcessingInfoState extends State { labelTextKey: "processing.name", iconData: Icons.perm_identity, ); - final statusBox = DisplayText( - text: _package.currentStatus, - labelTextKey: "processing.status", - iconData: AntDesign.exclamationcircleo, - ); final marketBox = DisplayText( text: _package.market ?? "-", labelTextKey: "processing.market", @@ -109,12 +104,14 @@ class _ProcessingInfoState extends State { color: primaryColor, ), actions: [ - isCustomer - ? Container() - : IconButton( - icon: Icon(Icons.edit, color: primaryColor), - onPressed: _gotoEditor, - ) + IconButton( + icon: Icon(Icons.delete, color: primaryColor), + onPressed: _delete, + ), + IconButton( + icon: Icon(Icons.edit, color: primaryColor), + onPressed: _gotoEditor, + ), ], ), body: Card( @@ -127,27 +124,12 @@ class _ProcessingInfoState extends State { trackingIdBox, customerNameBox, marketBox, - statusBox, _package.photoUrls.length == 0 ? Container() : img, descBox, remarkBox, - ExpansionTile( - initiallyExpanded: true, - title: Text( - 'Status', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Container( - padding: EdgeInsets.only(left: 20), - height: 400, - child: Timeline( - children: _models(), - position: TimelinePosition.Left), - ), - ], - ), + StatusTree( + shipmentHistory: _package.shipmentHistory, + currentStatus: _package.currentStatus), SizedBox( height: 20, ) @@ -160,36 +142,26 @@ class _ProcessingInfoState extends State { ); } - List _models() { - if (_package.shipmentHistory == null) return []; - return _package.shipmentHistory - .map((e) => TimelineModel( - Padding( - padding: const EdgeInsets.all(18.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(e.status, - style: TextStyle( - color: e.done ? primaryColor : Colors.grey, - fontSize: 16, - fontWeight: FontWeight.bold)), - Text(dateFormat.format(e.date)), - ], - ), - ), - iconBackground: e.done ? primaryColor : Colors.grey, - icon: Icon( - e.status == "shipped" - ? Ionicons.ios_airplane - : e.status == "delivered" - ? MaterialCommunityIcons.truck_fast - : e.status == "processed" - ? MaterialIcons.check - : Octicons.package, - color: Colors.white, - ))) - .toList(); + _delete() { + showConfirmDialog(context, "processing.delete.confirm", _deletePackage); + } + + _deletePackage() async { + setState(() { + _isLoading = true; + }); + PackageModel packageModel = + Provider.of(context, listen: false); + try { + await packageModel.deleteProcessing(_package); + Navigator.pop(context, true); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } } _gotoEditor() async { diff --git a/lib/pages/processing/processing_list.dart b/lib/pages/processing/processing_list.dart index 6e34748..c6e79db 100644 --- a/lib/pages/processing/processing_list.dart +++ b/lib/pages/processing/processing_list.dart @@ -1,10 +1,8 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/package/package_info.dart'; -import 'package:fcs/pages/package/package_new.dart'; import 'package:fcs/pages/package_search/package_serach.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; @@ -13,6 +11,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'processing_info.dart'; import 'processing_list_row.dart'; class ProcessingList extends StatefulWidget { @@ -91,7 +90,7 @@ class _ProcessingListState extends State { if (_package == null) return; Navigator.push( context, - BottomUpPageRoute(PackageInfo(package: _package)), + BottomUpPageRoute(ProcessingInfo(package: _package)), ); } } diff --git a/lib/pages/receiving/receiving_new.dart b/lib/pages/receiving/receiving_editor.dart similarity index 77% rename from lib/pages/receiving/receiving_new.dart rename to lib/pages/receiving/receiving_editor.dart index 0a0af86..f51805a 100644 --- a/lib/pages/receiving/receiving_new.dart +++ b/lib/pages/receiving/receiving_editor.dart @@ -20,22 +20,38 @@ import 'package:provider/provider.dart'; typedef void FindCallBack(); -class ReceivingNew extends StatefulWidget { - const ReceivingNew(); +class ReceivingEditor extends StatefulWidget { + final Package package; + const ReceivingEditor({this.package}); @override - _ReceivingNewState createState() => _ReceivingNewState(); + _ReceivingEditorState createState() => _ReceivingEditorState(); } -class _ReceivingNewState extends State { +class _ReceivingEditorState extends State { + Package package = Package(); bool _isLoading = false; + bool _isNew; User user; - TextEditingController _transcationIDCtl = new TextEditingController(); + TextEditingController _trackingIDCtl = new TextEditingController(); TextEditingController _remarkCtl = new TextEditingController(); MultiImgController _multiImgController = MultiImgController(); @override void initState() { super.initState(); + _isNew = widget.package == null; + if (!_isNew) { + package = widget.package; + _trackingIDCtl.text = package.trackingID; + _remarkCtl.text = package.remark; + _multiImgController.setImageUrls = package.photoUrls; + user = User( + fcsID: package.fcsID, + name: package.userName, + phoneNumber: package.phoneNumber); + } else { + package = new Package(); + } } @override @@ -66,7 +82,7 @@ class _ReceivingNewState extends State { Expanded( child: InputText( labelTextKey: "receiving.tracking.id", - controller: _transcationIDCtl, + controller: _trackingIDCtl, )), IconButton( icon: Icon(MaterialCommunityIcons.barcode_scan, @@ -99,7 +115,13 @@ class _ReceivingNewState extends State { final createButton = fcsButton( context, getLocalString(context, 'receiving.create_btn'), - callack: _create, + callack: _save, + ); + + final updateButton = fcsButton( + context, + getLocalString(context, 'receiving.update_btn'), + callack: _save, ); return LocalProgress( @@ -115,7 +137,7 @@ class _ReceivingNewState extends State { backgroundColor: Colors.white, title: LocalText( context, - "receiving.new", + _isNew ? "receiving.new" : "receiving.update", fontSize: 20, color: primaryColor, ), @@ -139,7 +161,7 @@ class _ReceivingNewState extends State { SizedBox( height: 20, ), - createButton, + _isNew ? createButton : updateButton, SizedBox( height: 10, ), @@ -166,7 +188,7 @@ class _ReceivingNewState extends State { String barcode = await scanBarcode(); if (barcode != null) { setState(() { - _transcationIDCtl.text = barcode; + _trackingIDCtl.text = barcode; }); } } catch (e) { @@ -174,9 +196,8 @@ class _ReceivingNewState extends State { } } - _create() async { - Package package = Package(); - package.trackingID = _transcationIDCtl.text; + _save() async { + package.trackingID = _trackingIDCtl.text; package.remark = _remarkCtl.text; if (package.trackingID == null || package.trackingID == "") { @@ -189,8 +210,17 @@ class _ReceivingNewState extends State { PackageModel packageModel = Provider.of(context, listen: false); try { - await packageModel.createPackage(user, package, - _multiImgController.getAddedFile, _multiImgController.getDeletedUrl); + if (_isNew) { + await packageModel.createReceiving( + user, package, _multiImgController.getAddedFile); + } else { + package.id = widget.package.id; + await packageModel.updateReceiving( + user, + package, + _multiImgController.getAddedFile, + _multiImgController.getDeletedUrl); + } Navigator.pop(context); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/receiving/receiving_info.dart b/lib/pages/receiving/receiving_info.dart index dbaac71..407abcb 100644 --- a/lib/pages/receiving/receiving_info.dart +++ b/lib/pages/receiving/receiving_info.dart @@ -18,6 +18,8 @@ import 'package:provider/provider.dart'; import 'package:timeline_list/timeline.dart'; import 'package:timeline_list/timeline_model.dart'; +import 'receiving_editor.dart'; + final DateFormat dateFormat = DateFormat("d MMM yyyy"); class ReceivingInfo extends StatefulWidget { @@ -40,9 +42,9 @@ class _ReceivingInfoState extends State { } initPackage(Package package) { + multiImgController.setImageUrls = package.photoUrls; setState(() { _package = package; - multiImgController.setImageUrls = package.photoUrls; }); } @@ -89,18 +91,22 @@ class _ReceivingInfoState extends State { backgroundColor: Colors.white, title: LocalText( context, - "package.info.title", + "receiving.info", fontSize: 20, color: primaryColor, ), - actions: [ - isCustomer - ? Container() - : IconButton( + actions: isCustomer + ? null + : [ + IconButton( icon: Icon(Icons.delete, color: primaryColor), onPressed: _delete, + ), + IconButton( + icon: Icon(Icons.edit, color: primaryColor), + onPressed: _edit, ) - ], + ], ), body: Card( child: Column( @@ -113,19 +119,9 @@ class _ReceivingInfoState extends State { _package.userID != null ? customerNameBox : Container(), _package.photoUrls.length == 0 ? Container() : img, remarkBox, - ExpansionTile( - initiallyExpanded: true, - title: Text( - 'Status', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - StatusTree( - shipmentHistory: _package.shipmentHistory, - currentStatus: _package.currentStatus), - ], - ), + StatusTree( + shipmentHistory: _package.shipmentHistory, + currentStatus: _package.currentStatus), SizedBox( height: 20, ) @@ -138,6 +134,19 @@ class _ReceivingInfoState extends State { ); } + _edit() async { + await Navigator.push( + context, + BottomUpPageRoute(ReceivingEditor( + package: widget.package, + )), + ); + PackageModel packageModel = + Provider.of(context, listen: false); + var pkg = await packageModel.getPackage(widget.package.id); + initPackage(pkg); + } + _delete() { showConfirmDialog(context, "receiving.delete.confirm", _deleteReceiving); } @@ -149,7 +158,7 @@ class _ReceivingInfoState extends State { try { PackageModel packageModel = Provider.of(context, listen: false); - await packageModel.deletePackage(_package); + await packageModel.deleteReceiving(_package); Navigator.pop(context); } catch (e) { showMsgDialog(context, "Error", e.toString()); diff --git a/lib/pages/receiving/receiving_list.dart b/lib/pages/receiving/receiving_list.dart index e145d9a..733f04a 100644 --- a/lib/pages/receiving/receiving_list.dart +++ b/lib/pages/receiving/receiving_list.dart @@ -12,7 +12,7 @@ import 'package:provider/provider.dart'; import 'receiving_info.dart'; import 'receiving_list_row.dart'; -import 'receiving_new.dart'; +import 'receiving_editor.dart'; class ReceivingList extends StatefulWidget { @override @@ -98,7 +98,7 @@ class _ReceivingListState extends State { _newReceiving() { Navigator.push( context, - BottomUpPageRoute(ReceivingNew()), + BottomUpPageRoute(ReceivingEditor()), ); } diff --git a/lib/pages/shipment/shipment_list.dart b/lib/pages/shipment/shipment_list.dart index 4df16c0..949f046 100644 --- a/lib/pages/shipment/shipment_list.dart +++ b/lib/pages/shipment/shipment_list.dart @@ -4,6 +4,7 @@ import 'package:fcs/pages/shipment/model/shipment_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/progress.dart'; +import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; import 'package:flutter/material.dart'; @@ -40,7 +41,7 @@ class _ShipmentListState extends State { appBar: AppBar( centerTitle: true, leading: new IconButton( - icon: new Icon(Icons.close), + icon: new Icon(CupertinoIcons.back), onPressed: () => Navigator.of(context).pop(), ), backgroundColor: primaryColor, @@ -72,7 +73,7 @@ class _ShipmentListState extends State { _newPickup(); }, icon: Icon(Icons.add), - label: Text(AppTranslations.of(context).text("shipment.new")), + label: LocalText(context, "shipment.new", color: Colors.white), backgroundColor: primaryColor, ), body: new ListView.separated( diff --git a/lib/pages/widgets/badge.dart b/lib/pages/widgets/badge.dart index be6006e..2018b2f 100644 --- a/lib/pages/widgets/badge.dart +++ b/lib/pages/widgets/badge.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; Widget badgeCounter(Widget child, int counter) { return Container( width: 120, - height: 140, child: new Stack( children: [ child, diff --git a/lib/pages/widgets/local_popup_menu_button.dart b/lib/pages/widgets/local_popup_menu_button.dart new file mode 100644 index 0000000..3132ac5 --- /dev/null +++ b/lib/pages/widgets/local_popup_menu_button.dart @@ -0,0 +1,120 @@ +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/pages/widgets/local_text.dart'; +import 'package:flutter/material.dart'; + +import 'local_popupmenu.dart'; + +typedef PopupMenuCallback = Function(LocalPopupMenu popupMenu); + +class LocalPopupMenuButton extends StatefulWidget { + final PopupMenuCallback popupMenuCallback; + final List popmenus; + final bool multiSelect; + + const LocalPopupMenuButton( + {Key key, + this.popupMenuCallback, + this.popmenus, + this.multiSelect = false}) + : super(key: key); + + @override + _LocalPopupMenuButtonState createState() => _LocalPopupMenuButtonState(); +} + +class _LocalPopupMenuButtonState extends State { + List popmenus; + + @override + void initState() { + popmenus = widget.popmenus; + super.initState(); + } + + @override + Widget build(BuildContext context) { + bool hightlight = _needHighlight(); + return PopupMenuButton( + elevation: 3.2, + onSelected: (selected) { + if (!widget.multiSelect) { + setState(() { + popmenus.forEach((e) { + if (e.id != selected.id) + e.selected = false; + else + e.selected = true; + }); + }); + selected.selected = true; + } else { + setState(() { + popmenus.forEach((e) { + if (e.id == selected.id) e.selected = !e.selected; + }); + }); + selected.selected = !selected.selected; + } + if (widget.popupMenuCallback != null) + widget.popupMenuCallback(selected); + }, + icon: Container( + width: 30, + height: 30, + decoration: new BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + child: Stack( + fit: StackFit.expand, + children: [ + Icon( + Icons.filter_list, + color: primaryColor, + ), + hightlight + ? Positioned( + bottom: 0, + right: 0, + child: Container( + width: 10, + height: 10, + decoration: new BoxDecoration( + shape: BoxShape.circle, + color: secondaryColor, + ), + ), + ) + : Container() + ], + )), + itemBuilder: (BuildContext context) { + return popmenus.map((LocalPopupMenu choice) { + return PopupMenuItem( + value: choice, + child: Row( + children: [ + LocalText(context, choice.textKey, color: primaryColor), + SizedBox( + width: 10, + ), + choice.selected + ? Icon( + Icons.check, + color: Colors.grey, + ) + : Container(), + ], + ), + ); + }).toList(); + }); + } + + bool _needHighlight() { + popmenus.forEach((e) { + if (e.selected && e.highlight) return true; + }); + return false; + } +} diff --git a/lib/pages/widgets/local_popupmenu.dart b/lib/pages/widgets/local_popupmenu.dart new file mode 100644 index 0000000..7029c58 --- /dev/null +++ b/lib/pages/widgets/local_popupmenu.dart @@ -0,0 +1,8 @@ +class LocalPopupMenu { + int id; + String textKey; + bool selected; + bool highlight; + LocalPopupMenu( + {this.id, this.textKey, this.selected = false, this.highlight = false}); +} diff --git a/lib/pages/widgets/popupmenu.dart b/lib/pages/widgets/popupmenu.dart index 7cc6380..c95d348 100644 --- a/lib/pages/widgets/popupmenu.dart +++ b/lib/pages/widgets/popupmenu.dart @@ -1,5 +1,3 @@ -import 'package:flutter/material.dart'; - class PopupMenu { int id; String status; diff --git a/lib/pages/widgets/status_tree.dart b/lib/pages/widgets/status_tree.dart index fb89a54..234cba3 100644 --- a/lib/pages/widgets/status_tree.dart +++ b/lib/pages/widgets/status_tree.dart @@ -19,10 +19,19 @@ class StatusTree extends StatelessWidget { : super(key: key); @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 20), - height: 400, - child: Timeline(children: _models(), position: TimelinePosition.Left), + return ExpansionTile( + initiallyExpanded: true, + title: Text( + 'Status', + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), + ), + children: [ + Container( + padding: EdgeInsets.only(left: 20), + height: 400, + child: Timeline(children: _models(), position: TimelinePosition.Left), + ) + ], ); } diff --git a/lib/pages/widgets/task_button.dart b/lib/pages/widgets/task_button.dart index 07037ce..5ad828c 100644 --- a/lib/pages/widgets/task_button.dart +++ b/lib/pages/widgets/task_button.dart @@ -1,3 +1,4 @@ +import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/main/model/language_model.dart'; import 'package:flutter/material.dart'; @@ -22,7 +23,7 @@ class TaskButton extends StatelessWidget { onTap: btnCallback != null ? btnCallback : () => {}, child: Container( width: 120, - height: 170, + height: 155, padding: EdgeInsets.only(top: 0.0, left: 5, right: 5), decoration: new BoxDecoration( color: Colors.transparent, @@ -42,7 +43,7 @@ class TaskButton extends StatelessWidget { ), ), Container( - height: 60, + height: 45, alignment: Alignment.topCenter, child: Text(AppTranslations.of(context).text(titleKey), textAlign: TextAlign.center, From 2b02806715be42009197a263f6f605b255d4bd9c Mon Sep 17 00:00:00 2001 From: Sai Naw Wun Date: Mon, 12 Oct 2020 08:26:27 +0630 Subject: [PATCH 3/4] add shipment --- assets/local/localization_en.json | 9 +- assets/local/localization_mu.json | 7 +- lib/data/services/auth_imp.dart | 2 +- lib/data/services/auth_service.dart | 2 +- lib/domain/constants.dart | 6 + .../delivery_address_list.dart | 35 +- .../fcs_shipment/fcs_shipment_editor.dart | 4 +- lib/pages/package/model/package_model.dart | 2 + lib/pages/processing/processing_editor.dart | 87 ++- lib/pages/processing/processing_info.dart | 3 - lib/pages/shipment/model/shipment_model.dart | 8 + lib/pages/shipment/pickup_box_editor.dart | 97 ++- lib/pages/shipment/shipment_editor.dart | 731 +++++++----------- lib/pages/shipment/shipment_list_row.dart | 2 +- lib/pages/widgets/input_date.dart | 4 +- lib/pages/widgets/input_text.dart | 4 +- lib/pages/widgets/input_time.dart | 98 +++ pubspec.yaml | 2 +- 18 files changed, 549 insertions(+), 554 deletions(-) create mode 100644 lib/pages/widgets/input_time.dart diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 08d0ae9..1a809ba 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -291,15 +291,20 @@ "Shipment Start ================================================================":"", "shipment": "Shipments", - "shipment.title": "SHIPMENTS", + "shipment.title": "Shipments", "shipment.new": "New Shipment", - "shipment.edit.title": "SHIPMENT", + "shipment.new.title": "New Shipment", + "shipment.edit.title": "Edit Shipment", + "shipment.type": "Pickup/Drop-off", "shipment.date": "Pickup Date", + "shipment.time": "Pickup Time", + "shipment.location": "Pickup Location", "shipment.location_time": "Pickup Location / Time", "shipment.information": "Pickup Informations", "shipment.recipient_information": "Recipient Informations", "shipment.from":"From", "shipment.to":"To", + "shipment.box.delivery":"Delivery Address", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index 6219dbb..79c720f 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -293,13 +293,18 @@ "shipment": "ပို့ဆောင်ခြင်းများ", "shipment.title": "ပို့ဆောင်ခြင်းများ", "shipment.new": "ပို့ဆောင်ခြင်း အသစ်", - "shipment.edit.title": "PICKUP", + "shipment.new.title": "ပို့ဆောင်ခြင်း အသစ်", + "shipment.edit.title": "ပို့ဆောင်ခြင်း ပြင်ဆင်ခြင်း", + "shipment.type": "Pickup/Drop-off", "shipment.date": "Pickup Date", + "shipment.time": "Pickup Time", "shipment.location_time": "Pickup Location / Time", + "shipment.location": "Pickup Location", "shipment.information": "Pickup Informations", "shipment.recipient_information": "Recipient Informations", "shipment.from":"From", "shipment.to":"To", + "shipment.box.delivery":"Delivery Address", "Shipment End ================================================================":"", "Rate Start ================================================================":"", diff --git a/lib/data/services/auth_imp.dart b/lib/data/services/auth_imp.dart index 27d0376..bcf6f06 100644 --- a/lib/data/services/auth_imp.dart +++ b/lib/data/services/auth_imp.dart @@ -47,7 +47,7 @@ class AuthServiceImp implements AuthService { } @override - Future joinInvite(String userName) { + Future joinInvite(String userName) { return authFb.joinInvite(userName); } diff --git a/lib/data/services/auth_service.dart b/lib/data/services/auth_service.dart index 412c498..f97d63e 100644 --- a/lib/data/services/auth_service.dart +++ b/lib/data/services/auth_service.dart @@ -7,7 +7,7 @@ abstract class AuthService { Future signInWithSmsCode(String smsCode); Future signout(); Future signup(String userName); - Future joinInvite(String userName); + Future joinInvite(String userName); Future updateProfileName(String newUserName); Future updatePreferredCurrency(String currency); Future hasInvite(); diff --git a/lib/domain/constants.dart b/lib/domain/constants.dart index 10f6be1..a8d83ca 100644 --- a/lib/domain/constants.dart +++ b/lib/domain/constants.dart @@ -48,3 +48,9 @@ const privilege_delivery = "deli"; const privilege_invoice = "inv"; const privilege_processing = "pr"; const privilege_receiving = "rc"; + +// Pickup types +const shipment_local_pickup = "Local Pickup"; +const shipment_courier_pickup = "Courier Pickup"; +const shipment_local_dropoff = "Local Drop-off"; +const shipment_courier_dropoff = "Courier Drop-off"; diff --git a/lib/pages/delivery_address/delivery_address_list.dart b/lib/pages/delivery_address/delivery_address_list.dart index b2c967d..2d932b9 100644 --- a/lib/pages/delivery_address/delivery_address_list.dart +++ b/lib/pages/delivery_address/delivery_address_list.dart @@ -13,8 +13,11 @@ import 'delivery_address_row.dart'; class DeliveryAddressList extends StatefulWidget { final DeliveryAddress deliveryAddress; + final bool forSelection; - const DeliveryAddressList({Key key, this.deliveryAddress}) : super(key: key); + const DeliveryAddressList( + {Key key, this.deliveryAddress, this.forSelection = false}) + : super(key: key); @override _DeliveryAddressListState createState() => _DeliveryAddressListState(); } @@ -80,15 +83,18 @@ class _DeliveryAddressListState extends State { _row(BuildContext context, DeliveryAddress deliveryAddress) { return Row( children: [ - InkWell( - onTap: () => _select(deliveryAddress), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Icon(Icons.check, - color: - deliveryAddress.isDefault ? primaryColor : Colors.black26), - ), - ), + widget.forSelection + ? Container() + : InkWell( + onTap: () => _select(deliveryAddress), + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Icon(Icons.check, + color: deliveryAddress.isDefault + ? primaryColor + : Colors.black26), + ), + ), Expanded( child: DeliveryAddressRow( key: ValueKey(deliveryAddress.id), @@ -100,6 +106,11 @@ class _DeliveryAddressListState extends State { } _edit(BuildContext context, DeliveryAddress deliveryAddress) { + if (widget.forSelection) { + Navigator.pop(context, deliveryAddress); + return; + } + Navigator.push( context, BottomUpPageRoute( @@ -108,6 +119,10 @@ class _DeliveryAddressListState extends State { } Future _select(DeliveryAddress deliveryAddress) async { + if (widget.forSelection) { + return; + } + if (deliveryAddress.isDefault) { Navigator.pop(context); return; diff --git a/lib/pages/fcs_shipment/fcs_shipment_editor.dart b/lib/pages/fcs_shipment/fcs_shipment_editor.dart index 83083d9..b2d9e8a 100644 --- a/lib/pages/fcs_shipment/fcs_shipment_editor.dart +++ b/lib/pages/fcs_shipment/fcs_shipment_editor.dart @@ -131,7 +131,9 @@ class _FcsShipmentEditorState extends State { enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: primaryColor)), fillColor: Colors.white, - labelStyle: languageModel.isEng ? labelStyle : labelStyleMM, + labelStyle: languageModel.isEng + ? newLabelStyle(color: Colors.black54, fontSize: 20) + : newLabelStyleMM(color: Colors.black54, fontSize: 20), labelText: AppTranslations.of(context) .text('FCSshipment.shipment_type'), icon: Icon(Ionicons.ios_airplane, color: primaryColor)), diff --git a/lib/pages/package/model/package_model.dart b/lib/pages/package/model/package_model.dart index 5411e5c..8d71d4d 100644 --- a/lib/pages/package/model/package_model.dart +++ b/lib/pages/package/model/package_model.dart @@ -173,6 +173,7 @@ class PackageModel extends BaseModel { .collection("$path") .where("tracking_id", isEqualTo: trackingID) .where("has_user_id", isEqualTo: false) + .where("is_deleted", isEqualTo: false) .getDocuments(source: Source.server); if (qsnap.documents.length > 0) { var snap = qsnap.documents[0]; @@ -186,6 +187,7 @@ class PackageModel extends BaseModel { .collection("$path") .where("tracking_id", isEqualTo: trackingID) .where("user_id", isEqualTo: user.id) + .where("is_deleted", isEqualTo: false) .getDocuments(source: Source.server); if (qsnap.documents.length > 0) { var snap = qsnap.documents[0]; diff --git a/lib/pages/processing/processing_editor.dart b/lib/pages/processing/processing_editor.dart index 70f38a4..cdcb374 100644 --- a/lib/pages/processing/processing_editor.dart +++ b/lib/pages/processing/processing_editor.dart @@ -161,49 +161,58 @@ class _ProcessingEditorState extends State { } return Padding( - padding: const EdgeInsets.only(left: 8.0), + padding: const EdgeInsets.only(left: 5.0, right: 0), child: Row( children: [ Padding( - padding: const EdgeInsets.only(right: 18.0), - child: LocalText( - context, - "processing.market", - color: primaryColor, - fontSize: 16, - ), + padding: const EdgeInsets.only(left: 0, right: 10), + child: Icon(Icons.store, color: primaryColor), ), - Container( - width: 150, - child: DropdownButton( - value: selectedMarket, - style: TextStyle(color: Colors.black, fontSize: 14), - underline: Container( - height: 1, - color: Colors.grey, - ), - onChanged: (String newValue) { - setState(() { - if (newValue == MANAGE_MARKET) { - selectedMarket = null; - _manageMarket(); - return; - } - selectedMarket = newValue; - }); - }, - isExpanded: true, - items: markets.map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value ?? "", - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: value == MANAGE_MARKET - ? secondaryColor - : primaryColor)), - ); - }).toList(), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 18.0), + child: LocalText( + context, + "processing.market", + color: Colors.black54, + fontSize: 16, + ), + ), + DropdownButton( + isDense: true, + value: selectedMarket, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container( + height: 1, + color: Colors.grey, + ), + onChanged: (String newValue) { + setState(() { + if (newValue == MANAGE_MARKET) { + selectedMarket = null; + _manageMarket(); + return; + } + selectedMarket = newValue; + }); + }, + isExpanded: true, + items: markets.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value ?? "", + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: value == MANAGE_MARKET + ? secondaryColor + : primaryColor)), + ); + }).toList(), + ), + ], ), ), ], diff --git a/lib/pages/processing/processing_info.dart b/lib/pages/processing/processing_info.dart index b3783b7..f250adb 100644 --- a/lib/pages/processing/processing_info.dart +++ b/lib/pages/processing/processing_info.dart @@ -1,6 +1,5 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/helpers/theme.dart'; -import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/package/model/package_model.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; @@ -14,8 +13,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; -import 'package:timeline_list/timeline.dart'; -import 'package:timeline_list/timeline_model.dart'; import 'processing_editor.dart'; diff --git a/lib/pages/shipment/model/shipment_model.dart b/lib/pages/shipment/model/shipment_model.dart index a49a453..a20558f 100644 --- a/lib/pages/shipment/model/shipment_model.dart +++ b/lib/pages/shipment/model/shipment_model.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/cargo.dart'; import 'package:fcs/domain/entities/pickup.dart'; import 'package:fcs/domain/vo/radio.dart'; @@ -31,6 +32,13 @@ class ShipmentModel extends BaseModel { ), ]; + List pickupTypes = [ + shipment_local_pickup, + shipment_courier_pickup, + shipment_local_dropoff, + shipment_courier_dropoff + ]; + List get radioGroups { List radioGroups = [ RadioGroup( diff --git a/lib/pages/shipment/pickup_box_editor.dart b/lib/pages/shipment/pickup_box_editor.dart index 0d53b96..5ed3b7c 100644 --- a/lib/pages/shipment/pickup_box_editor.dart +++ b/lib/pages/shipment/pickup_box_editor.dart @@ -4,13 +4,16 @@ import 'package:fcs/domain/entities/package.dart'; import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/pages/delivery_address/delivery_address_list.dart'; import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; +import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; +import 'package:fcs/pages/widgets/display_text.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/my_data_table.dart'; import 'package:fcs/pages/widgets/progress.dart'; import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:flutter_icons/flutter_icons.dart'; import 'package:provider/provider.dart'; import '../main/util.dart'; @@ -30,14 +33,14 @@ class _PickupBoxEditorState extends State { bool isNew; bool isMixBox = false; - DeliveryAddress _shippingAddress = new DeliveryAddress(); + DeliveryAddress _deliveryAddress = new DeliveryAddress(); @override void initState() { super.initState(); if (widget.box != null) { _box = widget.box; - _shippingAddress = _box.shippingAddress; + _deliveryAddress = _box.shippingAddress; isNew = false; } else { @@ -55,7 +58,7 @@ class _PickupBoxEditorState extends State { var shipmentModel = Provider.of(context, listen: false); - _shippingAddress = shipmentModel.deliveryAddresses[1]; + _deliveryAddress = shipmentModel.deliveryAddresses[1]; isNew = true; _box = Box( @@ -111,7 +114,7 @@ class _PickupBoxEditorState extends State { fillColor: Colors.white, labelText: 'Actual Weight', filled: true, - icon: Icon(FontAwesomeIcons.weightHanging, + icon: Icon(MaterialCommunityIcons.weight, color: primaryColor), )), ), @@ -170,7 +173,7 @@ class _PickupBoxEditorState extends State { Padding( padding: const EdgeInsets.only(left: 20.0, right: 20), child: fcsInputReadOnly( - "Shipment Weight", FontAwesomeIcons.weightHanging, + "Shipment Weight", MaterialCommunityIcons.weight, value: _box.shipmentWeight.toString()), ), Padding( @@ -182,7 +185,7 @@ class _PickupBoxEditorState extends State { fillColor: Colors.white, labelText: 'Width', filled: true, - icon: Icon(FontAwesomeIcons.arrowCircleRight, + icon: Icon(FontAwesome.arrow_circle_right, color: primaryColor), )), ), @@ -195,7 +198,7 @@ class _PickupBoxEditorState extends State { fillColor: Colors.white, labelText: 'Height', filled: true, - icon: Icon(FontAwesomeIcons.arrowAltCircleUp, + icon: Icon(FontAwesome.arrow_circle_up, color: primaryColor), )), ), @@ -208,46 +211,14 @@ class _PickupBoxEditorState extends State { fillColor: Colors.white, labelText: 'Length', filled: true, - icon: Icon(FontAwesomeIcons.arrowCircleUp, + icon: Icon(FontAwesome.arrow_circle_left, color: primaryColor), )), ), SizedBox(height: 25), ], ), - ExpansionTile( - title: Text( - 'Shipment Address', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - DeliveryAddressRow(deliveryAddress: _shippingAddress), - Container( - padding: - EdgeInsets.only(top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.bottomRight, - child: Container( - width: 120, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - onPressed: () {}, - icon: Icon(Icons.add), - label: Text( - 'Select\nAddress', - style: TextStyle(fontSize: 12), - ), - backgroundColor: primaryColor, - ), - ), - ), - ), - SizedBox(height: 25), - ], - ), + makeLocation(context, _deliveryAddress), ], ), ), @@ -292,6 +263,48 @@ class _PickupBoxEditorState extends State { ); } + Widget makeLocation(BuildContext context, DeliveryAddress deliveryAddress) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: DisplayText( + labelTextKey: "shipment.box.delivery", + iconData: MaterialCommunityIcons.truck_fast, + ), + ), + Chip( + label: InkWell( + onTap: () async { + DeliveryAddress d = await Navigator.push( + context, + BottomUpPageRoute(DeliveryAddressList( + forSelection: true, + )), + ); + setState(() { + this._deliveryAddress = d; + }); + }, + child: LocalText(context, "delivery_address.change_address", + color: primaryColor), + )) + ], + ), + Padding( + padding: const EdgeInsets.only(left: 28.0), + child: deliveryAddress == null + ? Container() + : DeliveryAddressRow( + key: ValueKey(deliveryAddress.id), + deliveryAddress: deliveryAddress), + ), + ], + ); + } + List getCargoRows(BuildContext context) { if (_box == null || _box.cargoTypes == null) { return []; diff --git a/lib/pages/shipment/shipment_editor.dart b/lib/pages/shipment/shipment_editor.dart index bc412b9..36c94f3 100644 --- a/lib/pages/shipment/shipment_editor.dart +++ b/lib/pages/shipment/shipment_editor.dart @@ -1,3 +1,4 @@ +import 'package:fcs/domain/constants.dart'; import 'package:fcs/domain/entities/box.dart'; import 'package:fcs/domain/entities/cargo.dart'; import 'package:fcs/domain/entities/pickup.dart'; @@ -5,13 +6,17 @@ import 'package:fcs/domain/vo/delivery_address.dart'; import 'package:fcs/helpers/theme.dart'; import 'package:fcs/localization/app_translations.dart'; import 'package:fcs/pages/box/model/box_model.dart'; +import 'package:fcs/pages/delivery_address/delivery_address_list.dart'; import 'package:fcs/pages/delivery_address/delivery_address_row.dart'; import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart'; import 'package:fcs/pages/main/model/main_model.dart'; import 'package:fcs/pages/shipment/model/shipment_model.dart'; import 'package:fcs/pages/main/util.dart'; import 'package:fcs/pages/widgets/bottom_up_page_route.dart'; +import 'package:fcs/pages/widgets/display_text.dart'; +import 'package:fcs/pages/widgets/input_date.dart'; import 'package:fcs/pages/widgets/input_text.dart'; +import 'package:fcs/pages/widgets/input_time.dart'; import 'package:fcs/pages/widgets/local_text.dart'; import 'package:fcs/pages/widgets/multi_img_controller.dart'; import 'package:fcs/pages/widgets/multi_img_file.dart'; @@ -27,8 +32,8 @@ import 'package:flutter/material.dart'; import 'pickup_box_editor.dart'; class ShipmentEditor extends StatefulWidget { - final Shipment pickUp; - ShipmentEditor({this.pickUp}); + final Shipment shipment; + ShipmentEditor({this.shipment}); @override _ShipmentEditorState createState() => _ShipmentEditorState(); @@ -58,17 +63,20 @@ class _ShipmentEditorState extends State { Shipment _pickUp; bool _isLoading = false; var now = new DateTime.now(); - bool isNew; - DeliveryAddress _shippingAddress = new DeliveryAddress(); + bool _isNew; + DeliveryAddress _pickupAddress = new DeliveryAddress(); int _currVal = 1; + String selectedPickupType; @override void initState() { super.initState(); - if (widget.pickUp != null) { - isNew = false; - _pickUp = widget.pickUp; + selectedPickupType = shipment_local_pickup; + + if (widget.shipment != null) { + _isNew = false; + _pickUp = widget.shipment; _addressEditingController.text = _pickUp.address; _fromTimeEditingController.text = _pickUp.fromTime; _toTimeEditingController.text = _pickUp.toTime; @@ -84,7 +92,7 @@ class _ShipmentEditorState extends State { // _recipientAddressEditingController.text = // mainModel.recipient.shippingAddress; } else { - isNew = true; + _isNew = true; List _cargoTypes = [ Cargo(type: 'General Cargo', weight: 25), Cargo(type: 'Medicine', weight: 20), @@ -94,7 +102,7 @@ class _ShipmentEditorState extends State { } var shipmentModel = Provider.of(context, listen: false); - _shippingAddress = shipmentModel.deliveryAddresses[1]; + _pickupAddress = shipmentModel.defalutAddress; } @override @@ -104,17 +112,13 @@ class _ShipmentEditorState extends State { @override Widget build(BuildContext context) { - var pickupModel = Provider.of(context); - - final fromTimeBox = InputText( + final fromTimeBox = InputTime( labelTextKey: 'shipment.from', iconData: Icons.timer, controller: _fromTimeEditingController); - final toTimeBox = InputText( - labelTextKey: 'shipment.to', - iconData: null, - controller: _toTimeEditingController); + final toTimeBox = InputTime( + labelTextKey: 'shipment.to', controller: _toTimeEditingController); final fromTimeBoxReadOnly = fcsInputReadOnly( 'From', @@ -128,25 +132,23 @@ class _ShipmentEditorState extends State { controller: _toTimeEditingController, ); - final pickupTime = Padding( - padding: const EdgeInsets.only(left: 20.0), - child: Row( - children: [ - Container( - child: fromTimeBox, - width: 120, - ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text('-'), - ), - Container( - padding: EdgeInsets.only(left: 20), - child: toTimeBox, - width: 120, - ), - ], - ), + final pickupTimeBox = Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + child: fromTimeBox, + width: 120, + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text('-'), + ), + Container( + padding: EdgeInsets.only(left: 20), + child: toTimeBox, + width: 120, + ), + ], ); final pickupTimeReadOnly = Padding( @@ -170,54 +172,6 @@ class _ShipmentEditorState extends State { ), ); - final noOfPackageBoxReadonly = fcsInputReadOnly( - 'Number of Packages', - Octicons.package, - controller: _noOfPackageEditingController, - ); - - final requestDateBox = Container( - child: InkWell( - onTap: () { - DatePicker.showDatePicker( - context, - showTitleActions: true, - currentTime: _pickupDate.text == "" - ? null - : dateFormatter.parse(_pickupDate.text), - minTime: DateTime.now(), - maxTime: DateTime(2030, 12, 31), - onConfirm: (date) {}, - locale: LocaleType.en, - ); - }, - child: TextFormField( - controller: _pickupDate, - autofocus: false, - cursorColor: primaryColor, - style: textStyle, - enabled: false, - keyboardType: TextInputType.datetime, - decoration: new InputDecoration( - border: InputBorder.none, - focusedBorder: InputBorder.none, - labelText: AppTranslations.of(context).text("shipment.date"), - // labelStyle: languageModel.isEng ? labelStyle : labelStyleMM, - contentPadding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0), - icon: Icon( - Icons.date_range, - color: primaryColor, - )), - validator: (value) { - if (value.isEmpty) { - return AppTranslations.of(context).text("do.form.date"); - } - return null; - }, - ), - )); - MainModel mainModel = Provider.of(context); var boxModel = Provider.of(context); @@ -230,386 +184,165 @@ class _ShipmentEditorState extends State { icon: new Icon(Icons.close), onPressed: () => Navigator.of(context).pop(), ), - backgroundColor: primaryColor, - title: LocalText(context, "shipment.edit.title", - fontSize: 18, color: Colors.white), + shadowColor: Colors.transparent, + backgroundColor: Colors.white, + title: LocalText( + context, + _isNew ? "shipment.new.title" : "shipment.edit.title", + fontSize: 20, + color: primaryColor, + ), ), - body: Card( - child: Column( + body: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.all(10.0), - child: ListView(children: [ - Center(child: nameWidget("mainModel.customer.name")), - Center(child: nameWidget("mainModel.customer.phoneNumber")), - isNew - ? Container() - : Center( - child: Padding( - padding: const EdgeInsets.only(left: 10.0, top: 8), - child: Text( - '#P200304', - style: TextStyle( - color: Colors.black87, - fontSize: 14, - fontWeight: FontWeight.bold), - ), - ), - ), - widget.pickUp == null - ? Container() - : widget.pickUp.isCourier - ? Padding( - padding: const EdgeInsets.only(left: 15.0), - child: fcsInputReadOnly( - "Handling Fee/Courier Fee", - FontAwesomeIcons.moneyBill, - controller: _handlingFeeController), - ) - : Padding( - padding: const EdgeInsets.only(left: 15.0), - child: fcsInputReadOnly( - "Handling Fee/Courier Fee", - FontAwesomeIcons.moneyBill, - controller: _handlingFeeController), - ), - - ExpansionTile( - title: Text( - 'Pickup/Drop-off', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Container( - child: Wrap( - children: pickupModel.radioGroups - .map((t) => RadioListTile( - title: Text("${t.text}"), - groupValue: _currVal, - activeColor: primaryColor, - value: t.index, - onChanged: (val) { - setState(() { - _currVal = val; - }); - }, - )) - .toList(), + _isNew + ? Container() + : Center( + child: Padding( + padding: const EdgeInsets.only(left: 10.0, top: 8), + child: Text( + '#P200304', + style: TextStyle( + color: Colors.black87, + fontSize: 14, + fontWeight: FontWeight.bold), ), ), - ], - ), - _currVal == 3 - ? Container( - child: DeliveryAddressRow( - deliveryAddress: DeliveryAddress( - fullName: 'FCS Office', - addressLine1: '154-19 64th Ave.', - addressLine2: 'Flushing', - city: 'NY', - state: 'NY', - phoneNumber: '+1 (292)215-2247'), - ), + ), + widget.shipment == null + ? Container() + : widget.shipment.isCourier + ? Padding( + padding: const EdgeInsets.only(left: 15.0), + child: fcsInputReadOnly("Handling Fee/Courier Fee", + FontAwesomeIcons.moneyBill, + controller: _handlingFeeController), ) - : _currVal == 4 - ? Container( - child: Column( - children: [ - Container( - padding: EdgeInsets.only( - top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.center, - child: Container( - width: 350, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - onPressed: () {}, - icon: Icon(Icons.arrow_right), - label: Text( - 'Visit courier websie for nearest drop-off', - style: TextStyle(fontSize: 12), - ), - backgroundColor: primaryColor, - ), + : Padding( + padding: const EdgeInsets.only(left: 15.0), + child: fcsInputReadOnly("Handling Fee/Courier Fee", + FontAwesomeIcons.moneyBill, + controller: _handlingFeeController), + ), + makeDropdown(), + makeLocation(context, _pickupAddress), + InputDate( + labelTextKey: "shipment.date", + iconData: Icons.date_range, + controller: _pickupDate, + ), + pickupTimeBox, + _currVal == 3 + ? Container( + child: DeliveryAddressRow( + deliveryAddress: DeliveryAddress( + fullName: 'FCS Office', + addressLine1: '154-19 64th Ave.', + addressLine2: 'Flushing', + city: 'NY', + state: 'NY', + phoneNumber: '+1 (292)215-2247'), + ), + ) + : _currVal == 4 + ? Container( + child: Column( + children: [ + Container( + padding: EdgeInsets.only( + top: 20, bottom: 15, right: 15), + child: Align( + alignment: Alignment.center, + child: Container( + width: 350, + height: 40, + child: FloatingActionButton.extended( + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + onPressed: () {}, + icon: Icon(Icons.arrow_right), + label: Text( + 'Visit courier websie for nearest drop-off', + style: TextStyle(fontSize: 12), ), + backgroundColor: primaryColor, ), ), - ], - )) - : Container(), - - ExpansionTile( - title: Text( - 'Package Information', + ), + ), + ], + )) + : Container(), + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Text( + 'Boxes', style: TextStyle( color: primaryColor, fontWeight: FontWeight.bold), ), - children: [ - Column( - children: getBoxList(context, boxModel.boxes), - ), - Container( - padding: - EdgeInsets.only(top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.bottomRight, - child: Container( - width: 120, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - icon: Icon(Icons.add), - onPressed: () { - Navigator.push( - context, - BottomUpPageRoute(PickupBoxEditor()), - ); - }, - label: Text( - 'Add Package', - style: TextStyle(fontSize: 12), + Spacer(), + IconButton( + onPressed: () { + Navigator.push( + context, + BottomUpPageRoute(PickupBoxEditor()), + ); + }, + icon: Icon( + Icons.add, + color: primaryColor, + )) + ], + ), + ), + Column( + children: getBoxList(context, boxModel.boxes), + ), + mainModel.isCustomer() || _isNew + ? Container() + : ExpansionTile( + title: Text('For FCS'), + children: [ + widget.shipment != null + ? widget.shipment.status == 'Pending' + ? Padding( + padding: const EdgeInsets.only(left: 20.0), + child: fcsDropDown("Assigned", + MaterialCommunityIcons.worker), + ) + : Container() + : Container(), + Padding( + padding: EdgeInsets.only(left: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only(top: 8), + child: Text( + 'Attach Courier Shiping Labels', + style: TextStyle( + color: Colors.black, fontSize: 16), + ), ), - backgroundColor: primaryColor, - ), + Container( + padding: EdgeInsets.only(left: 10), + child: MultiImageFile( + enabled: true, + controller: multiImgController, + title: "Receipt File", + )), + ], ), ), - ), - SizedBox(height: 10.0), - ], - ), - _currVal == 3 || _currVal == 4 - ? Container() - : ExpansionTile( - title: Text( - 'Pickup Location / Time', - style: TextStyle( - color: primaryColor, - fontWeight: FontWeight.bold), - ), - children: [ - Padding( - padding: const EdgeInsets.only(left: 20.0), - child: Column( - children: [ - Row( - children: [ - Icon( - Icons.location_on, - color: primaryColor, - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text('Pickup Address'), - ), - ], - ), - Padding( - padding: const EdgeInsets.only(left: 10.0), - child: DeliveryAddressRow( - deliveryAddress: _shippingAddress), - ), - Container( - padding: EdgeInsets.only( - top: 20, bottom: 15, right: 15), - child: Align( - alignment: Alignment.bottomRight, - child: Container( - width: 120, - height: 40, - child: FloatingActionButton.extended( - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - onPressed: () {}, - icon: Icon(Icons.add), - label: Text( - 'Select\nAddress', - style: TextStyle(fontSize: 12), - ), - backgroundColor: primaryColor, - ), - ), - ), - ), - ], - ), - // child: ExpansionTile( - // leading: Icon( - // Icons.location_on, - // color: primaryColor, - // ), - // title: Text('My Address'), - // children: [ - // Padding( - // padding: const EdgeInsets.only(left: 10.0), - // child: ShippingAddressRow( - // shippingAddress: _shippingAddress), - // ), - // Container( - // padding: EdgeInsets.only( - // top: 20, bottom: 15, right: 15), - // child: Align( - // alignment: Alignment.bottomRight, - // child: Container( - // width: 120, - // height: 40, - // child: FloatingActionButton.extended( - // materialTapTargetSize: - // MaterialTapTargetSize.shrinkWrap, - // onPressed: () {}, - // icon: Icon(Icons.add), - // label: Text( - // 'Select\nAddress', - // style: TextStyle(fontSize: 12), - // ), - // backgroundColor: primaryColor, - // ), - // ), - // ), - // ), - // ], - // ), - ), - widget.pickUp == null - ? pickupTime - : widget.pickUp.status == 'Pending' - ? pickupTime - : pickupTimeReadOnly, - Padding( - padding: const EdgeInsets.only(left: 20.0), - child: Column( - children: [ - SizedBox(height: 5), - Container(height: 50.0, child: requestDateBox) - ], - ), - ), - SizedBox(height: 15.0), - ], - ), - // ExpansionTile( - // title: Text( - // 'Package Information', - // style: TextStyle( - // color: primaryColor, fontWeight: FontWeight.bold), - // ), - // children: [ - // Padding( - // padding: const EdgeInsets.only(left: 20.0), - // child: widget.pickUp == null - // ? noOfPackageBox - // : widget.pickUp.status == 'Pending' - // ? noOfPackageBox - // : noOfPackageBoxReadonly, - // ), - // Padding( - // padding: const EdgeInsets.only(left: 20.0), - // child: widget.pickUp == null - // ? fcsInput("Total Weight (lb)", - // FontAwesomeIcons.weightHanging, - // controller: _weightEditingController) - // : widget.pickUp.status == 'Pending' - // ? fcsInput("Total Weight (lb)", - // FontAwesomeIcons.weightHanging, - // controller: _weightEditingController) - // : fcsInputReadOnly("Total Weight (lb)", - // FontAwesomeIcons.weightHanging, - // controller: _weightEditingController), - // ), - // Padding( - // padding: const EdgeInsets.only(left: 20.0), - // child: fcsInput("Remark", MaterialCommunityIcons.note), - // ), - // Padding( - // padding: const EdgeInsets.only(left: 3.0), - // child: ExpansionTile( - // leading: Icon( - // SimpleLineIcons.location_pin, - // color: primaryColor, - // ), - // title: Text( - // 'Shipping Address', - // ), - // children: [ - // ShippingAddressRow( - // shippingAddress: _shippingAddress), - // Container( - // padding: EdgeInsets.only( - // top: 20, bottom: 15, right: 15), - // child: Align( - // alignment: Alignment.bottomRight, - // child: Container( - // width: 130, - // height: 40, - // child: FloatingActionButton.extended( - // materialTapTargetSize: - // MaterialTapTargetSize.shrinkWrap, - // onPressed: () {}, - // icon: Icon(Icons.add), - // label: Text( - // 'Add Shipping\nAddress', - // style: TextStyle(fontSize: 12), - // ), - // backgroundColor: primaryColor, - // ), - // ), - // ), - // ), - // ], - // ), - // ), - // SizedBox(height: 10.0), - // ], - // ), - mainModel.isCustomer() - ? Container() - : ExpansionTile( - title: Text('For FCS'), - children: [ - widget.pickUp != null - ? widget.pickUp.status == 'Pending' - ? Padding( - padding: - const EdgeInsets.only(left: 20.0), - child: fcsDropDown("Assigned", - MaterialCommunityIcons.worker), - ) - : Container() - : Container(), - Padding( - padding: EdgeInsets.only(left: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.only(top: 8), - child: Text( - 'Attach Courier Shiping Labels', - style: TextStyle( - color: Colors.black, fontSize: 16), - ), - ), - Container( - padding: EdgeInsets.only(left: 10), - child: MultiImageFile( - enabled: true, - controller: multiImgController, - title: "Receipt File", - )), - ], - ), - ), - ], - ), - ]), - )), - widget.pickUp == null + ], + ), + widget.shipment == null ? Align( alignment: Alignment.bottomCenter, child: Center( @@ -627,7 +360,7 @@ class _ShipmentEditorState extends State { : Container( child: Column( children: [ - widget.pickUp.status == 'Confirmed' + widget.shipment.status == 'Confirmed' ? Align( alignment: Alignment.bottomCenter, child: Center( @@ -679,6 +412,104 @@ class _ShipmentEditorState extends State { ); } + Widget makeDropdown() { + ShipmentModel pickupModel = Provider.of(context); + + return Padding( + padding: const EdgeInsets.only(left: 5.0, right: 0), + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(left: 0, right: 10), + child: Icon(SimpleLineIcons.direction, color: primaryColor), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(right: 18.0), + child: LocalText( + context, + "shipment.type", + color: Colors.black54, + fontSize: 16, + ), + ), + DropdownButton( + isDense: true, + value: selectedPickupType, + style: TextStyle(color: Colors.black, fontSize: 14), + underline: Container( + height: 1, + color: Colors.grey, + ), + onChanged: (String newValue) { + setState(() { + selectedPickupType = newValue; + }); + }, + isExpanded: true, + items: pickupModel.pickupTypes + .map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value ?? "", + overflow: TextOverflow.ellipsis, + style: TextStyle(color: primaryColor)), + ); + }).toList(), + ), + ], + ), + ), + ], + ), + ); + } + + Widget makeLocation(BuildContext context, DeliveryAddress deliveryAddress) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: DisplayText( + labelTextKey: "shipment.location", + iconData: MaterialCommunityIcons.truck_fast, + ), + ), + Chip( + label: InkWell( + onTap: () async { + DeliveryAddress d = await Navigator.push( + context, + BottomUpPageRoute(DeliveryAddressList( + forSelection: true, + )), + ); + setState(() { + this._pickupAddress = d; + }); + }, + child: LocalText(context, "delivery_address.change_address", + color: primaryColor), + )) + ], + ), + Padding( + padding: const EdgeInsets.only(left: 28.0), + child: deliveryAddress == null + ? Container() + : DeliveryAddressRow( + key: ValueKey(deliveryAddress.id), + deliveryAddress: deliveryAddress), + ), + ], + ); + } + List getBoxList(BuildContext context, List boxes) { List _boxes = [boxes[0], boxes[1]]; diff --git a/lib/pages/shipment/shipment_list_row.dart b/lib/pages/shipment/shipment_list_row.dart index d8c08f0..0a0046c 100644 --- a/lib/pages/shipment/shipment_list_row.dart +++ b/lib/pages/shipment/shipment_list_row.dart @@ -41,7 +41,7 @@ class _ShipmentListRowState extends State { child: InkWell( onTap: () { Navigator.of(context) - .push(BottomUpPageRoute(ShipmentEditor(pickUp: _pickUp))); + .push(BottomUpPageRoute(ShipmentEditor(shipment: _pickUp))); }, child: Row( children: [ diff --git a/lib/pages/widgets/input_date.dart b/lib/pages/widgets/input_date.dart index f9ac184..c490584 100644 --- a/lib/pages/widgets/input_date.dart +++ b/lib/pages/widgets/input_date.dart @@ -73,7 +73,9 @@ class InputDate extends StatelessWidget { labelText: labelTextKey == null ? null : AppTranslations.of(context).text(labelTextKey), - labelStyle: languageModel.isEng ? labelStyle : labelStyleMM, + labelStyle: languageModel.isEng + ? newLabelStyle(color: Colors.black54, fontSize: 20) + : newLabelStyleMM(color: Colors.black54, fontSize: 20), icon: iconData == null ? null : Icon( diff --git a/lib/pages/widgets/input_text.dart b/lib/pages/widgets/input_text.dart index ac5e81c..b0bd81a 100644 --- a/lib/pages/widgets/input_text.dart +++ b/lib/pages/widgets/input_text.dart @@ -49,7 +49,9 @@ class InputText extends StatelessWidget { labelText: labelTextKey == null ? null : AppTranslations.of(context).text(labelTextKey), - labelStyle: languageModel.isEng ? labelStyle : labelStyleMM, + labelStyle: languageModel.isEng + ? newLabelStyle(color: Colors.black54, fontSize: 20) + : newLabelStyleMM(color: Colors.black54, fontSize: 20), icon: iconData == null ? null : Icon( diff --git a/lib/pages/widgets/input_time.dart b/lib/pages/widgets/input_time.dart new file mode 100644 index 0000000..06f65ae --- /dev/null +++ b/lib/pages/widgets/input_time.dart @@ -0,0 +1,98 @@ +import 'package:fcs/helpers/theme.dart'; +import 'package:fcs/localization/app_translations.dart'; +import 'package:fcs/pages/main/model/language_model.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class InputTime extends StatelessWidget { + final String labelTextKey; + final IconData iconData; + final TextEditingController controller; + final FormFieldValidator validator; + final int maxLines; + final bool withBorder; + final Color borderColor; + final TextInputType textInputType; + final bool autoFocus; + + const InputTime( + {Key key, + this.labelTextKey, + this.iconData, + this.controller, + this.validator, + this.maxLines = 1, + this.withBorder = false, + this.borderColor, + this.autoFocus = false, + this.textInputType}) + : super(key: key); + + @override + Widget build(BuildContext context) { + var languageModel = Provider.of(context); + + return Padding( + padding: const EdgeInsets.only(top: 15.0, bottom: 5), + child: TextFormField( + readOnly: true, + onTap: () async { + FocusScope.of(context).unfocus(); + var initialDate = TimeOfDay.now(); + if (controller != null) { + try { + var values = controller.text.split(":"); + initialDate = TimeOfDay( + hour: int.parse(values[0]), minute: int.parse(values[1])); + } catch (e) {} // ignore error + } + + var t = await showTimePicker( + initialTime: initialDate, + context: context, + ); + if (t != null && controller != null) { + controller.text = "${t.hour} : ${t.minute}"; + } + }, + controller: controller, + autofocus: autoFocus, + cursorColor: primaryColor, + style: textStyle, + maxLines: maxLines, + keyboardType: textInputType, + decoration: new InputDecoration( + // hintText: '', + hintStyle: TextStyle( + height: 1.5, + ), + labelText: labelTextKey == null + ? null + : AppTranslations.of(context).text(labelTextKey), + labelStyle: languageModel.isEng + ? newLabelStyle(color: Colors.black54, fontSize: 20) + : newLabelStyleMM(color: Colors.black54, fontSize: 20), + icon: iconData == null + ? null + : Icon( + iconData, + color: primaryColor, + ), + enabledBorder: withBorder + ? OutlineInputBorder( + borderSide: BorderSide(color: primaryColor, width: 1.0), + ) + : UnderlineInputBorder( + borderSide: BorderSide(color: primaryColor, width: 1.0)), + focusedBorder: withBorder + ? OutlineInputBorder( + borderSide: BorderSide(color: primaryColor, width: 1.0), + ) + : UnderlineInputBorder( + borderSide: BorderSide(color: primaryColor, width: 1.0)), + ), + validator: validator), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 02707c8..350d597 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: fcs description: FCS Logistics publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0+1 +version: 1.0.0+2 environment: sdk: ">=2.7.0 <3.0.0" From ea1f38437088e9455302f142eaa3cb40cbb69457 Mon Sep 17 00:00:00 2001 From: Sai Naw Wun Date: Mon, 12 Oct 2020 09:00:22 +0630 Subject: [PATCH 4/4] fix staff mode sharepref --- lib/pages/main/home_page.dart | 3 ++- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pages/main/home_page.dart b/lib/pages/main/home_page.dart index d0d18fa..e204808 100644 --- a/lib/pages/main/home_page.dart +++ b/lib/pages/main/home_page.dart @@ -90,7 +90,7 @@ class _HomePageState extends State { if (isCustomer) { isFcs[0] = false; } else { - isFcs[0] = staffMode; + isFcs[0] = staffMode ?? false; } }); } @@ -341,6 +341,7 @@ class _HomePageState extends State { final fcsToggle = ToggleButtons( selectedColor: Colors.white, + color: Colors.blue, children: [ Icon(MaterialCommunityIcons.worker), ], diff --git a/pubspec.yaml b/pubspec.yaml index 350d597..433121e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: fcs description: FCS Logistics publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0+2 +version: 1.0.0+3 environment: sdk: ">=2.7.0 <3.0.0"