| @@ -1,5 +1,6 @@ | |||
| import 'package:farm_tpf/presentation/screens/home/view/home_page.dart'; | |||
| import 'package:farm_tpf/presentation/screens/login/view/login_page.dart'; | |||
| import 'package:farm_tpf/presentation/screens/slide_menu/navigation_home_screen.dart'; | |||
| import 'package:farm_tpf/presentation/screens/splash/view/splash_page.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| @@ -60,7 +61,7 @@ class _AppViewState extends State<AppView> { | |||
| switch (state.status) { | |||
| case AuthenticationStatus.authenticated: | |||
| _navigator.pushAndRemoveUntil<void>( | |||
| HomePage.route(), | |||
| NavigationHomeScreen.route(), | |||
| (route) => false, | |||
| ); | |||
| break; | |||
| @@ -15,17 +15,7 @@ class HomePage extends StatelessWidget { | |||
| child: Column( | |||
| mainAxisSize: MainAxisSize.min, | |||
| children: <Widget>[ | |||
| Text("logged in." | |||
| // 'UserID: ${context.bloc<AuthenticationBloc>().state.user.id}', | |||
| ), | |||
| RaisedButton( | |||
| child: const Text('Đăng xuất'), | |||
| onPressed: () { | |||
| context | |||
| .bloc<AuthenticationBloc>() | |||
| .add(AuthenticationLogoutRequested()); | |||
| }, | |||
| ), | |||
| Text("logged in."), | |||
| ], | |||
| ), | |||
| ), | |||
| @@ -0,0 +1,220 @@ | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'home_drawer.dart'; | |||
| class DrawerUserController extends StatefulWidget { | |||
| const DrawerUserController({ | |||
| Key key, | |||
| this.drawerWidth = 250, | |||
| this.onDrawerCall, | |||
| this.screenView, | |||
| this.animatedIconData = AnimatedIcons.arrow_menu, | |||
| this.menuView, | |||
| this.drawerIsOpen, | |||
| this.screenIndex, | |||
| }) : super(key: key); | |||
| final double drawerWidth; | |||
| final Function(DrawerIndex) onDrawerCall; | |||
| final Widget screenView; | |||
| final Function(bool) drawerIsOpen; | |||
| final AnimatedIconData animatedIconData; | |||
| final Widget menuView; | |||
| final DrawerIndex screenIndex; | |||
| @override | |||
| _DrawerUserControllerState createState() => _DrawerUserControllerState(); | |||
| } | |||
| class _DrawerUserControllerState extends State<DrawerUserController> | |||
| with TickerProviderStateMixin { | |||
| ScrollController scrollController; | |||
| AnimationController iconAnimationController; | |||
| AnimationController animationController; | |||
| double scrolloffset = 0.0; | |||
| @override | |||
| void initState() { | |||
| animationController = AnimationController( | |||
| duration: const Duration(milliseconds: 2000), vsync: this); | |||
| iconAnimationController = AnimationController( | |||
| vsync: this, duration: const Duration(milliseconds: 0)); | |||
| iconAnimationController | |||
| ..animateTo(1.0, | |||
| duration: const Duration(milliseconds: 0), | |||
| curve: Curves.fastOutSlowIn); | |||
| scrollController = | |||
| ScrollController(initialScrollOffset: widget.drawerWidth); | |||
| scrollController | |||
| ..addListener(() { | |||
| if (scrollController.offset <= 0) { | |||
| if (scrolloffset != 1.0) { | |||
| setState(() { | |||
| scrolloffset = 1.0; | |||
| try { | |||
| widget.drawerIsOpen(true); | |||
| } catch (_) {} | |||
| }); | |||
| } | |||
| iconAnimationController.animateTo(0.0, | |||
| duration: const Duration(milliseconds: 0), | |||
| curve: Curves.fastOutSlowIn); | |||
| } else if (scrollController.offset > 0 && | |||
| scrollController.offset < widget.drawerWidth) { | |||
| iconAnimationController.animateTo( | |||
| (scrollController.offset * 100 / (widget.drawerWidth)) / 100, | |||
| duration: const Duration(milliseconds: 0), | |||
| curve: Curves.fastOutSlowIn); | |||
| } else if (scrollController.offset <= widget.drawerWidth) { | |||
| if (scrolloffset != 0.0) { | |||
| setState(() { | |||
| scrolloffset = 0.0; | |||
| try { | |||
| widget.drawerIsOpen(false); | |||
| } catch (_) {} | |||
| }); | |||
| } | |||
| iconAnimationController.animateTo(1.0, | |||
| duration: const Duration(milliseconds: 0), | |||
| curve: Curves.fastOutSlowIn); | |||
| } | |||
| }); | |||
| WidgetsBinding.instance.addPostFrameCallback((_) => getInitState()); | |||
| super.initState(); | |||
| } | |||
| Future<bool> getInitState() async { | |||
| scrollController.jumpTo( | |||
| widget.drawerWidth, | |||
| ); | |||
| return true; | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| backgroundColor: COLOR_CONST.WHITE, | |||
| body: SingleChildScrollView( | |||
| controller: scrollController, | |||
| scrollDirection: Axis.horizontal, | |||
| physics: const PageScrollPhysics(parent: ClampingScrollPhysics()), | |||
| child: SizedBox( | |||
| height: MediaQuery.of(context).size.height, | |||
| width: MediaQuery.of(context).size.width + widget.drawerWidth, | |||
| //we use with as screen width and add drawerWidth (from navigation_home_screen) | |||
| child: Row( | |||
| children: <Widget>[ | |||
| SizedBox( | |||
| width: widget.drawerWidth, | |||
| //we divided first drawer Width with HomeDrawer and second full-screen Width with all home screen, we called screen View | |||
| height: MediaQuery.of(context).size.height, | |||
| child: AnimatedBuilder( | |||
| animation: iconAnimationController, | |||
| builder: (BuildContext context, Widget child) { | |||
| return Transform( | |||
| //transform we use for the stable drawer we, not need to move with scroll view | |||
| transform: Matrix4.translationValues( | |||
| scrollController.offset, 0.0, 0.0), | |||
| child: HomeDrawer( | |||
| screenIndex: widget.screenIndex == null | |||
| ? DrawerIndex.Home | |||
| : widget.screenIndex, | |||
| iconAnimationController: iconAnimationController, | |||
| callBackIndex: (DrawerIndex indexType) { | |||
| onDrawerClick(); | |||
| try { | |||
| widget.onDrawerCall(indexType); | |||
| } catch (e) {} | |||
| }, | |||
| ), | |||
| ); | |||
| }, | |||
| ), | |||
| ), | |||
| SizedBox( | |||
| width: MediaQuery.of(context).size.width, | |||
| height: MediaQuery.of(context).size.height, | |||
| //full-screen Width with widget.screenView | |||
| child: Container( | |||
| decoration: BoxDecoration( | |||
| color: COLOR_CONST.WHITE, | |||
| boxShadow: <BoxShadow>[ | |||
| BoxShadow(color: COLOR_CONST.GRAY1, blurRadius: 24), | |||
| ], | |||
| ), | |||
| child: Stack( | |||
| children: <Widget>[ | |||
| //this IgnorePointer we use as touch(user Interface) widget.screen View, for example scrolloffset == 1 means drawer is close we just allow touching all widget.screen View | |||
| IgnorePointer( | |||
| ignoring: scrolloffset == 1 || false, | |||
| child: widget.screenView, | |||
| ), | |||
| //alternative touch(user Interface) for widget.screen, for example, drawer is close we need to tap on a few home screen area and close the drawer | |||
| if (scrolloffset == 1.0) | |||
| InkWell( | |||
| onTap: () { | |||
| onDrawerClick(); | |||
| }, | |||
| ), | |||
| // this just menu and arrow icon animation | |||
| Padding( | |||
| padding: EdgeInsets.only( | |||
| top: MediaQuery.of(context).padding.top + 8, | |||
| left: 8), | |||
| child: SizedBox( | |||
| width: AppBar().preferredSize.height - 8, | |||
| height: AppBar().preferredSize.height - 8, | |||
| child: Material( | |||
| color: Colors.transparent, | |||
| child: InkWell( | |||
| borderRadius: BorderRadius.circular( | |||
| AppBar().preferredSize.height), | |||
| child: Center( | |||
| // if you use your own menu view UI you add form initialization | |||
| child: widget.menuView != null | |||
| ? widget.menuView | |||
| : AnimatedIcon( | |||
| icon: widget.animatedIconData != null | |||
| ? widget.animatedIconData | |||
| : AnimatedIcons.arrow_menu, | |||
| progress: iconAnimationController), | |||
| ), | |||
| onTap: () { | |||
| FocusScope.of(context) | |||
| .requestFocus(FocusNode()); | |||
| onDrawerClick(); | |||
| }, | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| void onDrawerClick() { | |||
| //if scrollcontroller.offset != 0.0 then we set to closed the drawer(with animation to offset zero position) if is not 1 then open the drawer | |||
| if (scrollController.offset != 0.0) { | |||
| scrollController.animateTo( | |||
| 0.0, | |||
| duration: const Duration(milliseconds: 400), | |||
| curve: Curves.fastOutSlowIn, | |||
| ); | |||
| } else { | |||
| scrollController.animateTo( | |||
| widget.drawerWidth, | |||
| duration: const Duration(milliseconds: 400), | |||
| curve: Curves.fastOutSlowIn, | |||
| ); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,276 @@ | |||
| import 'package:farm_tpf/authentication/authentication.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_bloc/flutter_bloc.dart'; | |||
| class HomeDrawer extends StatefulWidget { | |||
| const HomeDrawer( | |||
| {Key key, | |||
| this.screenIndex, | |||
| this.iconAnimationController, | |||
| this.callBackIndex}) | |||
| : super(key: key); | |||
| final AnimationController iconAnimationController; | |||
| final DrawerIndex screenIndex; | |||
| final Function(DrawerIndex) callBackIndex; | |||
| @override | |||
| _HomeDrawerState createState() => _HomeDrawerState(); | |||
| } | |||
| class _HomeDrawerState extends State<HomeDrawer> { | |||
| List<DrawerList> drawerList; | |||
| @override | |||
| void initState() { | |||
| setdDrawerListArray(); | |||
| super.initState(); | |||
| } | |||
| void setdDrawerListArray() { | |||
| drawerList = <DrawerList>[ | |||
| DrawerList( | |||
| index: DrawerIndex.Home, | |||
| labelName: 'Trang chủ', | |||
| icon: Icon(Icons.home), | |||
| ), | |||
| DrawerList( | |||
| index: DrawerIndex.Setting, | |||
| labelName: 'Cài đặt', | |||
| icon: Icon(Icons.settings), | |||
| ) | |||
| ]; | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Container( | |||
| child: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.stretch, | |||
| mainAxisAlignment: MainAxisAlignment.start, | |||
| children: <Widget>[ | |||
| Container( | |||
| width: double.infinity, | |||
| padding: const EdgeInsets.only(top: 45.0), | |||
| child: Container( | |||
| padding: const EdgeInsets.all(16.0), | |||
| child: Column( | |||
| crossAxisAlignment: CrossAxisAlignment.start, | |||
| mainAxisAlignment: MainAxisAlignment.start, | |||
| children: <Widget>[ | |||
| AnimatedBuilder( | |||
| animation: widget.iconAnimationController, | |||
| builder: (BuildContext context, Widget child) { | |||
| return ScaleTransition( | |||
| scale: AlwaysStoppedAnimation<double>( | |||
| 1.0 - (widget.iconAnimationController.value) * 0.2), | |||
| child: RotationTransition( | |||
| turns: AlwaysStoppedAnimation<double>(Tween<double>( | |||
| begin: 0.0, end: 24.0) | |||
| .animate(CurvedAnimation( | |||
| parent: widget.iconAnimationController, | |||
| curve: Curves.fastOutSlowIn)) | |||
| .value / | |||
| 360), | |||
| child: Container( | |||
| height: 100, | |||
| width: 100, | |||
| decoration: BoxDecoration( | |||
| borderRadius: BorderRadius.circular(120), | |||
| border: Border.all( | |||
| width: 0.35, color: COLOR_CONST.DEFAULT), | |||
| ), | |||
| child: ClipRRect( | |||
| borderRadius: | |||
| const BorderRadius.all(Radius.circular(10.0)), | |||
| child: FlutterLogo( | |||
| size: 10, | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ); | |||
| }, | |||
| ), | |||
| Padding( | |||
| padding: const EdgeInsets.only(top: 8, left: 20), | |||
| child: Text( | |||
| 'Võ Phước Đại', | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.w600, | |||
| color: COLOR_CONST.GRAY1, | |||
| fontSize: 18, | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ), | |||
| const SizedBox( | |||
| height: 4, | |||
| ), | |||
| Divider( | |||
| height: 1, | |||
| color: COLOR_CONST.GRAY1, | |||
| ), | |||
| Expanded( | |||
| child: ListView.builder( | |||
| physics: const BouncingScrollPhysics(), | |||
| padding: const EdgeInsets.all(0.0), | |||
| itemCount: drawerList.length, | |||
| itemBuilder: (BuildContext context, int index) { | |||
| return inkwell(drawerList[index]); | |||
| }, | |||
| ), | |||
| ), | |||
| Divider( | |||
| height: 1, | |||
| color: COLOR_CONST.GRAY1, | |||
| ), | |||
| Column( | |||
| children: <Widget>[ | |||
| ListTile( | |||
| title: Text( | |||
| 'Đăng xuất', | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.w600, | |||
| fontSize: 16, | |||
| ), | |||
| textAlign: TextAlign.left, | |||
| ), | |||
| trailing: Icon( | |||
| Icons.power_settings_new, | |||
| color: Colors.red, | |||
| ), | |||
| onTap: () { | |||
| _clickSignOut(); | |||
| }, | |||
| ), | |||
| SizedBox( | |||
| height: MediaQuery.of(context).padding.bottom, | |||
| ) | |||
| ], | |||
| ), | |||
| ], | |||
| ), | |||
| ); | |||
| } | |||
| Widget inkwell(DrawerList listData) { | |||
| return Material( | |||
| color: Colors.white, | |||
| child: InkWell( | |||
| splashColor: Colors.grey.withOpacity(0.1), | |||
| highlightColor: Colors.transparent, | |||
| onTap: () { | |||
| navigationtoScreen(listData.index); | |||
| }, | |||
| child: Stack( | |||
| children: <Widget>[ | |||
| Container( | |||
| padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Container( | |||
| width: 6.0, | |||
| height: 46.0, | |||
| ), | |||
| const Padding( | |||
| padding: EdgeInsets.all(4.0), | |||
| ), | |||
| listData.isAssetsImage | |||
| ? Container( | |||
| width: 24, | |||
| height: 24, | |||
| child: Image.asset(listData.imageName, | |||
| color: widget.screenIndex == listData.index | |||
| ? COLOR_CONST.DEFAULT | |||
| : COLOR_CONST.BLACK), | |||
| ) | |||
| : Icon(listData.icon.icon, | |||
| color: widget.screenIndex == listData.index | |||
| ? COLOR_CONST.DEFAULT | |||
| : COLOR_CONST.BLACK), | |||
| const Padding( | |||
| padding: EdgeInsets.all(4.0), | |||
| ), | |||
| Text( | |||
| listData.labelName, | |||
| style: TextStyle( | |||
| fontWeight: FontWeight.w500, | |||
| fontSize: 16, | |||
| color: widget.screenIndex == listData.index | |||
| ? COLOR_CONST.DEFAULT | |||
| : COLOR_CONST.BLACK, | |||
| ), | |||
| textAlign: TextAlign.left, | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| widget.screenIndex == listData.index | |||
| ? AnimatedBuilder( | |||
| animation: widget.iconAnimationController, | |||
| builder: (BuildContext context, Widget child) { | |||
| return Transform( | |||
| transform: Matrix4.translationValues( | |||
| (MediaQuery.of(context).size.width * 0.75 - 64) * | |||
| (1.0 - | |||
| widget.iconAnimationController.value - | |||
| 1.0), | |||
| 0.0, | |||
| 0.0), | |||
| child: Padding( | |||
| padding: EdgeInsets.only(top: 8, bottom: 8), | |||
| child: Container( | |||
| width: | |||
| MediaQuery.of(context).size.width * 0.75 - 64, | |||
| height: 46, | |||
| decoration: BoxDecoration( | |||
| color: COLOR_CONST.DEFAULT.withOpacity(0.2), | |||
| borderRadius: new BorderRadius.only( | |||
| topLeft: Radius.circular(0), | |||
| topRight: Radius.circular(28), | |||
| bottomLeft: Radius.circular(0), | |||
| bottomRight: Radius.circular(28), | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ); | |||
| }, | |||
| ) | |||
| : const SizedBox() | |||
| ], | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| Future<void> navigationtoScreen(DrawerIndex indexScreen) async { | |||
| widget.callBackIndex(indexScreen); | |||
| } | |||
| _clickSignOut() { | |||
| context.bloc<AuthenticationBloc>().add(AuthenticationLogoutRequested()); | |||
| } | |||
| } | |||
| enum DrawerIndex { Home, Setting } | |||
| class DrawerList { | |||
| DrawerList({ | |||
| this.isAssetsImage = false, | |||
| this.labelName = '', | |||
| this.icon, | |||
| this.index, | |||
| this.imageName = '', | |||
| }); | |||
| String labelName; | |||
| Icon icon; | |||
| bool isAssetsImage; | |||
| String imageName; | |||
| DrawerIndex index; | |||
| } | |||
| @@ -0,0 +1,68 @@ | |||
| import 'package:farm_tpf/presentation/screens/home/home.dart'; | |||
| import 'package:farm_tpf/utils/const_color.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'drawer_user_controller.dart'; | |||
| import 'home_drawer.dart'; | |||
| class NavigationHomeScreen extends StatefulWidget { | |||
| static Route route() { | |||
| return MaterialPageRoute<void>(builder: (_) => NavigationHomeScreen()); | |||
| } | |||
| @override | |||
| _NavigationHomeScreenState createState() => _NavigationHomeScreenState(); | |||
| } | |||
| class _NavigationHomeScreenState extends State<NavigationHomeScreen> { | |||
| Widget screenView; | |||
| DrawerIndex drawerIndex; | |||
| @override | |||
| void initState() { | |||
| drawerIndex = DrawerIndex.Home; | |||
| screenView = HomePage(); | |||
| super.initState(); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Container( | |||
| color: COLOR_CONST.DEFAULT, | |||
| child: SafeArea( | |||
| top: false, | |||
| bottom: false, | |||
| child: Scaffold( | |||
| backgroundColor: COLOR_CONST.WHITE, | |||
| body: DrawerUserController( | |||
| screenIndex: drawerIndex, | |||
| drawerWidth: MediaQuery.of(context).size.width * 0.75, | |||
| onDrawerCall: (DrawerIndex drawerIndexdata) { | |||
| changeIndex(drawerIndexdata); | |||
| //callback from drawer for replace screen as user need with passing DrawerIndex(Enum index) | |||
| }, | |||
| screenView: screenView, | |||
| //we replace screen view as we need on navigate starting screens like MyHomePage, HelpScreen, FeedbackScreen, etc... | |||
| ), | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| void changeIndex(DrawerIndex drawerIndexdata) { | |||
| if (drawerIndex != drawerIndexdata) { | |||
| drawerIndex = drawerIndexdata; | |||
| if (drawerIndex == DrawerIndex.Home) { | |||
| setState(() { | |||
| screenView = HomePage(); | |||
| }); | |||
| } else if (drawerIndex == DrawerIndex.Setting) { | |||
| setState(() { | |||
| screenView = HomePage(); | |||
| }); | |||
| } else { | |||
| //do in your way...... | |||
| } | |||
| } | |||
| } | |||
| } | |||