Resolves #120 Horizontal Stack Cards
This commit is contained in:
parent
20b1b90e39
commit
9c403480e2
@ -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";
|
||||||
|
@ -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(
|
||||||
|
45
lib/entity_widgets/button_entity_container.dart
Normal file
45
lib/entity_widgets/button_entity_container.dart
Normal 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -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),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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(
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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';
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
),
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user