From 2a828a128955d296f77d18ba9f471c151edd4ef3 Mon Sep 17 00:00:00 2001 From: Yegor Vialov Date: Wed, 15 Apr 2020 15:39:53 +0000 Subject: [PATCH] WIP: bottom info bar as separate component --- lib/main.dart | 1 + lib/pages/main/main.page.dart | 189 +++------------------ lib/pages/widgets/bottom_info_bar.dart | 218 +++++++++++++++++++++++++ lib/types/event_bus_events.dart | 6 + 4 files changed, 249 insertions(+), 165 deletions(-) create mode 100644 lib/pages/widgets/bottom_info_bar.dart diff --git a/lib/main.dart b/lib/main.dart index a1f539d..1b6623d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -106,6 +106,7 @@ part 'pages/settings/connection_settings.part.dart'; part 'pages/purchase.page.dart'; part 'pages/widgets/product_purchase.widget.dart'; part 'pages/widgets/page_loading_indicator.dart'; +part 'pages/widgets/bottom_info_bar.dart'; part 'pages/widgets/page_loading_error.dart'; part 'pages/panel.page.dart'; part 'pages/main/main.page.dart'; diff --git a/lib/pages/main/main.page.dart b/lib/pages/main/main.page.dart index ff55e4f..3e800f5 100644 --- a/lib/pages/main/main.page.dart +++ b/lib/pages/main/main.page.dart @@ -21,7 +21,9 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker StreamSubscription _showPopupDialogSubscription; StreamSubscription _showPopupMessageSubscription; StreamSubscription _reloadUISubscription; + StreamSubscription _fullReloadSubscription; StreamSubscription _showPageSubscription; + BottomInfoBarController _bottomInfoBarController; int _previousViewCount; bool _showLoginButton = false; bool _preventAppRefresh = false; @@ -46,6 +48,8 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } ); + _bottomInfoBarController = BottomInfoBarController(); + _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 @@ -91,7 +95,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } void _fullLoad() { - _showInfoBottomBar(progress: true,); + _bottomInfoBarController.showInfoBottomBar(progress: true,); _subscribe().then((_) { ConnectionManager().init(loadSettings: true, forceReconnect: true).then((__){ SharedPreferences.getInstance().then((prefs) { @@ -107,8 +111,8 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } void _quickLoad({bool uiOnly: false}) { - _hideBottomBar(); - _showInfoBottomBar(progress: true,); + _bottomInfoBarController.hideBottomBar(); + _bottomInfoBarController.showInfoBottomBar(progress: true,); ConnectionManager().init(loadSettings: false, forceReconnect: false).then((_){ _fetchData(useCache: false, uiOnly: uiOnly); }, onError: (e) { @@ -123,7 +127,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker }); } await HomeAssistant().fetchData(uiOnly).then((_) { - _hideBottomBar(); + _bottomInfoBarController.hideBottomBar(); }).catchError((e) { if (e is HAError) { _setErrorState(e); @@ -167,6 +171,11 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker _quickLoad(uiOnly: true); }); } + if (_fullReloadSubscription == null) { + _fullReloadSubscription = eventBus.on().listen((event){ + _fullLoad(); + }); + } if (_showPopupDialogSubscription == null) { _showPopupDialogSubscription = eventBus.on().listen((event){ _showPopupDialog( @@ -213,7 +222,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker if (_showErrorSubscription == null) { _showErrorSubscription = eventBus.on().listen((event){ - _showErrorBottomBar(event.error); + _bottomInfoBarController.showErrorBottomBar(event.error); }); } @@ -245,11 +254,11 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker _setErrorState(HAError e) { if (e == null) { - _showErrorBottomBar( + _bottomInfoBarController.showErrorBottomBar( HAError("Unknown error") ); } else { - _showErrorBottomBar(e); + _bottomInfoBarController.showErrorBottomBar(e); } } @@ -291,7 +300,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker } void _notifyServiceCalled(String domain, String service, entityId) { - _showInfoBottomBar( + _bottomInfoBarController.showInfoBottomBar( message: "Calling $domain.$service", duration: Duration(seconds: 4) ); @@ -481,111 +490,6 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker ); } - void _hideBottomBar() { - //_scaffoldKey?.currentState?.hideCurrentSnackBar(); - setState(() { - _showBottomBar = false; - }); - } - - Widget _bottomBarAction; - bool _showBottomBar = false; - String _bottomBarText; - bool _bottomBarProgress; - bool _bottomBarErrorColor; - Timer _bottomBarTimer; - - void _showInfoBottomBar({String message, bool progress: false, Duration duration}) { - _bottomBarTimer?.cancel(); - _bottomBarAction = Container(height: 0.0, width: 0.0,); - _bottomBarErrorColor = false; - setState(() { - _bottomBarText = message; - _bottomBarProgress = progress; - _showBottomBar = true; - }); - if (duration != null) { - _bottomBarTimer = Timer(duration, () { - _hideBottomBar(); - }); - } - } - - void _showErrorBottomBar(HAError error) { - TextStyle textStyle = Theme.of(context).textTheme.button.copyWith( - decoration: TextDecoration.underline - ); - _bottomBarErrorColor = true; - List actions = []; - error.actions.forEach((HAErrorAction action) { - switch (action.type) { - case HAErrorActionType.FULL_RELOAD: { - actions.add(FlatButton( - child: Text("${action.title}", style: textStyle), - onPressed: () { - _fullLoad(); - }, - )); - break; - } - - case HAErrorActionType.QUICK_RELOAD: { - actions.add(FlatButton( - child: Text("${action.title}", style: textStyle), - onPressed: () { - _quickLoad(); - }, - )); - break; - } - - case HAErrorActionType.RELOGIN: { - actions.add(FlatButton( - child: Text("${action.title}", style: textStyle), - onPressed: () { - ConnectionManager().logout().then((_) => _fullLoad()); - }, - )); - break; - } - - case HAErrorActionType.URL: { - actions.add(FlatButton( - child: Text("${action.title}", style: textStyle), - onPressed: () { - Launcher.launchURLInCustomTab(context: context, url: "${action.url}"); - }, - )); - break; - } - - case HAErrorActionType.OPEN_CONNECTION_SETTINGS: { - actions.add(FlatButton( - child: Text("${action.title}", style: textStyle), - onPressed: () { - Navigator.pushNamed(context, '/connection-settings'); - }, - )); - break; - } - } - }); - if (actions.isNotEmpty) { - _bottomBarAction = Row( - mainAxisSize: MainAxisSize.min, - children: actions, - mainAxisAlignment: MainAxisAlignment.end, - ); - } else { - _bottomBarAction = Container(height: 0.0, width: 0.0,); - } - setState(() { - _bottomBarProgress = false; - _bottomBarText = "${error.message}"; - _showBottomBar = true; - }); - } - final GlobalKey _scaffoldKey = new GlobalKey(); Widget _buildScaffoldBody(bool empty) { @@ -765,60 +669,14 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker @override Widget build(BuildContext context) { - Widget bottomBar; - if (_showBottomBar) { - List 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: [ - Icon(Icons.stop, size: 10.0, color: HAClientTheme().getOnStateColor(context),), - Icon(Icons.stop, size: 10.0, color: HAClientTheme().getDisabledStateColor(context),), - Icon(Icons.stop, size: 10.0, color: HAClientTheme().getOffStateColor(context),), - ], - ), - ); - } - if (bottomBarChildren.isNotEmpty) { - bottomBar = Container( - color: _bottomBarErrorColor ? Theme.of(context).errorColor : Theme.of(context).primaryColorLight, - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: Column( - crossAxisAlignment: _bottomBarProgress ? CrossAxisAlignment.center : CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: bottomBarChildren, - ), - ), - _bottomBarAction - ], - ), - ); - } - } if (HomeAssistant().isNoViews) { return Scaffold( key: _scaffoldKey, primary: false, drawer: _buildAppDrawer(), - bottomNavigationBar: bottomBar, + bottomNavigationBar: BottomInfoBar( + controller: _bottomInfoBarController, + ), body: _buildScaffoldBody(true) ); } else { @@ -826,7 +684,9 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker key: _scaffoldKey, drawer: _buildAppDrawer(), primary: false, - bottomNavigationBar: bottomBar, + bottomNavigationBar: BottomInfoBar( + controller: _bottomInfoBarController, + ), body: _buildScaffoldBody(false) ); } @@ -848,9 +708,8 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker _showErrorSubscription?.cancel(); _startAuthSubscription?.cancel(); _showPageSubscription?.cancel(); + _fullReloadSubscription?.cancel(); _reloadUISubscription?.cancel(); - //TODO disconnect - //widget.homeAssistant?.disconnect(); super.dispose(); } } diff --git a/lib/pages/widgets/bottom_info_bar.dart b/lib/pages/widgets/bottom_info_bar.dart new file mode 100644 index 0000000..fd866e6 --- /dev/null +++ b/lib/pages/widgets/bottom_info_bar.dart @@ -0,0 +1,218 @@ +part of '../../main.dart'; + +class BottomInfoBarController { + + Function show; + Function hide; + + String bottomBarText; + bool bottomBarProgress; + bool bottomBarErrorColor; + Timer _bottomBarTimer; + bool initialState = false; + + List actions = []; + + void hideBottomBar() { + //_scaffoldKey?.currentState?.hideCurrentSnackBar(); + _bottomBarTimer?.cancel(); + if (hide == null) { + initialState = false; + } else { + hide(); + } + } + + void showInfoBottomBar({String message, bool progress: false, Duration duration}) { + _bottomBarTimer?.cancel(); + actions.clear(); + bottomBarErrorColor = false; + bottomBarText = message; + bottomBarProgress = progress; + if (show == null) { + initialState = true; + } else { + Logger.d("Calling show() - ${bottomBarProgress}"); + show(); + } + if (duration != null) { + _bottomBarTimer = Timer(duration, () { + hideBottomBar(); + }); + } + } + + void showErrorBottomBar(HAError error) { + actions.clear(); + actions.addAll(error.actions); + bottomBarErrorColor = true; + bottomBarProgress = false; + bottomBarText = "${error.message}"; + if (show == null) { + initialState = true; + } else { + show(); + } + } + +} + +class BottomInfoBar extends StatefulWidget { + + final BottomInfoBarController controller; + + const BottomInfoBar({Key key, this.controller}) : super(key: key); + + @override + State createState() { + return new _BottomInfoBarState(); + } + +} + +class _BottomInfoBarState extends State { + + bool _show; + + @override + void initState() { + _show = widget.controller.initialState; + widget.controller.show = () { + Logger.d('Set state in show() - ${widget.controller.bottomBarProgress}'); + setState(() { + _show = true; + }); + }; + widget.controller.hide = () { + setState(() { + _show = false; + }); + }; + super.initState(); + } + + + @override + Widget build(BuildContext context) { + if (!_show) { + return Container(width: 0, height: 0,); + } else { + Widget bottomBar; + List bottomBarChildren = []; + Widget actionsWidget; + TextStyle textStyle = Theme.of(context).textTheme.button.copyWith( + decoration: TextDecoration.underline + ); + List actions = []; + widget.controller.actions.forEach((HAErrorAction action) { + switch (action.type) { + case HAErrorActionType.FULL_RELOAD: { + actions.add(FlatButton( + child: Text("${action.title}", style: textStyle), + onPressed: () { + Logger.d('FULL_RELOAD action'); + EventBus().fire(FullReloadEvent()); + }, + )); + break; + } + + case HAErrorActionType.QUICK_RELOAD: { + actions.add(FlatButton( + child: Text("${action.title}", style: textStyle), + onPressed: () { + EventBus().fire(ReloadUIEvent()); + }, + )); + break; + } + + case HAErrorActionType.RELOGIN: { + actions.add(FlatButton( + child: Text("${action.title}", style: textStyle), + onPressed: () { + ConnectionManager().logout().then((_) => EventBus().fire(FullReloadEvent())); + }, + )); + break; + } + + case HAErrorActionType.URL: { + actions.add(FlatButton( + child: Text("${action.title}", style: textStyle), + onPressed: () { + Launcher.launchURLInCustomTab(context: context, url: "${action.url}"); + }, + )); + break; + } + + case HAErrorActionType.OPEN_CONNECTION_SETTINGS: { + actions.add(FlatButton( + child: Text("${action.title}", style: textStyle), + onPressed: () { + Navigator.pushNamed(context, '/connection-settings'); + }, + )); + break; + } + } + }); + if (actions.isNotEmpty) { + actionsWidget = Row( + mainAxisSize: MainAxisSize.min, + children: actions, + mainAxisAlignment: MainAxisAlignment.end, + ); + } else { + actionsWidget = Container(height: 0.0, width: 0.0,); + } + + if (widget.controller.bottomBarText != null) { + bottomBarChildren.add( + Padding( + padding: EdgeInsets.fromLTRB( + Sizes.leftWidgetPadding, Sizes.rowPadding, 0.0, + Sizes.rowPadding), + child: Text( + "${widget.controller.bottomBarText}", + textAlign: TextAlign.left, + softWrap: true, + ), + ) + + ); + } + if (widget.controller.bottomBarProgress) { + bottomBarChildren.add( + CollectionScaleTransition( + children: [ + Icon(Icons.stop, size: 10.0, color: HAClientTheme().getOnStateColor(context),), + Icon(Icons.stop, size: 10.0, color: HAClientTheme().getDisabledStateColor(context),), + Icon(Icons.stop, size: 10.0, color: HAClientTheme().getOffStateColor(context),), + ], + ), + ); + } + if (bottomBarChildren.isNotEmpty) { + bottomBar = Container( + color: widget.controller.bottomBarErrorColor ? Theme.of(context).errorColor : Theme.of(context).primaryColorLight, + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Column( + crossAxisAlignment: widget.controller.bottomBarProgress ? CrossAxisAlignment.center : CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: bottomBarChildren, + ), + ), + actionsWidget + ], + ), + ); + } + return bottomBar; + } + } +} \ No newline at end of file diff --git a/lib/types/event_bus_events.dart b/lib/types/event_bus_events.dart index df0acc2..56b923b 100644 --- a/lib/types/event_bus_events.dart +++ b/lib/types/event_bus_events.dart @@ -25,9 +25,15 @@ class RefreshDataFinishedEvent { } class ReloadUIEvent { + //TODO uiOnly bool + ReloadUIEvent(); } +class FullReloadEvent { + FullReloadEvent(); +} + class ChangeThemeEvent { final AppTheme theme;