WIP #120 History chart based on attributes
This commit is contained in:
		| @@ -4,6 +4,13 @@ class ClimateEntity extends Entity { | |||||||
|   @override |   @override | ||||||
|   double widgetHeight = 38.0; |   double widgetHeight = 38.0; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   EntityHistoryConfig historyConfig = EntityHistoryConfig( | ||||||
|  |     chartType: EntityHistoryWidgetType.numericAttributes, | ||||||
|  |     numericState: false, | ||||||
|  |     numericAttributesToShow: ["temperature", "current_temperature"] | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   static const SUPPORT_TARGET_TEMPERATURE = 1; |   static const SUPPORT_TARGET_TEMPERATURE = 1; | ||||||
|   static const SUPPORT_TARGET_TEMPERATURE_HIGH = 2; |   static const SUPPORT_TARGET_TEMPERATURE_HIGH = 2; | ||||||
|   static const SUPPORT_TARGET_TEMPERATURE_LOW = 4; |   static const SUPPORT_TARGET_TEMPERATURE_LOW = 4; | ||||||
|   | |||||||
| @@ -38,7 +38,9 @@ class Entity { | |||||||
|  |  | ||||||
|   List<Entity> childEntities = []; |   List<Entity> childEntities = []; | ||||||
|   List<String> attributesToShow = ["all"]; |   List<String> attributesToShow = ["all"]; | ||||||
|   int historyWidgetType = EntityHistoryWidgetType.simple; |   EntityHistoryConfig historyConfig = EntityHistoryConfig( | ||||||
|  |     chartType: EntityHistoryWidgetType.simple | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   String get displayName => |   String get displayName => | ||||||
|       attributes["friendly_name"] ?? (attributes["name"] ?? "_"); |       attributes["friendly_name"] ?? (attributes["name"] ?? "_"); | ||||||
| @@ -136,7 +138,7 @@ class Entity { | |||||||
|  |  | ||||||
|   Widget buildHistoryWidget() { |   Widget buildHistoryWidget() { | ||||||
|     return EntityHistoryWidget( |     return EntityHistoryWidget( | ||||||
|       type: historyWidgetType, |       config: historyConfig, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,7 +7,10 @@ class SunEntity extends Entity { | |||||||
| class SensorEntity extends Entity { | class SensorEntity extends Entity { | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   int historyWidgetType = EntityHistoryWidgetType.valueToTime; |   EntityHistoryConfig historyConfig = EntityHistoryConfig( | ||||||
|  |       chartType: EntityHistoryWidgetType.numericState, | ||||||
|  |       numericState: true | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   SensorEntity(Map rawData) : super(rawData); |   SensorEntity(Map rawData) : super(rawData); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ class EntityColors { | |||||||
|         charts.Color c1 = charts.MaterialPalette.getOrderedPalettes(id + 1)[id].shadeDefault; |         charts.Color c1 = charts.MaterialPalette.getOrderedPalettes(id + 1)[id].shadeDefault; | ||||||
|         return Color.fromARGB(c1.a, c1.r, c1.g, c1.b); |         return Color.fromARGB(c1.a, c1.r, c1.g, c1.b); | ||||||
|       } else { |       } else { | ||||||
|         return _stateColors["default"]; |         return _stateColors["on"]; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
							
								
								
									
										264
									
								
								lib/entity_widgets/history_chart/combined_history_chart.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								lib/entity_widgets/history_chart/combined_history_chart.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,264 @@ | |||||||
|  | part of '../../main.dart'; | ||||||
|  |  | ||||||
|  | class CombinedHistoryChartWidget extends StatefulWidget { | ||||||
|  |   final rawHistory; | ||||||
|  |   final EntityHistoryConfig config; | ||||||
|  |  | ||||||
|  |   const CombinedHistoryChartWidget({Key key, @required this.rawHistory, @required this.config}) : super(key: key); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<StatefulWidget> createState() { | ||||||
|  |     return new _CombinedHistoryChartWidgetState(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CombinedHistoryChartWidgetState extends State<CombinedHistoryChartWidget> { | ||||||
|  |  | ||||||
|  |   int _selectedId = -1; | ||||||
|  |   List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> _parsedHistory; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     _parsedHistory = _parseHistory(); | ||||||
|  |     DateTime selectedTime; | ||||||
|  |     List<String> selectedStates = []; | ||||||
|  |     List<int> colorIndexes = []; | ||||||
|  |     if ((_selectedId > -1) && (_parsedHistory != null) && (_parsedHistory.first.data.length >= (_selectedId + 1))) { | ||||||
|  |       selectedTime = _parsedHistory.first.data[_selectedId].time; | ||||||
|  |       _parsedHistory.where((item) { return item.id == "value"; }).forEach((item) { | ||||||
|  |         selectedStates.add("${item.data[_selectedId].value}"); | ||||||
|  |         colorIndexes.add(item.data[_selectedId].colorId); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |     return Column( | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.start, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: <Widget>[ | ||||||
|  |         CombinedHistoryControlWidget( | ||||||
|  |           selectedTimeStart: selectedTime, | ||||||
|  |           selectedStates: selectedStates, | ||||||
|  |           onPrevTap: () => _selectPrev(), | ||||||
|  |           onNextTap: () => _selectNext(), | ||||||
|  |           colorIndexes: colorIndexes, | ||||||
|  |         ), | ||||||
|  |         SizedBox( | ||||||
|  |           height: 150.0, | ||||||
|  |           child: charts.TimeSeriesChart( | ||||||
|  |             _parsedHistory, | ||||||
|  |             animate: false, | ||||||
|  |             primaryMeasureAxis: new charts.NumericAxisSpec( | ||||||
|  |                 tickProviderSpec: | ||||||
|  |                 new charts.BasicNumericTickProviderSpec(zeroBound: false)), | ||||||
|  |             dateTimeFactory: const charts.LocalDateTimeFactory(), | ||||||
|  |             defaultRenderer: charts.LineRendererConfig(includeArea: false), | ||||||
|  |             customSeriesRenderers: [ | ||||||
|  |               new charts.PointRendererConfig( | ||||||
|  |                 // ID used to link series to this renderer. | ||||||
|  |                   customRendererId: 'valuePoints') | ||||||
|  |             ], | ||||||
|  |             /*primaryMeasureAxis: charts.NumericAxisSpec( | ||||||
|  |                 renderSpec: charts.NoneRenderSpec() | ||||||
|  |             ),*/ | ||||||
|  |             selectionModels: [ | ||||||
|  |               new charts.SelectionModelConfig( | ||||||
|  |                 type: charts.SelectionModelType.info, | ||||||
|  |                 listener: (model) => _onSelectionChanged(model), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |             behaviors: [ | ||||||
|  |               charts.PanAndZoomBehavior(), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ) | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   double _parseToDouble(temp1) { | ||||||
|  |     if (temp1 is int) { | ||||||
|  |       return temp1.toDouble(); | ||||||
|  |     } else if (temp1 is double) { | ||||||
|  |       return temp1; | ||||||
|  |     } else { | ||||||
|  |       return double.tryParse("$temp1"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> _parseHistory() { | ||||||
|  |     TheLogger.debug("  parsing history..."); | ||||||
|  |     Map<String, List<CombinedEntityStateHistoryMoment>> dataList = {}; | ||||||
|  |     int colorIdCounter = 0; | ||||||
|  |     widget.config.numericAttributesToShow.forEach((String attrName) { | ||||||
|  |       TheLogger.debug("    parsing attribute $attrName"); | ||||||
|  |       List<CombinedEntityStateHistoryMoment> data = []; | ||||||
|  |       DateTime now = DateTime.now(); | ||||||
|  |       for (var i = 0; i < widget.rawHistory.length; i++) { | ||||||
|  |         var stateData = widget.rawHistory[i]; | ||||||
|  |         DateTime time = DateTime.tryParse(stateData["last_updated"])?.toLocal(); | ||||||
|  |         if (stateData["attributes"] != null) { | ||||||
|  |           data.add(CombinedEntityStateHistoryMoment(_parseToDouble(stateData["attributes"]["$attrName"]), stateData["state"], time, i, colorIdCounter)); | ||||||
|  |         } else { | ||||||
|  |           data.add(CombinedEntityStateHistoryMoment(null, stateData["state"], time, i, colorIdCounter)); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       data.add(CombinedEntityStateHistoryMoment(data.last.value, data.last.state, now, widget.rawHistory.length, colorIdCounter)); | ||||||
|  |       dataList.addAll({attrName: data}); | ||||||
|  |       colorIdCounter += 1; | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     if ((_selectedId == -1) && (dataList.isNotEmpty)) { | ||||||
|  |       _selectedId = 0; | ||||||
|  |     } | ||||||
|  |     List<charts.Series<CombinedEntityStateHistoryMoment, DateTime>> result = []; | ||||||
|  |     dataList.forEach((attrName, dataItem) { | ||||||
|  |       TheLogger.debug("  adding ${dataItem.length} data values"); | ||||||
|  |       result.addAll([ | ||||||
|  |         new charts.Series<CombinedEntityStateHistoryMoment, DateTime>( | ||||||
|  |           id: "value", | ||||||
|  |           colorFn: (CombinedEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("_", historyMoment.colorId), | ||||||
|  |           domainFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.time, | ||||||
|  |           measureFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.value, | ||||||
|  |           data: dataItem, | ||||||
|  |         ), | ||||||
|  |         new charts.Series<CombinedEntityStateHistoryMoment, DateTime>( | ||||||
|  |           id: "points", | ||||||
|  |           radiusPxFn: (CombinedEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 1.0, | ||||||
|  |           colorFn: (CombinedEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("_", historyMoment.colorId), | ||||||
|  |           domainFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.time, | ||||||
|  |           measureFn: (CombinedEntityStateHistoryMoment historyMoment, _) => historyMoment.value, | ||||||
|  |           data: dataItem, | ||||||
|  |         )..setAttribute(charts.rendererIdKey, 'valuePoints') | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|  |     return result; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void _selectPrev() { | ||||||
|  |     if (_selectedId > 0) { | ||||||
|  |       setState(() { | ||||||
|  |         _selectedId -= 1; | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void _selectNext() { | ||||||
|  |     if (_selectedId < (_parsedHistory.first.data.length - 1)) { | ||||||
|  |       setState(() { | ||||||
|  |         _selectedId += 1; | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void _onSelectionChanged(charts.SelectionModel model) { | ||||||
|  |     final selectedDatum = model.selectedDatum; | ||||||
|  |  | ||||||
|  |     int selectedId; | ||||||
|  |  | ||||||
|  |     if (selectedDatum.isNotEmpty) { | ||||||
|  |       selectedId = selectedDatum.first.datum.id; | ||||||
|  |       setState(() { | ||||||
|  |         _selectedId = selectedId; | ||||||
|  |       }); | ||||||
|  |     } else { | ||||||
|  |       setState(() { | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class CombinedHistoryControlWidget extends StatelessWidget { | ||||||
|  |  | ||||||
|  |   final Function onPrevTap; | ||||||
|  |   final Function onNextTap; | ||||||
|  |   final DateTime selectedTimeStart; | ||||||
|  |   final DateTime selectedTimeEnd; | ||||||
|  |   final List<String> selectedStates; | ||||||
|  |   final List<int> colorIndexes; | ||||||
|  |  | ||||||
|  |   const CombinedHistoryControlWidget({Key key, this.onPrevTap, this.onNextTap, this.selectedTimeStart, this.selectedTimeEnd, this.selectedStates, @ required this.colorIndexes}) : super(key: key); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     if (selectedTimeStart != null) { | ||||||
|  |       return | ||||||
|  |         Row( | ||||||
|  |           mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |           crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |           children: <Widget>[ | ||||||
|  |             IconButton( | ||||||
|  |               icon: Icon(Icons.chevron_left), | ||||||
|  |               padding: EdgeInsets.all(0.0), | ||||||
|  |               iconSize: 40.0, | ||||||
|  |               onPressed: onPrevTap, | ||||||
|  |             ), | ||||||
|  |             Expanded( | ||||||
|  |               child: Padding( | ||||||
|  |                 padding: EdgeInsets.only(right: 10.0), | ||||||
|  |                 child: _buildStates(), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |             _buildTime(), | ||||||
|  |             IconButton( | ||||||
|  |               icon: Icon(Icons.chevron_right), | ||||||
|  |               padding: EdgeInsets.all(0.0), | ||||||
|  |               iconSize: 40.0, | ||||||
|  |               onPressed: onNextTap, | ||||||
|  |             ), | ||||||
|  |           ], | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |     } else { | ||||||
|  |       return Container(height: 48.0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget _buildStates() { | ||||||
|  |     List<Widget> children = []; | ||||||
|  |     for (int i = 0; i < selectedStates.length; i++) { | ||||||
|  |       children.add( | ||||||
|  |           Text( | ||||||
|  |             "${selectedStates[i]}", | ||||||
|  |             textAlign: TextAlign.right, | ||||||
|  |             style: TextStyle( | ||||||
|  |                 fontWeight: FontWeight.bold, | ||||||
|  |                 color: EntityColors.historyStateColor(selectedStates[i], colorIndexes[i]), | ||||||
|  |                 fontSize: 22.0 | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     return Column( | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.end, | ||||||
|  |       children: children, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget _buildTime() { | ||||||
|  |     List<Widget> children = []; | ||||||
|  |     children.add( | ||||||
|  |         Text("${formatDate(selectedTimeStart, [M, ' ', d, ', ', HH, ':', nn, ':', ss])}", textAlign: TextAlign.left,) | ||||||
|  |     ); | ||||||
|  |     if (selectedTimeEnd != null) { | ||||||
|  |       children.add( | ||||||
|  |           Text("${formatDate(selectedTimeEnd, [M, ' ', d, ', ', HH, ':', nn, ':', ss])}", textAlign: TextAlign.left,) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     return Column( | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |       children: children, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class CombinedEntityStateHistoryMoment { | ||||||
|  |   final DateTime time; | ||||||
|  |   final double value; | ||||||
|  |   final int id; | ||||||
|  |   final int colorId; | ||||||
|  |   final String state; | ||||||
|  |  | ||||||
|  |   CombinedEntityStateHistoryMoment(this.value, this.state, this.time,  this.id, this.colorId); | ||||||
|  | } | ||||||
| @@ -2,15 +2,24 @@ part of '../../main.dart'; | |||||||
|  |  | ||||||
| class EntityHistoryWidgetType { | class EntityHistoryWidgetType { | ||||||
|   static const int simple = 0; |   static const int simple = 0; | ||||||
|   static const int valueToTime = 1; |   static const int numericState = 1; | ||||||
|   static const int randomColors = 2; |   static const int numericAttributes = 2; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class EntityHistoryConfig { | ||||||
|  |   final int chartType; | ||||||
|  |   final List<String> numericAttributesToShow; | ||||||
|  |   final bool numericState; | ||||||
|  |  | ||||||
|  |   EntityHistoryConfig({this.chartType, this.numericAttributesToShow, this.numericState: true}); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| class EntityHistoryWidget extends StatefulWidget { | class EntityHistoryWidget extends StatefulWidget { | ||||||
|  |  | ||||||
|   final int type; |   final EntityHistoryConfig config; | ||||||
|  |  | ||||||
|   const EntityHistoryWidget({Key key, @required this.type}) : super(key: key); |   const EntityHistoryWidget({Key key, @required this.config}) : super(key: key); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   _EntityHistoryWidgetState createState() { |   _EntityHistoryWidgetState createState() { | ||||||
| @@ -74,7 +83,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> { | |||||||
|     } |     } | ||||||
|     children.add(Divider()); |     children.add(Divider()); | ||||||
|     return Padding( |     return Padding( | ||||||
|       padding: EdgeInsets.fromLTRB(0.0, Entity.rowPadding, 0.0, Entity.rowPadding), |       padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, Entity.rowPadding), | ||||||
|       child: Column( |       child: Column( | ||||||
|         children: children, |         children: children, | ||||||
|       ), |       ), | ||||||
| @@ -82,20 +91,34 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget _selectChartWidget() { |   Widget _selectChartWidget() { | ||||||
|     switch (widget.type) { |     TheLogger.debug("  selecting history widget (${widget.config.chartType})"); | ||||||
|  |     switch (widget.config.chartType) { | ||||||
|  |  | ||||||
|       case EntityHistoryWidgetType.simple: { |       case EntityHistoryWidgetType.simple: { | ||||||
|  |           TheLogger.debug("  Simple selected"); | ||||||
|           return SimpleStateHistoryChartWidget( |           return SimpleStateHistoryChartWidget( | ||||||
|             rawHistory: _history, |             rawHistory: _history, | ||||||
|           ); |           ); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       case EntityHistoryWidgetType.valueToTime: { |       case EntityHistoryWidgetType.numericState: { | ||||||
|  |         TheLogger.debug("  EntityHistory selected"); | ||||||
|         return NumericStateHistoryChartWidget( |         return NumericStateHistoryChartWidget( | ||||||
|           rawHistory: _history, |           rawHistory: _history, | ||||||
|  |           config: widget.config, | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       case EntityHistoryWidgetType.numericAttributes: { | ||||||
|  |         TheLogger.debug("  NumericAttributes selected"); | ||||||
|  |         return CombinedHistoryChartWidget( | ||||||
|  |           rawHistory: _history, | ||||||
|  |           config: widget.config, | ||||||
|         ); |         ); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       default: { |       default: { | ||||||
|  |         TheLogger.debug("  Simple selected as default"); | ||||||
|         return SimpleStateHistoryChartWidget( |         return SimpleStateHistoryChartWidget( | ||||||
|           rawHistory: _history, |           rawHistory: _history, | ||||||
|         ); |         ); | ||||||
|   | |||||||
| @@ -2,8 +2,9 @@ part of '../../main.dart'; | |||||||
|  |  | ||||||
| class NumericStateHistoryChartWidget extends StatefulWidget { | class NumericStateHistoryChartWidget extends StatefulWidget { | ||||||
|   final rawHistory; |   final rawHistory; | ||||||
|  |   final EntityHistoryConfig config; | ||||||
|  |  | ||||||
|   const NumericStateHistoryChartWidget({Key key, this.rawHistory}) : super(key: key); |   const NumericStateHistoryChartWidget({Key key, @required this.rawHistory, @required this.config}) : super(key: key); | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
| @@ -86,15 +87,15 @@ class _NumericStateHistoryChartWidgetState extends State<NumericStateHistoryChar | |||||||
|     return [ |     return [ | ||||||
|       new charts.Series<NumericEntityStateHistoryMoment, DateTime>( |       new charts.Series<NumericEntityStateHistoryMoment, DateTime>( | ||||||
|         id: 'State', |         id: 'State', | ||||||
|         colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("unavailable", historyMoment.id), |         colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("on", -1), | ||||||
|         domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time, |         domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time, | ||||||
|         measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value, |         measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value, | ||||||
|         data: data, |         data: data, | ||||||
|       ), |       ), | ||||||
|       new charts.Series<NumericEntityStateHistoryMoment, DateTime>( |       new charts.Series<NumericEntityStateHistoryMoment, DateTime>( | ||||||
|         id: 'State', |         id: 'State', | ||||||
|         radiusPxFn: (NumericEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 2.0, |         radiusPxFn: (NumericEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 5.0 : 1.0, | ||||||
|         colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("off", historyMoment.id), |         colorFn: (NumericEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor("on", -1), | ||||||
|         domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time, |         domainFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.time, | ||||||
|         measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value, |         measureFn: (NumericEntityStateHistoryMoment historyMoment, _) => historyMoment.value, | ||||||
|         data: data, |         data: data, | ||||||
| @@ -111,7 +112,7 @@ class _NumericStateHistoryChartWidgetState extends State<NumericStateHistoryChar | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   void _selectNext() { |   void _selectNext() { | ||||||
|     if (_selectedId < (_parsedHistory.first.data.length - 2)) { |     if (_selectedId < (_parsedHistory.first.data.length - 1)) { | ||||||
|       setState(() { |       setState(() { | ||||||
|         _selectedId += 1; |         _selectedId += 1; | ||||||
|       }); |       }); | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW | |||||||
|           selectedState: selectedState, |           selectedState: selectedState, | ||||||
|           onPrevTap: () => _selectPrev(), |           onPrevTap: () => _selectPrev(), | ||||||
|           onNextTap: () => _selectNext(), |           onNextTap: () => _selectNext(), | ||||||
|           colorIndex: _selectedId, |           colorIndex: _parsedHistory.first.data[_selectedId].colorId, | ||||||
|         ), |         ), | ||||||
|         SizedBox( |         SizedBox( | ||||||
|           height: 70.0, |           height: 70.0, | ||||||
| @@ -68,6 +68,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW | |||||||
|   List<charts.Series<SimpleEntityStateHistoryMoment, DateTime>> _parseHistory() { |   List<charts.Series<SimpleEntityStateHistoryMoment, DateTime>> _parseHistory() { | ||||||
|     List<SimpleEntityStateHistoryMoment> data = []; |     List<SimpleEntityStateHistoryMoment> data = []; | ||||||
|     DateTime now = DateTime.now(); |     DateTime now = DateTime.now(); | ||||||
|  |     Map<String, int> cachedStates = {}; | ||||||
|     for (var i = 0; i < widget.rawHistory.length; i++) { |     for (var i = 0; i < widget.rawHistory.length; i++) { | ||||||
|       var stateData = widget.rawHistory[i]; |       var stateData = widget.rawHistory[i]; | ||||||
|       DateTime startTime = DateTime.tryParse(stateData["last_updated"])?.toLocal(); |       DateTime startTime = DateTime.tryParse(stateData["last_updated"])?.toLocal(); | ||||||
| @@ -77,9 +78,12 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW | |||||||
|       } else { |       } else { | ||||||
|         endTime = now; |         endTime = now; | ||||||
|       } |       } | ||||||
|       data.add(SimpleEntityStateHistoryMoment(stateData["state"], startTime, endTime, i)); |       if (cachedStates[stateData["state"]] == null) { | ||||||
|  |         cachedStates.addAll({"${stateData["state"]}": cachedStates.length}); | ||||||
|  |       } | ||||||
|  |       data.add(SimpleEntityStateHistoryMoment(stateData["state"], startTime, endTime, i, cachedStates[stateData["state"]])); | ||||||
|     } |     } | ||||||
|     data.add(SimpleEntityStateHistoryMoment(data.last.state, now, null, widget.rawHistory.length)); |     data.add(SimpleEntityStateHistoryMoment(data.last.state, now, null, widget.rawHistory.length, data.last.colorId)); | ||||||
|     if (_selectedId == -1) { |     if (_selectedId == -1) { | ||||||
|       _selectedId = 0; |       _selectedId = 0; | ||||||
|     } |     } | ||||||
| @@ -87,7 +91,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW | |||||||
|       new charts.Series<SimpleEntityStateHistoryMoment, DateTime>( |       new charts.Series<SimpleEntityStateHistoryMoment, DateTime>( | ||||||
|         id: 'State', |         id: 'State', | ||||||
|         strokeWidthPxFn: (SimpleEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 70.0 : 40.0, |         strokeWidthPxFn: (SimpleEntityStateHistoryMoment historyMoment, __) => (historyMoment.id == _selectedId) ? 70.0 : 40.0, | ||||||
|         colorFn: (SimpleEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor(historyMoment.state, historyMoment.id), |         colorFn: (SimpleEntityStateHistoryMoment historyMoment, __) => EntityColors.chartHistoryStateColor(historyMoment.state, historyMoment.colorId), | ||||||
|         domainFn: (SimpleEntityStateHistoryMoment historyMoment, _) => historyMoment.startTime, |         domainFn: (SimpleEntityStateHistoryMoment historyMoment, _) => historyMoment.startTime, | ||||||
|         measureFn: (SimpleEntityStateHistoryMoment historyMoment, _) => 0, |         measureFn: (SimpleEntityStateHistoryMoment historyMoment, _) => 0, | ||||||
|         data: data, |         data: data, | ||||||
| @@ -205,6 +209,7 @@ class SimpleEntityStateHistoryMoment { | |||||||
|   final DateTime endTime; |   final DateTime endTime; | ||||||
|   final String state; |   final String state; | ||||||
|   final int id; |   final int id; | ||||||
|  |   final int colorId; | ||||||
|  |  | ||||||
|   SimpleEntityStateHistoryMoment(this.state, this.startTime, this.endTime,  this.id); |   SimpleEntityStateHistoryMoment(this.state, this.startTime, this.endTime,  this.id, this.colorId); | ||||||
| } | } | ||||||
| @@ -41,6 +41,7 @@ part 'entity_widgets/entity_page_container.dart'; | |||||||
| part 'entity_widgets/history_chart/entity_history.dart'; | part 'entity_widgets/history_chart/entity_history.dart'; | ||||||
| part 'entity_widgets/history_chart/simple_state_history_chart.dart'; | part 'entity_widgets/history_chart/simple_state_history_chart.dart'; | ||||||
| part 'entity_widgets/history_chart/numeric_state_history_chart.dart'; | part 'entity_widgets/history_chart/numeric_state_history_chart.dart'; | ||||||
|  | part 'entity_widgets/history_chart/combined_history_chart.dart'; | ||||||
| part 'entity_widgets/state/switch_state.dart'; | part 'entity_widgets/state/switch_state.dart'; | ||||||
| part 'entity_widgets/state/slider_state.dart'; | part 'entity_widgets/state/slider_state.dart'; | ||||||
| part 'entity_widgets/state/text_input_state.dart'; | part 'entity_widgets/state/text_input_state.dart'; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user