Revert all rash decisions
This commit is contained in:
@ -1,486 +0,0 @@
|
||||
part of '../main.dart';
|
||||
|
||||
class MainPage extends StatefulWidget {
|
||||
MainPage({Key key, this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_MainPageState createState() => new _MainPageState();
|
||||
}
|
||||
|
||||
class _MainPageState extends State<MainPage> with WidgetsBindingObserver, TickerProviderStateMixin {
|
||||
|
||||
StreamSubscription<List<PurchaseDetails>> _subscription;
|
||||
StreamSubscription _stateSubscription;
|
||||
StreamSubscription _settingsSubscription;
|
||||
StreamSubscription _serviceCallSubscription;
|
||||
StreamSubscription _showEntityPageSubscription;
|
||||
StreamSubscription _showErrorSubscription;
|
||||
StreamSubscription _startAuthSubscription;
|
||||
StreamSubscription _showPopupDialogSubscription;
|
||||
StreamSubscription _showPopupMessageSubscription;
|
||||
StreamSubscription _reloadUISubscription;
|
||||
StreamSubscription _showPageSubscription;
|
||||
int _previousViewCount;
|
||||
//bool _showLoginButton = false;
|
||||
bool _preventAppRefresh = false;
|
||||
UserError _userError;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
final Stream purchaseUpdates =
|
||||
InAppPurchaseConnection.instance.purchaseUpdatedStream;
|
||||
_subscription = purchaseUpdates.listen((purchases) {
|
||||
_handlePurchaseUpdates(purchases);
|
||||
});
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
|
||||
_firebaseMessaging.configure(
|
||||
onLaunch: (data) {
|
||||
Logger.d("Notification [onLaunch]: $data");
|
||||
return Future.value();
|
||||
},
|
||||
onMessage: (data) {
|
||||
Logger.d("Notification [onMessage]: $data");
|
||||
return _showNotification(title: data["notification"]["title"], text: data["notification"]["body"]);
|
||||
},
|
||||
onResume: (data) {
|
||||
Logger.d("Notification [onResume]: $data");
|
||||
return Future.value();
|
||||
}
|
||||
);
|
||||
|
||||
_firebaseMessaging.requestNotificationPermissions(const IosNotificationSettings(sound: true, badge: true, alert: true));
|
||||
|
||||
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
|
||||
var initializationSettingsAndroid =
|
||||
new AndroidInitializationSettings('mini_icon');
|
||||
var initializationSettingsIOS = new IOSInitializationSettings(
|
||||
onDidReceiveLocalNotification: null);
|
||||
var initializationSettings = new InitializationSettings(
|
||||
initializationSettingsAndroid, initializationSettingsIOS);
|
||||
flutterLocalNotificationsPlugin.initialize(initializationSettings,
|
||||
onSelectNotification: onSelectNotification);
|
||||
|
||||
_settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) {
|
||||
Logger.d("Settings change event: reconnect=${event.reconnect}");
|
||||
if (event.reconnect) {
|
||||
_preventAppRefresh = false;
|
||||
_fullLoad();
|
||||
}
|
||||
});
|
||||
|
||||
_fullLoad();
|
||||
|
||||
|
||||
}
|
||||
|
||||
Future onSelectNotification(String payload) async {
|
||||
if (payload != null) {
|
||||
Logger.d('Notification clicked: ' + payload);
|
||||
}
|
||||
}
|
||||
|
||||
Future _showNotification({String title, String text}) async {
|
||||
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
|
||||
'ha_notify', 'Home Assistant notifications', 'Notifications from Home Assistant notify service',
|
||||
importance: Importance.Max, priority: Priority.High);
|
||||
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
|
||||
var platformChannelSpecifics = new NotificationDetails(
|
||||
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
|
||||
await flutterLocalNotificationsPlugin.show(
|
||||
0,
|
||||
title ?? appName,
|
||||
text,
|
||||
platformChannelSpecifics
|
||||
);
|
||||
}
|
||||
|
||||
void _fullLoad() async {
|
||||
//TODO show loading somewhere somehow
|
||||
//_showInfoBottomBar(progress: true,);
|
||||
_subscribe().then((_) {
|
||||
ConnectionManager().init(loadSettings: true, forceReconnect: true).then((__){
|
||||
_fetchData();
|
||||
}, onError: (error) {
|
||||
_setErrorState(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _quickLoad() {
|
||||
//_hideBottomBar();
|
||||
//TODO show loading somewhere somehow
|
||||
//_showInfoBottomBar(progress: true,);
|
||||
ConnectionManager().init(loadSettings: false, forceReconnect: false).then((_){
|
||||
_fetchData();
|
||||
}, onError: (error) {
|
||||
_setErrorState(error);
|
||||
});
|
||||
}
|
||||
|
||||
_fetchData() async {
|
||||
setState(() {
|
||||
_userError = null;
|
||||
});
|
||||
await HomeAssistant().fetchData().then((_) {
|
||||
int currentViewCount = HomeAssistant().ui?.views?.length ?? 0;
|
||||
if (_previousViewCount != currentViewCount) {
|
||||
Logger.d("Views count changed ($_previousViewCount->$currentViewCount). Creating new tabs controller.");
|
||||
_viewsTabController = TabController(vsync: this, length: currentViewCount);
|
||||
_previousViewCount = currentViewCount;
|
||||
}
|
||||
}).catchError((code) {
|
||||
_setErrorState(code);
|
||||
});
|
||||
eventBus.fire(RefreshDataFinishedEvent());
|
||||
StartupUserMessagesManager().checkMessagesToShow();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
Logger.d("$state");
|
||||
if (state == AppLifecycleState.resumed && ConnectionManager().settingsLoaded && !_preventAppRefresh) {
|
||||
_quickLoad();
|
||||
}
|
||||
}
|
||||
|
||||
void _handlePurchaseUpdates(purchase) {
|
||||
if (purchase is List<PurchaseDetails>) {
|
||||
if (purchase[0].status == PurchaseStatus.purchased) {
|
||||
eventBus.fire(ShowPopupMessageEvent(
|
||||
title: "Thanks a lot!",
|
||||
body: "Thank you for supporting HA Client development!",
|
||||
buttonText: "Ok"
|
||||
));
|
||||
} else {
|
||||
Logger.d("Purchase change handler: ${purchase[0].status}");
|
||||
}
|
||||
} else {
|
||||
Logger.e("Something wrong with purchase handling. Got: $purchase");
|
||||
}
|
||||
}
|
||||
|
||||
Future _subscribe() {
|
||||
Completer completer = Completer();
|
||||
if (_stateSubscription == null) {
|
||||
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
|
||||
if (event.needToRebuildUI) {
|
||||
Logger.d("New entity. Need to rebuild UI");
|
||||
_quickLoad();
|
||||
} else {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (_reloadUISubscription == null) {
|
||||
_reloadUISubscription = eventBus.on<ReloadUIEvent>().listen((event){
|
||||
if (event.full)
|
||||
_fullLoad();
|
||||
else
|
||||
_quickLoad();
|
||||
});
|
||||
}
|
||||
if (_showPopupDialogSubscription == null) {
|
||||
_showPopupDialogSubscription = eventBus.on<ShowPopupDialogEvent>().listen((event){
|
||||
_showPopupDialog(
|
||||
title: event.title,
|
||||
body: event.body,
|
||||
onPositive: event.onPositive,
|
||||
onNegative: event.onNegative,
|
||||
positiveText: event.positiveText,
|
||||
negativeText: event.negativeText
|
||||
);
|
||||
});
|
||||
}
|
||||
if (_showPopupMessageSubscription == null) {
|
||||
_showPopupMessageSubscription = eventBus.on<ShowPopupMessageEvent>().listen((event){
|
||||
_showPopupDialog(
|
||||
title: event.title,
|
||||
body: event.body,
|
||||
onPositive: event.onButtonClick,
|
||||
positiveText: event.buttonText,
|
||||
negativeText: null
|
||||
);
|
||||
});
|
||||
}
|
||||
if (_serviceCallSubscription == null) {
|
||||
_serviceCallSubscription =
|
||||
eventBus.on<ServiceCallEvent>().listen((event) {
|
||||
_callService(event.domain, event.service, event.entityId,
|
||||
event.additionalParams);
|
||||
});
|
||||
}
|
||||
|
||||
if (_showEntityPageSubscription == null) {
|
||||
_showEntityPageSubscription =
|
||||
eventBus.on<ShowEntityPageEvent>().listen((event) {
|
||||
_showEntityPage(event.entity.entityId);
|
||||
});
|
||||
}
|
||||
|
||||
if (_showPageSubscription == null) {
|
||||
_showPageSubscription =
|
||||
eventBus.on<ShowPageEvent>().listen((event) {
|
||||
_showPage(event.path, event.goBackFirst);
|
||||
});
|
||||
}
|
||||
|
||||
if (_showErrorSubscription == null) {
|
||||
_showErrorSubscription = eventBus.on<ShowErrorEvent>().listen((event){
|
||||
_setErrorState(event.error);
|
||||
});
|
||||
}
|
||||
|
||||
if (_startAuthSubscription == null) {
|
||||
_startAuthSubscription = eventBus.on<StartAuthEvent>().listen((event){
|
||||
if (event.starting) {
|
||||
_showOAuth();
|
||||
} else {
|
||||
_preventAppRefresh = false;
|
||||
Navigator.of(context).pop();
|
||||
setState(() {
|
||||
_userError = null;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_firebaseMessaging.getToken().then((String token) {
|
||||
HomeAssistant().fcmToken = token;
|
||||
completer.complete();
|
||||
});
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
void _showOAuth() {
|
||||
_preventAppRefresh = true;
|
||||
_setErrorState(UserError(code: ErrorCode.NOT_LOGGED_IN));
|
||||
Navigator.of(context).pushNamed('/login');
|
||||
}
|
||||
|
||||
_setErrorState(error) {
|
||||
if (error is UserError) {
|
||||
setState(() {
|
||||
//_showBottomBar = false;
|
||||
_userError = error;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
//_showBottomBar = false;
|
||||
_userError = UserError(code: ErrorCode.UNKNOWN);
|
||||
});
|
||||
}
|
||||
/*if (e == null) {
|
||||
_showErrorBottomBar(
|
||||
HAError("Unknown error")
|
||||
);
|
||||
} else {
|
||||
_showErrorBottomBar(e);
|
||||
}*/
|
||||
}
|
||||
|
||||
void _showPopupDialog({String title, String body, var onPositive, var onNegative, String positiveText, String negativeText}) {
|
||||
List<Widget> buttons = [];
|
||||
buttons.add(FlatButton(
|
||||
child: new Text("$positiveText"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
if (onPositive != null) {
|
||||
onPositive();
|
||||
}
|
||||
},
|
||||
));
|
||||
if (negativeText != null) {
|
||||
buttons.add(FlatButton(
|
||||
child: new Text("$negativeText"),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
if (onNegative != null) {
|
||||
onNegative();
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
// flutter defined function
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
// return object of type Dialog
|
||||
return AlertDialog(
|
||||
title: new Text("$title"),
|
||||
content: new Text("$body"),
|
||||
actions: buttons,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _callService(String domain, String service, String entityId, Map additionalParams) {
|
||||
//TODO show SnackBar
|
||||
/*_showInfoBottomBar(
|
||||
message: "Calling $domain.$service",
|
||||
duration: Duration(seconds: 3)
|
||||
);*/
|
||||
ConnectionManager().callService(domain: domain, service: service, entityId: entityId, additionalServiceData: additionalParams).catchError((e) => _setErrorState(e));
|
||||
}
|
||||
|
||||
void _showEntityPage(String entityId) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => EntityViewPage(entityId: entityId),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void _showPage(String path, bool goBackFirst) {
|
||||
if (goBackFirst) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
/*void _hideBottomBar() {
|
||||
//_scaffoldKey?.currentState?.hideCurrentSnackBar();
|
||||
setState(() {
|
||||
_showBottomBar = false;
|
||||
});
|
||||
}*/
|
||||
|
||||
/*Widget _bottomBarAction;
|
||||
bool _showBottomBar = false;
|
||||
String _bottomBarText;
|
||||
bool _bottomBarProgress;
|
||||
Color _bottomBarColor;
|
||||
Timer _bottomBarTimer;*/
|
||||
|
||||
/*void _showInfoBottomBar({String message, bool progress: false, Duration duration}) {
|
||||
_bottomBarTimer?.cancel();
|
||||
_bottomBarAction = Container(height: 0.0, width: 0.0,);
|
||||
_bottomBarColor = Colors.grey.shade50;
|
||||
setState(() {
|
||||
_bottomBarText = message;
|
||||
_bottomBarProgress = progress;
|
||||
_showBottomBar = true;
|
||||
});
|
||||
if (duration != null) {
|
||||
_bottomBarTimer = Timer(duration, () {
|
||||
_hideBottomBar();
|
||||
});
|
||||
}
|
||||
}*/
|
||||
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
TabController _viewsTabController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget bottomBar;
|
||||
if (_userError != null) {
|
||||
bottomBar = UserErrorPanel(error: _userError,);
|
||||
/*List<Widget> bottomBarChildren = [];
|
||||
if (_bottomBarText != null) {
|
||||
bottomBarChildren.add(
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
Sizes.leftWidgetPadding, Sizes.rowPadding, 0.0,
|
||||
Sizes.rowPadding),
|
||||
child: Text(
|
||||
"$_bottomBarText",
|
||||
textAlign: TextAlign.left,
|
||||
softWrap: true,
|
||||
),
|
||||
)
|
||||
|
||||
);
|
||||
}*/
|
||||
/*if (_bottomBarProgress) {
|
||||
bottomBarChildren.add(
|
||||
CollectionScaleTransition(
|
||||
children: <Widget>[
|
||||
Icon(Icons.stop, size: 10.0, color: EntityColor.stateColor(EntityState.on),),
|
||||
Icon(Icons.stop, size: 10.0, color: EntityColor.stateColor(EntityState.unavailable),),
|
||||
Icon(Icons.stop, size: 10.0, color: EntityColor.stateColor(EntityState.off),),
|
||||
],
|
||||
),
|
||||
);
|
||||
}*/
|
||||
/*if (bottomBarChildren.isNotEmpty) {
|
||||
bottomBar = Container(
|
||||
color: _bottomBarColor,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: _bottomBarProgress ? CrossAxisAlignment.center : CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: bottomBarChildren,
|
||||
),
|
||||
),
|
||||
_bottomBarAction
|
||||
],
|
||||
),
|
||||
);
|
||||
}*/
|
||||
}
|
||||
// This method is rerun every time setState is called.
|
||||
if (HomeAssistant().isNoViews) {
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
primary: false,
|
||||
drawer: AppDrawer(),
|
||||
bottomNavigationBar: bottomBar,
|
||||
body: MainPageBody(
|
||||
empty: true,
|
||||
onReload: () => _quickLoad(),
|
||||
tabController: _viewsTabController,
|
||||
onMenu: () => _scaffoldKey.currentState.openDrawer(),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
drawer: AppDrawer(),
|
||||
primary: false,
|
||||
bottomNavigationBar: bottomBar,
|
||||
body: MainPageBody(
|
||||
empty: false,
|
||||
onReload: () => _quickLoad(),
|
||||
tabController: _viewsTabController,
|
||||
onMenu: () => _scaffoldKey.currentState.openDrawer(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
||||
flutterWebviewPlugin.dispose();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
_viewsTabController?.dispose();
|
||||
_stateSubscription?.cancel();
|
||||
_settingsSubscription?.cancel();
|
||||
_serviceCallSubscription?.cancel();
|
||||
_showPopupDialogSubscription?.cancel();
|
||||
_showPopupMessageSubscription?.cancel();
|
||||
_showEntityPageSubscription?.cancel();
|
||||
_showErrorSubscription?.cancel();
|
||||
_startAuthSubscription?.cancel();
|
||||
_subscription?.cancel();
|
||||
_showPageSubscription?.cancel();
|
||||
_reloadUISubscription?.cancel();
|
||||
//TODO disconnect
|
||||
//widget.homeAssistant?.disconnect();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
part of '../../main.dart';
|
||||
|
||||
class AppDrawer extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> menuItems = [];
|
||||
menuItems.add(
|
||||
UserAccountsDrawerHeader(
|
||||
accountName: Text(HomeAssistant().userName),
|
||||
accountEmail: Text(ConnectionManager().displayHostname ?? "Not configured"),
|
||||
onDetailsPressed: () {
|
||||
final flutterWebViewPlugin = new FlutterWebviewPlugin();
|
||||
flutterWebViewPlugin.onStateChanged.listen((viewState) async {
|
||||
if (viewState.type == WebViewState.startLoad) {
|
||||
Logger.d("[WebView] Injecting external auth JS");
|
||||
rootBundle.loadString('assets/js/externalAuth.js').then((js){
|
||||
flutterWebViewPlugin.evalJavascript(js.replaceFirst("[token]", ConnectionManager()._token));
|
||||
});
|
||||
}
|
||||
});
|
||||
Navigator.of(context).pushNamed(
|
||||
"/webview",
|
||||
arguments: {
|
||||
"url": "${ConnectionManager().httpWebHost}/profile?external_auth=1",
|
||||
"title": "Profile"
|
||||
}
|
||||
);
|
||||
},
|
||||
currentAccountPicture: CircleAvatar(
|
||||
child: Text(
|
||||
HomeAssistant().userAvatarText,
|
||||
style: TextStyle(
|
||||
fontSize: 32.0
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
if (HomeAssistant().panels.isNotEmpty) {
|
||||
HomeAssistant().panels.forEach((Panel panel) {
|
||||
if (!panel.isHidden) {
|
||||
menuItems.add(
|
||||
new ListTile(
|
||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName(panel.icon)),
|
||||
title: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text("${panel.title}"),
|
||||
Container(width: 4.0,),
|
||||
panel.isWebView ? Text("webview", style: TextStyle(fontSize: 8.0, color: Colors.black45),) : Container(width: 1.0,)
|
||||
],
|
||||
),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
panel.handleOpen(context);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
menuItems.addAll([
|
||||
Divider(),
|
||||
ListTile(
|
||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:login-variant")),
|
||||
title: Text("Connection settings"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/connection-settings');
|
||||
},
|
||||
)
|
||||
]);
|
||||
menuItems.addAll([
|
||||
Divider(),
|
||||
new ListTile(
|
||||
leading: Icon(Icons.insert_drive_file),
|
||||
title: Text("Log"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/log-view');
|
||||
},
|
||||
),
|
||||
new ListTile(
|
||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:github-circle")),
|
||||
title: Text("Report an issue"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURL("https://github.com/estevez-dev/ha_client/issues/new");
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
new ListTile(
|
||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:food")),
|
||||
title: Text("Support app development"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed('/putchase');
|
||||
},
|
||||
),
|
||||
Divider(),
|
||||
new ListTile(
|
||||
leading: Icon(Icons.help),
|
||||
title: Text("Help"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURL("http://ha-client.homemade.systems/docs");
|
||||
},
|
||||
),
|
||||
new ListTile(
|
||||
leading: Icon(MaterialDesignIcons.getIconDataFromIconName("mdi:discord")),
|
||||
title: Text("Join Discord channel"),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURL("https://discord.gg/AUzEvwn");
|
||||
},
|
||||
),
|
||||
new AboutListTile(
|
||||
aboutBoxChildren: <Widget>[
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURL("http://ha-client.homemade.systems/");
|
||||
},
|
||||
child: Text(
|
||||
"ha-client.homemade.systems",
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 10.0,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURLInCustomTab(context: context, url: "http://ha-client.homemade.systems/terms_and_conditions");
|
||||
},
|
||||
child: Text(
|
||||
"Terms and Conditions",
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 10.0,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
Launcher.launchURLInCustomTab(context: context, url: "http://ha-client.homemade.systems/privacy_policy");
|
||||
},
|
||||
child: Text(
|
||||
"Privacy Policy",
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
applicationName: appName,
|
||||
applicationVersion: appVersion
|
||||
)
|
||||
]);
|
||||
return new Drawer(
|
||||
child: ListView(
|
||||
children: menuItems,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
part of '../../main.dart';
|
||||
|
||||
class MainPageBody extends StatelessWidget {
|
||||
|
||||
final bool empty;
|
||||
final onReload;
|
||||
final onMenu;
|
||||
final TabController tabController;
|
||||
|
||||
const MainPageBody({Key key, this.empty, this.onReload, this.tabController, this.onMenu}) : super(key: key);
|
||||
|
||||
List<Tab> buildUIViewTabs() {
|
||||
List<Tab> result = [];
|
||||
|
||||
if (HomeAssistant().ui.views.isNotEmpty) {
|
||||
HomeAssistant().ui.views.forEach((HAView view) {
|
||||
//TODO Create a widget for that and pass view to it. An opposit way as it is implemented now
|
||||
result.add(view.buildTab());
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<PopupMenuItem<String>> popupMenuItems = [];
|
||||
|
||||
popupMenuItems.add(PopupMenuItem<String>(
|
||||
child: new Text("Reload"),
|
||||
value: "reload",
|
||||
));
|
||||
/*List<Widget> emptyBody = [
|
||||
Text("."),
|
||||
];*/
|
||||
if (ConnectionManager().isAuthenticated) {
|
||||
//_showLoginButton = false;
|
||||
popupMenuItems.add(
|
||||
PopupMenuItem<String>(
|
||||
child: new Text("Logout"),
|
||||
value: "logout",
|
||||
));
|
||||
}
|
||||
Widget bodyWidget;
|
||||
if (empty) {
|
||||
bodyWidget = Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircularProgressIndicator()
|
||||
],
|
||||
);
|
||||
} else {
|
||||
bodyWidget = HomeAssistant().buildViews(context, tabController);
|
||||
}
|
||||
/*if (_showLoginButton) {
|
||||
emptyBody = [
|
||||
FlatButton(
|
||||
child: Text("Login with Home Assistant", style: TextStyle(fontSize: 16.0, color: Colors.white)),
|
||||
color: Colors.blue,
|
||||
onPressed: () => _fullLoad(),
|
||||
)
|
||||
];
|
||||
}*/
|
||||
return NestedScrollView(
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverAppBar(
|
||||
floating: true,
|
||||
pinned: true,
|
||||
primary: true,
|
||||
title: Text(HomeAssistant().locationName ?? ""),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(MaterialDesignIcons.getIconDataFromIconName(
|
||||
"mdi:dots-vertical"), color: Colors.white,),
|
||||
onPressed: () {
|
||||
showMenu(
|
||||
position: RelativeRect.fromLTRB(MediaQuery.of(context).size.width, 70.0, 0.0, 0.0),
|
||||
context: context,
|
||||
items: popupMenuItems
|
||||
).then((String val) {
|
||||
if (val == "reload") {
|
||||
onReload();
|
||||
} else if (val == "logout") {
|
||||
HomeAssistant().logout().then((_) {
|
||||
onReload();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
],
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.menu),
|
||||
onPressed: () => onMenu(),
|
||||
),
|
||||
bottom: empty ? null : TabBar(
|
||||
controller: tabController,
|
||||
tabs: buildUIViewTabs(),
|
||||
isScrollable: true,
|
||||
),
|
||||
),
|
||||
|
||||
];
|
||||
},
|
||||
body: bodyWidget,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
part of '../../main.dart';
|
||||
|
||||
class UserErrorActionButton extends StatelessWidget {
|
||||
|
||||
final onPressed;
|
||||
final String text;
|
||||
|
||||
const UserErrorActionButton({Key key, this.onPressed, this.text}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RaisedButton(
|
||||
onPressed: () => this.onPressed(),
|
||||
color: Colors.blue,
|
||||
child: Text(
|
||||
"${this.text}",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UserErrorPanel extends StatelessWidget {
|
||||
|
||||
final UserError error;
|
||||
|
||||
const UserErrorPanel({Key key, this.error}) : super(key: key);
|
||||
|
||||
void _goToAppSettings(BuildContext context) {
|
||||
Navigator.pushNamed(context, '/connection-settings');
|
||||
}
|
||||
|
||||
void _reload() {
|
||||
eventBus.fire(ReloadUIEvent(true));
|
||||
}
|
||||
|
||||
void _disableLovelace() {
|
||||
SharedPreferences.getInstance().then((prefs){
|
||||
prefs.setBool("use-lovelace", false);
|
||||
eventBus.fire(ReloadUIEvent(true));
|
||||
});
|
||||
}
|
||||
|
||||
void _reLogin() {
|
||||
ConnectionManager().logout().then((_) => eventBus.fire(ReloadUIEvent(true)));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String errorText;
|
||||
List<Widget> buttons = [];
|
||||
switch (this.error.code) {
|
||||
case ErrorCode.AUTH_ERROR: {
|
||||
errorText = "There was an error logging in to Home Assistant";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry",
|
||||
));
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _reLogin(),
|
||||
text: "Login again",
|
||||
));
|
||||
break;
|
||||
}
|
||||
case ErrorCode.UNABLE_TO_CONNECT: {
|
||||
errorText = "Unable to connect to Home Assistant";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _goToAppSettings(context),
|
||||
text: "Check application settings",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.AUTH_INVALID: {
|
||||
errorText = "${error.message ?? "Can't login to Home Assistant"}";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reLogin(),
|
||||
text: "Login again",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.GENERAL_AUTH_ERROR: {
|
||||
errorText = "There was some error logging in. ${this.error.message ?? ""}";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reLogin(),
|
||||
text: "Login again",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.SECURE_STORAGE_READ_ERROR: {
|
||||
errorText = "There was an error reading secure storage. You can try again or clear saved auth data and login again.";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reLogin(),
|
||||
text: "Clear and login again",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.DISCONNECTED: {
|
||||
errorText = "Disconnected";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Reconnect"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _goToAppSettings(context),
|
||||
text: "Check application settings",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.CONNECTION_TIMEOUT: {
|
||||
errorText = "Connection timeout";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Reconnect"
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _goToAppSettings(context),
|
||||
text: "Check application settings",
|
||||
)
|
||||
]
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.NOT_CONFIGURED: {
|
||||
errorText = "Looks like HA Client is not configured yet.";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _goToAppSettings(context),
|
||||
text: "Open application settings",
|
||||
));
|
||||
break;
|
||||
}
|
||||
case ErrorCode.ERROR_GETTING_PANELS:
|
||||
case ErrorCode.ERROR_GETTING_CONFIG:
|
||||
case ErrorCode.ERROR_GETTING_STATES: {
|
||||
errorText = "Couldn't get data from Home Assistant. ${error.message ?? ""}";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Try again",
|
||||
));
|
||||
break;
|
||||
}
|
||||
case ErrorCode.ERROR_GETTING_LOVELACE_CONFIG: {
|
||||
errorText = "Couldn't get Lovelace UI config. You can try to disable it and use group-based UI istead.";
|
||||
buttons.addAll(<Widget>[
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Retry",
|
||||
),
|
||||
UserErrorActionButton(
|
||||
onPressed: () => _disableLovelace(),
|
||||
text: "Disable Lovelace UI",
|
||||
)
|
||||
]);
|
||||
break;
|
||||
}
|
||||
case ErrorCode.NOT_LOGGED_IN: {
|
||||
errorText = "You are not logged in yet. Please login.";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Login",
|
||||
));
|
||||
break;
|
||||
}
|
||||
case ErrorCode.NO_MOBILE_APP_COMPONENT: {
|
||||
errorText = "Looks like mobile_app component is not enabled on your Home Assistant instance. Please add it to your configuration.yaml";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => Launcher.launchURLInCustomTab(context: context, url: "https://www.home-assistant.io/components/mobile_app/"),
|
||||
text: "Help",
|
||||
));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
errorText = "There was an error. Code ${this.error.code}";
|
||||
buttons.add(UserErrorActionButton(
|
||||
onPressed: () => _reload(),
|
||||
text: "Reload",
|
||||
));
|
||||
}
|
||||
}
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Divider(
|
||||
color: Colors.deepOrange,
|
||||
height: 1.0,
|
||||
indent: 8.0,
|
||||
endIndent: 8.0,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(8.0, 14.0, 8.0, 0.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
errorText,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(color: Colors.black87, fontSize: 18.0),
|
||||
softWrap: true,
|
||||
maxLines: 3,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
ButtonBar(
|
||||
children: buttons,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user