diff --git a/lib/entity_class/entity.class.dart b/lib/entity_class/entity.class.dart index d354132..13535e2 100644 --- a/lib/entity_class/entity.class.dart +++ b/lib/entity_class/entity.class.dart @@ -23,17 +23,18 @@ class Entity { "sensor" ]; - double rightWidgetPadding = 14.0; - double leftWidgetPadding = 8.0; - double extendedWidgetHeight = 50.0; + static const rightWidgetPadding = 14.0; + static const leftWidgetPadding = 8.0; + static const extendedWidgetHeight = 50.0; + static const iconSize = 28.0; + static const stateFontSize = 16.0; + static const nameFontSize = 16.0; + static const smallFontSize = 14.0; + static const largeFontSize = 24.0; + static const inputWidth = 160.0; + static const rowPadding = 10.0; + double widgetHeight = 34.0; - double iconSize = 28.0; - double stateFontSize = 16.0; - double nameFontSize = 16.0; - double smallFontSize = 14.0; - double largeFontSize = 24.0; - double inputWidth = 160.0; - double rowPadding = 10.0; Map attributes; String domain; @@ -89,7 +90,10 @@ class Entity { Widget buildDefaultWidget(BuildContext context) { return EntityModel( entity: this, - child: DefaultEntityContainer(state: _buildStatePart(context)), + child: DefaultEntityContainer( + state: _buildStatePart(context), + height: widgetHeight, + ), handleTap: true, ); } @@ -113,7 +117,7 @@ class Entity { return EntityModel( entity: this, child: EntityPageContainer(children: [ - DefaultEntityContainer(state: _buildStatePartForPage(context)), + DefaultEntityContainer(state: _buildStatePartForPage(context), height: widgetHeight), LastUpdatedWidget(), Divider(), _buildAdditionalControlsForPage(context), diff --git a/lib/entity_class/stateful_widgets.dart b/lib/entity_class/stateful_widgets.dart index 36d1eb5..ec7f7d4 100644 --- a/lib/entity_class/stateful_widgets.dart +++ b/lib/entity_class/stateful_widgets.dart @@ -64,7 +64,7 @@ class _ButtonControlWidgetState extends State { "EXECUTE", textAlign: TextAlign.right, style: - new TextStyle(fontSize: entityModel.entity.stateFontSize, color: Colors.blue), + new TextStyle(fontSize: Entity.stateFontSize, color: Colors.blue), ), ); } @@ -398,7 +398,7 @@ class _ClimateControlWidgetState extends State { _resetVars(entity); } return Padding( - padding: EdgeInsets.fromLTRB(entity.leftWidgetPadding, entity.rowPadding, entity.rightWidgetPadding, 0.0), + padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -418,21 +418,10 @@ class _ClimateControlWidgetState extends State { Widget _buildAwayModeControl(ClimateEntity entity) { if (entity.supportAwayMode) { - return Row( - children: [ - Expanded( - child: Text( - "Away mode", - style: TextStyle( - fontSize: entity.stateFontSize - ), - ), - ), - Switch( - onChanged: (value) => _setAwayMode(entity, value), - value: _tmpAwayMode, - ) - ], + return ModeSwitchWidget( + caption: "Away mode", + onChange: (value) => _setAwayMode(entity, value), + value: _tmpAwayMode, ); } else { return Container(height: 0.0, width: 0.0,); @@ -441,21 +430,10 @@ class _ClimateControlWidgetState extends State { Widget _buildOnOffControl(ClimateEntity entity) { if (entity.supportOnOff) { - return Row( - children: [ - Expanded( - child: Text( - "On / Off", - style: TextStyle( - fontSize: entity.stateFontSize - ), - ), - ), - Switch( - onChanged: (value) => _setOnOf(entity, value), - value: !_tmpIsOff, - ) - ], + return ModeSwitchWidget( + onChange: (value) => _setOnOf(entity, value), + caption: "On / Off", + value: !_tmpIsOff ); } else { return Container(height: 0.0, width: 0.0,); @@ -464,21 +442,10 @@ class _ClimateControlWidgetState extends State { Widget _buildAuxHeatControl(ClimateEntity entity) { if (entity.supportAuxHeat ) { - return Row( - children: [ - Expanded( - child: Text( - "Aux heat", - style: TextStyle( - fontSize: entity.stateFontSize - ), - ), - ), - Switch( - onChanged: (value) => _setAuxHeat(entity, value), - value: _tmpAuxHeat, - ) - ], + return ModeSwitchWidget( + caption: "Aux heat", + onChange: (value) => _setAuxHeat(entity, value), + value: _tmpAuxHeat ); } else { return Container(height: 0.0, width: 0.0,); @@ -487,29 +454,11 @@ class _ClimateControlWidgetState extends State { Widget _buildOperationControl(ClimateEntity entity) { if (entity.supportOperationMode) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Operation", style: TextStyle( - fontSize: entity.stateFontSize - )), - DropdownButton( - value: "$_tmpOperationMode", - iconSize: 30.0, - style: TextStyle( - fontSize: entity.largeFontSize, - color: Colors.black, - ), - items: entity.operationList.map((String value) { - return new DropdownMenuItem( - value: value, - child: new Text(value), - ); - }).toList(), - onChanged: (mode) => _setOperationMode(entity, mode), - ), - Container(height: entity.rowPadding,) - ], + return ModeSelectorWidget( + onChange: (mode) => _setOperationMode(entity, mode), + options: entity.operationList, + caption: "Operation", + value: _tmpOperationMode, ); } else { return Container(height: 0.0, width: 0.0); @@ -518,29 +467,11 @@ class _ClimateControlWidgetState extends State { Widget _buildFanControl(ClimateEntity entity) { if (entity.supportFanMode) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Fan mode", style: TextStyle( - fontSize: entity.stateFontSize - )), - DropdownButton( - value: "$_tmpFanMode", - iconSize: 30.0, - style: TextStyle( - fontSize: entity.largeFontSize, - color: Colors.black, - ), - items: entity.fanList.map((String value) { - return new DropdownMenuItem( - value: value, - child: new Text(value), - ); - }).toList(), - onChanged: (mode) => _setFanMode(entity, mode), - ), - Container(height: entity.rowPadding,) - ], + return ModeSelectorWidget( + options: entity.fanList, + onChange: (mode) => _setFanMode(entity, mode), + caption: "Fan mode", + value: _tmpFanMode, ); } else { return Container(height: 0.0, width: 0.0); @@ -549,29 +480,11 @@ class _ClimateControlWidgetState extends State { Widget _buildSwingControl(ClimateEntity entity) { if (entity.supportSwingMode) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Swing mode", style: TextStyle( - fontSize: entity.stateFontSize - )), - DropdownButton( - value: "$_tmpSwingMode", - iconSize: 30.0, - style: TextStyle( - fontSize: entity.largeFontSize, - color: Colors.black, - ), - items: entity.swingList.map((String value) { - return new DropdownMenuItem( - value: value, - child: new Text(value), - ); - }).toList(), - onChanged: (mode) => _setSwingMode(entity, mode), - ), - Container(height: entity.rowPadding,) - ], + return ModeSelectorWidget( + onChange: (mode) => _setSwingMode(entity, mode), + options: entity.swingList, + value: _tmpSwingMode, + caption: "Swing mode" ); } else { return Container(height: 0.0, width: 0.0); @@ -584,10 +497,11 @@ class _ClimateControlWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Target temperature", style: TextStyle( - fontSize: entity.stateFontSize + fontSize: Entity.stateFontSize )), TemperatureControlWidget( value: _tmpTemperature, + fontColor: _showPending ? Colors.red : Colors.black, onLargeDec: () => _temperatureDown(entity, 0.5), onLargeInc: () => _temperatureUp(entity, 0.5), onSmallDec: () => _temperatureDown(entity, 0.1), @@ -606,6 +520,7 @@ class _ClimateControlWidgetState extends State { controls.addAll([ TemperatureControlWidget( value: _tmpTargetLow, + fontColor: _showPending ? Colors.red : Colors.black, onLargeDec: () => _targetLowDown(entity, 0.5), onLargeInc: () => _targetLowUp(entity, 0.5), onSmallDec: () => _targetLowDown(entity, 0.1), @@ -620,6 +535,7 @@ class _ClimateControlWidgetState extends State { controls.add( TemperatureControlWidget( value: _tmpTargetHigh, + fontColor: _showPending ? Colors.red : Colors.black, onLargeDec: () => _targetHighDown(entity, 0.5), onLargeInc: () => _targetHighUp(entity, 0.5), onSmallDec: () => _targetHighDown(entity, 0.1), @@ -632,7 +548,7 @@ class _ClimateControlWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Target temperature range", style: TextStyle( - fontSize: entity.stateFontSize + fontSize: Entity.stateFontSize )), Row( children: controls, @@ -650,7 +566,7 @@ class _ClimateControlWidgetState extends State { result.addAll([ Text( "$_tmpTargetHumidity%", - style: TextStyle(fontSize: entity.largeFontSize), + style: TextStyle(fontSize: Entity.largeFontSize), ), Expanded( child: Slider( @@ -674,9 +590,9 @@ class _ClimateControlWidgetState extends State { children: [ Padding( padding: EdgeInsets.fromLTRB( - 0.0, entity.rowPadding, 0.0, entity.rowPadding), + 0.0, Entity.rowPadding, 0.0, Entity.rowPadding), child: Text("Target humidity", style: TextStyle( - fontSize: entity.stateFontSize + fontSize: Entity.stateFontSize )), ), Row( @@ -684,7 +600,7 @@ class _ClimateControlWidgetState extends State { children: result, ), Container( - height: entity.rowPadding, + height: Entity.rowPadding, ) ], ); @@ -795,7 +711,7 @@ class _CoverControlWidgetState extends State { _resetVars(entity); } return Padding( - padding: EdgeInsets.fromLTRB(entity.leftWidgetPadding, entity.rowPadding, entity.rightWidgetPadding, 0.0), + padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -813,9 +729,9 @@ class _CoverControlWidgetState extends State { children: [ Padding( padding: EdgeInsets.fromLTRB( - 0.0, entity.rowPadding, 0.0, entity.rowPadding), + 0.0, Entity.rowPadding, 0.0, Entity.rowPadding), child: Text("Position", style: TextStyle( - fontSize: entity.stateFontSize + fontSize: Entity.stateFontSize )), ), Slider( @@ -831,7 +747,7 @@ class _CoverControlWidgetState extends State { }, onChangeEnd: (double value) => _setNewPosition(entity, value), ), - Container(height: entity.rowPadding,) + Container(height: Entity.rowPadding,) ], ); } else { @@ -861,15 +777,15 @@ class _CoverControlWidgetState extends State { }, onChangeEnd: (double value) => _setNewTiltPosition(entity, value), ), - Container(height: entity.rowPadding,) + Container(height: Entity.rowPadding,) ]); } if (controls.isNotEmpty) { controls.insert(0, Padding( padding: EdgeInsets.fromLTRB( - 0.0, entity.rowPadding, 0.0, entity.rowPadding), + 0.0, Entity.rowPadding, 0.0, Entity.rowPadding), child: Text("Tilt position", style: TextStyle( - fontSize: entity.stateFontSize + fontSize: Entity.stateFontSize )), )); return Column( diff --git a/lib/entity_class/stateless_widgets.dart b/lib/entity_class/stateless_widgets.dart index 3d67b1a..21adbd4 100644 --- a/lib/entity_class/stateless_widgets.dart +++ b/lib/entity_class/stateless_widgets.dart @@ -27,15 +27,16 @@ class DefaultEntityContainer extends StatelessWidget { DefaultEntityContainer({ Key key, @required this.state, + @required this.height }) : super(key: key); final Widget state; + final double height; @override Widget build(BuildContext context) { - final entityModel = EntityModel.of(context); return SizedBox( - height: entityModel.entity.widgetHeight, + height: height, child: Row( children: [ EntityIcon(), @@ -68,13 +69,13 @@ class SimpleEntityState extends StatelessWidget { final entityModel = EntityModel.of(context); return Padding( padding: EdgeInsets.fromLTRB( - 0.0, 0.0, entityModel.entity.rightWidgetPadding, 0.0), + 0.0, 0.0, Entity.rightWidgetPadding, 0.0), child: GestureDetector( child: Text( "${entityModel.entity.state}${entityModel.entity.unitOfMeasurement}", textAlign: TextAlign.right, style: new TextStyle( - fontSize: entityModel.entity.stateFontSize, + fontSize: Entity.stateFontSize, )), onTap: () => entityModel.handleTap ? eventBus.fire(new ShowEntityPageEvent(entityModel.entity)) @@ -94,7 +95,7 @@ class EntityName extends StatelessWidget { "${entityModel.entity.displayName}", overflow: TextOverflow.ellipsis, softWrap: false, - style: TextStyle(fontSize: entityModel.entity.nameFontSize), + style: TextStyle(fontSize: Entity.nameFontSize), ), ), onTap: () => entityModel.handleTap @@ -111,11 +112,11 @@ class EntityIcon extends StatelessWidget { return GestureDetector( child: Padding( padding: EdgeInsets.fromLTRB( - entityModel.entity.leftWidgetPadding, 0.0, 12.0, 0.0), + Entity.leftWidgetPadding, 0.0, 12.0, 0.0), //TODO: move createIconWidgetFromEntityData into this widget child: MaterialDesignIcons.createIconWidgetFromEntityData( entityModel.entity, - entityModel.entity.iconSize, + Entity.iconSize, Entity.STATE_ICONS_COLORS[entityModel.entity.state] ?? Entity.STATE_ICONS_COLORS["default"]), ), @@ -132,12 +133,12 @@ class LastUpdatedWidget extends StatelessWidget { final entityModel = EntityModel.of(context); return Padding( padding: EdgeInsets.fromLTRB( - entityModel.entity.leftWidgetPadding, 0.0, 0.0, 0.0), + Entity.leftWidgetPadding, 0.0, 0.0, 0.0), child: Text( '${entityModel.entity.lastUpdated}', textAlign: TextAlign.left, style: TextStyle( - fontSize: entityModel.entity.smallFontSize, color: Colors.black26), + fontSize: Entity.smallFontSize, color: Colors.black26), ), ); } @@ -153,14 +154,14 @@ class EntityAttributesList extends StatelessWidget { if ((entityModel.entity.attributesToShow == null) || (entityModel.entity.attributesToShow.contains("all"))) { entityModel.entity.attributes.forEach((name, value) { - attrs.add(_buildSingleAttribute(entityModel.entity, "$name", "$value")); + attrs.add(_buildSingleAttribute("$name", "$value")); }); } else { entityModel.entity.attributesToShow.forEach((String attr) { String attrValue = entityModel.entity.getAttribute("$attr"); if (attrValue != null) { attrs.add( - _buildSingleAttribute(entityModel.entity, "$attr", "$attrValue")); + _buildSingleAttribute("$attr", "$attrValue")); } }); } @@ -171,13 +172,13 @@ class EntityAttributesList extends StatelessWidget { ); } - Widget _buildSingleAttribute(Entity entity, String name, String value) { + Widget _buildSingleAttribute(String name, String value) { return Row( children: [ Expanded( child: Padding( padding: EdgeInsets.fromLTRB( - entity.leftWidgetPadding, entity.rowPadding, 0.0, 0.0), + Entity.leftWidgetPadding, Entity.rowPadding, 0.0, 0.0), child: Text( "$name", textAlign: TextAlign.left, @@ -187,7 +188,7 @@ class EntityAttributesList extends StatelessWidget { Expanded( child: Padding( padding: EdgeInsets.fromLTRB( - 0.0, entity.rowPadding, entity.rightWidgetPadding, 0.0), + 0.0, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), child: Text( "$value", textAlign: TextAlign.right, @@ -341,7 +342,7 @@ class ClimateStateWidget extends StatelessWidget { } return Padding( padding: EdgeInsets.fromLTRB( - 0.0, 0.0, entityModel.entity.rightWidgetPadding, 0.0), + 0.0, 0.0, Entity.rightWidgetPadding, 0.0), child: GestureDetector( child: Column( crossAxisAlignment: CrossAxisAlignment.end, @@ -353,12 +354,12 @@ class ClimateStateWidget extends StatelessWidget { textAlign: TextAlign.right, style: new TextStyle( fontWeight: FontWeight.bold, - fontSize: entityModel.entity.stateFontSize, + fontSize: Entity.stateFontSize, )), Text(" $targetTemp", textAlign: TextAlign.right, style: new TextStyle( - fontSize: entityModel.entity.stateFontSize, + fontSize: Entity.stateFontSize, )) ], ), @@ -366,7 +367,7 @@ class ClimateStateWidget extends StatelessWidget { Text("Currently: ${entity.attributes["current_temperature"]}", textAlign: TextAlign.right, style: new TextStyle( - fontSize: entityModel.entity.stateFontSize, + fontSize: Entity.stateFontSize, color: Colors.black45) ) : Container(height: 0.0,) @@ -454,12 +455,12 @@ class DateTimeStateWidget extends StatelessWidget { final entityModel = EntityModel.of(context); final DateTimeEntity entity = entityModel.entity; return Padding( - padding: EdgeInsets.fromLTRB(0.0, 0.0, entity.rightWidgetPadding, 0.0), + padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.rightWidgetPadding, 0.0), child: GestureDetector( child: Text("${entity.formattedState}", textAlign: TextAlign.right, style: new TextStyle( - fontSize: entity.stateFontSize, + fontSize: Entity.stateFontSize, )), onTap: () => _handleStateTap(context, entity), )); @@ -547,36 +548,36 @@ class CoverEntityControlState extends StatelessWidget { buttons.add(IconButton( icon: Icon( MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-up"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: entity.canBeOpened ? () => _open(entity) : null)); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } if (entity.supportStop) { buttons.add(IconButton( icon: Icon( MaterialDesignIcons.createIconDataFromIconName("mdi:stop"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: () => _stop(entity))); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } if (entity.supportClose) { buttons.add(IconButton( icon: Icon( MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-down"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: entity.canBeClosed ? () => _close(entity) : null)); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } @@ -612,24 +613,24 @@ class CoverEntityTiltControlButtons extends StatelessWidget { icon: Icon( MaterialDesignIcons.createIconDataFromIconName( "mdi:arrow-top-right"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: entity.canTiltBeOpened ? () => _open(entity) : null)); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } if (entity.supportStopTilt) { buttons.add(IconButton( icon: Icon( MaterialDesignIcons.createIconDataFromIconName("mdi:stop"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: () => _stop(entity))); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } if (entity.supportCloseTilt) { @@ -637,12 +638,12 @@ class CoverEntityTiltControlButtons extends StatelessWidget { icon: Icon( MaterialDesignIcons.createIconDataFromIconName( "mdi:arrow-bottom-left"), - size: entity.iconSize, + size: Entity.iconSize, ), onPressed: entity.canTiltBeClosed ? () => _close(entity) : null)); } else { buttons.add(Container( - width: entity.iconSize + 20.0, + width: Entity.iconSize + 20.0, )); } @@ -651,3 +652,90 @@ class CoverEntityTiltControlButtons extends StatelessWidget { ); } } + +class ModeSelectorWidget extends StatelessWidget { + + final String caption; + final List options; + final String value; + final double captionFontSize; + final double valueFontSize; + final double bottomPadding; + final onChange; + + ModeSelectorWidget({ + Key key, + this.caption, + @required this.options, + this.value, + @required this.onChange, + this.captionFontSize, + this.valueFontSize, + this.bottomPadding + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("$caption", style: TextStyle( + fontSize: captionFontSize ?? Entity.stateFontSize + )), + DropdownButton( + value: "$value", + iconSize: 30.0, + style: TextStyle( + fontSize: valueFontSize ?? Entity.largeFontSize, + color: Colors.black, + ), + items: options.map((String value) { + return new DropdownMenuItem( + value: value, + child: new Text(value), + ); + }).toList(), + onChanged: (mode) => onChange(mode), + ), + Container(height: bottomPadding ?? Entity.rowPadding,) + ], + ); + } +} + +class ModeSwitchWidget extends StatelessWidget { + + final String caption; + final onChange; + final double captionFontSize; + final bool value; + + ModeSwitchWidget({ + Key key, + @required this.caption, + @required this.onChange, + this.captionFontSize, + this.value + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: Text( + "$caption", + style: TextStyle( + fontSize: captionFontSize ?? Entity.stateFontSize + ), + ), + ), + Switch( + onChanged: (value) => onChange(value), + value: value ?? false, + ) + ], + ); + } + +} \ No newline at end of file