2018-10-01 21:57:54 +03:00
|
|
|
part of '../main.dart';
|
|
|
|
|
|
|
|
class Entity {
|
|
|
|
static const STATE_ICONS_COLORS = {
|
|
|
|
"on": Colors.amber,
|
|
|
|
"off": Color.fromRGBO(68, 115, 158, 1.0),
|
|
|
|
"unavailable": Colors.black12,
|
|
|
|
"unknown": Colors.black12,
|
|
|
|
"playing": Colors.amber
|
|
|
|
};
|
|
|
|
static const RIGHT_WIDGET_PADDING = 14.0;
|
|
|
|
static const LEFT_WIDGET_PADDING = 8.0;
|
|
|
|
static const EXTENDED_WIDGET_HEIGHT = 50.0;
|
|
|
|
static const WIDGET_HEIGHT = 34.0;
|
|
|
|
static const ICON_SIZE = 28.0;
|
|
|
|
static const STATE_FONT_SIZE = 16.0;
|
|
|
|
static const NAME_FONT_SIZE = 16.0;
|
|
|
|
static const SMALL_FONT_SIZE = 14.0;
|
|
|
|
static const INPUT_WIDTH = 160.0;
|
|
|
|
|
|
|
|
Map _attributes;
|
|
|
|
String _domain;
|
|
|
|
String _entityId;
|
|
|
|
String _state;
|
|
|
|
DateTime _lastUpdated;
|
|
|
|
|
|
|
|
String get displayName =>
|
|
|
|
_attributes["friendly_name"] ?? (_attributes["name"] ?? "_");
|
|
|
|
String get domain => _domain;
|
|
|
|
String get entityId => _entityId;
|
|
|
|
String get state => _state;
|
|
|
|
set state(value) => _state = value;
|
|
|
|
|
|
|
|
String get deviceClass => _attributes["device_class"] ?? null;
|
|
|
|
bool get isView =>
|
|
|
|
(_domain == "group") &&
|
|
|
|
(_attributes != null ? _attributes["view"] ?? false : false);
|
|
|
|
bool get isGroup => _domain == "group";
|
|
|
|
String get icon => _attributes["icon"] ?? "";
|
|
|
|
bool get isOn => state == "on";
|
|
|
|
String get entityPicture => _attributes["entity_picture"];
|
|
|
|
String get unitOfMeasurement => _attributes["unit_of_measurement"] ?? "";
|
|
|
|
List get childEntities => _attributes["entity_id"] ?? [];
|
|
|
|
String get lastUpdated => _getLastUpdatedFormatted();
|
|
|
|
|
|
|
|
Entity(Map rawData) {
|
|
|
|
update(rawData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void update(Map rawData) {
|
|
|
|
_attributes = rawData["attributes"] ?? {};
|
|
|
|
_domain = rawData["entity_id"].split(".")[0];
|
|
|
|
_entityId = rawData["entity_id"];
|
|
|
|
_state = rawData["state"];
|
|
|
|
_lastUpdated = DateTime.tryParse(rawData["last_updated"]);
|
|
|
|
}
|
|
|
|
|
2018-10-02 00:41:40 +03:00
|
|
|
EntityWidget buildWidget(BuildContext context, bool inCard) {
|
|
|
|
return EntityWidget(
|
|
|
|
entity: this,
|
|
|
|
inCard: inCard,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:57:54 +03:00
|
|
|
String _getLastUpdatedFormatted() {
|
|
|
|
if (_lastUpdated == null) {
|
|
|
|
return "-";
|
|
|
|
} else {
|
|
|
|
DateTime now = DateTime.now();
|
|
|
|
Duration d = now.difference(_lastUpdated);
|
|
|
|
String text;
|
|
|
|
int v;
|
|
|
|
if (d.inDays == 0) {
|
|
|
|
if (d.inHours == 0) {
|
|
|
|
if (d.inMinutes == 0) {
|
|
|
|
text = "seconds ago";
|
|
|
|
v = d.inSeconds;
|
|
|
|
} else {
|
|
|
|
text = "minutes ago";
|
|
|
|
v = d.inMinutes;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
text = "hours ago";
|
|
|
|
v = d.inHours;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
text = "days ago";
|
|
|
|
v = d.inDays;
|
|
|
|
}
|
|
|
|
return "$v $text";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-02 00:41:40 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class EntityWidget extends StatefulWidget {
|
|
|
|
EntityWidget({Key key, this.entity, this.inCard}) : super(key: key);
|
|
|
|
|
|
|
|
final Entity entity;
|
|
|
|
final bool inCard;
|
|
|
|
|
|
|
|
@override
|
|
|
|
_EntityWidgetState createState() {
|
|
|
|
switch (entity.domain) {
|
|
|
|
case "automation":
|
|
|
|
case "input_boolean ":
|
|
|
|
case "switch":
|
|
|
|
case "light": {
|
|
|
|
return _SwitchEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
case "script":
|
|
|
|
case "scene": {
|
|
|
|
return _ButtonEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
case "input_datetime": {
|
|
|
|
return _DateTimeEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
case "input_select": {
|
|
|
|
return _SelectEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
case "input_number": {
|
|
|
|
return _SliderEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
case "input_text": {
|
|
|
|
return _TextEntityWidgetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
default: {
|
|
|
|
return _EntityWidgetState();
|
|
|
|
}
|
|
|
|
}
|
2018-10-01 21:57:54 +03:00
|
|
|
}
|
2018-10-02 00:41:40 +03:00
|
|
|
}
|
2018-10-01 21:57:54 +03:00
|
|
|
|
2018-10-02 00:41:40 +03:00
|
|
|
class _EntityWidgetState extends State<EntityWidget> {
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
if (widget.inCard) {
|
|
|
|
return _buildMainWidget(context);
|
|
|
|
} else {
|
|
|
|
return ListView(
|
|
|
|
children: <Widget>[
|
|
|
|
_buildMainWidget(context),
|
|
|
|
_buildLastUpdatedWidget()
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
2018-10-01 21:57:54 +03:00
|
|
|
}
|
|
|
|
|
2018-10-02 00:41:40 +03:00
|
|
|
Widget _buildMainWidget(BuildContext context) {
|
2018-10-01 21:57:54 +03:00
|
|
|
return SizedBox(
|
|
|
|
height: Entity.WIDGET_HEIGHT,
|
|
|
|
child: Row(
|
|
|
|
children: <Widget>[
|
|
|
|
GestureDetector(
|
|
|
|
child: _buildIconWidget(),
|
2018-10-02 00:41:40 +03:00
|
|
|
onTap: widget.inCard ? openEntityPage : null,
|
2018-10-01 21:57:54 +03:00
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: GestureDetector(
|
|
|
|
child: _buildNameWidget(),
|
2018-10-02 00:41:40 +03:00
|
|
|
onTap: widget.inCard ? openEntityPage : null,
|
2018-10-01 21:57:54 +03:00
|
|
|
),
|
|
|
|
),
|
2018-10-02 00:41:40 +03:00
|
|
|
_buildActionWidget(widget.inCard, context)
|
2018-10-01 21:57:54 +03:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-10-02 00:41:40 +03:00
|
|
|
void openEntityPage() {
|
|
|
|
eventBus.fire(new ShowEntityPageEvent(widget.entity));
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendNewState(newState) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-01 21:57:54 +03:00
|
|
|
Widget buildAdditionalWidget() {
|
|
|
|
return _buildLastUpdatedWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildIconWidget() {
|
|
|
|
return Padding(
|
|
|
|
padding: EdgeInsets.fromLTRB(Entity.LEFT_WIDGET_PADDING, 0.0, 12.0, 0.0),
|
|
|
|
child: MaterialDesignIcons.createIconWidgetFromEntityData(
|
2018-10-02 00:41:40 +03:00
|
|
|
widget.entity,
|
2018-10-01 21:57:54 +03:00
|
|
|
Entity.ICON_SIZE,
|
2018-10-02 00:41:40 +03:00
|
|
|
Entity.STATE_ICONS_COLORS[widget.entity.state] ?? Colors.blueGrey),
|
2018-10-01 21:57:54 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildLastUpdatedWidget() {
|
|
|
|
return Padding(
|
|
|
|
padding: EdgeInsets.fromLTRB(
|
|
|
|
Entity.LEFT_WIDGET_PADDING, Entity.SMALL_FONT_SIZE, 0.0, 0.0),
|
|
|
|
child: Text(
|
2018-10-02 00:41:40 +03:00
|
|
|
'${widget.entity.lastUpdated}',
|
2018-10-01 21:57:54 +03:00
|
|
|
textAlign: TextAlign.left,
|
|
|
|
style:
|
2018-10-02 00:41:40 +03:00
|
|
|
TextStyle(fontSize: Entity.SMALL_FONT_SIZE, color: Colors.black26),
|
2018-10-01 21:57:54 +03:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildNameWidget() {
|
|
|
|
return Padding(
|
|
|
|
padding: EdgeInsets.only(right: 10.0),
|
|
|
|
child: Text(
|
2018-10-02 00:41:40 +03:00
|
|
|
"${widget.entity.displayName}",
|
2018-10-01 21:57:54 +03:00
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
softWrap: false,
|
|
|
|
style: TextStyle(fontSize: Entity.NAME_FONT_SIZE),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildActionWidget(bool inCard, BuildContext context) {
|
|
|
|
return Padding(
|
|
|
|
padding:
|
2018-10-02 00:41:40 +03:00
|
|
|
EdgeInsets.fromLTRB(0.0, 0.0, Entity.RIGHT_WIDGET_PADDING, 0.0),
|
2018-10-01 21:57:54 +03:00
|
|
|
child: GestureDetector(
|
|
|
|
child: Text(
|
2018-10-02 00:41:40 +03:00
|
|
|
"${widget.entity.state}${widget.entity.unitOfMeasurement}",
|
2018-10-01 21:57:54 +03:00
|
|
|
textAlign: TextAlign.right,
|
|
|
|
style: new TextStyle(
|
|
|
|
fontSize: Entity.STATE_FONT_SIZE,
|
|
|
|
)),
|
|
|
|
onTap: openEntityPage,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|