From 716d2f7b62f9003f624d340dc47329540121ab6b Mon Sep 17 00:00:00 2001 From: Benjamin Ramhorst Date: Thu, 10 Feb 2022 11:06:37 +0000 Subject: [PATCH] Added metrics page --- .../legbarkr/leg_barkr_app/MainActivity.kt | 3 +- lib/home.dart | 11 ++- lib/model/metrics_data.dart | 16 +++ lib/model/temp_series.dart | 6 ++ lib/utils/constants.dart | 13 +++ lib/view/data_page.dart | 10 -- lib/view/map_page.dart | 2 +- lib/view/metrics/metrics_min_max.dart | 26 +++++ lib/view/metrics/metrics_now.dart | 98 +++++++++++++++++++ lib/view/metrics/metrics_page.dart | 54 ++++++++++ lib/view/metrics/metrics_row.dart | 32 ++++++ lib/view/metrics/metrics_summary.dart | 27 +++++ lib/view/metrics/temp_chart.dart | 36 +++++++ lib/view/steps/steps_page.dart | 3 +- pubspec.lock | 14 +++ pubspec.yaml | 2 + 16 files changed, 335 insertions(+), 18 deletions(-) create mode 100644 lib/model/metrics_data.dart create mode 100644 lib/model/temp_series.dart create mode 100644 lib/utils/constants.dart delete mode 100644 lib/view/data_page.dart create mode 100644 lib/view/metrics/metrics_min_max.dart create mode 100644 lib/view/metrics/metrics_now.dart create mode 100644 lib/view/metrics/metrics_page.dart create mode 100644 lib/view/metrics/metrics_row.dart create mode 100644 lib/view/metrics/metrics_summary.dart create mode 100644 lib/view/metrics/temp_chart.dart diff --git a/android/app/src/main/kotlin/com/legbarkr/leg_barkr_app/MainActivity.kt b/android/app/src/main/kotlin/com/legbarkr/leg_barkr_app/MainActivity.kt index ff0eff6..227f50e 100644 --- a/android/app/src/main/kotlin/com/legbarkr/leg_barkr_app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/legbarkr/leg_barkr_app/MainActivity.kt @@ -2,5 +2,4 @@ package com.legbarkr.leg_barkr_app import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity: FlutterActivity() diff --git a/lib/home.dart b/lib/home.dart index 25f4d35..495a51d 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:leg_barkr_app/view/metrics/metrics_page.dart'; import 'package:leg_barkr_app/view/steps/steps_page.dart'; -import 'package:leg_barkr_app/view/data_page.dart'; import 'package:leg_barkr_app/view/map_page.dart'; import 'package:leg_barkr_app/view/settings_page.dart'; @@ -29,16 +29,21 @@ class _HomeScreenState extends State { body: PageView( controller: _pageController, children: const [ - DataPage(), + MetricsPage(), StepsPage(), MapPage(), SettingsPage() ], + onPageChanged: (page) { + setState(() { + _page = page; + }); + }, ), bottomNavigationBar: BottomNavigationBar( items: const [ BottomNavigationBarItem(icon: Icon(Icons.data_usage), label: 'Home'), - BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'), + BottomNavigationBarItem(icon: Icon(Icons.pets), label: 'Steps'), BottomNavigationBarItem(icon: Icon(Icons.location_on_outlined), label: 'Location'), BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'), ], diff --git a/lib/model/metrics_data.dart b/lib/model/metrics_data.dart new file mode 100644 index 0000000..26488e8 --- /dev/null +++ b/lib/model/metrics_data.dart @@ -0,0 +1,16 @@ +class MetricsData{ + double currentReading, lowestReading, highestReading, minimumPossible, maximumPossible, lowCutOff, highCutOff; + String metric, units; + + MetricsData( + this.currentReading, + this.lowestReading, + this.highestReading, + this.minimumPossible, + this.maximumPossible, + this.lowCutOff, + this.highCutOff, + this.metric, + this.units + ); +} \ No newline at end of file diff --git a/lib/model/temp_series.dart b/lib/model/temp_series.dart new file mode 100644 index 0000000..c3fa6c7 --- /dev/null +++ b/lib/model/temp_series.dart @@ -0,0 +1,6 @@ +class TempSeries { + final DateTime date; + final double temperature; + + TempSeries(this.date, this.temperature); +} \ No newline at end of file diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart new file mode 100644 index 0000000..5b1d596 --- /dev/null +++ b/lib/utils/constants.dart @@ -0,0 +1,13 @@ +const double LOW_AIR_TEMP_DOG = -5.0; +const double HIGH_AIR_TEMP_DOG = 29.0; +const double LOW_SKIN_TEMP_DOG = 37.5; +const double HIGH_SKIN_TEMP_DOG = 39.4; +const double LOW_HUMIDITY_DOG = 0.0; +const double HIGH_HUMIDITY_DOG = 100.0; + +const double MAX_AIR_TEMP = 50.0; +const double MIN_AIR_TEMP = -25.0; +const double MAX_SKIN_TEMP = 42; +const double MIN_SKIN_TEMP = 35; +const double MAX_HUMIDITY = 100; +const double MIN_HUMIDITY = 0; \ No newline at end of file diff --git a/lib/view/data_page.dart b/lib/view/data_page.dart deleted file mode 100644 index c34dc40..0000000 --- a/lib/view/data_page.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class DataPage extends StatelessWidget { - const DataPage({ Key? key }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Text("Data Page"); - } -} \ No newline at end of file diff --git a/lib/view/map_page.dart b/lib/view/map_page.dart index 7f1402d..c7b967e 100644 --- a/lib/view/map_page.dart +++ b/lib/view/map_page.dart @@ -11,7 +11,7 @@ class MapPage extends StatefulWidget { class _MapPageState extends State { late GoogleMapController _mapController; - // This will be changed, to center around the dog (once app reads data from the server) + // This will be changed, to center around the dog (once app reads metrics from the server) final LatLng _center = const LatLng(51.498356, -0.176894); void _onMapCreated(GoogleMapController mapController) { diff --git a/lib/view/metrics/metrics_min_max.dart b/lib/view/metrics/metrics_min_max.dart new file mode 100644 index 0000000..1eeeb5b --- /dev/null +++ b/lib/view/metrics/metrics_min_max.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class MetricsMinMax extends StatelessWidget { + double lowest, highest; + String units; + + MetricsMinMax(this.lowest, this.highest, this.units); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.fromLTRB(0.0, 10.0, 5.0, 10.0), + child: Text("Minimum\n" + lowest.toString() + " " + units, textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold)) + ), + Padding( + padding: EdgeInsets.fromLTRB(5.0, 10.0, 0.0, 10.0), + child: Text("Maximum\n" + highest.toString() + " " + units, textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold)) + ) + ], + ); + } +} \ No newline at end of file diff --git a/lib/view/metrics/metrics_now.dart b/lib/view/metrics/metrics_now.dart new file mode 100644 index 0000000..f18b4cb --- /dev/null +++ b/lib/view/metrics/metrics_now.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:leg_barkr_app/model/metrics_data.dart'; +import 'package:syncfusion_flutter_gauges/gauges.dart'; + +class MetricsNow extends StatelessWidget { + MetricsData data; + Color textColor; + bool showGauge; + + MetricsNow(this.data, this.textColor, this.showGauge); + + @override + Widget build(BuildContext context) { + if (showGauge) { + return SizedBox( + height: 150, + width: 150, + child: SfRadialGauge( + axes: [ + RadialAxis( + minimum: data.minimumPossible, + maximum: data.maximumPossible, + ranges: [ + GaugeRange( + startValue: data.minimumPossible, + endValue: data.lowCutOff, + color: Colors.blue, + startWidth: 10, + endWidth: 10), + GaugeRange( + startValue: data.lowCutOff, + endValue: data.highCutOff, + color: textColor, + startWidth: 10, + endWidth: 10), + GaugeRange( + startValue: data.highCutOff, + endValue: data.maximumPossible, + color: Colors.red, + startWidth: 10, + endWidth: 10) + ], + pointers: [ + MarkerPointer( + value: data.currentReading, + color: Colors.black, + markerWidth: 20) + ], + annotations: [ + GaugeAnnotation( + angle: 90, + positionFactor: 0.75, + widget: Column( + children: [ + Text(data.currentReading.toString(), + style: TextStyle(fontSize: 26, + color: textColor, + fontWeight: FontWeight.bold)), + Text(data.units, style: TextStyle(fontSize: 16, + color: textColor, + fontWeight: FontWeight.bold)), + ], + ) + ) + ] + ) + ] + ) + ); + } else { + return ElevatedButton( + onPressed: () {}, + child:Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(data.currentReading.toString(), + style: TextStyle(fontSize: 32, + color: textColor, + fontWeight: FontWeight.bold)), + Text(data.units, style: TextStyle(fontSize: 18, + color: textColor, + fontWeight: FontWeight.bold)), + ], + ), + style: ElevatedButton.styleFrom( + alignment: Alignment.center, + side: BorderSide(width: 15.0, color: textColor), + shape: CircleBorder(), + padding: EdgeInsets.all(25), + primary: Colors.green, + minimumSize: Size(150, 150), + maximumSize: Size(150, 150) + ), + ); + } + } +} \ No newline at end of file diff --git a/lib/view/metrics/metrics_page.dart b/lib/view/metrics/metrics_page.dart new file mode 100644 index 0000000..30325db --- /dev/null +++ b/lib/view/metrics/metrics_page.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:leg_barkr_app/model/metrics_data.dart'; +import 'package:leg_barkr_app/model/temp_series.dart'; +import 'metrics_row.dart'; +import 'package:leg_barkr_app/utils/constants.dart' as Constants; + +import 'temp_chart.dart'; + +class MetricsPage extends StatefulWidget { + const MetricsPage({ Key? key }) : super(key: key); + + @override + _MetricsPageState createState() => _MetricsPageState(); +} + +class _MetricsPageState extends State { + // Dummy data, will be removed + final List data = [ + TempSeries(DateTime.parse('2022-02-09 20:00:00Z'), 38.4), + TempSeries(DateTime.parse('2022-02-09 19:30:00Z'), 38.8), + TempSeries(DateTime.parse('2022-02-09 19:00:00Z'), 38.2), + TempSeries(DateTime.parse('2022-02-09 18:30:00Z'), 39.2), + TempSeries(DateTime.parse('2022-02-09 18:00:00Z'), 39.5), + TempSeries(DateTime.parse('2022-02-09 17:30:00Z'), 37.8) + ]; + + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.fromLTRB(0.0, 50.0, 0.0, 0.0), + child: Expanded( + child: ListView( + padding: EdgeInsets.all(5.0), + children: [ + Text("Today's summary", textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontSize: 36, fontWeight: FontWeight.bold)), + + // Dummy data + MetricsRow(new MetricsData(38.6, 38.1, 39.2, Constants.MIN_SKIN_TEMP, Constants.MAX_SKIN_TEMP, Constants.LOW_SKIN_TEMP_DOG, Constants.HIGH_SKIN_TEMP_DOG, "Skin temperature", "°C"), Colors.white, Colors.green, true), + MetricsRow(new MetricsData(22, 16, 34, Constants.MIN_HUMIDITY, Constants.MAX_HUMIDITY, Constants.LOW_HUMIDITY_DOG, Constants.HIGH_HUMIDITY_DOG, "Humidity", "%"), Colors.green, Colors.black, false), + MetricsRow(new MetricsData(24, 21, 29, Constants.MIN_AIR_TEMP, Constants.MAX_AIR_TEMP, Constants.LOW_AIR_TEMP_DOG, Constants.HIGH_AIR_TEMP_DOG, "Air temperature", "°C"), Colors.white, Colors.green, true), + + Padding( + padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0), + child: Text("Today's temperature", textAlign: TextAlign.center, style: TextStyle(color: Colors.black, fontSize: 36, fontWeight: FontWeight.bold)), + ), + TempChart(data) + + ] + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/view/metrics/metrics_row.dart b/lib/view/metrics/metrics_row.dart new file mode 100644 index 0000000..b7c4c98 --- /dev/null +++ b/lib/view/metrics/metrics_row.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:leg_barkr_app/model/metrics_data.dart'; +import 'metrics_now.dart'; +import 'metrics_summary.dart'; + +class MetricsRow extends StatelessWidget { + MetricsData data; + Color backgroundColour; + Color textColour; + bool showGauge; + + MetricsRow(this.data, this.backgroundColour, this.textColour, this.showGauge); + + @override + Widget build(BuildContext context) { + return Card( + elevation: 10, + shadowColor: Colors.black, + color: backgroundColour, + child: Padding( + padding: EdgeInsets.all(5.0), + child: Row( + children: [ + MetricsNow(data, textColour, showGauge), + MetricsSummary(data, textColour) + ], + ), + ), + ); + } + +} \ No newline at end of file diff --git a/lib/view/metrics/metrics_summary.dart b/lib/view/metrics/metrics_summary.dart new file mode 100644 index 0000000..2483905 --- /dev/null +++ b/lib/view/metrics/metrics_summary.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:leg_barkr_app/model/metrics_data.dart'; +import 'metrics_min_max.dart'; + +class MetricsSummary extends StatelessWidget { + MetricsData data; + Color textColour; + + MetricsSummary(this.data, this.textColour); + + @override + Widget build(BuildContext context) { + return Expanded( + child: Padding( + padding: EdgeInsets.all(15.0), + child: Center( + child: Column( + children: [ + Text(data.metric, textAlign: TextAlign.center, style: TextStyle(color: textColour, fontSize: 24, fontWeight: FontWeight.bold)), + MetricsMinMax(data.lowestReading, data.highestReading, data.units) + ], + ) + ) + ) + ); + } +} \ No newline at end of file diff --git a/lib/view/metrics/temp_chart.dart b/lib/view/metrics/temp_chart.dart new file mode 100644 index 0000000..37e2d17 --- /dev/null +++ b/lib/view/metrics/temp_chart.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:charts_flutter/flutter.dart' as charts; +import 'package:leg_barkr_app/model/temp_series.dart'; +import 'package:leg_barkr_app/utils/constants.dart' as Constants; + +class TempChart extends StatelessWidget { + List tempData; + + TempChart(this.tempData); + + @override + Widget build(BuildContext context) { + List> series = [ + charts.Series( + id: "Temperature", + data: tempData, + domainFn: (TempSeries series, _) => series.date, + measureFn: (TempSeries series, _) => series.temperature, + colorFn: (TempSeries series, _) => charts.ColorUtil.fromDartColor(Colors.green) + ) + ]; + + return Container( + height: 600, + width: double.infinity, + child: charts.TimeSeriesChart( + series, + animate: true, + primaryMeasureAxis: const charts.NumericAxisSpec( + tickProviderSpec: charts.BasicNumericTickProviderSpec(zeroBound: false), + viewport: charts.NumericExtents(Constants.MIN_SKIN_TEMP, Constants.MAX_SKIN_TEMP), + ),) + ); + } + +} \ No newline at end of file diff --git a/lib/view/steps/steps_page.dart b/lib/view/steps/steps_page.dart index 2c2c3c9..5806796 100644 --- a/lib/view/steps/steps_page.dart +++ b/lib/view/steps/steps_page.dart @@ -1,4 +1,3 @@ -import 'package:charts_flutter/flutter.dart' as charts; import 'package:flutter/material.dart'; import 'package:leg_barkr_app/model/steps_series.dart'; import 'package:leg_barkr_app/view/steps/steps_chart.dart'; @@ -12,7 +11,7 @@ class StepsPage extends StatefulWidget { } class _StepsPageState extends State { - // Dummy data + // Dummy metrics final List data = [ StepsSeries(DateTime.utc(2022, 2, 9), 9867), StepsSeries(DateTime.utc(2022, 2, 8), 8123), diff --git a/pubspec.lock b/pubspec.lock index 2408d0c..9990d18 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -266,6 +266,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + url: "https://pub.dartlang.org" + source: hosted + version: "19.4.50" + syncfusion_flutter_gauges: + dependency: "direct main" + description: + name: syncfusion_flutter_gauges + url: "https://pub.dartlang.org" + source: hosted + version: "19.4.50" term_glyph: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f5ae781..c1ad566 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,8 @@ dependencies: google_maps_flutter: ^2.1.1 google_maps_flutter_web: ^0.3.2+1 charts_flutter: ^0.12.0 + syncfusion_flutter_gauges: ^19.4.50 + dev_dependencies: flutter_test: