From 5f3c77f4b94733b38dc8960b09856fd0ccd1940a Mon Sep 17 00:00:00 2001 From: Yegor Vialov Date: Sat, 24 Nov 2018 17:00:45 +0200 Subject: [PATCH] Resolves #145 Fan support --- lib/entity_class/fan_entity.class.dart | 32 +++++ lib/entity_collection.class.dart | 3 + lib/entity_widgets/common/mode_swicth.dart | 28 ++-- lib/entity_widgets/controls/fan_controls.dart | 123 ++++++++++++++++++ lib/main.dart | 2 + lib/mdi.class.dart | 1 + 6 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 lib/entity_class/fan_entity.class.dart create mode 100644 lib/entity_widgets/controls/fan_controls.dart diff --git a/lib/entity_class/fan_entity.class.dart b/lib/entity_class/fan_entity.class.dart new file mode 100644 index 0000000..e10a5ad --- /dev/null +++ b/lib/entity_class/fan_entity.class.dart @@ -0,0 +1,32 @@ +part of '../main.dart'; + +class FanEntity extends Entity { + + static const SUPPORT_SET_SPEED = 1; + static const SUPPORT_OSCILLATE = 2; + static const SUPPORT_DIRECTION = 4; + + FanEntity(Map rawData) : super(rawData); + + bool get supportSetSpeed => ((attributes["supported_features"] & + FanEntity.SUPPORT_SET_SPEED) == + FanEntity.SUPPORT_SET_SPEED); + bool get supportOscillate => ((attributes["supported_features"] & + FanEntity.SUPPORT_OSCILLATE) == + FanEntity.SUPPORT_OSCILLATE); + bool get supportDirection => ((attributes["supported_features"] & + FanEntity.SUPPORT_DIRECTION) == + FanEntity.SUPPORT_DIRECTION); + + List get speedList => getStringListAttributeValue("speed_list"); + + @override + Widget _buildStatePart(BuildContext context) { + return SwitchStateWidget(); + } + + @override + Widget _buildAdditionalControlsForPage(BuildContext context) { + return FanControlsWidget(); + } +} \ No newline at end of file diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index a09d293..18c1682 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -80,6 +80,9 @@ class EntityCollection { case "cover": { return CoverEntity(rawEntityData); } + case "fan": { + return FanEntity(rawEntityData); + } default: { return Entity(rawEntityData); } diff --git a/lib/entity_widgets/common/mode_swicth.dart b/lib/entity_widgets/common/mode_swicth.dart index 925c6ff..c842df1 100644 --- a/lib/entity_widgets/common/mode_swicth.dart +++ b/lib/entity_widgets/common/mode_swicth.dart @@ -6,27 +6,22 @@ class ModeSwitchWidget extends StatelessWidget { final onChange; final double captionFontSize; final bool value; + final bool expanded; ModeSwitchWidget({ Key key, @required this.caption, @required this.onChange, this.captionFontSize, - this.value + this.value, + this.expanded: true }) : super(key: key); @override Widget build(BuildContext context) { return Row( children: [ - Expanded( - child: Text( - "$caption", - style: TextStyle( - fontSize: captionFontSize ?? Sizes.stateFontSize - ), - ), - ), + _buildCaption(), Switch( onChanged: (value) => onChange(value), value: value ?? false, @@ -35,4 +30,19 @@ class ModeSwitchWidget extends StatelessWidget { ); } + Widget _buildCaption() { + Widget captionWidget = Text( + "$caption", + style: TextStyle( + fontSize: captionFontSize ?? Sizes.stateFontSize + ), + ); + if (expanded) { + return Expanded( + child: captionWidget, + ); + } + return captionWidget; + } + } \ No newline at end of file diff --git a/lib/entity_widgets/controls/fan_controls.dart b/lib/entity_widgets/controls/fan_controls.dart new file mode 100644 index 0000000..a2e2457 --- /dev/null +++ b/lib/entity_widgets/controls/fan_controls.dart @@ -0,0 +1,123 @@ +part of '../../main.dart'; + +class FanControlsWidget extends StatefulWidget { + + @override + _FanControlsWidgetState createState() => _FanControlsWidgetState(); + +} + +class _FanControlsWidgetState extends State { + + bool _tmpOscillate; + bool _tmpDirectionForward; + bool _changedHere = false; + String _tmpSpeed; + + void _resetState(FanEntity entity) { + _tmpOscillate = entity.attributes["oscillating"] ?? false; + _tmpDirectionForward = entity.attributes["direction"] == "forward"; + _tmpSpeed = entity.attributes["speed"]; + } + + void _setOscillate(FanEntity entity, bool oscillate) { + setState(() { + _tmpOscillate = oscillate; + _changedHere = true; + eventBus.fire(new ServiceCallEvent( + "fan", "oscillate", entity.entityId, + {"oscillating": oscillate})); + }); + } + + void _setDirection(FanEntity entity, bool forward) { + setState(() { + _tmpDirectionForward = forward; + _changedHere = true; + eventBus.fire(new ServiceCallEvent( + "fan", "set_direction", entity.entityId, + {"direction": forward ? "forward" : "reverse"})); + }); + } + + void _setSpeed(FanEntity entity, String value) { + setState(() { + _tmpSpeed = value; + _changedHere = true; + eventBus.fire(new ServiceCallEvent( + "fan", "set_speed", entity.entityId, + {"speed": value})); + }); + } + + @override + Widget build(BuildContext context) { + final entityModel = EntityModel.of(context); + final FanEntity entity = entityModel.entityWrapper.entity; + if (!_changedHere) { + _resetState(entity); + } else { + _changedHere = false; + } + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildSpeedControl(entity), + _buildOscillateControl(entity), + _buildDirectionControl(entity) + ], + ); + } + + Widget _buildSpeedControl(FanEntity entity) { + if (entity.supportSetSpeed && entity.speedList != null && entity.speedList.isNotEmpty) { + return ModeSelectorWidget( + onChange: (effect) => _setSpeed(entity, effect), + caption: "Speed", + options: entity.speedList, + value: _tmpSpeed + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildOscillateControl(FanEntity entity) { + if (entity.supportOscillate) { + return ModeSwitchWidget( + onChange: (value) => _setOscillate(entity, value), + caption: "Oscillate", + value: _tmpOscillate, + expanded: false, + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildDirectionControl(FanEntity entity) { + if (entity.supportDirection) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: _tmpDirectionForward ? + () => _setDirection(entity, false) : + null, + icon: Icon(Icons.rotate_left), + ), + IconButton( + onPressed: !_tmpDirectionForward ? + () => _setDirection(entity, true) : + null, + icon: Icon(Icons.rotate_right), + ), + ], + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 7d558f4..2b62c43 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -31,6 +31,7 @@ part 'entity_class/slider_entity.dart'; part 'entity_class/media_player_entity.class.dart'; part 'entity_class/lock_entity.class.dart'; part 'entity_class/group_entity.class.dart'; +part 'entity_class/fan_entity.class.dart'; part 'entity_widgets/common/badge.dart'; part 'entity_widgets/model_widgets.dart'; part 'entity_widgets/default_entity_container.dart'; @@ -64,6 +65,7 @@ part 'entity_widgets/controls/climate_controls.dart'; part 'entity_widgets/controls/cover_controls.dart'; part 'entity_widgets/controls/light_controls.dart'; part 'entity_widgets/controls/media_player_widgets.dart'; +part 'entity_widgets/controls/fan_controls.dart'; part 'settings.page.dart'; part 'home_assistant.class.dart'; part 'log.page.dart'; diff --git a/lib/mdi.class.dart b/lib/mdi.class.dart index 4667118..9203e18 100644 --- a/lib/mdi.class.dart +++ b/lib/mdi.class.dart @@ -24,6 +24,7 @@ class MaterialDesignIcons { "cover.opening": "mdi:window-open", "lock.locked": "mdi:lock", "lock.unlocked": "mdi:lock-open", + "fan": "mdi:fan" }; static Map _defaultIconsByDeviceClass = {