From ccb88884a738c82c9d0b35b629402695f3ae4e0b Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Tue, 19 Mar 2019 23:07:40 +0200 Subject: [PATCH] Settings loading refactored. WIP #338 --- android/app/src/main/AndroidManifest.xml | 3 +- .../main/res/xml/network_security_config.xml | 6 +++ .../alarm_control_panel.class.dart | 3 +- lib/entity_class/automation_entity.dart | 3 +- lib/entity_class/button_entity.class.dart | 3 +- lib/entity_class/camera_entity.class.dart | 2 +- lib/entity_class/climate_entity.class.dart | 8 ++-- lib/entity_class/cover_entity.class.dart | 4 +- lib/entity_class/date_time_entity.class.dart | 4 +- lib/entity_class/entity.class.dart | 15 +++--- lib/entity_class/fan_entity.class.dart | 2 +- lib/entity_class/group_entity.class.dart | 7 +-- lib/entity_class/light_entity.class.dart | 2 +- lib/entity_class/lock_entity.class.dart | 2 +- .../media_player_entity.class.dart | 2 +- lib/entity_class/other_entity.class.dart | 4 +- lib/entity_class/select_entity.class.dart | 2 +- lib/entity_class/slider_entity.dart | 2 +- lib/entity_class/switch_entity.class.dart | 2 +- lib/entity_class/text_entity.class.dart | 2 +- lib/entity_class/timer_entity.dart | 6 +-- lib/entity_collection.class.dart | 46 ++++++++++--------- .../common/camera_stream_view.dart | 4 +- .../controls/media_player_widgets.dart | 2 +- lib/home_assistant.class.dart | 28 +++++++++-- lib/main.dart | 41 +++++++++-------- lib/settings.page.dart | 32 +++++++++++++ lib/ui_class/panel_class.dart | 3 +- pubspec.lock | 7 +++ pubspec.yaml | 1 + 30 files changed, 163 insertions(+), 85 deletions(-) create mode 100644 android/app/src/main/res/xml/network_security_config.xml diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 53e7a14..49d7f01 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -15,7 +15,8 @@ + android:icon="@mipmap/ic_launcher" + android:networkSecurityConfig="@xml/network_security_config"> + + + homemade.systems + + \ No newline at end of file diff --git a/lib/entity_class/alarm_control_panel.class.dart b/lib/entity_class/alarm_control_panel.class.dart index 42cde19..7166a96 100644 --- a/lib/entity_class/alarm_control_panel.class.dart +++ b/lib/entity_class/alarm_control_panel.class.dart @@ -1,7 +1,8 @@ part of '../main.dart'; class AlarmControlPanelEntity extends Entity { - AlarmControlPanelEntity(Map rawData) : super(rawData); + AlarmControlPanelEntity(Map rawData, String webHost) : super(rawData, webHost); + @override Widget _buildAdditionalControlsForPage(BuildContext context) { diff --git a/lib/entity_class/automation_entity.dart b/lib/entity_class/automation_entity.dart index 6862be4..b2d0270 100644 --- a/lib/entity_class/automation_entity.dart +++ b/lib/entity_class/automation_entity.dart @@ -1,7 +1,8 @@ part of '../main.dart'; class AutomationEntity extends Entity { - AutomationEntity(Map rawData) : super(rawData); + AutomationEntity(Map rawData, String webHost) : super(rawData, webHost); + @override Widget _buildStatePart(BuildContext context) { diff --git a/lib/entity_class/button_entity.class.dart b/lib/entity_class/button_entity.class.dart index b22d31e..05da8f0 100644 --- a/lib/entity_class/button_entity.class.dart +++ b/lib/entity_class/button_entity.class.dart @@ -1,7 +1,8 @@ part of '../main.dart'; class ButtonEntity extends Entity { - ButtonEntity(Map rawData) : super(rawData); + ButtonEntity(Map rawData, String webHost) : super(rawData, webHost); + @override Widget _buildStatePart(BuildContext context) { diff --git a/lib/entity_class/camera_entity.class.dart b/lib/entity_class/camera_entity.class.dart index f05538e..4a2d519 100644 --- a/lib/entity_class/camera_entity.class.dart +++ b/lib/entity_class/camera_entity.class.dart @@ -4,7 +4,7 @@ class CameraEntity extends Entity { static const SUPPORT_ON_OFF = 1; - CameraEntity(Map rawData) : super(rawData); + CameraEntity(Map rawData, String webHost) : super(rawData, webHost); bool get supportOnOff => ((supportedFeatures & CameraEntity.SUPPORT_ON_OFF) == diff --git a/lib/entity_class/climate_entity.class.dart b/lib/entity_class/climate_entity.class.dart index b25e42f..672e0db 100644 --- a/lib/entity_class/climate_entity.class.dart +++ b/lib/entity_class/climate_entity.class.dart @@ -23,6 +23,8 @@ class ClimateEntity extends Entity { static const SUPPORT_AUX_HEAT = 2048; static const SUPPORT_ON_OFF = 4096; + ClimateEntity(Map rawData, String webHost) : super(rawData, webHost); + bool get supportTargetTemperature => ((supportedFeatures & ClimateEntity.SUPPORT_TARGET_TEMPERATURE) == ClimateEntity.SUPPORT_TARGET_TEMPERATURE); @@ -88,11 +90,9 @@ class ClimateEntity extends Entity { bool get isOff => state == EntityState.off; bool get auxHeat => attributes['aux_heat'] == "on"; - ClimateEntity(Map rawData) : super(rawData); - @override - void update(Map rawData) { - super.update(rawData); + void update(Map rawData, String webHost) { + super.update(rawData, webHost); if (supportTargetTemperature) { historyConfig.numericAttributesToShow.add("temperature"); } diff --git a/lib/entity_class/cover_entity.class.dart b/lib/entity_class/cover_entity.class.dart index 3d31e68..9082bd7 100644 --- a/lib/entity_class/cover_entity.class.dart +++ b/lib/entity_class/cover_entity.class.dart @@ -11,6 +11,8 @@ class CoverEntity extends Entity { static const SUPPORT_STOP_TILT = 64; static const SUPPORT_SET_TILT_POSITION = 128; + CoverEntity(Map rawData, String webHost) : super(rawData, webHost); + bool get supportOpen => ((supportedFeatures & CoverEntity.SUPPORT_OPEN) == CoverEntity.SUPPORT_OPEN); @@ -45,8 +47,6 @@ class CoverEntity extends Entity { bool get canTiltBeOpened => currentTiltPosition < 100; bool get canTiltBeClosed => currentTiltPosition > 0; - CoverEntity(Map rawData) : super(rawData); - @override Widget _buildStatePart(BuildContext context) { return CoverStateWidget(); diff --git a/lib/entity_class/date_time_entity.class.dart b/lib/entity_class/date_time_entity.class.dart index 1223a7e..8aea4e5 100644 --- a/lib/entity_class/date_time_entity.class.dart +++ b/lib/entity_class/date_time_entity.class.dart @@ -1,6 +1,8 @@ part of '../main.dart'; class DateTimeEntity extends Entity { + DateTimeEntity(Map rawData, String webHost) : super(rawData, webHost); + bool get hasDate => attributes["has_date"] ?? false; bool get hasTime => attributes["has_time"] ?? false; int get year => attributes["year"] ?? 1970; @@ -12,8 +14,6 @@ class DateTimeEntity extends Entity { String get formattedState => _getFormattedState(); DateTime get dateTimeState => _getDateTimeState(); - DateTimeEntity(Map rawData) : super(rawData); - @override Widget _buildStatePart(BuildContext context) { return DateTimeStateWidget(); diff --git a/lib/entity_class/entity.class.dart b/lib/entity_class/entity.class.dart index 7cb6b23..b71433c 100644 --- a/lib/entity_class/entity.class.dart +++ b/lib/entity_class/entity.class.dart @@ -73,6 +73,7 @@ class Entity { Map attributes; String domain; String entityId; + String entityPicture; String state; String displayState; DateTime _lastUpdated; @@ -94,7 +95,6 @@ class Entity { bool get isBadge => Entity.badgeDomains.contains(domain); String get icon => attributes["icon"] ?? ""; bool get isOn => state == EntityState.on; - String get entityPicture => _getEntityPictureUrl(); String get unitOfMeasurement => attributes["unit_of_measurement"] ?? ""; List get childEntityIds => attributes["entity_id"] ?? []; String get lastUpdated => _getLastUpdatedFormatted(); @@ -102,21 +102,21 @@ class Entity { double get doubleState => double.tryParse(state) ?? 0.0; int get supportedFeatures => attributes["supported_features"] ?? 0; - String _getEntityPictureUrl() { + String _getEntityPictureUrl(String webHost) { String result = attributes["entity_picture"]; if (result == null) return result; if (!result.startsWith("http")) { if (result.startsWith("/")) { - result = "$homeAssistantWebHost$result"; + result = "$webHost$result"; } else { - result = "$homeAssistantWebHost/$result"; + result = "$webHost/$result"; } } return result; } - Entity(Map rawData) { - update(rawData); + Entity(Map rawData, String webHost) { + update(rawData, webHost); } Entity.missed(String entityId) { @@ -148,7 +148,7 @@ class Entity { attributes = {"hidden": false, "friendly_name": "${name ?? url}", "icon": "${icon ?? 'mdi:link'}"}; } - void update(Map rawData) { + void update(Map rawData, String webHost) { attributes = rawData["attributes"] ?? {}; domain = rawData["entity_id"].split(".")[0]; entityId = rawData["entity_id"]; @@ -156,6 +156,7 @@ class Entity { state = rawData["state"]; displayState = Entity.StateByDeviceClass["$deviceClass.$state"] ?? state; _lastUpdated = DateTime.tryParse(rawData["last_updated"]); + entityPicture = _getEntityPictureUrl(webHost); } double _getDoubleAttributeValue(String attributeName) { diff --git a/lib/entity_class/fan_entity.class.dart b/lib/entity_class/fan_entity.class.dart index 601b7c0..927a57c 100644 --- a/lib/entity_class/fan_entity.class.dart +++ b/lib/entity_class/fan_entity.class.dart @@ -6,7 +6,7 @@ class FanEntity extends Entity { static const SUPPORT_OSCILLATE = 2; static const SUPPORT_DIRECTION = 4; - FanEntity(Map rawData) : super(rawData); + FanEntity(Map rawData, String webHost) : super(rawData, webHost); bool get supportSetSpeed => ((supportedFeatures & FanEntity.SUPPORT_SET_SPEED) == diff --git a/lib/entity_class/group_entity.class.dart b/lib/entity_class/group_entity.class.dart index d82fe84..ada70a9 100644 --- a/lib/entity_class/group_entity.class.dart +++ b/lib/entity_class/group_entity.class.dart @@ -1,12 +1,13 @@ part of '../main.dart'; class GroupEntity extends Entity { - GroupEntity(Map rawData) : super(rawData); final List _domainsForSwitchableGroup = ["switch", "light", "automation", "input_boolean"]; String mutualDomain; bool switchable = false; + GroupEntity(Map rawData, String webHost) : super(rawData, webHost); + @override Widget _buildStatePart(BuildContext context) { if (switchable) { @@ -19,8 +20,8 @@ class GroupEntity extends Entity { } @override - void update(Map rawData) { - super.update(rawData); + void update(Map rawData, String webHost) { + super.update(rawData, webHost); if (_isOneDomain()) { mutualDomain = attributes['entity_id'][0].split(".")[0]; switchable = _domainsForSwitchableGroup.contains(mutualDomain); diff --git a/lib/entity_class/light_entity.class.dart b/lib/entity_class/light_entity.class.dart index c0b6cdc..687ddfc 100644 --- a/lib/entity_class/light_entity.class.dart +++ b/lib/entity_class/light_entity.class.dart @@ -42,7 +42,7 @@ class LightEntity extends Entity { bool get isAdditionalControls => ((supportedFeatures != null) && (supportedFeatures != 0)); List get effectList => getStringListAttributeValue("effect_list"); - LightEntity(Map rawData) : super(rawData); + LightEntity(Map rawData, String webHost) : super(rawData, webHost); HSVColor _getColor() { List hs = attributes["hs_color"]; diff --git a/lib/entity_class/lock_entity.class.dart b/lib/entity_class/lock_entity.class.dart index 9ed21f0..238cce5 100644 --- a/lib/entity_class/lock_entity.class.dart +++ b/lib/entity_class/lock_entity.class.dart @@ -1,7 +1,7 @@ part of '../main.dart'; class LockEntity extends Entity { - LockEntity(Map rawData) : super(rawData); + LockEntity(Map rawData, String webHost) : super(rawData, webHost); bool get isLocked => state == "locked"; diff --git a/lib/entity_class/media_player_entity.class.dart b/lib/entity_class/media_player_entity.class.dart index 2fe87d7..f144b79 100644 --- a/lib/entity_class/media_player_entity.class.dart +++ b/lib/entity_class/media_player_entity.class.dart @@ -20,7 +20,7 @@ class MediaPlayerEntity extends Entity { static const SUPPORT_SHUFFLE_SET = 32768; static const SUPPORT_SELECT_SOUND_MODE = 65536; - MediaPlayerEntity(Map rawData) : super(rawData); + MediaPlayerEntity(Map rawData, String webHost) : super(rawData, webHost); bool get supportPause => ((supportedFeatures & MediaPlayerEntity.SUPPORT_PAUSE) == diff --git a/lib/entity_class/other_entity.class.dart b/lib/entity_class/other_entity.class.dart index 0cdf8ba..9f64996 100644 --- a/lib/entity_class/other_entity.class.dart +++ b/lib/entity_class/other_entity.class.dart @@ -1,7 +1,7 @@ part of '../main.dart'; class SunEntity extends Entity { - SunEntity(Map rawData) : super(rawData); + SunEntity(Map rawData, String webHost) : super(rawData, webHost); } class SensorEntity extends Entity { @@ -12,6 +12,6 @@ class SensorEntity extends Entity { numericState: true ); - SensorEntity(Map rawData) : super(rawData); + SensorEntity(Map rawData, String webHost) : super(rawData, webHost); } \ No newline at end of file diff --git a/lib/entity_class/select_entity.class.dart b/lib/entity_class/select_entity.class.dart index 636a74f..ce0637a 100644 --- a/lib/entity_class/select_entity.class.dart +++ b/lib/entity_class/select_entity.class.dart @@ -5,7 +5,7 @@ class SelectEntity extends Entity { ? (attributes["options"] as List).cast() : []; - SelectEntity(Map rawData) : super(rawData); + SelectEntity(Map rawData, String webHost) : super(rawData, webHost); @override Widget _buildStatePart(BuildContext context) { diff --git a/lib/entity_class/slider_entity.dart b/lib/entity_class/slider_entity.dart index 1eecbee..233377b 100644 --- a/lib/entity_class/slider_entity.dart +++ b/lib/entity_class/slider_entity.dart @@ -1,7 +1,7 @@ part of '../main.dart'; class SliderEntity extends Entity { - SliderEntity(Map rawData) : super(rawData); + SliderEntity(Map rawData, String webHost) : super(rawData, webHost); double get minValue => _getDoubleAttributeValue("min") ?? 0.0; double get maxValue =>_getDoubleAttributeValue("max") ?? 100.0; diff --git a/lib/entity_class/switch_entity.class.dart b/lib/entity_class/switch_entity.class.dart index f6aee40..082f7d5 100644 --- a/lib/entity_class/switch_entity.class.dart +++ b/lib/entity_class/switch_entity.class.dart @@ -1,7 +1,7 @@ part of '../main.dart'; class SwitchEntity extends Entity { - SwitchEntity(Map rawData) : super(rawData); + SwitchEntity(Map rawData, String webHost) : super(rawData, webHost); @override Widget _buildStatePart(BuildContext context) { diff --git a/lib/entity_class/text_entity.class.dart b/lib/entity_class/text_entity.class.dart index 7230c84..c8382a2 100644 --- a/lib/entity_class/text_entity.class.dart +++ b/lib/entity_class/text_entity.class.dart @@ -1,7 +1,7 @@ part of '../main.dart'; class TextEntity extends Entity { - TextEntity(Map rawData) : super(rawData); + TextEntity(Map rawData, String webHost) : super(rawData, webHost); int get valueMinLength => attributes["min"] ?? -1; int get valueMaxLength => attributes["max"] ?? -1; diff --git a/lib/entity_class/timer_entity.dart b/lib/entity_class/timer_entity.dart index 3251d56..17f219a 100644 --- a/lib/entity_class/timer_entity.dart +++ b/lib/entity_class/timer_entity.dart @@ -1,13 +1,13 @@ part of '../main.dart'; class TimerEntity extends Entity { - TimerEntity(Map rawData) : super(rawData); + TimerEntity(Map rawData, String webHost) : super(rawData, webHost); Duration duration; @override - void update(Map rawData) { - super.update(rawData); + void update(Map rawData, String webHost) { + super.update(rawData, webHost); String durationSource = "${attributes["duration"]}"; if (durationSource != null && durationSource.isNotEmpty) { try { diff --git a/lib/entity_collection.class.dart b/lib/entity_collection.class.dart index 3b4a07d..ff9df26 100644 --- a/lib/entity_collection.class.dart +++ b/lib/entity_collection.class.dart @@ -2,13 +2,15 @@ part of 'main.dart'; class EntityCollection { + final homeAssistantWebHost; + Map _allEntities; //Map views; bool get isEmpty => _allEntities.isEmpty; List get viewEntities => _allEntities.values.where((entity) => entity.isView).toList(); - EntityCollection() { + EntityCollection(this.homeAssistantWebHost) { _allEntities = {}; //views = {}; } @@ -36,67 +38,67 @@ class EntityCollection { Entity _createEntityInstance(rawEntityData) { switch (rawEntityData["entity_id"].split(".")[0]) { case 'sun': { - return SunEntity(rawEntityData); + return SunEntity(rawEntityData, homeAssistantWebHost); } case "media_player": { - return MediaPlayerEntity(rawEntityData); + return MediaPlayerEntity(rawEntityData, homeAssistantWebHost); } case 'sensor': { - return SensorEntity(rawEntityData); + return SensorEntity(rawEntityData, homeAssistantWebHost); } case 'lock': { - return LockEntity(rawEntityData); + return LockEntity(rawEntityData, homeAssistantWebHost); } case "automation": { - return AutomationEntity(rawEntityData); + return AutomationEntity(rawEntityData, homeAssistantWebHost); } case "input_boolean": case "switch": { - return SwitchEntity(rawEntityData); + return SwitchEntity(rawEntityData, homeAssistantWebHost); } case "light": { - return LightEntity(rawEntityData); + return LightEntity(rawEntityData, homeAssistantWebHost); } case "group": { - return GroupEntity(rawEntityData); + return GroupEntity(rawEntityData, homeAssistantWebHost); } case "script": case "scene": { - return ButtonEntity(rawEntityData); + return ButtonEntity(rawEntityData, homeAssistantWebHost); } case "input_datetime": { - return DateTimeEntity(rawEntityData); + return DateTimeEntity(rawEntityData, homeAssistantWebHost); } case "input_select": { - return SelectEntity(rawEntityData); + return SelectEntity(rawEntityData, homeAssistantWebHost); } case "input_number": { - return SliderEntity(rawEntityData); + return SliderEntity(rawEntityData, homeAssistantWebHost); } case "input_text": { - return TextEntity(rawEntityData); + return TextEntity(rawEntityData, homeAssistantWebHost); } case "climate": { - return ClimateEntity(rawEntityData); + return ClimateEntity(rawEntityData, homeAssistantWebHost); } case "cover": { - return CoverEntity(rawEntityData); + return CoverEntity(rawEntityData, homeAssistantWebHost); } case "fan": { - return FanEntity(rawEntityData); + return FanEntity(rawEntityData, homeAssistantWebHost); } case "camera": { - return CameraEntity(rawEntityData); + return CameraEntity(rawEntityData, homeAssistantWebHost); } case "alarm_control_panel": { - return AlarmControlPanelEntity(rawEntityData); + return AlarmControlPanelEntity(rawEntityData, homeAssistantWebHost); } case "timer": { - return TimerEntity(rawEntityData); + return TimerEntity(rawEntityData, homeAssistantWebHost); } default: { - return Entity(rawEntityData); + return Entity(rawEntityData, homeAssistantWebHost); } } } @@ -121,7 +123,7 @@ class EntityCollection { } void updateFromRaw(Map rawEntityData) { - get("${rawEntityData["entity_id"]}")?.update(rawEntityData); + get("${rawEntityData["entity_id"]}")?.update(rawEntityData, homeAssistantWebHost); } Entity get(String entityId) { diff --git a/lib/entity_widgets/common/camera_stream_view.dart b/lib/entity_widgets/common/camera_stream_view.dart index 60fa76c..8b7f4e6 100644 --- a/lib/entity_widgets/common/camera_stream_view.dart +++ b/lib/entity_widgets/common/camera_stream_view.dart @@ -16,6 +16,7 @@ class _CameraStreamViewState extends State { } CameraEntity _entity; + String _webHost; http.Client client; http.StreamedResponse response; @@ -28,7 +29,7 @@ class _CameraStreamViewState extends State { void _connect() async { started = true; timeToStop = false; - String streamUrl = '$homeAssistantWebHost/api/camera_proxy_stream/${_entity.entityId}?token=${_entity.attributes['access_token']}'; + String streamUrl = '$_webHost/api/camera_proxy_stream/${_entity.entityId}?token=${_entity.attributes['access_token']}'; client = new http.Client(); // create a client to make api calls http.Request request = new http.Request("GET", Uri.parse(streamUrl)); // create get request Logger.d("[Sending] ==> $streamUrl"); @@ -130,6 +131,7 @@ class _CameraStreamViewState extends State { .of(context) .entityWrapper .entity; + _webHost = HomeAssistantModel.of(context).homeAssistant.httpAPIEndpoint; _connect(); } diff --git a/lib/entity_widgets/controls/media_player_widgets.dart b/lib/entity_widgets/controls/media_player_widgets.dart index 3f942f6..baf5f48 100644 --- a/lib/entity_widgets/controls/media_player_widgets.dart +++ b/lib/entity_widgets/controls/media_player_widgets.dart @@ -73,7 +73,7 @@ class MediaPlayerWidget extends StatelessWidget { Widget _buildImage(MediaPlayerEntity entity) { String state = entity.state; - if (homeAssistantWebHost != null && entity.entityPicture != null && state != EntityState.off && state != EntityState.unavailable && state != EntityState.idle) { + if (entity.entityPicture != null && state != EntityState.off && state != EntityState.unavailable && state != EntityState.idle) { return Container( color: Colors.black, child: Row( diff --git a/lib/home_assistant.class.dart b/lib/home_assistant.class.dart index d405e40..a5944bb 100644 --- a/lib/home_assistant.class.dart +++ b/lib/home_assistant.class.dart @@ -2,8 +2,10 @@ part of 'main.dart'; class HomeAssistant { String _webSocketAPIEndpoint; + String httpAPIEndpoint; String _password; bool _useLovelace = false; + bool isSettingsLoaded = false; IOWebSocketChannel _hassioChannel; SendMessageQueue _messageQueue; @@ -15,6 +17,7 @@ class HomeAssistant { HomeAssistantUI ui; Map _instanceConfig = {}; String _userName; + String hostname; HSVColor savedColor; Map _rawLovelaceData; @@ -45,10 +48,27 @@ class HomeAssistant { //int get viewsCount => entities.views.length ?? 0; HomeAssistant() { - entities = EntityCollection(); _messageQueue = SendMessageQueue(messageExpirationTime); } + Future loadConnectionSettings() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + String domain = prefs.getString('hassio-domain'); + String port = prefs.getString('hassio-port'); + hostname = "$domain:$port"; + _webSocketAPIEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket"; + httpAPIEndpoint = "${prefs.getString('hassio-res-protocol')}://$domain:$port"; + _password = prefs.getString('hassio-password'); + _useLovelace = prefs.getBool('use-lovelace') ?? true; + if ((domain == null) || (port == null) || (_password == null) || + (domain.length == 0) || (port.length == 0) || (_password.length == 0)) { + throw("Check connection settings"); + } else { + isSettingsLoaded = true; + entities = EntityCollection(httpAPIEndpoint); + } + } + void updateSettings(String url, String password, bool useLovelace) { _webSocketAPIEndpoint = url; _password = password; @@ -555,7 +575,7 @@ class HomeAssistant { } } - Widget buildViews(BuildContext context, bool lovelace, TabController tabController) { + Widget buildViews(BuildContext context, TabController tabController) { return ui.build(context, tabController); } @@ -563,7 +583,7 @@ class HomeAssistant { DateTime now = DateTime.now(); //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 url = "$homeAssistantWebHost/api/history/period/$startTime?&filter_entity_id=$entityId"; + String url = "$httpAPIEndpoint/api/history/period/$startTime?&filter_entity_id=$entityId"; Logger.d("[Sending] ==> $url"); http.Response historyResponse; historyResponse = await http.get(url, headers: { @@ -580,7 +600,7 @@ class HomeAssistant { } Future sendHTTPRequest(String data) async { - String url = "$homeAssistantWebHost/api/notify.fcm-android"; + String url = "$httpAPIEndpoint/api/notify.fcm-android"; Logger.d("[Sending] ==> $url"); http.Response response; response = await http.post( diff --git a/lib/main.dart b/lib/main.dart index 2adaaaa..a078694 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,6 +18,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_custom_tabs/flutter_custom_tabs.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; part 'entity_class/const.dart'; part 'entity_class/entity.class.dart'; @@ -103,7 +104,7 @@ EventBus eventBus = new EventBus(); const String appName = "HA Client"; const appVersion = "0.5.2"; -String homeAssistantWebHost; +//String homeAssistantWebHost; void main() { FlutterError.onError = (errorDetails) { @@ -156,29 +157,28 @@ class MainPage extends StatefulWidget { class _MainPageState extends State with WidgetsBindingObserver, TickerProviderStateMixin { HomeAssistant _homeAssistant; //Map _instanceConfig; - String _webSocketApiEndpoint; - String _password; + //String _webSocketApiEndpoint; + //String _password; //int _uiViewsCount = 0; - String _instanceHost; + //String _instanceHost; StreamSubscription _stateSubscription; StreamSubscription _settingsSubscription; StreamSubscription _serviceCallSubscription; StreamSubscription _showEntityPageSubscription; StreamSubscription _showErrorSubscription; - bool _settingsLoaded = false; + //bool _settingsLoaded = false; bool _accountMenuExpanded = false; - bool _useLovelaceUI; + //bool _useLovelaceUI; int _previousViewCount; final FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); @override void initState() { super.initState(); - _settingsLoaded = false; - WidgetsBinding.instance.addObserver(this); - Logger.d(" Creating new HomeAssistant instance"); _homeAssistant = HomeAssistant(); + //_settingsLoaded = false; + WidgetsBinding.instance.addObserver(this); _settingsSubscription = eventBus.on().listen((event) { Logger.d("Settings change event: reconnect=${event.reconnect}"); @@ -193,7 +193,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } void _initialLoad() { - _loadConnectionSettings().then((_){ + _homeAssistant.loadConnectionSettings().then((_){ _subscribe(); _refreshData(); }, onError: (_) { @@ -203,13 +203,13 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker @override void didChangeAppLifecycleState(AppLifecycleState state) { - Logger.d("$state"); - if (state == AppLifecycleState.resumed && _settingsLoaded) { + //Logger.d("$state"); + if (state == AppLifecycleState.resumed && _homeAssistant.isSettingsLoaded) { _refreshData(); } } - _loadConnectionSettings() async { + /*_loadConnectionSettings() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String domain = prefs.getString('hassio-domain'); String port = prefs.getString('hassio-port'); @@ -224,7 +224,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } else { _settingsLoaded = true; } - } + }*/ _subscribe() { if (_stateSubscription == null) { @@ -258,7 +258,8 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker }); } - /*_firebaseMessaging.getToken().then((String token) { + _firebaseMessaging.getToken().then((String token) { + //Logger.d("FCM token: $token"); _homeAssistant.sendHTTPRequest('{"token": "$token"}'); }); _firebaseMessaging.configure( @@ -271,11 +272,11 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker onResume: (data) { Logger.d("Notification [onResume]: $data"); } - );*/ + ); } _refreshData() async { - _homeAssistant.updateSettings(_webSocketApiEndpoint, _password, _useLovelaceUI); + //_homeAssistant.updateSettings(_webSocketApiEndpoint, _password, _useLovelaceUI); _hideBottomBar(); _showInfoBottomBar(progress: true,); await _homeAssistant.fetch().then((result) { @@ -342,7 +343,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker menuItems.add( UserAccountsDrawerHeader( accountName: Text(_homeAssistant.userName), - accountEmail: Text(_instanceHost ?? "Not configured"), + accountEmail: Text(_homeAssistant.hostname ?? "Not configured"), onDetailsPressed: () { setState(() { _accountMenuExpanded = !_accountMenuExpanded; @@ -387,7 +388,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker new ListTile( leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:home-assistant")), title: Text("Open Web UI"), - onTap: () => HAUtils.launchURL(homeAssistantWebHost), + onTap: () => HAUtils.launchURL(_homeAssistant.httpAPIEndpoint), ), Divider() ]); @@ -631,7 +632,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker ), ) : - _homeAssistant.buildViews(context, _useLovelaceUI, _viewsTabController), + _homeAssistant.buildViews(context, _viewsTabController), ); } diff --git a/lib/settings.page.dart b/lib/settings.page.dart index 0ed9285..626c845 100644 --- a/lib/settings.page.dart +++ b/lib/settings.page.dart @@ -21,10 +21,21 @@ class _ConnectionSettingsPageState extends State { bool _useLovelace = true; bool _newUseLovelace = true; + String oauthUrl; + final flutterWebviewPlugin = new FlutterWebviewPlugin(); + @override void initState() { super.initState(); _loadSettings(); + flutterWebviewPlugin.onUrlChanged.listen((String url) { + Logger.d("Launched url: $url"); + if (url.startsWith("http://ha-client.homemade.systems/service/auth_callback.html")) { + String authCode = url.split("=")[1]; + Logger.d("Auth code: $authCode"); + flutterWebviewPlugin.close(); + } + }); } _loadSettings() async { @@ -40,6 +51,8 @@ class _ConnectionSettingsPageState extends State { } catch (e) { _useLovelace = _newUseLovelace = true; } + oauthUrl = "${ _newSocketProtocol == "wss" ? "https" : "http"}://$_newHassioDomain:${_newHassioPort ?? ''}/auth/authorize?client_id=${Uri.encodeComponent('http://ha-client.homemade.systems/')}&redirect_uri=${Uri.encodeComponent('http://ha-client.homemade.systems/service/auth_callback.html')}"; + Logger.d("OAuth url: $oauthUrl"); }); } @@ -67,6 +80,24 @@ class _ConnectionSettingsPageState extends State { @override Widget build(BuildContext context) { + Widget webViewButton; + if (oauthUrl != null) { + webViewButton = FlatButton( + onPressed: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => WebviewScaffold( + url: oauthUrl, + appBar: new AppBar( + title: new Text("Login"), + ) + ) + )); + }, + child: Text("Login with Home Assistant") + ); + } else { + webViewButton = Container(height: 0.0,); + } return new Scaffold( appBar: new AppBar( leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){ @@ -149,6 +180,7 @@ class _ConnectionSettingsPageState extends State { "Try ports 80 and 443 if default is not working and you don't know why.", style: TextStyle(color: Colors.grey), ), + webViewButton, new TextField( decoration: InputDecoration( labelText: "Access token" diff --git a/lib/ui_class/panel_class.dart b/lib/ui_class/panel_class.dart index ae21b2b..e39a080 100644 --- a/lib/ui_class/panel_class.dart +++ b/lib/ui_class/panel_class.dart @@ -36,7 +36,8 @@ class Panel { ) ); } else { - String url = "$homeAssistantWebHost/$urlPath"; + HomeAssistantModel haModel = HomeAssistantModel.of(context); + String url = "${haModel.homeAssistant.httpAPIEndpoint}/$urlPath"; Logger.d("Launching custom tab with $url"); HAUtils.launchURLInCustomTab(context, url); } diff --git a/pubspec.lock b/pubspec.lock index d0eff9e..e3d0769 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -153,6 +153,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_webview_plugin: + dependency: "direct main" + description: + name: flutter_webview_plugin + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.1" http: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 12c9303..714d1af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: flutter_svg: ^0.10.3 flutter_custom_tabs: ^0.6.0 firebase_messaging: ^4.0.0+1 + flutter_webview_plugin: ^0.3.1 dev_dependencies: flutter_test: