From 571778fbd41f43eac798e14b02e87e3166e7be8b Mon Sep 17 00:00:00 2001 From: estevez Date: Sat, 29 Sep 2018 23:13:02 +0300 Subject: [PATCH 01/10] Resolves #80: Card without title --- lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 36ff6ad..649e0aa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -385,7 +385,7 @@ class _MainPageState extends State with WidgetsBindingObserver { Widget _buildCardHeader(String name) { var result; - if (name.length > 0) { + if (name.trim().length > 0) { result = new ListTile( //leading: const Icon(Icons.device_hub), //subtitle: Text(".."), From 76d2750ad60192fc7b4360f7d2989eb979ca8ece Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 01:07:02 +0300 Subject: [PATCH 02/10] Fix slider issues. Siplify Entity view --- lib/entity.class.dart | 84 +++++++++++++++++++++++++------------------ lib/entity.page.dart | 13 +++---- lib/main.dart | 2 +- lib/mdi.class.dart | 1 + 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index eea1b20..b7e6b0e 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -8,16 +8,19 @@ class Entity { "unknown": Colors.black12, "playing": Colors.amber }; - static const RIGTH_WIDGET_PADDING = 14.0; + static const RIGHT_WIDGET_PADDING = 14.0; static const LEFT_WIDGET_PADDING = 8.0; static const EXTENDED_WIDGET_HEIGHT = 50.0; static const WIDGET_HEIGHT = 34.0; + static const ICON_SIZE = 28.0; + static const STATE_FONT_SIZE = 16.0; + static const NAME_FONT_SIZE = 16.0; + static const SMALL_FONT_SIZE = 12.0; Map _attributes; String _domain; String _entityId; String _state; - String _entityPicture; DateTime _lastUpdated; String get displayName => _attributes["friendly_name"] ?? (_attributes["name"] ?? "_"); @@ -72,28 +75,28 @@ class Entity { eventBus.fire(new ShowEntityPageEvent(this)); } - Widget buildWidget(BuildContext context) { + Widget buildWidget(GlobalKey formKey, bool tapAction) { return SizedBox( height: Entity.WIDGET_HEIGHT, child: Row( children: [ GestureDetector( child: _buildIconWidget(), - onTap: openEntityPage, + onTap: tapAction ? openEntityPage : null, ), Expanded( child: GestureDetector( child: _buildNameWidget(), - onTap: openEntityPage, + onTap: tapAction ? openEntityPage : null, ), ), - _buildActionWidget(context) + _buildActionWidget() ], ), ); } - Widget buildExtendedWidget(BuildContext context, String staticState) { + /*Widget buildExtendedWidget(BuildContext context, GlobalKey formKey, String staticState) { return Row( children: [ _buildIconWidget(), @@ -115,12 +118,12 @@ class Entity { ) ], ); - } + }*/ Widget _buildIconWidget() { return Padding( padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, 12.0, 0.0), - child: MaterialDesignIcons.createIconWidgetFromEntityData(this, 28.0, Entity.STATE_ICONS_COLORS[_state] ?? Colors.blueGrey), + child: MaterialDesignIcons.createIconWidgetFromEntityData(this, Entity.ICON_SIZE, Entity.STATE_ICONS_COLORS[_state] ?? Colors.blueGrey), ); } @@ -129,7 +132,7 @@ class Entity { '${this.lastUpdated}', textAlign: TextAlign.left, style: TextStyle( - fontSize: 12.0, + fontSize: Entity.SMALL_FONT_SIZE, color: Colors.black26 ), ); @@ -143,22 +146,22 @@ class Entity { overflow: TextOverflow.ellipsis, softWrap: false, style: TextStyle( - fontSize: 16.0 + fontSize: Entity.NAME_FONT_SIZE ), ), ); } - Widget _buildActionWidget(BuildContext context) { + Widget _buildActionWidget() { return Padding( - padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGTH_WIDGET_PADDING, 0.0), + padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), child: GestureDetector( child: Text( this.isPasswordField ? "******" : "$_state${this.unitOfMeasurement}", textAlign: TextAlign.right, style: new TextStyle( - fontSize: 16.0, + fontSize: Entity.STATE_FONT_SIZE, ) ), onTap: openEntityPage, @@ -166,9 +169,9 @@ class Entity { ); } - Widget _buildExtendedActionWidget(BuildContext context, String staticState) { + /*Widget _buildExtendedActionWidget(BuildContext context, String staticState) { return _buildActionWidget(context); - } + }*/ } class SwitchEntity extends Entity { @@ -176,7 +179,7 @@ class SwitchEntity extends Entity { SwitchEntity(Map rawData) : super(rawData); @override - Widget _buildActionWidget(BuildContext context) { + Widget _buildActionWidget() { return Switch( value: this.isOn, onChanged: ((switchState) { @@ -192,7 +195,7 @@ class ButtonEntity extends Entity { ButtonEntity(Map rawData) : super(rawData); @override - Widget _buildActionWidget(BuildContext context) { + Widget _buildActionWidget() { return FlatButton( onPressed: (() { eventBus.fire(new ServiceCallEvent(_domain, "turn_on", _entityId, null)); @@ -200,7 +203,7 @@ class ButtonEntity extends Entity { child: Text( "EXECUTE", textAlign: TextAlign.right, - style: new TextStyle(fontSize: 16.0, color: Colors.blue), + style: new TextStyle(fontSize: Entity.STATE_FONT_SIZE, color: Colors.blue), ), ); } @@ -211,8 +214,8 @@ class InputEntity extends Entity { InputEntity(Map rawData) : super(rawData); - @override - Widget buildExtendedWidget(BuildContext context, String staticState) { + /*@override + Widget buildExtendedWidget(BuildContext context, GlobalKey formKey, String staticState) { return Column( children: [ SizedBox( @@ -229,14 +232,14 @@ class InputEntity extends Entity { ), SizedBox( height: Entity.EXTENDED_WIDGET_HEIGHT, - child: _buildExtendedActionWidget(context, staticState), + child: _buildInputWidget(context, formKey, staticState), ) ], ); - } + }*/ @override - Widget _buildActionWidget(BuildContext context) { + Widget _buildActionWidget() { if (this.isSliderField) { return Container( width: 200.0, @@ -247,9 +250,9 @@ class InputEntity extends Entity { min: this.minValue*10, max: this.maxValue*10, value: (this.doubleState <= this.maxValue) && (this.doubleState >= this.minValue) ? this.doubleState*10 : this.minValue*10, - divisions: this.getValueDivisions(), + //divisions: this.getValueDivisions(), onChanged: (value) { - eventBus.fire(new StateChangedEvent(_entityId, (value.roundToDouble() / 10).toString(), true)); + eventBus.fire(new StateChangedEvent(_entityId, ((value / 10).roundToDouble()).toString(), true)); }, onChangeEnd: (value) { eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId,{"value": "$_state"})); @@ -257,27 +260,40 @@ class InputEntity extends Entity { ), ), Padding( - padding: EdgeInsets.only(right: 16.0), + padding: EdgeInsets.only(right: Entity.RIGHT_WIDGET_PADDING), child: Text( "$_state${this.unitOfMeasurement}", textAlign: TextAlign.right, style: new TextStyle( - fontSize: 16.0, + fontSize: Entity.STATE_FONT_SIZE, ) ), ) ], ), ); + } else if (this.isTextField || this.isPasswordField) { + return Container( + width: 160.0, + child: TextField( + obscureText: this.isPasswordField, + controller: TextEditingController( + text: _state, + ), + onChanged: (value) { + //TODO + //staticState = value; + }, + ), + ); } else { - return super._buildActionWidget(context); + return super._buildActionWidget(); } } - @override - Widget _buildExtendedActionWidget(BuildContext context, String staticState) { + /*Widget _buildInputWidget(BuildContext context, GlobalKey formKey, String staticState) { return Padding( - padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, Entity.RIGTH_WIDGET_PADDING, 0.0), + padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -302,13 +318,13 @@ class InputEntity extends Entity { child: Text( "SET", textAlign: TextAlign.right, - style: new TextStyle(fontSize: 16.0, color: Colors.blue), + style: new TextStyle(fontSize: Entity.STATE_FONT_SIZE, color: Colors.blue), ), ), ) ], ) ); - } + }*/ } \ No newline at end of file diff --git a/lib/entity.page.dart b/lib/entity.page.dart index 1314440..365710f 100644 --- a/lib/entity.page.dart +++ b/lib/entity.page.dart @@ -12,21 +12,18 @@ class EntityViewPage extends StatefulWidget { class _EntityViewPageState extends State { String _title; Entity _entity; - String _lastState; StreamSubscription _stateSubscription; + final _formKey = GlobalKey(); @override void initState() { super.initState(); _entity = widget.entity; - _lastState = _entity.state; if (_stateSubscription != null) _stateSubscription.cancel(); _stateSubscription = eventBus.on().listen((event) { - setState(() { - if (event.entityId == _entity.entityId) { - _lastState = event.newState ?? _entity.state; - } - }); + if (event.entityId == _entity.entityId) { + setState(() {}); + } }); _prepareData(); } @@ -50,7 +47,7 @@ class _EntityViewPageState extends State { padding: EdgeInsets.all(10.0), child: ListView( children: [ - _entity.buildExtendedWidget(context, _lastState) + _entity.buildWidget(_formKey, false) ], ), ), diff --git a/lib/main.dart b/lib/main.dart index 649e0aa..54e816f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -409,7 +409,7 @@ class _MainPageState extends State with WidgetsBindingObserver { entities.add( Padding( padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), - child: entity.buildWidget(context), + child: entity.buildWidget(null, true), )); } }); diff --git a/lib/mdi.class.dart b/lib/mdi.class.dart index 3bd9c1c..bcc0cd6 100644 --- a/lib/mdi.class.dart +++ b/lib/mdi.class.dart @@ -2875,6 +2875,7 @@ class MaterialDesignIcons { if (data.entityPicture != null) { if (homeAssistantWebHost != null) { return CircleAvatar( + radius: size/2, backgroundColor: Colors.white, backgroundImage: CachedNetworkImageProvider( "$homeAssistantWebHost${data.entityPicture}", From 2f135169a981dccbb2398c64feef502f424026c7 Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 01:37:33 +0300 Subject: [PATCH 03/10] Fix slider step issue --- lib/entity.class.dart | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index b7e6b0e..788f7b1 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -51,10 +51,6 @@ class Entity { update(rawData); } - int getValueDivisions() { - return ((maxValue - minValue)/valueStep).round().round(); - } - void update(Map rawData) { _attributes = rawData["attributes"] ?? {}; _domain = rawData["entity_id"].split(".")[0]; @@ -250,9 +246,8 @@ class InputEntity extends Entity { min: this.minValue*10, max: this.maxValue*10, value: (this.doubleState <= this.maxValue) && (this.doubleState >= this.minValue) ? this.doubleState*10 : this.minValue*10, - //divisions: this.getValueDivisions(), onChanged: (value) { - eventBus.fire(new StateChangedEvent(_entityId, ((value / 10).roundToDouble()).toString(), true)); + eventBus.fire(new StateChangedEvent(_entityId, (value.roundToDouble() / 10).toString(), true)); }, onChangeEnd: (value) { eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId,{"value": "$_state"})); From 9e83a3e447cbd60f0c47845f8eba7592dd70606d Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 10:00:19 +0300 Subject: [PATCH 04/10] Refactoring: Input text and focus --- lib/entity.class.dart | 126 +++++++++--------------------------------- lib/entity.page.dart | 7 ++- lib/main.dart | 2 +- 3 files changed, 33 insertions(+), 102 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index 788f7b1..fb5555d 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -71,51 +71,27 @@ class Entity { eventBus.fire(new ShowEntityPageEvent(this)); } - Widget buildWidget(GlobalKey formKey, bool tapAction) { + Widget buildWidget(bool inCard) { return SizedBox( height: Entity.WIDGET_HEIGHT, child: Row( children: [ GestureDetector( child: _buildIconWidget(), - onTap: tapAction ? openEntityPage : null, + onTap: inCard ? openEntityPage : null, ), Expanded( child: GestureDetector( child: _buildNameWidget(), - onTap: tapAction ? openEntityPage : null, + onTap: inCard ? openEntityPage : null, ), ), - _buildActionWidget() + _buildActionWidget(inCard) ], ), ); } - /*Widget buildExtendedWidget(BuildContext context, GlobalKey formKey, String staticState) { - return Row( - children: [ - _buildIconWidget(), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Expanded( - child: _buildNameWidget(), - ), - _buildExtendedActionWidget(context, staticState) - ], - ), - _buildLastUpdatedWidget() - ], - ), - ) - ], - ); - }*/ - Widget _buildIconWidget() { return Padding( padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, 12.0, 0.0), @@ -148,7 +124,7 @@ class Entity { ); } - Widget _buildActionWidget() { + Widget _buildActionWidget(bool inCard) { return Padding( padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), child: GestureDetector( @@ -175,7 +151,7 @@ class SwitchEntity extends Entity { SwitchEntity(Map rawData) : super(rawData); @override - Widget _buildActionWidget() { + Widget _buildActionWidget(bool inCard) { return Switch( value: this.isOn, onChanged: ((switchState) { @@ -191,7 +167,7 @@ class ButtonEntity extends Entity { ButtonEntity(Map rawData) : super(rawData); @override - Widget _buildActionWidget() { + Widget _buildActionWidget(bool inCard) { return FlatButton( onPressed: (() { eventBus.fire(new ServiceCallEvent(_domain, "turn_on", _entityId, null)); @@ -207,35 +183,25 @@ class ButtonEntity extends Entity { } class InputEntity extends Entity { + String tmpState; + FocusNode _focusNode; - InputEntity(Map rawData) : super(rawData); + InputEntity(Map rawData) : super(rawData) { + _focusNode = FocusNode(); + //TODO memory leak generator + _focusNode.addListener(_focusListener); + tmpState = state; + } - /*@override - Widget buildExtendedWidget(BuildContext context, GlobalKey formKey, String staticState) { - return Column( - children: [ - SizedBox( - height: Entity.EXTENDED_WIDGET_HEIGHT, - child: Row( - children: [ - _buildIconWidget(), - Expanded( - child: _buildNameWidget(), - ), - _buildLastUpdatedWidget() - ], - ), - ), - SizedBox( - height: Entity.EXTENDED_WIDGET_HEIGHT, - child: _buildInputWidget(context, formKey, staticState), - ) - ], - ); - }*/ + void _focusListener() { + //TheLogger.log("Debug", "Focused ${_focusNode.hasFocus? 'on' : 'of'} $entityId. Old state: $state. New state: $tmpState"); + if (!_focusNode.hasFocus && (tmpState != state)) { + eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId, {"value": "$tmpState"})); + } + } @override - Widget _buildActionWidget() { + Widget _buildActionWidget(bool inCard) { if (this.isSliderField) { return Container( width: 200.0, @@ -271,55 +237,17 @@ class InputEntity extends Entity { return Container( width: 160.0, child: TextField( + focusNode: inCard ? _focusNode : null, obscureText: this.isPasswordField, - controller: TextEditingController( - text: _state, - ), + controller: new TextEditingController.fromValue(new TextEditingValue(text: _state,selection: new TextSelection.collapsed(offset: _state.length))), onChanged: (value) { - //TODO - //staticState = value; - }, + tmpState = value; + } ), ); } else { - return super._buildActionWidget(); + return super._buildActionWidget(inCard); } } - /*Widget _buildInputWidget(BuildContext context, GlobalKey formKey, String staticState) { - return Padding( - padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: TextField( - obscureText: this.isPasswordField, - controller: TextEditingController( - text: staticState, - ), - onChanged: (value) { - staticState = value; - }, - ), - ), - SizedBox( - width: 63.0, - child: FlatButton( - onPressed: () { - eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId,{"value": "$staticState"})); - Navigator.pop(context); - }, - child: Text( - "SET", - textAlign: TextAlign.right, - style: new TextStyle(fontSize: Entity.STATE_FONT_SIZE, color: Colors.blue), - ), - ), - ) - ], - ) - ); - }*/ - } \ No newline at end of file diff --git a/lib/entity.page.dart b/lib/entity.page.dart index 365710f..d133d79 100644 --- a/lib/entity.page.dart +++ b/lib/entity.page.dart @@ -13,7 +13,6 @@ class _EntityViewPageState extends State { String _title; Entity _entity; StreamSubscription _stateSubscription; - final _formKey = GlobalKey(); @override void initState() { @@ -47,7 +46,7 @@ class _EntityViewPageState extends State { padding: EdgeInsets.all(10.0), child: ListView( children: [ - _entity.buildWidget(_formKey, false) + _entity.buildWidget(false) ], ), ), @@ -56,6 +55,10 @@ class _EntityViewPageState extends State { @override void dispose(){ + if (_entity is InputEntity && (_entity as InputEntity).tmpState != _entity.state) { + eventBus.fire(new ServiceCallEvent(_entity.domain, "set_value", _entity.entityId, {"value": "${(_entity as InputEntity).tmpState}"})); + TheLogger.log("Debug", "Saving changed input value for ${_entity.entityId}"); + } if (_stateSubscription != null) _stateSubscription.cancel(); super.dispose(); } diff --git a/lib/main.dart b/lib/main.dart index 54e816f..bb1be1b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -409,7 +409,7 @@ class _MainPageState extends State with WidgetsBindingObserver { entities.add( Padding( padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), - child: entity.buildWidget(null, true), + child: entity.buildWidget(true), )); } }); From 7dd8f65af70eb6b94245db3b2937a3d6ad82faff Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 10:15:32 +0300 Subject: [PATCH 05/10] Last updated time in duration --- lib/entity.class.dart | 44 +++++++++++++++++++++++++++++++++++-------- lib/entity.page.dart | 3 ++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index fb5555d..ec7a8bc 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -15,7 +15,7 @@ class Entity { static const ICON_SIZE = 28.0; static const STATE_FONT_SIZE = 16.0; static const NAME_FONT_SIZE = 16.0; - static const SMALL_FONT_SIZE = 12.0; + static const SMALL_FONT_SIZE = 14.0; Map _attributes; String _domain; @@ -63,7 +63,28 @@ class Entity { if (_lastUpdated == null) { return "-"; } else { - return formatDate(_lastUpdated, [yy, '-', M, '-', d, ' ', HH, ':', nn, ':', ss]); + DateTime now = DateTime.now(); + Duration d = now.difference(_lastUpdated); + String text; + int v; + if (d.inDays == 0) { + if (d.inHours == 0) { + if (d.inMinutes == 0) { + text = "seconds ago"; + v = d.inSeconds; + } else { + text = "minutes ago"; + v = d.inMinutes; + } + } else { + text = "hours ago"; + v = d.inHours; + } + } else { + text = "days ago"; + v = d.inDays; + } + return "$v $text"; } } @@ -92,6 +113,10 @@ class Entity { ); } + Widget buildAdditionalWidget() { + return _buildLastUpdatedWidget(); + } + Widget _buildIconWidget() { return Padding( padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, 12.0, 0.0), @@ -100,12 +125,15 @@ class Entity { } Widget _buildLastUpdatedWidget() { - return Text( - '${this.lastUpdated}', - textAlign: TextAlign.left, - style: TextStyle( - fontSize: Entity.SMALL_FONT_SIZE, - color: Colors.black26 + return Padding( + padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, Entity.SMALL_FONT_SIZE, 0.0, 0.0), + child: Text( + '${this.lastUpdated}', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: Entity.SMALL_FONT_SIZE, + color: Colors.black26 + ), ), ); } diff --git a/lib/entity.page.dart b/lib/entity.page.dart index d133d79..5136138 100644 --- a/lib/entity.page.dart +++ b/lib/entity.page.dart @@ -46,7 +46,8 @@ class _EntityViewPageState extends State { padding: EdgeInsets.all(10.0), child: ListView( children: [ - _entity.buildWidget(false) + _entity.buildWidget(false), + _entity.buildAdditionalWidget() ], ), ), From 9de8a659d33bd30b4cd8359cd13bb783430a56df Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 12:51:55 +0300 Subject: [PATCH 06/10] Resolves #95: Input value validation --- lib/entity.class.dart | 64 ++++++++++++++++++++++++++++++----- lib/home_assistant.class.dart | 2 +- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index ec7a8bc..0655bed 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -33,6 +33,9 @@ class Entity { double get maxValue => _attributes["max"] ?? 100.0; double get valueStep => _attributes["step"] ?? 1.0; double get doubleState => double.tryParse(_state) ?? 0.0; + int get valueMinLength => _attributes["min"] ?? -1; + int get valueMaxLength => _attributes["max"] ?? -1; + String get valuePattern => _attributes["pattern"] ?? null; bool get isSliderField => _attributes["mode"] == "slider"; bool get isTextField => _attributes["mode"] == "text"; bool get isPasswordField => _attributes["mode"] == "password"; @@ -92,6 +95,10 @@ class Entity { eventBus.fire(new ShowEntityPageEvent(this)); } + void sendNewState(newState) { + return; + } + Widget buildWidget(bool inCard) { return SizedBox( height: Entity.WIDGET_HEIGHT, @@ -178,12 +185,17 @@ class SwitchEntity extends Entity { SwitchEntity(Map rawData) : super(rawData); + @override + void sendNewState(newValue) { + eventBus.fire(new ServiceCallEvent(_domain, (newValue as bool) ? "turn_on" : "turn_off", entityId, null)); + } + @override Widget _buildActionWidget(bool inCard) { return Switch( value: this.isOn, onChanged: ((switchState) { - eventBus.fire(new ServiceCallEvent(_domain, switchState ? "turn_on" : "turn_off", entityId, null)); + sendNewState(switchState); }), ); } @@ -194,11 +206,16 @@ class ButtonEntity extends Entity { ButtonEntity(Map rawData) : super(rawData); + @override + void sendNewState(newValue) { + eventBus.fire(new ServiceCallEvent(_domain, "turn_on", _entityId, null)); + } + @override Widget _buildActionWidget(bool inCard) { return FlatButton( onPressed: (() { - eventBus.fire(new ServiceCallEvent(_domain, "turn_on", _entityId, null)); + sendNewState(null); }), child: Text( "EXECUTE", @@ -213,18 +230,43 @@ class ButtonEntity extends Entity { class InputEntity extends Entity { String tmpState; FocusNode _focusNode; + bool validValue = false; InputEntity(Map rawData) : super(rawData) { _focusNode = FocusNode(); - //TODO memory leak generator + //TODO possible memory leak generator _focusNode.addListener(_focusListener); - tmpState = state; + //tmpState = state; + } + + @override + void sendNewState(newValue) { + if (validate(newValue)) { + eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId, + {"value": "${newValue.toString()}"})); + } + } + + @override + void update(Map rawData) { + super.update(rawData); + tmpState = _state; + } + + bool validate(newValue) { + if (newValue is String) { + //TODO add pattern support + validValue = (newValue.length >= this.valueMinLength) && (this.valueMaxLength == -1 || (newValue.length <= this.valueMaxLength)); + } else { + validValue = true; + } + return validValue; } void _focusListener() { - //TheLogger.log("Debug", "Focused ${_focusNode.hasFocus? 'on' : 'of'} $entityId. Old state: $state. New state: $tmpState"); if (!_focusNode.hasFocus && (tmpState != state)) { - eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId, {"value": "$tmpState"})); + sendNewState(tmpState); + tmpState = state; } } @@ -241,10 +283,14 @@ class InputEntity extends Entity { max: this.maxValue*10, value: (this.doubleState <= this.maxValue) && (this.doubleState >= this.minValue) ? this.doubleState*10 : this.minValue*10, onChanged: (value) { - eventBus.fire(new StateChangedEvent(_entityId, (value.roundToDouble() / 10).toString(), true)); + if (validate(value.roundToDouble() / 10)) { + eventBus.fire(new StateChangedEvent( + _entityId, (value.roundToDouble() / 10).toString(), + true)); + } }, onChangeEnd: (value) { - eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId,{"value": "$_state"})); + sendNewState(value.roundToDouble() / 10); }, ), ), @@ -267,7 +313,7 @@ class InputEntity extends Entity { child: TextField( focusNode: inCard ? _focusNode : null, obscureText: this.isPasswordField, - controller: new TextEditingController.fromValue(new TextEditingValue(text: _state,selection: new TextSelection.collapsed(offset: _state.length))), + controller: new TextEditingController.fromValue(new TextEditingValue(text: tmpState,selection: new TextSelection.collapsed(offset: tmpState.length))), onChanged: (value) { tmpState = value; } diff --git a/lib/home_assistant.class.dart b/lib/home_assistant.class.dart index 03790f3..4653f72 100644 --- a/lib/home_assistant.class.dart +++ b/lib/home_assistant.class.dart @@ -183,7 +183,7 @@ class HomeAssistant { } void _handleEntityStateChange(Map eventData) { - TheLogger.log("Debug", "Parsing new state for ${eventData['entity_id']}"); + TheLogger.log("Debug", "New state for ${eventData['entity_id']}"); _entities.updateState(eventData); eventBus.fire(new StateChangedEvent(eventData["entity_id"], null, false)); } From 60f216df13c6e412ed8afa570a0aab34f632f9d4 Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 20:24:13 +0300 Subject: [PATCH 07/10] Resolves #99 Slider with mutliplier --- lib/entity.class.dart | 184 ++++++++++++++++++------------- lib/entity_collection.class.dart | 5 +- 2 files changed, 109 insertions(+), 80 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index 0655bed..e38d7c0 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -23,25 +23,17 @@ class Entity { String _state; DateTime _lastUpdated; - String get displayName => _attributes["friendly_name"] ?? (_attributes["name"] ?? "_"); + String get displayName => + _attributes["friendly_name"] ?? (_attributes["name"] ?? "_"); String get domain => _domain; String get entityId => _entityId; String get state => _state; set state(value) => _state = value; - double get minValue => _attributes["min"] ?? 0.0; - double get maxValue => _attributes["max"] ?? 100.0; - double get valueStep => _attributes["step"] ?? 1.0; - double get doubleState => double.tryParse(_state) ?? 0.0; - int get valueMinLength => _attributes["min"] ?? -1; - int get valueMaxLength => _attributes["max"] ?? -1; - String get valuePattern => _attributes["pattern"] ?? null; - bool get isSliderField => _attributes["mode"] == "slider"; - bool get isTextField => _attributes["mode"] == "text"; - bool get isPasswordField => _attributes["mode"] == "password"; - String get deviceClass => _attributes["device_class"] ?? null; - bool get isView => (_domain == "group") && (_attributes != null ? _attributes["view"] ?? false : false); + bool get isView => + (_domain == "group") && + (_attributes != null ? _attributes["view"] ?? false : false); bool get isGroup => _domain == "group"; String get icon => _attributes["icon"] ?? ""; bool get isOn => state == "on"; @@ -127,20 +119,22 @@ class Entity { Widget _buildIconWidget() { return Padding( padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, 12.0, 0.0), - child: MaterialDesignIcons.createIconWidgetFromEntityData(this, Entity.ICON_SIZE, Entity.STATE_ICONS_COLORS[_state] ?? Colors.blueGrey), + child: MaterialDesignIcons.createIconWidgetFromEntityData( + this, + Entity.ICON_SIZE, + Entity.STATE_ICONS_COLORS[_state] ?? Colors.blueGrey), ); } Widget _buildLastUpdatedWidget() { return Padding( - padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, Entity.SMALL_FONT_SIZE, 0.0, 0.0), + padding: EdgeInsets.fromLTRB( + Entity.LEFT_WIDGET_PADDING, Entity.SMALL_FONT_SIZE, 0.0, 0.0), child: Text( '${this.lastUpdated}', textAlign: TextAlign.left, - style: TextStyle( - fontSize: Entity.SMALL_FONT_SIZE, - color: Colors.black26 - ), + style: + TextStyle(fontSize: Entity.SMALL_FONT_SIZE, color: Colors.black26), ), ); } @@ -152,28 +146,24 @@ class Entity { "${this.displayName}", overflow: TextOverflow.ellipsis, softWrap: false, - style: TextStyle( - fontSize: Entity.NAME_FONT_SIZE - ), + style: TextStyle(fontSize: Entity.NAME_FONT_SIZE), ), ); } Widget _buildActionWidget(bool inCard) { return Padding( - padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), + padding: + EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), child: GestureDetector( child: Text( - this.isPasswordField ? "******" : "$_state${this.unitOfMeasurement}", textAlign: TextAlign.right, style: new TextStyle( fontSize: Entity.STATE_FONT_SIZE, - ) - ), + )), onTap: openEntityPage, - ) - ); + )); } /*Widget _buildExtendedActionWidget(BuildContext context, String staticState) { @@ -182,12 +172,12 @@ class Entity { } class SwitchEntity extends Entity { - SwitchEntity(Map rawData) : super(rawData); @override void sendNewState(newValue) { - eventBus.fire(new ServiceCallEvent(_domain, (newValue as bool) ? "turn_on" : "turn_off", entityId, null)); + eventBus.fire(new ServiceCallEvent( + _domain, (newValue as bool) ? "turn_on" : "turn_off", entityId, null)); } @override @@ -199,11 +189,9 @@ class SwitchEntity extends Entity { }), ); } - } class ButtonEntity extends Entity { - ButtonEntity(Map rawData) : super(rawData); @override @@ -220,11 +208,73 @@ class ButtonEntity extends Entity { child: Text( "EXECUTE", textAlign: TextAlign.right, - style: new TextStyle(fontSize: Entity.STATE_FONT_SIZE, color: Colors.blue), + style: + new TextStyle(fontSize: Entity.STATE_FONT_SIZE, color: Colors.blue), ), ); } +} +class SliderEntity extends Entity { + double _oldValue; + int _multiplier = 1; + + double get minValue => _attributes["min"] ?? 0.0; + double get maxValue => _attributes["max"] ?? 100.0; + double get valueStep => _attributes["step"] ?? 1.0; + double get doubleState => double.tryParse(_state) ?? 0.0; + + SliderEntity(Map rawData) : super(rawData) { + _oldValue = doubleState; + if (valueStep < 1) { + _multiplier = 10; + } else if (valueStep < 0.1) { + _multiplier = 100; + } + } + + @override + void sendNewState(newValue) { + eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId, + {"value": "${newValue.toString()}"})); + } + + @override + Widget _buildActionWidget(bool inCard) { + return Container( + width: 200.0, + child: Row( + children: [ + Expanded( + child: Slider( + min: this.minValue * _multiplier, + max: this.maxValue * _multiplier, + value: (this.doubleState <= this.maxValue) && + (this.doubleState >= this.minValue) + ? this.doubleState * _multiplier + : this.minValue * _multiplier, + onChanged: (value) { + //debugPrint("$value"); + eventBus.fire(new StateChangedEvent(_entityId, + (value.roundToDouble() / _multiplier).toString(), true)); + }, + onChangeEnd: (value) { + sendNewState(value.roundToDouble() / _multiplier); + }, + ), + ), + Padding( + padding: EdgeInsets.only(right: Entity.RIGHT_WIDGET_PADDING), + child: Text("$_state${this.unitOfMeasurement}", + textAlign: TextAlign.right, + style: new TextStyle( + fontSize: Entity.STATE_FONT_SIZE, + )), + ) + ], + ), + ); + } } class InputEntity extends Entity { @@ -232,6 +282,12 @@ class InputEntity extends Entity { FocusNode _focusNode; bool validValue = false; + int get valueMinLength => _attributes["min"] ?? -1; + int get valueMaxLength => _attributes["max"] ?? -1; + String get valuePattern => _attributes["pattern"] ?? null; + bool get isTextField => _attributes["mode"] == "text"; + bool get isPasswordField => _attributes["mode"] == "password"; + InputEntity(Map rawData) : super(rawData) { _focusNode = FocusNode(); //TODO possible memory leak generator @@ -256,7 +312,9 @@ class InputEntity extends Entity { bool validate(newValue) { if (newValue is String) { //TODO add pattern support - validValue = (newValue.length >= this.valueMinLength) && (this.valueMaxLength == -1 || (newValue.length <= this.valueMaxLength)); + validValue = (newValue.length >= this.valueMinLength) && + (this.valueMaxLength == -1 || + (newValue.length <= this.valueMaxLength)); } else { validValue = true; } @@ -272,56 +330,24 @@ class InputEntity extends Entity { @override Widget _buildActionWidget(bool inCard) { - if (this.isSliderField) { - return Container( - width: 200.0, - child: Row( - children: [ - Expanded( - child: Slider( - min: this.minValue*10, - max: this.maxValue*10, - value: (this.doubleState <= this.maxValue) && (this.doubleState >= this.minValue) ? this.doubleState*10 : this.minValue*10, - onChanged: (value) { - if (validate(value.roundToDouble() / 10)) { - eventBus.fire(new StateChangedEvent( - _entityId, (value.roundToDouble() / 10).toString(), - true)); - } - }, - onChangeEnd: (value) { - sendNewState(value.roundToDouble() / 10); - }, - ), - ), - Padding( - padding: EdgeInsets.only(right: Entity.RIGHT_WIDGET_PADDING), - child: Text( - "$_state${this.unitOfMeasurement}", - textAlign: TextAlign.right, - style: new TextStyle( - fontSize: Entity.STATE_FONT_SIZE, - ) - ), - ) - ], - ), - ); - } else if (this.isTextField || this.isPasswordField) { + if (this.isTextField || this.isPasswordField) { return Container( width: 160.0, child: TextField( - focusNode: inCard ? _focusNode : null, - obscureText: this.isPasswordField, - controller: new TextEditingController.fromValue(new TextEditingValue(text: tmpState,selection: new TextSelection.collapsed(offset: tmpState.length))), - onChanged: (value) { - tmpState = value; - } - ), + focusNode: inCard ? _focusNode : null, + obscureText: this.isPasswordField, + controller: new TextEditingController.fromValue( + new TextEditingValue( + text: tmpState, + selection: + new TextSelection.collapsed(offset: tmpState.length))), + onChanged: (value) { + tmpState = value; + }), ); } else { + TheLogger.log("Warning", "Unsupported input mode for $entityId"); return super._buildActionWidget(inCard); } } - -} \ No newline at end of file +} diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index 1aae3b6..ae9bd91 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -40,8 +40,11 @@ class EntityCollection { return ButtonEntity(rawEntityData); } - case "input_text": case "input_number": { + return SliderEntity(rawEntityData); + } + + case "input_text": { return InputEntity(rawEntityData); } From acd468ae759260c5c4d70d4cb9d25127d87fb0e9 Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 20:57:07 +0300 Subject: [PATCH 08/10] Resolves #53 input_select support --- lib/entity.class.dart | 49 ++++++++++++++++++++++++++++---- lib/entity.page.dart | 4 +-- lib/entity_collection.class.dart | 6 +++- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index e38d7c0..884e1af 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -16,6 +16,7 @@ class Entity { static const STATE_FONT_SIZE = 16.0; static const NAME_FONT_SIZE = 16.0; static const SMALL_FONT_SIZE = 14.0; + static const INPUT_WIDTH = 160.0; Map _attributes; String _domain; @@ -216,7 +217,6 @@ class ButtonEntity extends Entity { } class SliderEntity extends Entity { - double _oldValue; int _multiplier = 1; double get minValue => _attributes["min"] ?? 0.0; @@ -225,7 +225,6 @@ class SliderEntity extends Entity { double get doubleState => double.tryParse(_state) ?? 0.0; SliderEntity(Map rawData) : super(rawData) { - _oldValue = doubleState; if (valueStep < 1) { _multiplier = 10; } else if (valueStep < 0.1) { @@ -277,7 +276,45 @@ class SliderEntity extends Entity { } } -class InputEntity extends Entity { +class SelectEntity extends Entity { + List _listOptions = []; + String get initialValue => _attributes["initial"] ?? null; + + SelectEntity(Map rawData) : super(rawData) { + if (_attributes["options"] != null) { + _attributes["options"].forEach((value){ + _listOptions.add(value.toString()); + }); + } + } + + @override + void sendNewState(newValue) { + eventBus.fire(new ServiceCallEvent(_domain, "select_option", _entityId, + {"option": "$newValue"})); + } + + @override + Widget _buildActionWidget(bool inCard) { + return Container( + width: Entity.INPUT_WIDTH, + child: DropdownButton( + value: _state, + items: this._listOptions.map((String value) { + return new DropdownMenuItem( + value: value, + child: new Text(value), + ); + }).toList(), + onChanged: (_) { + sendNewState(_); + }, + ), + ); + } +} + +class TextEntity extends Entity { String tmpState; FocusNode _focusNode; bool validValue = false; @@ -288,7 +325,7 @@ class InputEntity extends Entity { bool get isTextField => _attributes["mode"] == "text"; bool get isPasswordField => _attributes["mode"] == "password"; - InputEntity(Map rawData) : super(rawData) { + TextEntity(Map rawData) : super(rawData) { _focusNode = FocusNode(); //TODO possible memory leak generator _focusNode.addListener(_focusListener); @@ -299,7 +336,7 @@ class InputEntity extends Entity { void sendNewState(newValue) { if (validate(newValue)) { eventBus.fire(new ServiceCallEvent(_domain, "set_value", _entityId, - {"value": "${newValue.toString()}"})); + {"value": "{newValue"})); } } @@ -332,7 +369,7 @@ class InputEntity extends Entity { Widget _buildActionWidget(bool inCard) { if (this.isTextField || this.isPasswordField) { return Container( - width: 160.0, + width: Entity.INPUT_WIDTH, child: TextField( focusNode: inCard ? _focusNode : null, obscureText: this.isPasswordField, diff --git a/lib/entity.page.dart b/lib/entity.page.dart index 5136138..a81b44e 100644 --- a/lib/entity.page.dart +++ b/lib/entity.page.dart @@ -56,8 +56,8 @@ class _EntityViewPageState extends State { @override void dispose(){ - if (_entity is InputEntity && (_entity as InputEntity).tmpState != _entity.state) { - eventBus.fire(new ServiceCallEvent(_entity.domain, "set_value", _entity.entityId, {"value": "${(_entity as InputEntity).tmpState}"})); + if (_entity is TextEntity && (_entity as TextEntity).tmpState != _entity.state) { + eventBus.fire(new ServiceCallEvent(_entity.domain, "set_value", _entity.entityId, {"value": "${(_entity as TextEntity).tmpState}"})); TheLogger.log("Debug", "Saving changed input value for ${_entity.entityId}"); } if (_stateSubscription != null) _stateSubscription.cancel(); diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index ae9bd91..1b33480 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -40,12 +40,16 @@ class EntityCollection { return ButtonEntity(rawEntityData); } + case "input_select": { + return SelectEntity(rawEntityData); + } + case "input_number": { return SliderEntity(rawEntityData); } case "input_text": { - return InputEntity(rawEntityData); + return TextEntity(rawEntityData); } default: { From 062392b38c4b192f17fc75d296c82946837d7604 Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 23:12:27 +0300 Subject: [PATCH 09/10] Resolves #100 input_datetime --- lib/entity.class.dart | 126 +++++++++++++++++++++++++++---- lib/entity.page.dart | 2 +- lib/entity_collection.class.dart | 4 + lib/main.dart | 2 +- 4 files changed, 117 insertions(+), 17 deletions(-) diff --git a/lib/entity.class.dart b/lib/entity.class.dart index 884e1af..01a3212 100644 --- a/lib/entity.class.dart +++ b/lib/entity.class.dart @@ -92,7 +92,7 @@ class Entity { return; } - Widget buildWidget(bool inCard) { + Widget buildWidget(bool inCard, BuildContext context) { return SizedBox( height: Entity.WIDGET_HEIGHT, child: Row( @@ -107,7 +107,7 @@ class Entity { onTap: inCard ? openEntityPage : null, ), ), - _buildActionWidget(inCard) + _buildActionWidget(inCard, context) ], ), ); @@ -152,7 +152,7 @@ class Entity { ); } - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { return Padding( padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), @@ -164,12 +164,9 @@ class Entity { fontSize: Entity.STATE_FONT_SIZE, )), onTap: openEntityPage, - )); + ) + ); } - - /*Widget _buildExtendedActionWidget(BuildContext context, String staticState) { - return _buildActionWidget(context); - }*/ } class SwitchEntity extends Entity { @@ -182,7 +179,7 @@ class SwitchEntity extends Entity { } @override - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { return Switch( value: this.isOn, onChanged: ((switchState) { @@ -201,7 +198,7 @@ class ButtonEntity extends Entity { } @override - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { return FlatButton( onPressed: (() { sendNewState(null); @@ -216,6 +213,9 @@ class ButtonEntity extends Entity { } } +// +// SLIDER +// class SliderEntity extends Entity { int _multiplier = 1; @@ -239,7 +239,7 @@ class SliderEntity extends Entity { } @override - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { return Container( width: 200.0, child: Row( @@ -253,7 +253,6 @@ class SliderEntity extends Entity { ? this.doubleState * _multiplier : this.minValue * _multiplier, onChanged: (value) { - //debugPrint("$value"); eventBus.fire(new StateChangedEvent(_entityId, (value.roundToDouble() / _multiplier).toString(), true)); }, @@ -276,6 +275,103 @@ class SliderEntity extends Entity { } } +// +// DATETIME +// + +class DateTimeEntity extends Entity { + bool get hasDate => _attributes["has_date"] ?? false; + bool get hasTime => _attributes["has_time"] ?? false; + int get year => _attributes["year"] ?? 1970; + int get month => _attributes["month"] ?? 1; + int get day => _attributes["day"] ?? 1; + int get hour => _attributes["hour"] ?? 0; + int get minute => _attributes["minute"] ?? 0; + int get second => _attributes["second"] ?? 0; + String get formattedState => _getFormattedState(); + DateTime get dateTimeState => _getDateTimeState(); + + DateTimeEntity(Map rawData) : super(rawData); + + DateTime _getDateTimeState() { + return DateTime(this.year, this.month, this.day, this.hour, this.minute, this.second); + } + + String _getFormattedState() { + String formattedState = ""; + if (this.hasDate) { + formattedState += formatDate(dateTimeState, [M, ' ', d, ', ', yyyy]); + } + if (this.hasTime) { + formattedState += " "+formatDate(dateTimeState, [HH, ':', nn]); + } + return formattedState; + } + + @override + void sendNewState(newValue) { + eventBus.fire(new ServiceCallEvent(_domain, "set_datetime", _entityId, + newValue)); + } + + @override + Widget _buildActionWidget(bool inCard, BuildContext context) { + return Padding( + padding: + EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0), + child: GestureDetector( + child: Text( + "$formattedState", + textAlign: TextAlign.right, + style: new TextStyle( + fontSize: Entity.STATE_FONT_SIZE, + )), + onTap: () => _handleStateTap(context), + ) + ); + } + + void _handleStateTap(BuildContext context) { + if (hasDate) { + _showDatePicker(context).then((date) { + if (date != null) { + if (hasTime) { + _showTimePicker(context).then((time){ + sendNewState({"date": "${formatDate(date, [yyyy, '-', mm, '-', dd])}", "time": "${formatDate(DateTime(1970, 1, 1, time.hour, time.minute), [HH, ':', nn])}"}); + }); + } else { + sendNewState({"date": "${formatDate(date, [yyyy, '-', mm, '-', dd])}"}); + } + } + }); + } else if (hasTime) { + _showTimePicker(context).then((time){ + if (time != null) { + sendNewState({"time": "${formatDate(DateTime(1970, 1, 1, time.hour, time.minute), [HH, ':', nn])}"}); + } + }); + } else { + TheLogger.log("Warning", "$entityId has no date and no time"); + } + } + + Future _showDatePicker(BuildContext context) { + return showDatePicker( + context: context, + initialDate: dateTimeState, + firstDate: DateTime(1970), + lastDate: DateTime(2037) //Unix timestamp will finish at Jan 19, 2038 + ); + } + + Future _showTimePicker(BuildContext context) { + return showTimePicker( + context: context, + initialTime: TimeOfDay.fromDateTime(dateTimeState) + ); + } +} + class SelectEntity extends Entity { List _listOptions = []; String get initialValue => _attributes["initial"] ?? null; @@ -295,7 +391,7 @@ class SelectEntity extends Entity { } @override - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { return Container( width: Entity.INPUT_WIDTH, child: DropdownButton( @@ -366,7 +462,7 @@ class TextEntity extends Entity { } @override - Widget _buildActionWidget(bool inCard) { + Widget _buildActionWidget(bool inCard, BuildContext context) { if (this.isTextField || this.isPasswordField) { return Container( width: Entity.INPUT_WIDTH, @@ -384,7 +480,7 @@ class TextEntity extends Entity { ); } else { TheLogger.log("Warning", "Unsupported input mode for $entityId"); - return super._buildActionWidget(inCard); + return super._buildActionWidget(inCard, context); } } } diff --git a/lib/entity.page.dart b/lib/entity.page.dart index a81b44e..2bc2372 100644 --- a/lib/entity.page.dart +++ b/lib/entity.page.dart @@ -46,7 +46,7 @@ class _EntityViewPageState extends State { padding: EdgeInsets.all(10.0), child: ListView( children: [ - _entity.buildWidget(false), + _entity.buildWidget(false, context), _entity.buildAdditionalWidget() ], ), diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index 1b33480..4e06795 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -40,6 +40,10 @@ class EntityCollection { return ButtonEntity(rawEntityData); } + case "input_datetime": { + return DateTimeEntity(rawEntityData); + } + case "input_select": { return SelectEntity(rawEntityData); } diff --git a/lib/main.dart b/lib/main.dart index bb1be1b..259631d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -409,7 +409,7 @@ class _MainPageState extends State with WidgetsBindingObserver { entities.add( Padding( padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0), - child: entity.buildWidget(true), + child: entity.buildWidget(true, context), )); } }); From 0d7e7eb6f72991c290341b6e7426d4a8e288b99b Mon Sep 17 00:00:00 2001 From: estevez Date: Sun, 30 Sep 2018 23:14:40 +0300 Subject: [PATCH 10/10] Version 0.2.3 --- lib/main.dart | 2 +- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 259631d..3f690c9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -27,7 +27,7 @@ part 'badge_class.dart'; EventBus eventBus = new EventBus(); const String appName = "HA Client"; -const appVersion = "0.2.0"; +const appVersion = "0.2.1"; String homeAssistantWebHost; diff --git a/pubspec.lock b/pubspec.lock index 54e3160..4673b8b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -285,7 +285,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" plugin: dependency: transitive description: @@ -486,7 +486,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.2.1" + version: "3.2.3" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6476290..e5a0c9b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 0.2.0+22 +version: 0.2.1+23 environment: sdk: ">=2.0.0-dev.68.0 <3.0.0"