WIP: App settings refactoring
This commit is contained in:
parent
a20dfaf05e
commit
5683ab5158
@ -10,7 +10,7 @@ class Badges extends StatelessWidget {
|
|||||||
List<EntityWrapper> entitiesToShow = badges.getEntitiesToShow();
|
List<EntityWrapper> entitiesToShow = badges.getEntitiesToShow();
|
||||||
|
|
||||||
if (entitiesToShow.isNotEmpty) {
|
if (entitiesToShow.isNotEmpty) {
|
||||||
if (ConnectionManager().scrollBadges) {
|
if (AppSettings().scrollBadges) {
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: BoxConstraints.tightFor(height: 112),
|
constraints: BoxConstraints.tightFor(height: 112),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
@ -42,7 +42,7 @@ class _CameraStreamViewState extends State<CameraStreamView> {
|
|||||||
_jsMessageChannelName = 'HA_${_entity.entityId.replaceAll('.', '_')}';
|
_jsMessageChannelName = 'HA_${_entity.entityId.replaceAll('.', '_')}';
|
||||||
rootBundle.loadString('assets/html/cameraLiveView.html').then((file) {
|
rootBundle.loadString('assets/html/cameraLiveView.html').then((file) {
|
||||||
_webViewHtml = Uri.dataFromString(
|
_webViewHtml = Uri.dataFromString(
|
||||||
file.replaceFirst('{{stream_url}}', '${ConnectionManager().httpWebHost}${data["url"]}').replaceFirst('{{message_channel}}', _jsMessageChannelName),
|
file.replaceFirst('{{stream_url}}', '${AppSettings().httpWebHost}${data["url"]}').replaceFirst('{{message_channel}}', _jsMessageChannelName),
|
||||||
mimeType: 'text/html',
|
mimeType: 'text/html',
|
||||||
encoding: Encoding.getByName('utf-8')
|
encoding: Encoding.getByName('utf-8')
|
||||||
).toString();
|
).toString();
|
||||||
@ -69,7 +69,7 @@ class _CameraStreamViewState extends State<CameraStreamView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future _loadMJPEG() async {
|
Future _loadMJPEG() async {
|
||||||
_streamUrl = '${ConnectionManager().httpWebHost}/api/camera_proxy_stream/${_entity
|
_streamUrl = '${AppSettings().httpWebHost}/api/camera_proxy_stream/${_entity
|
||||||
.entityId}?token=${_entity.attributes['access_token']}';
|
.entityId}?token=${_entity.attributes['access_token']}';
|
||||||
_jsMessageChannelName = 'HA_${_entity.entityId.replaceAll('.', '_')}';
|
_jsMessageChannelName = 'HA_${_entity.entityId.replaceAll('.', '_')}';
|
||||||
var file = await rootBundle.loadString('assets/html/cameraView.html');
|
var file = await rootBundle.loadString('assets/html/cameraView.html');
|
||||||
|
@ -61,7 +61,7 @@ class EntityWrapper {
|
|||||||
case EntityUIAction.navigate: {
|
case EntityUIAction.navigate: {
|
||||||
if (uiAction.tapService != null && uiAction.tapService.startsWith("/")) {
|
if (uiAction.tapService != null && uiAction.tapService.startsWith("/")) {
|
||||||
//TODO handle local urls
|
//TODO handle local urls
|
||||||
Launcher.launchURLInBrowser('${ConnectionManager().httpWebHost}${uiAction.tapService}');
|
Launcher.launchURLInBrowser('${AppSettings().httpWebHost}${uiAction.tapService}');
|
||||||
} else {
|
} else {
|
||||||
Launcher.launchURLInBrowser(uiAction.tapService);
|
Launcher.launchURLInBrowser(uiAction.tapService);
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ class EntityWrapper {
|
|||||||
case EntityUIAction.navigate: {
|
case EntityUIAction.navigate: {
|
||||||
if (uiAction.holdService != null && uiAction.holdService.startsWith("/")) {
|
if (uiAction.holdService != null && uiAction.holdService.startsWith("/")) {
|
||||||
//TODO handle local urls
|
//TODO handle local urls
|
||||||
Launcher.launchURLInBrowser('${ConnectionManager().httpWebHost}${uiAction.holdService}');
|
Launcher.launchURLInBrowser('${AppSettings().httpWebHost}${uiAction.holdService}');
|
||||||
} else {
|
} else {
|
||||||
Launcher.launchURLInBrowser(uiAction.holdService);
|
Launcher.launchURLInBrowser(uiAction.holdService);
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ class EntityWrapper {
|
|||||||
case EntityUIAction.navigate: {
|
case EntityUIAction.navigate: {
|
||||||
if (uiAction.doubleTapService != null && uiAction.doubleTapService.startsWith("/")) {
|
if (uiAction.doubleTapService != null && uiAction.doubleTapService.startsWith("/")) {
|
||||||
//TODO handle local urls
|
//TODO handle local urls
|
||||||
Launcher.launchURLInBrowser('${ConnectionManager().httpWebHost}${uiAction.doubleTapService}');
|
Launcher.launchURLInBrowser('${AppSettings().httpWebHost}${uiAction.doubleTapService}');
|
||||||
} else {
|
} else {
|
||||||
Launcher.launchURLInBrowser(uiAction.doubleTapService);
|
Launcher.launchURLInBrowser(uiAction.doubleTapService);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ class HomeAssistant {
|
|||||||
_fetchCompleter = Completer();
|
_fetchCompleter = Completer();
|
||||||
List<Future> futures = [];
|
List<Future> futures = [];
|
||||||
if (!uiOnly) {
|
if (!uiOnly) {
|
||||||
if (entities == null) entities = EntityCollection(ConnectionManager().httpWebHost);
|
if (entities == null) entities = EntityCollection(AppSettings().httpWebHost);
|
||||||
futures.add(_getStates(null));
|
futures.add(_getStates(null));
|
||||||
futures.add(_getConfig(null));
|
futures.add(_getConfig(null));
|
||||||
futures.add(_getUserInfo(null));
|
futures.add(_getUserInfo(null));
|
||||||
@ -92,7 +92,7 @@ class HomeAssistant {
|
|||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
bool cached = prefs.getBool('cached');
|
bool cached = prefs.getBool('cached');
|
||||||
if (cached != null && cached) {
|
if (cached != null && cached) {
|
||||||
if (entities == null) entities = EntityCollection(ConnectionManager().httpWebHost);
|
if (entities == null) entities = EntityCollection(AppSettings().httpWebHost);
|
||||||
try {
|
try {
|
||||||
_getStates(prefs);
|
_getStates(prefs);
|
||||||
if (!autoUi) {
|
if (!autoUi) {
|
||||||
@ -194,7 +194,7 @@ class HomeAssistant {
|
|||||||
} else {
|
} else {
|
||||||
Completer completer = Completer();
|
Completer completer = Completer();
|
||||||
var additionalData;
|
var additionalData;
|
||||||
if (ConnectionManager().haVersion >= 107 && _lovelaceDashbordUrl != HomeAssistant.DEFAULT_DASHBOARD) {
|
if (AppSettings().haVersion >= 107 && _lovelaceDashbordUrl != HomeAssistant.DEFAULT_DASHBOARD) {
|
||||||
additionalData = {
|
additionalData = {
|
||||||
'url_path': _lovelaceDashbordUrl
|
'url_path': _lovelaceDashbordUrl
|
||||||
};
|
};
|
||||||
|
@ -187,12 +187,11 @@ void main() async {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
AppSettings().loadAppTheme();
|
||||||
AppTheme theme = AppTheme.values[prefs.getInt('app-theme') ?? AppTheme.defaultTheme.index];
|
|
||||||
|
|
||||||
runZoned(() {
|
runZoned(() {
|
||||||
runApp(new HAClientApp(
|
runApp(new HAClientApp(
|
||||||
theme: theme,
|
theme: AppSettings().appTheme,
|
||||||
));
|
));
|
||||||
}, onError: (error, stack) {
|
}, onError: (error, stack) {
|
||||||
_reportError(error, stack);
|
_reportError(error, stack);
|
||||||
@ -287,7 +286,7 @@ class _HAClientAppState extends State<HAClientApp> {
|
|||||||
"/quick-start": (context) => QuickStartPage(),
|
"/quick-start": (context) => QuickStartPage(),
|
||||||
"/haclient_zha": (context) => ZhaPage(),
|
"/haclient_zha": (context) => ZhaPage(),
|
||||||
"/auth": (context) => new standaloneWebview.WebviewScaffold(
|
"/auth": (context) => new standaloneWebview.WebviewScaffold(
|
||||||
url: "${ConnectionManager().oauthUrl}",
|
url: "${AppSettings().oauthUrl}",
|
||||||
appBar: new AppBar(
|
appBar: new AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.help),
|
icon: Icon(Icons.help),
|
||||||
|
@ -16,15 +16,25 @@ class AppSettings {
|
|||||||
String displayHostname;
|
String displayHostname;
|
||||||
String webSocketAPIEndpoint;
|
String webSocketAPIEndpoint;
|
||||||
String httpWebHost;
|
String httpWebHost;
|
||||||
String _token;
|
String longLivedToken;
|
||||||
String _tempToken;
|
String tempToken;
|
||||||
String oauthUrl;
|
String oauthUrl;
|
||||||
String webhookId;
|
String webhookId;
|
||||||
double haVersion;
|
double haVersion;
|
||||||
bool scrollBadges;
|
bool scrollBadges;
|
||||||
int appIntegrationVersion;
|
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 {
|
Future load(bool quick) async {
|
||||||
if (!quick) {
|
if (!quick) {
|
||||||
@ -36,13 +46,16 @@ class AppSettings {
|
|||||||
appIntegrationVersion = prefs.getInt('app-integration-version') ?? 0;
|
appIntegrationVersion = prefs.getInt('app-integration-version') ?? 0;
|
||||||
scrollBadges = prefs.getBool('scroll-badges') ?? true;
|
scrollBadges = prefs.getBool('scroll-badges') ?? true;
|
||||||
displayHostname = "$_domain:$_port";
|
displayHostname = "$_domain:$_port";
|
||||||
_webSocketAPIEndpoint =
|
webSocketAPIEndpoint =
|
||||||
"${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket";
|
"${prefs.getString('hassio-protocol')}://$_domain:$_port/api/websocket";
|
||||||
httpWebHost =
|
httpWebHost =
|
||||||
"${prefs.getString('hassio-res-protocol')}://$_domain:$_port";
|
"${prefs.getString('hassio-res-protocol')}://$_domain:$_port";
|
||||||
|
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
||||||
|
defaultLocationUpdateIntervalMinutes);
|
||||||
|
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
||||||
try {
|
try {
|
||||||
final storage = new FlutterSecureStorage();
|
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");
|
Logger.d("Long-lived token read successful");
|
||||||
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
||||||
'https://ha-client.app')}&redirect_uri=${Uri
|
'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() {
|
Future startAuth() {
|
||||||
return AuthManager().start(
|
return AuthManager().start(
|
||||||
oauthUrl: oauthUrl
|
oauthUrl: oauthUrl
|
||||||
).then((token) {
|
).then((token) {
|
||||||
Logger.d("Token from AuthManager recived");
|
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() {
|
bool isNotConfigured() {
|
||||||
return _domain == null && _port == null && webhookId == null && mobileAppDeviceName == null;
|
return _domain == null && _port == null && webhookId == null && mobileAppDeviceName == null;
|
||||||
}
|
}
|
||||||
|
@ -212,16 +212,16 @@ class ConnectionManager {
|
|||||||
Logger.d( "[Sending] ==> auth request");
|
Logger.d( "[Sending] ==> auth request");
|
||||||
sendSocketMessage(
|
sendSocketMessage(
|
||||||
type: "auth",
|
type: "auth",
|
||||||
additionalData: {"access_token": "$_token"},
|
additionalData: {"access_token": "${AppSettings().longLivedToken}"},
|
||||||
auth: true
|
auth: true
|
||||||
).then((_) {
|
).then((_) {
|
||||||
completer.complete();
|
completer.complete();
|
||||||
}).catchError((e) => completer.completeError(e));
|
}).catchError((e) => completer.completeError(e));
|
||||||
} else if (_tempToken != null) {
|
} else if (AppSettings().isTempAuthenticated != null) {
|
||||||
Logger.d("We have temp token. Loging in...");
|
Logger.d("We have temp token. Loging in...");
|
||||||
sendSocketMessage(
|
sendSocketMessage(
|
||||||
type: "auth",
|
type: "auth",
|
||||||
additionalData: {"access_token": "$_tempToken"},
|
additionalData: {"access_token": "${AppSettings().tempToken}"},
|
||||||
auth: true
|
auth: true
|
||||||
).then((_) {
|
).then((_) {
|
||||||
Logger.d("Requesting long-lived token...");
|
Logger.d("Requesting long-lived token...");
|
||||||
@ -239,35 +239,17 @@ class ConnectionManager {
|
|||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future logout() {
|
Future logout() async {
|
||||||
Logger.d("Logging out");
|
Logger.d("Logging out");
|
||||||
Completer completer = Completer();
|
await _disconnect();
|
||||||
_disconnect().whenComplete(() {
|
await AppSettings().clearTokens();
|
||||||
_token = null;
|
|
||||||
_tempToken = null;
|
|
||||||
final storage = new FlutterSecureStorage();
|
|
||||||
storage.delete(key: "hacl_llt").whenComplete((){
|
|
||||||
completer.complete();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return completer.future;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _getLongLivedToken() {
|
Future _getLongLivedToken() {
|
||||||
Completer completer = Completer();
|
Completer completer = Completer();
|
||||||
sendSocketMessage(type: "auth/long_lived_access_token", additionalData: {"client_name": "HA Client app ${DateTime.now().millisecondsSinceEpoch}", "lifespan": 365}).then((data) {
|
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.");
|
Logger.d("Got long-lived token.");
|
||||||
_token = data;
|
AppSettings().saveLongLivedToken(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;
|
|
||||||
});
|
|
||||||
}).catchError((e) {
|
}).catchError((e) {
|
||||||
completer.completeError(HACException("Authentication error: $e", actions: [HAErrorAction.reload(title: "Retry"), HAErrorAction.loginAgain(title: "Relogin")]));
|
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();
|
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 = "$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");
|
Logger.d("[Sending] ==> HTTP /api/history/period/$startTime?&filter_entity_id=$entityId");
|
||||||
http.Response historyResponse;
|
http.Response historyResponse;
|
||||||
historyResponse = await http.get(url, headers: {
|
historyResponse = await http.get(url, headers: {
|
||||||
"authorization": "Bearer $_token",
|
"authorization": "Bearer ${AppSettings().longLivedToken}",
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
});
|
});
|
||||||
var history = json.decode(historyResponse.body);
|
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 {
|
Future sendHTTPPost({String endPoint, String data, String contentType: "application/json", bool includeAuthHeader: true}) async {
|
||||||
Completer completer = Completer();
|
Completer completer = Completer();
|
||||||
String url = "$httpWebHost$endPoint";
|
String url = "${AppSettings().httpWebHost}$endPoint";
|
||||||
Logger.d("[Sending] ==> HTTP $endPoint");
|
Logger.d("[Sending] ==> HTTP $endPoint");
|
||||||
Map<String, String> headers = {};
|
Map<String, String> headers = {};
|
||||||
if (contentType != null) {
|
if (contentType != null) {
|
||||||
headers["Content-Type"] = contentType;
|
headers["Content-Type"] = contentType;
|
||||||
}
|
}
|
||||||
if (includeAuthHeader) {
|
if (includeAuthHeader) {
|
||||||
headers["authorization"] = "Bearer $_token";
|
headers["authorization"] = "Bearer ${AppSettings().longLivedToken}";
|
||||||
}
|
}
|
||||||
http.post(
|
http.post(
|
||||||
url,
|
url,
|
||||||
|
@ -13,68 +13,53 @@ class LocationManager {
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
final int defaultUpdateIntervalMinutes = 20;
|
|
||||||
final String backgroundTaskId = "haclocationtask0";
|
final String backgroundTaskId = "haclocationtask0";
|
||||||
final String backgroundTaskTag = "haclocation";
|
final String backgroundTaskTag = "haclocation";
|
||||||
Duration _updateInterval;
|
|
||||||
bool _isRunning;
|
|
||||||
|
|
||||||
void init() async {
|
void init() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
if (AppSettings().locationTrackingEnabled) {
|
||||||
await prefs.reload();
|
|
||||||
_updateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
|
||||||
defaultUpdateIntervalMinutes);
|
|
||||||
_isRunning = prefs.getBool("location-enabled") ?? false;
|
|
||||||
if (_isRunning) {
|
|
||||||
await _startLocationService();
|
await _startLocationService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSettings(bool enabled, int interval) async {
|
setSettings(bool enabled, int interval) async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
if (interval != AppSettings().locationUpdateInterval.inMinutes) {
|
||||||
if (interval != _updateInterval.inMinutes) {
|
await _stopLocationService();
|
||||||
prefs.setInt("location-interval", interval);
|
|
||||||
_updateInterval = Duration(minutes: interval);
|
|
||||||
if (_isRunning) {
|
|
||||||
Logger.d("Stopping location tracking...");
|
|
||||||
_isRunning = false;
|
|
||||||
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");
|
Logger.d("Starting location tracking");
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
prefs.setBool("location-enabled", enabled);
|
|
||||||
_isRunning = true;
|
|
||||||
await _startLocationService();
|
await _startLocationService();
|
||||||
} else if (!enabled && _isRunning) {
|
} else if (!enabled && AppSettings().locationTrackingEnabled) {
|
||||||
Logger.d("Stopping location tracking...");
|
Logger.d("Stopping location tracking...");
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
prefs.setBool("location-enabled", enabled);
|
|
||||||
_isRunning = false;
|
|
||||||
await _stopLocationService();
|
await _stopLocationService();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startLocationService() async {
|
_startLocationService() async {
|
||||||
String webhookId = ConnectionManager().webhookId;
|
String webhookId = AppSettings().webhookId;
|
||||||
String httpWebHost = ConnectionManager().httpWebHost;
|
String httpWebHost = AppSettings().httpWebHost;
|
||||||
if (webhookId != null && webhookId.isNotEmpty) {
|
if (webhookId != null && webhookId.isNotEmpty) {
|
||||||
Duration interval;
|
Duration interval;
|
||||||
int delayFactor;
|
int delayFactor;
|
||||||
int taskCount;
|
int taskCount;
|
||||||
Logger.d("Starting location update for every ${_updateInterval
|
Logger.d("Starting location update for every ${AppSettings().locationUpdateInterval
|
||||||
.inMinutes} minutes...");
|
.inMinutes} minutes...");
|
||||||
if (_updateInterval.inMinutes == 10) {
|
if (AppSettings().locationUpdateInterval.inMinutes == 10) {
|
||||||
interval = Duration(minutes: 20);
|
interval = Duration(minutes: 20);
|
||||||
taskCount = 2;
|
taskCount = 2;
|
||||||
delayFactor = 10;
|
delayFactor = 10;
|
||||||
} else if (_updateInterval.inMinutes == 5) {
|
} else if (AppSettings().locationUpdateInterval.inMinutes == 5) {
|
||||||
interval = Duration(minutes: 15);
|
interval = Duration(minutes: 15);
|
||||||
taskCount = 3;
|
taskCount = 3;
|
||||||
delayFactor = 5;
|
delayFactor = 5;
|
||||||
} else {
|
} else {
|
||||||
interval = _updateInterval;
|
interval = AppSettings().locationUpdateInterval;
|
||||||
taskCount = 1;
|
taskCount = 1;
|
||||||
delayFactor = 0;
|
delayFactor = 0;
|
||||||
}
|
}
|
||||||
@ -112,8 +97,8 @@ class LocationManager {
|
|||||||
Logger.d("[Foreground location] Started");
|
Logger.d("[Foreground location] Started");
|
||||||
Geolocator geolocator = Geolocator();
|
Geolocator geolocator = Geolocator();
|
||||||
var battery = Battery();
|
var battery = Battery();
|
||||||
String webhookId = ConnectionManager().webhookId;
|
String webhookId = AppSettings().webhookId;
|
||||||
String httpWebHost = ConnectionManager().httpWebHost;
|
String httpWebHost = AppSettings().httpWebHost;
|
||||||
if (webhookId != null && webhookId.isNotEmpty) {
|
if (webhookId != null && webhookId.isNotEmpty) {
|
||||||
Logger.d("[Foreground location] Getting battery level...");
|
Logger.d("[Foreground location] Getting battery level...");
|
||||||
int batteryLevel = await battery.batteryLevel;
|
int batteryLevel = await battery.batteryLevel;
|
||||||
|
@ -25,9 +25,9 @@ class MobileAppIntegrationManager {
|
|||||||
|
|
||||||
static Future checkAppRegistration() {
|
static Future checkAppRegistration() {
|
||||||
Completer completer = Completer();
|
Completer completer = Completer();
|
||||||
_appRegistrationData["device_name"] = ConnectionManager().mobileAppDeviceName ?? getDefaultDeviceName();
|
_appRegistrationData["device_name"] = AppSettings().mobileAppDeviceName ?? getDefaultDeviceName();
|
||||||
(_appRegistrationData["app_data"] as Map)["push_token"] = "${HomeAssistant().fcmToken}";
|
(_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...");
|
Logger.d("Mobile app was not registered yet. Registering...");
|
||||||
var registrationData = Map.from(_appRegistrationData);
|
var registrationData = Map.from(_appRegistrationData);
|
||||||
registrationData.addAll({
|
registrationData.addAll({
|
||||||
@ -36,7 +36,7 @@ class MobileAppIntegrationManager {
|
|||||||
"os_name": DeviceInfoManager().osName,
|
"os_name": DeviceInfoManager().osName,
|
||||||
"supports_encryption": false,
|
"supports_encryption": false,
|
||||||
});
|
});
|
||||||
if (ConnectionManager().haVersion >= 104) {
|
if (AppSettings().haVersion >= 104) {
|
||||||
registrationData.addAll({
|
registrationData.addAll({
|
||||||
"device_id": "${DeviceInfoManager().unicDeviceId}"
|
"device_id": "${DeviceInfoManager().unicDeviceId}"
|
||||||
});
|
});
|
||||||
@ -48,12 +48,12 @@ class MobileAppIntegrationManager {
|
|||||||
).then((response) {
|
).then((response) {
|
||||||
Logger.d("Processing registration responce...");
|
Logger.d("Processing registration responce...");
|
||||||
var responseObject = json.decode(response);
|
var responseObject = json.decode(response);
|
||||||
ConnectionManager().webhookId = responseObject["webhook_id"];
|
AppSettings().webhookId = responseObject["webhook_id"];
|
||||||
ConnectionManager().appIntegrationVersion = INTEGRATION_VERSION;
|
AppSettings().appIntegrationVersion = INTEGRATION_VERSION;
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
AppSettings().save({
|
||||||
prefs.setString("app-webhook-id", responseObject["webhook_id"]);
|
'app-webhook-id': responseObject["webhook_id"],
|
||||||
prefs.setInt('app-integration-version', INTEGRATION_VERSION);
|
'app-integration-version': INTEGRATION_VERSION
|
||||||
|
}).then((prefs) {
|
||||||
completer.complete();
|
completer.complete();
|
||||||
eventBus.fire(ShowPopupEvent(
|
eventBus.fire(ShowPopupEvent(
|
||||||
popup: Popup(
|
popup: Popup(
|
||||||
@ -84,7 +84,7 @@ class MobileAppIntegrationManager {
|
|||||||
"data": _appRegistrationData
|
"data": _appRegistrationData
|
||||||
};
|
};
|
||||||
ConnectionManager().sendHTTPPost(
|
ConnectionManager().sendHTTPPost(
|
||||||
endPoint: "/api/webhook/${ConnectionManager().webhookId}",
|
endPoint: "/api/webhook/${AppSettings().webhookId}",
|
||||||
includeAuthHeader: false,
|
includeAuthHeader: false,
|
||||||
data: json.encode(updateData)
|
data: json.encode(updateData)
|
||||||
).then((response) {
|
).then((response) {
|
||||||
@ -98,7 +98,7 @@ class MobileAppIntegrationManager {
|
|||||||
Logger.w("No registration data in response. MobileApp integration was removed or broken");
|
Logger.w("No registration data in response. MobileApp integration was removed or broken");
|
||||||
_askToRegisterApp();
|
_askToRegisterApp();
|
||||||
} else {
|
} else {
|
||||||
if (INTEGRATION_VERSION > ConnectionManager().appIntegrationVersion) {
|
if (INTEGRATION_VERSION > AppSettings().appIntegrationVersion) {
|
||||||
Logger.d('App registration needs to be updated');
|
Logger.d('App registration needs to be updated');
|
||||||
_askToRemoveAndRegisterApp();
|
_askToRemoveAndRegisterApp();
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,7 +246,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
|
|
||||||
void _showOAuth() {
|
void _showOAuth() {
|
||||||
_preventAppRefresh = true;
|
_preventAppRefresh = true;
|
||||||
Navigator.of(context).pushNamed("/auth", arguments: {"url": ConnectionManager().oauthUrl});
|
Navigator.of(context).pushNamed("/auth", arguments: {"url": AppSettings().oauthUrl});
|
||||||
}
|
}
|
||||||
|
|
||||||
_setErrorState(HACException e) {
|
_setErrorState(HACException e) {
|
||||||
@ -463,7 +463,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
child: new Text("Reload"),
|
child: new Text("Reload"),
|
||||||
value: "reload",
|
value: "reload",
|
||||||
));
|
));
|
||||||
if (ConnectionManager().isAuthenticated) {
|
if (AppSettings().isAuthenticated) {
|
||||||
_showLoginButton = false;
|
_showLoginButton = false;
|
||||||
serviceMenuItems.add(
|
serviceMenuItems.add(
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
|
@ -39,7 +39,7 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
|
|||||||
_buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:network'), 'Connection settings', AppSettingsSection.connectionSettings),
|
_buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:network'), 'Connection settings', AppSettingsSection.connectionSettings),
|
||||||
_buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:brush'), 'Look and feel', AppSettingsSection.lookAndFeel),
|
_buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:brush'), 'Look and feel', AppSettingsSection.lookAndFeel),
|
||||||
];
|
];
|
||||||
if (ConnectionManager().webhookId != null) {
|
if (AppSettings().webhookId != null) {
|
||||||
items.insert(1, _buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:cellphone-android'), 'Integration settings', AppSettingsSection.integrationSettings));
|
items.insert(1, _buildMenuItem(context, MaterialDesignIcons.getIconDataFromIconName('mdi:cellphone-android'), 'Integration settings', AppSettingsSection.integrationSettings));
|
||||||
}
|
}
|
||||||
return ListView(
|
return ListView(
|
||||||
|
@ -31,7 +31,7 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_loadSettings() async {
|
_loadSettings() async {
|
||||||
_includeDeviceName = widget.quickStart || ConnectionManager().webhookId == null;
|
_includeDeviceName = widget.quickStart || AppSettings().webhookId == null;
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
String domain = prefs.getString('hassio-domain')?? '';
|
String domain = prefs.getString('hassio-domain')?? '';
|
||||||
String port = prefs.getString('hassio-port') ?? '';
|
String port = prefs.getString('hassio-port') ?? '';
|
||||||
|
@ -11,7 +11,7 @@ class IntegrationSettingsPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||||
|
|
||||||
int _locationInterval = LocationManager().defaultUpdateIntervalMinutes;
|
int _locationInterval = AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||||
bool _locationTrackingEnabled = false;
|
bool _locationTrackingEnabled = false;
|
||||||
bool _wait = false;
|
bool _wait = false;
|
||||||
|
|
||||||
@ -28,7 +28,8 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
SharedPreferences.getInstance().then((prefs) {
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
_locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
||||||
_locationInterval = prefs.getInt("location-interval") ?? LocationManager().defaultUpdateIntervalMinutes;
|
_locationInterval = prefs.getInt("location-interval") ??
|
||||||
|
AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||||
if (_locationInterval % 5 != 0) {
|
if (_locationInterval % 5 != 0) {
|
||||||
_locationInterval = 5 * (_locationInterval ~/ 5);
|
_locationInterval = 5 * (_locationInterval ~/ 5);
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ class _LookAndFeelSettingsPageState extends State<LookAndFeelSettingsPage> {
|
|||||||
|
|
||||||
Future _saveOther() async {
|
Future _saveOther() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
ConnectionManager().scrollBadges = _scrollBadges;
|
AppSettings().scrollBadges = _scrollBadges;
|
||||||
await prefs.setBool('scroll-badges', _scrollBadges);
|
await prefs.setBool('scroll-badges', _scrollBadges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ class _ConfigPanelWidgetState extends State<ConfigPanelWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
LinkToWebConfig(name: "Home Assistant configuration", url: ConnectionManager().httpWebHost+"/config"),
|
LinkToWebConfig(name: "Home Assistant configuration", url: AppSettings().httpWebHost+"/config"),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class Panel {
|
|||||||
eventBus.fire(ReloadUIEvent());
|
eventBus.fire(ReloadUIEvent());
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Launcher.launchAuthenticatedWebView(context: context, url: "${ConnectionManager().httpWebHost}/$urlPath", title: "${this.title}");
|
Launcher.launchAuthenticatedWebView(context: context, url: "${AppSettings().httpWebHost}/$urlPath", title: "${this.title}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,14 +153,14 @@ class RegisterAppPopup extends Popup {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
initialValue: ConnectionManager().mobileAppDeviceName ?? MobileAppIntegrationManager.getDefaultDeviceName(),
|
initialValue: AppSettings().mobileAppDeviceName ?? MobileAppIntegrationManager.getDefaultDeviceName(),
|
||||||
onSaved: (newValue) {
|
onSaved: (newValue) {
|
||||||
String deviceName = newValue?.trim();
|
String deviceName = newValue?.trim();
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
prefs.remove("app-webhook-id");
|
prefs.remove("app-webhook-id");
|
||||||
prefs.setString('app-integration-device-name', deviceName);
|
prefs.setString('app-integration-device-name', deviceName);
|
||||||
ConnectionManager().webhookId = null;
|
AppSettings().webhookId = null;
|
||||||
ConnectionManager().mobileAppDeviceName = deviceName;
|
AppSettings().mobileAppDeviceName = deviceName;
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
MobileAppIntegrationManager.checkAppRegistration();
|
MobileAppIntegrationManager.checkAppRegistration();
|
||||||
});
|
});
|
||||||
|
@ -45,7 +45,7 @@ class Launcher {
|
|||||||
if (viewState.type == standaloneWebview.WebViewState.startLoad) {
|
if (viewState.type == standaloneWebview.WebViewState.startLoad) {
|
||||||
Logger.d("[WebView] Injecting external auth JS");
|
Logger.d("[WebView] Injecting external auth JS");
|
||||||
rootBundle.loadString('assets/js/externalAuth.js').then((js){
|
rootBundle.loadString('assets/js/externalAuth.js').then((js){
|
||||||
flutterWebViewPlugin.evalJavascript(js.replaceFirst("[token]", ConnectionManager()._token));
|
flutterWebViewPlugin.evalJavascript(js.replaceFirst("[token]", AppSettings().longLivedToken));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user