Compare commits
20 Commits
rc/1.1.0-b
...
1.1.0-beta
Author | SHA1 | Date | |
---|---|---|---|
fec3c525e1 | |||
b1bbed6d80 | |||
13878cfc51 | |||
be49180205 | |||
c4a0b16553 | |||
caacd5e9f4 | |||
5fa28abb6c | |||
e0a28c0b59 | |||
096e714a04 | |||
78893ea01f | |||
90efb29be5 | |||
fca323c56b | |||
e5fe6af5f3 | |||
f0090d522d | |||
edbfd8359b | |||
2702bb254a | |||
ca7b6ed550 | |||
fb00b5d9ff | |||
7ffba397ce | |||
1080076e3b |
@ -1,5 +1,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.keyboardcrumbs.hassclient">
|
package="com.keyboardcrumbs.hassclient"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.touchscreen"
|
<uses-feature android:name="android.hardware.touchscreen"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
@ -16,6 +16,8 @@ import io.flutter.plugin.common.MethodChannel;
|
|||||||
|
|
||||||
import com.google.android.gms.tasks.OnCompleteListener;
|
import com.google.android.gms.tasks.OnCompleteListener;
|
||||||
import com.google.android.gms.tasks.Task;
|
import com.google.android.gms.tasks.Task;
|
||||||
|
import com.google.android.gms.common.GoogleApiAvailability;
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.firebase.iid.FirebaseInstanceId;
|
import com.google.firebase.iid.FirebaseInstanceId;
|
||||||
import com.google.firebase.iid.InstanceIdResult;
|
import com.google.firebase.iid.InstanceIdResult;
|
||||||
import com.google.firebase.messaging.FirebaseMessaging;
|
import com.google.firebase.messaging.FirebaseMessaging;
|
||||||
@ -31,28 +33,36 @@ public class MainActivity extends FlutterActivity {
|
|||||||
new MethodChannel.MethodCallHandler() {
|
new MethodChannel.MethodCallHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||||
|
Context context = getActivity();
|
||||||
if (call.method.equals("getFCMToken")) {
|
if (call.method.equals("getFCMToken")) {
|
||||||
FirebaseInstanceId.getInstance().getInstanceId()
|
if (checkPlayServices()) {
|
||||||
|
FirebaseInstanceId.getInstance().getInstanceId()
|
||||||
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
|
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(@NonNull Task<InstanceIdResult> task) {
|
public void onComplete(@NonNull Task<InstanceIdResult> task) {
|
||||||
if (task.isSuccessful()) {
|
if (task.isSuccessful()) {
|
||||||
Context context = getActivity();
|
|
||||||
String token = task.getResult().getToken();
|
String token = task.getResult().getToken();
|
||||||
UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
|
UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
|
||||||
updateTokenTask.execute(token);
|
updateTokenTask.execute(token);
|
||||||
result.success(token);
|
result.success(token);
|
||||||
} else {
|
} else {
|
||||||
result.error("fcm_error", task.getException().getMessage(), task.getException());
|
result.error("fcm_error", task.getException().getMessage(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
result.error("google_play_service_error", "Google Play Services unavailable", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkPlayServices() {
|
||||||
|
return (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -38,6 +38,15 @@ class CardData {
|
|||||||
case CardType.LIGHT:
|
case CardType.LIGHT:
|
||||||
return LightCardData(rawData);
|
return LightCardData(rawData);
|
||||||
break;
|
break;
|
||||||
|
case CardType.PICTURE_ELEMENTS:
|
||||||
|
//TODO temporary solution
|
||||||
|
if (rawData.containsKey('camera_image')) {
|
||||||
|
rawData['entity'] = rawData['camera_image'];
|
||||||
|
return ButtonCardData(rawData);
|
||||||
|
} else {
|
||||||
|
return CardData(null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CardType.ENTITY_BUTTON:
|
case CardType.ENTITY_BUTTON:
|
||||||
case CardType.BUTTON:
|
case CardType.BUTTON:
|
||||||
case CardType.PICTURE_ENTITY:
|
case CardType.PICTURE_ENTITY:
|
||||||
|
@ -16,7 +16,8 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'package:charts_flutter/flutter.dart' as charts;
|
import 'package:charts_flutter/flutter.dart' as charts;
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
|
import 'package:flutter_custom_tabs/flutter_custom_tabs.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:device_info/device_info.dart';
|
import 'package:device_info/device_info.dart';
|
||||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||||
import 'plugins/dynamic_multi_column_layout.dart';
|
import 'plugins/dynamic_multi_column_layout.dart';
|
||||||
@ -184,7 +185,13 @@ void main() async {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
AppSettings().loadAppTheme();
|
await AppSettings().loadStartupSettings();
|
||||||
|
await Hive.initFlutter();
|
||||||
|
if (AppSettings().displayMode == DisplayMode.fullscreen) {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays([]);
|
||||||
|
} else {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
|
||||||
|
}
|
||||||
|
|
||||||
runZoned(() {
|
runZoned(() {
|
||||||
runApp(new HAClientApp(
|
runApp(new HAClientApp(
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
part of '../main.dart';
|
part of '../main.dart';
|
||||||
|
|
||||||
|
enum DisplayMode {normal, fullscreen}
|
||||||
|
|
||||||
class AppSettings {
|
class AppSettings {
|
||||||
|
|
||||||
|
static const DEFAULT_HIVE_BOX = 'defaultSettingsBox';
|
||||||
|
|
||||||
|
static const AUTH_TOKEN_KEY = 'llt';
|
||||||
|
|
||||||
static final AppSettings _instance = AppSettings._internal();
|
static final AppSettings _instance = AppSettings._internal();
|
||||||
|
|
||||||
factory AppSettings() {
|
factory AppSettings() {
|
||||||
@ -22,6 +28,7 @@ class AppSettings {
|
|||||||
String webhookId;
|
String webhookId;
|
||||||
double haVersion;
|
double haVersion;
|
||||||
bool scrollBadges;
|
bool scrollBadges;
|
||||||
|
DisplayMode displayMode;
|
||||||
AppTheme appTheme;
|
AppTheme appTheme;
|
||||||
final int defaultLocationUpdateIntervalMinutes = 20;
|
final int defaultLocationUpdateIntervalMinutes = 20;
|
||||||
Duration locationUpdateInterval;
|
Duration locationUpdateInterval;
|
||||||
@ -30,13 +37,15 @@ class AppSettings {
|
|||||||
bool get isAuthenticated => longLivedToken != null;
|
bool get isAuthenticated => longLivedToken != null;
|
||||||
bool get isTempAuthenticated => tempToken != null;
|
bool get isTempAuthenticated => tempToken != null;
|
||||||
|
|
||||||
loadAppTheme() async {
|
loadStartupSettings() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
appTheme = AppTheme.values[prefs.getInt('app-theme') ?? AppTheme.defaultTheme.index];
|
appTheme = AppTheme.values[prefs.getInt('app-theme') ?? AppTheme.defaultTheme.index];
|
||||||
|
displayMode = DisplayMode.values[prefs.getInt('display-mode') ?? DisplayMode.normal.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future load(bool full) async {
|
Future load(bool full) async {
|
||||||
if (full) {
|
if (full) {
|
||||||
|
await Hive.openBox(DEFAULT_HIVE_BOX);
|
||||||
Logger.d('Loading settings...');
|
Logger.d('Loading settings...');
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
_domain = prefs.getString('hassio-domain');
|
_domain = prefs.getString('hassio-domain');
|
||||||
@ -52,18 +61,11 @@ class AppSettings {
|
|||||||
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
locationUpdateInterval = Duration(minutes: prefs.getInt("location-interval") ??
|
||||||
defaultLocationUpdateIntervalMinutes);
|
defaultLocationUpdateIntervalMinutes);
|
||||||
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
||||||
Logger.d('Done. $_domain:$_port');
|
longLivedToken = Hive.box(DEFAULT_HIVE_BOX).get(AUTH_TOKEN_KEY);
|
||||||
try {
|
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
||||||
final storage = new FlutterSecureStorage();
|
'https://ha-client.app')}&redirect_uri=${Uri
|
||||||
longLivedToken = await storage.read(key: "hacl_llt");
|
.encodeComponent(
|
||||||
Logger.d("Long-lived token read successful");
|
'https://ha-client.app/service/auth_callback.html')}";
|
||||||
oauthUrl = "$httpWebHost/auth/authorize?client_id=${Uri.encodeComponent(
|
|
||||||
'https://ha-client.app')}&redirect_uri=${Uri
|
|
||||||
.encodeComponent(
|
|
||||||
'https://ha-client.app/service/auth_callback.html')}";
|
|
||||||
} catch (e, stacktrace) {
|
|
||||||
Logger.e("Error reading secure storage: $e", stacktrace: stacktrace);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,25 +105,13 @@ class AppSettings {
|
|||||||
Future clearTokens() async {
|
Future clearTokens() async {
|
||||||
longLivedToken = null;
|
longLivedToken = null;
|
||||||
tempToken = null;
|
tempToken = null;
|
||||||
try {
|
Hive.box(DEFAULT_HIVE_BOX).delete(AUTH_TOKEN_KEY);
|
||||||
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 {
|
void saveLongLivedToken(token) {
|
||||||
longLivedToken = token;
|
longLivedToken = token;
|
||||||
tempToken = null;
|
tempToken = null;
|
||||||
try {
|
Hive.box(DEFAULT_HIVE_BOX).put(AUTH_TOKEN_KEY, longLivedToken);
|
||||||
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() {
|
||||||
|
@ -254,6 +254,7 @@ class ConnectionManager {
|
|||||||
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.");
|
||||||
AppSettings().saveLongLivedToken(data);
|
AppSettings().saveLongLivedToken(data);
|
||||||
|
completer.complete();
|
||||||
}).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")]));
|
||||||
});
|
});
|
||||||
|
@ -139,7 +139,7 @@ class MobileAppIntegrationManager {
|
|||||||
positiveText: "Report issue",
|
positiveText: "Report issue",
|
||||||
negativeText: "Close",
|
negativeText: "Close",
|
||||||
onPositive: () {
|
onPositive: () {
|
||||||
Launcher.launchURLInBrowser("https://github.com/estevez-dev/ha_client/issues/new");
|
Launcher.launchURLInBrowser("https://github.com/estevez-dev/ha_client/issues/new/choose");
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
@ -1,18 +1,37 @@
|
|||||||
part of '../main.dart';
|
part of '../main.dart';
|
||||||
|
|
||||||
class FullScreenPage extends StatelessWidget {
|
class FullScreenPage extends StatefulWidget {
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const FullScreenPage({Key key, this.child}) : super(key: key);
|
const FullScreenPage({Key key, this.child}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FullScreenPageState createState() => _FullScreenPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FullScreenPageState extends State<FullScreenPage> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays([]);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: this.child,
|
child: this.widget.child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -301,7 +301,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
title: Text("Report an issue"),
|
title: Text("Report an issue"),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Launcher.launchURLInBrowser("https://github.com/estevez-dev/ha_client/issues/new");
|
Launcher.launchURLInBrowser("https://github.com/estevez-dev/ha_client/issues/new/choose");
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Divider(),
|
Divider(),
|
||||||
@ -484,7 +484,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
floating: true,
|
floating: true,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
snap: false,
|
snap: false,
|
||||||
primary: true,
|
primary: AppSettings().displayMode == DisplayMode.normal,
|
||||||
title: Text(HomeAssistant().locationName ?? ""),
|
title: Text(HomeAssistant().locationName ?? ""),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
@ -493,6 +493,15 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
child: Icon(MaterialDesignIcons.getIconDataFromIconName(
|
child: Icon(MaterialDesignIcons.getIconDataFromIconName(
|
||||||
"mdi:dots-vertical"), color: Theme.of(context).primaryIconTheme.color)
|
"mdi:dots-vertical"), color: Theme.of(context).primaryIconTheme.color)
|
||||||
),
|
),
|
||||||
|
onSelected: (String val) {
|
||||||
|
if (val == "reload") {
|
||||||
|
_quickLoad();
|
||||||
|
} else if (val == "logout") {
|
||||||
|
HomeAssistant().logout().then((_) {
|
||||||
|
_quickLoad();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
itemBuilder: (BuildContext context) {
|
itemBuilder: (BuildContext context) {
|
||||||
List<PopupMenuEntry<String>> result = [
|
List<PopupMenuEntry<String>> result = [
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
@ -654,6 +663,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver, Ticker
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
Hive.close();
|
||||||
//final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
//final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
||||||
//flutterWebviewPlugin.dispose();
|
//flutterWebviewPlugin.dispose();
|
||||||
_viewsTabController?.dispose();
|
_viewsTabController?.dispose();
|
||||||
|
@ -31,7 +31,7 @@ class _PurchasePageState extends State<PurchasePage> {
|
|||||||
} else {
|
} else {
|
||||||
const Set<String> _kIds = {'one_time_support','just_few_bucks_per_year', 'app_fan_support_per_year', 'grateful_user_support_per_year'};
|
const Set<String> _kIds = {'one_time_support','just_few_bucks_per_year', 'app_fan_support_per_year', 'grateful_user_support_per_year'};
|
||||||
final ProductDetailsResponse response = await InAppPurchaseConnection.instance.queryProductDetails(_kIds);
|
final ProductDetailsResponse response = await InAppPurchaseConnection.instance.queryProductDetails(_kIds);
|
||||||
if (!response.notFoundIDs.isEmpty) {
|
if (response.notFoundIDs.isNotEmpty) {
|
||||||
Logger.d("Products not found: ${response.notFoundIDs}");
|
Logger.d("Products not found: ${response.notFoundIDs}");
|
||||||
}
|
}
|
||||||
_products = response.productDetails;
|
_products = response.productDetails;
|
||||||
@ -90,22 +90,6 @@ class _PurchasePageState extends State<PurchasePage> {
|
|||||||
} else {
|
} else {
|
||||||
body = _buildProducts();
|
body = _buildProducts();
|
||||||
}
|
}
|
||||||
body.add(
|
|
||||||
Card(
|
|
||||||
child: Container(
|
|
||||||
height: 80,
|
|
||||||
child: InkWell(
|
|
||||||
child: Image.network('https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif'),
|
|
||||||
onTap: () {
|
|
||||||
Launcher.launchURLInCustomTab(
|
|
||||||
context: context,
|
|
||||||
url: 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ARWGETZD2D83Q&source=url'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
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: (){
|
||||||
|
@ -23,7 +23,7 @@ class _AppSettingsPageState extends State<AppSettingsPage> {
|
|||||||
|
|
||||||
Widget _buildMenuItem(BuildContext context, IconData icon,String title, AppSettingsSection section) {
|
Widget _buildMenuItem(BuildContext context, IconData icon,String title, AppSettingsSection section) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(title, style: Theme.of(context).textTheme.subhead),
|
title: Text(title),
|
||||||
leading: Icon(icon),
|
leading: Icon(icon),
|
||||||
trailing: Icon(Icons.keyboard_arrow_right),
|
trailing: Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
@ -13,6 +13,7 @@ class _LookAndFeelSettingsPageState extends State<LookAndFeelSettingsPage> {
|
|||||||
|
|
||||||
AppTheme _currentTheme;
|
AppTheme _currentTheme;
|
||||||
bool _scrollBadges = false;
|
bool _scrollBadges = false;
|
||||||
|
DisplayMode _displayMode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -25,7 +26,8 @@ class _LookAndFeelSettingsPageState extends State<LookAndFeelSettingsPage> {
|
|||||||
await prefs.reload();
|
await prefs.reload();
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_currentTheme = AppTheme.values[prefs.getInt("app-theme") ?? AppTheme.defaultTheme.index];
|
_currentTheme = AppTheme.values[prefs.getInt('app-theme') ?? AppTheme.defaultTheme.index];
|
||||||
|
_displayMode = DisplayMode.values[prefs.getInt('display-mode') ?? DisplayMode.normal.index];
|
||||||
_scrollBadges = prefs.getBool('scroll-badges') ?? true;
|
_scrollBadges = prefs.getBool('scroll-badges') ?? true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -42,18 +44,34 @@ class _LookAndFeelSettingsPageState extends State<LookAndFeelSettingsPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _saveOther() async {
|
Future _saveBadgesSettings() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
AppSettings().scrollBadges = _scrollBadges;
|
AppSettings().scrollBadges = _scrollBadges;
|
||||||
await prefs.setBool('scroll-badges', _scrollBadges);
|
await prefs.setBool('scroll-badges', _scrollBadges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future _saveDisplayMode(DisplayMode mode) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
AppSettings().displayMode = mode;
|
||||||
|
await prefs.setInt('display-mode', mode.index);
|
||||||
|
if (mode == DisplayMode.fullscreen) {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays([]);
|
||||||
|
} else {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map appThemeName = {
|
Map appThemeName = {
|
||||||
AppTheme.defaultTheme: 'Default',
|
AppTheme.defaultTheme: 'Default',
|
||||||
AppTheme.haTheme: 'Home Assistant theme',
|
AppTheme.haTheme: 'Home Assistant theme',
|
||||||
AppTheme.darkTheme: 'Dark theme'
|
AppTheme.darkTheme: 'Dark theme'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Map DisplayModeName = {
|
||||||
|
DisplayMode.normal: 'Normal',
|
||||||
|
DisplayMode.fullscreen: 'Fullscreen'
|
||||||
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
@ -93,7 +111,28 @@ class _LookAndFeelSettingsPageState extends State<LookAndFeelSettingsPage> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_scrollBadges = val;
|
_scrollBadges = val;
|
||||||
});
|
});
|
||||||
_saveOther();
|
_saveBadgesSettings();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Container(height: Sizes.doubleRowPadding),
|
||||||
|
Text("Display mode:", style: Theme.of(context).textTheme.body2),
|
||||||
|
Container(height: Sizes.rowPadding),
|
||||||
|
DropdownButton<DisplayMode>(
|
||||||
|
value: _displayMode,
|
||||||
|
iconSize: 30.0,
|
||||||
|
isExpanded: true,
|
||||||
|
style: Theme.of(context).textTheme.title,
|
||||||
|
items: DisplayMode.values.map((value) {
|
||||||
|
return new DropdownMenuItem<DisplayMode>(
|
||||||
|
value: value,
|
||||||
|
child: Text('${DisplayModeName[value]}'),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (DisplayMode val) {
|
||||||
|
setState(() {
|
||||||
|
_displayMode = val;
|
||||||
|
});
|
||||||
|
_saveDisplayMode(val);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -73,11 +73,9 @@ class TokenLoginPopup extends Popup {
|
|||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
onSaved: (newValue) {
|
onSaved: (newValue) {
|
||||||
final storage = new FlutterSecureStorage();
|
Hive.box(AppSettings.DEFAULT_HIVE_BOX).put(AppSettings.AUTH_TOKEN_KEY, newValue.trim());
|
||||||
storage.write(key: "hacl_llt", value: newValue.trim()).then((_) {
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
eventBus.fire(SettingsChangedEvent(true));
|
||||||
eventBus.fire(SettingsChangedEvent(true));
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'Please enter long-lived token',
|
hintText: 'Please enter long-lived token',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: hass_client
|
name: hass_client
|
||||||
description: Home Assistant Android Client
|
description: Home Assistant Android Client
|
||||||
|
|
||||||
version: 0.0.0+1151
|
version: 1.1.0+1156
|
||||||
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
@ -23,7 +23,8 @@ dependencies:
|
|||||||
flutter_custom_tabs: ^0.6.0
|
flutter_custom_tabs: ^0.6.0
|
||||||
flutter_webview_plugin: ^0.3.10+1
|
flutter_webview_plugin: ^0.3.10+1
|
||||||
webview_flutter: ^0.3.19+7
|
webview_flutter: ^0.3.19+7
|
||||||
flutter_secure_storage: ^3.3.3
|
hive: ^1.4.1+1
|
||||||
|
hive_flutter: ^0.3.0+2
|
||||||
device_info: ^0.4.1+4
|
device_info: ^0.4.1+4
|
||||||
geolocator: ^5.3.1
|
geolocator: ^5.3.1
|
||||||
workmanager: ^0.2.2
|
workmanager: ^0.2.2
|
||||||
|
Reference in New Issue
Block a user