From d7625f7b88fa6c75938a033c67f66eea43ef1d4e Mon Sep 17 00:00:00 2001 From: Felix Date: Thu, 18 Jul 2019 12:05:09 +0100 Subject: [PATCH] implementing API graphs and getting frustrated at async stuff --- To Do List.txt | 17 -- android/build.gradle | 2 +- lib/common/apifunctions/get_graph_data.dart | 59 ++++++- .../widgets/charts/time_series_simple.dart | 60 +++++++ lib/main.dart | 4 +- lib/pages/receipt_page.dart | 4 +- lib/pages/stats_page.dart | 157 ++---------------- 7 files changed, 134 insertions(+), 169 deletions(-) delete mode 100644 To Do List.txt create mode 100644 lib/common/widgets/charts/time_series_simple.dart diff --git a/To Do List.txt b/To Do List.txt deleted file mode 100644 index 6617c34..0000000 --- a/To Do List.txt +++ /dev/null @@ -1,17 +0,0 @@ -TODO - ⁃ Show username - ⁃ add ‘confirm logout’ - - Splash Screen - ⁃ Splash screen transition - fade - - Login - ⁃ save login details option (checkbox or something) - - Navigation - ⁃ Make it look good - - Submit Receipt - ⁃ Categories - ⁃ Recurring - ⁃ 'organisation name' dialog works diff --git a/android/build.gradle b/android/build.gradle index 541636c..f44bb13 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,4 +26,4 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/lib/common/apifunctions/get_graph_data.dart b/lib/common/apifunctions/get_graph_data.dart index e217901..995ecfe 100644 --- a/lib/common/apifunctions/get_graph_data.dart +++ b/lib/common/apifunctions/get_graph_data.dart @@ -2,13 +2,12 @@ import 'dart:convert'; import 'dart:async'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; - -enum DataPoint {date, String} +import 'package:charts_flutter/flutter.dart' as charts; class GraphData { - List data = new List(); + List data = new List(); - Future> getGraphData(String graphType) async { + Future> getGraphData(String graphType) async { /// Graph types: /// - total_last_week /// - avg_spend_last_week @@ -18,6 +17,7 @@ class GraphData { /// HTTP POST request sample: /// {"graph":"total_last_week","session_key":"blahblahblah"} + charts.Series dataSeries = new charts.Series(); final url = "https://dev.peartrade.org/api/v1/customer/graphs"; SharedPreferences preferences = await SharedPreferences.getInstance(); @@ -33,17 +33,62 @@ class GraphData { if (response.statusCode == 200) { final responseJson = jsonDecode(response.body); - final labels = responseJson['graph']['labels']; - final data = responseJson['graph']['data']; -// final bounds = responseJson['graph']['bounds']; // why is this even returned? + final List labels = responseJson['graph']['labels']; + final List data = responseJson['graph']['data']; +// final List bounds = responseJson['graph']['bounds']; // why is this even returned? + + /* + 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), + ]; + */ + + List timeSeriesSpendList = new List(); + + for (int i = 0; i < labels.length; i++) { + print(DateTime(labels[i])); + timeSeriesSpendList.add(new TimeSeriesSpend(data[i], DateTime(labels[i]))); + } + + return [ + new charts.Series( + id: 'Spend', + colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault, + domainFn: (TimeSeriesSpend spend, _) => spend.time, + measureFn: (TimeSeriesSpend spend, _) => spend.spend, + data: timeSeriesSpendList, + ) + ]; + + /* + new charts.Series( + id: 'Sales', + colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault, + domainFn: (TimeSeriesSales sales, _) => sales.time, + measureFn: (TimeSeriesSales sales, _) => sales.sales, + data: data, + )*/ + // print(labels[5]); // print(data[5]); } else { final errorMessage = json.decode(response.body)['message']; print("Error: " + errorMessage); + + return null; } } } +class TimeSeriesSpend { + final DateTime time; + final int spend; + + TimeSeriesSpend(this.spend, this.time); +} + diff --git a/lib/common/widgets/charts/time_series_simple.dart b/lib/common/widgets/charts/time_series_simple.dart new file mode 100644 index 0000000..8144c67 --- /dev/null +++ b/lib/common/widgets/charts/time_series_simple.dart @@ -0,0 +1,60 @@ +/// Timeseries chart example +import 'package:charts_flutter/flutter.dart' as charts; +import 'package:flutter/material.dart'; + +class SimpleTimeSeriesChart extends StatelessWidget { + final List 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: true, + ); + } + + + @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> _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( + 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); +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 7970364..fe77db1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,8 +15,8 @@ void main() { class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - GraphData gd = new GraphData(); - gd.getGraphData('total_last_week'); +// GraphData gd = new GraphData(); +// gd.getGraphData('total_last_week'); //var config = ConfigWrapper.of(context); return new MaterialApp( diff --git a/lib/pages/receipt_page.dart b/lib/pages/receipt_page.dart index 343072e..d7ffa40 100644 --- a/lib/pages/receipt_page.dart +++ b/lib/pages/receipt_page.dart @@ -204,7 +204,7 @@ class ReceiptPageState extends State { List getRecurringOptions() { var options = new List(7); - options[0] = "None"; + options[0] = "None"; // this should not be hardcoded and should be fetched from API instead options[1] = "Daily"; options[2] = "Weekly"; options[3] = "Fortnightly"; @@ -556,7 +556,7 @@ class ReceiptPageState extends State { value: value, child: Text(value), ); - }).toList(), + }).toList(), // fix errors here by [items] being an empty container while _categoryDropDownItems is null ) ), ], diff --git a/lib/pages/stats_page.dart b/lib/pages/stats_page.dart index aefe483..5e94df9 100644 --- a/lib/pages/stats_page.dart +++ b/lib/pages/stats_page.dart @@ -12,6 +12,9 @@ import 'package:local_spend/common/widgets/charts/grouped_bar_chart.dart'; import 'package:local_spend/common/widgets/charts/scatter_bucketingAxis_legend.dart'; import 'package:local_spend/common/widgets/charts/numeric_line_bar_combo.dart'; import 'package:local_spend/common/widgets/charts/series_legend_with_measures.dart'; +import 'package:local_spend/common/widgets/charts/time_series_simple.dart'; +import 'package:local_spend/common/apifunctions/get_graph_data.dart'; +import 'package:charts_flutter/flutter.dart' as charts; const URL = "https://flutter.io/"; const demonstration = false; @@ -25,6 +28,9 @@ class StatsPage extends StatefulWidget { class StatsPageState extends State { + GraphData graphData = new GraphData(); + List totalLastWeek; + @override void initState() { super.initState(); @@ -43,6 +49,15 @@ class StatsPageState extends State { @override Widget build(BuildContext context) { + if (graphData.data != null) { + graphData.getGraphData('total_last_week').then((val) { + totalLastWeek = val; + setState(() { + // update view + }); + }); + } + return PlatformScaffold( appBar: AppBar( backgroundColor: Colors.blue[400], @@ -63,30 +78,11 @@ class StatsPageState extends State { padding: EdgeInsets.fromLTRB(0, 0, 0, 0), child: ListView( children: [ - // some graphs and charts here etc -// Container( -// padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), -// child : Text( -// "Really Cool Chart", -// textAlign: TextAlign.center, -// style: TextStyle( -// fontSize: 22.0, -// color: Colors.black, -// fontWeight: FontWeight.bold, -// ), -// ), -// ), -// -// Container( -// height: 250, -//// width: 250, -// child: new DonutPieChart.withSampleData() -// ), Container( padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), child : Text( - "GroupedBarChart", + "This Week's Spend", textAlign: TextAlign.center, style: TextStyle( fontSize: 22.0, @@ -100,127 +96,8 @@ class StatsPageState extends State { padding: EdgeInsets.symmetric(horizontal: 10), height: 200, // width: 250, - child: new GroupedBarChart.withSampleData() - ), - Container( - padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), - child : Text( - "BucketingAxisScatterPlotChart", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new BucketingAxisScatterPlotChart.withSampleData() - ), - - Container( - padding: EdgeInsets.fromLTRB(0.0,20,0.0,0.0), - child : Text( - "PieOutsideLabelChart", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new PieOutsideLabelChart.withSampleData() - ), - - Container( - padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), - child : Text( - "DonutAutoLabelChart", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new DonutAutoLabelChart.withSampleData() - ), - - Container( - padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), - child : Text( - "DonutPieChart", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new DonutPieChart.withSampleData() - ), - - Container( - padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), - child : Text( - "NumericComboLineBarChart", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new NumericComboLineBarChart.withSampleData() - ), - - Container( - padding: EdgeInsets.fromLTRB(0.0,17,0.0,0.0), - child : Text( - "LegendWithMeasures", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 22.0, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ), - ), - - Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 200, -// width: 250, - child: new LegendWithMeasures.withSampleData() + child: new SimpleTimeSeriesChart(totalLastWeek),//seriesList: List ), ],