Add mode switch stateless widget

This commit is contained in:
Yegor Vialov
2018-10-16 23:20:27 +03:00
parent 9e80b0eaaf
commit a308aa29a4
3 changed files with 181 additions and 173 deletions

View File

@ -23,17 +23,18 @@ class Entity {
"sensor"
];
double rightWidgetPadding = 14.0;
double leftWidgetPadding = 8.0;
double extendedWidgetHeight = 50.0;
static const rightWidgetPadding = 14.0;
static const leftWidgetPadding = 8.0;
static const extendedWidgetHeight = 50.0;
static const iconSize = 28.0;
static const stateFontSize = 16.0;
static const nameFontSize = 16.0;
static const smallFontSize = 14.0;
static const largeFontSize = 24.0;
static const inputWidth = 160.0;
static const rowPadding = 10.0;
double widgetHeight = 34.0;
double iconSize = 28.0;
double stateFontSize = 16.0;
double nameFontSize = 16.0;
double smallFontSize = 14.0;
double largeFontSize = 24.0;
double inputWidth = 160.0;
double rowPadding = 10.0;
Map attributes;
String domain;
@ -89,7 +90,10 @@ class Entity {
Widget buildDefaultWidget(BuildContext context) {
return EntityModel(
entity: this,
child: DefaultEntityContainer(state: _buildStatePart(context)),
child: DefaultEntityContainer(
state: _buildStatePart(context),
height: widgetHeight,
),
handleTap: true,
);
}
@ -113,7 +117,7 @@ class Entity {
return EntityModel(
entity: this,
child: EntityPageContainer(children: <Widget>[
DefaultEntityContainer(state: _buildStatePartForPage(context)),
DefaultEntityContainer(state: _buildStatePartForPage(context), height: widgetHeight),
LastUpdatedWidget(),
Divider(),
_buildAdditionalControlsForPage(context),

View File

@ -64,7 +64,7 @@ class _ButtonControlWidgetState extends State<ButtonControlWidget> {
"EXECUTE",
textAlign: TextAlign.right,
style:
new TextStyle(fontSize: entityModel.entity.stateFontSize, color: Colors.blue),
new TextStyle(fontSize: Entity.stateFontSize, color: Colors.blue),
),
);
}
@ -398,7 +398,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
_resetVars(entity);
}
return Padding(
padding: EdgeInsets.fromLTRB(entity.leftWidgetPadding, entity.rowPadding, entity.rightWidgetPadding, 0.0),
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@ -418,21 +418,10 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildAwayModeControl(ClimateEntity entity) {
if (entity.supportAwayMode) {
return Row(
children: <Widget>[
Expanded(
child: Text(
"Away mode",
style: TextStyle(
fontSize: entity.stateFontSize
),
),
),
Switch(
onChanged: (value) => _setAwayMode(entity, value),
value: _tmpAwayMode,
)
],
return ModeSwitchWidget(
caption: "Away mode",
onChange: (value) => _setAwayMode(entity, value),
value: _tmpAwayMode,
);
} else {
return Container(height: 0.0, width: 0.0,);
@ -441,21 +430,10 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildOnOffControl(ClimateEntity entity) {
if (entity.supportOnOff) {
return Row(
children: <Widget>[
Expanded(
child: Text(
"On / Off",
style: TextStyle(
fontSize: entity.stateFontSize
),
),
),
Switch(
onChanged: (value) => _setOnOf(entity, value),
value: !_tmpIsOff,
)
],
return ModeSwitchWidget(
onChange: (value) => _setOnOf(entity, value),
caption: "On / Off",
value: !_tmpIsOff
);
} else {
return Container(height: 0.0, width: 0.0,);
@ -464,21 +442,10 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildAuxHeatControl(ClimateEntity entity) {
if (entity.supportAuxHeat ) {
return Row(
children: <Widget>[
Expanded(
child: Text(
"Aux heat",
style: TextStyle(
fontSize: entity.stateFontSize
),
),
),
Switch(
onChanged: (value) => _setAuxHeat(entity, value),
value: _tmpAuxHeat,
)
],
return ModeSwitchWidget(
caption: "Aux heat",
onChange: (value) => _setAuxHeat(entity, value),
value: _tmpAuxHeat
);
} else {
return Container(height: 0.0, width: 0.0,);
@ -487,29 +454,11 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildOperationControl(ClimateEntity entity) {
if (entity.supportOperationMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Operation", style: TextStyle(
fontSize: entity.stateFontSize
)),
DropdownButton<String>(
value: "$_tmpOperationMode",
iconSize: 30.0,
style: TextStyle(
fontSize: entity.largeFontSize,
color: Colors.black,
),
items: entity.operationList.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (mode) => _setOperationMode(entity, mode),
),
Container(height: entity.rowPadding,)
],
return ModeSelectorWidget(
onChange: (mode) => _setOperationMode(entity, mode),
options: entity.operationList,
caption: "Operation",
value: _tmpOperationMode,
);
} else {
return Container(height: 0.0, width: 0.0);
@ -518,29 +467,11 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildFanControl(ClimateEntity entity) {
if (entity.supportFanMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Fan mode", style: TextStyle(
fontSize: entity.stateFontSize
)),
DropdownButton<String>(
value: "$_tmpFanMode",
iconSize: 30.0,
style: TextStyle(
fontSize: entity.largeFontSize,
color: Colors.black,
),
items: entity.fanList.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (mode) => _setFanMode(entity, mode),
),
Container(height: entity.rowPadding,)
],
return ModeSelectorWidget(
options: entity.fanList,
onChange: (mode) => _setFanMode(entity, mode),
caption: "Fan mode",
value: _tmpFanMode,
);
} else {
return Container(height: 0.0, width: 0.0);
@ -549,29 +480,11 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
Widget _buildSwingControl(ClimateEntity entity) {
if (entity.supportSwingMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Swing mode", style: TextStyle(
fontSize: entity.stateFontSize
)),
DropdownButton<String>(
value: "$_tmpSwingMode",
iconSize: 30.0,
style: TextStyle(
fontSize: entity.largeFontSize,
color: Colors.black,
),
items: entity.swingList.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (mode) => _setSwingMode(entity, mode),
),
Container(height: entity.rowPadding,)
],
return ModeSelectorWidget(
onChange: (mode) => _setSwingMode(entity, mode),
options: entity.swingList,
value: _tmpSwingMode,
caption: "Swing mode"
);
} else {
return Container(height: 0.0, width: 0.0);
@ -584,10 +497,11 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Target temperature", style: TextStyle(
fontSize: entity.stateFontSize
fontSize: Entity.stateFontSize
)),
TemperatureControlWidget(
value: _tmpTemperature,
fontColor: _showPending ? Colors.red : Colors.black,
onLargeDec: () => _temperatureDown(entity, 0.5),
onLargeInc: () => _temperatureUp(entity, 0.5),
onSmallDec: () => _temperatureDown(entity, 0.1),
@ -606,6 +520,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
controls.addAll(<Widget>[
TemperatureControlWidget(
value: _tmpTargetLow,
fontColor: _showPending ? Colors.red : Colors.black,
onLargeDec: () => _targetLowDown(entity, 0.5),
onLargeInc: () => _targetLowUp(entity, 0.5),
onSmallDec: () => _targetLowDown(entity, 0.1),
@ -620,6 +535,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
controls.add(
TemperatureControlWidget(
value: _tmpTargetHigh,
fontColor: _showPending ? Colors.red : Colors.black,
onLargeDec: () => _targetHighDown(entity, 0.5),
onLargeInc: () => _targetHighUp(entity, 0.5),
onSmallDec: () => _targetHighDown(entity, 0.1),
@ -632,7 +548,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Target temperature range", style: TextStyle(
fontSize: entity.stateFontSize
fontSize: Entity.stateFontSize
)),
Row(
children: controls,
@ -650,7 +566,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
result.addAll(<Widget>[
Text(
"$_tmpTargetHumidity%",
style: TextStyle(fontSize: entity.largeFontSize),
style: TextStyle(fontSize: Entity.largeFontSize),
),
Expanded(
child: Slider(
@ -674,9 +590,9 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(
0.0, entity.rowPadding, 0.0, entity.rowPadding),
0.0, Entity.rowPadding, 0.0, Entity.rowPadding),
child: Text("Target humidity", style: TextStyle(
fontSize: entity.stateFontSize
fontSize: Entity.stateFontSize
)),
),
Row(
@ -684,7 +600,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
children: result,
),
Container(
height: entity.rowPadding,
height: Entity.rowPadding,
)
],
);
@ -795,7 +711,7 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
_resetVars(entity);
}
return Padding(
padding: EdgeInsets.fromLTRB(entity.leftWidgetPadding, entity.rowPadding, entity.rightWidgetPadding, 0.0),
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
@ -813,9 +729,9 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(
0.0, entity.rowPadding, 0.0, entity.rowPadding),
0.0, Entity.rowPadding, 0.0, Entity.rowPadding),
child: Text("Position", style: TextStyle(
fontSize: entity.stateFontSize
fontSize: Entity.stateFontSize
)),
),
Slider(
@ -831,7 +747,7 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
},
onChangeEnd: (double value) => _setNewPosition(entity, value),
),
Container(height: entity.rowPadding,)
Container(height: Entity.rowPadding,)
],
);
} else {
@ -861,15 +777,15 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
},
onChangeEnd: (double value) => _setNewTiltPosition(entity, value),
),
Container(height: entity.rowPadding,)
Container(height: Entity.rowPadding,)
]);
}
if (controls.isNotEmpty) {
controls.insert(0, Padding(
padding: EdgeInsets.fromLTRB(
0.0, entity.rowPadding, 0.0, entity.rowPadding),
0.0, Entity.rowPadding, 0.0, Entity.rowPadding),
child: Text("Tilt position", style: TextStyle(
fontSize: entity.stateFontSize
fontSize: Entity.stateFontSize
)),
));
return Column(

View File

@ -27,15 +27,16 @@ class DefaultEntityContainer extends StatelessWidget {
DefaultEntityContainer({
Key key,
@required this.state,
@required this.height
}) : super(key: key);
final Widget state;
final double height;
@override
Widget build(BuildContext context) {
final entityModel = EntityModel.of(context);
return SizedBox(
height: entityModel.entity.widgetHeight,
height: height,
child: Row(
children: <Widget>[
EntityIcon(),
@ -68,13 +69,13 @@ class SimpleEntityState extends StatelessWidget {
final entityModel = EntityModel.of(context);
return Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, entityModel.entity.rightWidgetPadding, 0.0),
0.0, 0.0, Entity.rightWidgetPadding, 0.0),
child: GestureDetector(
child: Text(
"${entityModel.entity.state}${entityModel.entity.unitOfMeasurement}",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: entityModel.entity.stateFontSize,
fontSize: Entity.stateFontSize,
)),
onTap: () => entityModel.handleTap
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity))
@ -94,7 +95,7 @@ class EntityName extends StatelessWidget {
"${entityModel.entity.displayName}",
overflow: TextOverflow.ellipsis,
softWrap: false,
style: TextStyle(fontSize: entityModel.entity.nameFontSize),
style: TextStyle(fontSize: Entity.nameFontSize),
),
),
onTap: () => entityModel.handleTap
@ -111,11 +112,11 @@ class EntityIcon extends StatelessWidget {
return GestureDetector(
child: Padding(
padding: EdgeInsets.fromLTRB(
entityModel.entity.leftWidgetPadding, 0.0, 12.0, 0.0),
Entity.leftWidgetPadding, 0.0, 12.0, 0.0),
//TODO: move createIconWidgetFromEntityData into this widget
child: MaterialDesignIcons.createIconWidgetFromEntityData(
entityModel.entity,
entityModel.entity.iconSize,
Entity.iconSize,
Entity.STATE_ICONS_COLORS[entityModel.entity.state] ??
Entity.STATE_ICONS_COLORS["default"]),
),
@ -132,12 +133,12 @@ class LastUpdatedWidget extends StatelessWidget {
final entityModel = EntityModel.of(context);
return Padding(
padding: EdgeInsets.fromLTRB(
entityModel.entity.leftWidgetPadding, 0.0, 0.0, 0.0),
Entity.leftWidgetPadding, 0.0, 0.0, 0.0),
child: Text(
'${entityModel.entity.lastUpdated}',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: entityModel.entity.smallFontSize, color: Colors.black26),
fontSize: Entity.smallFontSize, color: Colors.black26),
),
);
}
@ -153,14 +154,14 @@ class EntityAttributesList extends StatelessWidget {
if ((entityModel.entity.attributesToShow == null) ||
(entityModel.entity.attributesToShow.contains("all"))) {
entityModel.entity.attributes.forEach((name, value) {
attrs.add(_buildSingleAttribute(entityModel.entity, "$name", "$value"));
attrs.add(_buildSingleAttribute("$name", "$value"));
});
} else {
entityModel.entity.attributesToShow.forEach((String attr) {
String attrValue = entityModel.entity.getAttribute("$attr");
if (attrValue != null) {
attrs.add(
_buildSingleAttribute(entityModel.entity, "$attr", "$attrValue"));
_buildSingleAttribute("$attr", "$attrValue"));
}
});
}
@ -171,13 +172,13 @@ class EntityAttributesList extends StatelessWidget {
);
}
Widget _buildSingleAttribute(Entity entity, String name, String value) {
Widget _buildSingleAttribute(String name, String value) {
return Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(
entity.leftWidgetPadding, entity.rowPadding, 0.0, 0.0),
Entity.leftWidgetPadding, Entity.rowPadding, 0.0, 0.0),
child: Text(
"$name",
textAlign: TextAlign.left,
@ -187,7 +188,7 @@ class EntityAttributesList extends StatelessWidget {
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(
0.0, entity.rowPadding, entity.rightWidgetPadding, 0.0),
0.0, Entity.rowPadding, Entity.rightWidgetPadding, 0.0),
child: Text(
"$value",
textAlign: TextAlign.right,
@ -341,7 +342,7 @@ class ClimateStateWidget extends StatelessWidget {
}
return Padding(
padding: EdgeInsets.fromLTRB(
0.0, 0.0, entityModel.entity.rightWidgetPadding, 0.0),
0.0, 0.0, Entity.rightWidgetPadding, 0.0),
child: GestureDetector(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
@ -353,12 +354,12 @@ class ClimateStateWidget extends StatelessWidget {
textAlign: TextAlign.right,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: entityModel.entity.stateFontSize,
fontSize: Entity.stateFontSize,
)),
Text(" $targetTemp",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: entityModel.entity.stateFontSize,
fontSize: Entity.stateFontSize,
))
],
),
@ -366,7 +367,7 @@ class ClimateStateWidget extends StatelessWidget {
Text("Currently: ${entity.attributes["current_temperature"]}",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: entityModel.entity.stateFontSize,
fontSize: Entity.stateFontSize,
color: Colors.black45)
) :
Container(height: 0.0,)
@ -454,12 +455,12 @@ class DateTimeStateWidget extends StatelessWidget {
final entityModel = EntityModel.of(context);
final DateTimeEntity entity = entityModel.entity;
return Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, entity.rightWidgetPadding, 0.0),
padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.rightWidgetPadding, 0.0),
child: GestureDetector(
child: Text("${entity.formattedState}",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: entity.stateFontSize,
fontSize: Entity.stateFontSize,
)),
onTap: () => _handleStateTap(context, entity),
));
@ -547,36 +548,36 @@ class CoverEntityControlState extends StatelessWidget {
buttons.add(IconButton(
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-up"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: entity.canBeOpened ? () => _open(entity) : null));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
if (entity.supportStop) {
buttons.add(IconButton(
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: () => _stop(entity)));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
if (entity.supportClose) {
buttons.add(IconButton(
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-down"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: entity.canBeClosed ? () => _close(entity) : null));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
@ -612,24 +613,24 @@ class CoverEntityTiltControlButtons extends StatelessWidget {
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName(
"mdi:arrow-top-right"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: entity.canTiltBeOpened ? () => _open(entity) : null));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
if (entity.supportStopTilt) {
buttons.add(IconButton(
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: () => _stop(entity)));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
if (entity.supportCloseTilt) {
@ -637,12 +638,12 @@ class CoverEntityTiltControlButtons extends StatelessWidget {
icon: Icon(
MaterialDesignIcons.createIconDataFromIconName(
"mdi:arrow-bottom-left"),
size: entity.iconSize,
size: Entity.iconSize,
),
onPressed: entity.canTiltBeClosed ? () => _close(entity) : null));
} else {
buttons.add(Container(
width: entity.iconSize + 20.0,
width: Entity.iconSize + 20.0,
));
}
@ -651,3 +652,90 @@ class CoverEntityTiltControlButtons extends StatelessWidget {
);
}
}
class ModeSelectorWidget extends StatelessWidget {
final String caption;
final List<String> options;
final String value;
final double captionFontSize;
final double valueFontSize;
final double bottomPadding;
final onChange;
ModeSelectorWidget({
Key key,
this.caption,
@required this.options,
this.value,
@required this.onChange,
this.captionFontSize,
this.valueFontSize,
this.bottomPadding
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("$caption", style: TextStyle(
fontSize: captionFontSize ?? Entity.stateFontSize
)),
DropdownButton<String>(
value: "$value",
iconSize: 30.0,
style: TextStyle(
fontSize: valueFontSize ?? Entity.largeFontSize,
color: Colors.black,
),
items: options.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (mode) => onChange(mode),
),
Container(height: bottomPadding ?? Entity.rowPadding,)
],
);
}
}
class ModeSwitchWidget extends StatelessWidget {
final String caption;
final onChange;
final double captionFontSize;
final bool value;
ModeSwitchWidget({
Key key,
@required this.caption,
@required this.onChange,
this.captionFontSize,
this.value
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(
child: Text(
"$caption",
style: TextStyle(
fontSize: captionFontSize ?? Entity.stateFontSize
),
),
),
Switch(
onChanged: (value) => onChange(value),
value: value ?? false,
)
],
);
}
}