WIP #183 tap_action support. State change event fix

This commit is contained in:
Yegor Vialov
2018-11-16 22:32:43 +02:00
parent 1bd04abd37
commit 82c9bd26d1
29 changed files with 89 additions and 50 deletions

View File

@ -28,4 +28,10 @@ class EntityState {
static const unavailable = 'unavailable'; static const unavailable = 'unavailable';
static const ok = 'ok'; static const ok = 'ok';
static const problem = 'problem'; static const problem = 'problem';
}
class EntityTapAction {
static const moreInfo = 'more-info';
static const toggle = 'toggle';
static const callService = 'call-service';
} }

View File

@ -106,7 +106,7 @@ class Entity {
Widget buildEntityPageWidget(BuildContext context) { Widget buildEntityPageWidget(BuildContext context) {
return EntityModel( return EntityModel(
entity: EntityWrapper(entity: this), entityWrapper: EntityWrapper(entity: this),
child: EntityPageContainer(children: <Widget>[ child: EntityPageContainer(children: <Widget>[
DefaultEntityContainer(state: _buildStatePartForPage(context)), DefaultEntityContainer(state: _buildStatePartForPage(context)),
LastUpdatedWidget(), LastUpdatedWidget(),
@ -128,7 +128,7 @@ class Entity {
Widget buildBadgeWidget(BuildContext context) { Widget buildBadgeWidget(BuildContext context) {
return EntityModel( return EntityModel(
entity: EntityWrapper(entity: this), entityWrapper: EntityWrapper(entity: this),
child: BadgeWidget(), child: BadgeWidget(),
handleTap: true, handleTap: true,
); );

View File

@ -4,9 +4,18 @@ class EntityWrapper {
String displayName; String displayName;
String icon; String icon;
String tapAction;
String holdAction;
Entity entity; Entity entity;
EntityWrapper({this.entity, String icon, String displayName}) {
EntityWrapper({
this.entity,
String icon,
String displayName,
this.tapAction: EntityTapAction.moreInfo,
this.holdAction
}) {
this.icon = icon ?? entity.icon; this.icon = icon ?? entity.icon;
this.displayName = displayName ?? entity.displayName; this.displayName = displayName ?? entity.displayName;
} }

View File

@ -7,12 +7,12 @@ class BadgeWidget extends StatelessWidget {
double iconSize = 26.0; double iconSize = 26.0;
Widget badgeIcon; Widget badgeIcon;
String onBadgeTextValue; String onBadgeTextValue;
Color iconColor = EntityColor.badgeColors[entityModel.entity.entity.domain] ?? Color iconColor = EntityColor.badgeColors[entityModel.entityWrapper.entity.domain] ??
EntityColor.badgeColors["default"]; EntityColor.badgeColors["default"];
switch (entityModel.entity.entity.domain) { switch (entityModel.entityWrapper.entity.domain) {
case "sun": case "sun":
{ {
badgeIcon = entityModel.entity.entity.state == "below_horizon" badgeIcon = entityModel.entityWrapper.entity.state == "below_horizon"
? Icon( ? Icon(
MaterialDesignIcons.createIconDataFromIconCode(0xf0dc), MaterialDesignIcons.createIconDataFromIconCode(0xf0dc),
size: iconSize, size: iconSize,
@ -25,10 +25,10 @@ class BadgeWidget extends StatelessWidget {
} }
case "sensor": case "sensor":
{ {
onBadgeTextValue = entityModel.entity.entity.unitOfMeasurement; onBadgeTextValue = entityModel.entityWrapper.entity.unitOfMeasurement;
badgeIcon = Center( badgeIcon = Center(
child: Text( child: Text(
"${entityModel.entity.entity.state}", "${entityModel.entityWrapper.entity.state}",
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
softWrap: false, softWrap: false,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -40,14 +40,14 @@ class BadgeWidget extends StatelessWidget {
case "device_tracker": case "device_tracker":
{ {
badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData( badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData(
entityModel.entity, iconSize, Colors.black); entityModel.entityWrapper, iconSize, Colors.black);
onBadgeTextValue = entityModel.entity.entity.state; onBadgeTextValue = entityModel.entityWrapper.entity.state;
break; break;
} }
default: default:
{ {
badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData( badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData(
entityModel.entity, iconSize, Colors.black); entityModel.entityWrapper, iconSize, Colors.black);
} }
} }
Widget onBadgeText; Widget onBadgeText;
@ -109,7 +109,7 @@ class BadgeWidget extends StatelessWidget {
Container( Container(
width: 60.0, width: 60.0,
child: Text( child: Text(
"${entityModel.entity.displayName}", "${entityModel.entityWrapper.displayName}",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle(fontSize: 12.0), style: TextStyle(fontSize: 12.0),
softWrap: true, softWrap: true,
@ -120,6 +120,6 @@ class BadgeWidget extends StatelessWidget {
], ],
), ),
onTap: () => onTap: () =>
eventBus.fire(new ShowEntityPageEvent(entityModel.entity.entity))); eventBus.fire(new ShowEntityPageEvent(entityModel.entityWrapper.entity)));
} }
} }

View File

@ -165,7 +165,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final ClimateEntity entity = entityModel.entity.entity; final ClimateEntity entity = entityModel.entityWrapper.entity;
if (_changedHere) { if (_changedHere) {
_showPending = (_tmpTemperature != entity.temperature); _showPending = (_tmpTemperature != entity.temperature);
_changedHere = false; _changedHere = false;

View File

@ -38,7 +38,7 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final CoverEntity entity = entityModel.entity.entity; final CoverEntity entity = entityModel.entityWrapper.entity;
if (_changedHere) { if (_changedHere) {
_changedHere = false; _changedHere = false;
} else { } else {
@ -152,7 +152,7 @@ class CoverTiltControlsWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final CoverEntity entity = entityModel.entity.entity; final CoverEntity entity = entityModel.entityWrapper.entity;
List<Widget> buttons = []; List<Widget> buttons = [];
if (entity.supportOpenTilt) { if (entity.supportOpenTilt) {
buttons.add(IconButton( buttons.add(IconButton(

View File

@ -80,7 +80,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final LightEntity entity = entityModel.entity.entity; final LightEntity entity = entityModel.entityWrapper.entity;
if (!_changedHere) { if (!_changedHere) {
_resetState(entity); _resetState(entity);
} else { } else {

View File

@ -28,7 +28,7 @@ class MediaPlayerWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final EntityModel entityModel = EntityModel.of(context); final EntityModel entityModel = EntityModel.of(context);
final MediaPlayerEntity entity = entityModel.entity.entity; final MediaPlayerEntity entity = entityModel.entityWrapper.entity;
return Column( return Column(
children: <Widget>[ children: <Widget>[
Stack( Stack(
@ -229,7 +229,7 @@ class _MediaPlayerProgressWidgetState extends State<MediaPlayerProgressWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final EntityModel entityModel = EntityModel.of(context); final EntityModel entityModel = EntityModel.of(context);
final MediaPlayerEntity entity = entityModel.entity.entity; final MediaPlayerEntity entity = entityModel.entityWrapper.entity;
double progress; double progress;
try { try {
DateTime lastUpdated = DateTime.parse( DateTime lastUpdated = DateTime.parse(

View File

@ -25,7 +25,7 @@ class _SliderControlsWidgetState extends State<SliderControlsWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final SliderEntity entity = entityModel.entity.entity; final SliderEntity entity = entityModel.entityWrapper.entity;
if (entity.valueStep < 1) { if (entity.valueStep < 1) {
_multiplier = 10; _multiplier = 10;
} else if (entity.valueStep < 0.1) { } else if (entity.valueStep < 0.1) {

View File

@ -7,14 +7,14 @@ class EntityAttributesList extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
List<Widget> attrs = []; List<Widget> attrs = [];
if ((entityModel.entity.entity.attributesToShow == null) || if ((entityModel.entityWrapper.entity.attributesToShow == null) ||
(entityModel.entity.entity.attributesToShow.contains("all"))) { (entityModel.entityWrapper.entity.attributesToShow.contains("all"))) {
entityModel.entity.entity.attributes.forEach((name, value) { entityModel.entityWrapper.entity.attributes.forEach((name, value) {
attrs.add(_buildSingleAttribute("$name", "$value")); attrs.add(_buildSingleAttribute("$name", "$value"));
}); });
} else { } else {
entityModel.entity.entity.attributesToShow.forEach((String attr) { entityModel.entityWrapper.entity.attributesToShow.forEach((String attr) {
String attrValue = entityModel.entity.entity.getAttribute("$attr"); String attrValue = entityModel.entityWrapper.entity.getAttribute("$attr");
if (attrValue != null) { if (attrValue != null) {
attrs.add( attrs.add(
_buildSingleAttribute("$attr", "$attrValue")); _buildSingleAttribute("$attr", "$attrValue"));

View File

@ -15,14 +15,29 @@ class EntityIcon extends StatelessWidget {
child: Padding( child: Padding(
padding: padding, padding: padding,
child: MaterialDesignIcons.createIconWidgetFromEntityData( child: MaterialDesignIcons.createIconWidgetFromEntityData(
entityModel.entity, entityModel.entityWrapper,
iconSize, iconSize,
EntityColor.stateColor(entityModel.entity.entity.state) EntityColor.stateColor(entityModel.entityWrapper.entity.state)
), ),
), ),
onTap: () => entityModel.handleTap onTap: () {
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity.entity)) if (entityModel.handleTap) {
: null, switch (entityModel.entityWrapper.tapAction) {
case EntityTapAction.moreInfo: {
eventBus.fire(
new ShowEntityPageEvent(entityModel.entityWrapper.entity));
break;
}
case EntityTapAction.toggle: {
eventBus.fire(
ServiceCallEvent("homeassistant", "toggle", entityModel.entityWrapper.entity.entityId, null));
break;
}
}
}
}
); );
} }
} }

View File

@ -17,7 +17,7 @@ class EntityName extends StatelessWidget {
child: Padding( child: Padding(
padding: padding, padding: padding,
child: Text( child: Text(
"${entityModel.entity.displayName}", "${entityModel.entityWrapper.displayName}",
overflow: textOverflow, overflow: textOverflow,
softWrap: wordsWrap, softWrap: wordsWrap,
style: TextStyle(fontSize: fontSize), style: TextStyle(fontSize: fontSize),
@ -26,7 +26,7 @@ class EntityName extends StatelessWidget {
), ),
onTap: () => onTap: () =>
entityModel.handleTap entityModel.handleTap
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity.entity)) ? eventBus.fire(new ShowEntityPageEvent(entityModel.entityWrapper.entity))
: null, : null,
); );
} }

View File

@ -65,7 +65,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final HomeAssistantModel homeAssistantModel = HomeAssistantModel.of(context); final HomeAssistantModel homeAssistantModel = HomeAssistantModel.of(context);
final EntityModel entityModel = EntityModel.of(context); final EntityModel entityModel = EntityModel.of(context);
final Entity entity = entityModel.entity.entity; final Entity entity = entityModel.entityWrapper.entity;
if (!_needToUpdateHistory) { if (!_needToUpdateHistory) {
_needToUpdateHistory = true; _needToUpdateHistory = true;
} else { } else {

View File

@ -8,7 +8,7 @@ class LastUpdatedWidget extends StatelessWidget {
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
Sizes.leftWidgetPadding, 0.0, 0.0, 0.0), Sizes.leftWidgetPadding, 0.0, 0.0, 0.0),
child: Text( child: Text(
'${entityModel.entity.entity.lastUpdated}', '${entityModel.entityWrapper.entity.lastUpdated}',
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
fontSize: Sizes.smallFontSize, color: Colors.black26), fontSize: Sizes.smallFontSize, color: Colors.black26),

View File

@ -3,12 +3,12 @@ part of '../main.dart';
class EntityModel extends InheritedWidget { class EntityModel extends InheritedWidget {
const EntityModel({ const EntityModel({
Key key, Key key,
@required this.entity, @required this.entityWrapper,
@required this.handleTap, @required this.handleTap,
@required Widget child, @required Widget child,
}) : super(key: key, child: child); }) : super(key: key, child: child);
final EntityWrapper entity; final EntityWrapper entityWrapper;
final bool handleTap; final bool handleTap;
static EntityModel of(BuildContext context) { static EntityModel of(BuildContext context) {

View File

@ -13,7 +13,7 @@ class ButtonStateWidget extends StatelessWidget {
height: 34.0, height: 34.0,
child: FlatButton( child: FlatButton(
onPressed: (() { onPressed: (() {
_setNewState(entityModel.entity.entity); _setNewState(entityModel.entityWrapper.entity);
}), }),
child: Text( child: Text(
"EXECUTE", "EXECUTE",

View File

@ -4,7 +4,7 @@ class ClimateStateWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final ClimateEntity entity = entityModel.entity.entity; final ClimateEntity entity = entityModel.entityWrapper.entity;
String targetTemp = "-"; String targetTemp = "-";
if ((entity.supportTargetTemperature) && (entity.temperature != null)) { if ((entity.supportTargetTemperature) && (entity.temperature != null)) {
targetTemp = "${entity.temperature}"; targetTemp = "${entity.temperature}";

View File

@ -19,7 +19,7 @@ class CoverStateWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final CoverEntity entity = entityModel.entity.entity; final CoverEntity entity = entityModel.entityWrapper.entity;
List<Widget> buttons = []; List<Widget> buttons = [];
if (entity.supportOpen) { if (entity.supportOpen) {
buttons.add(IconButton( buttons.add(IconButton(

View File

@ -4,7 +4,7 @@ class DateTimeStateWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final DateTimeEntity entity = entityModel.entity.entity; final DateTimeEntity entity = entityModel.entityWrapper.entity;
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0), padding: EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0),
child: GestureDetector( child: GestureDetector(

View File

@ -18,7 +18,7 @@ class _SelectStateWidgetState extends State<SelectStateWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final SelectEntity entity = entityModel.entity.entity; final SelectEntity entity = entityModel.entityWrapper.entity;
Widget ctrl; Widget ctrl;
if (entity.listOptions.isNotEmpty) { if (entity.listOptions.isNotEmpty) {
ctrl = DropdownButton<String>( ctrl = DropdownButton<String>(

View File

@ -15,7 +15,7 @@ class SimpleEntityState extends StatelessWidget {
padding: padding, padding: padding,
child: GestureDetector( child: GestureDetector(
child: Text( child: Text(
"${entityModel.entity.entity.state}${entityModel.entity.entity.unitOfMeasurement}", "${entityModel.entityWrapper.entity.state}${entityModel.entityWrapper.entity.unitOfMeasurement}",
textAlign: textAlign, textAlign: textAlign,
maxLines: 4, maxLines: 4,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -24,7 +24,7 @@ class SimpleEntityState extends StatelessWidget {
fontSize: Sizes.stateFontSize, fontSize: Sizes.stateFontSize,
)), )),
onTap: () => entityModel.handleTap onTap: () => entityModel.handleTap
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity.entity)) ? eventBus.fire(new ShowEntityPageEvent(entityModel.entityWrapper.entity))
: null, : null,
) )
); );

View File

@ -34,7 +34,7 @@ class _SwitchStateWidgetState extends State<SwitchStateWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final entity = entityModel.entity.entity; final entity = entityModel.entityWrapper.entity;
if (!updatedHere) { if (!updatedHere) {
newState = entity.state; newState = entity.state;
} else { } else {

View File

@ -55,7 +55,7 @@ class _TextInputStateWidgetState extends State<TextInputStateWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final TextEntity entity = entityModel.entity.entity; final TextEntity entity = entityModel.entityWrapper.entity;
_entityState = entity.state; _entityState = entity.state;
_entityDomain = entity.domain; _entityDomain = entity.domain;
_entityId = entity.entityId; _entityId = entity.entityId;

View File

@ -427,7 +427,9 @@ class HomeAssistant {
EntityWrapper( EntityWrapper(
entity: entities.get(rawEntity["entity"]), entity: entities.get(rawEntity["entity"]),
displayName: rawEntity["name"], displayName: rawEntity["name"],
icon: rawEntity["icon"] icon: rawEntity["icon"],
tapAction: rawEntity["tap_action"] ?? EntityTapAction.moreInfo,
holdAction: rawEntity["hold_action"] ?? EntityTapAction.moreInfo
) )
); );
} }

View File

@ -140,6 +140,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
String _authType; String _authType;
//int _uiViewsCount = 0; //int _uiViewsCount = 0;
String _instanceHost; String _instanceHost;
StreamSubscription _stateSubscription;
StreamSubscription _settingsSubscription; StreamSubscription _settingsSubscription;
StreamSubscription _serviceCallSubscription; StreamSubscription _serviceCallSubscription;
StreamSubscription _showEntityPageSubscription; StreamSubscription _showEntityPageSubscription;
@ -208,6 +209,11 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
} }
_subscribe() { _subscribe() {
if (_stateSubscription == null) {
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
setState(() {});
});
}
if (_serviceCallSubscription == null) { if (_serviceCallSubscription == null) {
_serviceCallSubscription = _serviceCallSubscription =
eventBus.on<ServiceCallEvent>().listen((event) { eventBus.on<ServiceCallEvent>().listen((event) {
@ -546,6 +552,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
@override @override
void dispose() { void dispose() {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
if (_stateSubscription != null) _stateSubscription.cancel();
if (_settingsSubscription != null) _settingsSubscription.cancel(); if (_settingsSubscription != null) _settingsSubscription.cancel();
if (_serviceCallSubscription != null) _serviceCallSubscription.cancel(); if (_serviceCallSubscription != null) _serviceCallSubscription.cancel();
if (_showEntityPageSubscription != null) _showEntityPageSubscription.cancel(); if (_showEntityPageSubscription != null) _showEntityPageSubscription.cancel();

View File

@ -30,7 +30,7 @@ class EntitiesCardWidget extends StatelessWidget {
Padding( Padding(
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding), padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: EntityModel( child: EntityModel(
entity: entity, entityWrapper: entity,
handleTap: true, handleTap: true,
child: entity.entity.buildDefaultWidget(context) child: entity.entity.buildDefaultWidget(context)
), ),

View File

@ -33,7 +33,7 @@ class GlanceCardWidget extends StatelessWidget {
SizedBox( SizedBox(
width: width / columnsCount, width: width / columnsCount,
child: EntityModel( child: EntityModel(
entity: entity, entityWrapper: entity,
child: entity.entity.buildGlanceWidget(context, card.showName, card.showState), child: entity.entity.buildGlanceWidget(context, card.showName, card.showState),
handleTap: true handleTap: true
), ),

View File

@ -17,7 +17,7 @@ class MediaControlCardWidget extends StatelessWidget {
return Card( return Card(
child: EntityModel( child: EntityModel(
entity: card.linkedEntity, entityWrapper: card.linkedEntity,
handleTap: null, handleTap: null,
child: MediaPlayerWidget() child: MediaPlayerWidget()
) )

View File

@ -33,7 +33,7 @@ class UnsupportedCardWidget extends StatelessWidget {
Padding( Padding(
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding), padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: EntityModel( child: EntityModel(
entity: card.linkedEntity, entityWrapper: card.linkedEntity,
handleTap: true, handleTap: true,
child: card.linkedEntity.entity.buildDefaultWidget(context) child: card.linkedEntity.entity.buildDefaultWidget(context)
), ),