From 5b922b43557b43322efc2355f9d9a6c5a07fca6a Mon Sep 17 00:00:00 2001 From: venbaittech Date: Thu, 6 Feb 2025 12:32:46 +0530 Subject: [PATCH] login and register UI changes added --- ...kotlin-compiler-3932177861650478103.salive | 0 android/app/build.gradle | 4 +- assets/icons/drawer/feedback.png | Bin 0 -> 366 bytes assets/icons/drawer/guide.png | Bin 0 -> 468 bytes assets/icons/drawer/manageusr.png | Bin 0 -> 339 bytes assets/icons/misc/save.png | Bin 0 -> 330 bytes lib/config/my_router.dart | 18 +- .../icons/drawer_asset_icon_path.dart | 3 + .../icons/misc_icon_asset_path.dart | 2 + .../auth_verification/registration.dart | 222 +++-- lib/presentation/Screens/profilepage.dart | 812 +++++++++--------- .../routes/auth_routes/login_route.dart | 162 ++-- .../auth_routes/pocketbase_service.dart | 66 ++ .../tab_routes/home_route.dart | 230 ++--- .../Drawer Items/edit_profile.dart | 57 +- .../drawer_routes/custom_drawer_routes.dart | 24 +- pubspec.yaml | 6 +- 17 files changed, 945 insertions(+), 661 deletions(-) delete mode 100644 android/.kotlin/sessions/kotlin-compiler-3932177861650478103.salive create mode 100644 assets/icons/drawer/feedback.png create mode 100644 assets/icons/drawer/guide.png create mode 100644 assets/icons/drawer/manageusr.png create mode 100644 assets/icons/misc/save.png create mode 100644 lib/presentation/routes/auth_routes/pocketbase_service.dart diff --git a/android/.kotlin/sessions/kotlin-compiler-3932177861650478103.salive b/android/.kotlin/sessions/kotlin-compiler-3932177861650478103.salive deleted file mode 100644 index e69de29b..00000000 diff --git a/android/app/build.gradle b/android/app/build.gradle index 6891a8ad..374c1b19 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) { def flutterVersionCode = localProperties.getProperty("flutter.versionCode") if (flutterVersionCode == null) { - flutterVersionCode = "7" + flutterVersionCode = "9" } def flutterVersionName = localProperties.getProperty("flutter.versionName") if (flutterVersionName == null) { - flutterVersionName = "1.0.6" + flutterVersionName = "1.0.8" } def keystorePropertiesFile = rootProject.file("key.properties") diff --git a/assets/icons/drawer/feedback.png b/assets/icons/drawer/feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..2d190a84fb5db235be2f5dab0f7c930074498f60 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`j)FbFd;%$g$s6l5$8 za(7}_cTVOdki(Mh=Xfs-haCjm_D6o>DQWPIP<1=i zTgo25_>LhEh%b3sDcqUxp-WRyRbkScM=3_IB-br^fm1op@p*cm$#V;oczkSxp@Lh`D@j>&?zsC z*Drj=uab1zBsApJPyf``zKxbu3G26MNHx2!epzR%e_^t%!reeGn@_4Gz~Eu8O4*&oF literal 0 HcmV?d00001 diff --git a/assets/icons/drawer/guide.png b/assets/icons/drawer/guide.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9c837898ccae2d844e02e691f31f6be544e0de GIT binary patch literal 468 zcmV;_0W1EAP)}`g=&$FywDfj~^CbE)Yt`ZWFTU&7H^T<@!mTL)K_emcTeHX;Cx8!HkU7?^W zr+l;5+gNVb7W90+H`V`SS@L$9uSGG&S^H!`v3n&^$>Sj8CksmEjMubixiuJ2$3$E# z4sXUWUc5$2wn82UhgK3+!V!qOAm5ikoieU%M;J%8nIsQ^j>81I+{xat)W-U{nfT2J ztWW`+G26nY&Ra7^*JTdN_>C$--U_(#I0RK<8oxT_%Xs_1o&{e{`gR$_Jc}~`0000< KMNUMnLSTYrwZY*4 literal 0 HcmV?d00001 diff --git a/assets/icons/drawer/manageusr.png b/assets/icons/drawer/manageusr.png new file mode 100644 index 0000000000000000000000000000000000000000..cfcba90b10d43d078774a703e364d9b1fba949a9 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W;!3HFgc;@~FQk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK>iC)7srqa#;KF{3N|?iv|gXjw1L^l*w9#5 z`vTvQ3m$73);btF>pE&3;Jd=5VltWU%UYeor)182OtYJ@_h$9?&DAddiw?>iadP0j zsx@e1-iExAEZ!&hqoGRNJSm<%p%Sx-FLH9-TJPFx@+&WVqt~eGT{xf{9d20F0|1%?c zq%^0TY`>HuZ&IF}>*s2Js+e;-)gy9ZT0&@Q1#`L9tm`W7WxEzX5@}S_ jf7t(4cJ0YWnstnC4fVFi1?+1B`kBGg)z4*}Q$iB}b|Hdz literal 0 HcmV?d00001 diff --git a/assets/icons/misc/save.png b/assets/icons/misc/save.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f0b947a8565cb92fa3e6eb5fc49d4b7e34c7c6 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIoCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eB{(Vmu$B+ufw^JHv@?CoaVCJVNk!o z+auf|y`i!10Nc3-Y&{3qzAg^+Sh~&Cx96p|-t;f){(kwSDZuG4gWGGR@MISWcf}+3 z!hCodn>5p}^oZ3h>6ujh(JMn^Q<%95Q$qd9?{AO2>U^#!z3fm>+$Xl{vkw$0>kArf zUt{m~N=T~imdKI;Vst07mA4Gynhq literal 0 HcmV?d00001 diff --git a/lib/config/my_router.dart b/lib/config/my_router.dart index e6b1a5fa..9a58cbc2 100644 --- a/lib/config/my_router.dart +++ b/lib/config/my_router.dart @@ -300,6 +300,7 @@ import 'package:uae_stat/presentation/Screens/charts/chart.dart'; import 'package:uae_stat/presentation/Screens/charts/screens/chart_screen.dart'; import 'package:uae_stat/presentation/Screens/demo_home2.dart'; import 'package:uae_stat/presentation/Screens/online_offline_verification/internet_check.dart'; +import 'package:uae_stat/presentation/routes/auth_routes/pocketbase_service.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/Drawer%20Items/user_guide/getting_started.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; @@ -324,20 +325,33 @@ import '../presentation/routes/drawer_routes/Drawer Items/user_guide/features.da import '../presentation/routes/drawer_routes/Drawer Items/user_guide/user_guide.dart'; import '../presentation/routes/drawer_routes/Drawer Items/manage_users.dart'; +final pbService = PocketBaseService(); + +Future getInitialRoute() async { + bool isLoggedIn = await pbService.loadSession(); + return isLoggedIn ? '/myhomepage' : '/login'; +} + final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', //builder: (context, state) => LoginRoute(), - builder: (context, state) => LoginRoute(isLoginScreen: true), + builder: (context, state) => LoginRoute(), ), + // GoRoute( + // path: '/', + // redirect: (context, state) async { + // return await getInitialRoute(); + // }, + // ), GoRoute( path: '/internetcheck', builder: (context, state) => InternetCheck(), ), GoRoute( path: '/login', - builder: (context, state) => LoginRoute(isLoginScreen: true), + builder: (context, state) => LoginRoute(), //builder: (context, state) => LoginRoute(), ), GoRoute( diff --git a/lib/infrastructure/services/img_asset_paths/icons/drawer_asset_icon_path.dart b/lib/infrastructure/services/img_asset_paths/icons/drawer_asset_icon_path.dart index 265d41f7..cbd0bc48 100644 --- a/lib/infrastructure/services/img_asset_paths/icons/drawer_asset_icon_path.dart +++ b/lib/infrastructure/services/img_asset_paths/icons/drawer_asset_icon_path.dart @@ -8,4 +8,7 @@ abstract class DrawerAssetIconPath { static const message = '$_basePath/message.png'; static const scroll = '$_basePath/scroll.png'; static const manageuser = '$_basePath/manageuser.png'; + static const manageUser = '$_basePath/manageusr.png'; + static const guide = '$_basePath/guide.png'; + static const feedback = '$_basePath/feedback.png'; } diff --git a/lib/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart b/lib/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart index 55f0bdcd..7912f789 100644 --- a/lib/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart +++ b/lib/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart @@ -9,4 +9,6 @@ abstract class MiscIconAssetPath { static const vector = '$_basePath/vector.png'; static const visibleOn = '$_basePath/visible_on.png'; static const visibilityOff = '$_basePath/visibility_off.png'; + static const save = '$_basePath/save.png'; + } diff --git a/lib/presentation/Screens/auth_verification/registration.dart b/lib/presentation/Screens/auth_verification/registration.dart index 973d3481..e8008c78 100644 --- a/lib/presentation/Screens/auth_verification/registration.dart +++ b/lib/presentation/Screens/auth_verification/registration.dart @@ -271,7 +271,13 @@ class _RegisterScreenState extends State { 'Email ID already exists. Please use a different email.'), actions: [ TextButton( - onPressed: () => Navigator.pop(context), + onPressed: () { + Navigator.pop(context); + setState(() { + isRegistering = + false; // Re-enable the button after error + }); + }, child: Text('OK'), ), ], @@ -356,6 +362,7 @@ class _RegisterScreenState extends State { }, ), ], + backgroundColor: Colors.white, ), backgroundColor: Colors.white, body: registrationSuccess @@ -474,8 +481,8 @@ class _RegisterScreenState extends State { ), ) : Padding( - padding: const EdgeInsets.only(top: 5.0,bottom: 20, left: 30,right: 30), - + padding: const EdgeInsets.only( + top: 5.0, bottom: 20, left: 30, right: 30), child: Form( key: _formKey, child: SingleChildScrollView( @@ -502,13 +509,23 @@ class _RegisterScreenState extends State { hintText: _showHints[0] ? AppLocalizations.of(context)!.register_name : null, + prefixIconConstraints: const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), prefixIcon: Padding( - padding: const EdgeInsets.only(bottom: 1.0,top:1.0,right:10.0,left:15.0 ), // Adjust the padding as needed + padding: const EdgeInsetsDirectional.only( + start: 16, + end: 10, + ), child: Image.asset( MiscIconAssetPath.person, - color: Color(0xFF90B0D5), + fit: BoxFit.fitHeight, + height: 25, width: 25, - height: 15, + color: + MyTheme.topicColor(IndicatorTopic.economy) + .shade300, ), ), @@ -520,20 +537,29 @@ class _RegisterScreenState extends State { // border: OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), -borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, - width: 1), // Enabled border - ), + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, + width: 1), // Enabled border + ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Error border + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border ), - focusedErrorBorder: OutlineInputBorder( + focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Match the error color + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Match the error color ), counterText: '', hintStyle: TextStyle(color: Color(0xFFC3C6CB)), @@ -554,32 +580,52 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 .enter_your_email : null, // _showHints[1] ? 'Enter your email' : null, + prefixIconConstraints: const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), prefixIcon: Padding( - padding: const EdgeInsets.only(bottom: 1.0,top:1.0,right:10.0,left:15.0 ), // Adjust the padding as needed + padding: const EdgeInsetsDirectional.only( + start: 16, + end: 10, + ), child: Image.asset( MiscIconAssetPath.vector, - color: Color(0xFF90B0D5), + fit: BoxFit.fitHeight, + height: 20, width: 25, - height: 15, + color: + MyTheme.topicColor(IndicatorTopic.economy) + .shade100, ), ), + // border: OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), -borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, width: 1), - ), + ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Error border + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border ), - focusedErrorBorder: OutlineInputBorder( + focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Match the error color + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Match the error color ), counterText: '', hintStyle: TextStyle(color: Color(0xFFC3C6CB)), @@ -603,15 +649,26 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 .enter_your_password : null, // _showHints[2] ? 'Enter your password' : null, + prefixIconConstraints: const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), prefixIcon: Padding( - padding: const EdgeInsets.only(bottom: 1.0,top:1.0,right:10.0,left:15.0 ), // Adjust the padding as needed + padding: const EdgeInsetsDirectional.only( + start: 16, + end: 10, + ), child: Image.asset( MiscIconAssetPath.lock, - color: Color(0xFF90B0D5), + fit: BoxFit.fitHeight, + height: 25, width: 25, - height: 15, + color: + MyTheme.topicColor(IndicatorTopic.economy) + .shade300, ), ), + // prefixIcon: Icon( // Icons.lock, // color: Color(0xFF90B0D5), @@ -626,15 +683,15 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 icon: Image.asset( _obscurePassword - ?MiscIconAssetPath.visibilityOff - :MiscIconAssetPath.visibleOn, + ? MiscIconAssetPath.visibilityOff + : MiscIconAssetPath.visibleOn, - color: Color(0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + color: Color( + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. width: 24, height: 24, ), - onPressed: () { setState(() { _obscurePassword = !_obscurePassword; @@ -644,20 +701,29 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 // border: OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), -borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, width: 1), - ), + ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Error border + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border ), - focusedErrorBorder: OutlineInputBorder( + focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Match the error color + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Match the error color ), counterText: '', @@ -678,23 +744,34 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 .register_Confirm_password : null, // _showHints[3] ? 'Confirm password' : null, + prefixIconConstraints: const BoxConstraints( + maxWidth: 25 + 16 + 10, + maxHeight: 25 + (8 * 2), + ), prefixIcon: Padding( - padding: const EdgeInsets.only(bottom: 1.0,top:1.0,right:10.0,left:15.0 ), // Adjust the padding as needed + padding: const EdgeInsetsDirectional.only( + start: 16, + end: 10, + ), child: Image.asset( MiscIconAssetPath.lock, - color: Color(0xFF90B0D5), + fit: BoxFit.fitHeight, + height: 25, width: 25, - height: 15, + color: + MyTheme.topicColor(IndicatorTopic.economy) + .shade300, ), ), - suffixIcon: IconButton( + suffixIcon: IconButton( icon: Image.asset( _obscureConfirmPassword - ?MiscIconAssetPath.visibilityOff - :MiscIconAssetPath.visibleOn, + ? MiscIconAssetPath.visibilityOff + : MiscIconAssetPath.visibleOn, - color: Color(0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. + color: Color( + 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. width: 24, height: 24, ), @@ -710,20 +787,29 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 // ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), -borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, + borderSide: BorderSide( + color: MyTheme.topicColor( + IndicatorTopic.economy) + .shade400, width: 1), - ), + ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border + borderSide: BorderSide( + color: Colors.deepPurple, + width: 2), // Focused border ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Error border + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Error border ), - focusedErrorBorder: OutlineInputBorder( + focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(10), - borderSide: BorderSide(color: Color(0xFFb22222), width: 1), // Match the error color + borderSide: BorderSide( + color: Color(0xFFb22222), + width: 1), // Match the error color ), counterText: '', hintStyle: TextStyle(color: Color(0xFFC3C6CB)), @@ -748,7 +834,9 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 }); }, side: BorderSide( - color: showError ? Color(0xFFD83731) : Color(0xFF92722A), + color: showError + ? Color(0xFFD83731) + : Color(0xFF92722A), width: 1, ), ), @@ -762,25 +850,31 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40 text: AppLocalizations.of(context)! .terms_conditions, // text: 'Terms & Conditions', -style: TextStyle(fontWeight: FontWeight.bold, - color: Color(0xFF648CBA), - // Makes the text bold - decoration: TextDecoration.underline, - decorationColor: Color(0xFF648CBA), - decorationThickness: 1), - ), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Color(0xFF648CBA), + // Makes the text bold + decoration: + TextDecoration.underline, + decorationColor: Color(0xFF648CBA), + decorationThickness: 1), + ), TextSpan( text: AppLocalizations.of(context)! .t_and), TextSpan( text: AppLocalizations.of(context)! .privacy_policy, - style: TextStyle(fontWeight: FontWeight.bold, - color: Color(0xFF648CBA), - decoration: TextDecoration.underline, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + fontFamily: 'Roboto', + color: Color(0xFF648CBA), + decoration: + TextDecoration.underline, decorationColor: Color(0xFF648CBA), decorationThickness: 1), - ), + ), TextSpan( text: AppLocalizations.of(context)! .conditions), @@ -831,7 +925,8 @@ style: TextStyle(fontWeight: FontWeight.bold, SizedBox(width: 8), const Icon( Icons.chevron_right_outlined, - color: Colors.white, // Set your desired color here + color: Colors + .white, // Set your desired color here ) ], ), @@ -841,7 +936,7 @@ style: TextStyle(fontWeight: FontWeight.bold, Text( AppLocalizations.of(context)!.account_confirmation, style: TextStyle( - fontSize: 16, color: Colors.grey[600]), + fontSize: 14, color: Colors.grey[600]), ), SizedBox(height: 15), SizedBox( @@ -868,7 +963,8 @@ style: TextStyle(fontWeight: FontWeight.bold, SizedBox(width: 8), const Icon( Icons.chevron_right_outlined, - color: Colors.white, // Set your desired color here + color: Colors + .white, // Set your desired color here ) ], ), diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index 3274d331..f9667d3b 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -10,6 +10,7 @@ import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; +import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart'; import '../components/my_bottom_nav_bar.dart'; @@ -74,7 +75,7 @@ class _ProfileScreenState extends State { // Regular expression to validate Full Name (no special characters) final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$"); late Future userDetails; - bool _isHoveringDate = false; + bool _isHoveringDate = false; bool _isHoveringDropdown = false; @override @@ -336,435 +337,450 @@ class _ProfileScreenState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios_new, color: Colors.black), - onPressed: () { - context.go('/'); - }, - ), - title: Text( - 'My Profile', - style: TextStyle(color: Colors.orange), - ), - actions: [ - TextButton( + return PopScope( + onPopInvokedWithResult: (didPop, result) { + if (didPop) return; + context.go('/'); + }, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios_new, color: Colors.black), onPressed: () { context.go('/'); }, - child: Text( - 'Logout', - style: TextStyle(color: Colors.orange), + ), + title: Text( + 'My Profile', + style: TextStyle(color: Color(0xFF985400)), + ), + actions: [ + TextButton( + onPressed: () { + context.go('/'); + }, + child: Text( + 'Logout', + style: TextStyle(color: Colors.orange), + ), ), - ), - IconButton( - icon: Icon(Icons.logout, color: Colors.black), - onPressed: () {}, - ), - ], - ), - body: SingleChildScrollView( - child: Form( - key: _formKey, - child: Padding( - padding: const EdgeInsets.only(top: 20.0,bottom: 20.0, left: 25,right: 25), - child: Column( - children: [ - // CircleAvatar( - // radius: 50, - // backgroundImage: _profileImage != null - // ? FileImage(_profileImage!) - // : AssetImage("assets/edit_profile/profile.png") - // as ImageProvider, - // child: Align( - // alignment: Alignment.bottomRight, - // child: GestureDetector( - // onTap: _pickImage, // Call `_pickImage` on tap - // child: CircleAvatar( - // radius: 15, - // backgroundColor: Colors.white, - // child: Icon( - // Icons.camera_alt, - // size: 15, - // color: Colors.grey, - // ), - // ), - // ), - // ), - // ), + IconButton( + icon: Icon(Icons.logout, color: Colors.black), + onPressed: () {}, + ), + ], + ), + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Padding( + padding: const EdgeInsets.only( + top: 20.0, bottom: 20.0, left: 25, right: 25), + child: Column( + children: [ + // CircleAvatar( + // radius: 50, + // backgroundImage: _profileImage != null + // ? FileImage(_profileImage!) + // : AssetImage("assets/edit_profile/profile.png") + // as ImageProvider, + // child: Align( + // alignment: Alignment.bottomRight, + // child: GestureDetector( + // onTap: _pickImage, // Call `_pickImage` on tap + // child: CircleAvatar( + // radius: 15, + // backgroundColor: Colors.white, + // child: Icon( + // Icons.camera_alt, + // size: 15, + // color: Colors.grey, + // ), + // ), + // ), + // ), + // ), - Stack( - alignment: Alignment.center, - children: [ - // CircleAvatar with the profile image - CircleAvatar( - radius: 50, - backgroundImage: _profileImage != null - ? FileImage(_profileImage!) - : AssetImage("assets/edit_profile/profile.png") - as ImageProvider, - child: Align( - alignment: Alignment.bottomRight, - child: GestureDetector( - onTap: _pickImage, // Call `_pickImage` on tap - child: CircleAvatar( - radius: 15, - backgroundColor: Colors.white, - child: Icon( - Icons.camera_alt, - size: 15, - color: Colors.grey, + Stack( + alignment: Alignment.center, + children: [ + // CircleAvatar with the profile image + CircleAvatar( + radius: 50, + backgroundImage: _profileImage != null + ? FileImage(_profileImage!) + : AssetImage("assets/edit_profile/profile.png") + as ImageProvider, + child: Align( + alignment: Alignment.bottomRight, + child: GestureDetector( + onTap: _pickImage, // Call `_pickImage` on tap + child: CircleAvatar( + radius: 15, + backgroundColor: Colors.white, + child: Icon( + Icons.camera_alt, + size: 15, + color: Colors.grey, + ), ), ), ), ), - ), - // Conditional loader that shows when _isLoading is true - if (_isLoading) - Positioned( - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: - AlwaysStoppedAnimation(Colors.grey), + // Conditional loader that shows when _isLoading is true + if (_isLoading) + Positioned( + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation(Colors.grey), + ), ), - ), - ], - ), - - SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "User Name", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.grey), - ), - ], - ), - SizedBox(height: 10), - TextFormField( - controller: _usernameController, - focusNode: _focusNodes[0], - decoration: InputDecoration( - // hintText: _showHints[0] ? 'Enter the User Name' : null, - hintStyle: TextStyle(color: Colors.grey), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - enabled: false, + ], ), - ), - SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Email ID", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.grey), - ), - ], - ), - SizedBox(height: 10), - TextFormField( - controller: _emailController, - focusNode: _focusNodes[1], - decoration: InputDecoration( - // hintText: - // _showHints[1] ? 'mohammad.hassan@fcsc.gov.ae' : null, - hintStyle: TextStyle(color: Colors.grey), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - enabled: false, - ), - ), - SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Full Name*", - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - ], - ), - SizedBox(height: 10), - TextFormField( - enabled: true, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Required'; - } - //RegExp(r"^[a-zA-Z\s]+$"); - final nameRegex = RegExp( - r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$"); - - if (!nameRegex.hasMatch(value)) { - return 'Invalid Characters'; - } - return null; - }, - controller: _fullNameController, - focusNode: _focusNodes[2], - decoration: InputDecoration( - hintText: _showHints[2] ? 'Enter the name' : null, - hintStyle: TextStyle(color: Colors.grey), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - counterText: '', - ), - maxLength: 40, // Set the maximum length to 20 characters - maxLengthEnforcement: MaxLengthEnforcement.enforced, - ), - SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Date of Birth*", - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - ], - ), - SizedBox(height: 10), - MouseRegion( - onEnter: (_) => setState(() => _isHoveringDate = true), - onExit: (_) => setState(() => _isHoveringDate = false), - child: TextFormField( - controller: _dateController, - focusNode: _focusNodes[3], - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - hintText: _showHints[3] ? 'DD/MM/YYYY' : null, - //_showHints[3] ? 'Select your Date of Birth' : null, - hintStyle: TextStyle(color: Colors.grey), - - suffixIcon: Container( - width: 45, - padding: EdgeInsets.only(right: 1), - alignment: Alignment.center, // Center the icon vertically - child: Icon( - Icons.keyboard_arrow_down_sharp, - color: _isHoveringDate ? Colors.black : Colors.grey, - - ), - ), - ), - readOnly: true, - onTap: _pickDate, - validator: _validateDob, - ),), - SizedBox(height: 10), - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - "Country/Region*", - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - ], - ), - SizedBox(height: 10), - MouseRegion( - onEnter: (_) => setState(() => _isHoveringDropdown = true), - onExit: (_) => setState(() => _isHoveringDropdown = false), - child: DropdownButtonFormField( - value: _selectedCountry, - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - labelText: 'Select', - ), - icon: Icon(Icons.keyboard_arrow_down_sharp, - color: _isHoveringDropdown ? Colors.black : Colors.grey ), - items: _countries - .map((item) => DropdownMenuItem( - value: item, - child: Text(item), - )) - .toList(), - onChanged: (String? newValue) { - setState(() { - _selectedCountry = newValue; - }); - }, - validator: _validateDropdown, - ),), - SizedBox(height: 20), - Row( - children: [ - Checkbox( - value: isChecked, - onChanged: (value) { - setState(() { - isChecked = value ?? false; - showError = false; - }); - }, - side: BorderSide( - color: showError ? Color(0xFFb22222) : Color(0xFF92722A), - width: 1, - ), - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 10, - ), - Text.rich( - TextSpan( - text: 'I agree to the ', - style: TextStyle(color: Colors.black), - children: [ - TextSpan( - text: 'Terms & Conditions', - style: TextStyle( - color: Color(0xFF648CBA), - decoration: TextDecoration.underline, - fontWeight: FontWeight.bold, // Makes the text bold - decorationColor: Color(0xFF648CBA), - decorationThickness: 1, - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - // Add action for Terms & Conditions tap - }, - ), - TextSpan( - text: ' and ', - style: TextStyle(color: Colors.black), - ), - TextSpan( - text: 'Privacy Policy', - style: TextStyle( - color: Color(0xFF648CBA), - decoration: TextDecoration.underline, - fontWeight: FontWeight.bold, // Makes the text bold - decorationColor: Color(0xFF648CBA), - decorationThickness: 1, - - ), - recognizer: TapGestureRecognizer() - ..onTap = () { - // Add action for Privacy Policy tap - }, - ), - TextSpan( - text: ' of FCSC.', - style: TextStyle(color: Colors.black), - ), - ], - ), - textAlign: TextAlign.start, - maxLines: 2, - overflow: TextOverflow.visible, - softWrap: true, - ), - ], - ), - ), - ], - ), - if (showError) + SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.only(left: 10.0), - child: Text( - 'Please agree to terms and conditions', - style: TextStyle( - color: Color(0xFFb22222), - fontSize: 12, + Text( + "User Name", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + controller: _usernameController, + focusNode: _focusNodes[0], + decoration: InputDecoration( + // hintText: _showHints[0] ? 'Enter the User Name' : null, + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + enabled: false, + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Email ID", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.grey), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + controller: _emailController, + focusNode: _focusNodes[1], + decoration: InputDecoration( + // hintText: + // _showHints[1] ? 'mohammad.hassan@fcsc.gov.ae' : null, + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + enabled: false, + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Full Name*", + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + enabled: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Required'; + } + + //RegExp(r"^[a-zA-Z\s]+$"); + final nameRegex = RegExp( + r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$"); + + if (!nameRegex.hasMatch(value)) { + return 'Invalid Characters'; + } + return null; + }, + controller: _fullNameController, + focusNode: _focusNodes[2], + decoration: InputDecoration( + hintText: _showHints[2] ? 'Enter the name' : null, + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + counterText: '', + ), + maxLength: 40, // Set the maximum length to 20 characters + maxLengthEnforcement: MaxLengthEnforcement.enforced, + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Date of Birth*", + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + MouseRegion( + onEnter: (_) => setState(() => _isHoveringDate = true), + onExit: (_) => setState(() => _isHoveringDate = false), + child: TextFormField( + controller: _dateController, + focusNode: _focusNodes[3], + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + hintText: _showHints[3] ? 'DD/MM/YYYY' : null, + //_showHints[3] ? 'Select your Date of Birth' : null, + hintStyle: TextStyle(color: Colors.grey), + + suffixIcon: Container( + width: 45, + padding: EdgeInsets.only(right: 1), + alignment: + Alignment.center, // Center the icon vertically + child: Icon( + Icons.keyboard_arrow_down_sharp, + color: _isHoveringDate ? Colors.black : Colors.grey, ), ), ), + readOnly: true, + onTap: _pickDate, + validator: _validateDob, + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Country/Region*", + style: TextStyle( + fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + MouseRegion( + onEnter: (_) => setState(() => _isHoveringDropdown = true), + onExit: (_) => setState(() => _isHoveringDropdown = false), + child: DropdownButtonFormField( + value: _selectedCountry, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + labelText: 'Select', + ), + icon: Icon(Icons.keyboard_arrow_down_sharp, + color: + _isHoveringDropdown ? Colors.black : Colors.grey), + items: _countries + .map((item) => DropdownMenuItem( + value: item, + child: Text(item), + )) + .toList(), + onChanged: (String? newValue) { + setState(() { + _selectedCountry = newValue; + }); + }, + validator: _validateDropdown, + ), + ), + SizedBox(height: 20), + Row( + children: [ + Checkbox( + value: isChecked, + onChanged: (value) { + setState(() { + isChecked = value ?? false; + showError = false; + }); + }, + side: BorderSide( + color: + showError ? Color(0xFFb22222) : Color(0xFF92722A), + width: 1, + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 10, + ), + Text.rich( + TextSpan( + text: 'I agree to the ', + style: TextStyle(color: Colors.black), + children: [ + TextSpan( + text: 'Terms & Conditions', + style: TextStyle( + color: Color(0xFF648CBA), + decoration: TextDecoration.underline, + fontWeight: FontWeight + .bold, // Makes the text bold + decorationColor: Color(0xFF648CBA), + decorationThickness: 1, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + // Add action for Terms & Conditions tap + }, + ), + TextSpan( + text: ' and ', + style: TextStyle(color: Colors.black), + ), + TextSpan( + text: 'Privacy Policy', + style: TextStyle( + color: Color(0xFF648CBA), + decoration: TextDecoration.underline, + fontWeight: FontWeight + .bold, // Makes the text bold + decorationColor: Color(0xFF648CBA), + decorationThickness: 1, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + // Add action for Privacy Policy tap + }, + ), + TextSpan( + text: ' of FCSC.', + style: TextStyle(color: Colors.black), + ), + ], + ), + textAlign: TextAlign.start, + maxLines: 2, + overflow: TextOverflow.visible, + softWrap: true, + ), + ], + ), + ), ], ), - SizedBox(height: 20), - Center( - child: GestureDetector( - onTap: () { - final userId = widget.userId; - final email = _emailController.text; + if (showError) + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 10.0), + child: Text( + 'Please agree to terms and conditions', + style: TextStyle( + color: Color(0xFFb22222), + fontSize: 12, + ), + ), + ), + ], + ), + SizedBox(height: 20), + Center( + child: GestureDetector( + onTap: () { + final userId = widget.userId; + final email = _emailController.text; - context.go('/createNewPw/$userId/$email'); - }, - child: Text( - 'Change Password', - style: TextStyle( - color: Color(0xFF648CBA), + context.go('/createNewPw/$userId/$email'); + }, + child: Text( + 'Change Password', + style: TextStyle( + color: Color(0xFF648CBA), fontSize: 14, - fontWeight: FontWeight.w700, - fontFamily: 'Roboto', - // decoration: TextDecoration.underline), + fontWeight: FontWeight.w700, + fontFamily: 'Roboto', + // decoration: TextDecoration.underline), + ), ), ), ), - ), - SizedBox(height: 20), - // ElevatedButton.icon( + SizedBox(height: 20), + // ElevatedButton.icon( ElevatedButton( - onPressed: () { - if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { - _formKey.currentState?.save(); - showConfirmationDialog(context); - } else { - setState(() { - showError = !isChecked; // Show error if the checkbox is not checked - }); - } - }, - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF92722A), - minimumSize: Size(double.infinity, 50), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + onPressed: () { + if ((_formKey.currentState?.validate() ?? false) && + (isChecked)) { + _formKey.currentState?.save(); + showConfirmationDialog(context); + } else { + setState(() { + showError = + !isChecked; // Show error if the checkbox is not checked + }); + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF92722A), + minimumSize: Size(double.infinity, 50), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), ), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, // Center the content - children: [ - Text( - 'Save', - style: TextStyle(color: Colors.white), - ), - SizedBox(width: 8), // Add space between text and icon - Icon( - Icons.save_outlined, - color: Colors.white, - ), - ], - ), - ) - - ], + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, // Center the content + children: [ + Text( + 'Save', + style: TextStyle(color: Colors.white), + ), + SizedBox(width: 8), // Add space between text and icon + Image.asset( + MiscIconAssetPath.save, + color: Colors.white, + width: 20, + height: 20, + ), + ], + ), + ) + ], + ), ), ), ), ), - //bottomNavigationBar: MyBottomNavBar(), ); } } diff --git a/lib/presentation/routes/auth_routes/login_route.dart b/lib/presentation/routes/auth_routes/login_route.dart index d68fc20d..e4f1ee20 100644 --- a/lib/presentation/routes/auth_routes/login_route.dart +++ b/lib/presentation/routes/auth_routes/login_route.dart @@ -17,6 +17,7 @@ import 'package:uae_stat/presentation/components/lang_toggle.dart'; import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; import 'package:uae_stat/presentation/components/space.dart'; import 'package:uae_stat/presentation/components/themed_text_field.dart'; +import 'package:uae_stat/presentation/routes/auth_routes/pocketbase_service.dart'; import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart'; import 'package:http/http.dart' as http; import '../../Screens/auth_verification/registration.dart'; @@ -27,10 +28,11 @@ import '../../components/my_toggle.dart'; class LoginRoute extends HookConsumerWidget { final pb = PocketBase('https://pb.venbait.in'); + final _pbService = PocketBaseService(); // final _pb = PocketBase('http://127.0.0.1:8090'); - final bool isLoginScreen; // Pass `true` if this is the login screen - LoginRoute({Key? key, required this.isLoginScreen}) : super(key: key); - // LoginRoute({super.key}); + // final bool isLoginScreen; // Pass `true` if this is the login screen + // LoginRoute({Key? key, required this.isLoginScreen}) : super(key: key); + LoginRoute({super.key}); dynamic userData; String? role; @@ -96,52 +98,91 @@ class LoginRoute extends HookConsumerWidget { final forgotPwFormKey = GlobalKey(); final email = await showDialog( context: context, - builder: (dialogCtx) => AlertDialog( - title: Text( - context.translate( - 'Reset Password', - 'إعادة تعيين كلمة المرور', + builder: (dialogCtx) => SizedBox( + // width: 850, // Increase dialog width + child: AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), // Rounded corners ), + elevation: 10, + shadowColor: Colors.black12, + title: Text( + context.translate( + 'Reset Password', + 'إعادة تعيين كلمة المرور', + ), + style: TextStyle( + fontSize: 20, + color: Color(0xFF898C81), + fontWeight: FontWeight.w600), + ), + content: Form( + key: forgotPwFormKey, + child: TextFormField( + validator: FieldValidator.email(), + controller: emailCtl, + decoration: InputDecoration( + labelText: context.translate( + 'Email address', + 'عنوان البريد الإلكتروني', + ), + labelStyle: TextStyle( + fontSize: 16, + color: Color(0xFF898C81), // For label text color + // fontWeight: FontWeight.w600, + ), + ), + ), + ), + actions: [ + TextButton( + onPressed: Navigator.of(dialogCtx, rootNavigator: true).pop, + style: TextButton.styleFrom( + // backgroundColor: Colors.white, // Background color + foregroundColor: Color(0xFF92722A), // Font (text) color + side: BorderSide( + color: Color(0xFF92722A)), // Border outline color + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(8), // Optional: Rounded corners + ), + padding: EdgeInsets.symmetric( + horizontal: 16, vertical: 12), // Optional: Padding + ), + child: Text( + context.translate( + 'Return', + 'يعود', + ), + ), + ), + ElevatedButton( + onPressed: () { + final isValid = forgotPwFormKey.currentState!.validate(); + if (!isValid) return; + Navigator.of(dialogCtx, rootNavigator: true).pop( + emailCtl.text, + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF92722A), + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 15, vertical: 15), // Optional: Adjusts size + shape: RoundedRectangleBorder( + // Optional: Adds rounded corners + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + context.translate( + 'Send Reset Email', + 'إرسال إعادة تعيين البريد الإلكتروني', + ), + ), + ), + ], ), - content: Form( - key: forgotPwFormKey, - child: TextFormField( - validator: FieldValidator.email(), - controller: emailCtl, - decoration: InputDecoration( - labelText: context.translate( - 'Email address', - 'عنوان البريد الإلكتروني', - ), - ), - ), - ), - actions: [ - TextButton( - onPressed: Navigator.of(dialogCtx, rootNavigator: true).pop, - child: Text( - context.translate( - 'Return', - 'يعود', - ), - ), - ), - ElevatedButton( - onPressed: () { - final isValid = forgotPwFormKey.currentState!.validate(); - if (!isValid) return; - Navigator.of(dialogCtx, rootNavigator: true).pop( - emailCtl.text, - ); - }, - child: Text( - context.translate( - 'Send Reset Email', - 'إرسال إعادة تعيين البريد الإلكتروني', - ), - ), - ), - ], ), ); if (email == null) return; @@ -177,7 +218,7 @@ class LoginRoute extends HookConsumerWidget { ), fontWeight: FontWeight.bold, fontSize: 14, - color: Color(0xFF985400), + color: Color(0xFF985400), ), ), ); @@ -361,7 +402,7 @@ class LoginRoute extends HookConsumerWidget { 6.horizontalSpace, const Icon( Icons.chevron_right_outlined, - color: Colors.white, // Set your desired color here + color: Colors.white, // Set your desired color here ) ], ), @@ -390,8 +431,7 @@ class LoginRoute extends HookConsumerWidget { validator: (text) { if (text == null || text.isEmpty) { return context.translate('Required', 'مطلوب'); - } - else if (text.length < 8) { + } else if (text.length < 8) { return 'The password must be at least 8 characters'; } return FieldValidator.password(minLength: 8)(text); @@ -403,12 +443,14 @@ class LoginRoute extends HookConsumerWidget { imgPath: MiscIconAssetPath.lock, controller: pwCtl, isObscurable: true, - ), // 6.verticalSpace, - Align( - alignment: AlignmentDirectional.topEnd, - child: forgotPwBtn, + Padding( + padding: EdgeInsets.zero, + child: Align( + alignment: AlignmentDirectional.topEnd, + child: forgotPwBtn, + ), ), 10.verticalSpace, loginBtn, @@ -460,7 +502,7 @@ class LoginRoute extends HookConsumerWidget { 'Roboto', 'NotoKufi', ), - fontSize: 18, + fontSize: 14, fontWeight: FontWeight.bold, ), children: [ @@ -482,8 +524,8 @@ class LoginRoute extends HookConsumerWidget { 'سجل الان', ), style: TextStyle( - color: Color(0xFF985400), - ), + color: Color(0xFF985400), + ), ), ], ), @@ -574,7 +616,7 @@ class LoginRoute extends HookConsumerWidget { helloAndPleaseLoginTexts, 42.verticalSpace, form, - 20.verticalSpace, + 15.verticalSpace, dontHaveAnAccountRegisterBtn, 20.verticalSpace, // continueAsGuestBtn, @@ -588,7 +630,7 @@ class LoginRoute extends HookConsumerWidget { // ); // return bgScaffold; return PopScope( - canPop: !isLoginScreen, // Allow back navigation only if not login screen + canPop: false, // Allow back navigation only if not login screen onPopInvokedWithResult: (didPop, result) { if (didPop) return; _showExitConfirmation(context); // Show exit confirmation dialog diff --git a/lib/presentation/routes/auth_routes/pocketbase_service.dart b/lib/presentation/routes/auth_routes/pocketbase_service.dart new file mode 100644 index 00000000..8e5cc2c8 --- /dev/null +++ b/lib/presentation/routes/auth_routes/pocketbase_service.dart @@ -0,0 +1,66 @@ +import 'package:pocketbase/pocketbase.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class PocketBaseService { + final PocketBase pb = PocketBase('https://pb.venbait.in'); + + // Save session to local storage + Future saveSession() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('pb_auth', pb.authStore.token); + await prefs.setString('pb_user', pb.authStore.model.toJson()); + await prefs.setInt('pb_auth_time', DateTime.now().millisecondsSinceEpoch); + } + + // Load session from local storage + Future loadSession() async { + final prefs = await SharedPreferences.getInstance(); + final token = prefs.getString('pb_auth'); + final userJson = prefs.getString('pb_user'); + + if (token != null && userJson != null) { + pb.authStore + .save(token, RecordModel.fromJson(userJson as Map)); + + if (!pb.authStore.isValid || isSessionExpired(prefs)) { + await clearSession(); + return false; + } + return true; + } + return false; + } + + // Check if the session is expired (4 days) + bool isSessionExpired(SharedPreferences prefs) { + final savedTime = prefs.getInt('pb_auth_time') ?? 0; + final currentTime = DateTime.now().millisecondsSinceEpoch; + const sessionDuration = Duration(days: 4); + return (currentTime - savedTime) > sessionDuration.inMilliseconds; + } + + // User login + Future loginUser(String email, String password) async { + try { + await pb.collection('users').authWithPassword(email, password); + await saveSession(); + return true; + } catch (e) { + return false; + } + } + + // User logout + Future logoutUser() async { + pb.authStore.clear(); + await clearSession(); + } + + // Clear session from local storage + Future clearSession() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('pb_auth'); + await prefs.remove('pb_user'); + await prefs.remove('pb_auth_time'); + } +} diff --git a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart index d8674d83..e4d22b45 100644 --- a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart +++ b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart @@ -207,7 +207,7 @@ class EconomyStatsWidget extends ConsumerStatefulWidget { class EconomyStatsState extends ConsumerState { List data = []; -final _pb = PocketBase('https://pb.venbait.in'); + final _pb = PocketBase('https://pb.venbait.in'); bool isLoading = true; final GlobalKey cardTopicKey = GlobalKey(); @@ -216,14 +216,13 @@ final _pb = PocketBase('https://pb.venbait.in'); late List homeTargets; late List previousHomeTargets; - void handleSkip() { tutorialCoachMark.skip(); debugPrint('Skip clicked'); - ref.read(chartsTourProvider.notifier).state = true; - ref.read(previousChartsTourProvider.notifier).state = true; - ref.read(homeTourProvider.notifier).state = true; - ref.read( previousHomeTourProvider.notifier).state = true; + ref.read(chartsTourProvider.notifier).state = true; + ref.read(previousChartsTourProvider.notifier).state = true; + ref.read(homeTourProvider.notifier).state = true; + ref.read(previousHomeTourProvider.notifier).state = true; ref.read(scaffoldTourProvider.notifier).state = true; ref.read(previousScaffoldTourProvider.notifier).state = true; } @@ -257,7 +256,8 @@ final _pb = PocketBase('https://pb.venbait.in'); ref.read(homeTourProvider.notifier).state = true; ref.read(chartsTourProvider.notifier).state = false; debugPrint('Home Tutorial Finished'); - context.go('/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); }, )..show(context: context); } else if (!previousHomeTour) { @@ -271,16 +271,16 @@ final _pb = PocketBase('https://pb.venbait.in'); onFinish: () { ref.read(previousHomeTourProvider.notifier).state = true; debugPrint('Previous Home Tutorial Finished'); - context.go('/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); }, )..show(context: context); } - } - void _initTarget(){ + void _initTarget() { final double screenWidth = MediaQuery.of(context).size.width; - homeTargets=[ + homeTargets = [ TargetFocus( identify: 'cardTopicKey', keyTarget: cardTopicKey, @@ -298,7 +298,7 @@ final _pb = PocketBase('https://pb.venbait.in'); align: ContentAlign.bottom, child: SizedBox( width: double.infinity, - height: MediaQuery.of(context).size.height*0.70, + height: MediaQuery.of(context).size.height * 0.70, child: Stack( children: [ Positioned( @@ -310,7 +310,8 @@ final _pb = PocketBase('https://pb.venbait.in'); Align( alignment: Alignment.bottomRight, child: Padding( - padding: const EdgeInsets.only(right: 10), // Adjust the value as needed + padding: const EdgeInsets.only( + right: 10), // Adjust the value as needed child: Text( '1/7', style: const TextStyle( @@ -320,7 +321,9 @@ final _pb = PocketBase('https://pb.venbait.in'); ), ), ), - SizedBox(height: 5,), + SizedBox( + height: 5, + ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -350,12 +353,14 @@ final _pb = PocketBase('https://pb.venbait.in'); decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFF7DAFBC), - border: Border.all(color: Color(0xFF7DAFBC), width: 1), + border: Border.all( + color: Color(0xFF7DAFBC), width: 1), ), child: IconButton( padding: EdgeInsets.zero, iconSize: 20, - icon: const Icon(Icons.arrow_forward, color: Colors.white), + icon: const Icon(Icons.arrow_forward, + color: Colors.white), onPressed: () { tutorialCoachMark.next(); }, @@ -366,8 +371,7 @@ final _pb = PocketBase('https://pb.venbait.in'); ], ), ], - ) - ), + )), ], ), ), @@ -399,16 +403,17 @@ final _pb = PocketBase('https://pb.venbait.in'); // targetPosition:TargetPosition(), contents: [ createTargetContent( - text:AppLocalizations.of(context)!.economy, + text: AppLocalizations.of(context)!.economy, alignment: ContentAlign.bottom, gap: 0, - space: 43,), + space: 43, + ), TargetContent( align: ContentAlign.bottom, - child: - SizedBox( + child: SizedBox( width: double.infinity, - height: MediaQuery.of(context).size.height *0.5, // Set an appropriate height for the Stack + height: MediaQuery.of(context).size.height * + 0.5, // Set an appropriate height for the Stack child: Stack( children: [ Positioned( @@ -419,23 +424,22 @@ final _pb = PocketBase('https://pb.venbait.in'); children: [ Align( alignment: Alignment.bottomRight, - child:Padding(padding: EdgeInsets.only(right: 10), - child: - Text( + child: Padding( + padding: EdgeInsets.only(right: 10), + child: Text( '2/7', style: const TextStyle( color: Colors.white, fontSize: 14, ), ), - ) - ), + )), const SizedBox(height: 3), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - onPressed: () =>handleSkip(), + onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), @@ -457,11 +461,13 @@ final _pb = PocketBase('https://pb.venbait.in'); Container( decoration: BoxDecoration( shape: BoxShape.circle, - border: Border.all(color: Colors.white, width: 2.0), + border: Border.all( + color: Colors.white, width: 2.0), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_back, color: Colors.white), + icon: const Icon(Icons.arrow_back, + color: Colors.white), onPressed: () { tutorialCoachMark.previous(); }, @@ -472,11 +478,13 @@ final _pb = PocketBase('https://pb.venbait.in'); decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFF7DAFBC), - border: Border.all(color: Color(0xFF7DAFBC), width: 1), + border: Border.all( + color: Color(0xFF7DAFBC), width: 1), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, color: Colors.white), + icon: const Icon(Icons.arrow_forward, + color: Colors.white), onPressed: () { tutorialCoachMark.next(); }, @@ -535,9 +543,9 @@ final _pb = PocketBase('https://pb.venbait.in'); ]; } - void _initPreviousTarget(){ + void _initPreviousTarget() { final double screenWidth = MediaQuery.of(context).size.width; - previousHomeTargets=[ + previousHomeTargets = [ TargetFocus( identify: 'cardsKey', keyTarget: cardsKey, @@ -546,16 +554,17 @@ final _pb = PocketBase('https://pb.venbait.in'); paddingFocus: 6, contents: [ createTargetContent( - text:AppLocalizations.of(context)!.economy, + text: AppLocalizations.of(context)!.economy, alignment: ContentAlign.bottom, gap: 0, - space: 43,), + space: 43, + ), TargetContent( align: ContentAlign.bottom, - child: - SizedBox( + child: SizedBox( width: double.infinity, - height: MediaQuery.of(context).size.height *0.5, // Set an appropriate height for the Stack + height: MediaQuery.of(context).size.height * + 0.5, // Set an appropriate height for the Stack child: Stack( children: [ Positioned( @@ -566,23 +575,24 @@ final _pb = PocketBase('https://pb.venbait.in'); children: [ Align( alignment: Alignment.bottomRight, - child:Padding(padding: EdgeInsets.only(right: 10), - child: - Text( + child: Padding( + padding: EdgeInsets.only(right: 10), + child: Text( '2/7', style: const TextStyle( color: Colors.white, fontSize: 14, ), ), - ) + )), + SizedBox( + height: 5, ), - SizedBox(height: 5,), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( - onPressed: () =>handleSkip(), + onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), @@ -600,17 +610,18 @@ final _pb = PocketBase('https://pb.venbait.in'); ), ), Row( - children: [ Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, - border: Border.all(color: Colors.white, width: 2.0), + border: Border.all( + color: Colors.white, width: 2.0), ), child: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), + icon: const Icon(Icons.arrow_back, + color: Colors.white), onPressed: () { tutorialCoachMark.next(); }, @@ -621,15 +632,24 @@ final _pb = PocketBase('https://pb.venbait.in'); decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFF7DAFBC), - border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + border: Border.all( + color: Color(0xFF7DAFBC), + width: 1.5), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, color: Colors.white), + icon: const Icon(Icons.arrow_forward, + color: Colors.white), onPressed: () { - ref.read(previousHomeTourProvider.notifier).state=true; - ref.read(chartsTourProvider.notifier).state=false; - context.go('/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); + ref + .read(previousHomeTourProvider + .notifier) + .state = true; + ref + .read(chartsTourProvider.notifier) + .state = false; + context.go( + '/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); tutorialCoachMark.finish(); }, ), @@ -673,7 +693,7 @@ final _pb = PocketBase('https://pb.venbait.in'); paddingFocus: 16, contents: [ createTargetContent( - text:AppLocalizations.of(context)!.home_topic, + text: AppLocalizations.of(context)!.home_topic, alignment: ContentAlign.bottom, gap: 0, space: 43, @@ -682,7 +702,7 @@ final _pb = PocketBase('https://pb.venbait.in'); align: ContentAlign.bottom, child: SizedBox( width: double.infinity, - height: MediaQuery.of(context).size.height*0.69, + height: MediaQuery.of(context).size.height * 0.69, child: Stack( children: [ Positioned( @@ -694,7 +714,7 @@ final _pb = PocketBase('https://pb.venbait.in'); Align( alignment: Alignment.bottomRight, child: Padding( - padding:EdgeInsets.only(right: 10), + padding: EdgeInsets.only(right: 10), child: Text( '1/7', style: const TextStyle( @@ -735,11 +755,13 @@ final _pb = PocketBase('https://pb.venbait.in'); decoration: BoxDecoration( shape: BoxShape.circle, color: Color(0xFF7DAFBC), - border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + border: Border.all( + color: Color(0xFF7DAFBC), width: 1.5), ), child: IconButton( iconSize: 20, - icon: const Icon(Icons.arrow_forward, color: Colors.white), + icon: const Icon(Icons.arrow_forward, + color: Colors.white), onPressed: () { tutorialCoachMark.previous(); }, @@ -777,15 +799,13 @@ final _pb = PocketBase('https://pb.venbait.in'); ]; } - -@override - void initState() { -super.initState(); -final locale = ref.read(localeProvider); -fetchData(locale?.languageCode ?? 'en'); -_fetchUserData(); - } - + @override + void initState() { + super.initState(); + final locale = ref.read(localeProvider); + fetchData(locale?.languageCode ?? 'en'); + _fetchUserData(); + } // @override // void didChangeDependencies() { @@ -795,43 +815,38 @@ _fetchUserData(); // fetchData(locale); // Pass the locale to the fetchData method // } + Future getUserId() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString('userId'); // Retrieve the userId + } -Future getUserId() async { -final prefs = await SharedPreferences.getInstance(); -return prefs.getString('userId'); // Retrieve the userId - } - - -Future _fetchUserData() async { -try { -final userId = await getUserId(); -print('EDIT PROFILE isPageLoad'); -final adminAuth = await _pb.admins - .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); -final adminToken = adminAuth.token; -print('adminToken- $adminToken'); -final userDetailsResponse = await _pb.collection('users').getOne( -userId!, -headers: { -'Authorization': 'Bearer $adminToken', - }, - ); -final loginCount = userDetailsResponse.data['login_count']; -print(loginCount); -if (loginCount == 1) { -WidgetsBinding.instance.addPostFrameCallback((_) { -_starTourRender(); - }); - } - } catch (e) { -print('Error fetching user details: $e'); - } - } - - - - - + Future _fetchUserData() async { + try { + final userId = await getUserId(); + print('EDIT PROFILE isPageLoad'); + final adminAuth = await _pb.admins + .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); + final adminToken = adminAuth.token; + print('adminToken- $adminToken'); + final userDetailsResponse = await _pb.collection('users').getOne( + userId!, + headers: { + 'Authorization': 'Bearer $adminToken', + }, + ); + final loginCount = userDetailsResponse.data['login_count']; + print(loginCount); + if (loginCount == 1) { + setState(() { + WidgetsBinding.instance.addPostFrameCallback((_) { + _starTourRender(); + }); + }); + } + } catch (e) { + print('Error fetching user details: $e'); + } + } Future fetchData(locale) async { const baseUrl = 'https://pb.venbait.in/api/getHomePageData'; @@ -940,7 +955,7 @@ print('Error fetching user details: $e'); crossAxisAlignment: CrossAxisAlignment.start, children: [ RoundedCornerContainer( - key: mainTopic['main_topic'] =='ECONOMY' + key: mainTopic['main_topic'] == 'ECONOMY' ? cardTopicKey : null, text: mainTopic['main_topic'], @@ -954,7 +969,7 @@ print('Error fetching user details: $e'); SizedBox( height: myheight / 4.8, // Set dynamic height child: Container( - key:mainTopic['main_topic'] == 'ECONOMY' + key: mainTopic['main_topic'] == 'ECONOMY' ? cardsKey : null, // color: Colors.grey[200], // Set a background color for the scrollable container @@ -1176,7 +1191,6 @@ class InfoCard extends StatelessWidget { final encodedTitle = Uri.encodeComponent(title); final encodedKey = Uri.encodeQueryComponent('home'); - return GestureDetector( onTap: () { context.go( @@ -1263,4 +1277,4 @@ class InfoCard extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart index e8a36040..55d92b96 100644 --- a/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart +++ b/lib/presentation/routes/drawer_routes/Drawer Items/edit_profile.dart @@ -11,6 +11,7 @@ import 'package:intl/intl.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; class EditProfile extends StatefulWidget { @@ -424,11 +425,11 @@ class _EditProfileState extends State { @override Widget build(BuildContext context) { return BaseScaffold( - title: Text(AppLocalizations.of(context)!.my_profile), + title: Text(AppLocalizations.of(context)!.my_profile, + style: TextStyle(color: Color(0xFF985400)),), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0), - child: Column( children: [ SingleChildScrollView( @@ -436,8 +437,9 @@ class _EditProfileState extends State { key: _formKey, child: Padding( // padding: const EdgeInsets.all(20.0), - padding: const EdgeInsets.only(top: 20.0,bottom: 20.0, left: 25,right: 25), - child: isPageLoad +padding: const EdgeInsets.only( + top: 20.0, bottom: 20.0, left: 25, right: 25), + child: isPageLoad ? Center( child: CircularProgressIndicator(), ) @@ -727,11 +729,11 @@ class _EditProfileState extends State { suffixIcon: Container( width: 45, padding: EdgeInsets.only(right: 1), - alignment: Alignment.center, // Center the icon vertically + alignment: Alignment + .center, // Center the icon vertically child: Icon( Icons.keyboard_arrow_down_sharp, color: Colors.grey, - ), ), enabled: !_isProfileCompleted, @@ -755,8 +757,10 @@ class _EditProfileState extends State { ), SizedBox(height: 10), MouseRegion( - onEnter: (_) => setState(() => _isHoveringDropdown = true), - onExit: (_) => setState(() => _isHoveringDropdown = false), + onEnter: (_) => + setState(() => _isHoveringDropdown = true), + onExit: (_) => + setState(() => _isHoveringDropdown = false), child: DropdownButtonFormField( value: _selectedCountry, decoration: InputDecoration( @@ -766,7 +770,9 @@ class _EditProfileState extends State { labelText: 'Select', ), icon: Icon(Icons.keyboard_arrow_down_sharp, - color: _isHoveringDropdown ? Colors.black : Colors.grey ), + color: _isHoveringDropdown + ? Colors.black + : Colors.grey), items: _countries .map( (item) => DropdownMenuItem( @@ -781,7 +787,8 @@ class _EditProfileState extends State { }); }, validator: _validateDropdown, - ),), + ), + ), SizedBox(height: 20), if (!_isProfileCompleted) // Conditional rendering Column( @@ -827,7 +834,8 @@ class _EditProfileState extends State { .terms_conditions, style: TextStyle( // color: Colors.blue, - color: Color(0xFF648CBA), + color: + Color(0xFF648CBA), decoration: TextDecoration .underline, @@ -854,7 +862,7 @@ class _EditProfileState extends State { .privacy_policy, style: TextStyle( // color: Colors.blue, - color: Color(0xFF648CBA), + color: Color(0xFF648CBA), decoration: TextDecoration .underline, @@ -911,7 +919,8 @@ class _EditProfileState extends State { child: GestureDetector( onTap: () { final email = _emailController.text; - context.go('/createNewPw/$userId/$email?key=editProfile'); + context.go( + '/createNewPw/$userId/$email?key=editProfile'); }, child: Text( AppLocalizations.of(context)! @@ -949,14 +958,14 @@ class _EditProfileState extends State { // ), ElevatedButton( onPressed: () { - if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { - _formKey.currentState?.save(); + // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { + // _formKey.currentState?.save(); showConfirmationDialog(context); - } else { - setState(() { - showError = !isChecked; // Show error if the checkbox is not checked - }); - } + // } else { + // setState(() { + // showError = !isChecked; // Show error if the checkbox is not checked + // }); + // } }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF92722A), @@ -969,13 +978,15 @@ class _EditProfileState extends State { mainAxisAlignment: MainAxisAlignment.center, // Center the content children: [ Text( - 'Save', + AppLocalizations.of(context)!.save, style: TextStyle(color: Colors.white), ), SizedBox(width: 8), // Add space between text and icon - Icon( - Icons.save_outlined, + Image.asset( + MiscIconAssetPath.save, color: Colors.white, + width: 20, + height: 20, ), ], ), diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 9fb351b9..5067f8da 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -11,6 +11,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/bottom_bar_asset_icon_path.dart'; +import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/drawer_asset_icon_path.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart'; @@ -734,15 +735,25 @@ class _BaseScaffoldState extends ConsumerState { ), if (userId != 'guest') ListTile( - leading: Icon(Icons.feedback), + leading: Image.asset( + DrawerAssetIconPath.feedback, + color: Colors.black , + width: 20, + height: 20, + ), // title: const Text('Feedback'), title: Text(AppLocalizations.of(context)!.feedback_title), onTap: () => context.go('/feedback'), ), if (role == 'admin') ListTile( - leading: Icon(Icons.manage_accounts), - // title: Text('Manage User'), +leading: Image.asset( + DrawerAssetIconPath.manageUser, + color: Colors.black , + width: 20, + height: 20, + ), + // title: Text('Manage User'), title: Text( AppLocalizations.of(context)!.manage_user, ), @@ -754,7 +765,12 @@ class _BaseScaffoldState extends ConsumerState { onTap: () => context.go('/bookmark'), ), ListTile( - leading: Icon(Icons.book), + leading: Image.asset( + DrawerAssetIconPath.guide, + color: Colors.black , + width: 20, + height: 20, + ), // title: const Text('User Guide'), title: Text(AppLocalizations.of(context)!.guide_title), onTap: () => context.go('/user-guide'), diff --git a/pubspec.yaml b/pubspec.yaml index 907eb18d..0b9e373d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: uae_stat description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." publish_to: "none" #version: 0.5.10 -version: 1.0.6+7 +version: 1.0.8+9 environment: sdk: ">=3.2.3 <4.0.0" @@ -120,6 +120,10 @@ flutter: - assets/icons/misc/vector.png - assets/icons/misc/visible_on.png - assets/icons/misc/visibility_off.png + - assets/icons/misc/save.png + - assets/icons/drawer/guide.png + - assets/icons/drawer/feedback.png + - assets/icons/drawer/manageusr.png fonts: - family: Segoe