Resolves #120 Horizontal Stack Cards

This commit is contained in:
Yegor Vialov 2018-11-25 20:44:19 +02:00
parent 20b1b90e39
commit 9c403480e2
11 changed files with 187 additions and 139 deletions

View File

@ -38,6 +38,8 @@ class EntityTapAction {
} }
class CardType { class CardType {
static const horizontalStack = "horizontal-stack";
static const verticalStack = "vertical-stack";
static const entities = "entities"; static const entities = "entities";
static const glance = "glance"; static const glance = "glance";
static const mediaControl = "media-control"; static const mediaControl = "media-control";

View File

@ -29,6 +29,7 @@ class EntityWrapper {
} }
void handleTap() { void handleTap() {
TheLogger.debug(tapAction);
switch (tapAction) { switch (tapAction) {
case EntityTapAction.toggle: { case EntityTapAction.toggle: {
eventBus.fire( eventBus.fire(

View File

@ -0,0 +1,45 @@
part of '../main.dart';
class ButtonEntityContainer extends StatelessWidget {
ButtonEntityContainer({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper;
return InkWell(
onTap: () => entityWrapper.handleTap(),
onLongPress: () => entityWrapper.handleHold(),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FractionallySizedBox(
widthFactor: 0.4,
child: FittedBox(
fit: BoxFit.fitHeight,
child: EntityIcon(
padding: EdgeInsets.fromLTRB(2.0, 6.0, 2.0, 2.0),
iconSize: Sizes.iconSize,
)
),
),
_buildName()
],
),
);
}
Widget _buildName() {
return EntityName(
padding: EdgeInsets.fromLTRB(Sizes.buttonPadding, 0.0, Sizes.buttonPadding, Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
maxLines: 3,
wordsWrap: true,
textAlign: TextAlign.center,
fontSize: Sizes.nameFontSize,
);
}
}

View File

@ -7,8 +7,9 @@ class EntityName extends StatelessWidget {
final bool wordsWrap; final bool wordsWrap;
final double fontSize; final double fontSize;
final TextAlign textAlign; final TextAlign textAlign;
final int maxLines;
const EntityName({Key key, this.padding: const EdgeInsets.only(right: 10.0), this.textOverflow: TextOverflow.ellipsis, this.wordsWrap: true, this.fontSize: Sizes.nameFontSize, this.textAlign: TextAlign.left}) : super(key: key); const EntityName({Key key, this.maxLines, this.padding: const EdgeInsets.only(right: 10.0), this.textOverflow: TextOverflow.ellipsis, this.wordsWrap: true, this.fontSize: Sizes.nameFontSize, this.textAlign: TextAlign.left}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -19,6 +20,7 @@ class EntityName extends StatelessWidget {
"${entityWrapper.displayName}", "${entityWrapper.displayName}",
overflow: textOverflow, overflow: textOverflow,
softWrap: wordsWrap, softWrap: wordsWrap,
maxLines: maxLines,
style: TextStyle(fontSize: fontSize), style: TextStyle(fontSize: fontSize),
textAlign: textAlign, textAlign: textAlign,
), ),

View File

@ -7,7 +7,7 @@ class GlanceEntityContainer extends StatelessWidget {
final bool nameInTheBottom; final bool nameInTheBottom;
final double iconSize; final double iconSize;
final double nameFontSize; final double nameFontSize;
final bool expanded; final bool wordsWrapInName;
GlanceEntityContainer({ GlanceEntityContainer({
Key key, Key key,
@ -16,7 +16,7 @@ class GlanceEntityContainer extends StatelessWidget {
this.nameInTheBottom: false, this.nameInTheBottom: false,
this.iconSize: Sizes.iconSize, this.iconSize: Sizes.iconSize,
this.nameFontSize: Sizes.smallFontSize, this.nameFontSize: Sizes.smallFontSize,
this.expanded: false this.wordsWrapInName: false
}) : super(key: key); }) : super(key: key);
@override @override
@ -25,21 +25,11 @@ class GlanceEntityContainer extends StatelessWidget {
List<Widget> result = []; List<Widget> result = [];
if (!nameInTheBottom) { if (!nameInTheBottom) {
if (showName) { if (showName) {
result.add(EntityName( result.add(_buildName());
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: false,
textAlign: TextAlign.center,
fontSize: nameFontSize,
));
} }
} else { } else {
if (showState) { if (showState) {
result.add(SimpleEntityState( result.add(_buildState());
textAlign: TextAlign.center,
expanded: false,
padding: EdgeInsets.only(top: Sizes.rowPadding),
));
} }
} }
result.add( result.add(
@ -50,40 +40,12 @@ class GlanceEntityContainer extends StatelessWidget {
); );
if (!nameInTheBottom) { if (!nameInTheBottom) {
if (showState) { if (showState) {
result.add(SimpleEntityState( result.add(_buildState());
textAlign: TextAlign.center,
expanded: false,
padding: EdgeInsets.only(top: Sizes.rowPadding),
));
} }
} else { } else {
result.add(EntityName( result.add(_buildName());
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: false,
textAlign: TextAlign.center,
fontSize: nameFontSize,
));
} }
if (expanded) {
return InkWell(
onTap: () => entityWrapper.handleTap(),
onLongPress: () => entityWrapper.handleHold(),
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: 100.0),
child: FittedBox(
fit: BoxFit.fitHeight,
child: Column(
mainAxisSize: MainAxisSize.min,
//mainAxisAlignment: MainAxisAlignment.start,
//crossAxisAlignment: CrossAxisAlignment.center,
children: result,
),
),
),
);
} else {
return Center( return Center(
child: InkResponse( child: InkResponse(
child: ConstrainedBox( child: ConstrainedBox(
@ -100,5 +62,23 @@ class GlanceEntityContainer extends StatelessWidget {
), ),
); );
} }
Widget _buildName() {
return EntityName(
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: wordsWrapInName,
textAlign: TextAlign.center,
fontSize: nameFontSize,
);
}
Widget _buildState() {
return SimpleEntityState(
textAlign: TextAlign.center,
expanded: false,
maxLines: 1,
padding: EdgeInsets.only(top: Sizes.rowPadding),
);
} }
} }

View File

@ -5,8 +5,9 @@ class SimpleEntityState extends StatelessWidget {
final bool expanded; final bool expanded;
final TextAlign textAlign; final TextAlign textAlign;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final int maxLines;
const SimpleEntityState({Key key, this.expanded: true, this.textAlign: TextAlign.right, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0)}) : super(key: key); const SimpleEntityState({Key key, this.maxLines: 10, this.expanded: true, this.textAlign: TextAlign.right, this.padding: const EdgeInsets.fromLTRB(0.0, 0.0, Sizes.rightWidgetPadding, 0.0)}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -16,7 +17,7 @@ class SimpleEntityState extends StatelessWidget {
child: Text( child: Text(
"${entityModel.entityWrapper.entity.state} ${entityModel.entityWrapper.entity.unitOfMeasurement}", "${entityModel.entityWrapper.entity.state} ${entityModel.entityWrapper.entity.unitOfMeasurement}",
textAlign: textAlign, textAlign: textAlign,
maxLines: 10, maxLines: maxLines,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: true, softWrap: true,
style: new TextStyle( style: new TextStyle(

View File

@ -428,9 +428,6 @@ class HomeAssistant {
List<HACard> _createLovelaceCards(List rawCards) { List<HACard> _createLovelaceCards(List rawCards) {
List<HACard> result = []; List<HACard> result = [];
rawCards.forEach((rawCard){ rawCards.forEach((rawCard){
if (rawCard["cards"] != null) {
result.addAll(_createLovelaceCards(rawCard["cards"]));
} else {
HACard card = HACard( HACard card = HACard(
id: "card", id: "card",
name: rawCard["title"] ?? rawCard["name"], name: rawCard["title"] ?? rawCard["name"],
@ -439,6 +436,9 @@ class HomeAssistant {
showName: rawCard['show_name'] ?? true, showName: rawCard['show_name'] ?? true,
showState: rawCard['show_state'] ?? true, showState: rawCard['show_state'] ?? true,
); );
if (rawCard["cards"] != null) {
card.childCards = _createLovelaceCards(rawCard["cards"]);
}
rawCard["entities"]?.forEach((rawEntity) { rawCard["entities"]?.forEach((rawEntity) {
if (rawEntity is String) { if (rawEntity is String) {
if (entities.isExist(rawEntity)) { if (entities.isExist(rawEntity)) {
@ -449,7 +449,7 @@ class HomeAssistant {
Entity e = entities.get(rawEntity["entity"]); Entity e = entities.get(rawEntity["entity"]);
String tapAction; String tapAction;
String holdAction; String holdAction;
if (card.type == CardType.glance && card.type == CardType.entityButton) { if (card.type == CardType.glance || card.type == CardType.entityButton) {
tapAction = rawEntity["tap_action"] ?? EntityTapAction.moreInfo; tapAction = rawEntity["tap_action"] ?? EntityTapAction.moreInfo;
holdAction = rawEntity["hold_action"] ?? EntityTapAction.none; holdAction = rawEntity["hold_action"] ?? EntityTapAction.none;
} else { } else {
@ -476,27 +476,32 @@ class HomeAssistant {
String holdAction = rawCard["hold_action"] ?? EntityTapAction.none; String holdAction = rawCard["hold_action"] ?? EntityTapAction.none;
if (en is String) { if (en is String) {
if (entities.isExist(en)) { if (entities.isExist(en)) {
Entity e = entities.get(en);
card.linkedEntityWrapper = EntityWrapper( card.linkedEntityWrapper = EntityWrapper(
entity: entities.get(en), entity: e,
tapAction: tapAction, tapAction: tapAction,
holdAction: holdAction holdAction: holdAction,
tapActionService: rawCard["service"],
tapActionServiceData: rawCard["service_data"] ?? {"entity_id": e.entityId}
); );
} }
} else { } else {
if (entities.isExist(en["entity"])) { if (entities.isExist(en["entity"])) {
Entity e = entities.get(en["entity"]);
card.linkedEntityWrapper = EntityWrapper( card.linkedEntityWrapper = EntityWrapper(
entity: entities.get(en["entity"]), entity: e,
icon: en["icon"], icon: en["icon"],
displayName: en["name"], displayName: en["name"],
tapAction: tapAction, tapAction: tapAction,
holdAction: holdAction holdAction: holdAction,
tapActionService: rawCard["service"],
tapActionServiceData: rawCard["service_data"] ?? {"entity_id": e.entityId}
); );
} }
} }
} }
result.add(card); result.add(card);
}
}); });
return result; return result;
} }

View File

@ -36,6 +36,7 @@ part 'entity_widgets/common/badge.dart';
part 'entity_widgets/model_widgets.dart'; part 'entity_widgets/model_widgets.dart';
part 'entity_widgets/default_entity_container.dart'; part 'entity_widgets/default_entity_container.dart';
part 'entity_widgets/glance_entity_container.dart'; part 'entity_widgets/glance_entity_container.dart';
part 'entity_widgets/button_entity_container.dart';
part 'entity_widgets/common/entity_attributes_list.dart'; part 'entity_widgets/common/entity_attributes_list.dart';
part 'entity_widgets/entity_icon.dart'; part 'entity_widgets/entity_icon.dart';
part 'entity_widgets/entity_name.dart'; part 'entity_widgets/entity_name.dart';

View File

@ -2,6 +2,7 @@ part of '../main.dart';
class HACard { class HACard {
List<EntityWrapper> entities = []; List<EntityWrapper> entities = [];
List<HACard> childCards = [];
EntityWrapper linkedEntityWrapper; EntityWrapper linkedEntityWrapper;
String name; String name;
String id; String id;
@ -47,6 +48,27 @@ class HACard {
); );
} }
case CardType.horizontalStack: {
if (childCards.isNotEmpty) {
List<Widget> children = [];
childCards.forEach((card) {
children.add(
Flexible(
fit: FlexFit.tight,
child: card.build(context),
)
);
});
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
);
}
return Container(height: 0.0, width: 0.0,);
}
case CardType.weatherForecast: case CardType.weatherForecast:
case CardType.thermostat: case CardType.thermostat:
case CardType.sensor: case CardType.sensor:

View File

@ -3,6 +3,7 @@ part of '../main.dart';
class Sizes { class Sizes {
static const rightWidgetPadding = 14.0; static const rightWidgetPadding = 14.0;
static const leftWidgetPadding = 8.0; static const leftWidgetPadding = 8.0;
static const buttonPadding = 4.0;
static const extendedWidgetHeight = 50.0; static const extendedWidgetHeight = 50.0;
static const iconSize = 28.0; static const iconSize = 28.0;
static const largeIconSize = 46.0; static const largeIconSize = 46.0;

View File

@ -14,24 +14,12 @@ class EntityButtonCardWidget extends StatelessWidget {
if (card.linkedEntityWrapper!= null && card.linkedEntityWrapper.entity.isHidden) { if (card.linkedEntityWrapper!= null && card.linkedEntityWrapper.entity.isHidden) {
return Container(width: 0.0, height: 0.0,); return Container(width: 0.0, height: 0.0,);
} }
if (card.name != null) { card.linkedEntityWrapper.displayName = card.name?.toUpperCase() ?? card.linkedEntityWrapper.displayName.toUpperCase();
card.linkedEntityWrapper.displayName = card.name;
}
return Card( return Card(
child: Padding(
padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding),
child: EntityModel( child: EntityModel(
entityWrapper: card.linkedEntityWrapper, entityWrapper: card.linkedEntityWrapper,
child: GlanceEntityContainer( child: ButtonEntityContainer(),
showName: true,
showState: false,
nameInTheBottom: true,
iconSize: Sizes.largeIconSize,
nameFontSize: Sizes.nameFontSize,
expanded: true,
),
handleTap: true handleTap: true
),
) )
); );
} }