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 {
static const horizontalStack = "horizontal-stack";
static const verticalStack = "vertical-stack";
static const entities = "entities";
static const glance = "glance";
static const mediaControl = "media-control";

View File

@ -29,6 +29,7 @@ class EntityWrapper {
}
void handleTap() {
TheLogger.debug(tapAction);
switch (tapAction) {
case EntityTapAction.toggle: {
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 double fontSize;
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
Widget build(BuildContext context) {
@ -19,6 +20,7 @@ class EntityName extends StatelessWidget {
"${entityWrapper.displayName}",
overflow: textOverflow,
softWrap: wordsWrap,
maxLines: maxLines,
style: TextStyle(fontSize: fontSize),
textAlign: textAlign,
),

View File

@ -7,7 +7,7 @@ class GlanceEntityContainer extends StatelessWidget {
final bool nameInTheBottom;
final double iconSize;
final double nameFontSize;
final bool expanded;
final bool wordsWrapInName;
GlanceEntityContainer({
Key key,
@ -16,7 +16,7 @@ class GlanceEntityContainer extends StatelessWidget {
this.nameInTheBottom: false,
this.iconSize: Sizes.iconSize,
this.nameFontSize: Sizes.smallFontSize,
this.expanded: false
this.wordsWrapInName: false
}) : super(key: key);
@override
@ -25,21 +25,11 @@ class GlanceEntityContainer extends StatelessWidget {
List<Widget> result = [];
if (!nameInTheBottom) {
if (showName) {
result.add(EntityName(
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: false,
textAlign: TextAlign.center,
fontSize: nameFontSize,
));
result.add(_buildName());
}
} else {
if (showState) {
result.add(SimpleEntityState(
textAlign: TextAlign.center,
expanded: false,
padding: EdgeInsets.only(top: Sizes.rowPadding),
));
result.add(_buildState());
}
}
result.add(
@ -50,55 +40,45 @@ class GlanceEntityContainer extends StatelessWidget {
);
if (!nameInTheBottom) {
if (showState) {
result.add(SimpleEntityState(
textAlign: TextAlign.center,
expanded: false,
padding: EdgeInsets.only(top: Sizes.rowPadding),
));
result.add(_buildState());
}
} else {
result.add(EntityName(
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
textOverflow: TextOverflow.ellipsis,
wordsWrap: false,
textAlign: TextAlign.center,
fontSize: nameFontSize,
));
result.add(_buildName());
}
if (expanded) {
return InkWell(
return Center(
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(),
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(
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(),
onLongPress: () => entityWrapper.handleHold(),
),
);
}
),
);
}
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 TextAlign textAlign;
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
Widget build(BuildContext context) {
@ -16,7 +17,7 @@ class SimpleEntityState extends StatelessWidget {
child: Text(
"${entityModel.entityWrapper.entity.state} ${entityModel.entityWrapper.entity.unitOfMeasurement}",
textAlign: textAlign,
maxLines: 10,
maxLines: maxLines,
overflow: TextOverflow.ellipsis,
softWrap: true,
style: new TextStyle(

View File

@ -428,75 +428,80 @@ class HomeAssistant {
List<HACard> _createLovelaceCards(List rawCards) {
List<HACard> result = [];
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) {
result.addAll(_createLovelaceCards(rawCard["cards"]));
} else {
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,
);
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}
)
);
}
card.childCards = _createLovelaceCards(rawCard["cards"]);
}
rawCard["entities"]?.forEach((rawEntity) {
if (rawEntity is String) {
if (entities.isExist(rawEntity)) {
card.entities.add(EntityWrapper(entity: entities.get(rawEntity)));
}
});
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)) {
card.linkedEntityWrapper = EntityWrapper(
entity: entities.get(en),
tapAction: tapAction,
holdAction: holdAction
);
} 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;
}
} else {
if (entities.isExist(en["entity"])) {
card.linkedEntityWrapper = EntityWrapper(
entity: entities.get(en["entity"]),
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}
)
);
}
}
});
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"],
displayName: en["name"],
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;
}

View File

@ -36,6 +36,7 @@ part 'entity_widgets/common/badge.dart';
part 'entity_widgets/model_widgets.dart';
part 'entity_widgets/default_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/entity_icon.dart';
part 'entity_widgets/entity_name.dart';

View File

@ -2,6 +2,7 @@ part of '../main.dart';
class HACard {
List<EntityWrapper> entities = [];
List<HACard> childCards = [];
EntityWrapper linkedEntityWrapper;
String name;
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.thermostat:
case CardType.sensor:

View File

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

View File

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