diff --git a/images/hassio-192x192.png b/images/hassio-192x192.png new file mode 100644 index 0000000..3cd8005 Binary files /dev/null and b/images/hassio-192x192.png differ diff --git a/lib/data_model.dart b/lib/data_model.dart index 4f2147a..ebc1776 100644 --- a/lib/data_model.dart +++ b/lib/data_model.dart @@ -14,17 +14,21 @@ class HassioDataModel { int _statesMessageId = 0; int _servicesMessageId = 0; int _subscriptionMessageId = 0; + int _configMessageId = 0; Map _entitiesData = {}; Map _servicesData = {}; Map _uiStructure = {}; + Map _instanceConfig = {}; Completer _fetchCompleter; Completer _statesCompleter; Completer _servicesCompleter; + Completer _configCompleter; Timer _fetchingTimer; Map get entities => _entitiesData; Map get services => _servicesData; Map get uiStructure => _uiStructure; + Map get instanceConfig => _instanceConfig; HassioDataModel(String url, String password) { _hassioAPIEndpoint = url; @@ -75,20 +79,30 @@ class HassioDataModel { } _getData() { - _getStates().then((result) { - _getServices().then((result) { - _fetchingTimer.cancel(); - _fetchCompleter.complete(); + _getConfig().then((result) { + _getStates().then((result) { + _getServices().then((result) { + _finishFetching(null); + }).catchError((e) { + _finishFetching(e); + }); }).catchError((e) { - _fetchingTimer.cancel(); - _fetchCompleter.completeError(e); + _finishFetching(e); }); }).catchError((e) { - _fetchingTimer.cancel(); - _fetchCompleter.completeError(e); + _finishFetching(e); }); } + _finishFetching(error) { + _fetchingTimer.cancel(); + if (error != null) { + _fetchCompleter.completeError(error); + } else { + _fetchCompleter.complete(); + } + } + _handleMessage(Completer connectionCompleter, String message) { var data = json.decode(message); debugPrint("[Received]Message type: ${data['type']}"); @@ -101,7 +115,10 @@ class HassioDataModel { connectionCompleter.completeError({message: "Auth error: ${data["message"]}"}); } else if (data["type"] == "result") { if (data["success"] == true) { - if (data["id"] == _statesMessageId) { + if (data["id"] == _configMessageId) { + _parseConfig(data["result"]); + _configCompleter.complete(); + } else if (data["id"] == _statesMessageId) { _parseEntities(data["result"]); _statesCompleter.complete(); } else if (data["id"] == _servicesMessageId) { @@ -142,11 +159,20 @@ class HassioDataModel { _sendMessageRaw('{"id": $_subscriptionMessageId, "type": "subscribe_events", "event_type": "state_changed"}'); } + Future _getConfig() { + _configCompleter = new Completer(); + _incrementMessageId(); + _configMessageId = _currentMssageId; + _sendMessageRaw('{"id": $_configMessageId, "type": "get_config"}'); + + return _configCompleter.future; + } + Future _getStates() { _statesCompleter = new Completer(); _incrementMessageId(); _statesMessageId = _currentMssageId; - _sendMessageRaw('{"id": $_currentMssageId, "type": "get_states"}'); + _sendMessageRaw('{"id": $_statesMessageId, "type": "get_states"}'); return _statesCompleter.future; } @@ -155,7 +181,7 @@ class HassioDataModel { _servicesCompleter = new Completer(); _incrementMessageId(); _servicesMessageId = _currentMssageId; - _sendMessageRaw('{"id": $_currentMssageId, "type": "get_services"}'); + _sendMessageRaw('{"id": $_servicesMessageId, "type": "get_services"}'); return _servicesCompleter.future; } @@ -171,8 +197,16 @@ class HassioDataModel { void _handleEntityStateChange(Map eventData) { String entityId = eventData["entity_id"]; - _entitiesData[entityId].addAll(eventData["new_state"]); - eventBus.fire(new StateChangedEvent(eventData["entity_id"])); + if (_entitiesData[entityId] != null) { + _entitiesData[entityId].addAll(eventData["new_state"]); + eventBus.fire(new StateChangedEvent(eventData["entity_id"])); + } else { + debugPrint("Unknown enity $entityId"); + } + } + + void _parseConfig(Map data) { + _instanceConfig = Map.from(data); } void _parseServices(Map data) { diff --git a/lib/main.dart b/lib/main.dart index 6026bef..f012734 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,7 +29,7 @@ class HassClientApp extends StatelessWidget { initialRoute: "/", routes: { "/": (context) => MainPage(title: 'Hass Client'), - "/settings": (context) => SettingsPage(title: "Settings") + "/connection-settings": (context) => ConnectionSettingsPage(title: "Connection Settings") }, ); } @@ -48,8 +48,10 @@ class _MainPageState extends State with WidgetsBindingObserver { HassioDataModel _dataModel; Map _entitiesData; Map _uiStructure; + Map _instanceConfig; int _uiViewsCount = 0; String _dataModelErrorMessage = ""; + String _instanceHost; bool loading = true; Map _stateIconColors = { "on": Colors.amber, @@ -76,10 +78,13 @@ class _MainPageState extends State with WidgetsBindingObserver { _init() async { SharedPreferences prefs = await SharedPreferences.getInstance(); + String domain = prefs.getString('hassio-domain'); + String port = prefs.getString('hassio-port'); + _instanceHost = domain+":"+port; String _hassioAPIEndpoint = prefs.getString('hassio-protocol')+"://" + - prefs.getString('hassio-domain') + + domain + ":" + - prefs.getString('hassio-port') + + port + "/api/websocket"; String _hassioPassword = prefs.getString('hassio-password'); _dataModel = HassioDataModel(_hassioAPIEndpoint, _hassioPassword); @@ -100,6 +105,7 @@ class _MainPageState extends State with WidgetsBindingObserver { if (_dataModel != null) { await _dataModel.fetch().then((result) { setState(() { + _instanceConfig = _dataModel.instanceConfig; _entitiesData = _dataModel.entities; _uiStructure = _dataModel.uiStructure; _uiViewsCount = _uiStructure.length; @@ -249,15 +255,15 @@ class _MainPageState extends State with WidgetsBindingObserver { Widget _buildTitle() { Row titleRow = Row( - children: [Text(widget.title)], + children: [Text(_instanceConfig != null ? _instanceConfig["location_name"] : "...")], ); if (loading) { titleRow.children.add(Padding( child: JumpingDotsProgressIndicator( - fontSize: 30.0, + fontSize: 26.0, 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, 30.0), )); } return titleRow; @@ -268,18 +274,15 @@ class _MainPageState extends State with WidgetsBindingObserver { child: ListView( children: [ new UserAccountsDrawerHeader( - accountName: Text("Edwin Home"), - accountEmail: Text("edwin-home.duckdns.org"), - currentAccountPicture: new CircleAvatar( - backgroundImage: new NetworkImage( - "https://edwin-home.duckdns.org:8123/static/icons/favicon-192x192.png"), - ), + accountName: Text(_instanceConfig != null ? _instanceConfig["location_name"] : "Unknown"), + accountEmail: Text(_instanceHost ?? "Not configured"), + currentAccountPicture: new Image.asset('images/hassio-192x192.png'), ), new ListTile( leading: Icon(Icons.settings), - title: Text("Settings"), + title: Text("Connection settings"), onTap: () { - Navigator.pushNamed(context, '/settings'); + Navigator.pushNamed(context, '/connection-settings'); }, ), new AboutListTile( @@ -309,7 +312,7 @@ class _MainPageState extends State with WidgetsBindingObserver { Padding( padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 10.0), child: Text( - _dataModelErrorMessage != null ? "Well... no.\n\nThere was an error: $_dataModelErrorMessage\n\nCheck your internet connection or something" : "Loading... or not...\n\nJust wait 10 seconds", + _dataModelErrorMessage != null ? "Well... no.\n\nThere was an error: $_dataModelErrorMessage\n\nCheck your internet connection or restart the app" : "Loading... I hope...", textAlign: TextAlign.center, style: TextStyle(fontSize: 16.0), ), diff --git a/lib/settings.dart b/lib/settings.dart index b8cae69..8fffbf8 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -1,15 +1,15 @@ part of 'main.dart'; -class SettingsPage extends StatefulWidget { - SettingsPage({Key key, this.title}) : super(key: key); +class ConnectionSettingsPage extends StatefulWidget { + ConnectionSettingsPage({Key key, this.title}) : super(key: key); final String title; @override - _SettingsPageState createState() => new _SettingsPageState(); + _ConnectionSettingsPageState createState() => new _ConnectionSettingsPageState(); } -class _SettingsPageState extends State { +class _ConnectionSettingsPageState extends State { String _hassioDomain = ""; String _hassioPort = ""; String _hassioPassword = ""; diff --git a/pubspec.yaml b/pubspec.yaml index 0880f73..800bd32 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -40,9 +40,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - images/hassio-192x192.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.io/assets-and-images/#resolution-aware.