diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 9efe1ba..80715cb 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -43,6 +43,9 @@ "faq.edit.answer":"Answer", "faq.edit.sn":"S/N", "faq.edit.delete.confirm":"Delete this FAQ?", + "faq.edit.page":"Additional Page", + "faq.edit.page.label.eng":"Page label in English", + "faq.edit.page.label.mm":"Page label in Myanmar", "language.selection.title":"Please select your language", @@ -104,6 +107,7 @@ "package.tracking.id":"Tracking ID", "package.create.packages":"Complete receiving", "package.create.market":"Market", + "package.delete.confirm":"Delete this package?", "package.edit.status":"Status", "package.edit.title":"Edit Package", diff --git a/assets/local/localization_mu.json b/assets/local/localization_mu.json index a6ded82..4a10b67 100644 --- a/assets/local/localization_mu.json +++ b/assets/local/localization_mu.json @@ -43,6 +43,10 @@ "faq.edit.answer":"အဖြေ", "faq.edit.sn":"S/N", "faq.edit.delete.confirm":"Delete this FAQ?", + "faq.edit.page":"Additional Page", + "faq.edit.page.label":"Page label", + "faq.edit.page.label.eng":"Page label in English", + "faq.edit.page.label.mm":"Page label in Myanmar", "language.selection.title":"ဘာသာစကား ရွေးချယ်ပါ", @@ -105,6 +109,7 @@ "package.tracking.id":"Tracking ID", "package.create.packages":"အထုပ် အသစ်များ လက်ခံမည်", "package.create.market":"အွန်လိုင်စျေးဆိုင်", + "package.delete.confirm":"အထုပ်ကို ဖျက်မလား?", "package.edit.title":"အထုပ် ပြင်ဆင်ခြင်း", "package.edit.remark":"မှတ်ချက်", diff --git a/lib/fcs/common/data/providers/package_data_provider.dart b/lib/fcs/common/data/providers/package_data_provider.dart index 90a7e01..768cb14 100644 --- a/lib/fcs/common/data/providers/package_data_provider.dart +++ b/lib/fcs/common/data/providers/package_data_provider.dart @@ -1,3 +1,7 @@ +import 'dart:convert'; + +import 'package:fcs/config.dart'; +import 'package:fcs/fcs/common/domain/constants.dart'; import 'package:fcs/fcs/common/domain/entities/package.dart'; import 'package:fcs/fcs/common/helpers/api_helper.dart'; import 'package:fcs/fcs/common/helpers/firebase_helper.dart'; @@ -11,4 +15,38 @@ class PackageDataProvider { return await requestAPI("/packages", "POST", payload: {"packages": json, "fcs_id": fcsID}, token: await getToken()); } + + Future deletePackage(Package package) async { + return await requestAPI("/packages", "DELETE", + payload: {"id": package.id}, token: await getToken()); + } + + Future> searchPackage(String term) async { + if (term == null || term == '') return List(); + + var bytes = utf8.encode(term); + var base64Str = base64.encode(bytes); + HtmlEscape htmlEscape = const HtmlEscape(); + String escapePackage = htmlEscape.convert(base64Str); + + int limit = 20; + List packages = []; + + try { + var data = await requestAPI( + "/api/fts/$packages_collection/$escapePackage/$limit", "GET", + url: Config.instance.reportURL, token: await getToken()); + + if (data == null) return List(); + + data.forEach((p) { + var package = Package.fromJson(p); + packages.add(package); + }); + } catch (e) { + log.warning("buyer error:" + e.toString()); + return null; + } + return packages; + } } diff --git a/lib/fcs/common/domain/constants.dart b/lib/fcs/common/domain/constants.dart index bd66e68..defa7b7 100644 --- a/lib/fcs/common/domain/constants.dart +++ b/lib/fcs/common/domain/constants.dart @@ -11,6 +11,11 @@ const user_invited_status = "invited"; const pkg_files_path = "/packages"; +// Link page +const page_payment_methods = "payment_methods"; +const page_buying_instructions = "buying_instructions"; +////////////////////////////// + const ok_doc_id = "ok"; const biz_collection = "bizs"; diff --git a/lib/fcs/common/domain/entities/faq.dart b/lib/fcs/common/domain/entities/faq.dart index 1c92074..fe20f07 100644 --- a/lib/fcs/common/domain/entities/faq.dart +++ b/lib/fcs/common/domain/entities/faq.dart @@ -5,18 +5,23 @@ class FAQ { String questionMm; String answerEng; String answerMm; + String pageLinkLabelEng; + String pageLinkLabelMm; + String pageLink; String question(bool isEng) => isEng ? questionEng : questionMm; String answer(bool isEng) => isEng ? answerEng : answerMm; - FAQ({ - this.id, - this.sn, - this.questionEng, - this.questionMm, - this.answerEng, - this.answerMm, - }); + FAQ( + {this.id, + this.sn, + this.questionEng, + this.questionMm, + this.answerEng, + this.answerMm, + this.pageLinkLabelEng, + this.pageLinkLabelMm, + this.pageLink}); Map toMap() { return { @@ -26,6 +31,9 @@ class FAQ { 'answer_eng': answerEng, 'question_mm': questionMm, 'answer_mm': answerMm, + 'page_link_label_eng': pageLinkLabelEng, + 'page_link_label_mm': pageLinkLabelMm, + 'page_link': pageLink, }; } @@ -37,6 +45,9 @@ class FAQ { answerEng: map['answer_eng'], questionMm: map['question_mm'], answerMm: map['answer_mm'], + pageLinkLabelEng: map['page_link_label_eng'], + pageLinkLabelMm: map['page_link_label_mm'], + pageLink: map['page_link'], ); } diff --git a/lib/fcs/common/domain/entities/package.dart b/lib/fcs/common/domain/entities/package.dart index 5424132..d5fce23 100644 --- a/lib/fcs/common/domain/entities/package.dart +++ b/lib/fcs/common/domain/entities/package.dart @@ -106,4 +106,20 @@ class Package { "remark": remark, "photo_urls": photoUrls }; + + factory Package.fromJson(Map json) { + return Package( + id: json['id'], + trackingID: json['tracking_id'], + market: json['market'], + userName: json['user_name'], + phoneNumber: json['phone_number'], + currentStatus: json['current_status'], + currentStatusDate: DateTime.parse(json['current_status_date'])); + } + + @override + String toString() { + return 'Package{id: $id, currentStatus: $currentStatus, market:$market, trackingID: $trackingID,}'; + } } diff --git a/lib/fcs/common/pages/buying_instruction/buying_online.dart b/lib/fcs/common/pages/buying_instruction/buying_online.dart index 85f9602..3dee003 100644 --- a/lib/fcs/common/pages/buying_instruction/buying_online.dart +++ b/lib/fcs/common/pages/buying_instruction/buying_online.dart @@ -99,8 +99,9 @@ class _BuyingOnlinePagetate extends State unselectedLabelColor: Colors.grey, controller: _tabController, tabs: [ - LocalText(context, "buy_online.fullname"), - LocalText(context, "buy_online.first.last"), + LocalText(context, "buy_online.fullname", color: primaryColor), + LocalText(context, "buy_online.first.last", + color: primaryColor), ], ), ), diff --git a/lib/fcs/common/pages/customer/customer_list.dart b/lib/fcs/common/pages/customer/customer_list.dart index 9dbb7e7..7dc1f8a 100644 --- a/lib/fcs/common/pages/customer/customer_list.dart +++ b/lib/fcs/common/pages/customer/customer_list.dart @@ -4,6 +4,7 @@ import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/pages/customer/customer_editor.dart'; import 'package:fcs/fcs/common/pages/customer/model/customer_model.dart'; import 'package:fcs/fcs/common/pages/model/main_model.dart'; +import 'package:fcs/fcs/common/pages/user_search/user_serach.dart'; import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/fcs/common/pages/widgets/local_text.dart'; import 'package:fcs/widget/progress.dart'; @@ -40,14 +41,11 @@ class _CustomerListState extends State { onPressed: () => Navigator.of(context).pop(), ), actions: [ - // IconButton( - // icon: Icon( - // Icons.search, - // color: Colors.white, - // ), - // iconSize: 30, - // onPressed: () => {}, - // ), + IconButton( + icon: Icon(Icons.search, color: Colors.white), + onPressed: () => searchUser(context, callbackUserSelect: (u) { + _select(u); + })), ], backgroundColor: primaryColor, title: LocalText( diff --git a/lib/fcs/common/pages/faq/faq_edit_page.dart b/lib/fcs/common/pages/faq/faq_edit_page.dart index 383aa35..738e28a 100644 --- a/lib/fcs/common/pages/faq/faq_edit_page.dart +++ b/lib/fcs/common/pages/faq/faq_edit_page.dart @@ -1,3 +1,4 @@ +import 'package:fcs/fcs/common/domain/constants.dart'; import 'package:fcs/fcs/common/domain/entities/faq.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/localization/app_translations.dart'; @@ -12,6 +13,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_icons/flutter_icons.dart'; import 'package:provider/provider.dart'; +const info = "Select additional page"; + class FAQEditor extends StatefulWidget { final FAQ faq; const FAQEditor({this.faq}); @@ -25,10 +28,14 @@ class _FAQEditorState extends State { TextEditingController _mmQ = new TextEditingController(); TextEditingController _engA = new TextEditingController(); TextEditingController _mmA = new TextEditingController(); + TextEditingController _pageLabelEng = new TextEditingController(); + TextEditingController _pageLabelMm = new TextEditingController(); final _formKey = GlobalKey(); bool _isLoading = false; bool _isNew = false; + String _pageLink = info; + @override void initState() { super.initState(); @@ -39,6 +46,9 @@ class _FAQEditorState extends State { _mmQ.text = widget.faq.questionMm; _engA.text = widget.faq.answerEng; _mmA.text = widget.faq.answerMm; + _pageLabelEng.text = widget.faq.pageLinkLabelEng; + _pageLabelMm.text = widget.faq.pageLinkLabelMm; + _pageLink = widget.faq.pageLink; } } @@ -72,6 +82,38 @@ class _FAQEditorState extends State { maxLines: 5, withBorder: true, ); + final pageLinkBox = DropdownButton( + value: _pageLink, + style: TextStyle(color: Colors.deepPurple), + underline: Container( + height: 2, + color: primaryColor, + ), + onChanged: (String newValue) { + setState(() { + _pageLink = newValue; + }); + }, + items: [info, page_buying_instructions, page_payment_methods] + .map>((String value) { + return DropdownMenuItem( + value: value, + child: Text( + value, + style: + TextStyle(color: value == info ? Colors.black : primaryColor), + ), + ); + }).toList(), + ); + final pageLabelEngBox = InputText( + controller: _pageLabelEng, + labelTextKey: "faq.edit.page.label.eng", + ); + final pageLabelMmBox = InputText( + controller: _pageLabelMm, + labelTextKey: "faq.edit.page.label.mm", + ); return LocalProgress( inAsyncCall: _isLoading, @@ -98,6 +140,12 @@ class _FAQEditorState extends State { fontSize: 20, color: Colors.white, )), + actions: [ + IconButton( + icon: Icon(Icons.delete), + onPressed: _delete, + ) + ], ), SliverList( delegate: SliverChildListDelegate([ @@ -106,6 +154,7 @@ class _FAQEditorState extends State { child: Padding( padding: EdgeInsets.only(left: 24.0, right: 24.0), child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ snBox, Center(child: itemTitle(context, "faq.edit.eng")), @@ -123,6 +172,11 @@ class _FAQEditorState extends State { subItemTitle(context, "faq.edit.answer", iconData: MaterialCommunityIcons.message_reply_text), answerMmBox, + Divider(), + Center(child: itemTitle(context, "faq.edit.page")), + pageLinkBox, + pageLabelEngBox, + pageLabelMmBox, fcsButton(context, getLocalString(context, "btn.save"), callack: _save), SizedBox( @@ -151,7 +205,10 @@ class _FAQEditorState extends State { questionEng: _engQ.text, answerEng: _engA.text, questionMm: _mmQ.text, - answerMm: _mmA.text); + answerMm: _mmA.text, + pageLinkLabelEng: _pageLabelEng.text, + pageLinkLabelMm: _pageLabelMm.text, + pageLink: _pageLink); if (_isNew) { await faqModel.addFAQ(_faq); } else { @@ -167,4 +224,25 @@ class _FAQEditorState extends State { }); } } + + _delete() { + showConfirmDialog(context, "faq.edit.delete.confirm", _deleteFAQ); + } + + _deleteFAQ() async { + setState(() { + _isLoading = true; + }); + try { + FAQModel faqModel = Provider.of(context, listen: false); + await faqModel.deleteFAQ(widget.faq); + Navigator.pop(context); + } catch (e) { + showMsgDialog(context, "Error", e.toString()); + } finally { + setState(() { + _isLoading = false; + }); + } + } } diff --git a/lib/fcs/common/pages/faq/faq_list_page.dart b/lib/fcs/common/pages/faq/faq_list_page.dart index 50bb6d9..1b9e4f3 100644 --- a/lib/fcs/common/pages/faq/faq_list_page.dart +++ b/lib/fcs/common/pages/faq/faq_list_page.dart @@ -1,9 +1,12 @@ +import 'package:fcs/fcs/common/domain/constants.dart'; import 'package:fcs/fcs/common/domain/entities/faq.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/localization/app_translations.dart'; +import 'package:fcs/fcs/common/pages/buying_instruction/buying_online.dart'; import 'package:fcs/fcs/common/pages/faq/faq_edit_page.dart'; import 'package:fcs/fcs/common/pages/model/language_model.dart'; import 'package:fcs/fcs/common/pages/model/main_model.dart'; +import 'package:fcs/fcs/common/pages/payment_methods/payment_method_page.dart'; import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart'; import 'package:fcs/fcs/common/pages/widgets/fcs_expansion_tile.dart'; import 'package:fcs/fcs/common/pages/widgets/local_text.dart'; @@ -115,6 +118,8 @@ class _FAQListPageState extends State context, faq.question(isEng), fontSize: 16, + fontWeight: FontWeight.w600, + color: primaryColor, ), onEditPress: () { Navigator.of(context).push(CupertinoPageRoute( @@ -133,11 +138,42 @@ class _FAQListPageState extends State Widget getAnwser(BuildContext context, FAQ faq) { bool isEng = Provider.of(context).isEng; - return TextLocalStyle( - context, - faq.answer(isEng), - fontSize: 16, - fontWeight: FontWeight.w200, + return Column( + children: [ + TextLocalStyle( + context, + faq.answer(isEng), + fontSize: 16, + fontWeight: FontWeight.w200, + ), + _pageLink( + faq.pageLink, + isEng ? faq.pageLinkLabelEng : faq.pageLinkLabelMm, + ), + ], ); } + + Widget _pageLink(String linkPage, String text) { + return linkPage == null || linkPage == "" || text == null || text == "" + ? Container() + : Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FlatButton( + color: primaryColor, + onPressed: () => _selectLinkPage(linkPage), + child: LocalText(context, "", text: text, color: Colors.white), + ) + ], + ); + } + + _selectLinkPage(String linkPage) { + if (linkPage == page_payment_methods) { + Navigator.of(context).push(BottomUpPageRoute(PaymentMethodPage())); + } else if (linkPage == page_buying_instructions) { + Navigator.of(context).push(BottomUpPageRoute(BuyingOnlinePage())); + } + } } diff --git a/lib/fcs/common/pages/home_page.dart b/lib/fcs/common/pages/home_page.dart index fb0bfd6..ebd9000 100644 --- a/lib/fcs/common/pages/home_page.dart +++ b/lib/fcs/common/pages/home_page.dart @@ -179,7 +179,7 @@ class _HomePageState extends State { List widgets = []; widgets.add(faqBtn); if (user != null) { - customer ? widgets.add(buyingBtn) : ""; + // customer ? widgets.add(buyingBtn) : ""; // customer || owner ? widgets.add(pickUpBtn) : ""; // !customer ? widgets.add(shipmentBtn) : ""; // customer || owner ? widgets.add(notiBtn) : ""; @@ -191,7 +191,7 @@ class _HomePageState extends State { // owner ? widgets.add(deliveryBtn) : ""; user.hasCustomers() ? widgets.add(customersBtn) : ""; // customer || owner ? widgets.add(invoicesBtn) : ""; - widgets.add(paymentMethodBtn); + // widgets.add(paymentMethodBtn); // owner ? widgets.add(discountBtn) : ""; // widgets.add(termBtn); } diff --git a/lib/fcs/common/pages/model/main_model.dart b/lib/fcs/common/pages/model/main_model.dart index 37169c8..7c72f58 100644 --- a/lib/fcs/common/pages/model/main_model.dart +++ b/lib/fcs/common/pages/model/main_model.dart @@ -48,6 +48,10 @@ class MainModel extends ChangeNotifier { return this.user != null && this.user.hasSupport(); } + bool paymentMethodsEditable() { + return this.user != null && this.user.hasSupport(); + } + bool termEditable() { return this.user != null && this.user.hasSupport(); } diff --git a/lib/fcs/common/pages/package/model/package_model.dart b/lib/fcs/common/pages/package/model/package_model.dart index 1f2ebff..f6ab839 100644 --- a/lib/fcs/common/pages/package/model/package_model.dart +++ b/lib/fcs/common/pages/package/model/package_model.dart @@ -45,7 +45,6 @@ class PackageModel extends BaseModel { .where("is_delivered", isEqualTo: false) .snapshots() .listen((QuerySnapshot snapshot) { - print("reloaded...."); packages.clear(); packages = snapshot.documents.map((documentSnapshot) { var package = Package.fromMap( @@ -59,13 +58,33 @@ class PackageModel extends BaseModel { } } + 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"; + } + try { + DocumentSnapshot snap = + await Firestore.instance.collection("$path").document(id).get(); + 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); } Future> searchPackage(String term) { - // return Services.instance.userService.searchUser(term); - return null; + return Services.instance.packageService.searchPackage(term); } Future createPackages(User user, List packages) { @@ -88,4 +107,8 @@ class PackageModel extends BaseModel { await request("/packages", "PUT", payload: package.toJson(), token: await getToken()); } + + Future deletePackage(Package package) { + return Services.instance.packageService.deletePackage(package); + } } diff --git a/lib/fcs/common/pages/package/package_editor.dart b/lib/fcs/common/pages/package/package_editor.dart index 735aeff..2b02700 100644 --- a/lib/fcs/common/pages/package/package_editor.dart +++ b/lib/fcs/common/pages/package/package_editor.dart @@ -36,7 +36,7 @@ class _PackageEditorPageState extends State { void initState() { super.initState(); _package = widget.package; - selectedMarket = _package.market; + selectedMarket = _package.market ?? ""; _descCtl.text = _package.desc; _remarkCtl.text = _package.remark; multiImgController.setImageUrls = _package.photoUrls; @@ -97,6 +97,12 @@ class _PackageEditorPageState extends State { fontSize: 20, color: primaryColor, ), + actions: [ + IconButton( + icon: Icon(Icons.delete, color: primaryColor), + onPressed: _delete, + ) + ], ), body: Padding( padding: const EdgeInsets.all(8.0), @@ -145,6 +151,9 @@ class _PackageEditorPageState extends State { List _markets = Provider.of(context).markets; List markets = _markets.map((e) => e.name).toList(); markets.insert(0, MANAGE_MARKET); + if (!markets.contains(selectedMarket)) { + markets.insert(0, selectedMarket); + } return Row( children: [ @@ -226,4 +235,26 @@ class _PackageEditorPageState extends State { }); } } + + _delete() { + showConfirmDialog(context, "package.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/fcs/common/pages/package/package_info.dart b/lib/fcs/common/pages/package/package_info.dart index b4b6110..1dd1937 100644 --- a/lib/fcs/common/pages/package/package_info.dart +++ b/lib/fcs/common/pages/package/package_info.dart @@ -11,9 +11,12 @@ import 'package:fcs/fcs/common/pages/widgets/progress.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 { @@ -33,8 +36,14 @@ class _PackageInfoState extends State { @override void initState() { super.initState(); - _package = widget.package; - multiImgController.setImageUrls = _package.photoUrls; + initPackage(widget.package); + } + + initPackage(Package package) { + setState(() { + _package = package; + multiImgController.setImageUrls = package.photoUrls; + }); } @override @@ -100,12 +109,7 @@ class _PackageInfoState extends State { actions: [ IconButton( icon: Icon(Icons.edit, color: primaryColor), - onPressed: () => Navigator.push( - context, - BottomUpPageRoute(PackageEditorPage( - package: widget.package, - )), - ), + onPressed: _gotoEditor, ) ], ), @@ -183,4 +187,20 @@ 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/fcs/common/pages/package/package_list.dart b/lib/fcs/common/pages/package/package_list.dart index d998b8a..ce6eee7 100644 --- a/lib/fcs/common/pages/package/package_list.dart +++ b/lib/fcs/common/pages/package/package_list.dart @@ -1,6 +1,9 @@ +import 'package:fcs/fcs/common/domain/entities/package.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/localization/app_translations.dart'; +import 'package:fcs/fcs/common/pages/model/main_model.dart'; import 'package:fcs/fcs/common/pages/package/model/package_model.dart'; +import 'package:fcs/fcs/common/pages/package/package_info.dart'; import 'package:fcs/fcs/common/pages/package/package_list_row.dart'; import 'package:fcs/fcs/common/pages/package/package_new.dart'; import 'package:fcs/fcs/common/pages/package_search/package_serach.dart'; @@ -33,6 +36,7 @@ class _PackageListState extends State { @override Widget build(BuildContext context) { var packageModel = Provider.of(context); + bool isCustomer = context.select((MainModel m) => m.isCustomer()); return LocalProgress( inAsyncCall: _isLoading, @@ -51,38 +55,30 @@ class _PackageListState extends State { color: Colors.white, ), actions: [ - // IconButton( - // icon: Icon( - // Ionicons.ios_barcode, - // color: Colors.white, - // ), - // iconSize: 30, - // onPressed: () { - // Navigator.push( - // context, - // BottomUpPageRoute(BarcodeScreenPage()), - // ); - // }, - // ), - IconButton( - icon: Icon( - Icons.search, - color: Colors.white, - ), - iconSize: 30, - onPressed: () => searchPackage(context), - ), + isCustomer + ? Container() + : IconButton( + icon: Icon( + Icons.search, + color: Colors.white, + ), + iconSize: 30, + onPressed: () => searchPackage(context, + callbackPackageSelect: _searchCallback), + ), ], ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - _newPackage(); - }, - icon: Icon(Icons.add), - label: - Text(AppTranslations.of(context).text("package.create.title")), - backgroundColor: primaryColor, - ), + 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, @@ -93,6 +89,7 @@ class _PackageListState extends State { itemCount: packageModel.packages.length, itemBuilder: (BuildContext context, int index) { return PackageListRow( + key: ValueKey(packageModel.packages[index].id), package: packageModel.packages[index], ); })), @@ -105,4 +102,14 @@ class _PackageListState extends State { BottomUpPageRoute(PackageNew()), ); } + + _searchCallback(Package package) async { + var packageModel = Provider.of(context, listen: false); + Package _package = await packageModel.getPackage(package.id); + if (_package == null) return; + Navigator.push( + context, + BottomUpPageRoute(PackageInfo(package: _package)), + ); + } } diff --git a/lib/fcs/common/pages/package/package_list_row.dart b/lib/fcs/common/pages/package/package_list_row.dart index cef66aa..7cf0f61 100644 --- a/lib/fcs/common/pages/package/package_list_row.dart +++ b/lib/fcs/common/pages/package/package_list_row.dart @@ -1,29 +1,20 @@ import 'package:fcs/fcs/common/domain/entities/package.dart'; -import 'package:fcs/fcs/common/pages/package/package_editor.dart'; import 'package:fcs/fcs/common/pages/package/package_info.dart'; import 'package:fcs/fcs/common/pages/util.dart'; import 'package:fcs/fcs/common/pages/widgets/bottom_up_page_route.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -class PackageListRow extends StatefulWidget { +typedef CallbackPackageSelect(Package package); + +class PackageListRow extends StatelessWidget { final Package package; - const PackageListRow({this.package}); - - @override - _PackageListRowtate createState() => _PackageListRowtate(); -} - -class _PackageListRowtate extends State { + final CallbackPackageSelect callbackPackageSelect; final double dotSize = 15.0; - Package _package = new Package(); final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); - @override - void initState() { - super.initState(); - _package = widget.package; - } + PackageListRow({Key key, this.package, this.callbackPackageSelect}) + : super(key: key); @override Widget build(BuildContext context) { @@ -31,9 +22,13 @@ class _PackageListRowtate extends State { padding: EdgeInsets.only(left: 15, right: 15), child: InkWell( onTap: () { + if (callbackPackageSelect != null) { + callbackPackageSelect(package); + return; + } Navigator.push( context, - BottomUpPageRoute(PackageInfo(package: _package)), + BottomUpPageRoute(PackageInfo(package: package)), ); }, child: Row( @@ -50,7 +45,7 @@ class _PackageListRowtate extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _package.id == null ? '' : _package.trackingID, + package.id == null ? '' : package.trackingID, style: new TextStyle( fontSize: 15.0, color: Colors.black), ), @@ -58,21 +53,11 @@ class _PackageListRowtate extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _package.market == null ? '' : _package.market, + package.market == null ? '' : package.market, style: new TextStyle( fontSize: 15.0, color: Colors.black), ), ), - // Padding( - // padding: const EdgeInsets.only(left: 8.0), - // child: new Text( - // _package.trackingID == null - // ? '' - // : _package.trackingID, - // style: new TextStyle( - // fontSize: 15.0, color: Colors.grey), - // ), - // ), ], ), ), @@ -84,36 +69,15 @@ class _PackageListRowtate extends State { children: [ Padding( padding: const EdgeInsets.all(3.0), - child: getStatus(_package.currentStatus), + child: getStatus(package.currentStatus), ), Padding( padding: const EdgeInsets.all(0), child: new Text( - dateFormat.format(_package.currentStatusDate), + dateFormat.format(package.currentStatusDate), style: new TextStyle(fontSize: 15.0, color: Colors.grey), ), ), - // Padding( - // padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), - // child: Row( - // children: [ - // new Text( - // _package.weight == null - // ? '' - // : _package.weight.toString() + 'lb - ', - // style: - // new TextStyle(fontSize: 15.0, color: Colors.grey), - // ), - // new Text( - // _package.price == null - // ? "" - // : "\$ " + _package.price.toString(), - // style: - // new TextStyle(fontSize: 15.0, color: Colors.grey), - // ), - // ], - // ), - // ), ], ) ], diff --git a/lib/fcs/common/pages/package/package_new.dart b/lib/fcs/common/pages/package/package_new.dart index 52ef4a1..ff44211 100644 --- a/lib/fcs/common/pages/package/package_new.dart +++ b/lib/fcs/common/pages/package/package_new.dart @@ -143,7 +143,7 @@ class _PackageNewState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(packages[index].market), + Text(packages[index].market ?? ""), Text(packages[index].trackingID), // DisplayText( // labelText: "Tracking ID", diff --git a/lib/fcs/common/pages/package/shipping_address_list.dart b/lib/fcs/common/pages/package/shipping_address_list.dart index 8441a62..90ff149 100644 --- a/lib/fcs/common/pages/package/shipping_address_list.dart +++ b/lib/fcs/common/pages/package/shipping_address_list.dart @@ -32,6 +32,7 @@ class _ShippingAddressListState extends State { @override Widget build(BuildContext context) { var shipmentModel = Provider.of(context); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( diff --git a/lib/fcs/common/pages/package_search/package_search_row.dart b/lib/fcs/common/pages/package_search/package_search_row.dart deleted file mode 100644 index 247c91e..0000000 --- a/lib/fcs/common/pages/package_search/package_search_row.dart +++ /dev/null @@ -1,88 +0,0 @@ -import 'package:fcs/fcs/common/domain/entities/package.dart'; -import 'package:fcs/fcs/common/helpers/theme.dart'; -import 'package:fcs/fcs/common/pages/package_search/package_serach.dart'; -import 'package:flutter/material.dart'; - -class PackageSearchRow extends StatefulWidget { - final CallbackPackageSelect callbackPackageSelect; - final Package package; - const PackageSearchRow({this.package, this.callbackPackageSelect}); - - @override - _PackageSearchRowState createState() => _PackageSearchRowState(); -} - -class _PackageSearchRowState extends State { - final double dotSize = 15.0; - Package package; - @override - void initState() { - super.initState(); - this.package = widget.package; - } - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 15, right: 15), - child: Card( - elevation: 10, - color: Colors.white, - child: InkWell( - onTap: () { - Navigator.pop(context); - if (widget.callbackPackageSelect != null) - widget.callbackPackageSelect(package); - }, - child: Row( - children: [ - Expanded( - child: new Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: new Row( - children: [ - new Padding( - padding: new EdgeInsets.symmetric( - horizontal: 32.0 - dotSize / 2), - child: Image.asset( - "assets/buyer.png", - width: 40, - height: 40, - color: primaryColor, - ), - ), - new Expanded( - child: new Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - new Text( - package.trackingID == null - ? '' - : package.trackingID, - style: new TextStyle( - fontSize: 15.0, color: Colors.black), - ), - new Text( - package.userName == null ? "" : package.userName, - style: new TextStyle( - fontSize: 13.0, color: Colors.grey), - ), - new Text( - package.fcsID == null ? "" : package.fcsID, - style: new TextStyle( - fontSize: 13.0, color: Colors.grey), - ), - ], - ), - ), - ], - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/fcs/common/pages/package_search/package_serach.dart b/lib/fcs/common/pages/package_search/package_serach.dart index 86e3b73..4740a42 100644 --- a/lib/fcs/common/pages/package_search/package_serach.dart +++ b/lib/fcs/common/pages/package_search/package_serach.dart @@ -1,12 +1,14 @@ +import 'package:barcode_scan/barcode_scan.dart'; import 'package:fcs/fcs/common/domain/entities/package.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/pages/package/model/package_model.dart'; -import 'package:fcs/fcs/common/pages/package_search/package_search_row.dart'; +import 'package:fcs/fcs/common/pages/package/package_list_row.dart'; +import 'package:fcs/fcs/common/pages/util.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; -typedef CallbackPackageSelect(Package package); - Future searchPackage(BuildContext context, {CallbackPackageSelect callbackPackageSelect}) async => await showSearch( @@ -21,7 +23,7 @@ class PackageSearchDelegate extends SearchDelegate { PackageSearchDelegate({this.callbackPackageSelect}); @override - String get searchFieldLabel => 'Search by FCS ID or Name'; + String get searchFieldLabel => 'Search by Tracking ID/Customer Name'; @override ThemeData appBarTheme(BuildContext context) { @@ -40,6 +42,11 @@ class PackageSearchDelegate extends SearchDelegate { @override List buildActions(BuildContext context) { return [ + IconButton( + icon: Icon(MaterialCommunityIcons.barcode_scan, + size: 30, color: Colors.white), + onPressed: () => _scan(context), + ), IconButton( icon: Icon(Icons.clear), onPressed: () => query = '', @@ -76,7 +83,7 @@ class PackageSearchDelegate extends SearchDelegate { padding: EdgeInsets.only(top: 15), child: ListView( children: snapshot.data - .map((u) => PackageSearchRow( + .map((u) => PackageListRow( package: u, callbackPackageSelect: callbackPackageSelect, )) @@ -110,8 +117,32 @@ class PackageSearchDelegate extends SearchDelegate { child: Center( child: Opacity( opacity: 0.2, - child: Icon(Icons.perm_identity, size: 200, color: primaryColor)), + child: Icon(Octicons.package, size: 200, color: primaryColor)), ), ); } + + _scan(BuildContext context) async { + PermissionStatus permission = + await PermissionHandler().checkPermissionStatus(PermissionGroup.camera); + if (permission != PermissionStatus.granted) { + Map permissions = + await PermissionHandler() + .requestPermissions([PermissionGroup.camera]); + if (permissions[PermissionGroup.camera] != PermissionStatus.granted) { + showMsgDialog(context, "Error", "Camera permission is not granted"); + return null; + } + } + + try { + String barcode = await BarcodeScanner.scan(); + if (barcode != null) { + query = barcode; + showResults(context); + } + } catch (e) { + print('error: $e'); + } + } } diff --git a/lib/fcs/common/pages/payment_methods/payment_method_page.dart b/lib/fcs/common/pages/payment_methods/payment_method_page.dart index 5918f52..b281297 100644 --- a/lib/fcs/common/pages/payment_methods/payment_method_page.dart +++ b/lib/fcs/common/pages/payment_methods/payment_method_page.dart @@ -1,6 +1,7 @@ import 'package:fcs/fcs/common/domain/entities/payment_method.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/localization/app_translations.dart'; +import 'package:fcs/fcs/common/pages/model/main_model.dart'; import 'package:fcs/fcs/common/pages/payment_methods/model/payment_method_model.dart'; import 'package:fcs/fcs/common/pages/payment_methods/payment_method_editor.dart'; import 'package:fcs/fcs/common/pages/util.dart'; @@ -24,6 +25,8 @@ class _PaymentMethodPageState extends State { @override Widget build(BuildContext context) { PaymentMethodModel mainModel = Provider.of(context); + bool isEditable = + context.select((MainModel m) => m.paymentMethodsEditable()); return LocalProgress( inAsyncCall: _isLoading, @@ -57,26 +60,28 @@ class _PaymentMethodPageState extends State { itemCount: mainModel.paymentMethods.length, itemBuilder: (BuildContext context, int index) { var method = mainModel.paymentMethods[index]; - return _item(method); + return _item(method, isEditable); }, ), ), - floatingActionButton: FloatingActionButton.extended( - onPressed: () { - Navigator.push( - context, - BottomUpPageRoute(PaymentMethodEditor()), - ); - }, - icon: Icon(Icons.add), - label: LocalText(context, "pm.new", color: Colors.white), - backgroundColor: primaryColor, - ), + floatingActionButton: isEditable + ? FloatingActionButton.extended( + onPressed: () { + Navigator.push( + context, + BottomUpPageRoute(PaymentMethodEditor()), + ); + }, + icon: Icon(Icons.add), + label: LocalText(context, "pm.new", color: Colors.white), + backgroundColor: primaryColor, + ) + : Container(), ), ); } - _item(PaymentMethod method) { + _item(PaymentMethod method, bool isEditable) { final accountName = _itemRow(method.accountName, "pm.account.name", iconData: MaterialCommunityIcons.bank); final accountNumber = _itemRow(method.account, "pm.account.no", @@ -86,14 +91,16 @@ class _PaymentMethodPageState extends State { final link = _itemRow(method.link, "pm.link", iconData: Icons.link); return InkWell( - onTap: () { - Navigator.push( - context, - BottomUpPageRoute(PaymentMethodEditor( - paymentMethod: method, - )), - ); - }, + onTap: isEditable + ? () { + Navigator.push( + context, + BottomUpPageRoute(PaymentMethodEditor( + paymentMethod: method, + )), + ); + } + : null, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/fcs/common/pages/util.dart b/lib/fcs/common/pages/util.dart index 370b601..4be719c 100644 --- a/lib/fcs/common/pages/util.dart +++ b/lib/fcs/common/pages/util.dart @@ -96,6 +96,7 @@ Future showConfirmDialog( context, translationKey, translationVariables: translationVariables, + color: primaryColor, ), ), content: Container( diff --git a/lib/fcs/common/pages/widgets/display_image_source.dart b/lib/fcs/common/pages/widgets/display_image_source.dart index 29f25cb..444586d 100644 --- a/lib/fcs/common/pages/widgets/display_image_source.dart +++ b/lib/fcs/common/pages/widgets/display_image_source.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/widgets.dart'; class DisplayImageSource { @@ -8,7 +9,7 @@ class DisplayImageSource { DisplayImageSource({this.url, this.file}); ImageProvider get imageProvider => - file == null ? NetworkImage(url) : FileImage(file); + file == null ? CachedNetworkImageProvider(url) : FileImage(file); @override bool operator ==(other) { diff --git a/lib/fcs/common/pages/widgets/fcs_expansion_tile.dart b/lib/fcs/common/pages/widgets/fcs_expansion_tile.dart index 19ea77a..1225bfd 100644 --- a/lib/fcs/common/pages/widgets/fcs_expansion_tile.dart +++ b/lib/fcs/common/pages/widgets/fcs_expansion_tile.dart @@ -31,7 +31,7 @@ class _FcsExpansionTileState extends State { Widget build(BuildContext context) { return Theme( data: ThemeData( - accentColor: secondaryColor, dividerColor: Colors.transparent), + accentColor: primaryColor, dividerColor: Colors.transparent), child: ExpansionTile( onExpansionChanged: (value) { setState(() { @@ -44,6 +44,8 @@ class _FcsExpansionTileState extends State { children: widget.children, trailing: widget.isEdit ? IconButton( + padding: EdgeInsets.all(0), + iconSize: 20, onPressed: () => widget.onEditPress != null ? widget.onEditPress() : {}, icon: Icon( diff --git a/lib/fcs/common/pages/widgets/image_slider.dart b/lib/fcs/common/pages/widgets/image_slider.dart deleted file mode 100644 index 34eb9ff..0000000 --- a/lib/fcs/common/pages/widgets/image_slider.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:fcs/fcs/common/helpers/theme.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_icons/flutter_icons.dart'; - -getImgSlider(List images) { - return Container( - height: 130, - width: 500, - child: ListView.separated( - separatorBuilder: (context, index) => Divider( - color: Colors.black, - ), - itemCount: images.length + 1, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - if (index == images.length) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: 200, - height: 70, - decoration: BoxDecoration( - border: Border.all( - color: primaryColor, - width: 2.0, - ), - ), - child: Icon(SimpleLineIcons.plus), - ), - ); - } else { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - width: 200, - height: 70, - decoration: BoxDecoration( - border: Border.all( - color: primaryColor, - width: 2.0, - ), - ), - child: Image.network( - "https://lh3.googleusercontent.com/Fu9J7YpHnHK8QPr3kdAyEbTFyvB3h9Na69-j8CpQqWbMQP9sGplj7hVqQ5beKKLGgdyA8f5zIfqWdp2ITxuqlGkWDVuTyAtj_Rmw=w0", - width: 50, - height: 50), - ), - ); - } - }, - ), - ); -} diff --git a/lib/fcs/common/pages/widgets/local_text.dart b/lib/fcs/common/pages/widgets/local_text.dart index 36333d0..887df1a 100644 --- a/lib/fcs/common/pages/widgets/local_text.dart +++ b/lib/fcs/common/pages/widgets/local_text.dart @@ -11,10 +11,12 @@ class LocalText extends Text { double fontSize, FontWeight fontWeight, List translationVariables, + String text, bool underline = false}) : super( - AppTranslations.of(context).text(translationKey, - translationVariables: translationVariables), + text ?? + AppTranslations.of(context).text(translationKey, + translationVariables: translationVariables), style: Provider.of(context, listen: false).isEng ? newLabelStyle( color: color, diff --git a/lib/fcs/common/pages/widgets/multi_img_file.dart b/lib/fcs/common/pages/widgets/multi_img_file.dart index 9a700fc..cb10c48 100644 --- a/lib/fcs/common/pages/widgets/multi_img_file.dart +++ b/lib/fcs/common/pages/widgets/multi_img_file.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/pages/widgets/show_img.dart'; import 'package:fcs/fcs/common/pages/widgets/show_multiple_img.dart'; @@ -95,6 +96,7 @@ class _MultiImageFileState extends State { MaterialPageRoute( builder: (context) => ShowMultiImage( displayImageSources: fileContainers, + initialPage: index, )), ), child: Stack(alignment: Alignment.topLeft, children: [ @@ -110,8 +112,17 @@ class _MultiImageFileState extends State { ), ), child: fileContainers[index].file == null - ? Image.network(fileContainers[index].url, - width: 50, height: 50) + ? CachedNetworkImage( + imageUrl: fileContainers[index].url, + placeholder: (context, url) => Container( + width: 50, + height: 50, + child: CircularProgressIndicator()), + errorWidget: (context, url, error) => + Icon(Icons.error), + ) + // Image.network(fileContainers[index].url, + // width: 50, height: 50) : Image.file(fileContainers[index].file, width: 50, height: 50), ), diff --git a/lib/fcs/common/pages/widgets/show_multiple_img.dart b/lib/fcs/common/pages/widgets/show_multiple_img.dart index ddfdaa5..434ffbd 100644 --- a/lib/fcs/common/pages/widgets/show_multiple_img.dart +++ b/lib/fcs/common/pages/widgets/show_multiple_img.dart @@ -1,3 +1,4 @@ +import 'package:fcs/fcs/common/helpers/theme.dart'; import 'package:fcs/fcs/common/pages/widgets/display_image_source.dart'; import 'package:flutter/material.dart'; import 'package:photo_view/photo_view.dart'; @@ -5,12 +6,22 @@ import 'package:photo_view/photo_view_gallery.dart'; class ShowMultiImage extends StatefulWidget { final List displayImageSources; - const ShowMultiImage({Key key, this.displayImageSources}) : super(key: key); + final int initialPage; + const ShowMultiImage( + {Key key, this.displayImageSources, this.initialPage = 0}) + : super(key: key); @override _ShowMultiImageState createState() => _ShowMultiImageState(); } class _ShowMultiImageState extends State { + PageController pageController; + @override + void initState() { + pageController = PageController(initialPage: widget.initialPage); + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -37,6 +48,10 @@ class _ShowMultiImageState extends State { ), ), ), + backgroundDecoration: const BoxDecoration( + color: primaryColor, + ), + pageController: pageController, ))); } } diff --git a/lib/fcs/common/services/package_imp.dart b/lib/fcs/common/services/package_imp.dart index f1b3eb7..02d9394 100644 --- a/lib/fcs/common/services/package_imp.dart +++ b/lib/fcs/common/services/package_imp.dart @@ -17,4 +17,14 @@ class PackageServiceImp implements PackageService { Future createPackages(List packages, String fcsID) { return packageDataProvider.createPackages(packages, fcsID); } + + @override + Future> searchPackage(String term) { + return packageDataProvider.searchPackage(term); + } + + @override + Future deletePackage(Package package) { + return packageDataProvider.deletePackage(package); + } } diff --git a/lib/fcs/common/services/package_service.dart b/lib/fcs/common/services/package_service.dart index e032ff0..b9498b2 100644 --- a/lib/fcs/common/services/package_service.dart +++ b/lib/fcs/common/services/package_service.dart @@ -2,4 +2,6 @@ import 'package:fcs/fcs/common/domain/entities/package.dart'; abstract class PackageService { Future createPackages(List packages, String fcsID); + Future deletePackage(Package package); + Future> searchPackage(String term); } diff --git a/pubspec.yaml b/pubspec.yaml index 29125f1..6eae269 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,6 +76,7 @@ dependencies: flutter_pdfview: ^1.0.3 flutter_local_notifications: ^1.4.4+4 share: ^0.6.5 + cached_network_image: ^2.3.2+1