Compare commits
13 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 |
@ -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" />
|
||||||
|
@ -46,7 +46,7 @@ public class MainActivity extends FlutterActivity {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -185,8 +185,13 @@ void main() async {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
await AppSettings().loadAppTheme();
|
await AppSettings().loadStartupSettings();
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
|
if (AppSettings().displayMode == DisplayMode.fullscreen) {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays([]);
|
||||||
|
} else {
|
||||||
|
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
|
||||||
|
}
|
||||||
|
|
||||||
runZoned(() {
|
runZoned(() {
|
||||||
runApp(new HAClientApp(
|
runApp(new HAClientApp(
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
part of '../main.dart';
|
part of '../main.dart';
|
||||||
|
|
||||||
|
enum DisplayMode {normal, fullscreen}
|
||||||
|
|
||||||
class AppSettings {
|
class AppSettings {
|
||||||
|
|
||||||
static const DEFAULT_HIVE_BOX = 'defaultSettingsBox';
|
static const DEFAULT_HIVE_BOX = 'defaultSettingsBox';
|
||||||
@ -26,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;
|
||||||
@ -34,9 +37,10 @@ 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 {
|
||||||
@ -104,7 +108,7 @@ class AppSettings {
|
|||||||
Hive.box(DEFAULT_HIVE_BOX).delete(AUTH_TOKEN_KEY);
|
Hive.box(DEFAULT_HIVE_BOX).delete(AUTH_TOKEN_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future saveLongLivedToken(token) async {
|
void saveLongLivedToken(token) {
|
||||||
longLivedToken = token;
|
longLivedToken = token;
|
||||||
tempToken = null;
|
tempToken = null;
|
||||||
Hive.box(DEFAULT_HIVE_BOX).put(AUTH_TOKEN_KEY, longLivedToken);
|
Hive.box(DEFAULT_HIVE_BOX).put(AUTH_TOKEN_KEY, longLivedToken);
|
||||||
|
@ -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>(
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: hass_client
|
name: hass_client
|
||||||
description: Home Assistant Android Client
|
description: Home Assistant Android Client
|
||||||
|
|
||||||
version: 1.1.0+1153
|
version: 1.1.0+1156
|
||||||
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
Reference in New Issue
Block a user