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,55 +40,45 @@ 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 Center(
return InkWell( child: InkResponse(
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: Sizes.iconSize * 2),
child: Column(
mainAxisSize: MainAxisSize.min,
//mainAxisAlignment: MainAxisAlignment.start,
//crossAxisAlignment: CrossAxisAlignment.center,
children: result,
),
),
onTap: () => entityWrapper.handleTap(), onTap: () => entityWrapper.handleTap(),
onLongPress: () => entityWrapper.handleHold(), onLongPress: () => entityWrapper.handleHold(),
child: ConstrainedBox( ),
constraints: BoxConstraints(maxHeight: 100.0), );
child: FittedBox( }
fit: BoxFit.fitHeight,
child: Column( Widget _buildName() {
mainAxisSize: MainAxisSize.min, return EntityName(
//mainAxisAlignment: MainAxisAlignment.start, padding: EdgeInsets.only(bottom: Sizes.rowPadding),
//crossAxisAlignment: CrossAxisAlignment.center, textOverflow: TextOverflow.ellipsis,
children: result, wordsWrap: wordsWrapInName,
), textAlign: TextAlign.center,
), fontSize: nameFontSize,
), );
); }
} else {
return Center( Widget _buildState() {
child: InkResponse( return SimpleEntityState(
child: ConstrainedBox( textAlign: TextAlign.center,
constraints: BoxConstraints(minWidth: Sizes.iconSize * 2), expanded: false,
child: Column( maxLines: 1,
mainAxisSize: MainAxisSize.min, padding: EdgeInsets.only(top: Sizes.rowPadding),
//mainAxisAlignment: MainAxisAlignment.start, );
//crossAxisAlignment: CrossAxisAlignment.center,
children: result,
),
),
onTap: () => entityWrapper.handleTap(),
onLongPress: () => entityWrapper.handleHold(),
),
);
}
} }
} }

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,75 +428,80 @@ class HomeAssistant {
List<HACard> _createLovelaceCards(List rawCards) { List<HACard> _createLovelaceCards(List rawCards) {
List<HACard> result = []; List<HACard> result = [];
rawCards.forEach((rawCard){ rawCards.forEach((rawCard){
HACard card = HACard(
id: "card",
name: rawCard["title"] ?? rawCard["name"],
type: rawCard['type'],
columnsCount: rawCard['columns'] ?? 4,
showName: rawCard['show_name'] ?? true,
showState: rawCard['show_state'] ?? true,
);
if (rawCard["cards"] != null) { if (rawCard["cards"] != null) {
result.addAll(_createLovelaceCards(rawCard["cards"])); card.childCards = _createLovelaceCards(rawCard["cards"]);
} else { }
HACard card = HACard( rawCard["entities"]?.forEach((rawEntity) {
id: "card", if (rawEntity is String) {
name: rawCard["title"] ?? rawCard["name"], if (entities.isExist(rawEntity)) {
type: rawCard['type'], card.entities.add(EntityWrapper(entity: entities.get(rawEntity)));
columnsCount: rawCard['columns'] ?? 4,
showName: rawCard['show_name'] ?? true,
showState: rawCard['show_state'] ?? true,
);
rawCard["entities"]?.forEach((rawEntity) {
if (rawEntity is String) {
if (entities.isExist(rawEntity)) {
card.entities.add(EntityWrapper(entity: entities.get(rawEntity)));
}
} else {
if (entities.isExist(rawEntity["entity"])) {
Entity e = entities.get(rawEntity["entity"]);
String tapAction;
String holdAction;
if (card.type == CardType.glance && card.type == CardType.entityButton) {
tapAction = rawEntity["tap_action"] ?? EntityTapAction.moreInfo;
holdAction = rawEntity["hold_action"] ?? EntityTapAction.none;
} else {
tapAction = EntityTapAction.moreInfo;
holdAction = EntityTapAction.none;
}
card.entities.add(
EntityWrapper(
entity: e,
displayName: rawEntity["name"],
icon: rawEntity["icon"],
tapAction: tapAction,
holdAction: holdAction,
tapActionService: rawEntity["service"],
tapActionServiceData: rawEntity["service_data"] ?? {"entity_id": e.entityId}
)
);
}
} }
}); } else {
if (rawCard["entity"] != null) { if (entities.isExist(rawEntity["entity"])) {
var en = rawCard["entity"]; Entity e = entities.get(rawEntity["entity"]);
String tapAction = rawCard["tap_action"] ?? EntityTapAction.moreInfo; String tapAction;
String holdAction = rawCard["hold_action"] ?? EntityTapAction.none; String holdAction;
if (en is String) { if (card.type == CardType.glance || card.type == CardType.entityButton) {
if (entities.isExist(en)) { tapAction = rawEntity["tap_action"] ?? EntityTapAction.moreInfo;
card.linkedEntityWrapper = EntityWrapper( holdAction = rawEntity["hold_action"] ?? EntityTapAction.none;
entity: entities.get(en), } else {
tapAction: tapAction, tapAction = EntityTapAction.moreInfo;
holdAction: holdAction holdAction = EntityTapAction.none;
);
} }
} else { card.entities.add(
if (entities.isExist(en["entity"])) { EntityWrapper(
card.linkedEntityWrapper = EntityWrapper( entity: e,
entity: entities.get(en["entity"]), displayName: rawEntity["name"],
icon: rawEntity["icon"],
tapAction: tapAction,
holdAction: holdAction,
tapActionService: rawEntity["service"],
tapActionServiceData: rawEntity["service_data"] ?? {"entity_id": e.entityId}
)
);
}
}
});
if (rawCard["entity"] != null) {
var en = rawCard["entity"];
String tapAction = rawCard["tap_action"] ?? EntityTapAction.moreInfo;
String holdAction = rawCard["hold_action"] ?? EntityTapAction.none;
if (en is String) {
if (entities.isExist(en)) {
Entity e = entities.get(en);
card.linkedEntityWrapper = EntityWrapper(
entity: e,
tapAction: tapAction,
holdAction: holdAction,
tapActionService: rawCard["service"],
tapActionServiceData: rawCard["service_data"] ?? {"entity_id": e.entityId}
);
}
} else {
if (entities.isExist(en["entity"])) {
Entity e = entities.get(en["entity"]);
card.linkedEntityWrapper = EntityWrapper(
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( child: EntityModel(
padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding), entityWrapper: card.linkedEntityWrapper,
child: EntityModel( child: ButtonEntityContainer(),
entityWrapper: card.linkedEntityWrapper, handleTap: true
child: GlanceEntityContainer(
showName: true,
showState: false,
nameInTheBottom: true,
iconSize: Sizes.largeIconSize,
nameFontSize: Sizes.nameFontSize,
expanded: true,
),
handleTap: true
),
) )
); );
} }