WIP: App settings refactoring

This commit is contained in:
Yegor Vialov
2020-05-13 12:46:25 +00:00
parent a20dfaf05e
commit 5683ab5158
18 changed files with 129 additions and 106 deletions

View File

@ -16,15 +16,25 @@ class AppSettings {
String displayHostname;
String webSocketAPIEndpoint;
String httpWebHost;
String _token;
String _tempToken;
String longLivedToken;
String tempToken;
String oauthUrl;
String webhookId;
double haVersion;
bool scrollBadges;
int appIntegrationVersion;
AppTheme appTheme;
final int defaultLocationUpdateIntervalMinutes = 20;
Duration locationUpdateInterval;
bool locationTrackingEnabled = false;
bool get isAuthenticated => _token != null;
bool get isAuthenticated => longLivedToken != null;
bool get isTempAuthenticated => tempToken != null;
loadAppTheme() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
appTheme = AppTheme.values[prefs.getInt('app-theme') ?? AppTheme.defaultTheme.index];
}
Future load(bool quick) async {
if (!quick) {
@ -36,13 +46,16 @@ class AppSettings {
appIntegrationVersion = prefs.getInt('app-integration-version') ?? 0;
scrollBadges = prefs.getBool('scroll-badges') ?? true;
displayHostname = "$_domain:$_port";
_webSocketAPIEndpoint =
webSocketAPIEndpoint =
"${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket";
httpWebHost =
"${prefs.getString('hassio-res-protocol')}://$_domain:$_port";
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
defaultLocationUpdateIntervalMinutes);
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
try {
final storage = new FlutterSecureStorage();
_token = await storage.read(key: "hacl_llt");
longLivedToken = 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
@ -54,15 +67,58 @@ class AppSettings {
}
}
Future save(Map<String, dynamic> settings) async {
if (settings != null && settings.isNotEmpty) {
SharedPreferences prefs = await SharedPreferences.getInstance();
settings.forEach((k,v) async {
if (v is String) {
await prefs.setString(k, v);
} else if (v is bool) {
await prefs.setBool(k ,v);
} else if (v is int) {
await prefs.setInt(k ,v);
} else if (v is double) {
await prefs.setDouble(k, v);
} else {
Logger.e('Unknown setting type: <$k, $v>');
}
});
}
}
Future startAuth() {
return AuthManager().start(
oauthUrl: oauthUrl
).then((token) {
Logger.d("Token from AuthManager recived");
_tempToken = token;
tempToken = token;
});
}
Future clearTokens() async {
longLivedToken = null;
tempToken = null;
try {
final storage = new FlutterSecureStorage();
await storage.delete(key: "hacl_llt");
} catch(e, stacktrace) {
Logger.e("Error clearing tokens: $e", stacktrace: stacktrace);
}
}
Future saveLongLivedToken(token) async {
longLivedToken = token;
tempToken = null;
try {
final storage = new FlutterSecureStorage();
await storage.write(key: "hacl_llt", value: "$longLivedToken");
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("oauth-used", true);
} catch(e, stacktrace) {
Logger.e("Error saving long-lived token: $e", stacktrace: stacktrace);
}
}
bool isNotConfigured() {
return _domain == null && _port == null && webhookId == null && mobileAppDeviceName == null;
}

View File

@ -212,16 +212,16 @@ class ConnectionManager {
Logger.d( "[Sending] ==> auth request");
sendSocketMessage(
type: "auth",
additionalData: {"access_token": "$_token"},
additionalData: {"access_token": "${AppSettings().longLivedToken}"},
auth: true
).then((_) {
completer.complete();
}).catchError((e) => completer.completeError(e));
} else if (_tempToken != null) {
} else if (AppSettings().isTempAuthenticated != null) {
Logger.d("We have temp token. Loging in...");
sendSocketMessage(
type: "auth",
additionalData: {"access_token": "$_tempToken"},
additionalData: {"access_token": "${AppSettings().tempToken}"},
auth: true
).then((_) {
Logger.d("Requesting long-lived token...");
@ -239,35 +239,17 @@ class ConnectionManager {
return completer.future;
}
Future logout() {
Future logout() async {
Logger.d("Logging out");
Completer completer = Completer();
_disconnect().whenComplete(() {
_token = null;
_tempToken = null;
final storage = new FlutterSecureStorage();
storage.delete(key: "hacl_llt").whenComplete((){
completer.complete();
});
});
return completer.future;
await _disconnect();
await AppSettings().clearTokens();
}
Future _getLongLivedToken() {
Completer completer = Completer();
sendSocketMessage(type: "auth/long_lived_access_token", additionalData: {"client_name": "HA Client app ${DateTime.now().millisecondsSinceEpoch}", "lifespan": 365}).then((data) {
Logger.d("Got long-lived token.");
_token = data;
_tempToken = null;
final storage = new FlutterSecureStorage();
storage.write(key: "hacl_llt", value: "$_token").then((_) {
SharedPreferences.getInstance().then((prefs) {
prefs.setBool("oauth-used", true);
completer.complete();
});
}).catchError((e) {
throw e;
});
AppSettings().saveLongLivedToken(data);
}).catchError((e) {
completer.completeError(HACException("Authentication error: $e", actions: [HAErrorAction.reload(title: "Retry"), HAErrorAction.loginAgain(title: "Relogin")]));
});
@ -339,11 +321,11 @@ class ConnectionManager {
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 = "$httpWebHost/api/history/period/$startTime?&filter_entity_id=$entityId";
String url = "${AppSettings().httpWebHost}/api/history/period/$startTime?&filter_entity_id=$entityId";
Logger.d("[Sending] ==> HTTP /api/history/period/$startTime?&filter_entity_id=$entityId");
http.Response historyResponse;
historyResponse = await http.get(url, headers: {
"authorization": "Bearer $_token",
"authorization": "Bearer ${AppSettings().longLivedToken}",
"Content-Type": "application/json"
});
var history = json.decode(historyResponse.body);
@ -357,14 +339,14 @@ class ConnectionManager {
Future sendHTTPPost({String endPoint, String data, String contentType: "application/json", bool includeAuthHeader: true}) async {
Completer completer = Completer();
String url = "$httpWebHost$endPoint";
String url = "${AppSettings().httpWebHost}$endPoint";
Logger.d("[Sending] ==> HTTP $endPoint");
Map<String, String> headers = {};
if (contentType != null) {
headers["Content-Type"] = contentType;
}
if (includeAuthHeader) {
headers["authorization"] = "Bearer $_token";
headers["authorization"] = "Bearer ${AppSettings().longLivedToken}";
}
http.post(
url,

View File

@ -13,68 +13,53 @@ class LocationManager {
init();
}
final int defaultUpdateIntervalMinutes = 20;
final String backgroundTaskId = "haclocationtask0";
final String backgroundTaskTag = "haclocation";
Duration _updateInterval;
bool _isRunning;
void init() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.reload();
_updateInterval = Duration(minutes: prefs.getInt("location-interval") ??
defaultUpdateIntervalMinutes);
_isRunning = prefs.getBool("location-enabled") ?? false;
if (_isRunning) {
if (AppSettings().locationTrackingEnabled) {
await _startLocationService();
}
}
setSettings(bool enabled, int interval) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (interval != _updateInterval.inMinutes) {
prefs.setInt("location-interval", interval);
_updateInterval = Duration(minutes: interval);
if (_isRunning) {
Logger.d("Stopping location tracking...");
_isRunning = false;
await _stopLocationService();
}
if (interval != AppSettings().locationUpdateInterval.inMinutes) {
await _stopLocationService();
}
if (enabled && !_isRunning) {
AppSettings().save({
'location-interval': interval,
'location-enabled': enabled
});
AppSettings().locationUpdateInterval = Duration(minutes: interval);
AppSettings().locationTrackingEnabled = enabled;
if (enabled && !AppSettings().locationTrackingEnabled) {
Logger.d("Starting location tracking");
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("location-enabled", enabled);
_isRunning = true;
await _startLocationService();
} else if (!enabled && _isRunning) {
} else if (!enabled && AppSettings().locationTrackingEnabled) {
Logger.d("Stopping location tracking...");
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("location-enabled", enabled);
_isRunning = false;
await _stopLocationService();
}
}
_startLocationService() async {
String webhookId = ConnectionManager().webhookId;
String httpWebHost = ConnectionManager().httpWebHost;
String webhookId = AppSettings().webhookId;
String httpWebHost = AppSettings().httpWebHost;
if (webhookId != null && webhookId.isNotEmpty) {
Duration interval;
int delayFactor;
int taskCount;
Logger.d("Starting location update for every ${_updateInterval
Logger.d("Starting location update for every ${AppSettings().locationUpdateInterval
.inMinutes} minutes...");
if (_updateInterval.inMinutes == 10) {
if (AppSettings().locationUpdateInterval.inMinutes == 10) {
interval = Duration(minutes: 20);
taskCount = 2;
delayFactor = 10;
} else if (_updateInterval.inMinutes == 5) {
} else if (AppSettings().locationUpdateInterval.inMinutes == 5) {
interval = Duration(minutes: 15);
taskCount = 3;
delayFactor = 5;
} else {
interval = _updateInterval;
interval = AppSettings().locationUpdateInterval;
taskCount = 1;
delayFactor = 0;
}
@ -112,8 +97,8 @@ class LocationManager {
Logger.d("[Foreground location] Started");
Geolocator geolocator = Geolocator();
var battery = Battery();
String webhookId = ConnectionManager().webhookId;
String httpWebHost = ConnectionManager().httpWebHost;
String webhookId = AppSettings().webhookId;
String httpWebHost = AppSettings().httpWebHost;
if (webhookId != null && webhookId.isNotEmpty) {
Logger.d("[Foreground location] Getting battery level...");
int batteryLevel = await battery.batteryLevel;

View File

@ -25,9 +25,9 @@ class MobileAppIntegrationManager {
static Future checkAppRegistration() {
Completer completer = Completer();
_appRegistrationData["device_name"] = ConnectionManager().mobileAppDeviceName ?? getDefaultDeviceName();
_appRegistrationData["device_name"] = AppSettings().mobileAppDeviceName ?? getDefaultDeviceName();
(_appRegistrationData["app_data"] as Map)["push_token"] = "${HomeAssistant().fcmToken}";
if (ConnectionManager().webhookId == null) {
if (AppSettings().webhookId == null) {
Logger.d("Mobile app was not registered yet. Registering...");
var registrationData = Map.from(_appRegistrationData);
registrationData.addAll({
@ -36,7 +36,7 @@ class MobileAppIntegrationManager {
"os_name": DeviceInfoManager().osName,
"supports_encryption": false,
});
if (ConnectionManager().haVersion >= 104) {
if (AppSettings().haVersion >= 104) {
registrationData.addAll({
"device_id": "${DeviceInfoManager().unicDeviceId}"
});
@ -48,12 +48,12 @@ class MobileAppIntegrationManager {
).then((response) {
Logger.d("Processing registration responce...");
var responseObject = json.decode(response);
ConnectionManager().webhookId = responseObject["webhook_id"];
ConnectionManager().appIntegrationVersion = INTEGRATION_VERSION;
SharedPreferences.getInstance().then((prefs) {
prefs.setString("app-webhook-id", responseObject["webhook_id"]);
prefs.setInt('app-integration-version', INTEGRATION_VERSION);
AppSettings().webhookId = responseObject["webhook_id"];
AppSettings().appIntegrationVersion = INTEGRATION_VERSION;
AppSettings().save({
'app-webhook-id': responseObject["webhook_id"],
'app-integration-version': INTEGRATION_VERSION
}).then((prefs) {
completer.complete();
eventBus.fire(ShowPopupEvent(
popup: Popup(
@ -84,7 +84,7 @@ class MobileAppIntegrationManager {
"data": _appRegistrationData
};
ConnectionManager().sendHTTPPost(
endPoint: "/api/webhook/${ConnectionManager().webhookId}",
endPoint: "/api/webhook/${AppSettings().webhookId}",
includeAuthHeader: false,
data: json.encode(updateData)
).then((response) {
@ -98,7 +98,7 @@ class MobileAppIntegrationManager {
Logger.w("No registration data in response. MobileApp integration was removed or broken");
_askToRegisterApp();
} else {
if (INTEGRATION_VERSION > ConnectionManager().appIntegrationVersion) {
if (INTEGRATION_VERSION > AppSettings().appIntegrationVersion) {
Logger.d('App registration needs to be updated');
_askToRemoveAndRegisterApp();
} else {