Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
d3c1422b9e | |||
b6ac9f985f | |||
a59de4b6dc | |||
f507d5df0c | |||
f77e46de37 | |||
cda17b1217 | |||
be560769ef | |||
3815800e32 | |||
a3226311a2 | |||
79669243c2 | |||
fdc81f6ea4 | |||
7fe44459e7 | |||
a8500d44e1 | |||
b4d4c5abec | |||
c19a3f272a | |||
b264534858 | |||
ab53f77f9e | |||
c73956720c | |||
051041e794 | |||
5c83be9fee | |||
4bece42693 | |||
4ae107fe4c | |||
9523ed2562 | |||
9c403480e2 | |||
20b1b90e39 | |||
5633e30448 |
1
docs/empty
Normal file
1
docs/empty
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
BIN
docs/ha_access_tokens.png
Normal file
BIN
docs/ha_access_tokens.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
docs/ha_profile-300x247.png
Normal file
BIN
docs/ha_profile-300x247.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
docs/settings-869x1024.png
Normal file
BIN
docs/settings-869x1024.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 KiB |
@ -19,7 +19,7 @@ class _EntityViewPageState extends State<EntityViewPage> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
|
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
|
||||||
TheLogger.debug("State change event handled by entity page: ${event.entityId}");
|
Logger.d("State change event handled by entity page: ${event.entityId}");
|
||||||
if (event.entityId == widget.entityId) {
|
if (event.entityId == widget.entityId) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
@ -30,14 +30,54 @@ class EntityState {
|
|||||||
static const problem = 'problem';
|
static const problem = 'problem';
|
||||||
}
|
}
|
||||||
|
|
||||||
class EntityTapAction {
|
class EntityUIAction {
|
||||||
static const moreInfo = 'more-info';
|
static const moreInfo = 'more-info';
|
||||||
static const toggle = 'toggle';
|
static const toggle = 'toggle';
|
||||||
static const callService = 'call-service';
|
static const callService = 'call-service';
|
||||||
|
static const navigate = 'navigate';
|
||||||
static const none = 'none';
|
static const none = 'none';
|
||||||
|
|
||||||
|
String tapAction = EntityUIAction.moreInfo;
|
||||||
|
String tapNavigationPath;
|
||||||
|
String tapService;
|
||||||
|
Map<String, dynamic> tapServiceData;
|
||||||
|
String holdAction = EntityUIAction.none;
|
||||||
|
String holdNavigationPath;
|
||||||
|
String holdService;
|
||||||
|
Map<String, dynamic> holdServiceData;
|
||||||
|
|
||||||
|
EntityUIAction({rawEntityData}) {
|
||||||
|
if (rawEntityData != null) {
|
||||||
|
if (rawEntityData["tap_action"] != null) {
|
||||||
|
if (rawEntityData["tap_action"] is String) {
|
||||||
|
tapAction = rawEntityData["tap_action"];
|
||||||
|
} else {
|
||||||
|
tapAction =
|
||||||
|
rawEntityData["tap_action"]["action"] ?? EntityUIAction.moreInfo;
|
||||||
|
tapNavigationPath = rawEntityData["tap_action"]["navigation_path"];
|
||||||
|
tapService = rawEntityData["tap_action"]["service"];
|
||||||
|
tapServiceData = rawEntityData["tap_action"]["service_data"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rawEntityData["hold_action"] != null) {
|
||||||
|
if (rawEntityData["hold_action"] is String) {
|
||||||
|
holdAction = rawEntityData["hold_action"];
|
||||||
|
} else {
|
||||||
|
holdAction =
|
||||||
|
rawEntityData["hold_action"]["action"] ?? EntityUIAction.none;
|
||||||
|
holdNavigationPath = rawEntityData["hold_action"]["navigation_path"];
|
||||||
|
holdService = rawEntityData["hold_action"]["service"];
|
||||||
|
holdServiceData = rawEntityData["hold_action"]["service_data"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
||||||
|
@ -12,14 +12,65 @@ class Entity {
|
|||||||
"sensor"
|
"sensor"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
static Map StateByDeviceClass = {
|
||||||
|
"battery.on": "Low",
|
||||||
|
"battery.off": "Normal",
|
||||||
|
"cold.on": "Cold",
|
||||||
|
"cold.off": "Normal",
|
||||||
|
"connectivity.on": "Connected",
|
||||||
|
"connectivity.off": "Diconnected",
|
||||||
|
"door.on": "Open",
|
||||||
|
"door.off": "Closed",
|
||||||
|
"garage_door.on": "Open",
|
||||||
|
"garage_door.off": "Closed",
|
||||||
|
"gas.on": "Detected",
|
||||||
|
"gas.off": "Clear",
|
||||||
|
"heat.on": "Hot",
|
||||||
|
"heat.off": "Normal",
|
||||||
|
"light.on": "Detected",
|
||||||
|
"lignt.off": "No light",
|
||||||
|
"lock.on": "Unlocked",
|
||||||
|
"lock.off": "Locked",
|
||||||
|
"moisture.on": "Wet",
|
||||||
|
"moisture.off": "Dry",
|
||||||
|
"motion.on": "Detected",
|
||||||
|
"motion.off": "Cler",
|
||||||
|
"moving.on": "Moving",
|
||||||
|
"moving.off": "Stopped",
|
||||||
|
"occupancy.on": "Occupied",
|
||||||
|
"occupancy.off": "Clear",
|
||||||
|
"opening.on": "Open",
|
||||||
|
"opening.off": "Closed",
|
||||||
|
"plug.on": "Plugged in",
|
||||||
|
"plug.off": "Unplugged",
|
||||||
|
"power.on": "Powered",
|
||||||
|
"power.off": "No power",
|
||||||
|
"presence.on": "Home",
|
||||||
|
"presence.off": "Away",
|
||||||
|
"problem.on": "Problem",
|
||||||
|
"problem.off": "OK",
|
||||||
|
"safety.on": "Unsafe",
|
||||||
|
"safety.off": "Safe",
|
||||||
|
"smoke.on": "Detected",
|
||||||
|
"smoke.off": "Clear",
|
||||||
|
"sound.on": "Detected",
|
||||||
|
"sound.off": "Clear",
|
||||||
|
"vibration.on": "Detected",
|
||||||
|
"vibration.off": "Clear",
|
||||||
|
"window.on": "Open",
|
||||||
|
"window.off": "Closed"
|
||||||
|
};
|
||||||
|
|
||||||
Map attributes;
|
Map attributes;
|
||||||
String domain;
|
String domain;
|
||||||
String entityId;
|
String entityId;
|
||||||
String state;
|
String state;
|
||||||
|
String displayState;
|
||||||
DateTime _lastUpdated;
|
DateTime _lastUpdated;
|
||||||
|
|
||||||
List<Entity> childEntities = [];
|
List<Entity> childEntities = [];
|
||||||
List<String> attributesToShow = ["all"];
|
List<String> attributesToShow = ["all"];
|
||||||
|
String deviceClass;
|
||||||
EntityHistoryConfig historyConfig = EntityHistoryConfig(
|
EntityHistoryConfig historyConfig = EntityHistoryConfig(
|
||||||
chartType: EntityHistoryWidgetType.simple
|
chartType: EntityHistoryWidgetType.simple
|
||||||
);
|
);
|
||||||
@ -27,7 +78,6 @@ class Entity {
|
|||||||
String get displayName =>
|
String get displayName =>
|
||||||
attributes["friendly_name"] ?? (attributes["name"] ?? entityId.split(".")[1].replaceAll("_", " "));
|
attributes["friendly_name"] ?? (attributes["name"] ?? entityId.split(".")[1].replaceAll("_", " "));
|
||||||
|
|
||||||
String get deviceClass => attributes["device_class"] ?? null;
|
|
||||||
bool get isView =>
|
bool get isView =>
|
||||||
(domain == "group") &&
|
(domain == "group") &&
|
||||||
(attributes != null ? attributes["view"] ?? false : false);
|
(attributes != null ? attributes["view"] ?? false : false);
|
||||||
@ -50,7 +100,9 @@ class Entity {
|
|||||||
attributes = rawData["attributes"] ?? {};
|
attributes = rawData["attributes"] ?? {};
|
||||||
domain = rawData["entity_id"].split(".")[0];
|
domain = rawData["entity_id"].split(".")[0];
|
||||||
entityId = rawData["entity_id"];
|
entityId = rawData["entity_id"];
|
||||||
|
deviceClass = attributes["device_class"];
|
||||||
state = rawData["state"];
|
state = rawData["state"];
|
||||||
|
displayState = Entity.StateByDeviceClass["$deviceClass.$state"] ?? state;
|
||||||
_lastUpdated = DateTime.tryParse(rawData["last_updated"]);
|
_lastUpdated = DateTime.tryParse(rawData["last_updated"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,13 +143,6 @@ class Entity {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildGlanceWidget(BuildContext context, bool showName, bool showState) {
|
|
||||||
return GlanceEntityContainer(
|
|
||||||
showName: showName,
|
|
||||||
showState: showState,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildStatePart(BuildContext context) {
|
Widget _buildStatePart(BuildContext context) {
|
||||||
return SimpleEntityState();
|
return SimpleEntityState();
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,7 @@ class EntityWrapper {
|
|||||||
|
|
||||||
String displayName;
|
String displayName;
|
||||||
String icon;
|
String icon;
|
||||||
String tapAction;
|
EntityUIAction uiAction;
|
||||||
String holdAction;
|
|
||||||
String tapActionService;
|
|
||||||
Map<String, dynamic> tapActionServiceData;
|
|
||||||
String holdActionService;
|
|
||||||
Map<String, dynamic> holdActionServiceData;
|
|
||||||
Entity entity;
|
Entity entity;
|
||||||
|
|
||||||
|
|
||||||
@ -17,58 +12,68 @@ class EntityWrapper {
|
|||||||
this.entity,
|
this.entity,
|
||||||
String icon,
|
String icon,
|
||||||
String displayName,
|
String displayName,
|
||||||
this.tapAction: EntityTapAction.moreInfo,
|
this.uiAction
|
||||||
this.holdAction: EntityTapAction.none,
|
|
||||||
this.tapActionService,
|
|
||||||
this.tapActionServiceData,
|
|
||||||
this.holdActionService,
|
|
||||||
this.holdActionServiceData
|
|
||||||
}) {
|
}) {
|
||||||
this.icon = icon ?? entity.icon;
|
this.icon = icon ?? entity.icon;
|
||||||
this.displayName = displayName ?? entity.displayName;
|
this.displayName = displayName ?? entity.displayName;
|
||||||
|
if (this.uiAction == null) {
|
||||||
|
this.uiAction = EntityUIAction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleTap() {
|
void handleTap() {
|
||||||
switch (tapAction) {
|
switch (uiAction.tapAction) {
|
||||||
case EntityTapAction.toggle: {
|
case EntityUIAction.toggle: {
|
||||||
eventBus.fire(
|
eventBus.fire(
|
||||||
ServiceCallEvent("homeassistant", "toggle", entity.entityId, null));
|
ServiceCallEvent("homeassistant", "toggle", entity.entityId, null));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EntityTapAction.callService: {
|
case EntityUIAction.callService: {
|
||||||
eventBus.fire(
|
if (uiAction.tapService != null) {
|
||||||
ServiceCallEvent(tapActionService.split(".")[0], tapActionService.split(".")[1], null, tapActionServiceData));
|
eventBus.fire(
|
||||||
|
ServiceCallEvent(uiAction.tapService.split(".")[0],
|
||||||
|
uiAction.tapService.split(".")[1], null,
|
||||||
|
uiAction.tapServiceData));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EntityTapAction.none: {
|
case EntityUIAction.none: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case EntityUIAction.moreInfo: {
|
||||||
|
eventBus.fire(
|
||||||
|
new ShowEntityPageEvent(entity));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
eventBus.fire(
|
|
||||||
new ShowEntityPageEvent(entity));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleHold() {
|
void handleHold() {
|
||||||
switch (holdAction) {
|
switch (uiAction.holdAction) {
|
||||||
case EntityTapAction.toggle: {
|
case EntityUIAction.toggle: {
|
||||||
eventBus.fire(
|
eventBus.fire(
|
||||||
ServiceCallEvent("homeassistant", "toggle", entity.entityId, null));
|
ServiceCallEvent("homeassistant", "toggle", entity.entityId, null));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EntityTapAction.callService: {
|
case EntityUIAction.callService: {
|
||||||
eventBus.fire(
|
if (uiAction.holdService != null) {
|
||||||
ServiceCallEvent(tapActionService.split(".")[0], tapActionService.split(".")[1], null, tapActionServiceData));
|
eventBus.fire(
|
||||||
|
ServiceCallEvent(uiAction.holdService.split(".")[0],
|
||||||
|
uiAction.holdService.split(".")[1], null,
|
||||||
|
uiAction.holdServiceData));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EntityTapAction.moreInfo: {
|
case EntityUIAction.moreInfo: {
|
||||||
eventBus.fire(
|
eventBus.fire(
|
||||||
new ShowEntityPageEvent(entity));
|
new ShowEntityPageEvent(entity));
|
||||||
break;
|
break;
|
||||||
|
@ -19,7 +19,7 @@ class EntityCollection {
|
|||||||
_allEntities.clear();
|
_allEntities.clear();
|
||||||
//views.clear();
|
//views.clear();
|
||||||
|
|
||||||
TheLogger.debug("Parsing ${rawData.length} Home Assistant entities");
|
Logger.d("Parsing ${rawData.length} Home Assistant entities");
|
||||||
rawData.forEach((rawEntityData) {
|
rawData.forEach((rawEntityData) {
|
||||||
addFromRaw(rawEntityData);
|
addFromRaw(rawEntityData);
|
||||||
});
|
});
|
||||||
@ -89,11 +89,13 @@ class EntityCollection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState(Map rawStateData) {
|
bool updateState(Map rawStateData) {
|
||||||
if (isExist(rawStateData["entity_id"])) {
|
if (isExist(rawStateData["entity_id"])) {
|
||||||
updateFromRaw(rawStateData["new_state"] ?? rawStateData["old_state"]);
|
updateFromRaw(rawStateData["new_state"] ?? rawStateData["old_state"]);
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
addFromRaw(rawStateData["new_state"] ?? rawStateData["old_state"]);
|
addFromRaw(rawStateData["new_state"] ?? rawStateData["old_state"]);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,10 +103,9 @@ class EntityCollection {
|
|||||||
_allEntities[entity.entityId] = entity;
|
_allEntities[entity.entityId] = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity addFromRaw(Map rawEntityData) {
|
void addFromRaw(Map rawEntityData) {
|
||||||
Entity entity = _createEntityInstance(rawEntityData);
|
Entity entity = _createEntityInstance(rawEntityData);
|
||||||
_allEntities[entity.entityId] = entity;
|
_allEntities[entity.entityId] = entity;
|
||||||
return entity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateFromRaw(Map rawEntityData) {
|
void updateFromRaw(Map rawEntityData) {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -52,7 +52,7 @@ class _LightControlsWidgetState extends State<LightControlsWidget> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_tmpColor = color;
|
_tmpColor = color;
|
||||||
_changedHere = true;
|
_changedHere = true;
|
||||||
TheLogger.debug( "Color: [${color.red}, ${color.green}, ${color.blue}]");
|
Logger.d( "Color: [${color.red}, ${color.green}, ${color.blue}]");
|
||||||
if ((color == Colors.black) || ((color.red == color.green) && (color.green == color.blue))) {
|
if ((color == Colors.black) || ((color.red == color.green) && (color.green == color.blue))) {
|
||||||
eventBus.fire(new ServiceCallEvent(
|
eventBus.fire(new ServiceCallEvent(
|
||||||
entity.domain, "turn_off", entity.entityId,
|
entity.domain, "turn_off", entity.entityId,
|
||||||
|
@ -120,12 +120,12 @@ class MediaPlayerPlaybackControls extends StatelessWidget {
|
|||||||
void _setPower(MediaPlayerEntity entity) {
|
void _setPower(MediaPlayerEntity entity) {
|
||||||
if (entity.state != EntityState.unavailable && entity.state != EntityState.unknown) {
|
if (entity.state != EntityState.unavailable && entity.state != EntityState.unknown) {
|
||||||
if (entity.state == EntityState.off) {
|
if (entity.state == EntityState.off) {
|
||||||
TheLogger.debug("${entity.entityId} turn_on");
|
Logger.d("${entity.entityId} turn_on");
|
||||||
eventBus.fire(new ServiceCallEvent(
|
eventBus.fire(new ServiceCallEvent(
|
||||||
entity.domain, "turn_on", entity.entityId,
|
entity.domain, "turn_on", entity.entityId,
|
||||||
null));
|
null));
|
||||||
} else {
|
} else {
|
||||||
TheLogger.debug("${entity.entityId} turn_off");
|
Logger.d("${entity.entityId} turn_off");
|
||||||
eventBus.fire(new ServiceCallEvent(
|
eventBus.fire(new ServiceCallEvent(
|
||||||
entity.domain, "turn_off", entity.entityId,
|
entity.domain, "turn_off", entity.entityId,
|
||||||
null));
|
null));
|
||||||
@ -134,7 +134,7 @@ class MediaPlayerPlaybackControls extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _callAction(MediaPlayerEntity entity, String action) {
|
void _callAction(MediaPlayerEntity entity, String action) {
|
||||||
TheLogger.debug("${entity.entityId} $action");
|
Logger.d("${entity.entityId} $action");
|
||||||
eventBus.fire(new ServiceCallEvent(
|
eventBus.fire(new ServiceCallEvent(
|
||||||
entity.domain, "$action", entity.entityId,
|
entity.domain, "$action", entity.entityId,
|
||||||
null));
|
null));
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -4,41 +4,52 @@ class GlanceEntityContainer extends StatelessWidget {
|
|||||||
|
|
||||||
final bool showName;
|
final bool showName;
|
||||||
final bool showState;
|
final bool showState;
|
||||||
|
final bool nameInTheBottom;
|
||||||
|
final double iconSize;
|
||||||
|
final double nameFontSize;
|
||||||
|
final bool wordsWrapInName;
|
||||||
|
|
||||||
GlanceEntityContainer({
|
GlanceEntityContainer({
|
||||||
Key key, @required this.showName, @required this.showState,
|
Key key,
|
||||||
|
@required this.showName,
|
||||||
|
@required this.showState,
|
||||||
|
this.nameInTheBottom: false,
|
||||||
|
this.iconSize: Sizes.iconSize,
|
||||||
|
this.nameFontSize: Sizes.smallFontSize,
|
||||||
|
this.wordsWrapInName: false
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper;
|
final EntityWrapper entityWrapper = EntityModel.of(context).entityWrapper;
|
||||||
List<Widget> result = [];
|
List<Widget> result = [];
|
||||||
if (showName) {
|
if (!nameInTheBottom) {
|
||||||
result.add(EntityName(
|
if (showName) {
|
||||||
padding: EdgeInsets.only(bottom: Sizes.rowPadding),
|
result.add(_buildName());
|
||||||
textOverflow: TextOverflow.ellipsis,
|
}
|
||||||
wordsWrap: false,
|
} else {
|
||||||
textAlign: TextAlign.center,
|
if (showState) {
|
||||||
fontSize: Sizes.smallFontSize,
|
result.add(_buildState());
|
||||||
));
|
}
|
||||||
}
|
}
|
||||||
result.add(
|
result.add(
|
||||||
EntityIcon(
|
EntityIcon(
|
||||||
padding: EdgeInsets.all(0.0),
|
padding: EdgeInsets.all(0.0),
|
||||||
iconSize: Sizes.iconSize,
|
iconSize: iconSize,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (showState) {
|
if (!nameInTheBottom) {
|
||||||
result.add(SimpleEntityState(
|
if (showState) {
|
||||||
textAlign: TextAlign.center,
|
result.add(_buildState());
|
||||||
expanded: false,
|
}
|
||||||
padding: EdgeInsets.only(top: Sizes.rowPadding),
|
} else {
|
||||||
));
|
result.add(_buildName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: InkResponse(
|
child: InkResponse(
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: BoxConstraints(minWidth: Sizes.iconSize*2),
|
constraints: BoxConstraints(minWidth: Sizes.iconSize * 2),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
//mainAxisAlignment: MainAxisAlignment.start,
|
//mainAxisAlignment: MainAxisAlignment.start,
|
||||||
@ -51,4 +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),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -94,11 +94,11 @@ class _CombinedHistoryChartWidgetState extends State<CombinedHistoryChartWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<charts.Series<EntityHistoryMoment, DateTime>> _parseHistory() {
|
List<charts.Series<EntityHistoryMoment, DateTime>> _parseHistory() {
|
||||||
TheLogger.debug(" parsing history...");
|
Logger.d(" parsing history...");
|
||||||
Map<String, List<EntityHistoryMoment>> numericDataLists = {};
|
Map<String, List<EntityHistoryMoment>> numericDataLists = {};
|
||||||
int colorIdCounter = 0;
|
int colorIdCounter = 0;
|
||||||
widget.config.numericAttributesToShow.forEach((String attrName) {
|
widget.config.numericAttributesToShow.forEach((String attrName) {
|
||||||
TheLogger.debug(" parsing attribute $attrName");
|
Logger.d(" parsing attribute $attrName");
|
||||||
List<EntityHistoryMoment> data = [];
|
List<EntityHistoryMoment> data = [];
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
for (var i = 0; i < widget.rawHistory.length; i++) {
|
for (var i = 0; i < widget.rawHistory.length; i++) {
|
||||||
@ -152,7 +152,7 @@ class _CombinedHistoryChartWidgetState extends State<CombinedHistoryChartWidget>
|
|||||||
}
|
}
|
||||||
List<charts.Series<EntityHistoryMoment, DateTime>> result = [];
|
List<charts.Series<EntityHistoryMoment, DateTime>> result = [];
|
||||||
numericDataLists.forEach((attrName, dataList) {
|
numericDataLists.forEach((attrName, dataList) {
|
||||||
TheLogger.debug(" adding ${dataList.length} data values");
|
Logger.d(" adding ${dataList.length} data values");
|
||||||
result.add(
|
result.add(
|
||||||
new charts.Series<EntityHistoryMoment, DateTime>(
|
new charts.Series<EntityHistoryMoment, DateTime>(
|
||||||
id: "value",
|
id: "value",
|
||||||
|
@ -42,7 +42,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
|
|||||||
void _loadHistory(HomeAssistant ha, String entityId) {
|
void _loadHistory(HomeAssistant ha, String entityId) {
|
||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
if (_historyLastUpdated != null) {
|
if (_historyLastUpdated != null) {
|
||||||
TheLogger.debug("History was updated ${now.difference(_historyLastUpdated).inSeconds} seconds ago");
|
Logger.d("History was updated ${now.difference(_historyLastUpdated).inSeconds} seconds ago");
|
||||||
}
|
}
|
||||||
if (_historyLastUpdated == null || now.difference(_historyLastUpdated).inSeconds > 30) {
|
if (_historyLastUpdated == null || now.difference(_historyLastUpdated).inSeconds > 30) {
|
||||||
_historyLastUpdated = now;
|
_historyLastUpdated = now;
|
||||||
@ -52,7 +52,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
|
|||||||
_needToUpdateHistory = false;
|
_needToUpdateHistory = false;
|
||||||
});
|
});
|
||||||
}).catchError((e) {
|
}).catchError((e) {
|
||||||
TheLogger.error("Error loading $entityId history: $e");
|
Logger.e("Error loading $entityId history: $e");
|
||||||
setState(() {
|
setState(() {
|
||||||
_history = [];
|
_history = [];
|
||||||
_needToUpdateHistory = false;
|
_needToUpdateHistory = false;
|
||||||
@ -122,7 +122,7 @@ class _EntityHistoryWidgetState extends State<EntityHistoryWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
TheLogger.debug(" Simple selected as default");
|
Logger.d(" Simple selected as default");
|
||||||
return SimpleStateHistoryChartWidget(
|
return SimpleStateHistoryChartWidget(
|
||||||
rawHistory: _history,
|
rawHistory: _history,
|
||||||
);
|
);
|
||||||
|
@ -54,7 +54,7 @@ class DateTimeStateWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
TheLogger.warning( "${entity.entityId} has no date and no time");
|
Logger.w( "${entity.entityId} has no date and no time");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,18 +5,24 @@ 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) {
|
||||||
final entityModel = EntityModel.of(context);
|
final entityModel = EntityModel.of(context);
|
||||||
|
String state = entityModel.entityWrapper.entity.displayState ?? "";
|
||||||
|
state = state.replaceAll("\n", "").replaceAll("\t", " ").trim();
|
||||||
|
while (state.contains(" ")){
|
||||||
|
state = state.replaceAll(" ", " ");
|
||||||
|
}
|
||||||
Widget result = Padding(
|
Widget result = Padding(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
child: Text(
|
child: Text(
|
||||||
"${entityModel.entityWrapper.entity.state} ${entityModel.entityWrapper.entity.unitOfMeasurement}",
|
"$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(
|
||||||
|
@ -85,7 +85,7 @@ class _TextInputStateWidgetState extends State<TextInputStateWidget> {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
TheLogger.warning( "Unsupported input mode for ${entity.entityId}");
|
Logger.w( "Unsupported input mode for ${entity.entityId}");
|
||||||
return SimpleEntityState();
|
return SimpleEntityState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,16 +61,16 @@ class HomeAssistant {
|
|||||||
_password = password;
|
_password = password;
|
||||||
_authType = authType;
|
_authType = authType;
|
||||||
_useLovelace = useLovelace;
|
_useLovelace = useLovelace;
|
||||||
TheLogger.debug( "Use lovelace is $_useLovelace");
|
Logger.d( "Use lovelace is $_useLovelace");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future fetch() {
|
Future fetch() {
|
||||||
if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) {
|
if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) {
|
||||||
TheLogger.warning("Previous fetch is not complited");
|
Logger.w("Previous fetch is not complited");
|
||||||
} else {
|
} else {
|
||||||
_fetchCompleter = new Completer();
|
_fetchCompleter = new Completer();
|
||||||
_fetchTimer = Timer(fetchTimeout, () {
|
_fetchTimer = Timer(fetchTimeout, () {
|
||||||
TheLogger.error( "Data fetching timeout");
|
Logger.e( "Data fetching timeout");
|
||||||
disconnect().then((_) {
|
disconnect().then((_) {
|
||||||
_completeFetching({
|
_completeFetching({
|
||||||
"errorCode": 9,
|
"errorCode": 9,
|
||||||
@ -90,7 +90,7 @@ class HomeAssistant {
|
|||||||
disconnect() async {
|
disconnect() async {
|
||||||
if ((_hassioChannel != null) && (_hassioChannel.closeCode == null) && (_hassioChannel.sink != null)) {
|
if ((_hassioChannel != null) && (_hassioChannel.closeCode == null) && (_hassioChannel.sink != null)) {
|
||||||
await _hassioChannel.sink.close().timeout(Duration(seconds: 3),
|
await _hassioChannel.sink.close().timeout(Duration(seconds: 3),
|
||||||
onTimeout: () => TheLogger.debug( "Socket sink closed")
|
onTimeout: () => Logger.d( "Socket sink closed")
|
||||||
);
|
);
|
||||||
await _socketSubscription.cancel();
|
await _socketSubscription.cancel();
|
||||||
_hassioChannel = null;
|
_hassioChannel = null;
|
||||||
@ -100,15 +100,15 @@ class HomeAssistant {
|
|||||||
|
|
||||||
Future _connection() {
|
Future _connection() {
|
||||||
if ((_connectionCompleter != null) && (!_connectionCompleter.isCompleted)) {
|
if ((_connectionCompleter != null) && (!_connectionCompleter.isCompleted)) {
|
||||||
TheLogger.debug("Previous connection is not complited");
|
Logger.d("Previous connection is not complited");
|
||||||
} else {
|
} else {
|
||||||
if ((_hassioChannel == null) || (_hassioChannel.closeCode != null)) {
|
if ((_hassioChannel == null) || (_hassioChannel.closeCode != null)) {
|
||||||
_connectionCompleter = new Completer();
|
_connectionCompleter = new Completer();
|
||||||
autoReconnect = false;
|
autoReconnect = false;
|
||||||
disconnect().then((_){
|
disconnect().then((_){
|
||||||
TheLogger.debug( "Socket connecting...");
|
Logger.d( "Socket connecting...");
|
||||||
_connectionTimer = Timer(connectTimeout, () {
|
_connectionTimer = Timer(connectTimeout, () {
|
||||||
TheLogger.error( "Socket connection timeout");
|
Logger.e( "Socket connection timeout");
|
||||||
_handleSocketError(null);
|
_handleSocketError(null);
|
||||||
});
|
});
|
||||||
if (_socketSubscription != null) {
|
if (_socketSubscription != null) {
|
||||||
@ -131,15 +131,15 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleSocketClose() {
|
void _handleSocketClose() {
|
||||||
TheLogger.debug("Socket disconnected. Automatic reconnect is $autoReconnect");
|
Logger.d("Socket disconnected. Automatic reconnect is $autoReconnect");
|
||||||
if (autoReconnect) {
|
if (autoReconnect) {
|
||||||
_reconnect();
|
_reconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSocketError(e) {
|
void _handleSocketError(e) {
|
||||||
TheLogger.error("Socket stream Error: $e");
|
Logger.e("Socket stream Error: $e");
|
||||||
TheLogger.debug("Automatic reconnect is $autoReconnect");
|
Logger.d("Automatic reconnect is $autoReconnect");
|
||||||
if (autoReconnect) {
|
if (autoReconnect) {
|
||||||
_reconnect();
|
_reconnect();
|
||||||
} else {
|
} else {
|
||||||
@ -186,7 +186,7 @@ class HomeAssistant {
|
|||||||
_fetchCompleter.completeError(error);
|
_fetchCompleter.completeError(error);
|
||||||
} else {
|
} else {
|
||||||
autoReconnect = true;
|
autoReconnect = true;
|
||||||
TheLogger.debug( "Fetch complete successful");
|
Logger.d( "Fetch complete successful");
|
||||||
_fetchCompleter.complete();
|
_fetchCompleter.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ class HomeAssistant {
|
|||||||
} else if (data["type"] == "auth_invalid") {
|
} else if (data["type"] == "auth_invalid") {
|
||||||
_completeConnecting({"errorCode": 6, "errorMessage": "${data["message"]}"});
|
_completeConnecting({"errorCode": 6, "errorMessage": "${data["message"]}"});
|
||||||
} else if (data["type"] == "result") {
|
} else if (data["type"] == "result") {
|
||||||
TheLogger.debug("[Received] <== id:${data["id"]}, ${data['success'] ? 'success' : 'error'}");
|
Logger.d("[Received] <== id:${data["id"]}, ${data['success'] ? 'success' : 'error'}");
|
||||||
if (data["id"] == _configMessageId) {
|
if (data["id"] == _configMessageId) {
|
||||||
_parseConfig(data);
|
_parseConfig(data);
|
||||||
} else if (data["id"] == _statesMessageId) {
|
} else if (data["id"] == _statesMessageId) {
|
||||||
@ -234,15 +234,15 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
} else if (data["type"] == "event") {
|
} else if (data["type"] == "event") {
|
||||||
if ((data["event"] != null) && (data["event"]["event_type"] == "state_changed")) {
|
if ((data["event"] != null) && (data["event"]["event_type"] == "state_changed")) {
|
||||||
TheLogger.debug("[Received] <== ${data['type']}.${data["event"]["event_type"]}: ${data["event"]["data"]["entity_id"]}");
|
Logger.d("[Received] <== ${data['type']}.${data["event"]["event_type"]}: ${data["event"]["data"]["entity_id"]}");
|
||||||
_handleEntityStateChange(data["event"]["data"]);
|
_handleEntityStateChange(data["event"]["data"]);
|
||||||
} else if (data["event"] != null) {
|
} else if (data["event"] != null) {
|
||||||
TheLogger.warning("Unhandled event type: ${data["event"]["event_type"]}");
|
Logger.w("Unhandled event type: ${data["event"]["event_type"]}");
|
||||||
} else {
|
} else {
|
||||||
TheLogger.error("Event is null: $message");
|
Logger.e("Event is null: $message");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TheLogger.warning("Unknown message type: $message");
|
Logger.w("Unknown message type: $message");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _sendAuthMessageRaw(String message) {
|
void _sendAuthMessageRaw(String message) {
|
||||||
TheLogger.debug( "[Sending] ==> auth request");
|
Logger.d( "[Sending] ==> auth request");
|
||||||
_hassioChannel.sink.add(message);
|
_hassioChannel.sink.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,11 +311,11 @@ class HomeAssistant {
|
|||||||
if (queued) _messageQueue.add(message);
|
if (queued) _messageQueue.add(message);
|
||||||
_connection().then((r) {
|
_connection().then((r) {
|
||||||
_messageQueue.getActualMessages().forEach((message){
|
_messageQueue.getActualMessages().forEach((message){
|
||||||
TheLogger.debug( "[Sending queued] ==> $message");
|
Logger.d( "[Sending queued] ==> $message");
|
||||||
_hassioChannel.sink.add(message);
|
_hassioChannel.sink.add(message);
|
||||||
});
|
});
|
||||||
if (!queued) {
|
if (!queued) {
|
||||||
TheLogger.debug( "[Sending] ==> $message");
|
Logger.d( "[Sending] ==> $message");
|
||||||
_hassioChannel.sink.add(message);
|
_hassioChannel.sink.add(message);
|
||||||
}
|
}
|
||||||
sendCompleter.complete();
|
sendCompleter.complete();
|
||||||
@ -367,8 +367,10 @@ class HomeAssistant {
|
|||||||
void _handleEntityStateChange(Map eventData) {
|
void _handleEntityStateChange(Map eventData) {
|
||||||
//TheLogger.debug( "New state for ${eventData['entity_id']}");
|
//TheLogger.debug( "New state for ${eventData['entity_id']}");
|
||||||
Map data = Map.from(eventData);
|
Map data = Map.from(eventData);
|
||||||
entities.updateState(data);
|
eventBus.fire(new StateChangedEvent(
|
||||||
eventBus.fire(new StateChangedEvent(data["entity_id"], null));
|
entityId: data["entity_id"],
|
||||||
|
needToRebuildUI: entities.updateState(data)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _parseConfig(Map data) {
|
void _parseConfig(Map data) {
|
||||||
@ -385,7 +387,7 @@ class HomeAssistant {
|
|||||||
_userName = data["result"]["name"];
|
_userName = data["result"]["name"];
|
||||||
} else {
|
} else {
|
||||||
_userName = null;
|
_userName = null;
|
||||||
TheLogger.warning("There was an error getting current user: $data");
|
Logger.w("There was an error getting current user: $data");
|
||||||
}
|
}
|
||||||
_userInfoCompleter.complete();
|
_userInfoCompleter.complete();
|
||||||
}
|
}
|
||||||
@ -398,19 +400,19 @@ class HomeAssistant {
|
|||||||
if (response["success"] == true) {
|
if (response["success"] == true) {
|
||||||
_rawLovelaceData = response["result"];
|
_rawLovelaceData = response["result"];
|
||||||
} else {
|
} else {
|
||||||
TheLogger.error("There was an error getting Lovelace config: $response");
|
Logger.e("There was an error getting Lovelace config: $response");
|
||||||
_rawLovelaceData = null;
|
_rawLovelaceData = null;
|
||||||
}
|
}
|
||||||
_lovelaceCompleter.complete();
|
_lovelaceCompleter.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _parseLovelace() {
|
void _parseLovelace() {
|
||||||
TheLogger.debug("--Title: ${_rawLovelaceData["title"]}");
|
Logger.d("--Title: ${_rawLovelaceData["title"]}");
|
||||||
ui.title = _rawLovelaceData["title"];
|
ui.title = _rawLovelaceData["title"];
|
||||||
int viewCounter = 0;
|
int viewCounter = 0;
|
||||||
TheLogger.debug("--Views count: ${_rawLovelaceData['views'].length}");
|
Logger.d("--Views count: ${_rawLovelaceData['views'].length}");
|
||||||
_rawLovelaceData["views"].forEach((rawView){
|
_rawLovelaceData["views"].forEach((rawView){
|
||||||
TheLogger.debug("----view id: ${rawView['id']}");
|
Logger.d("----view id: ${rawView['id']}");
|
||||||
HAView view = HAView(
|
HAView view = HAView(
|
||||||
count: viewCounter,
|
count: viewCounter,
|
||||||
id: "${rawView['id']}",
|
id: "${rawView['id']}",
|
||||||
@ -428,64 +430,63 @@ class HomeAssistant {
|
|||||||
List<HACard> _createLovelaceCards(List rawCards) {
|
List<HACard> _createLovelaceCards(List rawCards) {
|
||||||
List<HACard> result = [];
|
List<HACard> result = [];
|
||||||
rawCards.forEach((rawCard){
|
rawCards.forEach((rawCard){
|
||||||
|
bool isThereCardOptionsInside = rawCard["card"] != null;
|
||||||
|
HACard card = HACard(
|
||||||
|
id: "card",
|
||||||
|
name: isThereCardOptionsInside ? rawCard["card"]["title"] ?? rawCard["card"]["name"] : rawCard["title"] ?? rawCard["name"],
|
||||||
|
type: isThereCardOptionsInside ? rawCard["card"]['type'] : rawCard['type'],
|
||||||
|
columnsCount: isThereCardOptionsInside ? rawCard["card"]['columns'] ?? 4 : rawCard['columns'] ?? 4,
|
||||||
|
showName: isThereCardOptionsInside ? rawCard["card"]['show_name'] ?? true : rawCard['show_name'] ?? true,
|
||||||
|
showState: isThereCardOptionsInside ? rawCard["card"]['show_state'] ?? true : rawCard['show_state'] ?? true,
|
||||||
|
showEmpty: rawCard['show_empty'] ?? true,
|
||||||
|
stateFilter: rawCard['state_filter'] ?? []
|
||||||
|
);
|
||||||
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"],
|
if (entities.isExist(rawEntity)) {
|
||||||
type: rawCard['type'],
|
card.entities.add(EntityWrapper(entity: entities.get(rawEntity)));
|
||||||
columnsCount: rawCard['columns'] ?? 4,
|
}
|
||||||
showName: rawCard['show_name'] ?? true,
|
} else {
|
||||||
showState: rawCard['show_state'] ?? true,
|
if (entities.isExist(rawEntity["entity"])) {
|
||||||
);
|
Entity e = entities.get(rawEntity["entity"]);
|
||||||
rawCard["entities"]?.forEach((rawEntity) {
|
card.entities.add(
|
||||||
if (rawEntity is String) {
|
EntityWrapper(
|
||||||
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 = EntityTapAction.moreInfo;
|
|
||||||
String holdAction = EntityTapAction.none;
|
|
||||||
if (card.type == CardType.glance) {
|
|
||||||
tapAction = rawEntity["tap_action"] ?? EntityTapAction.moreInfo;
|
|
||||||
holdAction = rawEntity["hold_action"] ?? EntityTapAction.none;
|
|
||||||
}
|
|
||||||
card.entities.add(
|
|
||||||
EntityWrapper(
|
|
||||||
entity: e,
|
entity: e,
|
||||||
displayName: rawEntity["name"],
|
displayName: rawEntity["name"],
|
||||||
icon: rawEntity["icon"],
|
icon: rawEntity["icon"],
|
||||||
tapAction: tapAction,
|
uiAction: EntityUIAction(rawEntityData: rawEntity)
|
||||||
holdAction: holdAction,
|
)
|
||||||
tapActionService: rawEntity["service"],
|
);
|
||||||
tapActionServiceData: rawEntity["service_data"] ?? {"entity_id": e.entityId}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (rawCard["entity"] != null) {
|
|
||||||
var en = rawCard["entity"];
|
|
||||||
if (en is String) {
|
|
||||||
if (entities.isExist(en)) {
|
|
||||||
card.linkedEntity = EntityWrapper(entity: entities.get(en));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (entities.isExist(en["entity"])) {
|
|
||||||
card.linkedEntity = EntityWrapper(
|
|
||||||
entity: entities.get(en["entity"]),
|
|
||||||
icon: en["icon"],
|
|
||||||
displayName: en["name"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
result.add(card);
|
});
|
||||||
|
if (rawCard["entity"] != null) {
|
||||||
|
var en = rawCard["entity"];
|
||||||
|
if (en is String) {
|
||||||
|
if (entities.isExist(en)) {
|
||||||
|
Entity e = entities.get(en);
|
||||||
|
card.linkedEntityWrapper = EntityWrapper(
|
||||||
|
entity: e,
|
||||||
|
uiAction: EntityUIAction(rawEntityData: rawCard)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (entities.isExist(en["entity"])) {
|
||||||
|
Entity e = entities.get(en["entity"]);
|
||||||
|
card.linkedEntityWrapper = EntityWrapper(
|
||||||
|
entity: e,
|
||||||
|
icon: en["icon"],
|
||||||
|
displayName: en["name"],
|
||||||
|
uiAction: EntityUIAction(rawEntityData: rawCard)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
result.add(card);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -502,10 +503,10 @@ class HomeAssistant {
|
|||||||
void _createUI() {
|
void _createUI() {
|
||||||
ui = HomeAssistantUI();
|
ui = HomeAssistantUI();
|
||||||
if ((_useLovelace) && (_rawLovelaceData != null)) {
|
if ((_useLovelace) && (_rawLovelaceData != null)) {
|
||||||
TheLogger.debug("Creating Lovelace UI");
|
Logger.d("Creating Lovelace UI");
|
||||||
_parseLovelace();
|
_parseLovelace();
|
||||||
} else {
|
} else {
|
||||||
TheLogger.debug("Creating group-based UI");
|
Logger.d("Creating group-based UI");
|
||||||
int viewCounter = 0;
|
int viewCounter = 0;
|
||||||
if (!entities.hasDefaultView) {
|
if (!entities.hasDefaultView) {
|
||||||
HAView view = HAView(
|
HAView view = HAView(
|
||||||
@ -544,7 +545,7 @@ class HomeAssistant {
|
|||||||
//String endTime = formatDate(now, [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
//String endTime = formatDate(now, [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
||||||
String startTime = formatDate(now.subtract(Duration(hours: 24)), [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
String startTime = formatDate(now.subtract(Duration(hours: 24)), [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
||||||
String url = "$homeAssistantWebHost/api/history/period/$startTime?&filter_entity_id=$entityId";
|
String url = "$homeAssistantWebHost/api/history/period/$startTime?&filter_entity_id=$entityId";
|
||||||
TheLogger.debug("[Sending] ==> $url");
|
Logger.d("[Sending] ==> $url");
|
||||||
http.Response historyResponse;
|
http.Response historyResponse;
|
||||||
if (_authType == "access_token") {
|
if (_authType == "access_token") {
|
||||||
historyResponse = await http.get(url, headers: {
|
historyResponse = await http.get(url, headers: {
|
||||||
@ -559,7 +560,7 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
var history = json.decode(historyResponse.body);
|
var history = json.decode(historyResponse.body);
|
||||||
if (history is List) {
|
if (history is List) {
|
||||||
TheLogger.debug( "[Received] <== ${history.first.length} history recors");
|
Logger.d( "[Received] <== ${history.first.length} history recors");
|
||||||
return history;
|
return history;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
|
@ -19,7 +19,7 @@ class _LogViewPageState extends State<LogViewPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_loadLog() async {
|
_loadLog() async {
|
||||||
_logData = TheLogger.getLog();
|
_logData = Logger.getLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -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';
|
||||||
@ -78,23 +79,20 @@ 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_class/sizes_class.dart';
|
||||||
part 'ui_widgets/view.dart';
|
part 'ui_widgets/view.dart';
|
||||||
part 'ui_widgets/entities_card.dart';
|
part 'ui_widgets/card_widget.dart';
|
||||||
part 'ui_widgets/glance_card.dart';
|
|
||||||
part 'ui_widgets/unsupported_card.dart';
|
|
||||||
part 'ui_widgets/media_control_card.dart';
|
|
||||||
part 'ui_widgets/card_header_widget.dart';
|
part 'ui_widgets/card_header_widget.dart';
|
||||||
|
|
||||||
|
|
||||||
EventBus eventBus = new EventBus();
|
EventBus eventBus = new EventBus();
|
||||||
const String appName = "HA Client";
|
const String appName = "HA Client";
|
||||||
const appVersion = "0.3.10";
|
const appVersion = "0.3.13";
|
||||||
|
|
||||||
String homeAssistantWebHost;
|
String homeAssistantWebHost;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FlutterError.onError = (errorDetails) {
|
FlutterError.onError = (errorDetails) {
|
||||||
TheLogger.error( "${errorDetails.exception}");
|
Logger.e( "${errorDetails.exception}");
|
||||||
if (TheLogger.isInDebugMode) {
|
if (Logger.isInDebugMode) {
|
||||||
FlutterError.dumpErrorToConsole(errorDetails);
|
FlutterError.dumpErrorToConsole(errorDetails);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -102,9 +100,9 @@ void main() {
|
|||||||
runZoned(() {
|
runZoned(() {
|
||||||
runApp(new HAClientApp());
|
runApp(new HAClientApp());
|
||||||
}, onError: (error, stack) {
|
}, onError: (error, stack) {
|
||||||
TheLogger.error("$error");
|
Logger.e("$error");
|
||||||
TheLogger.error("$stack");
|
Logger.e("$stack");
|
||||||
if (TheLogger.isInDebugMode) {
|
if (Logger.isInDebugMode) {
|
||||||
debugPrint("$stack");
|
debugPrint("$stack");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -162,11 +160,11 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
_settingsLoaded = false;
|
_settingsLoaded = false;
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
TheLogger.debug("<!!!> Creating new HomeAssistant instance");
|
Logger.d("<!!!> Creating new HomeAssistant instance");
|
||||||
_homeAssistant = HomeAssistant();
|
_homeAssistant = HomeAssistant();
|
||||||
|
|
||||||
_settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) {
|
_settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) {
|
||||||
TheLogger.debug("Settings change event: reconnect=${event.reconnect}");
|
Logger.d("Settings change event: reconnect=${event.reconnect}");
|
||||||
if (event.reconnect) {
|
if (event.reconnect) {
|
||||||
_homeAssistant.disconnect().then((_){
|
_homeAssistant.disconnect().then((_){
|
||||||
_initialLoad();
|
_initialLoad();
|
||||||
@ -187,7 +185,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
TheLogger.debug("$state");
|
Logger.d("$state");
|
||||||
if (state == AppLifecycleState.resumed && _settingsLoaded) {
|
if (state == AppLifecycleState.resumed && _settingsLoaded) {
|
||||||
_refreshData();
|
_refreshData();
|
||||||
}
|
}
|
||||||
@ -214,7 +212,12 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
_subscribe() {
|
_subscribe() {
|
||||||
if (_stateSubscription == null) {
|
if (_stateSubscription == null) {
|
||||||
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
|
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
|
||||||
setState(() {});
|
if (event.needToRebuildUI) {
|
||||||
|
Logger.d("New entity. Need to rebuild UI");
|
||||||
|
_refreshData();
|
||||||
|
} else {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (_serviceCallSubscription == null) {
|
if (_serviceCallSubscription == null) {
|
||||||
@ -259,8 +262,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
|||||||
|
|
||||||
_setErrorState(e) {
|
_setErrorState(e) {
|
||||||
if (e is Error) {
|
if (e is Error) {
|
||||||
TheLogger.error(e.toString());
|
Logger.e(e.toString());
|
||||||
TheLogger.error("${e.stackTrace}");
|
Logger.e("${e.stackTrace}");
|
||||||
_showErrorBottomBar(
|
_showErrorBottomBar(
|
||||||
message: "There was some error",
|
message: "There was some error",
|
||||||
errorCode: 13
|
errorCode: 13
|
||||||
|
@ -41,8 +41,8 @@ class MaterialDesignIcons {
|
|||||||
"binary_sensor.heat.off": "mdi:thermometer",
|
"binary_sensor.heat.off": "mdi:thermometer",
|
||||||
"binary_sensor.light.on": "mdi:brightness-7",
|
"binary_sensor.light.on": "mdi:brightness-7",
|
||||||
"binary_sensor.light.off": "mdi:brightness-5",
|
"binary_sensor.light.off": "mdi:brightness-5",
|
||||||
//"binary_sensor.lock.on": "mdi:",
|
"binary_sensor.lock.on": "mdi:lock-open",
|
||||||
//"binary_sensor.lock.off": "mdi:",
|
"binary_sensor.lock.off": "mdi:lock",
|
||||||
"binary_sensor.moisture.on": "mdi:water",
|
"binary_sensor.moisture.on": "mdi:water",
|
||||||
"binary_sensor.moisture.off": "mdi:water-off",
|
"binary_sensor.moisture.off": "mdi:water-off",
|
||||||
"binary_sensor.motion.on": "mdi:run",
|
"binary_sensor.motion.on": "mdi:run",
|
||||||
@ -59,8 +59,8 @@ class MaterialDesignIcons {
|
|||||||
"binary_sensor.power.off": "mdi:verified",
|
"binary_sensor.power.off": "mdi:verified",
|
||||||
//"binary_sensor.presence.on": "mdi:",
|
//"binary_sensor.presence.on": "mdi:",
|
||||||
//"binary_sensor.presence.off": "mdi:",
|
//"binary_sensor.presence.off": "mdi:",
|
||||||
//"binary_sensor.problem.on": "mdi:",
|
"binary_sensor.problem.on": "mdi:alert-outline",
|
||||||
//"binary_sensor.problem.off": "mdi:",
|
"binary_sensor.problem.off": "mdi:check-outline",
|
||||||
"binary_sensor.safety.on": "mdi:alert",
|
"binary_sensor.safety.on": "mdi:alert",
|
||||||
"binary_sensor.safety.off": "mdi:verified",
|
"binary_sensor.safety.off": "mdi:verified",
|
||||||
"binary_sensor.smoke.on": "mdi:alert",
|
"binary_sensor.smoke.on": "mdi:alert",
|
||||||
@ -69,13 +69,13 @@ class MaterialDesignIcons {
|
|||||||
"binary_sensor.sound.off": "mdi:music-note-off",
|
"binary_sensor.sound.off": "mdi:music-note-off",
|
||||||
"binary_sensor.vibration.on": "mdi:vibrate",
|
"binary_sensor.vibration.on": "mdi:vibrate",
|
||||||
"binary_sensor.vibration.off": "mdi:mdi-crop-portrait",
|
"binary_sensor.vibration.off": "mdi:mdi-crop-portrait",
|
||||||
//"binary_sensor.window.on": "mdi:",
|
"binary_sensor.window.on": "mdi:window-open",
|
||||||
//"binary_sensor.window.off": "mdi:",
|
"binary_sensor.window.off": "mdi:window-closed",
|
||||||
"sensor.battery": "mdi:battery-80",
|
"sensor.battery": "mdi:battery-80",
|
||||||
"sensor.humidity": "mdi:water-percent",
|
"sensor.humidity": "mdi:water-percent",
|
||||||
//"sensor.illuminance": "mdi:",
|
//"sensor.illuminance": "mdi:",
|
||||||
"sensor.temperature": "mdi:thermometer",
|
"sensor.temperature": "mdi:thermometer",
|
||||||
//"cover.window": "mdi:",
|
"cover.window": "mdi:mdi:window-closed",
|
||||||
"cover.garage.closed": "mdi:garage",
|
"cover.garage.closed": "mdi:garage",
|
||||||
"cover.garage.open": "mdi:garage-open",
|
"cover.garage.open": "mdi:garage-open",
|
||||||
"cover.garage.opening": "mdi:garage-open",
|
"cover.garage.opening": "mdi:garage-open",
|
||||||
|
@ -83,13 +83,13 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
icon: Icon(Icons.check),
|
icon: Icon(Icons.check),
|
||||||
onPressed: (){
|
onPressed: (){
|
||||||
if (_checkConfigChanged()) {
|
if (_checkConfigChanged()) {
|
||||||
TheLogger.debug("Settings changed. Saving...");
|
Logger.d("Settings changed. Saving...");
|
||||||
_saveSettings().then((r) {
|
_saveSettings().then((r) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
eventBus.fire(SettingsChangedEvent(true));
|
eventBus.fire(SettingsChangedEvent(true));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
TheLogger.debug("Settings was not changed");
|
Logger.d("Settings was not changed");
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,6 +150,10 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
_newHassioPort = value;
|
_newHassioPort = value;
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
new Text(
|
||||||
|
"Try ports 80 and 443 if default is not working and you don't know why.",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
new Row(
|
new Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@ -170,6 +174,10 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
new Text(
|
||||||
|
"You should use access token for HA >= 0.84.1. Legacy password will not work there.",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
new TextField(
|
new TextField(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: _newAuthType == "access_token" ? "Access token" : "API password"
|
labelText: _newAuthType == "access_token" ? "Access token" : "API password"
|
||||||
|
@ -2,76 +2,45 @@ part of '../main.dart';
|
|||||||
|
|
||||||
class HACard {
|
class HACard {
|
||||||
List<EntityWrapper> entities = [];
|
List<EntityWrapper> entities = [];
|
||||||
EntityWrapper linkedEntity;
|
List<HACard> childCards = [];
|
||||||
|
EntityWrapper linkedEntityWrapper;
|
||||||
String name;
|
String name;
|
||||||
String id;
|
String id;
|
||||||
String type;
|
String type;
|
||||||
bool showName;
|
bool showName;
|
||||||
bool showState;
|
bool showState;
|
||||||
|
bool showEmpty;
|
||||||
int columnsCount;
|
int columnsCount;
|
||||||
|
List stateFilter;
|
||||||
|
|
||||||
HACard({
|
HACard({
|
||||||
this.name,
|
this.name,
|
||||||
this.id,
|
this.id,
|
||||||
this.linkedEntity,
|
this.linkedEntityWrapper,
|
||||||
this.columnsCount: 4,
|
this.columnsCount: 4,
|
||||||
this.showName: true,
|
this.showName: true,
|
||||||
this.showState: true,
|
this.showState: true,
|
||||||
|
this.stateFilter: const [],
|
||||||
|
this.showEmpty: true,
|
||||||
@required this.type
|
@required this.type
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget build(BuildContext context) {
|
List<EntityWrapper> getEntitiesToShow() {
|
||||||
switch (type) {
|
return entities.where((entityWrapper) {
|
||||||
|
if (entityWrapper.entity.isHidden) {
|
||||||
case CardType.entities: {
|
return false;
|
||||||
return EntitiesCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case CardType.glance: {
|
|
||||||
return GlanceCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case CardType.mediaControl: {
|
|
||||||
return MediaControlCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case CardType.weatherForecast:
|
|
||||||
case CardType.thermostat:
|
|
||||||
case CardType.sensor:
|
|
||||||
case CardType.plantStatus:
|
|
||||||
case CardType.pictureEntity:
|
|
||||||
case CardType.pictureElements:
|
|
||||||
case CardType.picture:
|
|
||||||
case CardType.map:
|
|
||||||
case CardType.iframe:
|
|
||||||
case CardType.gauge:
|
|
||||||
case CardType.entityButton:
|
|
||||||
case CardType.conditional:
|
|
||||||
case CardType.alarmPanel: {
|
|
||||||
return UnsupportedCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
if ((linkedEntity == null) && (entities.isNotEmpty)) {
|
|
||||||
return EntitiesCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return UnsupportedCardWidget(
|
|
||||||
card: this,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (stateFilter.isNotEmpty) {
|
||||||
|
return stateFilter.contains(entityWrapper.entity.state);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CardWidget(
|
||||||
|
card: this,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,9 +3,10 @@ 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 = 34.0;
|
static const largeIconSize = 46.0;
|
||||||
static const stateFontSize = 15.0;
|
static const stateFontSize = 15.0;
|
||||||
static const nameFontSize = 15.0;
|
static const nameFontSize = 15.0;
|
||||||
static const smallFontSize = 14.0;
|
static const smallFontSize = 14.0;
|
||||||
|
@ -28,8 +28,8 @@ class HAView {
|
|||||||
HACard card = HACard(
|
HACard card = HACard(
|
||||||
name: e.displayName,
|
name: e.displayName,
|
||||||
id: e.entityId,
|
id: e.entityId,
|
||||||
linkedEntity: EntityWrapper(entity: e),
|
linkedEntityWrapper: EntityWrapper(entity: e),
|
||||||
type: "media-control"
|
type: CardType.mediaControl
|
||||||
);
|
);
|
||||||
cards.add(card);
|
cards.add(card);
|
||||||
});
|
});
|
||||||
@ -40,7 +40,7 @@ class HAView {
|
|||||||
HACard card = HACard(
|
HACard card = HACard(
|
||||||
id: groupIdToAdd,
|
id: groupIdToAdd,
|
||||||
name: entity.domain,
|
name: entity.domain,
|
||||||
type: "entities"
|
type: CardType.entities
|
||||||
);
|
);
|
||||||
card.entities.add(EntityWrapper(entity: entity));
|
card.entities.add(EntityWrapper(entity: entity));
|
||||||
autoGeneratedCards.add(card);
|
autoGeneratedCards.add(card);
|
||||||
@ -51,16 +51,16 @@ class HAView {
|
|||||||
HACard card = HACard(
|
HACard card = HACard(
|
||||||
name: entity.displayName,
|
name: entity.displayName,
|
||||||
id: entity.entityId,
|
id: entity.entityId,
|
||||||
linkedEntity: EntityWrapper(entity: entity),
|
linkedEntityWrapper: EntityWrapper(entity: entity),
|
||||||
type: "entities"
|
type: CardType.entities
|
||||||
);
|
);
|
||||||
card.entities.addAll(entity.childEntities.where((entity) {return entity.domain != "media_player";}).map((e) {return EntityWrapper(entity: e);}));
|
card.entities.addAll(entity.childEntities.where((entity) {return entity.domain != "media_player";}).map((e) {return EntityWrapper(entity: e);}));
|
||||||
entity.childEntities.where((entity) {return entity.domain == "media_player";}).forEach((entity){
|
entity.childEntities.where((entity) {return entity.domain == "media_player";}).forEach((entity){
|
||||||
HACard mediaCard = HACard(
|
HACard mediaCard = HACard(
|
||||||
name: entity.displayName,
|
name: entity.displayName,
|
||||||
id: entity.entityId,
|
id: entity.entityId,
|
||||||
linkedEntity: EntityWrapper(entity: entity),
|
linkedEntityWrapper: EntityWrapper(entity: entity),
|
||||||
type: "media-control"
|
type: CardType.mediaControl
|
||||||
);
|
);
|
||||||
cards.add(mediaCard);
|
cards.add(mediaCard);
|
||||||
});
|
});
|
||||||
|
217
lib/ui_widgets/card_widget.dart
Normal file
217
lib/ui_widgets/card_widget.dart
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
part of '../main.dart';
|
||||||
|
|
||||||
|
class CardWidget extends StatelessWidget {
|
||||||
|
|
||||||
|
final HACard card;
|
||||||
|
|
||||||
|
const CardWidget({
|
||||||
|
Key key,
|
||||||
|
this.card
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if ((card.linkedEntityWrapper!= null) && (card.linkedEntityWrapper.entity.isHidden)) {
|
||||||
|
return Container(width: 0.0, height: 0.0,);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (card.type) {
|
||||||
|
|
||||||
|
case CardType.entities: {
|
||||||
|
return _buildEntitiesCard(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CardType.glance: {
|
||||||
|
return _buildGlanceCard(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CardType.mediaControl: {
|
||||||
|
return _buildMediaControlsCard(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CardType.entityButton: {
|
||||||
|
return _buildEntityButtonCard(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
case CardType.horizontalStack: {
|
||||||
|
if (card.childCards.isNotEmpty) {
|
||||||
|
List<Widget> children = [];
|
||||||
|
card.childCards.forEach((card) {
|
||||||
|
if (card.getEntitiesToShow().isNotEmpty || card.showEmpty) {
|
||||||
|
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.verticalStack: {
|
||||||
|
if (card.childCards.isNotEmpty) {
|
||||||
|
List<Widget> children = [];
|
||||||
|
card.childCards.forEach((card) {
|
||||||
|
children.add(
|
||||||
|
card.build(context)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: children,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Container(height: 0.0, width: 0.0,);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
if ((card.linkedEntityWrapper == null) && (card.entities.isNotEmpty)) {
|
||||||
|
return _buildEntitiesCard(context);
|
||||||
|
} else {
|
||||||
|
return _buildUnsupportedCard(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEntitiesCard(BuildContext context) {
|
||||||
|
List<EntityWrapper> entitiesToShow = card.getEntitiesToShow();
|
||||||
|
if (entitiesToShow.isEmpty && !card.showEmpty) {
|
||||||
|
return Container(height: 0.0, width: 0.0,);
|
||||||
|
}
|
||||||
|
List<Widget> body = [];
|
||||||
|
body.add(CardHeaderWidget(name: card.name));
|
||||||
|
entitiesToShow.forEach((EntityWrapper entity) {
|
||||||
|
if (!entity.entity.isHidden) {
|
||||||
|
body.add(
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
|
||||||
|
child: EntityModel(
|
||||||
|
entityWrapper: entity,
|
||||||
|
handleTap: true,
|
||||||
|
child: entity.entity.buildDefaultWidget(context)
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Card(
|
||||||
|
child: new Column(mainAxisSize: MainAxisSize.min, children: body)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildGlanceCard(BuildContext context) {
|
||||||
|
List<EntityWrapper> entitiesToShow = card.getEntitiesToShow();
|
||||||
|
if (entitiesToShow.isEmpty && !card.showEmpty) {
|
||||||
|
return Container(height: 0.0, width: 0.0,);
|
||||||
|
}
|
||||||
|
List<Widget> rows = [];
|
||||||
|
rows.add(CardHeaderWidget(name: card.name));
|
||||||
|
|
||||||
|
List<Widget> result = [];
|
||||||
|
int columnsCount = entitiesToShow.length >= card.columnsCount ? card.columnsCount : entitiesToShow.length;
|
||||||
|
|
||||||
|
entitiesToShow.forEach((EntityWrapper entity) {
|
||||||
|
result.add(
|
||||||
|
FractionallySizedBox(
|
||||||
|
widthFactor: 1/columnsCount,
|
||||||
|
child: EntityModel(
|
||||||
|
entityWrapper: entity,
|
||||||
|
child: GlanceEntityContainer(
|
||||||
|
showName: card.showName,
|
||||||
|
showState: card.showState,
|
||||||
|
),
|
||||||
|
handleTap: true
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
rows.add(
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, 2*Sizes.rowPadding),
|
||||||
|
child: Wrap(
|
||||||
|
//alignment: WrapAlignment.spaceAround,
|
||||||
|
runSpacing: Sizes.rowPadding*2,
|
||||||
|
children: result,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: new Column(mainAxisSize: MainAxisSize.min, children: rows)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMediaControlsCard(BuildContext context) {
|
||||||
|
if (card.linkedEntityWrapper == null || card.linkedEntityWrapper.entity == null) {
|
||||||
|
return Container(width: 0, height: 0,);
|
||||||
|
} else {
|
||||||
|
return Card(
|
||||||
|
child: EntityModel(
|
||||||
|
entityWrapper: card.linkedEntityWrapper,
|
||||||
|
handleTap: null,
|
||||||
|
child: MediaPlayerWidget()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEntityButtonCard(BuildContext context) {
|
||||||
|
if (card.linkedEntityWrapper == null || card.linkedEntityWrapper.entity == null) {
|
||||||
|
return Container(width: 0, height: 0,);
|
||||||
|
} else {
|
||||||
|
card.linkedEntityWrapper.displayName = card.name?.toUpperCase() ??
|
||||||
|
card.linkedEntityWrapper.displayName.toUpperCase();
|
||||||
|
return Card(
|
||||||
|
child: EntityModel(
|
||||||
|
entityWrapper: card.linkedEntityWrapper,
|
||||||
|
child: ButtonEntityContainer(),
|
||||||
|
handleTap: true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildUnsupportedCard(BuildContext context) {
|
||||||
|
List<Widget> body = [];
|
||||||
|
body.add(CardHeaderWidget(name: card.name ?? ""));
|
||||||
|
List<Widget> result = [];
|
||||||
|
if (card.linkedEntityWrapper != null) {
|
||||||
|
result.addAll(<Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
|
||||||
|
child: EntityModel(
|
||||||
|
entityWrapper: card.linkedEntityWrapper,
|
||||||
|
handleTap: true,
|
||||||
|
child: card.linkedEntityWrapper.entity.buildDefaultWidget(context)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
result.addAll(<Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding),
|
||||||
|
child: Text("'${card.type}' card is not supported yet"),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
body.addAll(result);
|
||||||
|
return Card(
|
||||||
|
child: new Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: body
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
part of '../main.dart';
|
|
||||||
|
|
||||||
class EntitiesCardWidget extends StatelessWidget {
|
|
||||||
|
|
||||||
final HACard card;
|
|
||||||
|
|
||||||
const EntitiesCardWidget({
|
|
||||||
Key key,
|
|
||||||
this.card
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if ((card.linkedEntity!= null) && (card.linkedEntity.entity.isHidden)) {
|
|
||||||
return Container(width: 0.0, height: 0.0,);
|
|
||||||
}
|
|
||||||
List<Widget> body = [];
|
|
||||||
body.add(CardHeaderWidget(name: card.name));
|
|
||||||
body.addAll(_buildCardBody(context));
|
|
||||||
return Card(
|
|
||||||
child: new Column(mainAxisSize: MainAxisSize.min, children: body)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _buildCardBody(BuildContext context) {
|
|
||||||
List<Widget> result = [];
|
|
||||||
card.entities.forEach((EntityWrapper entity) {
|
|
||||||
if (!entity.entity.isHidden) {
|
|
||||||
result.add(
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
|
|
||||||
child: EntityModel(
|
|
||||||
entityWrapper: entity,
|
|
||||||
handleTap: true,
|
|
||||||
child: entity.entity.buildDefaultWidget(context)
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
part of '../main.dart';
|
|
||||||
|
|
||||||
class GlanceCardWidget extends StatelessWidget {
|
|
||||||
|
|
||||||
final HACard card;
|
|
||||||
|
|
||||||
const GlanceCardWidget({
|
|
||||||
Key key,
|
|
||||||
this.card
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if ((card.linkedEntity!= null) && (card.linkedEntity.entity.isHidden)) {
|
|
||||||
return Container(width: 0.0, height: 0.0,);
|
|
||||||
}
|
|
||||||
List<Widget> rows = [];
|
|
||||||
rows.add(CardHeaderWidget(name: card.name));
|
|
||||||
rows.add(_buildRows(context));
|
|
||||||
return Card(
|
|
||||||
child: new Column(mainAxisSize: MainAxisSize.min, children: rows)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildRows(BuildContext context) {
|
|
||||||
List<Widget> result = [];
|
|
||||||
List<EntityWrapper> toShow = card.entities.where((entity) {return !entity.entity.isHidden;}).toList();
|
|
||||||
int columnsCount = toShow.length >= card.columnsCount ? card.columnsCount : toShow.length;
|
|
||||||
|
|
||||||
toShow.forEach((EntityWrapper entity) {
|
|
||||||
result.add(
|
|
||||||
FractionallySizedBox(
|
|
||||||
widthFactor: 1/columnsCount,
|
|
||||||
child: EntityModel(
|
|
||||||
entityWrapper: entity,
|
|
||||||
child: entity.entity.buildGlanceWidget(context, card.showName, card.showState),
|
|
||||||
handleTap: true
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, 2*Sizes.rowPadding),
|
|
||||||
child: Wrap(
|
|
||||||
//alignment: WrapAlignment.spaceAround,
|
|
||||||
runSpacing: Sizes.rowPadding*2,
|
|
||||||
children: result,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
part of '../main.dart';
|
|
||||||
|
|
||||||
class MediaControlCardWidget extends StatelessWidget {
|
|
||||||
|
|
||||||
final HACard card;
|
|
||||||
|
|
||||||
const MediaControlCardWidget({
|
|
||||||
Key key,
|
|
||||||
this.card
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if ((card.linkedEntity == null) || (card.linkedEntity.entity.isHidden)) {
|
|
||||||
return Container(width: 0.0, height: 0.0,);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Card(
|
|
||||||
child: EntityModel(
|
|
||||||
entityWrapper: card.linkedEntity,
|
|
||||||
handleTap: null,
|
|
||||||
child: MediaPlayerWidget()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
part of '../main.dart';
|
|
||||||
|
|
||||||
class UnsupportedCardWidget extends StatelessWidget {
|
|
||||||
|
|
||||||
final HACard card;
|
|
||||||
|
|
||||||
const UnsupportedCardWidget({
|
|
||||||
Key key,
|
|
||||||
this.card
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if ((card.linkedEntity!= null) && (card.linkedEntity.entity.isHidden)) {
|
|
||||||
return Container(width: 0.0, height: 0.0,);
|
|
||||||
}
|
|
||||||
List<Widget> body = [];
|
|
||||||
body.add(CardHeaderWidget(name: card.name ?? ""));
|
|
||||||
body.addAll(_buildCardBody(context));
|
|
||||||
return Card(
|
|
||||||
child: new Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: body
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Widget> _buildCardBody(BuildContext context) {
|
|
||||||
List<Widget> result = [];
|
|
||||||
if (card.linkedEntity != null) {
|
|
||||||
result.addAll(<Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(0.0, Sizes.rowPadding, 0.0, Sizes.rowPadding),
|
|
||||||
child: EntityModel(
|
|
||||||
entityWrapper: card.linkedEntity,
|
|
||||||
handleTap: true,
|
|
||||||
child: card.linkedEntity.entity.buildDefaultWidget(context)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
result.addAll(<Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding),
|
|
||||||
child: Text("'${card.type}' card is not supported yet"),
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -78,7 +78,7 @@ class ViewWidgetState extends State<ViewWidget> {
|
|||||||
|
|
||||||
Future _refreshData() {
|
Future _refreshData() {
|
||||||
if ((_refreshCompleter != null) && (!_refreshCompleter.isCompleted)) {
|
if ((_refreshCompleter != null) && (!_refreshCompleter.isCompleted)) {
|
||||||
TheLogger.debug("Previous data refresh is still in progress");
|
Logger.d("Previous data refresh is still in progress");
|
||||||
} else {
|
} else {
|
||||||
_refreshCompleter = Completer();
|
_refreshCompleter = Completer();
|
||||||
eventBus.fire(RefreshDataEvent());
|
eventBus.fire(RefreshDataEvent());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
part of 'main.dart';
|
part of 'main.dart';
|
||||||
|
|
||||||
class TheLogger {
|
class Logger {
|
||||||
|
|
||||||
static List<String> _log = [];
|
static List<String> _log = [];
|
||||||
|
|
||||||
@ -20,15 +20,15 @@ class TheLogger {
|
|||||||
return inDebugMode;
|
return inDebugMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void error(String message) {
|
static void e(String message) {
|
||||||
_writeToLog("Error", message);
|
_writeToLog("Error", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void warning(String message) {
|
static void w(String message) {
|
||||||
_writeToLog("Warning", message);
|
_writeToLog("Warning", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void debug(String message) {
|
static void d(String message) {
|
||||||
_writeToLog("Debug", message);
|
_writeToLog("Debug", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class HAUtils {
|
|||||||
if (await canLaunch(url)) {
|
if (await canLaunch(url)) {
|
||||||
await launch(url);
|
await launch(url);
|
||||||
} else {
|
} else {
|
||||||
TheLogger.error( "Could not launch $url");
|
Logger.e( "Could not launch $url");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,8 +58,13 @@ class HAUtils {
|
|||||||
class StateChangedEvent {
|
class StateChangedEvent {
|
||||||
String entityId;
|
String entityId;
|
||||||
String newState;
|
String newState;
|
||||||
|
bool needToRebuildUI;
|
||||||
|
|
||||||
StateChangedEvent(this.entityId, this.newState);
|
StateChangedEvent({
|
||||||
|
this.entityId,
|
||||||
|
this.newState,
|
||||||
|
this.needToRebuildUI: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsChangedEvent {
|
class SettingsChangedEvent {
|
||||||
|
12
pubspec.lock
12
pubspec.lock
@ -35,7 +35,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.5.0+1"
|
version: "0.5.1"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -83,7 +83,7 @@ packages:
|
|||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: c5727795659e886a7db8b39a14e2c8987280fe1f
|
resolved-ref: e26916e095244a7e5ea61315b030d298d127ed26
|
||||||
url: "https://github.com/MarkOSullivan94/dart_config.git"
|
url: "https://github.com/MarkOSullivan94/dart_config.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.5.0"
|
version: "0.5.0"
|
||||||
@ -126,7 +126,7 @@ packages:
|
|||||||
name: flutter_launcher_icons
|
name: flutter_launcher_icons
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.1"
|
version: "0.7.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -152,7 +152,7 @@ packages:
|
|||||||
name: image
|
name: image
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.4"
|
version: "2.0.5"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -290,7 +290,7 @@ packages:
|
|||||||
name: url_launcher
|
name: url_launcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.2"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -327,5 +327,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.15"
|
version: "2.1.15"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.0.0 <=2.1.0-dev.9.3.flutter-9c07fb64c4"
|
dart: ">=2.0.0 <3.0.0"
|
||||||
flutter: ">=0.5.6 <2.0.0"
|
flutter: ">=0.5.6 <2.0.0"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: hass_client
|
name: hass_client
|
||||||
description: Home Assistant Android Client
|
description: Home Assistant Android Client
|
||||||
|
|
||||||
version: 0.3.10+74
|
version: 0.3.13+80
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||||
|
Reference in New Issue
Block a user