clean up
This commit is contained in:
163
lib/app.dart
163
lib/app.dart
@@ -1,87 +1,45 @@
|
||||
import 'package:fcs/fcs/common/localization/app_translations_delegate.dart';
|
||||
import 'package:fcs/fcs/common/localization/transalation.dart';
|
||||
import 'package:fcs/fcs/common/pages/contact/model/contact_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/customer/model/customer_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/faq/model/faq_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/initial_language_selection.dart';
|
||||
import 'package:fcs/fcs/common/pages/market/model/market_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/model/language_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/model/main_model.dart' as fcs;
|
||||
import 'package:fcs/fcs/common/pages/package/model/package_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/package/model/shipment_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/payment_methods/model/payment_method_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/staff/model/staff_model.dart';
|
||||
import 'package:fcs/fcs/common/pages/term/model/term_model.dart';
|
||||
import 'package:fcs/model/buyer_model.dart';
|
||||
import 'package:fcs/model/delivery_model.dart';
|
||||
import 'package:fcs/model/discount_model.dart';
|
||||
import 'package:fcs/model/manual_model.dart';
|
||||
import 'package:fcs/model/notification_model.dart';
|
||||
import 'package:fcs/model/pd_model.dart';
|
||||
import 'package:fcs/model/reg_model.dart';
|
||||
import 'package:fcs/model/report_model.dart';
|
||||
import 'package:fcs/model/storage_model.dart';
|
||||
import 'package:fcs/model/test_model.dart';
|
||||
import 'package:fcs/pages/email_page.dart';
|
||||
import 'package:fcs/pages/login_page.dart';
|
||||
import 'package:fcs/localization/app_translations_delegate.dart';
|
||||
import 'package:fcs/localization/transalation.dart';
|
||||
import 'package:fcs/pages/box/model/box_model.dart';
|
||||
import 'package:fcs/pages/chat/model/message_model.dart';
|
||||
import 'package:fcs/pages/contact/model/contact_model.dart';
|
||||
import 'package:fcs/pages/customer/model/customer_model.dart';
|
||||
import 'package:fcs/pages/discount/model/discount_model.dart';
|
||||
import 'package:fcs/pages/faq/model/faq_model.dart';
|
||||
import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart';
|
||||
import 'package:fcs/pages/main/home_page.dart';
|
||||
import 'package:fcs/pages/main/initial_language_selection.dart';
|
||||
import 'package:fcs/pages/invoice/model/invoice_model.dart';
|
||||
import 'package:fcs/pages/market/model/market_model.dart';
|
||||
import 'package:fcs/pages/main/model/language_model.dart';
|
||||
import 'package:fcs/pages/main/model/main_model.dart';
|
||||
import 'package:fcs/pages/package/model/package_model.dart';
|
||||
import 'package:fcs/pages/payment_methods/model/payment_method_model.dart';
|
||||
import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
|
||||
import 'package:fcs/pages/shipment/model/pickup_model.dart';
|
||||
import 'package:fcs/pages/shipment_address/model/shipment_address_model.dart';
|
||||
import 'package:fcs/pages/main/splash_page.dart';
|
||||
import 'package:fcs/pages/staff/model/staff_model.dart';
|
||||
import 'package:fcs/pages/term/model/term_model.dart';
|
||||
import 'package:fcs/pages/main/welcome_page.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'fcs/common/pages/chat/model/message_model.dart';
|
||||
import 'fcs/common/pages/home_page.dart';
|
||||
import 'fcs/common/pages/splash_page.dart';
|
||||
import 'fcs/common/pages/welcome_page.dart';
|
||||
import 'model/announcement_model.dart';
|
||||
import 'model/chart_model.dart';
|
||||
import 'model/device_model.dart';
|
||||
import 'model/do_model.dart';
|
||||
import 'model/invoice_model.dart';
|
||||
import 'model/log_model.dart';
|
||||
import 'model/main_model.dart';
|
||||
import 'model/pickup_model.dart';
|
||||
import 'model/po_model.dart';
|
||||
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/term.dart';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
@override
|
||||
_AppState createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> {
|
||||
final fcs.MainModel mainModel2 = new fcs.MainModel();
|
||||
final MainModel mainModel = new MainModel();
|
||||
final ContactModel contactModel = new ContactModel();
|
||||
final TermModel termModel = new TermModel();
|
||||
final MainModel mainModel = new MainModel();
|
||||
final FAQModel faqModel = new FAQModel();
|
||||
final PaymentMethodModel paymentMethodModel = new PaymentMethodModel();
|
||||
|
||||
final UserModel userModel = new UserModel();
|
||||
final ProductModel productModel = new ProductModel();
|
||||
final POSubmissionModel poSubmissionModel = new POSubmissionModel();
|
||||
final DOModel doModel = new DOModel();
|
||||
final FcsShipmentModel fcsShipmentModel = new FcsShipmentModel();
|
||||
final LanguageModel lanuguageModel = new LanguageModel();
|
||||
final StorageModel storageModel = new StorageModel();
|
||||
final PDModel pdModel = new PDModel();
|
||||
final RegModel regModel = new RegModel();
|
||||
final BuyerModel buyerModel = new BuyerModel();
|
||||
final NotificationModel notificationModel = new NotificationModel();
|
||||
final ChartModel chartModel = new ChartModel();
|
||||
final DeliveryModel deliveryModel = new DeliveryModel();
|
||||
final ManualModel manualModel = new ManualModel();
|
||||
final TestModel testModel = new TestModel();
|
||||
final LogModel logModel = new LogModel();
|
||||
final PhoneDeviceModel phoneDeviceModel = new PhoneDeviceModel();
|
||||
final ReportModel reportModel = new ReportModel();
|
||||
final AnnouncementModel announcementModel = new AnnouncementModel();
|
||||
final ReportUserModel reportUserModel = new ReportUserModel();
|
||||
final PickUpModel pickUpModel = new PickUpModel();
|
||||
final ShipmentRateModel shipmentRateModel = new ShipmentRateModel();
|
||||
final BoxModel boxModel = new BoxModel();
|
||||
@@ -90,54 +48,31 @@ class _AppState extends State<App> {
|
||||
final CustomerModel customerModel = new CustomerModel();
|
||||
final DiscountModel discountModel = new DiscountModel();
|
||||
final StaffModel staffModel = new StaffModel();
|
||||
final ShipmentModel shipmentModel = new ShipmentModel();
|
||||
final ShipmentAddressModel shipmentAddressModel = new ShipmentAddressModel();
|
||||
final PackageModel packageModel = new PackageModel();
|
||||
final MarketModel marketModel = new MarketModel();
|
||||
|
||||
AppTranslationsDelegate _newLocaleDelegate;
|
||||
static FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
mainModel2
|
||||
mainModel
|
||||
..addModel(customerModel)
|
||||
..addModel(staffModel)
|
||||
..addModel(shipmentModel)
|
||||
..addModel(shipmentAddressModel)
|
||||
..addModel(packageModel)
|
||||
..addModel(messageModel)
|
||||
..addModel(fcsShipmentModel)
|
||||
..addModel(discountModel)
|
||||
..addModel(shipmentRateModel)
|
||||
..addModel(boxModel)
|
||||
..addModel(pickUpModel)
|
||||
..addModel(invoiceModel)
|
||||
..addModel(marketModel);
|
||||
|
||||
_newLocaleDelegate = AppTranslationsDelegate(newLocale: null);
|
||||
Translation().onLocaleChanged = onLocaleChange;
|
||||
mainModel
|
||||
..addModel(userModel)
|
||||
..addModel(storageModel)
|
||||
..addModel(regModel)
|
||||
..addModel(poSubmissionModel)
|
||||
..addModel(doModel)
|
||||
..addModel(productModel)
|
||||
..addModel(pdModel)
|
||||
..addModel(buyerModel)
|
||||
..addModel(notificationModel)
|
||||
..addModel(chartModel)
|
||||
..addModel(deliveryModel)
|
||||
..addModel(logModel)
|
||||
..addModel(manualModel)
|
||||
..addModel(phoneDeviceModel)
|
||||
..addModel(regModel)
|
||||
..addModel(announcementModel)
|
||||
..addModel(reportModel)
|
||||
..addModel(testModel)
|
||||
..addModel(reportUserModel)
|
||||
..addModel(pickUpModel)
|
||||
..addModel(shipmentRateModel)
|
||||
..addModel(boxModel)
|
||||
..addModel(shipmentRateModel)
|
||||
..addModel(invoiceModel)
|
||||
..addModel(discountModel);
|
||||
this.mainModel.init();
|
||||
}
|
||||
|
||||
void onLocaleChange(Locale locale) {
|
||||
@@ -151,11 +86,6 @@ class _AppState extends State<App> {
|
||||
'/': (_) => SplashScreen(),
|
||||
'/welcome': (_) => WelcomePage(),
|
||||
'/home': (_) => HomePage(),
|
||||
'/term': (context) => Term(
|
||||
agreePage: true,
|
||||
),
|
||||
'/login': (context) => LoginPage(),
|
||||
'/email': (context) => EmailPage(),
|
||||
'/language_selection': (context) => InitialLanguageSelectionPage(),
|
||||
};
|
||||
return routes;
|
||||
@@ -166,40 +96,23 @@ class _AppState extends State<App> {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider.value(value: mainModel),
|
||||
ChangeNotifierProvider.value(value: userModel),
|
||||
ChangeNotifierProvider.value(value: productModel),
|
||||
ChangeNotifierProvider.value(value: staffModel),
|
||||
ChangeNotifierProvider.value(value: poSubmissionModel),
|
||||
ChangeNotifierProvider.value(value: doModel),
|
||||
ChangeNotifierProvider.value(value: storageModel),
|
||||
ChangeNotifierProvider.value(value: pdModel),
|
||||
ChangeNotifierProvider.value(value: lanuguageModel),
|
||||
ChangeNotifierProvider.value(value: regModel),
|
||||
ChangeNotifierProvider.value(value: buyerModel),
|
||||
ChangeNotifierProvider.value(value: notificationModel),
|
||||
ChangeNotifierProvider.value(value: chartModel),
|
||||
ChangeNotifierProvider.value(value: deliveryModel),
|
||||
ChangeNotifierProvider.value(value: logModel),
|
||||
ChangeNotifierProvider.value(value: phoneDeviceModel),
|
||||
ChangeNotifierProvider.value(value: reportModel),
|
||||
ChangeNotifierProvider.value(value: announcementModel),
|
||||
ChangeNotifierProvider.value(value: reportUserModel),
|
||||
ChangeNotifierProvider.value(value: pickUpModel),
|
||||
ChangeNotifierProvider.value(value: shipmentRateModel),
|
||||
ChangeNotifierProvider.value(value: shipmentModel),
|
||||
ChangeNotifierProvider.value(value: shipmentAddressModel),
|
||||
ChangeNotifierProvider.value(value: packageModel),
|
||||
ChangeNotifierProvider.value(value: boxModel),
|
||||
ChangeNotifierProvider.value(value: messageModel),
|
||||
ChangeNotifierProvider.value(value: invoiceModel),
|
||||
ChangeNotifierProvider.value(value: customerModel),
|
||||
ChangeNotifierProvider.value(value: discountModel),
|
||||
ChangeNotifierProvider.value(value: testModel),
|
||||
ChangeNotifierProvider.value(value: mainModel2),
|
||||
ChangeNotifierProvider.value(value: contactModel),
|
||||
ChangeNotifierProvider.value(value: termModel),
|
||||
ChangeNotifierProvider.value(value: faqModel),
|
||||
ChangeNotifierProvider.value(value: paymentMethodModel),
|
||||
ChangeNotifierProvider.value(value: marketModel),
|
||||
ChangeNotifierProvider.value(value: fcsShipmentModel),
|
||||
],
|
||||
child: Consumer<LanguageModel>(
|
||||
builder: (context, value, child) {
|
||||
@@ -224,9 +137,7 @@ class _AppState extends State<App> {
|
||||
routes: route(context),
|
||||
localizationsDelegates: [
|
||||
_newLocaleDelegate,
|
||||
//provides localised strings
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
//provides RTL support
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: Translation().supportedLocales());
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:charts_flutter/flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/charts/qtyby_customer_table.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/product_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
class BarChart extends StatefulWidget {
|
||||
@override
|
||||
_BarChartState createState() => _BarChartState();
|
||||
}
|
||||
|
||||
class _BarChartState extends State<BarChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
List<POChartData> chartSummary = new List();
|
||||
List<charts.Series<POChartData, String>> series;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var chartModel = Provider.of<ChartModel>(context, listen: false);
|
||||
this.chartSummary = chartModel.chartSummary;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var productModel = Provider.of<ProductModel>(context);
|
||||
if (this.chartSummary.isNotEmpty) {
|
||||
this.chartSummary.forEach((s) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == s.productID) {
|
||||
s.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this
|
||||
.chartSummary
|
||||
.sort((s1, s2) => s1.displayOrder.compareTo(s2.displayOrder));
|
||||
}
|
||||
List<charts.Series<POChartData, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: this.chartSummary,
|
||||
domainFn: (POChartData series, _) => series.productName,
|
||||
measureFn: (POChartData series, _) => series.balanceQty,
|
||||
colorFn: (POChartData series, _) =>
|
||||
charts.ColorUtil.fromDartColor(series.getColor),
|
||||
labelAccessorFn: (POChartData series, _) =>
|
||||
'${numberFormatter.format(series.balanceQty)}'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, 'product.balance_qty',
|
||||
color: primaryColor, fontSize: 16),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.refresh,
|
||||
color: primaryColor,
|
||||
),
|
||||
onPressed: () {
|
||||
_load();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.BarChart(
|
||||
series,
|
||||
animate: true,
|
||||
vertical: false,
|
||||
defaultRenderer: new charts.BarRendererConfig(
|
||||
barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
labelPosition: charts.BarLabelPosition.auto,
|
||||
),
|
||||
),
|
||||
selectionModels: [
|
||||
SelectionModelConfig(changedListener: (SelectionModel model) {
|
||||
final selectedDatum = model.selectedDatum;
|
||||
if (selectedDatum.isNotEmpty) {
|
||||
selectedDatum.forEach((charts.SeriesDatum datumPair) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => QtyByCustomerTable(
|
||||
poChartData: datumPair.datum,
|
||||
)),
|
||||
);
|
||||
});
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
var _s = await chartModel.loadSummary();
|
||||
setState(() {
|
||||
this.chartSummary = _s ?? [];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
import 'delivery_do_line_detail.dart';
|
||||
|
||||
class DODeliveryLineChart extends StatefulWidget {
|
||||
@override
|
||||
_DODeliveryLineChartState createState() => _DODeliveryLineChartState();
|
||||
}
|
||||
|
||||
class _DODeliveryLineChartState extends State<DODeliveryLineChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<Data, DateTime>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getDeliveryDo(),
|
||||
domainFn: (Data series, _) => series.date,
|
||||
measureFn: (Data series, _) => series.count,
|
||||
colorFn: (_, __) => charts.ColorUtil.fromDartColor(primaryColor),
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "delivery.do.title",
|
||||
color: primaryColor, fontSize: 16),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"delivery.do.details",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => DODeliveryLineDetail()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.TimeSeriesChart(
|
||||
series,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DODeliveryLineDetail extends StatefulWidget {
|
||||
const DODeliveryLineDetail();
|
||||
@override
|
||||
_DODeliveryLineDetailState createState() => _DODeliveryLineDetailState();
|
||||
}
|
||||
|
||||
class _DODeliveryLineDetailState extends State<DODeliveryLineDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'delivery.do.counts',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "delivery.date")),
|
||||
MyDataColumn(label: LocalText(context, "delivery.do.count")),
|
||||
],
|
||||
rows: getProductRow(chartModel.revenue.getDeliveryDo()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Data> doList) {
|
||||
return doList.map((d) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(dateFormatter.format(d.date), style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
numberFormatter.format(d.count),
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
import 'delivery_do_summary_details.dart';
|
||||
|
||||
class DeliveryDoSummaryChart extends StatefulWidget {
|
||||
@override
|
||||
_DeliveryDoSummaryChartState createState() => _DeliveryDoSummaryChartState();
|
||||
}
|
||||
|
||||
class _DeliveryDoSummaryChartState extends State<DeliveryDoSummaryChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<Data, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getDeliveryDoSummary(),
|
||||
domainFn: (Data series, _) => "${series.totalDay}days",
|
||||
measureFn: (Data series, _) => series.totalCount,
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.totalCount)}'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "delivery.do.summary",
|
||||
color: primaryColor, fontSize: 16),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"delivery.do.details",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => DeliveryDoSummaryDetail()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.BarChart(
|
||||
series,
|
||||
animate: true,
|
||||
vertical: false,
|
||||
defaultRenderer: new charts.BarRendererConfig(
|
||||
barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
labelPosition: charts.BarLabelPosition.auto,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DeliveryDoSummaryDetail extends StatefulWidget {
|
||||
const DeliveryDoSummaryDetail();
|
||||
@override
|
||||
_DeliveryDoSummaryDetailState createState() =>
|
||||
_DeliveryDoSummaryDetailState();
|
||||
}
|
||||
|
||||
class _DeliveryDoSummaryDetailState extends State<DeliveryDoSummaryDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'delivery.do.sum.counts',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "delivery.days")),
|
||||
MyDataColumn(label: LocalText(context, "delivery.do.count")),
|
||||
],
|
||||
rows: getProductRow(chartModel.revenue.getDeliveryDoSummary()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Data> doList) {
|
||||
return doList.map((d) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(d.totalDay.toString(), style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
numberFormatter.format(d.totalCount),
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
import 'delivery_line_data.dart';
|
||||
|
||||
class DeliveryBarChart extends StatefulWidget {
|
||||
@override
|
||||
_DeliveryBarChartState createState() => _DeliveryBarChartState();
|
||||
}
|
||||
|
||||
class _DeliveryBarChartState extends State<DeliveryBarChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<Data, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getDelivery(),
|
||||
domainFn: (Data series, _) =>
|
||||
"${series.date.day}-${series.date.month}-${series.date.year}",
|
||||
measureFn: (Data series, _) => series.amount,
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.amount)}'),
|
||||
];
|
||||
|
||||
List<charts.Series<Data, DateTime>> seriesLine = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getDelivery(),
|
||||
domainFn: (Data series, _) => series.date,
|
||||
measureFn: (Data series, _) => series.amount,
|
||||
colorFn: (_, __) => charts.ColorUtil.fromDartColor(primaryColor),
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.amount)}',
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "delivery", color: primaryColor, fontSize: 16),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"delivery.detail",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => DeliveryBarData()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.TimeSeriesChart(
|
||||
seriesLine,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
),
|
||||
),
|
||||
// Expanded(
|
||||
// child: charts.BarChart(
|
||||
// series,
|
||||
// animate: true,
|
||||
// vertical: true,
|
||||
// defaultRenderer: new charts.BarRendererConfig(
|
||||
// barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
// labelPosition: charts.BarLabelPosition.auto,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import 'delivery_line_detail.dart';
|
||||
|
||||
class DeliveryBarData extends StatefulWidget {
|
||||
const DeliveryBarData();
|
||||
@override
|
||||
_DeliveryBarDataState createState() => _DeliveryBarDataState();
|
||||
}
|
||||
|
||||
class _DeliveryBarDataState extends State<DeliveryBarData> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'delivery.data.title',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "delivery.date")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "delivery.qty"), numeric: true),
|
||||
],
|
||||
rows: getProductRow(chartModel.revenue.getDelivery()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Data> doList) {
|
||||
return doList.map((d) {
|
||||
var r = MyDataRow(
|
||||
onSelectChanged: (bool selected) async {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => DeliveryBarDetail(d.date)),
|
||||
);
|
||||
},
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(dateFormatter.format(d.date), style: textStyle),
|
||||
),
|
||||
MyDataCell(NumberCell(d.amount)),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/do_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/do.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DeliveryBarDetail extends StatefulWidget {
|
||||
final DateTime date;
|
||||
const DeliveryBarDetail(this.date);
|
||||
@override
|
||||
_DeliveryBarDetailState createState() => _DeliveryBarDetailState();
|
||||
}
|
||||
|
||||
class _DeliveryBarDetailState extends State<DeliveryBarDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd-MMM-yyyy');
|
||||
bool _isLoading = false;
|
||||
List<DOSubmission> dos = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
DOModel dOModel = Provider.of<DOModel>(context, listen: false);
|
||||
dOModel.getDOForDelivery(widget.date).then((dos) {
|
||||
setState(() {
|
||||
this.dos = dos;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'delivery.detail.title',
|
||||
translationVariables: [dateFormatter.format(widget.date)],
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 3),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "do.name")),
|
||||
MyDataColumn(label: LocalText(context, "do.do_num")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "do.quantity"), numeric: true),
|
||||
],
|
||||
rows: getProductRow(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow() {
|
||||
return dos.map((d) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(d.userName, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(d.doNumber, style: textStyle),
|
||||
),
|
||||
MyDataCell(NumberCell(d.totalQty)),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'delivery_summary_detail.dart';
|
||||
|
||||
class DeliverySummary extends StatefulWidget {
|
||||
@override
|
||||
_DeliverySummaryState createState() => _DeliverySummaryState();
|
||||
}
|
||||
|
||||
class _DeliverySummaryState extends State<DeliverySummary> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<Data, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getDeliverySummary(),
|
||||
domainFn: (Data series, _) => "${series.totalDay}days",
|
||||
measureFn: (Data series, _) => series.totalAmount,
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.totalAmount)}'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "delivery.summary",
|
||||
color: primaryColor, fontSize: 16),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"delivery.detail",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (_) => DeliverySummaryDetail()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.BarChart(
|
||||
series,
|
||||
animate: true,
|
||||
vertical: false,
|
||||
defaultRenderer: new charts.BarRendererConfig(
|
||||
barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
labelPosition: charts.BarLabelPosition.auto,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DeliverySummaryDetail extends StatefulWidget {
|
||||
const DeliverySummaryDetail();
|
||||
@override
|
||||
_DeliverySummaryDetailState createState() => _DeliverySummaryDetailState();
|
||||
}
|
||||
|
||||
class _DeliverySummaryDetailState extends State<DeliverySummaryDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'delivery.sum.amounts',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "delivery.days")),
|
||||
MyDataColumn(label: LocalText(context, "delivery.amount")),
|
||||
],
|
||||
rows: getProductRow(chartModel.revenue.getDeliverySummary()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Data> doList) {
|
||||
return doList.map((d) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(d.totalDay.toString(), style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
numberFormatter.format(d.totalAmount),
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po_do_count.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
import 'do_line_detail.dart';
|
||||
|
||||
class DOLineChart extends StatefulWidget {
|
||||
@override
|
||||
_DOLineChartState createState() => _DOLineChartState();
|
||||
}
|
||||
|
||||
class _DOLineChartState extends State<DOLineChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<CountData, DateTime>> series = [
|
||||
charts.Series(
|
||||
id: "pending",
|
||||
data: chartModel.podoCount.getDODataCounts("pending"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "approved",
|
||||
data: chartModel.podoCount.getDODataCounts("approved"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "canceled",
|
||||
data: chartModel.podoCount.getDODataCounts("canceled"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.gray.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "rejected",
|
||||
data: chartModel.podoCount.getDODataCounts("rejected"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "expired",
|
||||
data: chartModel.podoCount.getDODataCounts("expired"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.purple.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 5, 2, 5],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "closed",
|
||||
data: chartModel.podoCount.getDODataCounts("closed"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.indigo.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 5, 2, 5],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "do", color: primaryColor, fontSize: 16),
|
||||
LocalText(context, 'chart.30_days',
|
||||
color: primaryColor, fontSize: 14)
|
||||
],
|
||||
),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"do.details",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (_) => DOLineDetail()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.TimeSeriesChart(
|
||||
series,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
behaviors: [
|
||||
new charts.SeriesLegend(
|
||||
position: charts.BehaviorPosition.end,
|
||||
outsideJustification:
|
||||
charts.OutsideJustification.middleDrawArea,
|
||||
entryTextStyle: charts.TextStyleSpec(
|
||||
color: charts.Color(r: 127, g: 63, b: 191),
|
||||
fontFamily: 'Georgia',
|
||||
fontSize: 11),
|
||||
)
|
||||
],
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po_do_count.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class DOLineDetail extends StatefulWidget {
|
||||
const DOLineDetail();
|
||||
@override
|
||||
_DOLineDetailState createState() => _DOLineDetailState();
|
||||
}
|
||||
|
||||
class _DOLineDetailState extends State<DOLineDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'do.counts',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "chart.date"),
|
||||
LocalText(context, "do.total_count")
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: getRowTotalCountWidget(
|
||||
chartModel.podoCount.getDOTotalCounts()),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> getRowTotalCountWidget(List<TotalCountData> data) {
|
||||
return data.map((d) {
|
||||
return Container(
|
||||
child: ExpansionTile(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(dateFormatter.format(d.date), style: textStyle),
|
||||
Text(numberFormatter.format(d.totalCount), style: textStyle),
|
||||
],
|
||||
),
|
||||
children: <Widget>[
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "do.count.status")),
|
||||
MyDataColumn(label: LocalText(context, "do.count")),
|
||||
],
|
||||
rows: getStatusRow(d.detailCountsList),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<MyDataRow> getStatusRow(List<CountData> doList) {
|
||||
doList.sort((a, b) => a.status.compareTo(b.status));
|
||||
return doList.map((d) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(d.status, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
numberFormatter.format(d.count),
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../model/product_model.dart';
|
||||
|
||||
typedef void ProductClick(DateTime date, Map<String, int> measures);
|
||||
|
||||
class ProductsChart extends StatelessWidget {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
final ChartData chartData;
|
||||
final ProductClick productClick;
|
||||
const ProductsChart(this.chartData, {Key key, this.productClick})
|
||||
: super(key: key);
|
||||
factory ProductsChart.fromModel(ProductModel productModel,
|
||||
{ProductClick productClick}) {
|
||||
return new ProductsChart(_createData(productModel),
|
||||
productClick: productClick);
|
||||
}
|
||||
|
||||
static ChartData _createData(ProductModel productModel) {
|
||||
List<charts.Series<TimeSeriesSales, DateTime>> list = [];
|
||||
var min = 9999, max = 0;
|
||||
productModel.products.forEach((p) {
|
||||
List<TimeSeriesSales> data = [];
|
||||
if (p.priceHistory != null) {
|
||||
var dateKeys = {};
|
||||
p.priceHistory.entries.forEach((e) {
|
||||
dateKeys[DateTime.parse(e.key)] = e.value;
|
||||
});
|
||||
|
||||
var sortedKeys = dateKeys.keys.toList()..sort((a, b) => b.compareTo(a));
|
||||
sortedKeys.forEach((k) {
|
||||
var v = dateKeys[k];
|
||||
data.add(new TimeSeriesSales(k, v));
|
||||
if (v < min) min = v;
|
||||
if (v > max) max = v;
|
||||
});
|
||||
}
|
||||
|
||||
list.add(new charts.Series<TimeSeriesSales, DateTime>(
|
||||
id: p.name,
|
||||
colorFn: (_, __) => charts.ColorUtil.fromDartColor(Color(p.color)),
|
||||
domainFn: (TimeSeriesSales sales, _) => sales.time,
|
||||
measureFn: (TimeSeriesSales sales, _) => sales.sales,
|
||||
data: data,
|
||||
labelAccessorFn: (TimeSeriesSales series, _) =>
|
||||
'${numberFormatter.format(series.sales)}',
|
||||
measureFormatterFn: (TimeSeriesSales series, _) => (n) => "s",
|
||||
));
|
||||
});
|
||||
var chartData = ChartData(list, min, max);
|
||||
return chartData;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return charts.TimeSeriesChart(
|
||||
chartData.seriesList,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
selectionModels: [
|
||||
new charts.SelectionModelConfig(
|
||||
type: charts.SelectionModelType.info,
|
||||
updatedListener: _onSelectionChanged,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_onSelectionChanged(charts.SelectionModel model) {
|
||||
final selectedDatum = model.selectedDatum;
|
||||
if (selectedDatum.isNotEmpty) {
|
||||
var _time = selectedDatum.first.datum.time;
|
||||
Map<String, int> _measures = <String, int>{};
|
||||
|
||||
selectedDatum.forEach((charts.SeriesDatum datumPair) {
|
||||
_measures[datumPair.series.displayName] = datumPair.datum.sales;
|
||||
});
|
||||
if (productClick != null) {
|
||||
productClick(_time, _measures);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TimeSeriesSales {
|
||||
final DateTime time;
|
||||
final int sales;
|
||||
|
||||
TimeSeriesSales(this.time, this.sales);
|
||||
}
|
||||
|
||||
class ChartData {
|
||||
final List<charts.Series> seriesList;
|
||||
final num min, max;
|
||||
ChartData(this.seriesList, this.min, this.max);
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:charts_flutter/flutter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/charts/po_balance_table.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/product_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
class POBalanceChart extends StatefulWidget {
|
||||
@override
|
||||
_POBalanceChartState createState() => _POBalanceChartState();
|
||||
}
|
||||
|
||||
class _POBalanceChartState extends State<POBalanceChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
List<POChartData> chartSummary = new List();
|
||||
List<charts.Series<POChartData, String>> series;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var chartModel = Provider.of<ChartModel>(context, listen: false);
|
||||
if (mounted) {
|
||||
load(chartModel);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> load(ChartModel chartModel) async {
|
||||
var _u = await chartModel.loadPOBalancesForBuyer();
|
||||
if (_u == null) return;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
this.chartSummary = _u;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var productModel = Provider.of<ProductModel>(context);
|
||||
if (this.chartSummary.isNotEmpty) {
|
||||
this.chartSummary.forEach((s) {
|
||||
productModel.products.forEach((p) {
|
||||
if (p.id == s.productID) {
|
||||
s.displayOrder = p.displayOrder;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this
|
||||
.chartSummary
|
||||
.sort((s1, s2) => s1.displayOrder.compareTo(s2.displayOrder));
|
||||
}
|
||||
List<charts.Series<POChartData, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: this.chartSummary,
|
||||
domainFn: (POChartData series, _) => series.productName,
|
||||
measureFn: (POChartData series, _) => series.balanceQty,
|
||||
colorFn: (POChartData series, _) =>
|
||||
charts.ColorUtil.fromDartColor(series.getColor),
|
||||
labelAccessorFn: (POChartData series, _) =>
|
||||
'${numberFormatter.format(series.balanceQty)}'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, 'po.balances',
|
||||
color: primaryColor, fontSize: 16),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.refresh,
|
||||
color: primaryColor,
|
||||
),
|
||||
onPressed: () {
|
||||
_load();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.BarChart(
|
||||
series,
|
||||
animate: true,
|
||||
vertical: false,
|
||||
defaultRenderer: new charts.BarRendererConfig(
|
||||
barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
labelPosition: charts.BarLabelPosition.auto,
|
||||
),
|
||||
),
|
||||
selectionModels: [
|
||||
SelectionModelConfig(changedListener: (SelectionModel model) {
|
||||
final selectedDatum = model.selectedDatum;
|
||||
if (selectedDatum.isNotEmpty) {
|
||||
selectedDatum.forEach((charts.SeriesDatum datumPair) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => POBalanceTable(
|
||||
poChartData: datumPair.datum,
|
||||
)),
|
||||
);
|
||||
});
|
||||
}
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
var _s = await chartModel.loadPOBalancesForBuyer();
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
this.chartSummary = _s ?? [];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.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/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class POBalanceTable extends StatefulWidget {
|
||||
final POChartData poChartData;
|
||||
const POBalanceTable({Key key, this.poChartData}) : super(key: key);
|
||||
@override
|
||||
_POBalanceTableState createState() => _POBalanceTableState();
|
||||
}
|
||||
|
||||
class _POBalanceTableState extends State<POBalanceTable> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
List<POChartData> chartUser = new List();
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var chartModel = Provider.of<ChartModel>(context, listen: false);
|
||||
if (mounted) {
|
||||
load(chartModel);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> load(ChartModel chartModel) async {
|
||||
var _u = await chartModel.loadPOBalProductsForBuyer();
|
||||
setState(() {
|
||||
this.chartUser = _u;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<POChartData> data = this
|
||||
.chartUser
|
||||
.where((u) => u.productName == widget.poChartData.productName)
|
||||
.toList();
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(
|
||||
AppTranslations.of(context).text("product.qtys"),
|
||||
style: Provider.of<LanguageModel>(context).isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode'),
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 40,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "buyer.name")),
|
||||
MyDataColumn(label: LocalText(context, "buyer.product")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "buyer.balQty"), numeric: true),
|
||||
],
|
||||
rows: getProductRow(data),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<POChartData> poLines) {
|
||||
return poLines.map((p) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(p.userName, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
p.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(
|
||||
NumberCell(p.balanceQty),
|
||||
//new Text(numberFormatter.format(p.balanceQty), style: textStyle),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
class POBalanceChart_ extends StatefulWidget {
|
||||
@override
|
||||
_POBalanceChartState createState() => _POBalanceChartState();
|
||||
}
|
||||
|
||||
class _POBalanceChartState extends State<POBalanceChart_> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
List<POBuyerData> chartSummary = new List();
|
||||
List<charts.Series<POBuyerData, String>> series;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var chartModel = Provider.of<ChartModel>(context, listen: false);
|
||||
if (mounted) {
|
||||
load(chartModel);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> load(ChartModel chartModel) async {
|
||||
var _u = await chartModel.loadPOBalancesForBuyer_();
|
||||
if (_u == null) return;
|
||||
setState(() {
|
||||
this.chartSummary = _u;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<charts.Series<POBuyerData, String>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: this.chartSummary,
|
||||
domainFn: (POBuyerData series, _) => series.status,
|
||||
measureFn: (POBuyerData series, _) => series.amount,
|
||||
colorFn: (POBuyerData series, _) =>
|
||||
charts.ColorUtil.fromDartColor(series.getColor),
|
||||
labelAccessorFn: (POBuyerData series, _) =>
|
||||
'${numberFormatter.format(series.amount)}'),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, 'po.balances',
|
||||
color: primaryColor, fontSize: 16),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.refresh,
|
||||
color: primaryColor,
|
||||
),
|
||||
onPressed: () {
|
||||
_load();
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.BarChart(
|
||||
series,
|
||||
animate: true,
|
||||
vertical: false,
|
||||
defaultRenderer: new charts.BarRendererConfig(
|
||||
barRendererDecorator: new charts.BarLabelDecorator<String>(
|
||||
labelPosition: charts.BarLabelPosition.auto,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
var _s = await chartModel.loadPOBalancesForBuyer_();
|
||||
if (_s == null) return;
|
||||
setState(() {
|
||||
this.chartSummary = _s;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/charts/po_line_detail.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po_do_count.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
class POLineChart extends StatefulWidget {
|
||||
@override
|
||||
_POLineChartState createState() => _POLineChartState();
|
||||
}
|
||||
|
||||
class _POLineChartState extends State<POLineChart> {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
List<charts.Series<CountData, DateTime>> series = [
|
||||
charts.Series(
|
||||
id: "pending",
|
||||
data: chartModel.podoCount.getPODataCounts('pending'),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "approved",
|
||||
data: chartModel.podoCount.getPODataCounts("approved"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "canceled",
|
||||
data: chartModel.podoCount.getPODataCounts("canceled"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.gray.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "rejected",
|
||||
data: chartModel.podoCount.getPODataCounts("rejected"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 3, 2, 3],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "expired",
|
||||
data: chartModel.podoCount.getPODataCounts("expired"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.purple.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 5, 2, 5],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
charts.Series(
|
||||
id: "closed",
|
||||
data: chartModel.podoCount.getPODataCounts("closed"),
|
||||
domainFn: (CountData series, _) => series.date,
|
||||
measureFn: (CountData series, _) =>
|
||||
series.count == null ? 0 : series.count,
|
||||
colorFn: (_, __) => charts.MaterialPalette.indigo.shadeDefault,
|
||||
dashPatternFn: (_, __) => [8, 5, 2, 5],
|
||||
labelAccessorFn: (CountData series, _) =>
|
||||
'${numberFormatter.format(series.count)}',
|
||||
),
|
||||
];
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, "po", color: primaryColor, fontSize: 16),
|
||||
LocalText(context, 'chart.30_days',
|
||||
color: primaryColor, fontSize: 14)
|
||||
],
|
||||
),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"po.details",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (_) => POLineDetail()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.TimeSeriesChart(
|
||||
series,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
behaviors: [
|
||||
new charts.SeriesLegend(
|
||||
position: charts.BehaviorPosition.end,
|
||||
outsideJustification:
|
||||
charts.OutsideJustification.middleDrawArea,
|
||||
entryTextStyle: charts.TextStyleSpec(
|
||||
color: charts.Color(r: 127, g: 63, b: 191),
|
||||
fontFamily: 'Georgia',
|
||||
fontSize: 11),
|
||||
)
|
||||
],
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po_do_count.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class POLineDetail extends StatefulWidget {
|
||||
const POLineDetail();
|
||||
@override
|
||||
_POLineDetailState createState() => _POLineDetailState();
|
||||
}
|
||||
|
||||
class _POLineDetailState extends State<POLineDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: LocalText(
|
||||
context,
|
||||
'po.counts',
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20, left: 20, right: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
LocalText(context, "chart.date"),
|
||||
LocalText(context, "po.total_count")
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: getRowTotalCountWidget(
|
||||
chartModel.podoCount.getPOTotalCounts()),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
List<Widget> getRowTotalCountWidget(List<TotalCountData> data) {
|
||||
return data.map((d) {
|
||||
return Container(
|
||||
child: ExpansionTile(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(dateFormatter.format(d.date), style: textStyle),
|
||||
Text(numberFormatter.format(d.totalCount), style: textStyle),
|
||||
],
|
||||
),
|
||||
children: <Widget>[
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "po.count.status")),
|
||||
MyDataColumn(label: LocalText(context, "po.count")),
|
||||
],
|
||||
rows: getStatusRow(d.detailCountsList),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<MyDataRow> getStatusRow(List<CountData> po) {
|
||||
po.sort((a, b) => a.status.compareTo(b.status));
|
||||
return po.map((p) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(p.status, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
p.count != null ? numberFormatter.format(p.count) : '0',
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/language_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.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/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class QtyByCustomerTable extends StatefulWidget {
|
||||
final POChartData poChartData;
|
||||
const QtyByCustomerTable({Key key, this.poChartData}) : super(key: key);
|
||||
@override
|
||||
_QtyByCustomerTableState createState() => _QtyByCustomerTableState();
|
||||
}
|
||||
|
||||
class _QtyByCustomerTableState extends State<QtyByCustomerTable> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
List<POChartData> chartUser = new List();
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
var chartModel = Provider.of<ChartModel>(context, listen: false);
|
||||
if (mounted) {
|
||||
load(chartModel);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> load(ChartModel chartModel) async {
|
||||
var _u = await chartModel.loadUsers();
|
||||
setState(() {
|
||||
this.chartUser = _u;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<POChartData> data = this
|
||||
.chartUser
|
||||
.where((u) => u.productName == widget.poChartData.productName)
|
||||
.toList();
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: Text(
|
||||
AppTranslations.of(context).text("product.qtys"),
|
||||
style: Provider.of<LanguageModel>(context).isEng
|
||||
? TextStyle(fontSize: 18)
|
||||
: TextStyle(fontSize: 18, fontFamily: 'MyanmarUnicode'),
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: MyDataTable(
|
||||
headingRowHeight: 40,
|
||||
columnSpacing: 40,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "buyer.name")),
|
||||
MyDataColumn(label: LocalText(context, "buyer.product")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "buyer.balQty"), numeric: true),
|
||||
],
|
||||
rows: getProductRow(data),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<POChartData> poLines) {
|
||||
return poLines.map((p) {
|
||||
return MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(p.userName, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(
|
||||
p.productName,
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
MyDataCell(NumberCell(p.balanceQty)),
|
||||
],
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/// Simple pie chart example.
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:fcs/vo/buyer.dart';
|
||||
import 'package:fcs/vo/product.dart';
|
||||
import 'package:fcs/widget/localization/app_translations.dart';
|
||||
|
||||
class QuotaChart extends StatelessWidget {
|
||||
static final numberFormatter = new NumberFormat("#,###");
|
||||
|
||||
final List<charts.Series> quotaSeries;
|
||||
final String title;
|
||||
|
||||
QuotaChart(this.quotaSeries, this.title);
|
||||
|
||||
factory QuotaChart.dailyQuota(
|
||||
BuildContext context, Buyer buyer, List<Product> products) {
|
||||
List<Quota> data = [];
|
||||
products.sort((p1, p2) => p1.displayOrder.compareTo(p2.displayOrder));
|
||||
products.forEach((p) {
|
||||
if (buyer.dailyQuotaUsedProducts.containsKey(p.id)) {
|
||||
int value = buyer.dailyQuotaUsedProducts[p.id];
|
||||
data.add(Quota(p.name, value, p.color));
|
||||
}
|
||||
});
|
||||
data.add(
|
||||
new Quota(AppTranslations.of(context).text("chart.remaining"),
|
||||
buyer.dailyQuota - buyer.dailyQuotaUsed, Colors.purple.value),
|
||||
);
|
||||
|
||||
return new QuotaChart(
|
||||
_createData(data),
|
||||
AppTranslations.of(context).text("chart.daily.title",
|
||||
translationVariables: [numberFormatter.format(buyer.dailyQuota)]));
|
||||
}
|
||||
|
||||
factory QuotaChart.maxQuota(
|
||||
BuildContext context, Buyer buyer, List<Product> products) {
|
||||
List<Quota> data = [];
|
||||
products.sort((p1, p2) => p1.displayOrder.compareTo(p2.displayOrder));
|
||||
products.forEach((p) {
|
||||
if (buyer.maxQuotaUsedProducts.containsKey(p.id)) {
|
||||
int value = buyer.maxQuotaUsedProducts[p.id];
|
||||
data.add(Quota(p.name, value, p.color));
|
||||
}
|
||||
});
|
||||
data.add(
|
||||
new Quota(AppTranslations.of(context).text("chart.remaining"),
|
||||
buyer.maxQuota - buyer.maxQuotaUsed, Colors.purple.value),
|
||||
);
|
||||
return new QuotaChart(
|
||||
_createData(data),
|
||||
AppTranslations.of(context).text("chart.max.title",
|
||||
translationVariables: [numberFormatter.format(buyer.maxQuota)]));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Text(title),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
height: 200,
|
||||
child: charts.PieChart(
|
||||
quotaSeries,
|
||||
animate: false,
|
||||
behaviors: [
|
||||
new charts.DatumLegend(
|
||||
position: charts.BehaviorPosition.end,
|
||||
horizontalFirst: false,
|
||||
cellPadding: new EdgeInsets.only(right: 4.0, bottom: 4.0),
|
||||
entryTextStyle: charts.TextStyleSpec(
|
||||
color: charts.MaterialPalette.purple.shadeDefault,
|
||||
fontFamily: 'Georgia',
|
||||
fontSize: 11),
|
||||
)
|
||||
],
|
||||
defaultRenderer: new charts.ArcRendererConfig(
|
||||
arcWidth: 60,
|
||||
arcRendererDecorators: [
|
||||
new charts.ArcLabelDecorator(
|
||||
labelPosition: charts.ArcLabelPosition.auto,
|
||||
labelPadding: 0)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
static List<charts.Series<Quota, String>> _createData(List<Quota> data) {
|
||||
return [
|
||||
new charts.Series<Quota, String>(
|
||||
id: 'Daily Quota',
|
||||
domainFn: (Quota quota, _) => "${quota.label}\n",
|
||||
measureFn: (Quota quota, _) => quota.quota,
|
||||
data: data,
|
||||
colorFn: (Quota quota, i) =>
|
||||
charts.ColorUtil.fromDartColor(Color(quota.color)),
|
||||
labelAccessorFn: (Quota row, _) =>
|
||||
'${numberFormatter.format(row.quota)}',
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Quota {
|
||||
final String label;
|
||||
final int quota;
|
||||
final int color;
|
||||
|
||||
Quota(this.label, this.quota, this.color);
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
|
||||
import 'revenue_line_data.dart';
|
||||
|
||||
class RevenueLineChart extends StatefulWidget {
|
||||
@override
|
||||
_RevenueLineChartState createState() => _RevenueLineChartState();
|
||||
}
|
||||
|
||||
class _RevenueLineChartState extends State<RevenueLineChart> {
|
||||
static final numberFormatter = NumberFormat.compact();
|
||||
int actualChart = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
var mainModel = Provider.of<MainModel>(context);
|
||||
|
||||
List<charts.Series<Data, DateTime>> series = [
|
||||
charts.Series(
|
||||
id: "Subscribers",
|
||||
data: chartModel.revenue.getData(),
|
||||
domainFn: (Data series, _) => series.date,
|
||||
measureFn: (Data series, _) => series.amount,
|
||||
colorFn: (_, __) => charts.ColorUtil.fromDartColor(primaryColor),
|
||||
labelAccessorFn: (Data series, _) =>
|
||||
'${numberFormatter.format(series.amount)}',
|
||||
),
|
||||
];
|
||||
|
||||
final moneyFormatter =
|
||||
new charts.BasicNumericTickFormatterSpec.fromNumberFormat(
|
||||
new NumberFormat.compact());
|
||||
|
||||
return Container(
|
||||
height: 200,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
mainModel.user.isOwnerAndAbove()
|
||||
? Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, 'chart.revenue',
|
||||
fontSize: 16, color: primaryColor),
|
||||
LocalText(context, 'chart.30_days',
|
||||
color: primaryColor, fontSize: 14),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: <Widget>[
|
||||
LocalText(context, 'chart.spending',
|
||||
fontSize: 16, color: primaryColor),
|
||||
LocalText(context, 'chart.30_days',
|
||||
color: primaryColor, fontSize: 14)
|
||||
],
|
||||
),
|
||||
Text(
|
||||
"${chartModel.revenue.mapData == null ? "" : numberFormatter.format(chartModel.revenue.getTotal(actualChart))}",
|
||||
style: TextStyle(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 17.0))
|
||||
],
|
||||
),
|
||||
InkWell(
|
||||
child: LocalText(
|
||||
context,
|
||||
"revenue.detail",
|
||||
color: secondaryColor,
|
||||
fontSize: 14,
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (_) => RevenueLineData()));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: charts.TimeSeriesChart(
|
||||
series,
|
||||
animate: true,
|
||||
defaultRenderer: new charts.LineRendererConfig(
|
||||
includePoints: true,
|
||||
),
|
||||
primaryMeasureAxis: new charts.NumericAxisSpec(
|
||||
tickFormatterSpec: moneyFormatter,
|
||||
tickProviderSpec: new charts.BasicNumericTickProviderSpec(
|
||||
zeroBound: false, desiredTickCount: 10),
|
||||
renderSpec: new charts.GridlineRendererSpec(
|
||||
lineStyle: charts.LineStyleSpec(
|
||||
dashPattern: [4, 4],
|
||||
))),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/chart_model.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
import 'revenue_line_detail.dart';
|
||||
|
||||
class RevenueLineData extends StatefulWidget {
|
||||
const RevenueLineData();
|
||||
@override
|
||||
_RevenueLineDataState createState() => _RevenueLineDataState();
|
||||
}
|
||||
|
||||
class _RevenueLineDataState extends State<RevenueLineData> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var chartModel = Provider.of<ChartModel>(context);
|
||||
var mainModel = Provider.of<MainModel>(context);
|
||||
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: mainModel.user.isOwnerAndAbove()
|
||||
? LocalText(context, 'revenue.amounts',
|
||||
color: Colors.white, fontSize: 18)
|
||||
: LocalText(context, 'spending.amounts',
|
||||
color: Colors.white, fontSize: 18),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 100,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "revenue.date")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "revenue.amount"),
|
||||
numeric: true),
|
||||
],
|
||||
rows: getProductRow(chartModel.revenue.getData()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow(List<Data> revs) {
|
||||
return revs.map((p) {
|
||||
var r = MyDataRow(
|
||||
onSelectChanged: (bool selected) async {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => RevenueLineDetail(p.date)),
|
||||
);
|
||||
},
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(dateFormatter.format(p.date), style: textStyle),
|
||||
),
|
||||
MyDataCell(NumberCell(p.amount)),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:fcs/model/main_model.dart';
|
||||
import 'package:fcs/model/po_model.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/widget/local_text.dart';
|
||||
import 'package:fcs/widget/my_data_table.dart';
|
||||
import 'package:fcs/widget/number_cell.dart';
|
||||
import 'package:fcs/widget/progress.dart';
|
||||
|
||||
class RevenueLineDetail extends StatefulWidget {
|
||||
final DateTime date;
|
||||
const RevenueLineDetail(this.date);
|
||||
@override
|
||||
_RevenueLineDetailState createState() => _RevenueLineDetailState();
|
||||
}
|
||||
|
||||
class _RevenueLineDetailState extends State<RevenueLineDetail> {
|
||||
final numberFormatter = new NumberFormat("#,###");
|
||||
var dateFormatter = new DateFormat('dd-MMM-yyyy');
|
||||
bool _isLoading = false;
|
||||
List<POSubmission> pos = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
POSubmissionModel pOModel =
|
||||
Provider.of<POSubmissionModel>(context, listen: false);
|
||||
pOModel.getPOForRevenue(widget.date).then((pos) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
this.pos = pos;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var mainModel = Provider.of<MainModel>(context);
|
||||
return LocalProgress(
|
||||
inAsyncCall: _isLoading,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: primaryColor,
|
||||
title: mainModel.user.isOwnerAndAbove()
|
||||
? LocalText(
|
||||
context,
|
||||
'revenue.detail.title',
|
||||
translationVariables: [dateFormatter.format(widget.date)],
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
)
|
||||
: LocalText(
|
||||
context,
|
||||
'spending.detail.title',
|
||||
translationVariables: [dateFormatter.format(widget.date)],
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
body: Container(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: EdgeInsets.only(left: 3),
|
||||
child: MyDataTable(
|
||||
columnSpacing: 20,
|
||||
columns: [
|
||||
MyDataColumn(label: LocalText(context, "po.name")),
|
||||
MyDataColumn(label: LocalText(context, "po.po_num")),
|
||||
MyDataColumn(
|
||||
label: LocalText(context, "po.amount"), numeric: true),
|
||||
],
|
||||
rows: getProductRow(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<MyDataRow> getProductRow() {
|
||||
return pos.map((p) {
|
||||
var r = MyDataRow(
|
||||
cells: [
|
||||
MyDataCell(
|
||||
new Text(p.userName, style: textStyle),
|
||||
),
|
||||
MyDataCell(
|
||||
new Text(p.poNumber, style: textStyle),
|
||||
),
|
||||
MyDataCell(NumberCell(p.amount)),
|
||||
],
|
||||
);
|
||||
|
||||
return r;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/// Timeseries chart example
|
||||
import 'package:charts_flutter/flutter.dart' as charts;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SimpleTimeSeriesChart extends StatelessWidget {
|
||||
final List<charts.Series> seriesList;
|
||||
final bool animate;
|
||||
|
||||
SimpleTimeSeriesChart(this.seriesList, {this.animate});
|
||||
|
||||
/// Creates a [TimeSeriesChart] with sample data and no transition.
|
||||
factory SimpleTimeSeriesChart.withSampleData() {
|
||||
return new SimpleTimeSeriesChart(
|
||||
_createSampleData(),
|
||||
// Disable animations for image tests.
|
||||
animate: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new charts.TimeSeriesChart(
|
||||
seriesList,
|
||||
animate: animate,
|
||||
// Optionally pass in a [DateTimeFactory] used by the chart. The factory
|
||||
// should create the same type of [DateTime] as the data provided. If none
|
||||
// specified, the default creates local date time.
|
||||
dateTimeFactory: const charts.LocalDateTimeFactory(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Create one series with sample hard coded data.
|
||||
static List<charts.Series<TimeSeriesSales, DateTime>> _createSampleData() {
|
||||
final data = [
|
||||
new TimeSeriesSales(new DateTime(2017, 9, 19), 5),
|
||||
new TimeSeriesSales(new DateTime(2017, 9, 26), 25),
|
||||
new TimeSeriesSales(new DateTime(2017, 10, 3), 100),
|
||||
new TimeSeriesSales(new DateTime(2017, 10, 10), 75),
|
||||
];
|
||||
|
||||
return [
|
||||
new charts.Series<TimeSeriesSales, DateTime>(
|
||||
id: 'Sales',
|
||||
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
|
||||
domainFn: (TimeSeriesSales sales, _) => sales.time,
|
||||
measureFn: (TimeSeriesSales sales, _) => sales.sales,
|
||||
data: data,
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample time series data type.
|
||||
class TimeSeriesSales {
|
||||
final DateTime time;
|
||||
final int sales;
|
||||
|
||||
TimeSeriesSales(this.time, this.sales);
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/fcs/common/domain/constants.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/auth_result.dart' as fcs;
|
||||
import 'package:fcs/fcs/common/domain/entities/auth_status.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/setting.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/fcs/common/domain/exceiptions/signin_exception.dart';
|
||||
import 'package:fcs/domain/constants.dart';
|
||||
import 'package:fcs/domain/entities/auth_result.dart' as fcs;
|
||||
import 'package:fcs/domain/entities/auth_status.dart';
|
||||
import 'package:fcs/domain/entities/setting.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
import 'package:fcs/domain/exceiptions/signin_exception.dart';
|
||||
import 'package:fcs/helpers/api_helper.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../../helpers/api_helper.dart';
|
||||
|
||||
class AuthFb {
|
||||
final log = Logger('AuthFb');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/fcs/common/domain/vo/message.dart';
|
||||
import 'package:fcs/fcs/common/helpers/api_helper.dart';
|
||||
import 'package:fcs/fcs/common/helpers/firebase_helper.dart';
|
||||
import 'package:fcs/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/domain/vo/message.dart';
|
||||
import 'package:fcs/helpers/api_helper.dart';
|
||||
import 'package:fcs/helpers/firebase_helper.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class CommonDataProvider {
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fcs/fcs/common/services/messaging_service.dart';
|
||||
import 'package:fcs/data/services/messaging_service.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
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';
|
||||
import 'package:fcs/domain/constants.dart';
|
||||
import 'package:fcs/domain/entities/package.dart';
|
||||
import 'package:fcs/helpers/api_helper.dart';
|
||||
import 'package:fcs/helpers/firebase_helper.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class PackageDataProvider {
|
||||
@@ -2,10 +2,10 @@ import 'dart:convert';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:fcs/fcs/common/domain/constants.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/fcs/common/helpers/api_helper.dart';
|
||||
import 'package:fcs/fcs/common/helpers/firebase_helper.dart';
|
||||
import 'package:fcs/domain/constants.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
import 'package:fcs/helpers/api_helper.dart';
|
||||
import 'package:fcs/helpers/firebase_helper.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class UserDataProvider {
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:fcs/fcs/common/data/providers/auth_fb.dart';
|
||||
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/auth_result.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/setting.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/data/provider/auth_fb.dart';
|
||||
import 'package:fcs/domain/entities/auth_result.dart';
|
||||
import 'package:fcs/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/domain/entities/setting.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'auth_service.dart';
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/auth_result.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/setting.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/domain/entities/auth_result.dart';
|
||||
import 'package:fcs/domain/entities/setting.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
|
||||
abstract class AuthService {
|
||||
Future<AuthResult> sendSmsCodeToPhoneNumber(String phoneNumber);
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:fcs/fcs/common/data/providers/common_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/fcs/common/domain/vo/message.dart';
|
||||
import 'package:fcs/data/provider/common_data_provider.dart';
|
||||
import 'package:fcs/data/provider/user_data_provider.dart';
|
||||
import 'package:fcs/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/domain/vo/message.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'common_service.dart';
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/fcs/common/domain/vo/message.dart';
|
||||
import 'package:fcs/domain/entities/payment_method.dart';
|
||||
import 'package:fcs/domain/vo/message.dart';
|
||||
|
||||
abstract class CommonService {
|
||||
// Payment
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fcs/fcs/common/data/providers/messaging_fcm.dart';
|
||||
import 'package:fcs/data/provider/messaging_fcm.dart';
|
||||
|
||||
import 'messaging_service.dart';
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:fcs/fcs/common/data/providers/package_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/package.dart';
|
||||
import 'package:fcs/fcs/common/services/package_service.dart';
|
||||
import 'package:fcs/data/provider/package_data_provider.dart';
|
||||
import 'package:fcs/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/domain/entities/package.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package_service.dart';
|
||||
|
||||
class PackageServiceImp implements PackageService {
|
||||
PackageServiceImp({
|
||||
@required this.connectivity,
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/package.dart';
|
||||
import 'package:fcs/domain/entities/package.dart';
|
||||
|
||||
abstract class PackageService {
|
||||
Future<void> createPackages(List<Package> packages, String fcsID);
|
||||
@@ -1,18 +1,18 @@
|
||||
import 'package:fcs/fcs/common/data/providers/auth_fb.dart';
|
||||
import 'package:fcs/fcs/common/data/providers/common_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/data/providers/package_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/services/auth_imp.dart';
|
||||
import 'package:fcs/fcs/common/services/common_imp.dart';
|
||||
import 'package:fcs/fcs/common/services/common_service.dart';
|
||||
import 'package:fcs/fcs/common/services/messaging_imp.dart';
|
||||
import 'package:fcs/fcs/common/services/messaging_service.dart';
|
||||
import 'package:fcs/fcs/common/services/package_imp.dart';
|
||||
import 'package:fcs/fcs/common/services/package_service.dart';
|
||||
import 'package:fcs/fcs/common/services/user_imp.dart';
|
||||
import 'package:fcs/fcs/common/services/user_service.dart';
|
||||
import 'package:fcs/data/provider/auth_fb.dart';
|
||||
import 'package:fcs/data/provider/common_data_provider.dart';
|
||||
import 'package:fcs/data/provider/package_data_provider.dart';
|
||||
import 'package:fcs/data/provider/user_data_provider.dart';
|
||||
|
||||
import 'auth_imp.dart';
|
||||
import 'auth_service.dart';
|
||||
import 'common_imp.dart';
|
||||
import 'common_service.dart';
|
||||
import 'messaging_imp.dart';
|
||||
import 'messaging_service.dart';
|
||||
import 'package_imp.dart';
|
||||
import 'package_service.dart';
|
||||
import 'user_imp.dart';
|
||||
import 'user_service.dart';
|
||||
|
||||
class Services {
|
||||
static final Services instance = Services._();
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:fcs/fcs/common/data/providers/user_data_provider.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/data/provider/user_data_provider.dart';
|
||||
import 'package:fcs/domain/entities/connectivity.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'user_service.dart';
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
|
||||
abstract class UserService {
|
||||
Future<void> inviteUser(String userName, String phoneNumber);
|
||||
@@ -1,13 +1,8 @@
|
||||
import 'package:fcs/vo/cargo.dart';
|
||||
import 'package:fcs/vo/shipping_address.dart';
|
||||
import 'package.dart';
|
||||
import 'package:fcs/domain/vo/shipment_status.dart';
|
||||
import 'package:fcs/domain/vo/shipping_address.dart';
|
||||
|
||||
class Status {
|
||||
String status;
|
||||
DateTime date;
|
||||
bool done;
|
||||
Status({this.status, this.date, this.done});
|
||||
}
|
||||
import 'cargo.dart';
|
||||
import 'package.dart';
|
||||
|
||||
class Box {
|
||||
String id;
|
||||
@@ -46,7 +41,7 @@ class Box {
|
||||
shipmentNumber + "-" + receiverNumber + " #" + boxNumber;
|
||||
double get price => rate.toDouble() * weight;
|
||||
|
||||
List<Status> statusHistory;
|
||||
List<ShipmentStatus> shipmentHistory;
|
||||
|
||||
Box(
|
||||
{this.id,
|
||||
@@ -70,7 +65,7 @@ class Box {
|
||||
this.status,
|
||||
this.arrivedDate,
|
||||
this.cargoDesc,
|
||||
this.statusHistory,
|
||||
this.shipmentHistory,
|
||||
this.packages,
|
||||
this.cargoTypes,
|
||||
this.shippingAddress});
|
||||
6
lib/domain/entities/discount_rate.dart
Normal file
6
lib/domain/entities/discount_rate.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
class DiscountRate {
|
||||
int weight;
|
||||
double discountRate;
|
||||
|
||||
DiscountRate({this.weight, this.discountRate});
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package.dart';
|
||||
import 'receipt.dart';
|
||||
|
||||
class Invoice {
|
||||
String invoiceNumber;
|
||||
@@ -29,10 +30,3 @@ class Invoice {
|
||||
|
||||
double get getAmount => packages.fold(0, (p, e) => (e.rate * e.weight) + p);
|
||||
}
|
||||
|
||||
class Receipt {
|
||||
int amount;
|
||||
DateTime date;
|
||||
|
||||
Receipt({this.amount, this.date});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/fcs/common/domain/vo/shipment_status.dart';
|
||||
import 'package:fcs/domain/vo/shipment_status.dart';
|
||||
|
||||
class Package {
|
||||
String id;
|
||||
6
lib/domain/entities/receipt.dart
Normal file
6
lib/domain/entities/receipt.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
class Receipt {
|
||||
int amount;
|
||||
DateTime date;
|
||||
|
||||
Receipt({this.amount, this.date});
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/fcs/common/helpers/const.dart';
|
||||
import 'package:fcs/fcs/common/pages/package/package_info.dart';
|
||||
import 'package:fcs/helpers/const.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
DateFormat dayFormat = DateFormat("MMM dd yyyy");
|
||||
DateFormat timeFormat = DateFormat("HH:mm");
|
||||
final DateFormat dateFormat = DateFormat("d MMM yyyy");
|
||||
|
||||
class User {
|
||||
String id;
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/setting.dart';
|
||||
import 'package:fcs/domain/entities/setting.dart';
|
||||
|
||||
class Contact {
|
||||
String usaAddress;
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/setting.dart';
|
||||
import 'package:fcs/domain/entities/setting.dart';
|
||||
|
||||
class Term {
|
||||
String termEng;
|
||||
@@ -1,576 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'full_photo.dart';
|
||||
import 'loading.dart';
|
||||
|
||||
final themeColor = Color(0xfff5a623);
|
||||
final primaryColor = Color(0xff203152);
|
||||
final greyColor = Color(0xffaeaeae);
|
||||
final greyColor2 = Color(0xffE8E8E8);
|
||||
|
||||
class Chat extends StatelessWidget {
|
||||
final String peerId;
|
||||
final String peerAvatar;
|
||||
|
||||
Chat({Key key, @required this.peerId, @required this.peerAvatar})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'CHAT',
|
||||
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: ChatScreen(
|
||||
peerId: peerId,
|
||||
peerAvatar: peerAvatar,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final String peerId;
|
||||
final String peerAvatar;
|
||||
|
||||
ChatScreen({Key key, @required this.peerId, @required this.peerAvatar})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State createState() =>
|
||||
ChatScreenState(peerId: peerId, peerAvatar: peerAvatar);
|
||||
}
|
||||
|
||||
class ChatScreenState extends State<ChatScreen> {
|
||||
ChatScreenState({Key key, @required this.peerId, @required this.peerAvatar});
|
||||
GlobalKey key = GlobalKey();
|
||||
|
||||
String peerId;
|
||||
String peerAvatar;
|
||||
String id;
|
||||
|
||||
List<DocumentSnapshot> listMessage = new List.from([]);
|
||||
int _limit = 20;
|
||||
final int _limitIncrement = 20;
|
||||
String groupChatId;
|
||||
SharedPreferences prefs;
|
||||
|
||||
File imageFile;
|
||||
bool isLoading;
|
||||
String imageUrl;
|
||||
|
||||
final TextEditingController textEditingController = TextEditingController();
|
||||
final ScrollController listScrollController = ScrollController();
|
||||
|
||||
_scrollListener() {
|
||||
if (listScrollController.offset >=
|
||||
listScrollController.position.maxScrollExtent &&
|
||||
!listScrollController.position.outOfRange) {
|
||||
print("reach the bottom");
|
||||
setState(() {
|
||||
print("reach the bottom");
|
||||
_limit += _limitIncrement;
|
||||
});
|
||||
}
|
||||
if (listScrollController.offset <=
|
||||
listScrollController.position.minScrollExtent &&
|
||||
!listScrollController.position.outOfRange) {
|
||||
print("reach the top");
|
||||
setState(() {
|
||||
print("reach the top");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
listScrollController.addListener(_scrollListener);
|
||||
|
||||
groupChatId = '';
|
||||
|
||||
isLoading = false;
|
||||
imageUrl = '';
|
||||
|
||||
readLocal();
|
||||
}
|
||||
|
||||
readLocal() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
id = prefs.getString('id') ?? '';
|
||||
if (id.hashCode <= peerId.hashCode) {
|
||||
groupChatId = '$id-$peerId';
|
||||
} else {
|
||||
groupChatId = '$peerId-$id';
|
||||
}
|
||||
|
||||
Firestore.instance
|
||||
.collection('users')
|
||||
.document(id)
|
||||
.updateData({'chattingWith': peerId});
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
Future getImage() async {
|
||||
ImagePicker imagePicker = ImagePicker();
|
||||
PickedFile pickedFile;
|
||||
|
||||
pickedFile = await imagePicker.getImage(source: ImageSource.gallery);
|
||||
imageFile = File(pickedFile.path);
|
||||
|
||||
if (imageFile != null) {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
uploadFile();
|
||||
}
|
||||
}
|
||||
|
||||
Future uploadFile() async {
|
||||
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
|
||||
StorageUploadTask uploadTask = reference.putFile(imageFile);
|
||||
StorageTaskSnapshot storageTaskSnapshot = await uploadTask.onComplete;
|
||||
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
|
||||
imageUrl = downloadUrl;
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
onSendMessage(imageUrl, 1);
|
||||
});
|
||||
}, onError: (err) {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void onSendMessage(String content, int type) {
|
||||
// type: 0 = text, 1 = image, 2 = sticker
|
||||
if (content.trim() != '') {
|
||||
textEditingController.clear();
|
||||
|
||||
var documentReference = Firestore.instance
|
||||
.collection('messages')
|
||||
.document(groupChatId)
|
||||
.collection(groupChatId)
|
||||
.document(DateTime.now().millisecondsSinceEpoch.toString());
|
||||
|
||||
Firestore.instance.runTransaction((transaction) async {
|
||||
transaction.set(
|
||||
documentReference,
|
||||
{
|
||||
'idFrom': id,
|
||||
'idTo': peerId,
|
||||
'timestamp': DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
'content': content,
|
||||
'type': type
|
||||
},
|
||||
);
|
||||
});
|
||||
listScrollController.animateTo(0.0,
|
||||
duration: Duration(milliseconds: 300), curve: Curves.easeOut);
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildItem(int index, DocumentSnapshot document) {
|
||||
if (document.data['idFrom'] == id) {
|
||||
// Right (my message)
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
document.data['type'] == 0
|
||||
// Text
|
||||
? Container(
|
||||
child: Text(
|
||||
document.data['content'],
|
||||
style: TextStyle(color: primaryColor),
|
||||
),
|
||||
padding: EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
|
||||
width: 200.0,
|
||||
decoration: BoxDecoration(
|
||||
color: greyColor2,
|
||||
borderRadius: BorderRadius.circular(8.0)),
|
||||
margin: EdgeInsets.only(
|
||||
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
|
||||
right: 10.0),
|
||||
)
|
||||
: document.data['type'] == 1
|
||||
// Image
|
||||
? Container(
|
||||
child: FlatButton(
|
||||
child: Material(
|
||||
child: CachedNetworkImage(
|
||||
placeholder: (context, url) => Container(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(themeColor),
|
||||
),
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
padding: EdgeInsets.all(70.0),
|
||||
decoration: BoxDecoration(
|
||||
color: greyColor2,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) => Material(
|
||||
child: Image.asset(
|
||||
'images/img_not_available.jpeg',
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
),
|
||||
imageUrl: document.data['content'],
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => FullPhoto(
|
||||
url: document.data['content'])));
|
||||
},
|
||||
padding: EdgeInsets.all(0),
|
||||
),
|
||||
margin: EdgeInsets.only(
|
||||
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
|
||||
right: 10.0),
|
||||
)
|
||||
// Sticker
|
||||
: Container(
|
||||
child: Image.asset(
|
||||
'images/${document.data['content']}.gif',
|
||||
width: 100.0,
|
||||
height: 100.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
margin: EdgeInsets.only(
|
||||
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
|
||||
right: 10.0),
|
||||
),
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
);
|
||||
} else {
|
||||
// Left (peer message)
|
||||
return Container(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
isLastMessageLeft(index)
|
||||
? Material(
|
||||
child: CachedNetworkImage(
|
||||
placeholder: (context, url) => Container(
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 1.0,
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(themeColor),
|
||||
),
|
||||
width: 35.0,
|
||||
height: 35.0,
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
imageUrl: peerAvatar,
|
||||
width: 35.0,
|
||||
height: 35.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(18.0),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
)
|
||||
: Container(width: 35.0),
|
||||
document.data['type'] == 0
|
||||
? Container(
|
||||
child: Text(
|
||||
document.data['content'],
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
padding: EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
|
||||
width: 200.0,
|
||||
decoration: BoxDecoration(
|
||||
color: primaryColor,
|
||||
borderRadius: BorderRadius.circular(8.0)),
|
||||
margin: EdgeInsets.only(left: 10.0),
|
||||
)
|
||||
: document.data['type'] == 1
|
||||
? Container(
|
||||
child: FlatButton(
|
||||
child: Material(
|
||||
child: CachedNetworkImage(
|
||||
placeholder: (context, url) => Container(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
themeColor),
|
||||
),
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
padding: EdgeInsets.all(70.0),
|
||||
decoration: BoxDecoration(
|
||||
color: greyColor2,
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
errorWidget: (context, url, error) =>
|
||||
Material(
|
||||
child: Image.asset(
|
||||
'images/img_not_available.jpeg',
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(8.0),
|
||||
),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
),
|
||||
imageUrl: document.data['content'],
|
||||
width: 200.0,
|
||||
height: 200.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(8.0)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => FullPhoto(
|
||||
url: document.data['content'])));
|
||||
},
|
||||
padding: EdgeInsets.all(0),
|
||||
),
|
||||
margin: EdgeInsets.only(left: 10.0),
|
||||
)
|
||||
: Container(
|
||||
child: Image.asset(
|
||||
'images/${document.data['content']}.gif',
|
||||
width: 100.0,
|
||||
height: 100.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
margin: EdgeInsets.only(
|
||||
bottom: isLastMessageRight(index) ? 20.0 : 10.0,
|
||||
right: 10.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Time
|
||||
isLastMessageLeft(index)
|
||||
? Container(
|
||||
child: Text(
|
||||
DateFormat('dd MMM kk:mm').format(
|
||||
DateTime.fromMillisecondsSinceEpoch(
|
||||
int.parse(document.data['timestamp']))),
|
||||
style: TextStyle(
|
||||
color: greyColor,
|
||||
fontSize: 12.0,
|
||||
fontStyle: FontStyle.italic),
|
||||
),
|
||||
margin: EdgeInsets.only(left: 50.0, top: 5.0, bottom: 5.0),
|
||||
)
|
||||
: Container()
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
margin: EdgeInsets.only(bottom: 10.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool isLastMessageLeft(int index) {
|
||||
if ((index > 0 &&
|
||||
listMessage != null &&
|
||||
listMessage[index - 1].data['idFrom'] == id) ||
|
||||
index == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isLastMessageRight(int index) {
|
||||
if ((index > 0 &&
|
||||
listMessage != null &&
|
||||
listMessage[index - 1].data['idFrom'] != id) ||
|
||||
index == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> onBackPress() {
|
||||
Firestore.instance
|
||||
.collection('users')
|
||||
.document(id)
|
||||
.updateData({'chattingWith': null});
|
||||
Navigator.pop(context);
|
||||
|
||||
return Future.value(false);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
// List of messages
|
||||
buildListMessage(),
|
||||
|
||||
// Input content
|
||||
buildInput(),
|
||||
],
|
||||
),
|
||||
|
||||
// Loading
|
||||
buildLoading()
|
||||
],
|
||||
),
|
||||
onWillPop: onBackPress,
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildLoading() {
|
||||
return Positioned(
|
||||
child: isLoading ? const Loading() : Container(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildInput() {
|
||||
return Container(
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
// Button send image
|
||||
Material(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 1.0),
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.image),
|
||||
onPressed: getImage,
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
Material(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 1.0),
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.face),
|
||||
onPressed: () => {},
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
|
||||
// Edit text
|
||||
Flexible(
|
||||
child: Container(
|
||||
child: TextField(
|
||||
onSubmitted: (value) {
|
||||
onSendMessage(textEditingController.text, 0);
|
||||
},
|
||||
style: TextStyle(color: primaryColor, fontSize: 15.0),
|
||||
controller: textEditingController,
|
||||
decoration: InputDecoration.collapsed(
|
||||
hintText: 'Type your message...',
|
||||
hintStyle: TextStyle(color: greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Button send message
|
||||
Material(
|
||||
child: Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: () => onSendMessage(textEditingController.text, 0),
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
width: double.infinity,
|
||||
height: 50.0,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(top: BorderSide(color: greyColor2, width: 0.5)),
|
||||
color: Colors.white),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildListMessage() {
|
||||
return Flexible(
|
||||
child: groupChatId == ''
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(themeColor)))
|
||||
: StreamBuilder(
|
||||
stream: Firestore.instance
|
||||
.collection('messages')
|
||||
.document(groupChatId)
|
||||
.collection(groupChatId)
|
||||
.orderBy('timestamp', descending: true)
|
||||
.limit(_limit)
|
||||
.snapshots(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(themeColor)));
|
||||
} else {
|
||||
listMessage.addAll(snapshot.data.documents);
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
itemBuilder: (context, index) =>
|
||||
buildItem(index, snapshot.data.documents[index]),
|
||||
itemCount: snapshot.data.documents.length,
|
||||
reverse: true,
|
||||
controller: listScrollController,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
import 'chat_page.dart';
|
||||
|
||||
class FullPhoto extends StatelessWidget {
|
||||
final String url;
|
||||
|
||||
FullPhoto({Key key, @required this.url}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'FULL PHOTO',
|
||||
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
|
||||
),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: FullPhotoScreen(url: url),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FullPhotoScreen extends StatefulWidget {
|
||||
final String url;
|
||||
|
||||
FullPhotoScreen({Key key, @required this.url}) : super(key: key);
|
||||
|
||||
@override
|
||||
State createState() => FullPhotoScreenState(url: url);
|
||||
}
|
||||
|
||||
class FullPhotoScreenState extends State<FullPhotoScreen> {
|
||||
final String url;
|
||||
|
||||
FullPhotoScreenState({Key key, @required this.url});
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: PhotoView(imageProvider: CachedNetworkImageProvider(url)));
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Loading extends StatelessWidget {
|
||||
const Loading();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(primaryColor),
|
||||
),
|
||||
),
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
import 'package:fcs/fcs/common/domain/vo/message.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/fcs/common/pages/chat/message_detail.dart';
|
||||
import 'package:fcs/fcs/common/pages/chat/model/message_model.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/fcs/common/pages/widgets/progress.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class NotificationList extends StatefulWidget {
|
||||
@override
|
||||
_NotificationListState createState() => _NotificationListState();
|
||||
}
|
||||
|
||||
class _NotificationListState extends State<NotificationList> {
|
||||
var timeFormatter = new DateFormat('KK:mm a');
|
||||
var dateFormatter = new DateFormat('dd MMM yyyy');
|
||||
final double dotSize = 25.0;
|
||||
int _selectedIndex = 0;
|
||||
bool _isLoading = false;
|
||||
bool _isClicked = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
MessageModel messageModel = Provider.of<MessageModel>(context);
|
||||
|
||||
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: LocalText(
|
||||
context,
|
||||
'message.title',
|
||||
fontSize: 20,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
body: new ListView.separated(
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
color: Colors.black,
|
||||
),
|
||||
scrollDirection: Axis.vertical,
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
shrinkWrap: true,
|
||||
itemCount: messageModel.messages.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
Message msg = messageModel.messages[index];
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
InkWell(
|
||||
onTap: () => _display(msg),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Padding(
|
||||
padding: new EdgeInsets.symmetric(
|
||||
horizontal: 22.0 - dotSize / 2),
|
||||
child: Icon(
|
||||
Icons.account_circle,
|
||||
color: primaryColor,
|
||||
size: 60,
|
||||
),
|
||||
),
|
||||
new Expanded(
|
||||
child: new Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new Text(
|
||||
msg.receiverName,
|
||||
style: new TextStyle(fontSize: 15.0),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 18.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
timeFormatter.format(msg.date),
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
),
|
||||
msg.fromToday()
|
||||
? Container()
|
||||
: Text(
|
||||
dateFormatter.format(msg.date),
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_display(Message msg) {
|
||||
Navigator.push(context,
|
||||
BottomUpPageRoute(MessageDetail(receiverName: msg.receiverName)));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fcs/fcs/common/domain/vo/contact.dart';
|
||||
import 'package:fcs/fcs/common/pages/model/base_model.dart';
|
||||
import 'package:fcs/fcs/common/services/services.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
class ContactModel extends BaseModel {
|
||||
final log = Logger('ContactModel');
|
||||
|
||||
Future<void> saveContact(Contact contact) async {
|
||||
await request("/contact", "PUT",
|
||||
payload: contact.toMap(), token: await Services.instance.authService.getToken());
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/fcs/common/localization/app_translations.dart';
|
||||
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget itemTitle(BuildContext context, String textKey) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 18.0, top: 25, bottom: 5),
|
||||
child: Text(
|
||||
AppTranslations.of(context).text(textKey),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget subItemTitle(BuildContext context, String textKey,{IconData iconData}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 0, top: 0, bottom: 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(iconData,color: primaryColor,),SizedBox(width:10),
|
||||
Text(
|
||||
AppTranslations.of(context).text(textKey),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700, fontSize: 15, color: primaryColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget contactItem(BuildContext context, String text, IconData iconData,
|
||||
{Function() onTap, String labelKey}) {
|
||||
return Material(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 18.0, bottom: 10, right: 18),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.8),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5.0) // <--- border radius here
|
||||
),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () => onTap != null ? onTap() : null,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
iconData,
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
labelKey == null
|
||||
? Container()
|
||||
: Padding(
|
||||
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
|
||||
child: LocalText(context, labelKey,
|
||||
color: primaryColor, fontWeight: FontWeight.w500,fontSize: 18),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
text == null ? "" : text,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 5,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
onTap == null
|
||||
? Container()
|
||||
: Icon(
|
||||
Icons.open_in_new,
|
||||
color: Colors.grey,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/fcs/common/localization/app_translations.dart';
|
||||
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget itemTitle(BuildContext context, String textKey) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 18.0, top: 15, bottom: 0),
|
||||
child: Text(
|
||||
AppTranslations.of(context).text(textKey),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget subItemTitle(BuildContext context, String textKey,{IconData iconData}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 0, top: 0, bottom: 0),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(iconData,color: primaryColor,),SizedBox(width:10),
|
||||
Text(
|
||||
AppTranslations.of(context).text(textKey),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700, fontSize: 15, color: primaryColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget contactItem(BuildContext context, String text, IconData iconData,
|
||||
{Function() onTap, String labelKey}) {
|
||||
return Material(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 18.0, bottom: 10, right: 18),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.grey, width: 0.8),
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5.0) // <--- border radius here
|
||||
),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: () => onTap != null ? onTap() : null,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
iconData,
|
||||
color: primaryColor,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
labelKey == null
|
||||
? Container()
|
||||
: Padding(
|
||||
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
|
||||
child: LocalText(context, labelKey,
|
||||
color: primaryColor, fontWeight: FontWeight.w500,fontSize: 18),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
text == null ? "" : text,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 5,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
onTap == null
|
||||
? Container()
|
||||
: Icon(
|
||||
Icons.open_in_new,
|
||||
color: Colors.grey,
|
||||
size: 15,
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import 'package:fcs/fcs/common/domain/entities/shipment.dart';
|
||||
import 'package:fcs/fcs/common/domain/vo/shipping_address.dart';
|
||||
import 'package:fcs/fcs/common/pages/model/base_model.dart';
|
||||
|
||||
class ShipmentModel extends BaseModel {
|
||||
List<String> shipmentType = ['Air', 'Ship', 'Cargo Truck'];
|
||||
List<Shipment> shipments = [
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 23),
|
||||
shipmentNumber: 'A103B',
|
||||
status: 'In Progress',
|
||||
arrivalDate: DateTime(2020, 4, 30),
|
||||
departureDate: DateTime(2020, 4, 23)),
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 2),
|
||||
shipmentNumber: 'A100A',
|
||||
status: 'Ready to ship',
|
||||
arrivalDate: DateTime(2020, 4, 28),
|
||||
departureDate: DateTime(2020, 4, 15)),
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 2),
|
||||
shipmentNumber: 'A100B',
|
||||
status: 'Arrived',
|
||||
arrivalDate: DateTime(2020, 4, 28),
|
||||
departureDate: DateTime(2020, 4, 15)),
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 10),
|
||||
shipmentNumber: 'A102B',
|
||||
status: 'Canceled',
|
||||
arrivalDate: DateTime(2020, 4, 20),
|
||||
departureDate: DateTime(2020, 4, 10)),
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 2),
|
||||
shipmentNumber: 'A100B',
|
||||
status: 'Canceled',
|
||||
arrivalDate: DateTime(2020, 4, 20),
|
||||
departureDate: DateTime(2020, 4, 23)),
|
||||
Shipment(
|
||||
shipDate: DateTime(2020, 4, 10),
|
||||
shipmentNumber: 'A102B',
|
||||
status: 'Arrived',
|
||||
arrivalDate: DateTime(2020, 4, 30),
|
||||
departureDate: DateTime(2020, 4, 20),
|
||||
)
|
||||
];
|
||||
|
||||
List<Shipment> get canceled {
|
||||
List<Shipment> _p = shipments.where((e) => e.status == "Canceled").toList()
|
||||
..sort((e1, e2) {
|
||||
return e1.shipDate.compareTo(e2.shipDate);
|
||||
});
|
||||
return _p;
|
||||
}
|
||||
|
||||
List<Shipment> get completed {
|
||||
return shipments.where((e) => e.status == "Arrived").toList()
|
||||
..sort((e1, e2) {
|
||||
return e1.shipDate.compareTo(e2.shipDate);
|
||||
});
|
||||
}
|
||||
|
||||
List<Shipment> get upcoming {
|
||||
List<Shipment> _shipments = shipments
|
||||
.where((e) =>
|
||||
e.status == "In Progress" ||
|
||||
e.status == "Ready to ship" ||
|
||||
e.status == "Processed" ||
|
||||
e.status == "Rescheduled")
|
||||
.toList();
|
||||
|
||||
_shipments.sort((e1, e2) {
|
||||
return e1.shipDate.compareTo(e2.shipDate);
|
||||
});
|
||||
return _shipments;
|
||||
}
|
||||
|
||||
List<ShippingAddress> shippingAddresses = [
|
||||
ShippingAddress(
|
||||
fullName: 'U Nyi Nyi',
|
||||
addressLine1: '154-19 64th Ave.',
|
||||
addressLine2: 'Flushing',
|
||||
city: 'NY',
|
||||
state: 'NY',
|
||||
phoneNumber: '+1 (292)215-2247'),
|
||||
ShippingAddress(
|
||||
fullName: 'Mg Myo',
|
||||
addressLine1: '153-154 5th Thitsar.',
|
||||
addressLine2: 'South Okkalapa Township',
|
||||
city: 'Yangon',
|
||||
state: 'Myanmar',
|
||||
phoneNumber: '+09 95724 8750'),
|
||||
];
|
||||
|
||||
void initUser(user) {
|
||||
super.initUser(user);
|
||||
}
|
||||
|
||||
@override
|
||||
logout() async {
|
||||
shipments = [];
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
import 'package:fcs/fcs/common/domain/vo/shipping_address.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/fcs/common/pages/util.dart';
|
||||
import 'package:fcs/fcs/common/pages/widgets/local_text.dart';
|
||||
import 'package:fcs/fcs/common/pages/widgets/progress.dart';
|
||||
import 'package:flutter_icons/flutter_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ShippingAddressEditor extends StatefulWidget {
|
||||
final ShippingAddress shippingAddress;
|
||||
ShippingAddressEditor({this.shippingAddress});
|
||||
|
||||
@override
|
||||
_ShippingAddressEditorState createState() => _ShippingAddressEditorState();
|
||||
}
|
||||
|
||||
class _ShippingAddressEditorState extends State<ShippingAddressEditor> {
|
||||
TextEditingController _nameController = new TextEditingController();
|
||||
TextEditingController _address1Controller = new TextEditingController();
|
||||
TextEditingController _address2Controller = new TextEditingController();
|
||||
TextEditingController _cityController = new TextEditingController();
|
||||
TextEditingController _stateController = new TextEditingController();
|
||||
TextEditingController _phoneController = new TextEditingController();
|
||||
|
||||
ShippingAddress _shippingAddress = new ShippingAddress();
|
||||
|
||||
bool _isLoading = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.shippingAddress != null) {
|
||||
_shippingAddress = widget.shippingAddress;
|
||||
_nameController.text = _shippingAddress.fullName;
|
||||
_address1Controller.text = _shippingAddress.addressLine1;
|
||||
_address2Controller.text = _shippingAddress.addressLine2;
|
||||
_cityController.text = _shippingAddress.city;
|
||||
_stateController.text = _shippingAddress.state;
|
||||
_phoneController.text = _shippingAddress.phoneNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final usaAddress =
|
||||
fcsInput('Full Name', Icons.text_format, controller: _nameController);
|
||||
final mmAddress = fcsInput('Address Line 1', Icons.location_on,
|
||||
controller: _address1Controller);
|
||||
|
||||
final contactNumber = fcsInput('Address Line 2', Icons.location_on,
|
||||
controller: _address2Controller);
|
||||
final mmContactNumber =
|
||||
fcsInput('City', Icons.location_city, controller: _cityController);
|
||||
|
||||
final mailBox =
|
||||
fcsInput('State/Region', Entypo.location, controller: _stateController);
|
||||
final fbLinkBox =
|
||||
fcsInput('Phone Number', Icons.phone, controller: _phoneController);
|
||||
|
||||
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: LocalText(
|
||||
context,
|
||||
'user.form.shipping_address',
|
||||
color: Colors.white,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
body: Card(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10.0, right: 10),
|
||||
child: ListView(children: <Widget>[
|
||||
usaAddress,
|
||||
SizedBox(height: 10),
|
||||
mmAddress,
|
||||
SizedBox(height: 10),
|
||||
contactNumber,
|
||||
SizedBox(height: 10),
|
||||
mmContactNumber,
|
||||
SizedBox(height: 10),
|
||||
mailBox,
|
||||
SizedBox(height: 10),
|
||||
fbLinkBox,
|
||||
SizedBox(height: 10),
|
||||
]),
|
||||
)),
|
||||
widget.shippingAddress == null
|
||||
? Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 250,
|
||||
child: FlatButton(
|
||||
child: Text('Create'),
|
||||
color: primaryColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
)))
|
||||
: Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 250,
|
||||
child: FlatButton(
|
||||
child: Text('Update'),
|
||||
color: primaryColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
))),
|
||||
SizedBox(height: 10)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ import 'dart:io';
|
||||
|
||||
import 'package:device_info/device_info.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:fcs/domain/vo/status.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:fcs/vo/status.dart';
|
||||
|
||||
import '../../../config.dart';
|
||||
import '../config.dart';
|
||||
import 'dev_info.dart';
|
||||
|
||||
final log = Logger('requestAPI');
|
||||
@@ -3,9 +3,10 @@ import 'dart:io';
|
||||
|
||||
import 'package:connectivity/connectivity.dart';
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:fcs/fcs/common/helpers/api_helper.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'api_helper.dart';
|
||||
|
||||
class NetworkConnectivity {
|
||||
final log = Logger('NetworkConnectivity');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fcs/fcs/common/domain/entities/user.dart';
|
||||
import 'package:fcs/domain/entities/user.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SharedPref {
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'app.dart';
|
||||
import 'config.dart';
|
||||
|
||||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'app.dart';
|
||||
import 'config.dart';
|
||||
|
||||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'app.dart';
|
||||
import 'config.dart';
|
||||
|
||||
void main() {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:fcs/vo/announcement.dart';
|
||||
|
||||
import 'base_model.dart';
|
||||
import 'constants.dart';
|
||||
import 'firebase_helper.dart';
|
||||
|
||||
class AnnouncementModel extends BaseModel {
|
||||
List<Announcement> announcements = [];
|
||||
|
||||
void initUser(user) {
|
||||
super.initUser(user);
|
||||
_loadAnnouncements();
|
||||
}
|
||||
|
||||
@override
|
||||
logout() async {
|
||||
announcements = [];
|
||||
}
|
||||
|
||||
Future<void> _loadAnnouncements() async {
|
||||
Stream<QuerySnapshot> snapshots = Firestore.instance
|
||||
.collection(
|
||||
"/$biz_collection/${setting.okEnergyId}/$announcement_collection")
|
||||
.snapshots();
|
||||
|
||||
snapshots.listen((snaps) async {
|
||||
announcements = snaps.documents.map((documentSnapshot) {
|
||||
var data = Announcement.fromMap(
|
||||
documentSnapshot.data, documentSnapshot.documentID);
|
||||
return data;
|
||||
}).toList();
|
||||
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
Future<Announcement> getAnnouncement(String id) async {
|
||||
String path =
|
||||
"/$biz_collection/${setting.okEnergyId}/$announcement_collection";
|
||||
var snap = await getDocSnap(path, id);
|
||||
return Announcement.fromMap(snap.data, snap.documentID);
|
||||
}
|
||||
|
||||
Future<void> createAnnouncement(Announcement announcement) async {
|
||||
await request("/announcement", "POST",
|
||||
payload: announcement.toMap(), token: await getToken());
|
||||
}
|
||||
|
||||
Future<void> updateAnnouncement(Announcement announcement) async {
|
||||
await request("/announcement", "PUT",
|
||||
payload: announcement.toMap(), token: await getToken());
|
||||
}
|
||||
|
||||
Future<void> deleteAnnouncement(Announcement announcement) async {
|
||||
await request("/announcement", "DELETE",
|
||||
payload: announcement.toMap(), token: await getToken());
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:fcs/fcs/common/helpers/api_helper.dart';
|
||||
|
||||
import '../vo/setting.dart';
|
||||
import '../vo/user.dart';
|
||||
import 'main_model.dart';
|
||||
|
||||
abstract class BaseModel extends ChangeNotifier {
|
||||
User user;
|
||||
Setting setting;
|
||||
MainModel mainModel;
|
||||
|
||||
void initUser(User user) async {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
void initSetting(Setting setting) async {
|
||||
this.setting = setting;
|
||||
}
|
||||
|
||||
void logout();
|
||||
|
||||
// request makes http request
|
||||
// if token is null
|
||||
dynamic request(
|
||||
String path,
|
||||
method, {
|
||||
dynamic payload,
|
||||
String token,
|
||||
String url,
|
||||
}) async {
|
||||
mainModel.resetPinTimer();
|
||||
return await requestAPI(path, method,
|
||||
payload: payload, token: token, url: url);
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert' show HtmlEscape, base64, utf8;
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:fcs/fcs/common/helpers/theme.dart';
|
||||
import 'package:fcs/vo/buyer.dart';
|
||||
import 'package:fcs/vo/popup_menu.dart';
|
||||
|
||||
import 'base_model.dart';
|
||||
import 'constants.dart';
|
||||
import 'firebase_helper.dart';
|
||||
|
||||
class BuyerModel extends BaseModel {
|
||||
final log = Logger('BuyerModel');
|
||||
|
||||
StreamSubscription<QuerySnapshot> listener;
|
||||
|
||||
List<Buyer> buyers = [];
|
||||
PopupMenu popupMenu = new PopupMenu(index: 0);
|
||||
PopupMenu sortMenu = new PopupMenu();
|
||||
Buyer searchBuyer;
|
||||
void initUser(user) {
|
||||
super.initUser(user);
|
||||
_loadBuyers();
|
||||
}
|
||||
|
||||
Future<void> _loadBuyers() async {
|
||||
if (!user.isOwnerAndAbove() && !user.hasBuyer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
listener = getQuerySnapshotByOrder(
|
||||
"/$biz_collection/${setting.okEnergyId}/$buyer_collection",
|
||||
'user_name')
|
||||
.listen((snaps) async {
|
||||
buyers.clear();
|
||||
snaps.documents.forEach((d) {
|
||||
buyers.add(Buyer.fromMap(d.data, d.documentID));
|
||||
});
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
logout() async {
|
||||
if (listener != null) await listener.cancel();
|
||||
buyers = [];
|
||||
}
|
||||
|
||||
Future<Buyer> getBuyer(String buyerID) async {
|
||||
var snap = await getDocSnap(
|
||||
"/$biz_collection/${setting.okEnergyId}/$buyer_collection", buyerID);
|
||||
return Buyer.fromMap(snap.data, snap.documentID);
|
||||
}
|
||||
|
||||
Future<Buyer> loadBuyerProducts(Buyer buyer, {bool force = false}) async {
|
||||
if (!force && buyer.buyerProducts != null && buyer.buyerProducts.length > 0)
|
||||
return buyer;
|
||||
var snaps = await getSnapshot(
|
||||
"/$biz_collection/${setting.okEnergyId}/$buyer_collection/${buyer.id}/$product_collection");
|
||||
buyer.buyerProducts = snaps.documents
|
||||
.map((s) => BuyerProduct.fromMap(s.data, s.documentID))
|
||||
.toList();
|
||||
return buyer;
|
||||
}
|
||||
|
||||
Future<void> delete(Buyer buyer) async {
|
||||
await request("/buyer/${buyer.id}", "DELETE", token: await getToken());
|
||||
}
|
||||
|
||||
Future<void> approve(Buyer buyer) async {
|
||||
await request("/buyer/approve", "PUT",
|
||||
payload: buyer.toMap(), token: await getToken());
|
||||
}
|
||||
|
||||
Future<void> reject(Buyer buyer) async {
|
||||
await request("/buyer/reject", "POST",
|
||||
payload: buyer.toMap(), token: await getToken());
|
||||
}
|
||||
|
||||
Future<void> allocate(Buyer buyer) async {
|
||||
await request("/buyer/allocate", "POST",
|
||||
payload: buyer.toMap(), token: await getToken());
|
||||
}
|
||||
|
||||
void filterStatus(String status, int _selectedIndex, int _sleectedSortIndex) {
|
||||
this.sortMenu.index = _sleectedSortIndex;
|
||||
buyers.clear();
|
||||
if (listener != null) {
|
||||
listener.cancel();
|
||||
}
|
||||
|
||||
this.popupMenu.index = _selectedIndex;
|
||||
String path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection";
|
||||
listener = getFilterStatusSnapshot(path, status, 'user_name')
|
||||
.listen((snaps) async {
|
||||
buyers.clear();
|
||||
snaps.documents.forEach((d) {
|
||||
buyers.add(Buyer.fromMap(d.data, d.documentID));
|
||||
});
|
||||
notifyListeners();
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<List<Buyer>> search(String searchBuyer) async {
|
||||
if (searchBuyer == null || searchBuyer == '') return List();
|
||||
|
||||
var bytes = utf8.encode(searchBuyer);
|
||||
var base64Str = base64.encode(bytes);
|
||||
HtmlEscape htmlEscape = const HtmlEscape();
|
||||
String escapeBuyer = htmlEscape.convert(base64Str);
|
||||
|
||||
int limit = 20;
|
||||
List<Buyer> _buyers = [];
|
||||
|
||||
try {
|
||||
var data = await request(
|
||||
"/api/fts/$buyer_collection/$escapeBuyer/$limit", "GET",
|
||||
token: await getToken(), url: Config.instance.reportURL);
|
||||
if (data == null) return List();
|
||||
|
||||
data.forEach((buyer) {
|
||||
var _buyer = Buyer.fromJson(buyer);
|
||||
_buyers.add(_buyer);
|
||||
});
|
||||
} catch (e) {
|
||||
// permission error
|
||||
log.warning("buyer error:" + e.toString());
|
||||
return null;
|
||||
}
|
||||
return _buyers;
|
||||
}
|
||||
|
||||
void filterSorting(int _sleectedSortIndex, int _selectedIndex) {
|
||||
this.popupMenu.index = _selectedIndex;
|
||||
buyers.clear();
|
||||
if (listener != null) {
|
||||
listener.cancel();
|
||||
}
|
||||
String _fieldName;
|
||||
bool descending = false;
|
||||
|
||||
if (_sleectedSortIndex == 0) {
|
||||
_fieldName = 'user_name';
|
||||
descending = false;
|
||||
}
|
||||
if (_sleectedSortIndex == 1) {
|
||||
_fieldName = 'user_name';
|
||||
descending = true;
|
||||
}
|
||||
if (_sleectedSortIndex == 2) {
|
||||
_fieldName = 'phone_number';
|
||||
descending = false;
|
||||
}
|
||||
if (_sleectedSortIndex == 3) {
|
||||
_fieldName = 'phone_number';
|
||||
descending = true;
|
||||
}
|
||||
|
||||
this.sortMenu.index = _sleectedSortIndex;
|
||||
String path = "/$biz_collection/${setting.okEnergyId}/$buyer_collection";
|
||||
listener =
|
||||
getFilterSnapshot(path, descending, _fieldName).listen((snaps) async {
|
||||
buyers.clear();
|
||||
snaps.documents.forEach((d) {
|
||||
buyers.add(Buyer.fromMap(d.data, d.documentID));
|
||||
notifyListeners();
|
||||
});
|
||||
|
||||
notifyListeners();
|
||||
});
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:fcs/config.dart';
|
||||
import 'package:fcs/model/firebase_helper.dart';
|
||||
import 'package:fcs/vo/po.dart';
|
||||
import 'package:fcs/vo/po_do_count.dart';
|
||||
import 'package:fcs/vo/revenue.dart';
|
||||
|
||||
import 'base_model.dart';
|
||||
import 'constants.dart';
|
||||
|
||||
class ChartModel extends BaseModel {
|
||||
final log = Logger('ChartModel');
|
||||
|
||||
List<POChartData> chartSummary = [];
|
||||
|
||||
Revenue revenue = new Revenue();
|
||||
PODOCount podoCount = new PODOCount();
|
||||
void initUser(user) async {
|
||||
super.initUser(user);
|
||||
revenue = new Revenue();
|
||||
podoCount = new PODOCount();
|
||||
|
||||
_loadRev();
|
||||
_loadPODOCount();
|
||||
if (user.hasPO() || user.isOwnerAndAbove()) {
|
||||
_getSummary();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadRev() async {
|
||||
try {
|
||||
String path = "/$biz_collection/${setting.okEnergyId}/$report_collection";
|
||||
String reportID = "revenue";
|
||||
|
||||
if (user.isBuyer()) {
|
||||
path =
|
||||
"/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$report_collection";
|
||||
reportID = "spending";
|
||||
}
|
||||
|
||||
getDocSnapshot(path, reportID).listen((DocumentSnapshot snapshot) async {
|
||||
if (snapshot.data == null) {
|
||||
return;
|
||||
}
|
||||
revenue = Revenue.fromMap(snapshot.data, snapshot.documentID);
|
||||
notifyListeners();
|
||||
}).onError((e) {
|
||||
log.warning("Error! $e");
|
||||
});
|
||||
} catch (e) {
|
||||
log.warning("Error!! $e");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadPODOCount() async {
|
||||
try {
|
||||
String path = "/$biz_collection/${setting.okEnergyId}/$report_collection";
|
||||
String reportID = "po_do_count";
|
||||
|
||||
if (user.isBuyer()) {
|
||||
path =
|
||||
"/$biz_collection/${setting.okEnergyId}/$buyer_collection/${user.docID}/$report_collection";
|
||||
}
|
||||
|
||||
getDocSnapshot(path, reportID).listen((DocumentSnapshot snapshot) async {
|
||||
if (snapshot.data == null) {
|
||||
return;
|
||||
}
|
||||
podoCount = PODOCount.fromMap(snapshot.data, snapshot.documentID);
|
||||
notifyListeners();
|
||||
}).onError((e) {
|
||||
log.warning("Error! $e");
|
||||
});
|
||||
} catch (e) {
|
||||
log.warning("Error!! $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
logout() async {
|
||||
chartSummary = [];
|
||||
revenue = new Revenue();
|
||||
podoCount = new PODOCount();
|
||||
}
|
||||
|
||||
_getSummary() async {
|
||||
chartSummary.clear();
|
||||
try {
|
||||
var data = {
|
||||
"fields": 'quantity,product_id,product_name,color',
|
||||
"aggfuns": "sum,,,",
|
||||
"groupbys": 'product_id',
|
||||
};
|
||||
var result = await request("/api/data/po_product_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
if (result == null) return;
|
||||
chartSummary.clear();
|
||||
result.forEach((chart) {
|
||||
var _list = POChartData.fromJson(chart, "quantity_sum");
|
||||
chartSummary.add(_list);
|
||||
});
|
||||
} catch (e) {
|
||||
log.warning("Error get Summary>>>>${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<POChartData>> loadSummary() async {
|
||||
List<POChartData> _list = List();
|
||||
try {
|
||||
var data = {
|
||||
"fields": 'quantity,product_id,product_name,color',
|
||||
"aggfuns": "sum,,,",
|
||||
"groupbys": 'product_id',
|
||||
};
|
||||
var result = await request("/api/data/po_product_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
if (result != null) {
|
||||
result.forEach((chart) {
|
||||
var _data = POChartData.fromJson(chart, "quantity_sum");
|
||||
_list.add(_data);
|
||||
});
|
||||
}
|
||||
return _list;
|
||||
} catch (e) {
|
||||
log.warning("Error>>>>${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<POChartData>> loadUsers() async {
|
||||
List<POChartData> _list = List();
|
||||
var data = {
|
||||
"fields": 'quantity,user_name,product_name',
|
||||
"aggfuns": "sum,,",
|
||||
"groupbys": 'product_id,user_id',
|
||||
};
|
||||
try {
|
||||
var result = await request("/api/data/po_product_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
|
||||
result.forEach((chart) {
|
||||
var _buyer = POChartData.fromJson(chart, "quantity_sum");
|
||||
_list.add(_buyer);
|
||||
});
|
||||
return _list;
|
||||
} catch (e) {
|
||||
log.warning("Error load>>>>${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<POBuyerData>> loadPOBalancesForBuyer_() async {
|
||||
List<POBuyerData> _list = List();
|
||||
try {
|
||||
var data = {
|
||||
"fields": 'amount,status',
|
||||
"aggfuns": "sum,",
|
||||
"groupbys": 'status',
|
||||
"filters": [
|
||||
{"field": "user_id", "compare": "==", "value": user.docID}
|
||||
]
|
||||
};
|
||||
var result = await request("/api/data/po_buyer_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
|
||||
if (result != null) {
|
||||
result.forEach((chart) {
|
||||
var _data = POBuyerData.fromJson(chart, "amount_sum");
|
||||
_list.add(_data);
|
||||
});
|
||||
}
|
||||
return _list;
|
||||
} catch (e) {
|
||||
log.warning("Error>>>>${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<POChartData>> loadPOBalancesForBuyer() async {
|
||||
List<POChartData> _list = List();
|
||||
try {
|
||||
var data = {
|
||||
"fields": 'quantity,product_id,product_name,user_id,color',
|
||||
"aggfuns": "sum,,,,",
|
||||
"groupbys": 'product_id,user_id',
|
||||
"filters": [
|
||||
{"field": "user_id", "compare": "==", "value": user.docID}
|
||||
]
|
||||
};
|
||||
var result = await request("/api/data/po_product_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
if (result != null) {
|
||||
result.forEach((chart) {
|
||||
var _data = POChartData.fromJson(chart, "quantity_sum");
|
||||
_list.add(_data);
|
||||
});
|
||||
}
|
||||
return _list;
|
||||
} catch (e) {
|
||||
log.warning("Error>>>>${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<POChartData>> loadPOBalProductsForBuyer() async {
|
||||
List<POChartData> _list = List();
|
||||
var data = {
|
||||
"fields": 'quantity,user_name,user_id,product_name',
|
||||
"aggfuns": "sum,,,",
|
||||
"groupbys": 'product_id,user_id',
|
||||
"filters": [
|
||||
{"field": "user_id", "compare": "==", "value": user.docID}
|
||||
]
|
||||
};
|
||||
try {
|
||||
var result = await request("/api/data/po_product_view", "POST",
|
||||
token: await getToken(),
|
||||
url: Config.instance.reportURL,
|
||||
payload: jsonEncode(data));
|
||||
result.forEach((chart) {
|
||||
var _buyer = POChartData.fromJson(chart, "quantity_sum");
|
||||
_list.add(_buyer);
|
||||
});
|
||||
return _list;
|
||||
} catch (e) {
|
||||
log.warning("Error load>>>>${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user