WIP
This commit is contained in:
@ -131,7 +131,7 @@ class _CameraStreamViewState extends State<CameraStreamView> {
|
|||||||
.of(context)
|
.of(context)
|
||||||
.entityWrapper
|
.entityWrapper
|
||||||
.entity;
|
.entity;
|
||||||
_webHost = HomeAssistantModel.of(context).homeAssistant.httpAPIEndpoint;
|
_webHost = HomeAssistantModel.of(context).homeAssistant.httpWebHost;
|
||||||
_connect();
|
_connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,10 @@ part of 'main.dart';
|
|||||||
|
|
||||||
class HomeAssistant {
|
class HomeAssistant {
|
||||||
String _webSocketAPIEndpoint;
|
String _webSocketAPIEndpoint;
|
||||||
String httpAPIEndpoint;
|
String httpWebHost;
|
||||||
String _password;
|
//String _password;
|
||||||
|
String _token;
|
||||||
|
String _tempToken;
|
||||||
bool _useLovelace = false;
|
bool _useLovelace = false;
|
||||||
bool isSettingsLoaded = false;
|
bool isSettingsLoaded = false;
|
||||||
|
|
||||||
@ -57,15 +59,16 @@ class HomeAssistant {
|
|||||||
String port = prefs.getString('hassio-port');
|
String port = prefs.getString('hassio-port');
|
||||||
hostname = "$domain:$port";
|
hostname = "$domain:$port";
|
||||||
_webSocketAPIEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket";
|
_webSocketAPIEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket";
|
||||||
httpAPIEndpoint = "${prefs.getString('hassio-res-protocol')}://$domain:$port";
|
httpWebHost = "${prefs.getString('hassio-res-protocol')}://$domain:$port";
|
||||||
_password = prefs.getString('hassio-password');
|
//_password = prefs.getString('hassio-password');
|
||||||
|
_token = prefs.getString('hassio-token');
|
||||||
_useLovelace = prefs.getBool('use-lovelace') ?? true;
|
_useLovelace = prefs.getBool('use-lovelace') ?? true;
|
||||||
if ((domain == null) || (port == null) || (_password == null) ||
|
if ((domain == null) || (port == null) ||
|
||||||
(domain.length == 0) || (port.length == 0) || (_password.length == 0)) {
|
(domain.length == 0) || (port.length == 0)) {
|
||||||
throw("Check connection settings");
|
throw("Check connection settings");
|
||||||
} else {
|
} else {
|
||||||
isSettingsLoaded = true;
|
isSettingsLoaded = true;
|
||||||
entities = EntityCollection(httpAPIEndpoint);
|
entities = EntityCollection(httpWebHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +83,7 @@ class HomeAssistant {
|
|||||||
if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) {
|
if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) {
|
||||||
Logger.w("Previous fetch is not complited");
|
Logger.w("Previous fetch is not complited");
|
||||||
} else {
|
} else {
|
||||||
|
Logger.d("Fetching...");
|
||||||
_fetchCompleter = new Completer();
|
_fetchCompleter = new Completer();
|
||||||
_fetchTimer = Timer(fetchTimeout, () {
|
_fetchTimer = Timer(fetchTimeout, () {
|
||||||
Logger.e( "Data fetching timeout");
|
Logger.e( "Data fetching timeout");
|
||||||
@ -178,6 +182,9 @@ class HomeAssistant {
|
|||||||
if (_useLovelace) {
|
if (_useLovelace) {
|
||||||
futures.add(_getLovelace());
|
futures.add(_getLovelace());
|
||||||
}
|
}
|
||||||
|
if (_token == null && _tempToken != null) {
|
||||||
|
futures.add(_getLongLivedToken());
|
||||||
|
}
|
||||||
futures.add(_getConfig());
|
futures.add(_getConfig());
|
||||||
futures.add(_getServices());
|
futures.add(_getServices());
|
||||||
futures.add(_getUserInfo());
|
futures.add(_getUserInfo());
|
||||||
@ -226,14 +233,18 @@ class HomeAssistant {
|
|||||||
_handleMessage(String message) {
|
_handleMessage(String message) {
|
||||||
var data = json.decode(message);
|
var data = json.decode(message);
|
||||||
if (data["type"] == "auth_required") {
|
if (data["type"] == "auth_required") {
|
||||||
_sendAuthMessage('{"type": "auth","access_token": "$_password"}');
|
Logger.d("[Received] <== ${data.toString()}");
|
||||||
|
_sendAuth();
|
||||||
} else if (data["type"] == "auth_ok") {
|
} else if (data["type"] == "auth_ok") {
|
||||||
|
Logger.d("[Received] <== ${data.toString()}");
|
||||||
_completeConnecting(null);
|
_completeConnecting(null);
|
||||||
_sendSubscribe();
|
_sendSubscribe();
|
||||||
} else if (data["type"] == "auth_invalid") {
|
} else if (data["type"] == "auth_invalid") {
|
||||||
|
Logger.d("[Received] <== ${data.toString()}");
|
||||||
|
//TODO remove token and login again
|
||||||
_completeConnecting({"errorCode": 6, "errorMessage": "${data["message"]}"});
|
_completeConnecting({"errorCode": 6, "errorMessage": "${data["message"]}"});
|
||||||
} else if (data["type"] == "result") {
|
} else if (data["type"] == "result") {
|
||||||
Logger.d("[Received] <== id:${data["id"]}, ${data['success'] ? 'success' : 'error'}");
|
Logger.d("[Received] <== ${data.toString()}");
|
||||||
_messageResolver[data["id"]]?.complete(data);
|
_messageResolver[data["id"]]?.complete(data);
|
||||||
_messageResolver.remove(data["id"]);
|
_messageResolver.remove(data["id"]);
|
||||||
} else if (data["type"] == "event") {
|
} else if (data["type"] == "event") {
|
||||||
@ -246,40 +257,56 @@ class HomeAssistant {
|
|||||||
Logger.e("Event is null: $message");
|
Logger.e("Event is null: $message");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger.w("Unknown message type: $message");
|
Logger.d("[Received] <== ${data.toString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendSubscribe() {
|
void _sendSubscribe() {
|
||||||
_incrementMessageId();
|
_incrementMessageId();
|
||||||
_subscriptionMessageId = _currentMessageId;
|
_subscriptionMessageId = _currentMessageId;
|
||||||
_send('{"id": $_subscriptionMessageId, "type": "subscribe_events", "event_type": "state_changed"}', false);
|
_rawSend('{"id": $_subscriptionMessageId, "type": "subscribe_events", "event_type": "state_changed"}', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getConfig() async {
|
Future _getConfig() async {
|
||||||
await _sendInitialMessage("get_config").then((data) => _instanceConfig = Map.from(data["result"]));
|
await _sendSocketMessage(type: "get_config").then((data) => _instanceConfig = Map.from(data["result"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getStates() async {
|
Future _getStates() async {
|
||||||
await _sendInitialMessage("get_states").then((data) => entities.parse(data["result"]));
|
await _sendSocketMessage(type: "get_states").then((data) => entities.parse(data["result"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _getLongLivedToken() async {
|
||||||
|
await _sendSocketMessage(type: "auth/long_lived_access_token", additionalData: {"client_name": "HA Client 3", "client_icon": null, "lifespan": 365}).then((data) {
|
||||||
|
if (data['success']) {
|
||||||
|
Logger.d("Got long-lived token: ${data['result']}");
|
||||||
|
_token = data['result'];
|
||||||
|
//TODO save token
|
||||||
|
} else {
|
||||||
|
Logger.e("Error getting long-lived token: ${data['error'].toString()}");
|
||||||
|
//TODO DO DO something here
|
||||||
|
}
|
||||||
|
}).catchError((e) {
|
||||||
|
Logger.e("Error getting long-lived token: ${e.toString()}");
|
||||||
|
//TODO DO DO something here
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getLovelace() async {
|
Future _getLovelace() async {
|
||||||
await _sendInitialMessage("lovelace/config").then((data) => _rawLovelaceData = data["result"]);
|
await _sendSocketMessage(type: "lovelace/config").then((data) => _rawLovelaceData = data["result"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getUserInfo() async {
|
Future _getUserInfo() async {
|
||||||
_userName = null;
|
_userName = null;
|
||||||
await _sendInitialMessage("auth/current_user").then((data) => _userName = data["result"]["name"]);
|
await _sendSocketMessage(type: "auth/current_user").then((data) => _userName = data["result"]["name"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getServices() async {
|
Future _getServices() async {
|
||||||
await _sendInitialMessage("get_services").then((data) => Logger.d("We actually don`t need the list of servcies for now"));
|
await _sendSocketMessage(type: "get_services").then((data) => Logger.d("We actually don`t need the list of servcies for now"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getPanels() async {
|
Future _getPanels() async {
|
||||||
panels.clear();
|
panels.clear();
|
||||||
await _sendInitialMessage("get_panels").then((data) {
|
await _sendSocketMessage(type: "get_panels").then((data) {
|
||||||
if (data["success"]) {
|
if (data["success"]) {
|
||||||
data["result"].forEach((k,v) {
|
data["result"].forEach((k,v) {
|
||||||
String title = v['title'] == null ? "${k[0].toUpperCase()}${k.substring(1)}" : "${v['title'][0].toUpperCase()}${v['title'].substring(1)}";
|
String title = v['title'] == null ? "${k[0].toUpperCase()}${k.substring(1)}" : "${v['title'][0].toUpperCase()}${v['title'].substring(1)}";
|
||||||
@ -301,22 +328,73 @@ class HomeAssistant {
|
|||||||
_currentMessageId += 1;
|
_currentMessageId += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sendAuthMessage(String message) {
|
void _sendAuth() {
|
||||||
|
if (_token != null) {
|
||||||
|
Logger.d( "Long leaved token exist");
|
||||||
Logger.d( "[Sending] ==> auth request");
|
Logger.d( "[Sending] ==> auth request");
|
||||||
_hassioChannel.sink.add(message);
|
_hassioChannel.sink.add('{"type": "auth","access_token": "$_token"}');
|
||||||
|
} else if (_tempToken == null) {
|
||||||
|
Logger.d( "No long leaved token. Need to authenticate.");
|
||||||
|
final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
||||||
|
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("We have auth code. Getting temporary access token...");
|
||||||
|
sendHTTPPost(
|
||||||
|
endPoint: "/auth/token",
|
||||||
|
contentType: "application/x-www-form-urlencoded",
|
||||||
|
includeAuthHeader: false,
|
||||||
|
data: "grant_type=authorization_code&code=$authCode&client_id=${Uri.encodeComponent('http://ha-client.homemade.systems/')}"
|
||||||
|
).then((response) {
|
||||||
|
Logger.d("Gottemp token");
|
||||||
|
_tempToken = json.decode(response)['access_token'];
|
||||||
|
Logger.d("Closing webview...");
|
||||||
|
flutterWebviewPlugin.close();
|
||||||
|
Logger.d("Firing event to reload UI");
|
||||||
|
eventBus.fire(ReloadUIEvent());
|
||||||
|
}).catchError((e) {
|
||||||
|
//TODO DO DO something here
|
||||||
|
Logger.e("Error getting temp token: ${e.toString()}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
disconnect().then((_){
|
||||||
|
//TODO create special error code to show "Login" in message
|
||||||
|
_completeConnecting({"errorCode": 6, "errorMessage": "Not authenticated"});
|
||||||
|
});
|
||||||
|
String oauthUrl = "$httpWebHost/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");
|
||||||
|
eventBus.fire(StartAuthEvent(oauthUrl));
|
||||||
|
} else if (_tempToken != null) {
|
||||||
|
Logger.d("We have temp token. Login...");
|
||||||
|
_hassioChannel.sink.add('{"type": "auth","access_token": "$_tempToken"}');
|
||||||
|
} else {
|
||||||
|
Logger.e("General login error");
|
||||||
|
//TODO DO DO something here
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _sendInitialMessage(String type) {
|
Future _sendSocketMessage({String type, Map additionalData, bool noId: false}) {
|
||||||
Completer _completer = Completer();
|
Completer _completer = Completer();
|
||||||
|
Map dataObject = {"type": "$type"};
|
||||||
|
if (!noId) {
|
||||||
_incrementMessageId();
|
_incrementMessageId();
|
||||||
|
dataObject["id"] = _currentMessageId;
|
||||||
|
}
|
||||||
|
if (additionalData != null) {
|
||||||
|
dataObject.addAll(additionalData);
|
||||||
|
}
|
||||||
_messageResolver[_currentMessageId] = _completer;
|
_messageResolver[_currentMessageId] = _completer;
|
||||||
_send('{"id": $_currentMessageId, "type": "$type"}', false);
|
_rawSend(json.encode(dataObject), false);
|
||||||
return _completer.future;
|
return _completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
_send(String message, bool queued) {
|
_rawSend(String message, bool queued) {
|
||||||
var sendCompleter = Completer();
|
var sendCompleter = Completer();
|
||||||
if (queued) _messageQueue.add(message);
|
if (queued) {
|
||||||
|
_messageQueue.add(message);
|
||||||
|
}
|
||||||
_connection().then((r) {
|
_connection().then((r) {
|
||||||
_messageQueue.getActualMessages().forEach((message){
|
_messageQueue.getActualMessages().forEach((message){
|
||||||
Logger.d( "[Sending queued] ==> $message");
|
Logger.d( "[Sending queued] ==> $message");
|
||||||
@ -369,7 +447,7 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
message += '}';
|
message += '}';
|
||||||
}
|
}
|
||||||
return _send(message, true);
|
return _rawSend(message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleEntityStateChange(Map eventData) {
|
void _handleEntityStateChange(Map eventData) {
|
||||||
@ -583,11 +661,11 @@ class HomeAssistant {
|
|||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
//String endTime = formatDate(now, [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
//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 startTime = formatDate(now.subtract(Duration(hours: 24)), [yyyy, '-', mm, '-', dd, 'T', HH, ':', nn, ':', ss, z]);
|
||||||
String url = "$httpAPIEndpoint/api/history/period/$startTime?&filter_entity_id=$entityId";
|
String url = "$httpWebHost/api/history/period/$startTime?&filter_entity_id=$entityId";
|
||||||
Logger.d("[Sending] ==> $url");
|
Logger.d("[Sending] ==> $url");
|
||||||
http.Response historyResponse;
|
http.Response historyResponse;
|
||||||
historyResponse = await http.get(url, headers: {
|
historyResponse = await http.get(url, headers: {
|
||||||
"authorization": "Bearer $_password",
|
"authorization": "Bearer $_token",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
});
|
});
|
||||||
var history = json.decode(historyResponse.body);
|
var history = json.decode(historyResponse.body);
|
||||||
@ -599,20 +677,33 @@ class HomeAssistant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future sendHTTPRequest(String data) async {
|
Future sendHTTPPost({String endPoint, String data, String contentType: "application/json", bool includeAuthHeader: true}) async {
|
||||||
String url = "$httpAPIEndpoint/api/notify.fcm-android";
|
Completer completer = Completer();
|
||||||
|
String url = "$httpWebHost$endPoint";
|
||||||
Logger.d("[Sending] ==> $url");
|
Logger.d("[Sending] ==> $url");
|
||||||
http.Response response;
|
Map<String, String> headers = {};
|
||||||
response = await http.post(
|
if (contentType != null) {
|
||||||
|
headers["Content-Type"] = contentType;
|
||||||
|
}
|
||||||
|
if (includeAuthHeader) {
|
||||||
|
headers["authorization"] = "Bearer $_token";
|
||||||
|
}
|
||||||
|
http.post(
|
||||||
url,
|
url,
|
||||||
headers: {
|
headers: headers,
|
||||||
"authorization": "Bearer $_password",
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
body: data
|
body: data
|
||||||
);
|
).then((response) {
|
||||||
//var resData = json.decode(response.body);
|
|
||||||
Logger.d("[Received] <== ${response.statusCode}, ${response.body}");
|
Logger.d("[Received] <== ${response.statusCode}, ${response.body}");
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
completer.complete(response.body);
|
||||||
|
} else {
|
||||||
|
completer.completeError({"code": response.statusCode, "message": "${response.body}"});
|
||||||
|
}
|
||||||
|
}).catchError((e) {
|
||||||
|
completer.completeError(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return completer.future;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +169,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
StreamSubscription _serviceCallSubscription;
|
StreamSubscription _serviceCallSubscription;
|
||||||
StreamSubscription _showEntityPageSubscription;
|
StreamSubscription _showEntityPageSubscription;
|
||||||
StreamSubscription _showErrorSubscription;
|
StreamSubscription _showErrorSubscription;
|
||||||
|
StreamSubscription _startAuthSubscription;
|
||||||
|
StreamSubscription _reloadUISubscription;
|
||||||
//bool _settingsLoaded = false;
|
//bool _settingsLoaded = false;
|
||||||
bool _accountMenuExpanded = false;
|
bool _accountMenuExpanded = false;
|
||||||
//bool _useLovelaceUI;
|
//bool _useLovelaceUI;
|
||||||
@ -239,6 +241,11 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (_reloadUISubscription == null) {
|
||||||
|
_reloadUISubscription = eventBus.on<ReloadUIEvent>().listen((event){
|
||||||
|
_refreshData();
|
||||||
|
});
|
||||||
|
}
|
||||||
if (_serviceCallSubscription == null) {
|
if (_serviceCallSubscription == null) {
|
||||||
_serviceCallSubscription =
|
_serviceCallSubscription =
|
||||||
eventBus.on<ServiceCallEvent>().listen((event) {
|
eventBus.on<ServiceCallEvent>().listen((event) {
|
||||||
@ -260,9 +267,28 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_firebaseMessaging.getToken().then((String token) {
|
if (_startAuthSubscription == null) {
|
||||||
|
_startAuthSubscription = eventBus.on<StartAuthEvent>().listen((event){
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => WebviewScaffold(
|
||||||
|
url: "${event.oauthUrl}",
|
||||||
|
appBar: new AppBar(
|
||||||
|
title: new Text("Login"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*_firebaseMessaging.getToken().then((String token) {
|
||||||
//Logger.d("FCM token: $token");
|
//Logger.d("FCM token: $token");
|
||||||
widget.homeAssistant.sendHTTPRequest('{"token": "$token"}');
|
widget.homeAssistant.sendHTTPPost(
|
||||||
|
endPoint: '/api/notify.fcm-android',
|
||||||
|
jsonData: '{"token": "$token"}'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
_firebaseMessaging.configure(
|
_firebaseMessaging.configure(
|
||||||
onLaunch: (data) {
|
onLaunch: (data) {
|
||||||
@ -274,13 +300,14 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
onResume: (data) {
|
onResume: (data) {
|
||||||
Logger.d("Notification [onResume]: $data");
|
Logger.d("Notification [onResume]: $data");
|
||||||
}
|
}
|
||||||
);
|
);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
_refreshData() async {
|
_refreshData() async {
|
||||||
//widget.homeAssistant.updateSettings(_webSocketApiEndpoint, _password, _useLovelaceUI);
|
//widget.homeAssistant.updateSettings(_webSocketApiEndpoint, _password, _useLovelaceUI);
|
||||||
_hideBottomBar();
|
_hideBottomBar();
|
||||||
_showInfoBottomBar(progress: true,);
|
_showInfoBottomBar(progress: true,);
|
||||||
|
Logger.d("Calling fetch()");
|
||||||
await widget.homeAssistant.fetch().then((result) {
|
await widget.homeAssistant.fetch().then((result) {
|
||||||
_hideBottomBar();
|
_hideBottomBar();
|
||||||
int currentViewCount = widget.homeAssistant.ui?.views?.length ?? 0;
|
int currentViewCount = widget.homeAssistant.ui?.views?.length ?? 0;
|
||||||
@ -390,7 +417,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
new ListTile(
|
new ListTile(
|
||||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:home-assistant")),
|
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:home-assistant")),
|
||||||
title: Text("Open Web UI"),
|
title: Text("Open Web UI"),
|
||||||
onTap: () => HAUtils.launchURL(widget.homeAssistant.httpAPIEndpoint),
|
onTap: () => HAUtils.launchURL(widget.homeAssistant.httpWebHost),
|
||||||
),
|
),
|
||||||
Divider()
|
Divider()
|
||||||
]);
|
]);
|
||||||
@ -715,14 +742,18 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
||||||
|
flutterWebviewPlugin.dispose();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_viewsTabController.dispose();
|
_viewsTabController?.dispose();
|
||||||
if (_stateSubscription != null) _stateSubscription.cancel();
|
_stateSubscription?.cancel();
|
||||||
if (_settingsSubscription != null) _settingsSubscription.cancel();
|
_settingsSubscription?.cancel();
|
||||||
if (_serviceCallSubscription != null) _serviceCallSubscription.cancel();
|
_serviceCallSubscription?.cancel();
|
||||||
if (_showEntityPageSubscription != null) _showEntityPageSubscription.cancel();
|
_showEntityPageSubscription?.cancel();
|
||||||
if (_showErrorSubscription != null) _showErrorSubscription.cancel();
|
_showErrorSubscription?.cancel();
|
||||||
widget.homeAssistant.disconnect();
|
_startAuthSubscription?.cancel();
|
||||||
|
_reloadUISubscription?.cancel();
|
||||||
|
widget.homeAssistant?.disconnect();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
part of 'main.dart';
|
part of 'main.dart';
|
||||||
|
|
||||||
class ConnectionSettingsPage extends StatefulWidget {
|
class ConnectionSettingsPage extends StatefulWidget {
|
||||||
ConnectionSettingsPage({Key key, this.title, this.homeAssistant}) : super(key: key);
|
ConnectionSettingsPage({Key key, this.title}) : super(key: key);
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final HomeAssistant homeAssistant;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ConnectionSettingsPageState createState() => new _ConnectionSettingsPageState();
|
_ConnectionSettingsPageState createState() => new _ConnectionSettingsPageState();
|
||||||
@ -23,20 +22,12 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
bool _newUseLovelace = true;
|
bool _newUseLovelace = true;
|
||||||
|
|
||||||
String oauthUrl;
|
String oauthUrl;
|
||||||
final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_loadSettings();
|
_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 {
|
_loadSettings() async {
|
||||||
@ -79,22 +70,6 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget webViewButton = RaisedButton(
|
|
||||||
color: Colors.blue[200],
|
|
||||||
onPressed: () {
|
|
||||||
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");
|
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
|
||||||
builder: (context) => WebviewScaffold(
|
|
||||||
url: oauthUrl,
|
|
||||||
appBar: new AppBar(
|
|
||||||
title: new Text("Login"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
));
|
|
||||||
},
|
|
||||||
child: Text("Login with Home Assistant")
|
|
||||||
);
|
|
||||||
return new Scaffold(
|
return new Scaffold(
|
||||||
appBar: new AppBar(
|
appBar: new AppBar(
|
||||||
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){
|
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){
|
||||||
@ -177,7 +152,6 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
"Try ports 80 and 443 if default is not working and you don't know why.",
|
"Try ports 80 and 443 if default is not working and you don't know why.",
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: Colors.grey),
|
||||||
),
|
),
|
||||||
webViewButton,
|
|
||||||
new TextField(
|
new TextField(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Access token"
|
labelText: "Access token"
|
||||||
|
@ -37,7 +37,7 @@ class Panel {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
HomeAssistantModel haModel = HomeAssistantModel.of(context);
|
HomeAssistantModel haModel = HomeAssistantModel.of(context);
|
||||||
String url = "${haModel.homeAssistant.httpAPIEndpoint}/$urlPath";
|
String url = "${haModel.homeAssistant.httpWebHost}/$urlPath";
|
||||||
Logger.d("Launching custom tab with $url");
|
Logger.d("Launching custom tab with $url");
|
||||||
HAUtils.launchURLInCustomTab(context, url);
|
HAUtils.launchURLInCustomTab(context, url);
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,16 @@ class RefreshDataFinishedEvent {
|
|||||||
RefreshDataFinishedEvent();
|
RefreshDataFinishedEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ReloadUIEvent {
|
||||||
|
ReloadUIEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartAuthEvent {
|
||||||
|
String oauthUrl;
|
||||||
|
|
||||||
|
StartAuthEvent(this.oauthUrl);
|
||||||
|
}
|
||||||
|
|
||||||
class ServiceCallEvent {
|
class ServiceCallEvent {
|
||||||
String domain;
|
String domain;
|
||||||
String service;
|
String service;
|
||||||
|
Reference in New Issue
Block a user