775 lines
22 KiB
Dart
775 lines
22 KiB
Dart
part of '../main.dart';
|
|
|
|
class EntityWidgetsSizes {}
|
|
|
|
class EntityModel extends InheritedWidget {
|
|
const EntityModel({
|
|
Key key,
|
|
@required this.entity,
|
|
@required this.handleTap,
|
|
@required Widget child,
|
|
}) : super(key: key, child: child);
|
|
|
|
final Entity entity;
|
|
final bool handleTap;
|
|
|
|
static EntityModel of(BuildContext context) {
|
|
return context.inheritFromWidgetOfExactType(EntityModel);
|
|
}
|
|
|
|
@override
|
|
bool updateShouldNotify(InheritedWidget oldWidget) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
return SizedBox(
|
|
height: height,
|
|
child: Row(
|
|
children: <Widget>[
|
|
EntityIcon(),
|
|
Expanded(
|
|
child: EntityName(),
|
|
),
|
|
state
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class EntityPageContainer extends StatelessWidget {
|
|
EntityPageContainer({Key key, @required this.children}) : super(key: key);
|
|
|
|
final List<Widget> children;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ListView(
|
|
children: children,
|
|
);
|
|
}
|
|
}
|
|
|
|
class SimpleEntityState extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
return Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
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: Entity.stateFontSize,
|
|
)),
|
|
onTap: () => entityModel.handleTap
|
|
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity))
|
|
: null,
|
|
));
|
|
}
|
|
}
|
|
|
|
class EntityName extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
return GestureDetector(
|
|
child: Padding(
|
|
padding: EdgeInsets.only(right: 10.0),
|
|
child: Text(
|
|
"${entityModel.entity.displayName}",
|
|
overflow: TextOverflow.ellipsis,
|
|
softWrap: false,
|
|
style: TextStyle(fontSize: Entity.nameFontSize),
|
|
),
|
|
),
|
|
onTap: () => entityModel.handleTap
|
|
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity))
|
|
: null,
|
|
);
|
|
}
|
|
}
|
|
|
|
class EntityIcon extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
return GestureDetector(
|
|
child: Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
Entity.leftWidgetPadding, 0.0, 12.0, 0.0),
|
|
//TODO: move createIconWidgetFromEntityData into this widget
|
|
child: MaterialDesignIcons.createIconWidgetFromEntityData(
|
|
entityModel.entity,
|
|
Entity.iconSize,
|
|
Entity.STATE_ICONS_COLORS[entityModel.entity.state] ??
|
|
Entity.STATE_ICONS_COLORS["default"]),
|
|
),
|
|
onTap: () => entityModel.handleTap
|
|
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity))
|
|
: null,
|
|
);
|
|
}
|
|
}
|
|
|
|
class LastUpdatedWidget extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
return Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
Entity.leftWidgetPadding, 0.0, 0.0, 0.0),
|
|
child: Text(
|
|
'${entityModel.entity.lastUpdated}',
|
|
textAlign: TextAlign.left,
|
|
style: TextStyle(
|
|
fontSize: Entity.smallFontSize, color: Colors.black26),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class EntityAttributesList extends StatelessWidget {
|
|
EntityAttributesList({Key key}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
List<Widget> attrs = [];
|
|
if ((entityModel.entity.attributesToShow == null) ||
|
|
(entityModel.entity.attributesToShow.contains("all"))) {
|
|
entityModel.entity.attributes.forEach((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("$attr", "$attrValue"));
|
|
}
|
|
});
|
|
}
|
|
return Column(
|
|
children: attrs,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
);
|
|
}
|
|
|
|
Widget _buildSingleAttribute(String name, String value) {
|
|
return Row(
|
|
children: <Widget>[
|
|
Expanded(
|
|
child: Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
Entity.leftWidgetPadding, Entity.rowPadding, 0.0, 0.0),
|
|
child: Text(
|
|
"$name",
|
|
textAlign: TextAlign.left,
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
0.0, Entity.rowPadding, Entity.rightWidgetPadding, 0.0),
|
|
child: Text(
|
|
"$value",
|
|
textAlign: TextAlign.right,
|
|
),
|
|
),
|
|
)
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class Badge extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
double iconSize = 26.0;
|
|
Widget badgeIcon;
|
|
String onBadgeTextValue;
|
|
Color iconColor = Entity.badgeColors[entityModel.entity.domain] ??
|
|
Entity.badgeColors["default"];
|
|
switch (entityModel.entity.domain) {
|
|
case "sun":
|
|
{
|
|
badgeIcon = entityModel.entity.state == "below_horizon"
|
|
? Icon(
|
|
MaterialDesignIcons.createIconDataFromIconCode(0xf0dc),
|
|
size: iconSize,
|
|
)
|
|
: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconCode(0xf5a8),
|
|
size: iconSize,
|
|
);
|
|
break;
|
|
}
|
|
case "sensor":
|
|
{
|
|
onBadgeTextValue = entityModel.entity.unitOfMeasurement;
|
|
badgeIcon = Center(
|
|
child: Text(
|
|
"${entityModel.entity.state}",
|
|
overflow: TextOverflow.fade,
|
|
softWrap: false,
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(fontSize: 17.0),
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
case "device_tracker":
|
|
{
|
|
badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData(
|
|
entityModel.entity, iconSize, Colors.black);
|
|
onBadgeTextValue = entityModel.entity.state;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
badgeIcon = MaterialDesignIcons.createIconWidgetFromEntityData(
|
|
entityModel.entity, iconSize, Colors.black);
|
|
}
|
|
}
|
|
Widget onBadgeText;
|
|
if (onBadgeTextValue == null || onBadgeTextValue.length == 0) {
|
|
onBadgeText = Container(width: 0.0, height: 0.0);
|
|
} else {
|
|
onBadgeText = Container(
|
|
padding: EdgeInsets.fromLTRB(6.0, 2.0, 6.0, 2.0),
|
|
child: Text("$onBadgeTextValue",
|
|
style: TextStyle(fontSize: 12.0, color: Colors.white),
|
|
textAlign: TextAlign.center,
|
|
softWrap: false,
|
|
overflow: TextOverflow.fade),
|
|
decoration: new BoxDecoration(
|
|
// Circle shape
|
|
//shape: BoxShape.circle,
|
|
color: iconColor,
|
|
borderRadius: BorderRadius.circular(9.0),
|
|
));
|
|
}
|
|
return GestureDetector(
|
|
child: Column(
|
|
children: <Widget>[
|
|
Container(
|
|
margin: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
|
|
width: 50.0,
|
|
height: 50.0,
|
|
decoration: new BoxDecoration(
|
|
// Circle shape
|
|
shape: BoxShape.circle,
|
|
color: Colors.white,
|
|
// The border you want
|
|
border: new Border.all(
|
|
width: 2.0,
|
|
color: iconColor,
|
|
),
|
|
),
|
|
child: Stack(
|
|
overflow: Overflow.visible,
|
|
children: <Widget>[
|
|
Positioned(
|
|
width: 46.0,
|
|
height: 46.0,
|
|
top: 0.0,
|
|
left: 0.0,
|
|
child: badgeIcon,
|
|
),
|
|
Positioned(
|
|
//width: 50.0,
|
|
bottom: -9.0,
|
|
left: -10.0,
|
|
right: -10.0,
|
|
child: Center(
|
|
child: onBadgeText,
|
|
))
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
width: 60.0,
|
|
child: Text(
|
|
"${entityModel.entity.displayName}",
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(fontSize: 12.0),
|
|
softWrap: true,
|
|
maxLines: 3,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
onTap: () =>
|
|
eventBus.fire(new ShowEntityPageEvent(entityModel.entity)));
|
|
}
|
|
}
|
|
|
|
class ClimateStateWidget extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
final ClimateEntity entity = entityModel.entity;
|
|
String targetTemp = "-";
|
|
if ((entity.supportTargetTemperature) && (entity.temperature != null)) {
|
|
targetTemp = "${entity.temperature}";
|
|
} else if ((entity.supportTargetTemperatureLow) &&
|
|
(entity.targetLow != null)) {
|
|
targetTemp = "${entity.targetLow}";
|
|
if ((entity.supportTargetTemperatureHigh) &&
|
|
(entity.targetHigh != null)) {
|
|
targetTemp += " - ${entity.targetHigh}";
|
|
}
|
|
}
|
|
return Padding(
|
|
padding: EdgeInsets.fromLTRB(
|
|
0.0, 0.0, Entity.rightWidgetPadding, 0.0),
|
|
child: GestureDetector(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
Row(
|
|
children: <Widget>[
|
|
Text("${entity.state}",
|
|
textAlign: TextAlign.right,
|
|
style: new TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
fontSize: Entity.stateFontSize,
|
|
)),
|
|
Text(" $targetTemp",
|
|
textAlign: TextAlign.right,
|
|
style: new TextStyle(
|
|
fontSize: Entity.stateFontSize,
|
|
))
|
|
],
|
|
),
|
|
entity.attributes["current_temperature"] != null ?
|
|
Text("Currently: ${entity.attributes["current_temperature"]}",
|
|
textAlign: TextAlign.right,
|
|
style: new TextStyle(
|
|
fontSize: Entity.stateFontSize,
|
|
color: Colors.black45)
|
|
) :
|
|
Container(height: 0.0,)
|
|
],
|
|
),
|
|
onTap: () => entityModel.handleTap
|
|
? eventBus.fire(new ShowEntityPageEvent(entity))
|
|
: null,
|
|
));
|
|
}
|
|
}
|
|
|
|
class TemperatureControlWidget extends StatelessWidget {
|
|
final double value;
|
|
final double fontSize;
|
|
final Color fontColor;
|
|
final onSmallInc;
|
|
final onLargeInc;
|
|
final onSmallDec;
|
|
final onLargeDec;
|
|
|
|
TemperatureControlWidget(
|
|
{Key key,
|
|
@required this.value,
|
|
@required this.onSmallInc,
|
|
@required this.onSmallDec,
|
|
@required this.onLargeInc,
|
|
@required this.onLargeDec,
|
|
this.fontSize,
|
|
this.fontColor})
|
|
: super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: <Widget>[
|
|
Text(
|
|
"$value",
|
|
style: TextStyle(
|
|
fontSize: fontSize ?? 24.0,
|
|
color: fontColor ?? Colors.black
|
|
),
|
|
),
|
|
Column(
|
|
children: <Widget>[
|
|
IconButton(
|
|
icon: Icon(MaterialDesignIcons.createIconDataFromIconName(
|
|
'mdi:chevron-up')),
|
|
iconSize: 30.0,
|
|
onPressed: () => onSmallInc(),
|
|
),
|
|
IconButton(
|
|
icon: Icon(MaterialDesignIcons.createIconDataFromIconName(
|
|
'mdi:chevron-down')),
|
|
iconSize: 30.0,
|
|
onPressed: () => onSmallDec(),
|
|
)
|
|
],
|
|
),
|
|
Column(
|
|
children: <Widget>[
|
|
IconButton(
|
|
icon: Icon(MaterialDesignIcons.createIconDataFromIconName(
|
|
'mdi:chevron-double-up')),
|
|
iconSize: 30.0,
|
|
onPressed: () => onLargeInc(),
|
|
),
|
|
IconButton(
|
|
icon: Icon(MaterialDesignIcons.createIconDataFromIconName(
|
|
'mdi:chevron-double-down')),
|
|
iconSize: 30.0,
|
|
onPressed: () => onLargeDec(),
|
|
)
|
|
],
|
|
)
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class DateTimeStateWidget extends StatelessWidget {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
final DateTimeEntity entity = entityModel.entity;
|
|
return Padding(
|
|
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,
|
|
)),
|
|
onTap: () => _handleStateTap(context, entity),
|
|
));
|
|
}
|
|
|
|
void _handleStateTap(BuildContext context, DateTimeEntity entity) {
|
|
if (entity.hasDate) {
|
|
_showDatePicker(context, entity).then((date) {
|
|
if (date != null) {
|
|
if (entity.hasTime) {
|
|
_showTimePicker(context, entity).then((time) {
|
|
entity.setNewState({
|
|
"date": "${formatDate(date, [yyyy, '-', mm, '-', dd])}",
|
|
"time":
|
|
"${formatDate(DateTime(1970, 1, 1, time.hour, time.minute), [
|
|
HH,
|
|
':',
|
|
nn
|
|
])}"
|
|
});
|
|
});
|
|
} else {
|
|
entity.setNewState({
|
|
"date": "${formatDate(date, [yyyy, '-', mm, '-', dd])}"
|
|
});
|
|
}
|
|
}
|
|
});
|
|
} else if (entity.hasTime) {
|
|
_showTimePicker(context, entity).then((time) {
|
|
if (time != null) {
|
|
entity.setNewState({
|
|
"time":
|
|
"${formatDate(DateTime(1970, 1, 1, time.hour, time.minute), [
|
|
HH,
|
|
':',
|
|
nn
|
|
])}"
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
TheLogger.log("Warning", "${entity.entityId} has no date and no time");
|
|
}
|
|
}
|
|
|
|
Future _showDatePicker(BuildContext context, DateTimeEntity entity) {
|
|
return showDatePicker(
|
|
context: context,
|
|
initialDate: entity.dateTimeState,
|
|
firstDate: DateTime(1970),
|
|
lastDate: DateTime(2037) //Unix timestamp will finish at Jan 19, 2038
|
|
);
|
|
}
|
|
|
|
Future _showTimePicker(BuildContext context, DateTimeEntity entity) {
|
|
return showTimePicker(
|
|
context: context,
|
|
initialTime: TimeOfDay.fromDateTime(entity.dateTimeState));
|
|
}
|
|
}
|
|
|
|
class CoverEntityControlState extends StatelessWidget {
|
|
void _open(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "open_cover", entity.entityId, null));
|
|
}
|
|
|
|
void _close(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "close_cover", entity.entityId, null));
|
|
}
|
|
|
|
void _stop(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "stop_cover", entity.entityId, null));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
final CoverEntity entity = entityModel.entity;
|
|
List<Widget> buttons = [];
|
|
if (entity.supportOpen) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-up"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: entity.canBeOpened ? () => _open(entity) : null));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
if (entity.supportStop) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: () => _stop(entity)));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
if (entity.supportClose) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-down"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: entity.canBeClosed ? () => _close(entity) : null));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
|
|
return Row(
|
|
children: buttons,
|
|
);
|
|
}
|
|
}
|
|
|
|
class CoverEntityTiltControlButtons extends StatelessWidget {
|
|
void _open(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "open_cover_tilt", entity.entityId, null));
|
|
}
|
|
|
|
void _close(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "close_cover_tilt", entity.entityId, null));
|
|
}
|
|
|
|
void _stop(CoverEntity entity) {
|
|
eventBus.fire(new ServiceCallEvent(
|
|
entity.domain, "stop_cover_tilt", entity.entityId, null));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final entityModel = EntityModel.of(context);
|
|
final CoverEntity entity = entityModel.entity;
|
|
List<Widget> buttons = [];
|
|
if (entity.supportOpenTilt) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName(
|
|
"mdi:arrow-top-right"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: entity.canTiltBeOpened ? () => _open(entity) : null));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
if (entity.supportStopTilt) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: () => _stop(entity)));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
if (entity.supportCloseTilt) {
|
|
buttons.add(IconButton(
|
|
icon: Icon(
|
|
MaterialDesignIcons.createIconDataFromIconName(
|
|
"mdi:arrow-bottom-left"),
|
|
size: Entity.iconSize,
|
|
),
|
|
onPressed: entity.canTiltBeClosed ? () => _close(entity) : null));
|
|
} else {
|
|
buttons.add(Container(
|
|
width: Entity.iconSize + 20.0,
|
|
));
|
|
}
|
|
|
|
return Row(
|
|
children: buttons,
|
|
);
|
|
}
|
|
}
|
|
|
|
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;
|
|
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
|
|
)),
|
|
Row(
|
|
children: <Widget>[
|
|
Expanded(
|
|
child: ButtonTheme(
|
|
alignedDropdown: true,
|
|
child: DropdownButton<String>(
|
|
value: value,
|
|
iconSize: 30.0,
|
|
isExpanded: true,
|
|
style: TextStyle(
|
|
fontSize: valueFontSize ?? Entity.largeFontSize,
|
|
color: Colors.black,
|
|
),
|
|
hint: Text("Select ${caption.toLowerCase()}"),
|
|
items: options.map((String value) {
|
|
return new DropdownMenuItem<String>(
|
|
value: value,
|
|
child: 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,
|
|
)
|
|
],
|
|
);
|
|
}
|
|
|
|
} |