diff --git a/src/ui/flutter_app/lib/l10n/intl_en.arb b/src/ui/flutter_app/lib/l10n/intl_en.arb index 9ac9b1ef..3c445ae4 100644 --- a/src/ui/flutter_app/lib/l10n/intl_en.arb +++ b/src/ui/flutter_app/lib/l10n/intl_en.arb @@ -369,7 +369,27 @@ "description": "Copy" }, "moveHistoryCopied": "Move history copied to clipboard", - "@copy": { + "@moveHistoryCopied": { "description": "Move history copied to clipboard" + }, + "help": "Help", + "@help": { + "description": "Help" + }, + "feedback": "FeedBack", + "@feedback": { + "description": "FeedBack" + }, + "inviteFriend": "Invite Friend", + "@inviteFriend": { + "description": "Invite Friend" + }, + "rateTheApp": "Rate The App", + "@rateTheApp": { + "description": "Rate The App" + }, + "exit": "Exit", + "@exit": { + "description": "Exit" } } diff --git a/src/ui/flutter_app/lib/l10n/intl_zh.arb b/src/ui/flutter_app/lib/l10n/intl_zh.arb index 87aa9cd2..0432d0a8 100644 --- a/src/ui/flutter_app/lib/l10n/intl_zh.arb +++ b/src/ui/flutter_app/lib/l10n/intl_zh.arb @@ -92,5 +92,10 @@ "mayFly": "剩余三颗子时飞棋", "maxStepsLedToDraw": "连续多少步无吃子则和棋", "copy": "复制", - "moveHistoryCopied": "棋谱已复制到剪贴板" + "moveHistoryCopied": "棋谱已复制到剪贴板", + "help": "帮助", + "feedback": "反馈", + "inviteFriend": "邀请", + "rateTheApp": "投票", + "exit": "退出" } \ No newline at end of file diff --git a/src/ui/flutter_app/lib/main.dart b/src/ui/flutter_app/lib/main.dart index cc448245..c21c9e60 100644 --- a/src/ui/flutter_app/lib/main.dart +++ b/src/ui/flutter_app/lib/main.dart @@ -25,11 +25,11 @@ import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sanmill/generated/l10n.dart'; +import 'package:sanmill/widgets/navigation_home_screen.dart'; import 'package:stack_trace/stack_trace.dart'; import 'services/audios.dart'; import 'services/player.dart'; -import 'widgets/main_menu.dart'; //import 'package:sentry_flutter/sentry_flutter.dart'; @@ -156,7 +156,7 @@ class _SanmillAppState extends State { Audios.release(); return true; }, - child: MainMenu(), + child: NavigationHomeScreen(), ), ); } diff --git a/src/ui/flutter_app/lib/style/app_theme.dart b/src/ui/flutter_app/lib/style/app_theme.dart new file mode 100644 index 00000000..0946edc3 --- /dev/null +++ b/src/ui/flutter_app/lib/style/app_theme.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; + +class AppTheme { + AppTheme._(); + + static const Color notWhite = Color(0xFFEDF0F2); + static const Color nearlyWhite = Color(0xFFFEFEFE); + static const Color white = Color(0xFFFFFFFF); + static const Color nearlyBlack = Color(0xFF213333); + static const Color grey = Color(0xFF3A5160); + static const Color dark_grey = Color(0xFF313A44); + + static const Color darkText = Color(0xFF253840); + static const Color darkerText = Color(0xFF17262A); + static const Color lightText = Color(0xFF4A6572); + static const Color deactivatedText = Color(0xFF767676); + static const Color dismissibleBackground = Color(0xFF364A54); + static const Color chipBackground = Color(0xFFEEF1F3); + static const Color spacer = Color(0xFFF2F2F2); + static const String fontName = 'WorkSans'; + + static const TextTheme textTheme = TextTheme( + headline4: display1, + headline5: headline, + headline6: title, + subtitle2: subtitle, + bodyText2: body2, + bodyText1: body1, + caption: caption, + ); + + static const TextStyle display1 = TextStyle( // h4 -> display1 + fontFamily: fontName, + fontWeight: FontWeight.bold, + fontSize: 36, + letterSpacing: 0.4, + height: 0.9, + color: darkerText, + ); + + static const TextStyle headline = TextStyle( // h5 -> headline + fontFamily: fontName, + fontWeight: FontWeight.bold, + fontSize: 24, + letterSpacing: 0.27, + color: darkerText, + ); + + static const TextStyle title = TextStyle( // h6 -> title + fontFamily: fontName, + fontWeight: FontWeight.bold, + fontSize: 16, + letterSpacing: 0.18, + color: darkerText, + ); + + static const TextStyle subtitle = TextStyle( // subtitle2 -> subtitle + fontFamily: fontName, + fontWeight: FontWeight.w400, + fontSize: 14, + letterSpacing: -0.04, + color: darkText, + ); + + static const TextStyle body2 = TextStyle( // body1 -> body2 + fontFamily: fontName, + fontWeight: FontWeight.w400, + fontSize: 14, + letterSpacing: 0.2, + color: darkText, + ); + + static const TextStyle body1 = TextStyle( // body2 -> body1 + fontFamily: fontName, + fontWeight: FontWeight.w400, + fontSize: 16, + letterSpacing: -0.05, + color: darkText, + ); + + static const TextStyle caption = TextStyle( // Caption -> caption + fontFamily: fontName, + fontWeight: FontWeight.w400, + fontSize: 12, + letterSpacing: 0.2, + color: lightText, // was lightText + ); + +} diff --git a/src/ui/flutter_app/lib/widgets/drawer_user_controller.dart b/src/ui/flutter_app/lib/widgets/drawer_user_controller.dart new file mode 100644 index 00000000..8caae2a5 --- /dev/null +++ b/src/ui/flutter_app/lib/widgets/drawer_user_controller.dart @@ -0,0 +1,222 @@ +import 'package:flutter/material.dart'; +import 'package:sanmill/style/app_theme.dart'; +import 'package:sanmill/widgets/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 + 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.floor()) { + iconAnimationController.animateTo( + (scrollController.offset * 100 / (widget.drawerWidth)) / 100, + duration: const Duration(milliseconds: 0), + curve: Curves.fastOutSlowIn); + } else { + 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 getInitState() async { + scrollController.jumpTo( + widget.drawerWidth, + ); + return true; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppTheme.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: [ + 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.humanVsAi + : 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: AppTheme.white, + boxShadow: [ + BoxShadow( + color: AppTheme.grey.withOpacity(0.6), + blurRadius: 24), + ], + ), + child: Stack( + children: [ + //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, + color: Colors.white, + 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, + ); + } + } +} diff --git a/src/ui/flutter_app/lib/widgets/feedback_screen.dart b/src/ui/flutter_app/lib/widgets/feedback_screen.dart new file mode 100644 index 00000000..4e29b932 --- /dev/null +++ b/src/ui/flutter_app/lib/widgets/feedback_screen.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:sanmill/style/app_theme.dart'; + +class FeedbackScreen extends StatefulWidget { + @override + _FeedbackScreenState createState() => _FeedbackScreenState(); +} + +class _FeedbackScreenState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + color: AppTheme.nearlyWhite, + child: SafeArea( + top: false, + child: Scaffold( + backgroundColor: AppTheme.nearlyWhite, + body: SingleChildScrollView( + child: SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + children: [ + Container( + padding: EdgeInsets.only( + top: MediaQuery.of(context).padding.top, + left: 16, + right: 16), + child: Image.asset('assets/images/feedbackImage.png'), + ), + Container( + padding: const EdgeInsets.only(top: 8), + child: Text( + 'Your FeedBack', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + Container( + padding: const EdgeInsets.only(top: 16), + child: const Text( + 'Give your best time for this moment.', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + ), + ), + ), + _buildComposer(), + Padding( + padding: const EdgeInsets.only(top: 16), + child: Center( + child: Container( + width: 120, + height: 40, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: + const BorderRadius.all(Radius.circular(4.0)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.6), + offset: const Offset(4, 4), + blurRadius: 8.0), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Center( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + 'Send', + style: TextStyle( + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ), + ), + ), + ), + ), + ) + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildComposer() { + return Padding( + padding: const EdgeInsets.only(top: 16, left: 32, right: 32), + child: Container( + decoration: BoxDecoration( + color: AppTheme.white, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.8), + offset: const Offset(4, 4), + blurRadius: 8), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(25), + child: Container( + padding: const EdgeInsets.all(4.0), + constraints: const BoxConstraints(minHeight: 80, maxHeight: 160), + color: AppTheme.white, + child: SingleChildScrollView( + padding: + const EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 0), + child: TextField( + maxLines: null, + onChanged: (String txt) {}, + style: TextStyle( + fontFamily: AppTheme.fontName, + fontSize: 16, + color: AppTheme.dark_grey, + ), + cursorColor: Colors.blue, + decoration: InputDecoration( + border: InputBorder.none, + hintText: 'Enter your feedback...'), + ), + ), + ), + ), + ), + ); + } +} diff --git a/src/ui/flutter_app/lib/widgets/game_page.dart b/src/ui/flutter_app/lib/widgets/game_page.dart index 0aff96fb..bcbb8af8 100644 --- a/src/ui/flutter_app/lib/widgets/game_page.dart +++ b/src/ui/flutter_app/lib/widgets/game_page.dart @@ -33,7 +33,6 @@ import 'package:sanmill/style/colors.dart'; import 'package:sanmill/style/toast.dart'; import 'board.dart'; -import 'settings_page.dart'; class GamePage extends StatefulWidget { // @@ -74,7 +73,7 @@ class _GamePageState extends State with RouteAware { } void showTips() { - if (context == null) { + if (!mounted || context == null) { //print("[showTips] context == null, return"); return; } @@ -214,6 +213,7 @@ class _GamePageState extends State with RouteAware { while ((Config.isAutoRestart == true || Game.shared.position.winner == Color.nobody) && Game.shared.isAiToMove() && + mounted && context != null) { if (widget.engineType == EngineType.aiVsAi) { String score = Game.shared.position.score[Color.black].toString() + @@ -477,14 +477,17 @@ class _GamePageState extends State with RouteAware { children: [ Row( children: [ + /* IconButton( icon: Icon(Icons.arrow_back, color: UIColors.darkTextSecondaryColor), onPressed: () => Navigator.of(context).pop(), ), + */ Expanded(child: SizedBox()), Text(engineTypeToString[widget.engineType], style: titleStyle), Expanded(child: SizedBox()), + /* IconButton( icon: Icon(Icons.menu /* more_vert */, color: UIColors.darkTextSecondaryColor), @@ -492,6 +495,7 @@ class _GamePageState extends State with RouteAware { MaterialPageRoute(builder: (context) => SettingsPage()), ), ), + */ ], ), Container( diff --git a/src/ui/flutter_app/lib/widgets/help_screen.dart b/src/ui/flutter_app/lib/widgets/help_screen.dart new file mode 100644 index 00000000..62412880 --- /dev/null +++ b/src/ui/flutter_app/lib/widgets/help_screen.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:sanmill/style/app_theme.dart'; + +class HelpScreen extends StatefulWidget { + @override + _HelpScreenState createState() => _HelpScreenState(); +} + +class _HelpScreenState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + color: AppTheme.nearlyWhite, + child: SafeArea( + top: false, + child: Scaffold( + backgroundColor: AppTheme.nearlyWhite, + body: Column( + children: [ + Container( + padding: EdgeInsets.only( + top: MediaQuery.of(context).padding.top, + left: 16, + right: 16), + child: Icon(Icons.help), + ), + Container( + padding: const EdgeInsets.only(top: 8), + child: Text( + 'How can we help you?', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + Container( + padding: const EdgeInsets.only(top: 16), + child: const Text( + 'It looks like you are experiencing problems\nwith our sign up process. We are here to\nhelp so please get in touch with us', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Container( + width: 140, + height: 40, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: + const BorderRadius.all(Radius.circular(4.0)), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.6), + offset: const Offset(4, 4), + blurRadius: 8.0), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () {}, + child: Center( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + 'Chat with Us', + style: TextStyle( + fontWeight: FontWeight.w500, + color: Colors.white, + ), + ), + ), + ), + ), + ), + ), + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/src/ui/flutter_app/lib/widgets/home_drawer.dart b/src/ui/flutter_app/lib/widgets/home_drawer.dart new file mode 100644 index 00000000..e7b06f32 --- /dev/null +++ b/src/ui/flutter_app/lib/widgets/home_drawer.dart @@ -0,0 +1,322 @@ +import 'package:flutter/material.dart'; +// import 'package:flutter/services.dart'; +import 'package:sanmill/generated/l10n.dart'; +import 'package:sanmill/style/app_theme.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 { + List drawerList; + @override + void initState() { + super.initState(); + } + + void setDrawerListArray() { + drawerList = [ + DrawerList( + index: DrawerIndex.humanVsAi, + labelName: S.of(context).humanVsAi, + icon: Icon(Icons.person), + ), + DrawerList( + index: DrawerIndex.humanVsHuman, + labelName: S.of(context).humanVsHuman, + icon: Icon(Icons.group), + ), + DrawerList( + index: DrawerIndex.aiVsAi, + labelName: S.of(context).aiVsAi, + icon: Icon(Icons.computer), + ), + DrawerList( + index: DrawerIndex.settings, + labelName: S.of(context).settings, + icon: Icon(Icons.settings), + ), + DrawerList( + index: DrawerIndex.Help, + labelName: S.of(context).help, + icon: Icon(Icons.help), + ), + /* + DrawerList( + index: DrawerIndex.FeedBack, + labelName: S.of(context).feedback, + icon: Icon(Icons.feedback), + ), + DrawerList( + index: DrawerIndex.Invite, + labelName: S.of(context).inviteFriend, + icon: Icon(Icons.group), + ), + DrawerList( + index: DrawerIndex.Share, + labelName: S.of(context).rateTheApp, + icon: Icon(Icons.share), + ), + */ + DrawerList( + index: DrawerIndex.About, + labelName: S.of(context).about, + icon: Icon(Icons.info), + ), + ]; + } + + @override + Widget build(BuildContext context) { + setDrawerListArray(); + + return Scaffold( + backgroundColor: AppTheme.notWhite.withOpacity(0.5), + body: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.only(top: 0.0), + child: Container( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + AnimatedBuilder( + animation: widget.iconAnimationController, + builder: (BuildContext context, Widget child) { + return ScaleTransition( + scale: AlwaysStoppedAnimation( + 1.0 - (widget.iconAnimationController.value) * 0.2), + child: RotationTransition( + turns: AlwaysStoppedAnimation(Tween( + begin: 0.0, end: 24.0) + .animate(CurvedAnimation( + parent: widget.iconAnimationController, + curve: Curves.fastOutSlowIn)) + .value / + 360), + ), + ); + }, + ), + Padding( + padding: const EdgeInsets.only(top: 8, left: 4), + child: Text( + S.of(context).appName, + style: TextStyle( + fontWeight: FontWeight.w600, + color: AppTheme.grey, + fontSize: 24, + ), + ), + ), + ], + ), + ), + ), + const SizedBox( + height: 4, + ), + Divider( + height: 1, + color: AppTheme.grey.withOpacity(0.6), + ), + 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: AppTheme.grey.withOpacity(0.6), + ), +/* + Column( + children: [ + ListTile( + title: Text( + S.of(context).exit, + style: TextStyle( + fontFamily: AppTheme.fontName, + fontWeight: FontWeight.w600, + fontSize: 16, + color: AppTheme.darkText, + ), + textAlign: TextAlign.left, + ), + trailing: Icon( + Icons.power_settings_new, + color: Colors.red, + ), + onTap: () async { + await SystemChannels.platform + .invokeMethod('SystemNavigator.pop'); + }, + ), + SizedBox( + height: MediaQuery.of(context).padding.bottom, + ) + ], + ), +*/ + ], + ), + ); + } + + Widget inkwell(DrawerList listData) { + return Material( + color: Colors.transparent, + child: InkWell( + splashColor: Colors.grey.withOpacity(0.1), + highlightColor: Colors.transparent, + onTap: () { + navigationtoScreen(listData.index); + }, + child: Stack( + children: [ + Container( + padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), + child: Row( + children: [ + Container( + width: 6.0, + height: 46.0, + // decoration: BoxDecoration( + // color: widget.screenIndex == listData.index + // ? Colors.blue + // : Colors.transparent, + // borderRadius: new BorderRadius.only( + // topLeft: Radius.circular(0), + // topRight: Radius.circular(16), + // bottomLeft: Radius.circular(0), + // bottomRight: Radius.circular(16), + // ), + // ), + ), + const Padding( + padding: EdgeInsets.all(4.0), + ), + listData.isAssetsImage + ? Container( + width: 24, + height: 24, + child: Image.asset(listData.imageName, + color: widget.screenIndex == listData.index + ? Colors.blue + : AppTheme.nearlyBlack), + ) + : Icon(listData.icon.icon, + color: widget.screenIndex == listData.index + ? Colors.blue + : AppTheme.nearlyBlack), + const Padding( + padding: EdgeInsets.all(4.0), + ), + Text( + listData.labelName, + style: TextStyle( + fontWeight: FontWeight.w500, + fontSize: 16, + color: widget.screenIndex == listData.index + ? Colors.blue + : AppTheme.nearlyBlack, + ), + 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: Colors.blue.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 navigationtoScreen(DrawerIndex indexScreen) async { + widget.callBackIndex(indexScreen); + } +} + +enum DrawerIndex { + humanVsAi, + humanVsHuman, + aiVsAi, + settings, + FeedBack, + Help, + Share, + About, + Invite, + Testing, +} + +class DrawerList { + DrawerList({ + this.isAssetsImage = false, + this.labelName = '', + this.icon, + this.index, + this.imageName = '', + }); + + String labelName; + Icon icon; + bool isAssetsImage; + String imageName; + DrawerIndex index; +} diff --git a/src/ui/flutter_app/lib/widgets/navigation_home_screen.dart b/src/ui/flutter_app/lib/widgets/navigation_home_screen.dart new file mode 100644 index 00000000..4b4b4185 --- /dev/null +++ b/src/ui/flutter_app/lib/widgets/navigation_home_screen.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:sanmill/engine/engine.dart'; +import 'package:sanmill/mill/game.dart'; +import 'package:sanmill/style/app_theme.dart'; +import 'package:sanmill/widgets/drawer_user_controller.dart'; +import 'package:sanmill/widgets/feedback_screen.dart'; +import 'package:sanmill/widgets/help_screen.dart'; +import 'package:sanmill/widgets/home_drawer.dart'; + +import 'game_page.dart'; +import 'settings_page.dart'; + +class NavigationHomeScreen extends StatefulWidget { + @override + _NavigationHomeScreenState createState() => _NavigationHomeScreenState(); +} + +class _NavigationHomeScreenState extends State { + Widget screenView; + DrawerIndex drawerIndex; + + @override + void initState() { + drawerIndex = DrawerIndex.humanVsAi; + screenView = GamePage(EngineType.humanVsAi); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Container( + color: AppTheme.nearlyWhite, + child: SafeArea( + top: false, + bottom: false, + child: Scaffold( + backgroundColor: AppTheme.nearlyWhite, + 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.humanVsAi) { + setState(() { + Game.shared.setWhoIsAi(EngineType.humanVsAi); + screenView = GamePage(EngineType.humanVsAi); + }); + } else if (drawerIndex == DrawerIndex.humanVsHuman) { + setState(() { + Game.shared.setWhoIsAi(EngineType.humanVsHuman); + screenView = GamePage(EngineType.humanVsHuman); + }); + } else if (drawerIndex == DrawerIndex.aiVsAi) { + setState(() { + Game.shared.setWhoIsAi(EngineType.aiVsAi); + screenView = GamePage(EngineType.aiVsAi); + }); + } else if (drawerIndex == DrawerIndex.settings) { + setState(() { + screenView = SettingsPage(); + }); + } else if (drawerIndex == DrawerIndex.Help) { + setState(() { + screenView = HelpScreen(); + }); + } else if (drawerIndex == DrawerIndex.FeedBack) { + setState(() { + screenView = FeedbackScreen(); + }); + } else if (drawerIndex == DrawerIndex.Invite) { + setState(() { + screenView = HelpScreen(); + }); + } else { + //do in your way...... + } + } + } +} diff --git a/src/ui/flutter_app/lib/widgets/settings_page.dart b/src/ui/flutter_app/lib/widgets/settings_page.dart index 8badc371..0245b75e 100644 --- a/src/ui/flutter_app/lib/widgets/settings_page.dart +++ b/src/ui/flutter_app/lib/widgets/settings_page.dart @@ -481,7 +481,7 @@ class _SettingsPageState extends State { return Scaffold( backgroundColor: UIColors.lightBackgroundColor, - appBar: AppBar(title: Text(S.of(context).settings)), + appBar: AppBar(centerTitle: true, title: Text(S.of(context).settings)), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column(