diff --git a/lib/entity_class/entity.class.dart b/lib/entity_class/entity.class.dart index 2f253ca..9b40c97 100644 --- a/lib/entity_class/entity.class.dart +++ b/lib/entity_class/entity.class.dart @@ -83,7 +83,18 @@ class Entity { } else if (temp1 is double) { return temp1; } else { - return null; + return double.tryParse("$temp1"); + } + } + + int _getIntAttributeValue(String attributeName) { + var temp1 = attributes["$attributeName"]; + if (temp1 is int) { + return temp1; + } else if (temp1 is double) { + return temp1.round(); + } else { + return int.tryParse("$temp1"); } } @@ -178,7 +189,7 @@ class SwitchEntity extends Entity { @override Widget _buildStatePart(BuildContext context) { - return SwitchControlWidget(); + return SwitchStateWidget(); } } @@ -187,7 +198,7 @@ class ButtonEntity extends Entity { @override Widget _buildStatePart(BuildContext context) { - return ButtonControlWidget(); + return ButtonStateWidget(); } } @@ -202,7 +213,7 @@ class TextEntity extends Entity { @override Widget _buildStatePart(BuildContext context) { - return TextControlWidget(); + return TextInputStateWidget(); } } @@ -224,7 +235,7 @@ class SliderEntity extends Entity { //width: 200.0, child: Row( children: [ - SliderControlWidget( + SliderStateWidget( expanded: true, ), SimpleEntityState(), @@ -240,7 +251,7 @@ class SliderEntity extends Entity { @override Widget _buildAdditionalControlsForPage(BuildContext context) { - return SliderControlWidget( + return SliderStateWidget( expanded: false, ); } @@ -468,3 +479,76 @@ class CoverEntity extends Entity { } } + +class LightEntity extends Entity { + + static const SUPPORT_BRIGHTNESS = 1; + static const SUPPORT_COLOR_TEMP = 2; + static const SUPPORT_EFFECT = 4; + static const SUPPORT_FLASH = 8; + static const SUPPORT_COLOR = 16; + static const SUPPORT_TRANSITION = 32; + static const SUPPORT_WHITE_VALUE = 128; + + bool get supportBrightness => ((attributes["supported_features"] & + LightEntity.SUPPORT_BRIGHTNESS) == + LightEntity.SUPPORT_BRIGHTNESS); + bool get supportColorTemp => ((attributes["supported_features"] & + LightEntity.SUPPORT_COLOR_TEMP) == + LightEntity.SUPPORT_COLOR_TEMP); + bool get supportEffect => ((attributes["supported_features"] & + LightEntity.SUPPORT_EFFECT) == + LightEntity.SUPPORT_EFFECT); + bool get supportFlash => ((attributes["supported_features"] & + LightEntity.SUPPORT_FLASH) == + LightEntity.SUPPORT_FLASH); + bool get supportColor => ((attributes["supported_features"] & + LightEntity.SUPPORT_COLOR) == + LightEntity.SUPPORT_COLOR); + bool get supportTransition => ((attributes["supported_features"] & + LightEntity.SUPPORT_TRANSITION) == + LightEntity.SUPPORT_TRANSITION); + bool get supportWhiteValue => ((attributes["supported_features"] & + LightEntity.SUPPORT_WHITE_VALUE) == + LightEntity.SUPPORT_WHITE_VALUE); + + int get brightness => _getIntAttributeValue("brightness"); + int get colorTemp => _getIntAttributeValue("color_temp"); + double get maxMireds => _getDoubleAttributeValue("max_mireds"); + double get minMireds => _getDoubleAttributeValue("min_mireds"); + Color get color => _getColor(); + bool get isAdditionalControls => ((attributes["supported_features"] != null) && (attributes["supported_features"] != 0)); + List get effectList => attributes["effect_list"] != null + ? (attributes["effect_list"] as List).cast() + : null; + + LightEntity(Map rawData) : super(rawData); + + Color _getColor() { + List rgb = attributes["rgb_color"]; + try { + if ((rgb != null) && (rgb.length > 0)) { + return Color.fromARGB(255, rgb[0], rgb[1], rgb[2]); + } else { + return null; + } + } catch (e) { + return null; + } + } + + @override + Widget _buildStatePart(BuildContext context) { + return SwitchStateWidget(); + } + + @override + Widget _buildAdditionalControlsForPage(BuildContext context) { + if (!isAdditionalControls) { + return Container(height: 0.0, width: 0.0); + } else { + return LightControlsWidget(); + } + } + +} diff --git a/lib/entity_class/stateful_widgets.dart b/lib/entity_class/stateful_widgets.dart index d00df5f..063470e 100644 --- a/lib/entity_class/stateful_widgets.dart +++ b/lib/entity_class/stateful_widgets.dart @@ -1,11 +1,11 @@ part of '../main.dart'; -class SwitchControlWidget extends StatefulWidget { +class SwitchStateWidget extends StatefulWidget { @override - _SwitchControlWidgetState createState() => _SwitchControlWidgetState(); + _SwitchStateWidgetState createState() => _SwitchStateWidgetState(); } -class _SwitchControlWidgetState extends State { +class _SwitchStateWidgetState extends State { @override void initState() { @@ -37,48 +37,15 @@ class _SwitchControlWidgetState extends State { } } -class ButtonControlWidget extends StatefulWidget { +class TextInputStateWidget extends StatefulWidget { + + TextInputStateWidget({Key key}) : super(key: key); + @override - _ButtonControlWidgetState createState() => _ButtonControlWidgetState(); + _TextInputStateWidgetState createState() => _TextInputStateWidgetState(); } -class _ButtonControlWidgetState extends State { - - @override - void initState() { - super.initState(); - } - - void _setNewState(Entity entity) { - eventBus.fire(new ServiceCallEvent(entity.domain, "turn_on", entity.entityId, null)); - } - - @override - Widget build(BuildContext context) { - final entityModel = EntityModel.of(context); - return FlatButton( - onPressed: (() { - _setNewState(entityModel.entity); - }), - child: Text( - "EXECUTE", - textAlign: TextAlign.right, - style: - new TextStyle(fontSize: Entity.stateFontSize, color: Colors.blue), - ), - ); - } -} - -class TextControlWidget extends StatefulWidget { - - TextControlWidget({Key key}) : super(key: key); - - @override - _TextControlWidgetState createState() => _TextControlWidgetState(); -} - -class _TextControlWidgetState extends State { +class _TextInputStateWidgetState extends State { String _tmpValue; String _entityState; String _entityDomain; @@ -167,17 +134,17 @@ class _TextControlWidgetState extends State { } -class SliderControlWidget extends StatefulWidget { +class SliderStateWidget extends StatefulWidget { final bool expanded; - SliderControlWidget({Key key, @required this.expanded}) : super(key: key); + SliderStateWidget({Key key, @required this.expanded}) : super(key: key); @override - _SliderControlWidgetState createState() => _SliderControlWidgetState(); + _SliderStateWidgetState createState() => _SliderStateWidgetState(); } -class _SliderControlWidgetState extends State { +class _SliderStateWidgetState extends State { int _multiplier = 1; void setNewState(newValue, domain, entityId) { @@ -798,4 +765,260 @@ class _CoverControlWidgetState extends State { } } +} + +class LightControlsWidget extends StatefulWidget { + + @override + _LightControlsWidgetState createState() => _LightControlsWidgetState(); + +} + +class _LightControlsWidgetState extends State { + + int _tmpBrightness; + int _tmpColorTemp; + Color _tmpColor; + bool _changedHere = false; + + void _resetState(LightEntity entity) { + _tmpBrightness = entity.brightness; + _tmpColorTemp = entity.colorTemp; + _tmpColor = entity.color; + } + + void _setBrightness(LightEntity entity, double value) { + setState(() { + _tmpBrightness = value.round(); + _changedHere = true; + if (_tmpBrightness > 0) { + eventBus.fire(new ServiceCallEvent( + entity.domain, "turn_on", entity.entityId, + {"brightness": _tmpBrightness})); + } else { + eventBus.fire(new ServiceCallEvent( + entity.domain, "turn_off", entity.entityId, + null)); + } + }); + } + + void _setColorTemp(LightEntity entity, double value) { + setState(() { + _tmpColorTemp = value.round(); + _changedHere = true; + eventBus.fire(new ServiceCallEvent( + entity.domain, "turn_on", entity.entityId, + {"color_temp": _tmpColorTemp})); + }); + } + + void _setColor(LightEntity entity, Color color) { + setState(() { + _tmpColor = color; + _changedHere = true; + TheLogger.log("Debug", "Color: [${color.red}, ${color.green}, ${color.blue}]"); + if ((color == Colors.black) || ((color.red == color.green) && (color.green == color.blue))) { + eventBus.fire(new ServiceCallEvent( + entity.domain, "turn_off", entity.entityId, + null)); + } else { + eventBus.fire(new ServiceCallEvent( + entity.domain, "turn_on", entity.entityId, + {"rgb_color": [color.red, color.green, color.blue]})); + } + }); + } + + @override + Widget build(BuildContext context) { + final entityModel = EntityModel.of(context); + final LightEntity entity = entityModel.entity; + if (!_changedHere) { + _resetState(entity); + } else { + _changedHere = false; + } + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildBrightnessControl(entity), + _buildColorTempControl(entity), + _buildColorControl(entity), + _buildEffectControl(entity), + _buildFlashControl(entity), + _buildTransitionControl(entity), + _buildWhiteValueControl(entity) + ], + ); + } + + Widget _buildBrightnessControl(LightEntity entity) { + if ((entity.supportBrightness) && (_tmpBrightness != null)) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container(height: Entity.rowPadding,), + Text( + "Brightness", + style: TextStyle(fontSize: Entity.stateFontSize), + ), + Container(height: Entity.rowPadding,), + Row( + children: [ + Icon(Icons.brightness_5), + Expanded( + child: Slider( + value: _tmpBrightness.toDouble(), + min: 0.0, + max: 255.0, + onChanged: (value) { + setState(() { + _changedHere = true; + _tmpBrightness = value.round(); + }); + }, + onChangeEnd: (value) => _setBrightness(entity, value), + ), + ) + ], + ), + Container(height: Entity.rowPadding,) + ], + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildColorTempControl(LightEntity entity) { + if ((entity.supportColorTemp) && (_tmpColorTemp != null)) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container(height: Entity.rowPadding,), + Text( + "Color temperature", + style: TextStyle(fontSize: Entity.stateFontSize), + ), + Container(height: Entity.rowPadding,), + Row( + children: [ + Text("Cold", style: TextStyle(color: Colors.lightBlue),), + Expanded( + child: Slider( + value: _tmpColorTemp.toDouble(), + min: entity.minMireds, + max: entity.maxMireds, + onChanged: (value) { + setState(() { + _changedHere = true; + _tmpColorTemp = value.round(); + }); + }, + onChangeEnd: (value) => _setColorTemp(entity, value), + ), + ), + Text("Warm", style: TextStyle(color: Colors.amberAccent),), + ], + ), + Container(height: Entity.rowPadding,) + ], + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildColorControl(LightEntity entity) { + if ((entity.supportColor)&&(entity.color != null)) { + Color backColor = Color.fromRGBO(255, 255, 255, 0.0); + if ((_tmpColor.red >=228) && (_tmpColor.green >=228) && (_tmpColor.blue >=228)) { + backColor = Colors.black12; + } + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container(height: Entity.rowPadding,), + GestureDetector( + child: Container( + width: 250.0, + child: Text( + "Color", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 50.0, + fontWeight: FontWeight.bold, + color: _tmpColor ?? Colors.black45, + ), + ), + decoration: BoxDecoration( + color: backColor + ), + ), + onTap: () => _showColorPicker(entity), + ), + Container(height: Entity.rowPadding,), + ], + ); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + void _showColorPicker(LightEntity entity) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + titlePadding: EdgeInsets.all(0.0), + contentPadding: EdgeInsets.all(0.0), + content: SingleChildScrollView( + child: MaterialPicker( + pickerColor: _tmpColor, + onColorChanged: (color) { + _setColor(entity, color); + Navigator.of(context).pop(); + }, + enableLabel: true, + ), + ), + ); + }, + ); + } + + Widget _buildEffectControl(LightEntity entity) { + if (entity.supportEffect) { + return Text("Effect is not supported yet =("); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildFlashControl(LightEntity entity) { + if (entity.supportFlash) { + return Text("Flash is not supported yet =("); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildTransitionControl(LightEntity entity) { + if (entity.supportTransition) { + return Text("Transition is not supported yet =("); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + Widget _buildWhiteValueControl(LightEntity entity) { + if (entity.supportWhiteValue) { + return Text("White value is not supported yet =("); + } else { + return Container(width: 0.0, height: 0.0); + } + } + + } \ No newline at end of file diff --git a/lib/entity_class/stateless_widgets.dart b/lib/entity_class/stateless_widgets.dart index 55498d9..f4dc37a 100644 --- a/lib/entity_class/stateless_widgets.dart +++ b/lib/entity_class/stateless_widgets.dart @@ -653,6 +653,29 @@ class CoverEntityTiltControlButtons extends StatelessWidget { } } +class ButtonStateWidget extends StatelessWidget { + + void _setNewState(Entity entity) { + eventBus.fire(new ServiceCallEvent(entity.domain, "turn_on", entity.entityId, null)); + } + + @override + Widget build(BuildContext context) { + final entityModel = EntityModel.of(context); + return FlatButton( + onPressed: (() { + _setNewState(entityModel.entity); + }), + child: Text( + "EXECUTE", + textAlign: TextAlign.right, + style: + new TextStyle(fontSize: Entity.stateFontSize, color: Colors.blue), + ), + ); + } +} + class ModeSelectorWidget extends StatelessWidget { final String caption; diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index 1d4d959..0893848 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -35,13 +35,15 @@ class EntityCollection { } case "automation": case "input_boolean": - case "switch": + case "switch": { + return SwitchEntity(rawEntityData); + } case "light": { - return SwitchEntity(rawEntityData); + return LightEntity(rawEntityData); } case "script": case "scene": { - return ButtonEntity(rawEntityData); + return ButtonEntity(rawEntityData); } case "input_datetime": { return DateTimeEntity(rawEntityData); diff --git a/lib/home_assistant.class.dart b/lib/home_assistant.class.dart index d70dac3..d8a9fd2 100644 --- a/lib/home_assistant.class.dart +++ b/lib/home_assistant.class.dart @@ -300,7 +300,7 @@ class HomeAssistant { String message = '{"id": $_currentMessageId, "type": "call_service", "domain": "$domain", "service": "$service", "service_data": {"entity_id": "$entityId"'; if (additionalParams != null) { additionalParams.forEach((name, value){ - if ((value is double) || (value is int)) { + if ((value is double) || (value is int) || (value is List)) { message += ', "$name" : $value'; } else { message += ', "$name" : "$value"'; diff --git a/lib/main.dart b/lib/main.dart index 7dbde36..c00ccef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -12,6 +12,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/services.dart'; import 'package:date_format/date_format.dart'; import 'package:http/http.dart' as http; +import 'package:flutter_colorpicker/material_picker.dart'; part 'entity_class/entity.class.dart'; part 'entity_class/stateless_widgets.dart'; diff --git a/pubspec.lock b/pubspec.lock index 31e038e..3479da4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.2" + flutter_colorpicker: + dependency: "direct main" + description: + name: flutter_colorpicker + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" flutter_launcher_icons: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index 218d29f..d5ae032 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: cached_network_image: ^0.4.1 url_launcher: ^3.0.3 date_format: ^1.0.5 + flutter_colorpicker: ^0.1.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons.