Some improvements

This commit is contained in:
Yegor Vialov 2018-11-12 20:28:10 +02:00
parent 0a7bbb5a38
commit 01090dc3b1
27 changed files with 263 additions and 213 deletions

View File

@ -16,17 +16,6 @@ class Entity {
"sensor" "sensor"
]; ];
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;
Map attributes; Map attributes;
String domain; String domain;
String entityId; String entityId;

View File

@ -174,7 +174,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
_resetVars(entity); _resetVars(entity);
} }
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, 0.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
@ -273,7 +273,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text("Target temperature", style: TextStyle( Text("Target temperature", style: TextStyle(
fontSize: Entity.stateFontSize fontSize: Sizes.stateFontSize
)), )),
TemperatureControlWidget( TemperatureControlWidget(
value: _tmpTemperature, value: _tmpTemperature,
@ -324,7 +324,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text("Target temperature range", style: TextStyle( Text("Target temperature range", style: TextStyle(
fontSize: Entity.stateFontSize fontSize: Sizes.stateFontSize
)), )),
Row( Row(
children: controls, children: controls,
@ -342,7 +342,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
result.addAll(<Widget>[ result.addAll(<Widget>[
Text( Text(
"$_tmpTargetHumidity%", "$_tmpTargetHumidity%",
style: TextStyle(fontSize: Entity.largeFontSize), style: TextStyle(fontSize: Sizes.largeFontSize),
), ),
Expanded( Expanded(
child: Slider( child: Slider(
@ -366,9 +366,9 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
0.0, Entity.rowPadding, 0.0, Entity.rowPadding), 0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: Text("Target humidity", style: TextStyle( child: Text("Target humidity", style: TextStyle(
fontSize: Entity.stateFontSize fontSize: Sizes.stateFontSize
)), )),
), ),
Row( Row(
@ -376,7 +376,7 @@ class _ClimateControlWidgetState extends State<ClimateControlWidget> {
children: result, children: result,
), ),
Container( Container(
height: Entity.rowPadding, height: Sizes.rowPadding,
) )
], ],
); );

View File

@ -45,7 +45,7 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
_resetVars(entity); _resetVars(entity);
} }
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, 0.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
@ -63,9 +63,9 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
children: <Widget>[ children: <Widget>[
Padding( Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
0.0, Entity.rowPadding, 0.0, Entity.rowPadding), 0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: Text("Position", style: TextStyle( child: Text("Position", style: TextStyle(
fontSize: Entity.stateFontSize fontSize: Sizes.stateFontSize
)), )),
), ),
Slider( Slider(
@ -81,7 +81,7 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
}, },
onChangeEnd: (double value) => _setNewPosition(entity, value), onChangeEnd: (double value) => _setNewPosition(entity, value),
), ),
Container(height: Entity.rowPadding,) Container(height: Sizes.rowPadding,)
], ],
); );
} else { } else {
@ -111,15 +111,15 @@ class _CoverControlWidgetState extends State<CoverControlWidget> {
}, },
onChangeEnd: (double value) => _setNewTiltPosition(entity, value), onChangeEnd: (double value) => _setNewTiltPosition(entity, value),
), ),
Container(height: Entity.rowPadding,) Container(height: Sizes.rowPadding,)
]); ]);
} }
if (controls.isNotEmpty) { if (controls.isNotEmpty) {
controls.insert(0, Padding( controls.insert(0, Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
0.0, Entity.rowPadding, 0.0, Entity.rowPadding), 0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: Text("Tilt position", style: TextStyle( child: Text("Tilt position", style: TextStyle(
fontSize: Entity.stateFontSize fontSize: Sizes.stateFontSize
)), )),
)); ));
return Column( return Column(
@ -159,24 +159,24 @@ class CoverTiltControlsWidget extends StatelessWidget {
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName( MaterialDesignIcons.createIconDataFromIconName(
"mdi:arrow-top-right"), "mdi:arrow-top-right"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: entity.canTiltBeOpened ? () => _open(entity) : null)); onPressed: entity.canTiltBeOpened ? () => _open(entity) : null));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }
if (entity.supportStopTilt) { if (entity.supportStopTilt) {
buttons.add(IconButton( buttons.add(IconButton(
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"), MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: () => _stop(entity))); onPressed: () => _stop(entity)));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }
if (entity.supportCloseTilt) { if (entity.supportCloseTilt) {
@ -184,12 +184,12 @@ class CoverTiltControlsWidget extends StatelessWidget {
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName( MaterialDesignIcons.createIconDataFromIconName(
"mdi:arrow-bottom-left"), "mdi:arrow-bottom-left"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: entity.canTiltBeClosed ? () => _close(entity) : null)); onPressed: entity.canTiltBeClosed ? () => _close(entity) : null));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }

View File

@ -102,12 +102,12 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Container(height: Entity.rowPadding,), Container(height: Sizes.rowPadding,),
Text( Text(
"Brightness", "Brightness",
style: TextStyle(fontSize: Entity.stateFontSize), style: TextStyle(fontSize: Sizes.stateFontSize),
), ),
Container(height: Entity.rowPadding,), Container(height: Sizes.rowPadding,),
Row( Row(
children: <Widget>[ children: <Widget>[
Icon(Icons.brightness_5), Icon(Icons.brightness_5),
@ -127,7 +127,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
) )
], ],
), ),
Container(height: Entity.rowPadding,) Container(height: Sizes.rowPadding,)
], ],
); );
} else { } else {
@ -140,12 +140,12 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Container(height: Entity.rowPadding,), Container(height: Sizes.rowPadding,),
Text( Text(
"Color temperature", "Color temperature",
style: TextStyle(fontSize: Entity.stateFontSize), style: TextStyle(fontSize: Sizes.stateFontSize),
), ),
Container(height: Entity.rowPadding,), Container(height: Sizes.rowPadding,),
Row( Row(
children: <Widget>[ children: <Widget>[
Text("Cold", style: TextStyle(color: Colors.lightBlue),), Text("Cold", style: TextStyle(color: Colors.lightBlue),),
@ -166,7 +166,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
Text("Warm", style: TextStyle(color: Colors.amberAccent),), Text("Warm", style: TextStyle(color: Colors.amberAccent),),
], ],
), ),
Container(height: Entity.rowPadding,) Container(height: Sizes.rowPadding,)
], ],
); );
} else { } else {
@ -179,7 +179,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Container(height: Entity.rowPadding,), Container(height: Sizes.rowPadding,),
RaisedButton( RaisedButton(
onPressed: () => _showColorPicker(entity), onPressed: () => _showColorPicker(entity),
color: _tmpColor ?? Colors.black45, color: _tmpColor ?? Colors.black45,
@ -193,7 +193,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
), ),
), ),
), ),
Container(height: 2*Entity.rowPadding,), Container(height: 2*Sizes.rowPadding,),
], ],
); );
} else { } else {

View File

@ -0,0 +1,155 @@
part of '../../main.dart';
class MediaPlayerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final EntityModel entityModel = EntityModel.of(context);
final MediaPlayerEntity entity = entityModel.entity;
List<Widget> body = [];
body.add(Stack(
alignment: AlignmentDirectional.topEnd,
children: <Widget>[
_buildImage(entity),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: Container(
color: Colors.black45,
child: _buildState(entity),
),
),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: MediaPlayerProgressWidget()
)
],
));
return Column(
children: body
);
}
Widget _buildState(MediaPlayerEntity entity) {
TextStyle style = TextStyle(
fontSize: 14.0,
color: Colors.white,
fontWeight: FontWeight.normal,
height: 1.2
);
List<Widget> states = [];
states.add(Text("${entity.displayName}", style: style));
String state = entity.state;
if (state == null || state == "off" || state == "unavailable" || state == "idle") {
states.add(Text("${entity.state}", style: style.apply(fontSizeDelta: 4.0),));
}
if (entity.attributes['media_title'] != null) {
states.add(Text("${entity.attributes['media_title']}", style: style.apply(fontSizeDelta: 6.0, fontWeightDelta: 50),));
}
if (entity.attributes['media_content_type'] == "music") {
states.add(Text("${entity.attributes['media_artist'] ?? entity.attributes['app_name']}", style: style.apply(fontSizeDelta: 4.0),));
} else if (entity.attributes['app_name'] != null) {
states.add(Text("${entity.attributes['app_name']}", style: style.apply(fontSizeDelta: 4.0),));
}
return Padding(
padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: states,
),
);
}
Widget _buildImage(MediaPlayerEntity entity) {
String state = entity.state;
if (homeAssistantWebHost != null && entity.entityPicture != null && state != "off" && state != "unavailable" && state != "idle") {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image: CachedNetworkImageProvider("$homeAssistantWebHost${entity.entityPicture}"),
height: 240.0,
width: 320.0,
fit: BoxFit.fitHeight,
)
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:movie"),
size: 150.0,
color: EntityColors.stateColor("$state"),
)
],
);
/*return Container(
color: Colors.blue,
height: 80.0,
);*/
}
}
}
class MediaPlayerProgressWidget extends StatefulWidget {
@override
_MediaPlayerProgressWidgetState createState() => _MediaPlayerProgressWidgetState();
}
class _MediaPlayerProgressWidgetState extends State<MediaPlayerProgressWidget> {
Timer _timer;
@override
Widget build(BuildContext context) {
final EntityModel entityModel = EntityModel.of(context);
final MediaPlayerEntity entity = entityModel.entity;
double progress;
try {
DateTime lastUpdated = DateTime.parse(
entity.attributes["media_position_updated_at"]).toLocal();
Duration duration = Duration(seconds: entity._getIntAttributeValue("media_duration") ?? 1);
Duration position = Duration(seconds: entity._getIntAttributeValue("media_position") ?? 0);
int currentPosition = position.inSeconds;
if (entity.state == "playing") {
_timer?.cancel();
_timer = Timer(Duration(seconds: 1), () {
setState(() {
});
});
int differenceInSeconds = DateTime
.now()
.difference(lastUpdated)
.inSeconds;
currentPosition = currentPosition + differenceInSeconds;
} else {
_timer?.cancel();
}
progress = currentPosition / duration.inSeconds;
return LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black45,
valueColor: AlwaysStoppedAnimation<Color>(EntityColors.stateColor("on")),
);
} catch (e) {
_timer?.cancel();
progress = 0.0;
}
return LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black45,
);
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
}

View File

@ -34,7 +34,7 @@ class EntityAttributesList extends StatelessWidget {
Expanded( Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
Entity.leftWidgetPadding, Entity.rowPadding, 0.0, 0.0), Sizes.leftWidgetPadding, Sizes.rowPadding, 0.0, 0.0),
child: Text( child: Text(
"$name", "$name",
textAlign: TextAlign.left, textAlign: TextAlign.left,
@ -44,7 +44,7 @@ class EntityAttributesList extends StatelessWidget {
Expanded( Expanded(
child: Padding( child: Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
0.0, Entity.rowPadding, Entity.rightWidgetPadding, 0.0), 0.0, Sizes.rowPadding, Sizes.rightWidgetPadding, 0.0),
child: Text( child: Text(
"$value", "$value",
textAlign: TextAlign.right, textAlign: TextAlign.right,

View File

@ -7,10 +7,10 @@ class EntityIcon extends StatelessWidget {
return GestureDetector( return GestureDetector(
child: Padding( child: Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
Entity.leftWidgetPadding, 0.0, 12.0, 0.0), Sizes.leftWidgetPadding, 0.0, 12.0, 0.0),
child: MaterialDesignIcons.createIconWidgetFromEntityData( child: MaterialDesignIcons.createIconWidgetFromEntityData(
entityModel.entity, entityModel.entity,
Entity.iconSize, Sizes.iconSize,
EntityColors.stateColor(entityModel.entity.state) EntityColors.stateColor(entityModel.entity.state)
), ),
), ),

View File

@ -11,7 +11,7 @@ class EntityName extends StatelessWidget {
"${entityModel.entity.displayName}", "${entityModel.entity.displayName}",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: false, softWrap: false,
style: TextStyle(fontSize: Entity.nameFontSize), style: TextStyle(fontSize: Sizes.nameFontSize),
), ),
), ),
onTap: () => onTap: () =>

View File

@ -69,7 +69,7 @@ class _CombinedHistoryChartWidgetState extends State<CombinedHistoryChartWidget>
selectionModels: [ selectionModels: [
new charts.SelectionModelConfig( new charts.SelectionModelConfig(
type: charts.SelectionModelType.info, type: charts.SelectionModelType.info,
listener: (model) => _onSelectionChanged(model), changedListener: (model) => _onSelectionChanged(model),
) )
], ],
customSeriesRenderers: [ customSeriesRenderers: [

View File

@ -83,7 +83,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
} }
children.add(Divider()); children.add(Divider());
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, Entity.rowPadding), padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, Sizes.rowPadding),
child: Column( child: Column(
children: children, children: children,
), ),

View File

@ -57,7 +57,7 @@ class _NumericStateHistoryChartWidgetState extends State<NumericStateHistoryChar
selectionModels: [ selectionModels: [
new charts.SelectionModelConfig( new charts.SelectionModelConfig(
type: charts.SelectionModelType.info, type: charts.SelectionModelType.info,
listener: (model) => _onSelectionChanged(model), changedListener: (model) => _onSelectionChanged(model),
) )
], ],
), ),

View File

@ -53,7 +53,7 @@ class _SimpleStateHistoryChartWidgetState extends State<SimpleStateHistoryChartW
selectionModels: [ selectionModels: [
new charts.SelectionModelConfig( new charts.SelectionModelConfig(
type: charts.SelectionModelType.info, type: charts.SelectionModelType.info,
listener: (model) => _onSelectionChanged(model), changedListener: (model) => _onSelectionChanged(model),
) )
], ],
customSeriesRenderers: [ customSeriesRenderers: [

View File

@ -6,12 +6,12 @@ class LastUpdatedWidget extends StatelessWidget {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
return Padding( return Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
Entity.leftWidgetPadding, 0.0, 0.0, 0.0), Sizes.leftWidgetPadding, 0.0, 0.0, 0.0),
child: Text( child: Text(
'${entityModel.entity.lastUpdated}', '${entityModel.entity.lastUpdated}',
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: TextStyle( style: TextStyle(
fontSize: Entity.smallFontSize, color: Colors.black26), fontSize: Sizes.smallFontSize, color: Colors.black26),
), ),
); );
} }

View File

@ -27,7 +27,7 @@ class ModeSelectorWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text("$caption", style: TextStyle( Text("$caption", style: TextStyle(
fontSize: captionFontSize ?? Entity.stateFontSize fontSize: captionFontSize ?? Sizes.stateFontSize
)), )),
Row( Row(
children: <Widget>[ children: <Widget>[
@ -39,7 +39,7 @@ class ModeSelectorWidget extends StatelessWidget {
iconSize: 30.0, iconSize: 30.0,
isExpanded: true, isExpanded: true,
style: TextStyle( style: TextStyle(
fontSize: valueFontSize ?? Entity.largeFontSize, fontSize: valueFontSize ?? Sizes.largeFontSize,
color: Colors.black, color: Colors.black,
), ),
hint: Text("Select ${caption.toLowerCase()}"), hint: Text("Select ${caption.toLowerCase()}"),
@ -55,7 +55,7 @@ class ModeSelectorWidget extends StatelessWidget {
) )
], ],
), ),
Container(height: bottomPadding ?? Entity.rowPadding,) Container(height: bottomPadding ?? Sizes.rowPadding,)
], ],
); );
} }

View File

@ -23,7 +23,7 @@ class ModeSwitchWidget extends StatelessWidget {
child: Text( child: Text(
"$caption", "$caption",
style: TextStyle( style: TextStyle(
fontSize: captionFontSize ?? Entity.stateFontSize fontSize: captionFontSize ?? Sizes.stateFontSize
), ),
), ),
), ),

View File

@ -19,7 +19,7 @@ class ButtonStateWidget extends StatelessWidget {
"EXECUTE", "EXECUTE",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: style:
new TextStyle(fontSize: Entity.stateFontSize, color: Colors.blue), new TextStyle(fontSize: Sizes.stateFontSize, color: Colors.blue),
), ),
) )
); );

View File

@ -18,7 +18,7 @@ class ClimateStateWidget extends StatelessWidget {
} }
return Padding( return Padding(
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
0.0, 0.0, Entity.rightWidgetPadding, 0.0), 0.0, 0.0, Sizes.rightWidgetPadding, 0.0),
child: GestureDetector( child: GestureDetector(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
@ -30,12 +30,12 @@ class ClimateStateWidget extends StatelessWidget {
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: new TextStyle( style: new TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: Entity.stateFontSize, fontSize: Sizes.stateFontSize,
)), )),
Text(" $targetTemp", Text(" $targetTemp",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: new TextStyle( style: new TextStyle(
fontSize: Entity.stateFontSize, fontSize: Sizes.stateFontSize,
)) ))
], ],
), ),
@ -43,7 +43,7 @@ class ClimateStateWidget extends StatelessWidget {
Text("Currently: ${entity.attributes["current_temperature"]}", Text("Currently: ${entity.attributes["current_temperature"]}",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: new TextStyle( style: new TextStyle(
fontSize: Entity.stateFontSize, fontSize: Sizes.stateFontSize,
color: Colors.black45) color: Colors.black45)
) : ) :
Container(height: 0.0,) Container(height: 0.0,)

View File

@ -25,36 +25,36 @@ class CoverStateWidget extends StatelessWidget {
buttons.add(IconButton( buttons.add(IconButton(
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-up"), MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-up"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: entity.canBeOpened ? () => _open(entity) : null)); onPressed: entity.canBeOpened ? () => _open(entity) : null));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }
if (entity.supportStop) { if (entity.supportStop) {
buttons.add(IconButton( buttons.add(IconButton(
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:stop"), MaterialDesignIcons.createIconDataFromIconName("mdi:stop"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: () => _stop(entity))); onPressed: () => _stop(entity)));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }
if (entity.supportClose) { if (entity.supportClose) {
buttons.add(IconButton( buttons.add(IconButton(
icon: Icon( icon: Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-down"), MaterialDesignIcons.createIconDataFromIconName("mdi:arrow-down"),
size: Entity.iconSize, size: Sizes.iconSize,
), ),
onPressed: entity.canBeClosed ? () => _close(entity) : null)); onPressed: entity.canBeClosed ? () => _close(entity) : null));
} else { } else {
buttons.add(Container( buttons.add(Container(
width: Entity.iconSize + 20.0, width: Sizes.iconSize + 20.0,
)); ));
} }

View File

@ -6,12 +6,12 @@ class DateTimeStateWidget extends StatelessWidget {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
final DateTimeEntity entity = entityModel.entity; final DateTimeEntity entity = entityModel.entity;
return Padding( return Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.rightWidgetPadding, 0.0), padding: EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0),
child: GestureDetector( child: GestureDetector(
child: Text("${entity.formattedState}", child: Text("${entity.formattedState}",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: new TextStyle( style: new TextStyle(
fontSize: Entity.stateFontSize, fontSize: Sizes.stateFontSize,
)), )),
onTap: () => _handleStateTap(context, entity), onTap: () => _handleStateTap(context, entity),
)); ));

View File

@ -10,13 +10,13 @@ class SimpleEntityState extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final entityModel = EntityModel.of(context); final entityModel = EntityModel.of(context);
Widget result = Padding( Widget result = Padding(
padding: EdgeInsets.fromLTRB(0.0, 0.0, Entity.rightWidgetPadding, 0.0), padding: EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0),
child: GestureDetector( child: GestureDetector(
child: Text( child: Text(
"${entityModel.entity.state}${entityModel.entity.unitOfMeasurement}", "${entityModel.entity.state}${entityModel.entity.unitOfMeasurement}",
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: new TextStyle( style: new TextStyle(
fontSize: Entity.stateFontSize, fontSize: Sizes.stateFontSize,
)), )),
onTap: () => entityModel.handleTap onTap: () => entityModel.handleTap
? eventBus.fire(new ShowEntityPageEvent(entityModel.entity)) ? eventBus.fire(new ShowEntityPageEvent(entityModel.entity))

View File

@ -52,13 +52,13 @@ class _SwitchStateWidgetState extends State<SwitchStateWidget> {
onPressed: () => _setNewState(false, entity), onPressed: () => _setNewState(false, entity),
icon: Icon(MaterialDesignIcons.createIconDataFromIconName("mdi:flash-off")), icon: Icon(MaterialDesignIcons.createIconDataFromIconName("mdi:flash-off")),
color: entity.assumedState == 'on' ? Colors.black : Colors.blue, color: entity.assumedState == 'on' ? Colors.black : Colors.blue,
iconSize: Entity.iconSize, iconSize: Sizes.iconSize,
), ),
IconButton( IconButton(
onPressed: () => _setNewState(true, entity), onPressed: () => _setNewState(true, entity),
icon: Icon(MaterialDesignIcons.createIconDataFromIconName("mdi:flash")), icon: Icon(MaterialDesignIcons.createIconDataFromIconName("mdi:flash")),
color: entity.assumedState == 'on' ? Colors.blue : Colors.black, color: entity.assumedState == 'on' ? Colors.blue : Colors.black,
iconSize: Entity.iconSize iconSize: Sizes.iconSize
) )
], ],
), ),

View File

@ -56,6 +56,7 @@ part 'entity_widgets/state/button_state.dart';
part 'entity_widgets/controls/climate_controls.dart'; part 'entity_widgets/controls/climate_controls.dart';
part 'entity_widgets/controls/cover_controls.dart'; part 'entity_widgets/controls/cover_controls.dart';
part 'entity_widgets/controls/light_controls.dart'; part 'entity_widgets/controls/light_controls.dart';
part 'entity_widgets/controls/media_player_widget.dart';
part 'settings.page.dart'; part 'settings.page.dart';
part 'home_assistant.class.dart'; part 'home_assistant.class.dart';
part 'log.page.dart'; part 'log.page.dart';
@ -66,6 +67,7 @@ part 'entity_collection.class.dart';
part 'ui_class/ui.dart'; part 'ui_class/ui.dart';
part 'ui_class/view.class.dart'; part 'ui_class/view.class.dart';
part 'ui_class/card.class.dart'; part 'ui_class/card.class.dart';
part 'ui_class/sizes_class.dart';
part 'ui_widgets/view.dart'; part 'ui_widgets/view.dart';
part 'ui_widgets/entities_card.dart'; part 'ui_widgets/entities_card.dart';
part 'ui_widgets/unsupported_card.dart'; part 'ui_widgets/unsupported_card.dart';

View File

@ -0,0 +1,14 @@
part of '../main.dart';
class Sizes {
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;
}

View File

@ -14,126 +14,16 @@ class MediaControlCardWidget extends StatelessWidget {
if ((card.linkedEntity == null) || (card.linkedEntity.isHidden)) { if ((card.linkedEntity == null) || (card.linkedEntity.isHidden)) {
return Container(width: 0.0, height: 0.0,); return Container(width: 0.0, height: 0.0,);
} }
List<Widget> body = [];
body.add(Stack(
alignment: AlignmentDirectional.topEnd,
children: <Widget>[
_buildImage(),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: Container(
color: Colors.black45,
child: _buildState(),
),
),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: _buildProgress(),
)
],
));
return Card( return Card(
child: Column( child: EntityModel(
//crossAxisAlignment: CrossAxisAlignment.center, entity: card.linkedEntity,
children: body handleTap: null,
child: MediaPlayerWidget()
) )
); );
} }
Widget _buildProgress() {
double progress;
try {
DateTime lastUpdated = DateTime.parse(
card.linkedEntity.attributes["media_position_updated_at"]).toLocal();
Duration duration = Duration(seconds: card.linkedEntity._getIntAttributeValue("media_duration") ?? 1);
Duration position = Duration(seconds: card.linkedEntity._getIntAttributeValue("media_position") ?? 0);
int currentPosition = position.inSeconds;
if (card.linkedEntity.state == "playing") {
int differenceInSeconds = DateTime
.now()
.difference(lastUpdated)
.inSeconds;
currentPosition = currentPosition + differenceInSeconds;
}
progress = currentPosition / duration.inSeconds;
return LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black45,
valueColor: AlwaysStoppedAnimation<Color>(EntityColors.stateColor("on")),
);
} catch (e) {
progress = 0.0;
}
return LinearProgressIndicator(
value: progress,
backgroundColor: Colors.black45,
);
}
Widget _buildState() {
TextStyle style = TextStyle(
fontSize: 14.0,
color: Colors.white,
fontWeight: FontWeight.normal,
height: 1.2
);
List<Widget> states = [];
states.add(Text("${card.linkedEntity.displayName}", style: style));
String state = card.linkedEntity.state;
if (state == null || state == "off" || state == "unavailable" || state == "idle") {
states.add(Text("${card.linkedEntity.state}", style: style.apply(fontSizeDelta: 4.0),));
}
if (card.linkedEntity.attributes['media_title'] != null) {
states.add(Text("${card.linkedEntity.attributes['media_title']}", style: style.apply(fontSizeDelta: 6.0, fontWeightDelta: 50),));
}
if (card.linkedEntity.attributes['media_content_type'] == "music") {
states.add(Text("${card.linkedEntity.attributes['media_artist'] ?? card.linkedEntity.attributes['app_name']}", style: style.apply(fontSizeDelta: 4.0),));
} else if (card.linkedEntity.attributes['app_name'] != null) {
states.add(Text("${card.linkedEntity.attributes['app_name']}", style: style.apply(fontSizeDelta: 4.0),));
}
return Padding(
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, Entity.rowPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: states,
),
);
}
Widget _buildImage() {
String state = card.linkedEntity.state;
if (homeAssistantWebHost != null && card.linkedEntity.entityPicture != null && state != "off" && state != "unavailable" && state != "idle") {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image: CachedNetworkImageProvider("$homeAssistantWebHost${card.linkedEntity.entityPicture}"),
height: 240.0,
width: 320.0,
fit: BoxFit.fitHeight,
)
],
);
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
MaterialDesignIcons.createIconDataFromIconName("mdi:movie"),
size: 150.0,
color: EntityColors.stateColor("$state"),
)
],
);
/*return Container(
color: Colors.blue,
height: 80.0,
);*/
}
}
} }

View File

@ -31,14 +31,14 @@ class UnsupportedCardWidget extends StatelessWidget {
if (card.linkedEntity != null) { if (card.linkedEntity != null) {
result.addAll(<Widget>[ result.addAll(<Widget>[
Padding( Padding(
padding: EdgeInsets.fromLTRB(0.0, Entity.rowPadding, 0.0, Entity.rowPadding), padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
child: card.linkedEntity.buildDefaultWidget(context), child: card.linkedEntity.buildDefaultWidget(context),
) )
]); ]);
} else { } else {
result.addAll(<Widget>[ result.addAll(<Widget>[
Padding( Padding(
padding: EdgeInsets.fromLTRB(Entity.leftWidgetPadding, Entity.rowPadding, Entity.rightWidgetPadding, Entity.rowPadding), padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding),
child: Text("'${card.type}' card is not supported yet"), child: Text("'${card.type}' card is not supported yet"),
), ),
]); ]);

View File

@ -7,7 +7,7 @@ packages:
name: analyzer name: analyzer
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.32.4" version: "0.33.0"
archive: archive:
dependency: transitive dependency: transitive
description: description:
@ -42,7 +42,7 @@ packages:
name: cached_network_image name: cached_network_image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.2" version: "0.5.0+1"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -56,14 +56,14 @@ packages:
name: charts_common name: charts_common
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.0" version: "0.5.0"
charts_flutter: charts_flutter:
dependency: "direct main" dependency: "direct main"
description: description:
name: charts_flutter name: charts_flutter
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.0" version: "0.5.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
@ -91,7 +91,7 @@ packages:
name: csslib name: csslib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.14.5" version: "0.14.6"
dart_config: dart_config:
dependency: transitive dependency: transitive
description: description:
@ -126,7 +126,7 @@ packages:
name: flutter_cache_manager name: flutter_cache_manager
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.2" version: "0.2.0+1"
flutter_colorpicker: flutter_colorpicker:
dependency: "direct main" dependency: "direct main"
description: description:
@ -152,7 +152,7 @@ packages:
name: front_end name: front_end
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.4" version: "0.1.6"
glob: glob:
dependency: transitive dependency: transitive
description: description:
@ -173,7 +173,7 @@ packages:
name: http name: http
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.11.3+17" version: "0.12.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -229,7 +229,7 @@ packages:
name: kernel name: kernel
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.4" version: "0.3.6"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -285,7 +285,7 @@ packages:
name: package_resolver name: package_resolver
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "1.0.6"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -395,7 +395,7 @@ packages:
name: source_maps name: source_maps
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.10.7" version: "0.10.8"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
@ -444,7 +444,7 @@ packages:
name: test name: test
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.3.0" version: "1.3.4"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -458,7 +458,7 @@ packages:
name: url_launcher name: url_launcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.3" version: "4.0.1"
utf: utf:
dependency: transitive dependency: transitive
description: description:
@ -516,5 +516,5 @@ packages:
source: hosted source: hosted
version: "2.1.15" version: "2.1.15"
sdks: sdks:
dart: ">=2.0.0 <=2.1.0-dev.5.0.flutter-a2eb050044" dart: ">=2.0.0 <=2.1.0-dev.8.0.flutter-bf26f760b1"
flutter: ">=0.1.4 <2.0.0" flutter: ">=0.5.6 <2.0.0"

View File

@ -10,13 +10,13 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences: any shared_preferences: any
progress_indicators: ^0.1.2 progress_indicators: any
event_bus: ^1.0.1 event_bus: any
cached_network_image: ^0.4.1 cached_network_image: any
url_launcher: ^3.0.3 url_launcher: any
date_format: ^1.0.5 date_format: any
flutter_colorpicker: ^0.1.0 flutter_colorpicker: any
charts_flutter: ^0.4.0 charts_flutter: any
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
@ -25,7 +25,7 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_launcher_icons: ^0.6.1 flutter_launcher_icons: any
flutter_icons: flutter_icons:
android: true android: true