Compare commits
	
		
			19 Commits
		
	
	
		
			1.1.0-beta
			...
			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 | 
| @@ -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")) { | ||||||
|  |                         if (checkPlayServices()) { | ||||||
|                             FirebaseInstanceId.getInstance().getInstanceId() |                             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 { |  | ||||||
|         final storage = new FlutterSecureStorage(); |  | ||||||
|         longLivedToken = await storage.read(key: "hacl_llt"); |  | ||||||
|         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 | ||||||
|           .encodeComponent( |           .encodeComponent( | ||||||
|           'https://ha-client.app/service/auth_callback.html')}"; |           '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