From 62d07bf8b950367878d0aa8baed25c50ec84289a Mon Sep 17 00:00:00 2001 From: Yegor Vialov Date: Tue, 7 Apr 2020 20:20:57 +0000 Subject: [PATCH] Gauge card refactoring --- .gitignore | 2 +- lib/cards/widgets/gauge_card_body.dart | 248 ++++++++++++++----------- lib/entities/entity_name.widget.dart | 2 + lib/entities/simple_state.widget.dart | 15 +- lib/main.dart | 4 + lib/managers/theme_manager.dart | 12 ++ pubspec.yaml | 2 + 7 files changed, 165 insertions(+), 120 deletions(-) diff --git a/.gitignore b/.gitignore index 297bd70..235e575 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,5 @@ flutter_export_environment.sh .flutter-plugins-dependencies key.properties -premium_features_manager.class.dart +secrets_manager.class.dart pubspec.lock diff --git a/lib/cards/widgets/gauge_card_body.dart b/lib/cards/widgets/gauge_card_body.dart index dc9a38a..7554f8b 100644 --- a/lib/cards/widgets/gauge_card_body.dart +++ b/lib/cards/widgets/gauge_card_body.dart @@ -14,10 +14,11 @@ class GaugeCardBody extends StatefulWidget { class _GaugeCardBodyState extends State { - List seriesList; - - List> _createData(double value) { + @override + Widget build(BuildContext context) { + EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper; double fixedValue; + double value = entityWrapper.entity.doubleState; if (value > widget.max) { fixedValue = widget.max.toDouble(); } else if (value < widget.min) { @@ -25,130 +26,151 @@ class _GaugeCardBodyState extends State { } else { fixedValue = value; } - double toShow = ((fixedValue - widget.min) / (widget.max - widget.min)) * 100; - Color mainColor; - if (widget.severity != null) { - if (widget.severity["red"] is int && fixedValue >= widget.severity["red"]) { - mainColor = Colors.red; - } else if (widget.severity["yellow"] is int && fixedValue >= widget.severity["yellow"]) { - mainColor = Colors.amber; - } else { - mainColor = Colors.green; - } - } else { - mainColor = Colors.green; + + List ranges; + if (widget.severity != null && widget.severity["green"] is int && widget.severity["red"] is int && widget.severity["yellow"] is int) { + List rangesList = [ + RangeContainer(widget.severity["green"], HAClientTheme().getGreenGaugeColor()), + RangeContainer(widget.severity["red"], HAClientTheme().getRedGaugeColor()), + RangeContainer(widget.severity["yellow"], HAClientTheme().getYellowGaugeColor()) + ]; + rangesList.sort((current, next) { + if (current.startFrom > next.startFrom) { + return 1; + } + if (current.startFrom < next.startFrom) { + return -1; + } + return 0; + }); + ranges = [ + GaugeRange( + startValue: rangesList[0].startFrom.toDouble(), + endValue: rangesList[1].startFrom.toDouble(), + color: fixedValue < rangesList[1].startFrom ? rangesList[0].color : rangesList[0].color.withOpacity(0.3), + sizeUnit: GaugeSizeUnit.factor, + endWidth: 0.3, + startWidth: 0.3 + ), + GaugeRange( + startValue: rangesList[1].startFrom.toDouble(), + endValue: rangesList[2].startFrom.toDouble(), + color: (fixedValue < rangesList[2].startFrom && fixedValue >= rangesList[1].startFrom) ? rangesList[1].color : rangesList[1].color.withOpacity(0.3), + sizeUnit: GaugeSizeUnit.factor, + endWidth: 0.3, + startWidth: 0.3 + ), + GaugeRange( + startValue: rangesList[2].startFrom.toDouble(), + endValue: widget.max.toDouble(), + color: fixedValue >= rangesList[2].startFrom ? rangesList[2].color : rangesList[2].color.withOpacity(0.3), + sizeUnit: GaugeSizeUnit.factor, + endWidth: 0.3, + startWidth: 0.3 + ) + ]; + } + if (ranges == null) { + ranges = [ + GaugeRange( + startValue: widget.min.toDouble(), + endValue: widget.max.toDouble(), + color: Theme.of(context).primaryColorDark, + sizeUnit: GaugeSizeUnit.factor, + endWidth: 0.3, + startWidth: 0.3 + ) + ]; } - final data = [ - GaugeSegment('Main', toShow, mainColor), - GaugeSegment('Rest', 100 - toShow, Colors.black45), - ]; - - return [ - charts.Series( - id: 'Segments', - domainFn: (GaugeSegment segment, _) => segment.segment, - measureFn: (GaugeSegment segment, _) => segment.value, - colorFn: (GaugeSegment segment, _) => segment.color, - // Set a label accessor to control the text of the arc label. - labelAccessorFn: (GaugeSegment segment, _) => - segment.segment == 'Main' ? '${segment.value}' : null, - data: data, - ) - ]; - } - - @override - Widget build(BuildContext context) { - EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper; return InkWell( onTap: () => entityWrapper.handleTap(), onLongPress: () => entityWrapper.handleHold(), onDoubleTap: () => entityWrapper.handleDoubleTap(), child: AspectRatio( - aspectRatio: 1.5, - child: Stack( - fit: StackFit.expand, - overflow: Overflow.clip, - children: [ - LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - double verticalOffset; - if(constraints.maxWidth > 150.0) { - verticalOffset = 0.2; - } else if (constraints.maxWidth > 100.0) { - verticalOffset = 0.3; - } else { - verticalOffset = 0.3; - } - return FractionallySizedBox( - heightFactor: 2, - widthFactor: 1, - alignment: FractionalOffset(0,verticalOffset), - child: charts.PieChart( - _createData(entityWrapper.entity.doubleState), - animate: false, - defaultRenderer: charts.ArcRendererConfig( - arcRatio: 0.4, - startAngle: pi, - arcLength: pi, - ), + aspectRatio: 2, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + double fontSizeFactor; + if (constraints.maxWidth > 300.0) { + fontSizeFactor = 1.6; + } else if (constraints.maxWidth > 150.0) { + fontSizeFactor = 1; + } else if (constraints.maxWidth > 100.0) { + fontSizeFactor = 0.6; + } else { + fontSizeFactor = 0.4; + } + return SfRadialGauge( + axes: [ + RadialAxis( + maximum: widget.max.toDouble(), + minimum: widget.min.toDouble(), + showLabels: false, + showTicks: false, + canScaleToFit: true, + ranges: ranges, + annotations: [ + GaugeAnnotation( + angle: -90, + positionFactor: 1.3, + //verticalAlignment: GaugeAlignment.far, + widget: EntityName( + textStyle: Theme.of(context).textTheme.body1.copyWith( + fontSize: Theme.of(context).textTheme.body1.fontSize * fontSizeFactor ), - ); - } - ), - Align( - alignment: Alignment.bottomCenter, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - double fontSize = constraints.maxHeight / 7; - return Padding( - padding: EdgeInsets.only(bottom: 2*fontSize), - child: SimpleEntityState( - //textAlign: TextAlign.center, - expanded: false, - maxLines: 1, - textAlign: TextAlign.center, - padding: EdgeInsets.all(0.0) - //padding: EdgeInsets.only(top: Sizes.rowPadding), - ), - ); - } - ), - ), - Align( - alignment: Alignment.bottomCenter, - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - double fontSize = constraints.maxHeight / 7; - return Padding( - padding: EdgeInsets.only(bottom: fontSize), - child: EntityName( - textStyle: Theme.of(context).textTheme.body1.copyWith( - fontSize: fontSize - ), - maxLines: 1, - padding: EdgeInsets.all(0.0), - textAlign: TextAlign.center, - textOverflow: TextOverflow.ellipsis, - ), - ); - } + ), + ), + GaugeAnnotation( + angle: 180, + positionFactor: 0, + verticalAlignment: GaugeAlignment.center, + widget: SimpleEntityState( + expanded: false, + maxLines: 1, + textAlign: TextAlign.center, + textStyle: Theme.of(context).textTheme.title.copyWith( + fontSize: Theme.of(context).textTheme.title.fontSize * fontSizeFactor, + ), + ), + ) + ], + axisLineStyle: AxisLineStyle( + thickness: 0.3, + thicknessUnit: GaugeSizeUnit.factor ), + startAngle: 180, + endAngle: 0, + pointers: [ + NeedlePointer( + value: fixedValue, + lengthUnit: GaugeSizeUnit.factor, + needleLength: 0.9, + needleColor: Theme.of(context).accentColor, + enableAnimation: true, + needleStartWidth: 1, + animationType: AnimationType.bounceOut, + needleEndWidth: 3, + knobStyle: KnobStyle( + sizeUnit: GaugeSizeUnit.factor, + color: Theme.of(context).buttonColor, + knobRadius: 0.1 + ) + ) + ] ) - ] - ) + ], + ); + }, + ), ), ); } } -class GaugeSegment { - final String segment; - final double value; - final charts.Color color; +class RangeContainer { + final int startFrom; + Color color; - GaugeSegment(this.segment, this.value, Color color) - : this.color = charts.Color( - r: color.red, g: color.green, b: color.blue, a: color.alpha); + RangeContainer(this.startFrom, this.color); } \ No newline at end of file diff --git a/lib/entities/entity_name.widget.dart b/lib/entities/entity_name.widget.dart index efdc775..c7457c3 100644 --- a/lib/entities/entity_name.widget.dart +++ b/lib/entities/entity_name.widget.dart @@ -21,6 +21,8 @@ class EntityName extends StatelessWidget { } else { tStyle = Theme.of(context).textTheme.body1; } + } else { + tStyle = textStyle; } return Padding( padding: padding, diff --git a/lib/entities/simple_state.widget.dart b/lib/entities/simple_state.widget.dart index 054ec1a..236b1e2 100644 --- a/lib/entities/simple_state.widget.dart +++ b/lib/entities/simple_state.widget.dart @@ -7,9 +7,10 @@ class SimpleEntityState extends StatelessWidget { final EdgeInsetsGeometry padding; final int maxLines; final String customValue; + final TextStyle textStyle; //final bool bold; - const SimpleEntityState({Key key,/*this.bold: false,*/ this.maxLines: 10, this.expanded: true, this.textAlign: TextAlign.right, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0), this.customValue}) : super(key: key); + const SimpleEntityState({Key key,/*this.bold: false,*/ this.maxLines: 10, this.expanded: true, this.textAlign: TextAlign.right, this.textStyle, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0), this.customValue}) : super(key: key); @override Widget build(BuildContext context) { @@ -21,13 +22,15 @@ class SimpleEntityState extends StatelessWidget { } else { state = customValue; } - TextStyle textStyle; - if (entityModel.entityWrapper.entity.statelessType == StatelessEntityType.CALL_SERVICE) { - textStyle = Theme.of(context).textTheme.subhead.copyWith( + TextStyle tStyle; + if (textStyle != null) { + tStyle = textStyle; + } else if (entityModel.entityWrapper.entity.statelessType == StatelessEntityType.CALL_SERVICE) { + tStyle = Theme.of(context).textTheme.subhead.copyWith( color: Colors.blue ); } else { - textStyle = Theme.of(context).textTheme.body1; + tStyle = Theme.of(context).textTheme.body1; } /*if (this.bold) { textStyle = textStyle.apply(fontWeightDelta: 100); @@ -43,7 +46,7 @@ class SimpleEntityState extends StatelessWidget { maxLines: maxLines, overflow: TextOverflow.ellipsis, softWrap: true, - style: textStyle + style: tStyle ) ); if (expanded) { diff --git a/lib/main.dart b/lib/main.dart index 7077cf7..edbb07e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,8 +34,11 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' as standaloneWebview; import 'package:webview_flutter/webview_flutter.dart'; import 'package:video_player/video_player.dart'; +import 'package:syncfusion_flutter_core/core.dart'; +import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'utils/logger.dart'; +import 'managers/secrets_manager.class.dart'; part 'const.dart'; part 'utils/launcher.dart'; @@ -164,6 +167,7 @@ Future _reportError(dynamic error, dynamic stackTrace) async { void main() async { Crashlytics.instance.enableInDevMode = false; + SyncfusionLicense.registerLicense(SecretsManager.SYNCFUSION_LICENSE_KEY); FlutterError.onError = (FlutterErrorDetails details) { Logger.e(" Caut Flutter runtime error: ${details.exception}"); diff --git a/lib/managers/theme_manager.dart b/lib/managers/theme_manager.dart index 8e25c2d..a762a26 100644 --- a/lib/managers/theme_manager.dart +++ b/lib/managers/theme_manager.dart @@ -154,6 +154,18 @@ class HAClientTheme { } } + Color getGreenGaugeColor() { + return Colors.green; + } + + Color getYellowGaugeColor() { + return Colors.yellow; + } + + Color getRedGaugeColor() { + return Colors.red; + } + TextStyle getLinkTextStyle(BuildContext context) { ThemeData theme = Theme.of(context); return theme.textTheme.body1.copyWith( diff --git a/pubspec.yaml b/pubspec.yaml index cc41ee3..c937231 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,8 @@ dependencies: battery: ^0.3.1+7 firebase_crashlytics: ^0.1.3+3 video_player: ^0.10.7 + syncfusion_flutter_core: ^18.1.43 + syncfusion_flutter_gauges: ^18.1.43 dev_dependencies: