[#25, #27, #15] Improve entities view, add units of measurement, icons

This commit is contained in:
estevez 2018-09-16 00:06:07 +03:00
parent b9e07abba9
commit c0fb90d480
4 changed files with 91 additions and 80 deletions

Binary file not shown.

View File

@ -13,6 +13,18 @@ class HassioDataModel {
Completer _fetchCompleter; Completer _fetchCompleter;
Completer _statesCompleter; Completer _statesCompleter;
Completer _servicesCompleter; Completer _servicesCompleter;
Map _icons = {
"light": 0xf335,
"switch": 0xf241,
"binary_sensor": 0xf130,
"group": 0xf2b1,
"sensor": 0xf208,
"automation": 0xf411,
"script": 0xf219,
"input_boolean": 0xf1de,
"input_datetime": 0xf953,
"sun": 0xf5a8
};
Map get entities => _entitiesData; Map get entities => _entitiesData;
Map get services => _servicesData; Map get services => _servicesData;
@ -159,15 +171,14 @@ class HassioDataModel {
composedEntity["display_name"] = "${entity["attributes"]!=null ? entity["attributes"]["friendly_name"] ?? entity["attributes"]["name"] : "_"}"; composedEntity["display_name"] = "${entity["attributes"]!=null ? entity["attributes"]["friendly_name"] ?? entity["attributes"]["name"] : "_"}";
composedEntity["domain"] = entityDomain; composedEntity["domain"] = entityDomain;
if ((entityDomain == "automation") || (entityDomain == "switch")) { if ((entityDomain == "automation") || (entityDomain == "switch") || (entityDomain == "light")) {
composedEntity["actionType"] = "switch"; composedEntity["actionType"] = "switch";
} else if (entityDomain == "light") {
composedEntity["actionType"] = "stateIcon";
} else if ((entityDomain == "script") || (entityDomain == "scene")) { } else if ((entityDomain == "script") || (entityDomain == "scene")) {
composedEntity["actionType"] = "statelessIcon"; composedEntity["actionType"] = "statelessIcon";
} else { } else {
composedEntity["actionType"] = "stateText"; composedEntity["actionType"] = "stateText";
} }
composedEntity["iconCode"] = _icons[entityDomain] ?? 0xf485;
_entitiesData[entityId] = Map.from(composedEntity); _entitiesData[entityId] = Map.from(composedEntity);
}); });

View File

@ -41,12 +41,18 @@ class MainPage extends StatefulWidget {
} }
class _MainPageState extends State<MainPage> { class _MainPageState extends State<MainPage> {
HassioDataModel _dataModel; HassioDataModel _dataModel;
Map _entitiesData; Map _entitiesData;
Map _uiStructure; Map _uiStructure;
String _dataModelErrorMessage = ""; String _dataModelErrorMessage = "";
bool loading = true; bool loading = true;
Map _stateIconColors = {
"on": Colors.amber,
"off": Colors.blueGrey,
"unavailable": Colors.black12,
"unknown": Colors.black12,
"playing": Colors.amber
};
@override @override
void initState() { void initState() {
@ -56,7 +62,11 @@ class _MainPageState extends State<MainPage> {
_initClient() async { _initClient() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); SharedPreferences prefs = await SharedPreferences.getInstance();
String _hassioAPIEndpoint = "wss://" + prefs.getString('hassio-domain') +":" + prefs.getString('hassio-port') + "/api/websocket"; String _hassioAPIEndpoint = "wss://" +
prefs.getString('hassio-domain') +
":" +
prefs.getString('hassio-port') +
"/api/websocket";
String _hassioPassword = prefs.getString('hassio-password'); String _hassioPassword = prefs.getString('hassio-password');
_dataModel = HassioDataModel(_hassioAPIEndpoint, _hassioPassword); _dataModel = HassioDataModel(_hassioAPIEndpoint, _hassioPassword);
await _refreshData(); await _refreshData();
@ -85,65 +95,55 @@ class _MainPageState extends State<MainPage> {
Widget _buildEntityAction(String entityId) { Widget _buildEntityAction(String entityId) {
var entity = _entitiesData[entityId]; var entity = _entitiesData[entityId];
Widget result;
if (entity["actionType"] == "switch") { if (entity["actionType"] == "switch") {
return Switch( result = Switch(
value: (entity["state"] == "on"), value: (entity["state"] == "on"),
onChanged: ((state) { onChanged: ((state) {
_dataModel.callService(entity["domain"], state ? "turn_on" : "turn_off", entityId); _dataModel.callService(
entity["domain"], state ? "turn_on" : "turn_off", entityId);
setState(() { setState(() {
_entitiesData[entityId]["state"] = state ? "on" : "off"; _entitiesData[entityId]["state"] = state ? "on" : "off";
}); });
}), }),
); );
} else if (entity["actionType"] == "statelessIcon") {
result = SizedBox(
width: 60.0,
child: FlatButton(
onPressed: (() {
_dataModel.callService(entity["domain"], "turn_on", entityId);
}),
child: Text(
"Run",
textAlign: TextAlign.right,
style: new TextStyle(fontSize: 16.0, color: Colors.blue),
),
));
} else { } else {
return Text( result = Padding(
"${entity["state"]}" padding: EdgeInsets.fromLTRB(0.0, 0.0, 16.0, 0.0),
); child: Text(
"${entity["state"]}${(entity["attributes"] != null && entity["attributes"]["unit_of_measurement"] != null) ? entity["attributes"]["unit_of_measurement"] : ''}",
textAlign: TextAlign.right,
style: new TextStyle(
fontSize: 16.0,
)));
} }
/*return SizedBox(
width: 60.0,
// height: double.infinity,
child: result
);*/
return result;
} }
/* Widget buildEntityCard(String entityId) {
var data = _entitiesData[entityId];
if (data != null) {
return Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
leading: const Icon(Icons.device_hub),
subtitle: Text("${data['entity_id']}"),
trailing: Text("${data["state"]}"),
title: Text("${data["display_name"]}"),
),
new ButtonTheme
.bar( // make buttons use the appropriate styles for cards
child: buildEntityButtons(data['entity_id']),
),
],
),
);
} else {
return Card(
child: new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text("Unknown entity: $entityId")
],
),
);
}
}*/
Card _buildEntityGroup(List<String> ids, String name) { Card _buildEntityGroup(List<String> ids, String name) {
List<Widget> body = []; List<Widget> body = [];
body.add(_buildEntityGroupHeader(name)); body.add(_buildEntityGroupHeader(name));
body.addAll(_buildEntityGroupBody(ids)); body.addAll(_buildEntityGroupBody(ids));
Card result = Card( Card result =
child: new Column( Card(child: new Column(mainAxisSize: MainAxisSize.min, children: body));
mainAxisSize: MainAxisSize.min,
children: body
)
);
return result; return result;
} }
@ -154,12 +154,10 @@ class _MainPageState extends State<MainPage> {
//leading: const Icon(Icons.device_hub), //leading: const Icon(Icons.device_hub),
//subtitle: Text(".."), //subtitle: Text(".."),
//trailing: Text("${data["state"]}"), //trailing: Text("${data["state"]}"),
title: Text( title: Text("$name",
"$name",
textAlign: TextAlign.left, textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: new TextStyle(fontWeight: FontWeight.bold, fontSize: 25.0) style: new TextStyle(fontWeight: FontWeight.bold, fontSize: 25.0)),
),
); );
} else { } else {
result = new Container(width: 0.0, height: 0.0); result = new Container(width: 0.0, height: 0.0);
@ -169,32 +167,34 @@ class _MainPageState extends State<MainPage> {
List<Widget> _buildEntityGroupBody(List<String> ids) { List<Widget> _buildEntityGroupBody(List<String> ids) {
List<Widget> entities = []; List<Widget> entities = [];
ids.forEach((id){ ids.forEach((id) {
var data = _entitiesData[id]; var data = _entitiesData[id];
entities.add( entities.add(new ListTile(
new ListTile( leading: Icon(
leading: const Icon(Icons.device_hub), IconData(data["iconCode"], fontFamily: 'Material Design Icons'),
//subtitle: Text("${data['entity_id']}"), color: _stateIconColors[data["state"]] ?? Colors.blueGrey,
trailing: _buildEntityAction(id), ),
title: Text( //subtitle: Text("${data['entity_id']}"),
"${data["display_name"]}", trailing: _buildEntityAction(id),
overflow: TextOverflow.ellipsis, title: Text(
), "${data["display_name"]}",
) overflow: TextOverflow.ellipsis,
); ),
));
}); });
return entities; return entities;
} }
List<Widget> buildEntitiesView() { List<Widget> buildEntitiesView() {
if ((_entitiesData != null)&&(_uiStructure != null)) { if ((_entitiesData != null) && (_uiStructure != null)) {
List<Widget> result = []; List<Widget> result = [];
if (_dataModelErrorMessage.length == 0) { if (_dataModelErrorMessage.length == 0) {
_uiStructure["standalone"].forEach((entityId) { _uiStructure["standalone"].forEach((entityId) {
result.add(_buildEntityGroup([entityId], "")); result.add(_buildEntityGroup([entityId], ""));
}); });
_uiStructure["groups"].forEach((group) { _uiStructure["groups"].forEach((group) {
result.add(_buildEntityGroup(group["children"], group["friendly_name"].toString())); result.add(_buildEntityGroup(
group["children"], group["friendly_name"].toString()));
}); });
} else { } else {
//TODO //TODO
@ -209,9 +209,7 @@ class _MainPageState extends State<MainPage> {
Widget _buildTitle() { Widget _buildTitle() {
Row titleRow = Row( Row titleRow = Row(
children: <Widget>[ children: <Widget>[Text(widget.title)],
Text(widget.title)
],
); );
if (loading) { if (loading) {
titleRow.children.add(Padding( titleRow.children.add(Padding(
@ -220,8 +218,7 @@ class _MainPageState extends State<MainPage> {
color: Colors.white, color: Colors.white,
), ),
padding: const EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 40.0), padding: const EdgeInsets.fromLTRB(5.0, 0.0, 0.0, 40.0),
) ));
);
} }
return titleRow; return titleRow;
} }
@ -244,11 +241,12 @@ class _MainPageState extends State<MainPage> {
child: ListView( child: ListView(
children: <Widget>[ children: <Widget>[
new UserAccountsDrawerHeader( new UserAccountsDrawerHeader(
accountName: Text("Edwin Home"), accountName: Text("Edwin Home"),
accountEmail: Text("edwin-home.duckdns.org"), accountEmail: Text("edwin-home.duckdns.org"),
currentAccountPicture: new CircleAvatar( currentAccountPicture: new CircleAvatar(
backgroundImage: new NetworkImage("https://edwin-home.duckdns.org:8123/static/icons/favicon-192x192.png"), backgroundImage: new NetworkImage(
), "https://edwin-home.duckdns.org:8123/static/icons/favicon-192x192.png"),
),
), ),
new ListTile( new ListTile(
leading: Icon(Icons.settings), leading: Icon(Icons.settings),
@ -265,9 +263,7 @@ class _MainPageState extends State<MainPage> {
], ],
), ),
), ),
body: ListView( body: ListView(children: buildEntitiesView()),
children: buildEntitiesView()
),
floatingActionButton: new FloatingActionButton( floatingActionButton: new FloatingActionButton(
onPressed: _refreshData, onPressed: _refreshData,
tooltip: 'Increment', tooltip: 'Increment',

View File

@ -7,7 +7,7 @@ description: Home Assistant Android Client
# Both the version and the builder number may be overridden in flutter # Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively. # build by specifying --build-name and --build-number, respectively.
# Read more about versioning at semver.org. # Read more about versioning at semver.org.
version: 0.0.0+11 version: 0.0.3
environment: environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0" sdk: ">=2.0.0-dev.68.0 <3.0.0"
@ -54,6 +54,10 @@ flutter:
# "family" key with the font family name, and a "fonts" key with a # "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For # list giving the asset and other descriptors for the font. For
# example: # example:
fonts:
- family: "Material Design Icons"
fonts:
- asset: fonts/materialdesignicons-webfont.ttf
# fonts: # fonts:
# - family: Schyler # - family: Schyler
# fonts: # fonts: