diff --git a/assets/local/localization_en.json b/assets/local/localization_en.json index 254bb26..fa7be69 100644 --- a/assets/local/localization_en.json +++ b/assets/local/localization_en.json @@ -513,14 +513,23 @@ "rate.edit.title":"EDIT RATES", - "rate.cal.title":"CALCULATE RATES", + "rate.cal.title":"ESTIMATE SHIPPING COST", + + "boxes.name":"Boxes", + "boxes.title":"BOXES", + "boxes.new":"New Box", + "box.edit.title":"BOX", + "box.package.id":"Package ID", + "box.package.desc":"Description", + "box.package.market":"Market", + "box.add_package":"Add Package", "package.name":"Packages", "package.title":"PACKAGES", "package.new":"New Package", "package.edit.title":"PACKAGE", "package.arrival.date":"Arrival Date", - "package.number":"Package Number", + "package.number":"Box Number", "package.rate":"Rate", "package.weight":"Weight", "package.amount":"Amount", @@ -542,7 +551,7 @@ "invoices.add":"New Invoice", "invoice.form.title":"INVOICE", "invoice.payment":"Payment Receipt", - "invoice.add_package":"Add Package", + "invoice.add_box":"Add Box", "term":"TERMS", "term.btn":"Terms", diff --git a/lib/app.dart b/lib/app.dart index 722c251..29fec3e 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -33,6 +33,7 @@ import 'model/product_model.dart'; import 'model/report_user_model.dart'; import 'model/shipment_rate_model.dart'; import 'model/user_model.dart'; +import 'model_fcs/box_model.dart'; import 'pages/home_page.dart'; import 'pages/splash.dart'; import 'pages/term.dart'; @@ -71,6 +72,7 @@ class _AppState extends State { final ShipmentRateModel shipmentRateModel = new ShipmentRateModel(); final ShipmentModel shipmentModel = new ShipmentModel(); final PackageModel packageModel=new PackageModel(); + final BoxModel boxModel=new BoxModel(); final MessageModel messageModel=new MessageModel(); final InvoiceModel invoiceModel = new InvoiceModel(); final CustomerModel customerModel = new CustomerModel(); @@ -108,6 +110,7 @@ class _AppState extends State { ..addModel(shipmentRateModel) ..addModel(shipmentModel) ..addModel(packageModel) + ..addModel(boxModel) ..addModel(messageModel) ..addModel(shipmentRateModel) ..addModel(invoiceModel) @@ -164,6 +167,7 @@ class _AppState extends State { ChangeNotifierProvider(builder: (context) => shipmentRateModel), ChangeNotifierProvider(builder: (context) => shipmentModel), ChangeNotifierProvider(builder: (context) => packageModel), + ChangeNotifierProvider(builder: (context) => boxModel), ChangeNotifierProvider(builder: (context) => messageModel), ChangeNotifierProvider(builder: (context) => invoiceModel), ChangeNotifierProvider(builder: (context) => customerModel), diff --git a/lib/model_fcs/box_model.dart b/lib/model_fcs/box_model.dart new file mode 100644 index 0000000..96d3b91 --- /dev/null +++ b/lib/model_fcs/box_model.dart @@ -0,0 +1,153 @@ +import 'dart:async'; + +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:fcs/model/base_model.dart'; +import 'package:fcs/model_fcs/package_model.dart'; +import 'package:fcs/vo/box.dart'; +import 'package:fcs/vo/package.dart'; +import 'package:logging/logging.dart'; + +class BoxModel extends BaseModel { + final log = Logger('BoxModel'); + + StreamSubscription listener; + static List statusHistory = [ + Status(status: "Packed", date: DateTime(2020, 6, 1), done: true), + Status(status: "Shipped", date: DateTime(2020, 6, 5), done: false), + Status(status: "Delivered", date: DateTime(2020, 6, 15), done: false) + ]; + static List packages = [ + PackageModel.packages[0], + PackageModel.packages[1], + PackageModel.packages[2] + ]; + List boxes = [ + Box( + shipmentNumber: "A202", + receiverNumber: "3", + receiverName: "Ko Myo Min", + boxNumber: "1", + rate: 7, + packageType: "General", + weight: 25, + status: "Packed", + receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', + cargoDesc: "Clothes", + arrivedDate: DateTime(2020, 6, 1), + packages: packages, + statusHistory: statusHistory), + Box( + shipmentNumber: "A202", + receiverNumber: "3", + receiverName: "Ko Myo Min", + boxNumber: "2", + rate: 7, + packageType: "General", + weight: 20, + status: "Packed", + cargoDesc: "Clothes", + arrivedDate: DateTime(2020, 6, 1), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'), + Box( + shipmentNumber: "A202", + receiverNumber: "3", + receiverName: "Ko Myo Min", + boxNumber: "3", + rate: 7, + packageType: "General", + weight: 15, + cargoDesc: "Shoes", + status: "Packed", + arrivedDate: DateTime(2020, 6, 1), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'), + Box( + shipmentNumber: "A202", + receiverNumber: "2", + receiverName: "Ma Aye", + boxNumber: "1", + rate: 8, + packageType: "Medicine", + weight: 15, + status: "Packed", + cargoDesc: "Dietary supplement", + arrivedDate: DateTime(2020, 6, 1), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'), + Box( + shipmentNumber: "A202", + receiverNumber: "2", + receiverName: "Ma Aye", + boxNumber: "2", + rate: 7, + packageType: "General", + cargoDesc: "Handbags", + weight: 55, + status: "Shipped", + arrivedDate: DateTime(2020, 6, 1), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'), + Box( + shipmentNumber: "A201", + receiverNumber: "1", + receiverName: "Ko Wai", + boxNumber: "1", + rate: 9, + packageType: "Dangerous", + cargoDesc: "Phones and Scooters", + weight: 25, + status: "Delivered", + arrivedDate: DateTime(2020, 5, 21), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon'), + Box( + shipmentNumber: "A201", + receiverNumber: "1", + receiverName: "Ko Wai", + boxNumber: "2", + rate: 7, + packageType: "General", + cargoDesc: "Construction tools", + weight: 5, + status: "Delivered", + arrivedDate: DateTime(2020, 5, 21), + statusHistory: statusHistory, + packages: packages, + receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon'), + ]; + + List get completed { + return boxes.where((e) => e.status == "Delivered").toList() + ..sort((e1, e2) { + return e2.packageNumber.compareTo(e1.packageNumber); + }); + } + + List get upcoming { + return boxes + .where((e) => + e.status == "Packed" || + e.status == "Received" || + e.status == "Shipped") + .toList() + ..sort((e1, e2) { + return e2.packageNumber.compareTo(e1.packageNumber); + }); + } + + void initUser(user) { + super.initUser(user); + } + + @override + logout() async { + if (listener != null) await listener.cancel(); + boxes = []; + } +} diff --git a/lib/model_fcs/package_model.dart b/lib/model_fcs/package_model.dart index 56138d0..7c17b02 100644 --- a/lib/model_fcs/package_model.dart +++ b/lib/model_fcs/package_model.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:fcs/model/base_model.dart'; +import 'package:fcs/vo/box.dart'; import 'package:fcs/vo/package.dart'; import 'package:logging/logging.dart'; @@ -15,24 +16,26 @@ class PackageModel extends BaseModel { Status(status: "Shipped", date: DateTime(2020, 6, 5), done: false), Status(status: "Delivered", date: DateTime(2020, 6, 15), done: false) ]; - List packages = [ + static List packages = [ Package( shipmentNumber: "A202", receiverNumber: "3", - receiverName: "Ko Oo", + receiverName: "Ko Myo Min", boxNumber: "1", rate: 7, packageType: "General", weight: 25, status: "Received", receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon', - cargoDesc: "Clothes", + cargoDesc: "Computers", arrivedDate: DateTime(2020, 6, 1), - statusHistory: statusHistory), + market: "Amazon", + id: "PKG2039", + trackingID: "23-234s-asdfl"), Package( shipmentNumber: "A202", receiverNumber: "3", - receiverName: "Ko Oo", + receiverName: "Ko Myo Min", boxNumber: "2", rate: 7, packageType: "General", @@ -40,20 +43,24 @@ class PackageModel extends BaseModel { status: "Received", cargoDesc: "Clothes", arrivedDate: DateTime(2020, 6, 1), - statusHistory: statusHistory, + market: "Macy", + trackingID: "asd-sdf-23498", + id: "PKG2040", receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'), Package( shipmentNumber: "A202", receiverNumber: "3", - receiverName: "Ko Oo", + receiverName: "Ko Myo Min", boxNumber: "3", rate: 7, packageType: "General", weight: 15, cargoDesc: "Shoes", status: "Processed", + market: "Macy", + trackingID: "8923-234-sd", + id: "PKG2041", arrivedDate: DateTime(2020, 6, 1), - statusHistory: statusHistory, receiverAddress: '1 Bo Yar Nyunt St.\nDagon Tsp, Yangon'), Package( shipmentNumber: "A202", @@ -64,9 +71,11 @@ class PackageModel extends BaseModel { packageType: "Medicine", weight: 15, status: "Processed", + market: "Macy", + trackingID: "lsdf-sd09sdf", cargoDesc: "Dietary supplement", + id: "PKG2042", arrivedDate: DateTime(2020, 6, 1), - statusHistory: statusHistory, receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'), Package( shipmentNumber: "A202", @@ -77,9 +86,11 @@ class PackageModel extends BaseModel { packageType: "General", cargoDesc: "Handbags", weight: 55, - status: "Ready to ship", + market: "Macy", + trackingID: "234-sdflsdf-213", + status: "Processed", + id: "PKG2043", arrivedDate: DateTime(2020, 6, 1), - statusHistory: statusHistory, receiverAddress: '2 Shwe Taung Kyar St, Bahan Tsp, Yangon'), Package( shipmentNumber: "A201", @@ -90,9 +101,11 @@ class PackageModel extends BaseModel { packageType: "Dangerous", cargoDesc: "Phones and Scooters", weight: 25, - status: "Delivered", + status: "Received", + market: "Amazon", + trackingID: "sdf-asdf-23489", + id: "PKG2044", arrivedDate: DateTime(2020, 5, 21), - statusHistory: statusHistory, receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon'), Package( shipmentNumber: "A201", @@ -103,29 +116,26 @@ class PackageModel extends BaseModel { packageType: "General", cargoDesc: "Construction tools", weight: 5, - status: "Delivered", + status: "Processed", + market: "Amazon", + id: "PKG2045", + trackingID: "oiuw-sdfpo-234", arrivedDate: DateTime(2020, 5, 21), - statusHistory: statusHistory, receiverAddress: '3 Kambzwza St, Bahan Tsp, Yangon'), ]; List get completed { - return packages.where((e) => e.status == "Delivered").toList() + return packages.where((e) => e.status == "Processed").toList() ..sort((e1, e2) { return e2.packageNumber.compareTo(e1.packageNumber); }); } List get upcoming { - return packages - .where((e) => - e.status == "Processed" || - e.status == "Received" || - e.status == "Ready to ship") - .toList() - ..sort((e1, e2) { - return e2.packageNumber.compareTo(e1.packageNumber); - }); + return packages.where((e) => e.status == "Received").toList() + ..sort((e1, e2) { + return e2.packageNumber.compareTo(e1.packageNumber); + }); } void initUser(user) { diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index ea75c0d..88636e6 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,6 +1,7 @@ import 'package:country_code_picker/country_code.dart'; import 'package:fcs/model/main_model.dart'; import 'package:fcs/pages/shipment_list.dart'; +import 'package:fcs/pages_fcs/box_list.dart'; import 'package:fcs/pages_fcs/package_list.dart'; import 'package:fcs/widget/bottom_up_page_route.dart'; import 'package:fcs/widget/localization/transalation.dart'; @@ -111,6 +112,11 @@ class _HomePageState extends State { btnCallback: () => Navigator.of(context).push(BottomUpPageRoute(PackageList()))); + final boxesBtn = _buildBtn2("boxes.name", + icon: MaterialCommunityIcons.package, + btnCallback: () => + Navigator.of(context).push(BottomUpPageRoute(BoxList()))); + final pickUpBtn = _buildBtn2("pickup", icon: SimpleLineIcons.direction, btnCallback: () => @@ -182,6 +188,7 @@ class _HomePageState extends State { owner ? widgets.add(fcsProfileBtn) : ""; widgets.add(shipmentCostBtn); customer || owner ? widgets.add(packagesBtn) : ""; + customer || owner ? widgets.add(boxesBtn) : ""; owner ? widgets.add(customersBtn) : ""; customer || owner ? widgets.add(invoicesBtn) : ""; widgets.add(termBtn); diff --git a/lib/pages/invoice/invoce_list.dart b/lib/pages/invoice/invoce_list.dart index 3f28280..eec9a21 100644 --- a/lib/pages/invoice/invoce_list.dart +++ b/lib/pages/invoice/invoce_list.dart @@ -65,7 +65,7 @@ class _InvoiceListState extends State { bottom: TabBar( unselectedLabelColor: Colors.grey, tabs: [ - Tab(text: "Packages"), + Tab(text: "Boxes"), Tab(text: "Pending"), Tab(text: "Paid"), ], diff --git a/lib/pages/invoice/invoice_editor.dart b/lib/pages/invoice/invoice_editor.dart index 8ce8efc..27b0334 100644 --- a/lib/pages/invoice/invoice_editor.dart +++ b/lib/pages/invoice/invoice_editor.dart @@ -1,3 +1,4 @@ +import 'package:fcs/model/main_model.dart'; import 'package:fcs/pages/invoice/package_addition.dart'; import 'package:fcs/theme/theme.dart'; import 'package:fcs/vo/invoice.dart'; @@ -86,6 +87,8 @@ class _InvoiceEditorState extends State { @override Widget build(BuildContext context) { + var mainModel = Provider.of(context); + return LocalProgress( inAsyncCall: _isLoading, child: Scaffold( @@ -246,7 +249,7 @@ class _InvoiceEditorState extends State { ], ), ExpansionTile( - title: Text('Package Informations'), + title: Text('Box Information'), children: [ Container( child: SingleChildScrollView( @@ -288,14 +291,14 @@ class _InvoiceEditorState extends State { ), ), ), - Container( + mainModel.isOwner()?Container( padding: EdgeInsets.only(top: 20), child: Align( alignment: Alignment.bottomRight, child: FloatingActionButton.extended( icon: Icon(Icons.add), label: Text(AppTranslations.of(context) - .text("invoice.add_package")), + .text("invoice.add_box")), backgroundColor: primaryColor, onPressed: () { Navigator.of(context) @@ -303,7 +306,7 @@ class _InvoiceEditorState extends State { }, ), ), - ), + ):Container(), SizedBox(height: 25), ], ), @@ -324,7 +327,7 @@ class _InvoiceEditorState extends State { }, ), ))) - : Container( + :mainModel.isCustomer()?Container():Container( child: Column( children: [ Align( @@ -351,7 +354,7 @@ class _InvoiceEditorState extends State { child: Container( width: 250, child: FlatButton( - child: Text('Confirm Payment'), + child: Text('Attach Payment Receipt'), color: primaryColor, textColor: Colors.white, onPressed: () { diff --git a/lib/pages/pickup_editor.dart b/lib/pages/pickup_editor.dart index 474e5e3..6a6443b 100644 --- a/lib/pages/pickup_editor.dart +++ b/lib/pages/pickup_editor.dart @@ -270,7 +270,7 @@ class _PickUpEditorState extends State { ], ), ExpansionTile( - title: Text('Package Informations'), + title: Text('Package Information'), children: [ Padding( padding: const EdgeInsets.only(left: 20.0), @@ -302,7 +302,7 @@ class _PickUpEditorState extends State { ], ), ExpansionTile( - title: Text('Recipient Informations'), + title: Text('Recipient Information'), children: [ Padding( padding: const EdgeInsets.only(left: 20.0), @@ -346,6 +346,7 @@ class _PickUpEditorState extends State { _recipientAddressEditingController)), ], ), + mainModel.isCustomer()?Container(): ExpansionTile( title: Text('For FCS'), children: [ diff --git a/lib/pages/shipment_rates.dart b/lib/pages/shipment_rates.dart index b6098b4..87b8e7a 100644 --- a/lib/pages/shipment_rates.dart +++ b/lib/pages/shipment_rates.dart @@ -109,7 +109,7 @@ class _ShipmentRatesState extends State { Navigator.of(context) .push(MaterialPageRoute(builder: (_) => Term())); }), - fcsButton(context, "Calculate", callack: () { + fcsButton(context, "Estimate shipping cost", callack: () { Navigator.of(context) .push(BottomUpPageRoute(ShipmentRatesCal())); }), diff --git a/lib/pages_fcs/box_editor.dart b/lib/pages_fcs/box_editor.dart new file mode 100644 index 0000000..4c3b174 --- /dev/null +++ b/lib/pages_fcs/box_editor.dart @@ -0,0 +1,407 @@ +import 'package:fcs/model/main_model.dart'; +import 'package:fcs/model_fcs/package_model.dart'; +import 'package:fcs/pages/invoice/package_addition.dart'; +import 'package:fcs/pages/util.dart'; +import 'package:fcs/vo/box.dart'; +import 'package:fcs/vo/package.dart'; +import 'package:fcs/widget/bottom_up_page_route.dart'; +import 'package:fcs/widget/local_text.dart'; +import 'package:fcs/widget/localization/app_translations.dart'; +import 'package:fcs/widget/my_data_table.dart'; +import 'package:fcs/widget/progress.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_icons/flutter_icons.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.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 '../theme/theme.dart'; + +class BoxEditor extends StatefulWidget { + final Box box; + BoxEditor({this.box}); + + @override + _BoxEditorState createState() => _BoxEditorState(); +} + +class _BoxEditorState extends State { + TextEditingController _addressEditingController = new TextEditingController(); + TextEditingController _fromTimeEditingController = + new TextEditingController(); + TextEditingController _toTimeEditingController = new TextEditingController(); + TextEditingController _noOfPackageEditingController = + new TextEditingController(); + TextEditingController _weightEditingController = new TextEditingController(); + + Box _box; + bool _isLoading = false; + List _images = [ + "assets/photos/1.jpg", + "assets/photos/2.jpg", + "assets/photos/3.jpg" + ]; + bool isNew; + + @override + void initState() { + super.initState(); + if (widget.box != null) { + _box = widget.box; + isNew = false; + // _addressEditingController.text = _pickUp.address; + // _fromTimeEditingController.text = _pickUp.fromTime; + // _toTimeEditingController.text = _pickUp.toTime; + // _noOfPackageEditingController.text = _pickUp.numberOfPackage.toString(); + // _weightEditingController.text = _pickUp.weight.toString(); + } else { + List packages = [ + PackageModel.packages[0], + PackageModel.packages[1], + PackageModel.packages[2] + ]; + + isNew = true; + _box = Box(rate: 0, weight: 0, packages: packages); + } + } + + @override + void dispose() { + super.dispose(); + } + + final DateFormat dateFormat = DateFormat("d MMM yyyy"); + List _models() { + // return []; + return _box.statusHistory + .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.status == "Processed" + ? Text("(Waiting for payment)", + style: TextStyle( + color: e.done ? primaryColor : Colors.grey, + fontSize: 14, + fontWeight: FontWeight.bold)) + : Container(), + 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(); + } + + @override + Widget build(BuildContext context) { + var mainModel = Provider.of(context); + + var images = isNew ? [] : _images; + return LocalProgress( + inAsyncCall: _isLoading, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + ), + backgroundColor: primaryColor, + title: Text(AppTranslations.of(context).text("box.edit.title")), + ), + body: Card( + child: Column( + children: [ + widget.box == null + ? Center( + child: Container( + padding: EdgeInsets.all(8), child: Text("New Box"))) + : Center(child: nameWidget(_box.packageNumber)), + Expanded( + child: ListView( + children: [ + ExpansionTile( + title: Text( + 'Shipment Information', + style: TextStyle( + color: primaryColor, fontWeight: FontWeight.bold), + ), + children: [ + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: DropdownButtonFormField( + value: _box.shipmentNumber, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Shipment Number', + icon: Icon(Ionicons.ios_airplane, + color: primaryColor) + // prefixIcon: Icon(Icons.play_arrow) + ), + items: ["A102", "A103", "A201", "A202"] + .map((e) => + DropdownMenuItem(child: Text(e), value: e)) + .toList(), + onChanged: (map) => {}, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: + isNew ? "FCS-0203-390-2" : "FCS-0203-390-2", + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'FCS_ID', + hintText: 'FCS_ID', + filled: true, + icon: Icon(Feather.user, color: primaryColor), + suffixIcon: IconButton( + icon: Icon(Icons.search), + onPressed: () {})), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: _box.receiverName, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Customer Name', + filled: true, + icon: Icon(Feather.user, color: Colors.white), + suffixIcon: IconButton( + icon: Icon(Icons.search), + onPressed: () {})), + ), + ), + SizedBox( + height: 30, + ) + ], + ), + ExpansionTile( + title: Text( + 'Packages', + style: TextStyle( + color: primaryColor, fontWeight: FontWeight.bold), + ), + children: [ + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: DropdownButtonFormField( + value: _box.packageType, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Cargo Type', + icon: Icon(Entypo.box, color: primaryColor)), + items: ["General", "Medicine", "Dangerous"] + .map((e) => + DropdownMenuItem(child: Text(e), value: e)) + .toList(), + onChanged: (map) => {}, + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: _box.weight.toString(), + textAlign: TextAlign.end, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Total Weight', + filled: true, + icon: Icon(FontAwesomeIcons.weightHanging, + color: primaryColor), + )), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: _box.rate.toString(), + textAlign: TextAlign.end, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Rate', + filled: true, + icon: Icon(FontAwesomeIcons.tag, + color: primaryColor), + )), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: _box.amount.toString(), + textAlign: TextAlign.end, + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Total Amount', + filled: true, + icon: Icon(FontAwesomeIcons.moneyBill, + color: primaryColor), + )), + ), + Container( + padding: EdgeInsets.only(top: 10), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: MyDataTable( + headingRowHeight: 40, + columnSpacing: 20, + columns: [ + MyDataColumn( + label: LocalText( + context, + "box.package.id", + color: Colors.grey, + ), + ), + MyDataColumn( + label: LocalText( + context, + "box.package.desc", + color: Colors.grey, + ), + ), + MyDataColumn( + label: LocalText( + context, + "box.package.market", + color: Colors.grey, + ), + ), + ], + rows: getPackageRow(context), + ), + ), + ), + mainModel.isOwner() + ? Container( + padding: EdgeInsets.only(top: 20), + child: Align( + alignment: Alignment.bottomRight, + child: FloatingActionButton.extended( + icon: Icon(Icons.add), + label: Text(AppTranslations.of(context) + .text("box.add_package")), + backgroundColor: primaryColor, + onPressed: () { + Navigator.of(context).push( + BottomUpPageRoute(PackageAddition())); + }, + ), + ), + ) + : Container(), + SizedBox(height: 25), + ], + ), + isNew + ? Container() + : ExpansionTile( + title: Text( + 'Status', + style: TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold), + ), + children: [ + Container( + height: 500, + padding: EdgeInsets.only(left: 20), + child: isNew + ? Container() + : Timeline( + children: _models(), + position: TimelinePosition.Left), + ), + ], + ) + ], + ), + ), + widget.box == null + ? Align( + alignment: Alignment.bottomCenter, + child: Center( + child: Container( + width: 250, + child: FlatButton( + child: Text('Create New Box'), + color: primaryColor, + textColor: Colors.white, + onPressed: () { + Navigator.pop(context); + }, + ), + ))) + : Container( + child: Column( + children: [ + Align( + alignment: Alignment.bottomCenter, + child: Center( + child: Container( + width: 250, + child: FlatButton( + child: Text('Complete packing'), + color: primaryColor, + textColor: Colors.white, + onPressed: () { + Navigator.pop(context); + }, + ), + ))), + ], + )) + ], + ), + ), + ), + ); + } + + List getPackageRow(BuildContext context) { + if (_box == null || _box.packages == null) { + return []; + } + return _box.packages.map((p) { + return MyDataRow( + onSelectChanged: (bool selected) {}, + cells: [ + MyDataCell(new Text( + p.id == null ? "" : p.id, + style: textStyle, + )), + MyDataCell( + new Text(p.cargoDesc, style: textStyle), + ), + MyDataCell( + new Text("${p.market}", style: textStyle), + ), + ], + ); + }).toList(); + } +} diff --git a/lib/pages_fcs/box_list.dart b/lib/pages_fcs/box_list.dart new file mode 100644 index 0000000..9d02ab8 --- /dev/null +++ b/lib/pages_fcs/box_list.dart @@ -0,0 +1,146 @@ +import 'package:fcs/model/pickup_model.dart'; +import 'package:fcs/model_fcs/box_model.dart'; +import 'package:fcs/model_fcs/package_model.dart'; +import 'package:fcs/pages/pickup_list_row.dart'; +import 'package:fcs/pages/search_page.dart'; +import 'package:fcs/pages_fcs/box_editor.dart'; +import 'package:fcs/pages_fcs/box_list_row.dart'; +import 'package:fcs/pages_fcs/package_editor.dart'; +import 'package:fcs/pages_fcs/package_list_row.dart'; +import 'package:fcs/vo/buyer.dart'; +import 'package:fcs/widget/bottom_up_page_route.dart'; +import 'package:fcs/widget/localization/app_translations.dart'; +import 'package:fcs/widget/progress.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../theme/theme.dart'; +import 'pickup_editor.dart'; + +class BoxList extends StatefulWidget { + @override + _BoxListState createState() => _BoxListState(); +} + +class _BoxListState extends State { + Buyer buyer; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return LocalProgress( + inAsyncCall: _isLoading, + child: DefaultTabController( + length: 2, + child: Scaffold( + appBar: AppBar( + centerTitle: true, + leading: new IconButton( + icon: new Icon(Icons.close), + onPressed: () => Navigator.of(context).pop(), + ), + backgroundColor: primaryColor, + title: Text(AppTranslations.of(context).text("boxes.title")), + actions: [ + IconButton( + icon: Icon( + Icons.search, + color: Colors.white, + ), + iconSize: 30, + onPressed: () => showPlacesSearch(context), + ), + ], + bottom: TabBar( + unselectedLabelColor: Colors.grey, + tabs: [ + Tab( + text: "Upcoming", + ), + Tab(text: "Delivered"), + ], + ), + ), + floatingActionButton: FloatingActionButton.extended( + onPressed: () { + _newPickup(); + }, + icon: Icon(Icons.add), + label: Text(AppTranslations.of(context).text("boxes.new")), + backgroundColor: primaryColor, + ), + body: TabBarView( + children: [ + _upComing(), + _completed(), + ], + )), + ), + ); + } + + _newPickup() { + Navigator.push( + context, + BottomUpPageRoute(BoxEditor()), + ); + } + + Widget _upComing() { + var boxModel = Provider.of(context); + return Column( + children: [ + Expanded( + child: new ListView.separated( + separatorBuilder: (context, index) => Divider( + color: Colors.black, + ), + scrollDirection: Axis.vertical, + padding: EdgeInsets.only(top: 15), + shrinkWrap: true, + itemCount: boxModel.upcoming.length, + itemBuilder: (BuildContext context, int index) { + return BoxListRow( + box: boxModel.upcoming[index], + isReadOnly: false, + ); + }), + ), + ], + ); + } + + Widget _completed() { + var boxModel = Provider.of(context); + return Column( + children: [ + Expanded( + child: new ListView.separated( + separatorBuilder: (context, index) => Divider( + color: Colors.black, + ), + scrollDirection: Axis.vertical, + padding: EdgeInsets.only(top: 15), + shrinkWrap: true, + itemCount: boxModel.completed.length, + itemBuilder: (BuildContext context, int index) { + return BoxListRow( + box: boxModel.completed[index], + isReadOnly: false, + ); + }), + ), + ], + ); + } +} diff --git a/lib/pages_fcs/box_list_row.dart b/lib/pages_fcs/box_list_row.dart new file mode 100644 index 0000000..ed67f36 --- /dev/null +++ b/lib/pages_fcs/box_list_row.dart @@ -0,0 +1,119 @@ +import 'package:fcs/pages/invoice/package_info.dart'; +import 'package:fcs/pages/util.dart'; +import 'package:fcs/pages_fcs/box_editor.dart'; +import 'package:fcs/pages_fcs/package_editor.dart'; +import 'package:fcs/vo/box.dart'; +import 'package:fcs/vo/package.dart'; +import 'package:fcs/widget/bottom_up_page_route.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class BoxListRow extends StatefulWidget { + final bool isReadOnly; + final Box box; + const BoxListRow({this.box, this.isReadOnly}); + + @override + _BoxListRowState createState() => _BoxListRowState(); +} + +class _BoxListRowState extends State { + final double dotSize = 15.0; + Box _box = new Box(); + final DateFormat dateFormat = new DateFormat("dd MMM yyyy"); + + @override + void initState() { + super.initState(); + _box = widget.box; + } + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(left: 15, right: 15), + child: InkWell( + onTap: () { + if (widget.isReadOnly) { + // Navigator.push( + // context, + // BottomUpPageRoute(PackageInfo(package: _box)), + // ); + } else { + Navigator.push( + context, + BottomUpPageRoute(BoxEditor(box: _box)), + ); + } + }, + child: Row( + children: [ + Expanded( + child: new Padding( + padding: const EdgeInsets.symmetric(vertical: 16.0), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: new Text( + _box.packageNumber == null + ? '' + : _box.packageNumber, + style: new TextStyle( + fontSize: 15.0, color: Colors.black), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 10.0, top: 10), + child: new Text( + dateFormat.format(_box.arrivedDate), + style: new TextStyle( + fontSize: 15.0, color: Colors.grey), + ), + ) + ], + ), + ), + ], + ), + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.all(0), + child: getStatus(_box.status), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), + child: Row( + children: [ + new Text( + _box.weight == null + ? '' + : _box.weight.toString() + 'lb - ', + style: + new TextStyle(fontSize: 15.0, color: Colors.grey), + ), + new Text( + _box.price == null + ? "" + : "\$ " + _box.price.toString(), + style: + new TextStyle(fontSize: 15.0, color: Colors.grey), + ), + ], + ), + ), + ], + ) + ], + ), + ), + ); + } +} diff --git a/lib/pages_fcs/package_editor.dart b/lib/pages_fcs/package_editor.dart index ded5c8a..dd51f3c 100644 --- a/lib/pages_fcs/package_editor.dart +++ b/lib/pages_fcs/package_editor.dart @@ -60,43 +60,6 @@ class _PackageEditorState extends State { } final DateFormat dateFormat = DateFormat("d MMM yyyy"); - List _models() { - return _package.statusHistory - .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.status == "Processed" - ? Text("(Waiting for payment)", - style: TextStyle( - color: e.done ? primaryColor : Colors.grey, - fontSize: 14, - fontWeight: FontWeight.bold)) - : Container(), - 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(); - } @override Widget build(BuildContext context) { @@ -116,12 +79,13 @@ class _PackageEditorState extends State { body: Card( child: Column( children: [ - widget.package == null + isNew ? Container() : Center(child: nameWidget(_package.market)), + isNew ? Center( child: Container( padding: EdgeInsets.all(8), child: Text("New Package"))) - : Center(child: nameWidget(_package.packageNumber)), + : Center(child: nameWidget(_package.trackingID)), Expanded( child: ListView( children: [ @@ -134,26 +98,49 @@ class _PackageEditorState extends State { children: [ Padding( padding: const EdgeInsets.only(left: 20.0, right: 20), - child: DropdownButtonFormField( - value: _package.shipmentNumber, + child: TextFormField( + initialValue: isNew ? "" : "PKG2039", decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Shipment Number', - icon: Icon(Ionicons.ios_airplane, - color: primaryColor) - // prefixIcon: Icon(Icons.play_arrow) - ), - items: ["A102", "A103", "A201", "A202"] - .map((e) => - DropdownMenuItem(child: Text(e), value: e)) - .toList(), - onChanged: (map) => {}, + fillColor: Colors.white, + labelText: 'Package ID', + hintText: 'Package ID', + filled: true, + icon: Icon(MaterialCommunityIcons.id_card, + color: primaryColor), + ), ), ), Padding( padding: const EdgeInsets.only(left: 20.0, right: 20), child: TextFormField( - initialValue: isNew ? "" : "FCS383-283-1", + initialValue: isNew ? "" : "Amazon", + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Market', + hintText: 'FCS_ID', + filled: true, + icon: Icon(MaterialCommunityIcons.cart_outline, + color: primaryColor), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: isNew ? "" : "zdf-sdfl-37sdfks", + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Tracking ID', + hintText: 'Tracking ID', + filled: true, + icon: Icon(Octicons.package, color: primaryColor), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 20.0, right: 20), + child: TextFormField( + initialValue: isNew ? "" : "FCS-0203-390-2", decoration: InputDecoration( fillColor: Colors.white, labelText: 'FCS_ID', @@ -182,7 +169,7 @@ class _PackageEditorState extends State { Padding( padding: const EdgeInsets.only(left: 20.0, right: 20), child: TextFormField( - initialValue: isNew ? "" : "P0203", + initialValue: isNew ? "" : "", decoration: InputDecoration( fillColor: Colors.white, labelText: 'Pickup ID', @@ -196,154 +183,90 @@ class _PackageEditorState extends State { ), ], ), - ExpansionTile( - title: Text( - 'Processing', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20), - child: DropdownButtonFormField( - value: _package.packageType, - decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Cargo Type', - icon: Icon(Entypo.box, color: primaryColor)), - items: ["General", "Medicine", "Dangerous"] - .map((e) => - DropdownMenuItem(child: Text(e), value: e)) - .toList(), - onChanged: (map) => {}, - ), - ), - Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20), - child: TextFormField( - initialValue: - isNew ? "" : _package.cargoDesc.toString(), - decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Description', - filled: true, - icon: Icon(MaterialIcons.description, - color: primaryColor), - )), - ), - Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20), - child: TextFormField( - initialValue: _package.weight.toString(), - textAlign: TextAlign.end, - decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Weight', - filled: true, - icon: Icon(FontAwesomeIcons.weightHanging, - color: primaryColor), - )), - ), - Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20), - child: TextFormField( - initialValue: _package.rate.toString(), - textAlign: TextAlign.end, - decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Rate', - filled: true, - icon: Icon(FontAwesomeIcons.tag, - color: primaryColor), - )), - ), - Padding( - padding: const EdgeInsets.only(left: 20.0, right: 20), - child: TextFormField( - initialValue: _package.amount.toString(), - textAlign: TextAlign.end, - decoration: InputDecoration( - fillColor: Colors.white, - labelText: 'Amount', - filled: true, - icon: Icon(FontAwesomeIcons.moneyBill, - color: primaryColor), - )), - ), - ], - ), - ExpansionTile( - title: Text( - 'Photos', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Container( - height: 130, - width: 500, - child: ListView.separated( - separatorBuilder: (context, index) => Divider( - color: Colors.black, + isNew + ? Container() + : ExpansionTile( + title: Text( + 'Processing', + style: TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold), ), - 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.asset(images[index], - width: 50, height: 50), - ), - ); - } - }, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 20.0, right: 20), + child: TextFormField( + initialValue: isNew + ? "" + : _package.cargoDesc.toString(), + decoration: InputDecoration( + fillColor: Colors.white, + labelText: 'Description', + filled: true, + icon: Icon(MaterialIcons.description, + color: primaryColor), + )), + ), + ], + ), + isNew + ? Container() + : ExpansionTile( + title: Text( + 'Photos', + style: TextStyle( + color: primaryColor, + fontWeight: FontWeight.bold), + ), + children: [ + 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.asset(images[index], + width: 50, height: 50), + ), + ); + } + }, + ), + ), + ], ), - ), - ], - ), - ExpansionTile( - title: Text( - 'Status', - style: TextStyle( - color: primaryColor, fontWeight: FontWeight.bold), - ), - children: [ - Container( - height: 500, - padding: EdgeInsets.only(left: 20), - child: isNew - ? Container() - : Timeline( - children: _models(), - position: TimelinePosition.Left), - ), - ], - ) ], ), ), diff --git a/lib/pages_fcs/package_list.dart b/lib/pages_fcs/package_list.dart index f7d4ccc..fc744e3 100644 --- a/lib/pages_fcs/package_list.dart +++ b/lib/pages_fcs/package_list.dart @@ -62,9 +62,9 @@ class _PackageListState extends State { unselectedLabelColor: Colors.grey, tabs: [ Tab( - text: "Upcoming", + text: "Received", ), - Tab(text: "Completed"), + Tab(text: "Processed"), ], ), ), diff --git a/lib/pages_fcs/package_list_row.dart b/lib/pages_fcs/package_list_row.dart index 3a6020a..7f264ae 100644 --- a/lib/pages_fcs/package_list_row.dart +++ b/lib/pages_fcs/package_list_row.dart @@ -58,21 +58,29 @@ class _PackageListRowtate extends State { Padding( padding: const EdgeInsets.only(left: 8.0), child: new Text( - _package.packageNumber == null - ? '' - : _package.packageNumber, + _package.id == null ? '' : _package.id, style: new TextStyle( fontSize: 15.0, color: Colors.black), ), ), Padding( - padding: const EdgeInsets.only(left: 10.0, top: 10), + padding: const EdgeInsets.only(left: 8.0), child: new Text( - dateFormat.format(_package.arrivedDate), + _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,7 +92,10 @@ class _PackageListRowtate extends State { children: [ Padding( padding: const EdgeInsets.all(0), - child: getStatus(_package.status), + child: new Text( + dateFormat.format(_package.arrivedDate), + style: new TextStyle(fontSize: 15.0, color: Colors.grey), + ), ), Padding( padding: const EdgeInsets.only(left: 8.0, top: 5, bottom: 5), diff --git a/lib/vo/box.dart b/lib/vo/box.dart new file mode 100644 index 0000000..81f7414 --- /dev/null +++ b/lib/vo/box.dart @@ -0,0 +1,61 @@ +import 'package.dart'; + +class Status { + String status; + DateTime date; + bool done; + Status({this.status, this.date, this.done}); +} + +class Box { + String id; + String shipmentNumber; + String senderFCSID; + String senderName; + String receiverFCSID; + String receiverName; + String receiverAddress; + String receiverNumber; + String boxNumber; + String status; + String cargoDesc; + + int rate; + int weight; + String packageType; + String pickUpID; + List photos; + String remark; + DateTime arrivedDate; + + List packages; + + int get amount => rate != null && weight != null ? rate * weight : 0; + + String get packageNumber => + shipmentNumber + "-" + receiverNumber + " #" + boxNumber; + double get price => rate.toDouble() * weight; + + List statusHistory; + + Box( + {this.id, + this.shipmentNumber, + this.senderFCSID, + this.senderName, + this.receiverFCSID, + this.receiverName, + this.receiverNumber, + this.receiverAddress, + this.boxNumber, + this.rate, + this.weight, + this.packageType, + this.pickUpID, + this.remark, + this.status, + this.arrivedDate, + this.cargoDesc, + this.statusHistory, + this.packages}); +} diff --git a/lib/vo/package.dart b/lib/vo/package.dart index 39d6105..88e8ded 100644 --- a/lib/vo/package.dart +++ b/lib/vo/package.dart @@ -1,9 +1,9 @@ -class Status { - String status; - DateTime date; - bool done; - Status({this.status, this.date, this.done}); -} +// class Status { +// String status; +// DateTime date; +// bool done; +// Status({this.status, this.date, this.done}); +// } class Package { String id; @@ -17,6 +17,8 @@ class Package { String boxNumber; String status; String cargoDesc; + String market; + String trackingID; int rate; int weight; @@ -32,7 +34,7 @@ class Package { shipmentNumber + "-" + receiverNumber + " #" + boxNumber; double get price => rate.toDouble() * weight; - List statusHistory; + // List statusHistory; Package( {this.id, @@ -52,5 +54,8 @@ class Package { this.status, this.arrivedDate, this.cargoDesc, - this.statusHistory}); + this.market, + this.trackingID + // this.statusHistory + }); }