diff --git a/lib/main.dart b/lib/main.dart index 44c1baa..6d45848 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -153,6 +153,7 @@ part 'pages/whats_new.page.dart'; part 'pages/fullscreen.page.dart'; part 'popups.dart'; part 'cards/badges.dart'; +part 'managers/app_settings.dart'; EventBus eventBus = new EventBus(); final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); diff --git a/lib/managers/app_settings.dart b/lib/managers/app_settings.dart new file mode 100644 index 0000000..27d149e --- /dev/null +++ b/lib/managers/app_settings.dart @@ -0,0 +1,74 @@ +part of '../main.dart'; + +class AppSettings { + + static final AppSettings _instance = AppSettings._internal(); + + factory AppSettings() { + return _instance; + } + + AppSettings._internal(); + + String mobileAppDeviceName; + String _domain; + String _port; + String displayHostname; + String webSocketAPIEndpoint; + String httpWebHost; + String _token; + String _tempToken; + String oauthUrl; + String webhookId; + double haVersion; + bool scrollBadges; + int appIntegrationVersion; + + bool get isAuthenticated => _token != null; + + Future load(bool quick) async { + if (!quick) { + SharedPreferences prefs = await SharedPreferences.getInstance(); + _domain = prefs.getString('hassio-domain'); + _port = prefs.getString('hassio-port'); + webhookId = prefs.getString('app-webhook-id'); + mobileAppDeviceName = prefs.getString('app-integration-device-name'); + appIntegrationVersion = prefs.getInt('app-integration-version') ?? 0; + scrollBadges = prefs.getBool('scroll-badges') ?? true; + displayHostname = "$_domain:$_port"; + _webSocketAPIEndpoint = + "${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket"; + httpWebHost = + "${prefs.getString('hassio-res-protocol')}://$_domain:$_port"; + try { + final storage = new FlutterSecureStorage(); + _token = await storage.read(key: "hacl_llt"); + Logger.d("Long-lived token read successful"); + oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent( + 'https://ha-client.app')}&redirect_uri=${Uri + .encodeComponent( + 'https://ha-client.app/service/auth_callback.html')}"; + } catch (e, stacktrace) { + Logger.e("Error reading secure storage: $e", stacktrace: stacktrace); + } + } + } + + Future startAuth() { + return AuthManager().start( + oauthUrl: oauthUrl + ).then((token) { + Logger.d("Token from AuthManager recived"); + _tempToken = token; + }); + } + + bool isNotConfigured() { + return _domain == null && _port == null && webhookId == null && mobileAppDeviceName == null; + } + + bool isSomethingMissed() { + return (_domain == null) || (_port == null) || (_domain.isEmpty) || (_port.isEmpty); + } + +} \ No newline at end of file diff --git a/lib/managers/connection_manager.class.dart b/lib/managers/connection_manager.class.dart index 9f74304..85ed2a5 100644 --- a/lib/managers/connection_manager.class.dart +++ b/lib/managers/connection_manager.class.dart @@ -10,25 +10,11 @@ class ConnectionManager { ConnectionManager._internal(); - String _domain; - String _port; - String displayHostname; - String _webSocketAPIEndpoint; - String httpWebHost; - String _token; - String _tempToken; - String oauthUrl; - String webhookId; - double haVersion; - bool scrollBadges; - String mobileAppDeviceName; - bool settingsLoaded = false; - int appIntegrationVersion; - bool get isAuthenticated => _token != null; StreamSubscription _socketSubscription; Duration connectTimeout = Duration(seconds: 15); bool isConnected = false; + bool settingsLoaded = false; var onStateChangeCallback; var onLovelaceUpdatedCallback; @@ -38,70 +24,23 @@ class ConnectionManager { int _currentMessageId = 0; Map _messageResolver = {}; - Future init({bool loadSettings, bool forceReconnect: false}) async { + Future init({bool loadSettings, bool forceReconnect: false}) { Completer completer = Completer(); - bool stopInit = false; - if (loadSettings) { - Logger.d("Loading settings..."); - SharedPreferences prefs = await SharedPreferences.getInstance(); - _domain = prefs.getString('hassio-domain'); - _port = prefs.getString('hassio-port'); - webhookId = prefs.getString('app-webhook-id'); - appIntegrationVersion = prefs.getInt('app-integration-version') ?? 0; - mobileAppDeviceName = prefs.getString('app-integration-device-name'); - scrollBadges = prefs.getBool('scroll-badges') ?? true; - displayHostname = "$_domain:$_port"; - _webSocketAPIEndpoint = - "${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket"; - httpWebHost = - "${prefs.getString('hassio-res-protocol')}://$_domain:$_port"; - Logger.d('$_domain$_port'); - if (_domain == null && _port == null && webhookId == null && mobileAppDeviceName == null) { + AppSettings().load(loadSettings).then((_) { + if (AppSettings().isNotConfigured()) { completer.completeError(HACNotSetUpException()); - stopInit = true; - } else if ((_domain == null) || (_port == null) || - (_domain.isEmpty) || (_port.isEmpty)) { + } else if (AppSettings().isSomethingMissed()) { completer.completeError(HACException.checkConnectionSettings()); - stopInit = true; - } else { - final storage = new FlutterSecureStorage(); - try { - _token = await storage.read(key: "hacl_llt"); - Logger.d("Long-lived token read successful"); - oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent( - 'https://ha-client.app')}&redirect_uri=${Uri - .encodeComponent( - 'https://ha-client.app/service/auth_callback.html')}"; - settingsLoaded = true; - } catch (e, stacktrace) { - completer.completeError(HACException("Error reading login details", actions: [HAErrorAction.tryAgain(type: HAErrorActionType.FULL_RELOAD), HAErrorAction.loginAgain()])); - Logger.e("Error reading secure storage: $e", stacktrace: stacktrace); - stopInit = true; - } - } - } else { - if ((_domain == null) || (_port == null) || - (_domain.isEmpty) || (_port.isEmpty)) { - completer.completeError(HACException.checkConnectionSettings()); - stopInit = true; - } - } - - if (!stopInit) { - if (_token == null) { - AuthManager().start( - oauthUrl: oauthUrl - ).then((token) { - Logger.d("Token from AuthManager recived"); - _tempToken = token; + } else if (!AppSettings().isAuthenticated) { + AppSettings().startAuth().then((_) { _doConnect(completer: completer, forceReconnect: forceReconnect); }).catchError((e) { completer.completeError(e); }); } else { _doConnect(completer: completer, forceReconnect: forceReconnect); - } - } + } + }); return completer.future; } @@ -143,7 +82,7 @@ class ConnectionManager { Logger.d("Socket connecting..."); try { _socket = IOWebSocketChannel.connect( - _webSocketAPIEndpoint, pingInterval: Duration(seconds: 15)); + AppSettings().webSocketAPIEndpoint, pingInterval: Duration(seconds: 15)); _socketSubscription = _socket.stream.listen( (message) { isConnected = true; @@ -159,9 +98,9 @@ class ConnectionManager { } else if (data["type"] == "auth_ok") { String v = data["ha_version"]; if (v != null && v.isNotEmpty) { - haVersion = double.tryParse(v.replaceFirst('0.','')) ?? 0; + AppSettings().haVersion = double.tryParse(v.replaceFirst('0.','')) ?? 0; } - Logger.d("Home assistant version: $v ($haVersion)"); + Logger.d("Home assistant version: $v (${AppSettings().haVersion})"); Crashlytics.instance.setString('ha_version', v); Logger.d("[Connection] Subscribing to events"); sendSocketMessage( @@ -174,7 +113,7 @@ class ConnectionManager { ).whenComplete((){ _messageResolver["auth"]?.complete(); _messageResolver.remove("auth"); - if (_token != null) { + if (AppSettings().isAuthenticated) { if (!connecting.isCompleted) connecting.complete(); } }); @@ -268,7 +207,7 @@ class ConnectionManager { Future _authenticate() { Completer completer = Completer(); - if (_token != null) { + if (AppSettings().isAuthenticated) { Logger.d( "Long-lived token exist"); Logger.d( "[Sending] ==> auth request"); sendSocketMessage(