login and register UI changes added

This commit is contained in:
venbaittech 2025-02-06 12:32:46 +05:30
parent b13aa81ad9
commit 5b922b4355
17 changed files with 945 additions and 661 deletions

View File

@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode") def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = "7" flutterVersionCode = "9"
} }
def flutterVersionName = localProperties.getProperty("flutter.versionName") def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) { if (flutterVersionName == null) {
flutterVersionName = "1.0.6" flutterVersionName = "1.0.8"
} }
def keystorePropertiesFile = rootProject.file("key.properties") def keystorePropertiesFile = rootProject.file("key.properties")

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

BIN
assets/icons/misc/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 B

View File

@ -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/charts/screens/chart_screen.dart';
import 'package:uae_stat/presentation/Screens/demo_home2.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/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/Drawer%20Items/user_guide/getting_started.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.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/user_guide/user_guide.dart';
import '../presentation/routes/drawer_routes/Drawer Items/manage_users.dart'; import '../presentation/routes/drawer_routes/Drawer Items/manage_users.dart';
final pbService = PocketBaseService();
Future<String> getInitialRoute() async {
bool isLoggedIn = await pbService.loadSession();
return isLoggedIn ? '/myhomepage' : '/login';
}
final GoRouter router = GoRouter( final GoRouter router = GoRouter(
routes: [ routes: [
GoRoute( GoRoute(
path: '/', path: '/',
//builder: (context, state) => LoginRoute(), //builder: (context, state) => LoginRoute(),
builder: (context, state) => LoginRoute(isLoginScreen: true), builder: (context, state) => LoginRoute(),
), ),
// GoRoute(
// path: '/',
// redirect: (context, state) async {
// return await getInitialRoute();
// },
// ),
GoRoute( GoRoute(
path: '/internetcheck', path: '/internetcheck',
builder: (context, state) => InternetCheck(), builder: (context, state) => InternetCheck(),
), ),
GoRoute( GoRoute(
path: '/login', path: '/login',
builder: (context, state) => LoginRoute(isLoginScreen: true), builder: (context, state) => LoginRoute(),
//builder: (context, state) => LoginRoute(), //builder: (context, state) => LoginRoute(),
), ),
GoRoute( GoRoute(

View File

@ -8,4 +8,7 @@ abstract class DrawerAssetIconPath {
static const message = '$_basePath/message.png'; static const message = '$_basePath/message.png';
static const scroll = '$_basePath/scroll.png'; static const scroll = '$_basePath/scroll.png';
static const manageuser = '$_basePath/manageuser.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';
} }

View File

@ -9,4 +9,6 @@ abstract class MiscIconAssetPath {
static const vector = '$_basePath/vector.png'; static const vector = '$_basePath/vector.png';
static const visibleOn = '$_basePath/visible_on.png'; static const visibleOn = '$_basePath/visible_on.png';
static const visibilityOff = '$_basePath/visibility_off.png'; static const visibilityOff = '$_basePath/visibility_off.png';
static const save = '$_basePath/save.png';
} }

View File

@ -271,7 +271,13 @@ class _RegisterScreenState extends State<RegisterScreen> {
'Email ID already exists. Please use a different email.'), 'Email ID already exists. Please use a different email.'),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.pop(context), onPressed: () {
Navigator.pop(context);
setState(() {
isRegistering =
false; // Re-enable the button after error
});
},
child: Text('OK'), child: Text('OK'),
), ),
], ],
@ -356,6 +362,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
}, },
), ),
], ],
backgroundColor: Colors.white,
), ),
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: registrationSuccess body: registrationSuccess
@ -474,8 +481,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
), ),
) )
: Padding( : 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( child: Form(
key: _formKey, key: _formKey,
child: SingleChildScrollView( child: SingleChildScrollView(
@ -502,13 +509,23 @@ class _RegisterScreenState extends State<RegisterScreen> {
hintText: _showHints[0] hintText: _showHints[0]
? AppLocalizations.of(context)!.register_name ? AppLocalizations.of(context)!.register_name
: null, : null,
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding( 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( child: Image.asset(
MiscIconAssetPath.person, MiscIconAssetPath.person,
color: Color(0xFF90B0D5), fit: BoxFit.fitHeight,
height: 25,
width: 25, width: 25,
height: 15, color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade300,
), ),
), ),
@ -520,20 +537,29 @@ class _RegisterScreenState extends State<RegisterScreen> {
// border: OutlineInputBorder(), // border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, borderSide: BorderSide(
width: 1), // Enabled border color: MyTheme.topicColor(
), IndicatorTopic.economy)
.shade400,
width: 1), // Enabled border
),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border borderSide: BorderSide(
color: Colors.deepPurple,
width: 2), // Focused border
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), 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), 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: '', counterText: '',
hintStyle: TextStyle(color: Color(0xFFC3C6CB)), hintStyle: TextStyle(color: Color(0xFFC3C6CB)),
@ -554,32 +580,52 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
.enter_your_email .enter_your_email
: null, : null,
// _showHints[1] ? 'Enter your email' : null, // _showHints[1] ? 'Enter your email' : null,
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding( 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( child: Image.asset(
MiscIconAssetPath.vector, MiscIconAssetPath.vector,
color: Color(0xFF90B0D5), fit: BoxFit.fitHeight,
height: 20,
width: 25, width: 25,
height: 15, color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade100,
), ),
), ),
// border: OutlineInputBorder(), // border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
width: 1), width: 1),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border borderSide: BorderSide(
color: Colors.deepPurple,
width: 2), // Focused border
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), 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), 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: '', counterText: '',
hintStyle: TextStyle(color: Color(0xFFC3C6CB)), hintStyle: TextStyle(color: Color(0xFFC3C6CB)),
@ -603,15 +649,26 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
.enter_your_password .enter_your_password
: null, : null,
// _showHints[2] ? 'Enter your password' : null, // _showHints[2] ? 'Enter your password' : null,
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding( 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( child: Image.asset(
MiscIconAssetPath.lock, MiscIconAssetPath.lock,
color: Color(0xFF90B0D5), fit: BoxFit.fitHeight,
height: 25,
width: 25, width: 25,
height: 15, color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade300,
), ),
), ),
// prefixIcon: Icon( // prefixIcon: Icon(
// Icons.lock, // Icons.lock,
// color: Color(0xFF90B0D5), // color: Color(0xFF90B0D5),
@ -626,15 +683,15 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
icon: Image.asset( icon: Image.asset(
_obscurePassword _obscurePassword
?MiscIconAssetPath.visibilityOff ? MiscIconAssetPath.visibilityOff
:MiscIconAssetPath.visibleOn, : 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, width: 24,
height: 24, height: 24,
), ),
onPressed: () { onPressed: () {
setState(() { setState(() {
_obscurePassword = !_obscurePassword; _obscurePassword = !_obscurePassword;
@ -644,20 +701,29 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
// border: OutlineInputBorder(), // border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
width: 1), width: 1),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border borderSide: BorderSide(
color: Colors.deepPurple,
width: 2), // Focused border
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), 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), 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: '', counterText: '',
@ -678,23 +744,34 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
.register_Confirm_password .register_Confirm_password
: null, : null,
// _showHints[3] ? 'Confirm password' : null, // _showHints[3] ? 'Confirm password' : null,
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding( 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( child: Image.asset(
MiscIconAssetPath.lock, MiscIconAssetPath.lock,
color: Color(0xFF90B0D5), fit: BoxFit.fitHeight,
height: 25,
width: 25, width: 25,
height: 15, color:
MyTheme.topicColor(IndicatorTopic.economy)
.shade300,
), ),
), ),
suffixIcon: IconButton(
suffixIcon: IconButton(
icon: Image.asset( icon: Image.asset(
_obscureConfirmPassword _obscureConfirmPassword
?MiscIconAssetPath.visibilityOff ? MiscIconAssetPath.visibilityOff
:MiscIconAssetPath.visibleOn, : 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, width: 24,
height: 24, height: 24,
), ),
@ -710,20 +787,29 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
// ), // ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade400, borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
.shade400,
width: 1), width: 1),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.deepPurple, width: 2), // Focused border borderSide: BorderSide(
color: Colors.deepPurple,
width: 2), // Focused border
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), 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), 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: '', counterText: '',
hintStyle: TextStyle(color: Color(0xFFC3C6CB)), hintStyle: TextStyle(color: Color(0xFFC3C6CB)),
@ -748,7 +834,9 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
}); });
}, },
side: BorderSide( side: BorderSide(
color: showError ? Color(0xFFD83731) : Color(0xFF92722A), color: showError
? Color(0xFFD83731)
: Color(0xFF92722A),
width: 1, width: 1,
), ),
), ),
@ -762,25 +850,31 @@ borderSide: BorderSide(color: MyTheme.topicColor(IndicatorTopic.economy).shade40
text: AppLocalizations.of(context)! text: AppLocalizations.of(context)!
.terms_conditions, .terms_conditions,
// text: 'Terms & Conditions', // text: 'Terms & Conditions',
style: TextStyle(fontWeight: FontWeight.bold, style: TextStyle(
color: Color(0xFF648CBA), fontWeight: FontWeight.bold,
// Makes the text bold color: Color(0xFF648CBA),
decoration: TextDecoration.underline, // Makes the text bold
decorationColor: Color(0xFF648CBA), decoration:
decorationThickness: 1), TextDecoration.underline,
), decorationColor: Color(0xFF648CBA),
decorationThickness: 1),
),
TextSpan( TextSpan(
text: AppLocalizations.of(context)! text: AppLocalizations.of(context)!
.t_and), .t_and),
TextSpan( TextSpan(
text: AppLocalizations.of(context)! text: AppLocalizations.of(context)!
.privacy_policy, .privacy_policy,
style: TextStyle(fontWeight: FontWeight.bold, style: TextStyle(
color: Color(0xFF648CBA), fontWeight: FontWeight.bold,
decoration: TextDecoration.underline, fontSize: 14,
fontFamily: 'Roboto',
color: Color(0xFF648CBA),
decoration:
TextDecoration.underline,
decorationColor: Color(0xFF648CBA), decorationColor: Color(0xFF648CBA),
decorationThickness: 1), decorationThickness: 1),
), ),
TextSpan( TextSpan(
text: AppLocalizations.of(context)! text: AppLocalizations.of(context)!
.conditions), .conditions),
@ -831,7 +925,8 @@ style: TextStyle(fontWeight: FontWeight.bold,
SizedBox(width: 8), SizedBox(width: 8),
const Icon( const Icon(
Icons.chevron_right_outlined, 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( Text(
AppLocalizations.of(context)!.account_confirmation, AppLocalizations.of(context)!.account_confirmation,
style: TextStyle( style: TextStyle(
fontSize: 16, color: Colors.grey[600]), fontSize: 14, color: Colors.grey[600]),
), ),
SizedBox(height: 15), SizedBox(height: 15),
SizedBox( SizedBox(
@ -868,7 +963,8 @@ style: TextStyle(fontWeight: FontWeight.bold,
SizedBox(width: 8), SizedBox(width: 8),
const Icon( const Icon(
Icons.chevron_right_outlined, Icons.chevron_right_outlined,
color: Colors.white, // Set your desired color here color: Colors
.white, // Set your desired color here
) )
], ],
), ),

View File

@ -10,6 +10,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/domain/use_cases/language.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 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import '../components/my_bottom_nav_bar.dart'; import '../components/my_bottom_nav_bar.dart';
@ -74,7 +75,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
// Regular expression to validate Full Name (no special characters) // Regular expression to validate Full Name (no special characters)
final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$"); final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$");
late Future<RecordModel> userDetails; late Future<RecordModel> userDetails;
bool _isHoveringDate = false; bool _isHoveringDate = false;
bool _isHoveringDropdown = false; bool _isHoveringDropdown = false;
@override @override
@ -336,435 +337,450 @@ class _ProfileScreenState extends State<ProfileScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return PopScope(
appBar: AppBar( onPopInvokedWithResult: (didPop, result) {
backgroundColor: Colors.white, if (didPop) return;
elevation: 0, context.go('/');
leading: IconButton( },
icon: Icon(Icons.arrow_back_ios_new, color: Colors.black), child: Scaffold(
onPressed: () { appBar: AppBar(
context.go('/'); backgroundColor: Colors.white,
}, elevation: 0,
), leading: IconButton(
title: Text( icon: Icon(Icons.arrow_back_ios_new, color: Colors.black),
'My Profile',
style: TextStyle(color: Colors.orange),
),
actions: [
TextButton(
onPressed: () { onPressed: () {
context.go('/'); context.go('/');
}, },
child: Text( ),
'Logout', title: Text(
style: TextStyle(color: Colors.orange), 'My Profile',
style: TextStyle(color: Color(0xFF985400)),
),
actions: [
TextButton(
onPressed: () {
context.go('/');
},
child: Text(
'Logout',
style: TextStyle(color: Colors.orange),
),
), ),
), IconButton(
IconButton( icon: Icon(Icons.logout, color: Colors.black),
icon: Icon(Icons.logout, color: Colors.black), onPressed: () {},
onPressed: () {}, ),
), ],
], ),
), body: SingleChildScrollView(
body: SingleChildScrollView( child: Form(
child: Form( key: _formKey,
key: _formKey, child: Padding(
child: Padding( padding: const EdgeInsets.only(
padding: const EdgeInsets.only(top: 20.0,bottom: 20.0, left: 25,right: 25), top: 20.0, bottom: 20.0, left: 25, right: 25),
child: Column( child: Column(
children: [ children: [
// CircleAvatar( // CircleAvatar(
// radius: 50, // radius: 50,
// backgroundImage: _profileImage != null // backgroundImage: _profileImage != null
// ? FileImage(_profileImage!) // ? FileImage(_profileImage!)
// : AssetImage("assets/edit_profile/profile.png") // : AssetImage("assets/edit_profile/profile.png")
// as ImageProvider, // as ImageProvider,
// child: Align( // child: Align(
// alignment: Alignment.bottomRight, // alignment: Alignment.bottomRight,
// child: GestureDetector( // child: GestureDetector(
// onTap: _pickImage, // Call `_pickImage` on tap // onTap: _pickImage, // Call `_pickImage` on tap
// child: CircleAvatar( // child: CircleAvatar(
// radius: 15, // radius: 15,
// backgroundColor: Colors.white, // backgroundColor: Colors.white,
// child: Icon( // child: Icon(
// Icons.camera_alt, // Icons.camera_alt,
// size: 15, // size: 15,
// color: Colors.grey, // color: Colors.grey,
// ), // ),
// ), // ),
// ), // ),
// ), // ),
// ), // ),
Stack( Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
// CircleAvatar with the profile image // CircleAvatar with the profile image
CircleAvatar( CircleAvatar(
radius: 50, radius: 50,
backgroundImage: _profileImage != null backgroundImage: _profileImage != null
? FileImage(_profileImage!) ? FileImage(_profileImage!)
: AssetImage("assets/edit_profile/profile.png") : AssetImage("assets/edit_profile/profile.png")
as ImageProvider, as ImageProvider,
child: Align( child: Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child: GestureDetector( child: GestureDetector(
onTap: _pickImage, // Call `_pickImage` on tap onTap: _pickImage, // Call `_pickImage` on tap
child: CircleAvatar( child: CircleAvatar(
radius: 15, radius: 15,
backgroundColor: Colors.white, backgroundColor: Colors.white,
child: Icon( child: Icon(
Icons.camera_alt, Icons.camera_alt,
size: 15, size: 15,
color: Colors.grey, color: Colors.grey,
),
), ),
), ),
), ),
), ),
),
// Conditional loader that shows when _isLoading is true // Conditional loader that shows when _isLoading is true
if (_isLoading) if (_isLoading)
Positioned( Positioned(
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
valueColor: valueColor:
AlwaysStoppedAnimation<Color>(Colors.grey), AlwaysStoppedAnimation<Color>(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]+$"); SizedBox(height: 20),
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<String>(
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<String>(
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)
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Padding( Text(
padding: const EdgeInsets.only(left: 10.0), "User Name",
child: Text( style: TextStyle(
'Please agree to terms and conditions', fontSize: 16,
style: TextStyle( fontWeight: FontWeight.w500,
color: Color(0xFFb22222), color: Colors.grey),
fontSize: 12, ),
],
),
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<String>(
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<String>(
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), if (showError)
Center( Row(
child: GestureDetector( mainAxisAlignment: MainAxisAlignment.start,
onTap: () { children: [
final userId = widget.userId; Padding(
final email = _emailController.text; 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'); context.go('/createNewPw/$userId/$email');
}, },
child: Text( child: Text(
'Change Password', 'Change Password',
style: TextStyle( style: TextStyle(
color: Color(0xFF648CBA), color: Color(0xFF648CBA),
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
fontFamily: 'Roboto', fontFamily: 'Roboto',
// decoration: TextDecoration.underline), // decoration: TextDecoration.underline),
),
), ),
), ),
), ),
), SizedBox(height: 20),
SizedBox(height: 20), // ElevatedButton.icon(
// ElevatedButton.icon(
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { if ((_formKey.currentState?.validate() ?? false) &&
_formKey.currentState?.save(); (isChecked)) {
showConfirmationDialog(context); _formKey.currentState?.save();
} else { showConfirmationDialog(context);
setState(() { } else {
showError = !isChecked; // Show error if the checkbox is not checked setState(() {
}); showError =
} !isChecked; // Show error if the checkbox is not checked
}, });
style: ElevatedButton.styleFrom( }
backgroundColor: Color(0xFF92722A), },
minimumSize: Size(double.infinity, 50), style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( backgroundColor: Color(0xFF92722A),
borderRadius: BorderRadius.circular(8), minimumSize: Size(double.infinity, 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
), ),
), child: Row(
child: Row( mainAxisAlignment:
mainAxisAlignment: MainAxisAlignment.center, // Center the content MainAxisAlignment.center, // Center the content
children: [ children: [
Text( Text(
'Save', 'Save',
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
SizedBox(width: 8), // Add space between text and icon SizedBox(width: 8), // Add space between text and icon
Icon( Image.asset(
Icons.save_outlined, MiscIconAssetPath.save,
color: Colors.white, color: Colors.white,
), width: 20,
], height: 20,
), ),
) ],
),
], )
],
),
), ),
), ),
), ),
), ),
//bottomNavigationBar: MyBottomNavBar(),
); );
} }
} }

View File

@ -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/my_bottom_nav_bar.dart';
import 'package:uae_stat/presentation/components/space.dart'; import 'package:uae_stat/presentation/components/space.dart';
import 'package:uae_stat/presentation/components/themed_text_field.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:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../../Screens/auth_verification/registration.dart'; import '../../Screens/auth_verification/registration.dart';
@ -27,10 +28,11 @@ import '../../components/my_toggle.dart';
class LoginRoute extends HookConsumerWidget { class LoginRoute extends HookConsumerWidget {
final pb = PocketBase('https://pb.venbait.in'); final pb = PocketBase('https://pb.venbait.in');
final _pbService = PocketBaseService();
// final _pb = PocketBase('http://127.0.0.1:8090'); // final _pb = PocketBase('http://127.0.0.1:8090');
final bool isLoginScreen; // Pass `true` if this is the login screen // final bool isLoginScreen; // Pass `true` if this is the login screen
LoginRoute({Key? key, required this.isLoginScreen}) : super(key: key); // LoginRoute({Key? key, required this.isLoginScreen}) : super(key: key);
// LoginRoute({super.key}); LoginRoute({super.key});
dynamic userData; dynamic userData;
String? role; String? role;
@ -96,52 +98,91 @@ class LoginRoute extends HookConsumerWidget {
final forgotPwFormKey = GlobalKey<FormState>(); final forgotPwFormKey = GlobalKey<FormState>();
final email = await showDialog<String>( final email = await showDialog<String>(
context: context, context: context,
builder: (dialogCtx) => AlertDialog( builder: (dialogCtx) => SizedBox(
title: Text( // width: 850, // Increase dialog width
context.translate( child: AlertDialog(
'Reset Password', 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; if (email == null) return;
@ -177,7 +218,7 @@ class LoginRoute extends HookConsumerWidget {
), ),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 14, fontSize: 14,
color: Color(0xFF985400), color: Color(0xFF985400),
), ),
), ),
); );
@ -361,7 +402,7 @@ class LoginRoute extends HookConsumerWidget {
6.horizontalSpace, 6.horizontalSpace,
const Icon( const Icon(
Icons.chevron_right_outlined, 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) { validator: (text) {
if (text == null || text.isEmpty) { if (text == null || text.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} } else if (text.length < 8) {
else if (text.length < 8) {
return 'The password must be at least 8 characters'; return 'The password must be at least 8 characters';
} }
return FieldValidator.password(minLength: 8)(text); return FieldValidator.password(minLength: 8)(text);
@ -403,12 +443,14 @@ class LoginRoute extends HookConsumerWidget {
imgPath: MiscIconAssetPath.lock, imgPath: MiscIconAssetPath.lock,
controller: pwCtl, controller: pwCtl,
isObscurable: true, isObscurable: true,
), ),
// 6.verticalSpace, // 6.verticalSpace,
Align( Padding(
alignment: AlignmentDirectional.topEnd, padding: EdgeInsets.zero,
child: forgotPwBtn, child: Align(
alignment: AlignmentDirectional.topEnd,
child: forgotPwBtn,
),
), ),
10.verticalSpace, 10.verticalSpace,
loginBtn, loginBtn,
@ -460,7 +502,7 @@ class LoginRoute extends HookConsumerWidget {
'Roboto', 'Roboto',
'NotoKufi', 'NotoKufi',
), ),
fontSize: 18, fontSize: 14,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
children: [ children: [
@ -482,8 +524,8 @@ class LoginRoute extends HookConsumerWidget {
'سجل الان', 'سجل الان',
), ),
style: TextStyle( style: TextStyle(
color: Color(0xFF985400), color: Color(0xFF985400),
), ),
), ),
], ],
), ),
@ -574,7 +616,7 @@ class LoginRoute extends HookConsumerWidget {
helloAndPleaseLoginTexts, helloAndPleaseLoginTexts,
42.verticalSpace, 42.verticalSpace,
form, form,
20.verticalSpace, 15.verticalSpace,
dontHaveAnAccountRegisterBtn, dontHaveAnAccountRegisterBtn,
20.verticalSpace, 20.verticalSpace,
// continueAsGuestBtn, // continueAsGuestBtn,
@ -588,7 +630,7 @@ class LoginRoute extends HookConsumerWidget {
// ); // );
// return bgScaffold; // return bgScaffold;
return PopScope( 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) { onPopInvokedWithResult: (didPop, result) {
if (didPop) return; if (didPop) return;
_showExitConfirmation(context); // Show exit confirmation dialog _showExitConfirmation(context); // Show exit confirmation dialog

View File

@ -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<void> 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<bool> 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<String, dynamic>));
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<bool> 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<void> logoutUser() async {
pb.authStore.clear();
await clearSession();
}
// Clear session from local storage
Future<void> clearSession() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('pb_auth');
await prefs.remove('pb_user');
await prefs.remove('pb_auth_time');
}
}

View File

@ -207,7 +207,7 @@ class EconomyStatsWidget extends ConsumerStatefulWidget {
class EconomyStatsState extends ConsumerState<EconomyStatsWidget> { class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
List<dynamic> data = []; List<dynamic> data = [];
final _pb = PocketBase('https://pb.venbait.in'); final _pb = PocketBase('https://pb.venbait.in');
bool isLoading = true; bool isLoading = true;
final GlobalKey cardTopicKey = GlobalKey(); final GlobalKey cardTopicKey = GlobalKey();
@ -216,14 +216,13 @@ final _pb = PocketBase('https://pb.venbait.in');
late List<TargetFocus> homeTargets; late List<TargetFocus> homeTargets;
late List<TargetFocus> previousHomeTargets; late List<TargetFocus> previousHomeTargets;
void handleSkip() { void handleSkip() {
tutorialCoachMark.skip(); tutorialCoachMark.skip();
debugPrint('Skip clicked'); debugPrint('Skip clicked');
ref.read(chartsTourProvider.notifier).state = true; ref.read(chartsTourProvider.notifier).state = true;
ref.read(previousChartsTourProvider.notifier).state = true; ref.read(previousChartsTourProvider.notifier).state = true;
ref.read(homeTourProvider.notifier).state = true; ref.read(homeTourProvider.notifier).state = true;
ref.read( previousHomeTourProvider.notifier).state = true; ref.read(previousHomeTourProvider.notifier).state = true;
ref.read(scaffoldTourProvider.notifier).state = true; ref.read(scaffoldTourProvider.notifier).state = true;
ref.read(previousScaffoldTourProvider.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(homeTourProvider.notifier).state = true;
ref.read(chartsTourProvider.notifier).state = false; ref.read(chartsTourProvider.notifier).state = false;
debugPrint('Home Tutorial Finished'); 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); )..show(context: context);
} else if (!previousHomeTour) { } else if (!previousHomeTour) {
@ -271,16 +271,16 @@ final _pb = PocketBase('https://pb.venbait.in');
onFinish: () { onFinish: () {
ref.read(previousHomeTourProvider.notifier).state = true; ref.read(previousHomeTourProvider.notifier).state = true;
debugPrint('Previous Home Tutorial Finished'); 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); )..show(context: context);
} }
} }
void _initTarget(){ void _initTarget() {
final double screenWidth = MediaQuery.of(context).size.width; final double screenWidth = MediaQuery.of(context).size.width;
homeTargets=[ homeTargets = [
TargetFocus( TargetFocus(
identify: 'cardTopicKey', identify: 'cardTopicKey',
keyTarget: cardTopicKey, keyTarget: cardTopicKey,
@ -298,7 +298,7 @@ final _pb = PocketBase('https://pb.venbait.in');
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
height: MediaQuery.of(context).size.height*0.70, height: MediaQuery.of(context).size.height * 0.70,
child: Stack( child: Stack(
children: [ children: [
Positioned( Positioned(
@ -310,7 +310,8 @@ final _pb = PocketBase('https://pb.venbait.in');
Align( Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child: Padding( 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( child: Text(
'1/7', '1/7',
style: const TextStyle( style: const TextStyle(
@ -320,7 +321,9 @@ final _pb = PocketBase('https://pb.venbait.in');
), ),
), ),
), ),
SizedBox(height: 5,), SizedBox(
height: 5,
),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -350,12 +353,14 @@ final _pb = PocketBase('https://pb.venbait.in');
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Color(0xFF7DAFBC), color: Color(0xFF7DAFBC),
border: Border.all(color: Color(0xFF7DAFBC), width: 1), border: Border.all(
color: Color(0xFF7DAFBC), width: 1),
), ),
child: IconButton( child: IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, color: Colors.white), icon: const Icon(Icons.arrow_forward,
color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.next(); 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(), // targetPosition:TargetPosition(),
contents: [ contents: [
createTargetContent( createTargetContent(
text:AppLocalizations.of(context)!.economy, text: AppLocalizations.of(context)!.economy,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 0, gap: 0,
space: 43,), space: 43,
),
TargetContent( TargetContent(
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: child: SizedBox(
SizedBox(
width: double.infinity, 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( child: Stack(
children: [ children: [
Positioned( Positioned(
@ -419,23 +424,22 @@ final _pb = PocketBase('https://pb.venbait.in');
children: [ children: [
Align( Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child:Padding(padding: EdgeInsets.only(right: 10), child: Padding(
child: padding: EdgeInsets.only(right: 10),
Text( child: Text(
'2/7', '2/7',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 14, fontSize: 14,
), ),
), ),
) )),
),
const SizedBox(height: 3), const SizedBox(height: 3),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
ElevatedButton( ElevatedButton(
onPressed: () =>handleSkip(), onPressed: () => handleSkip(),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@ -457,11 +461,13 @@ final _pb = PocketBase('https://pb.venbait.in');
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2.0), border: Border.all(
color: Colors.white, width: 2.0),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_back, color: Colors.white), icon: const Icon(Icons.arrow_back,
color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
}, },
@ -472,11 +478,13 @@ final _pb = PocketBase('https://pb.venbait.in');
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Color(0xFF7DAFBC), color: Color(0xFF7DAFBC),
border: Border.all(color: Color(0xFF7DAFBC), width: 1), border: Border.all(
color: Color(0xFF7DAFBC), width: 1),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, color: Colors.white), icon: const Icon(Icons.arrow_forward,
color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.next(); 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; final double screenWidth = MediaQuery.of(context).size.width;
previousHomeTargets=[ previousHomeTargets = [
TargetFocus( TargetFocus(
identify: 'cardsKey', identify: 'cardsKey',
keyTarget: cardsKey, keyTarget: cardsKey,
@ -546,16 +554,17 @@ final _pb = PocketBase('https://pb.venbait.in');
paddingFocus: 6, paddingFocus: 6,
contents: [ contents: [
createTargetContent( createTargetContent(
text:AppLocalizations.of(context)!.economy, text: AppLocalizations.of(context)!.economy,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 0, gap: 0,
space: 43,), space: 43,
),
TargetContent( TargetContent(
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: child: SizedBox(
SizedBox(
width: double.infinity, 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( child: Stack(
children: [ children: [
Positioned( Positioned(
@ -566,23 +575,24 @@ final _pb = PocketBase('https://pb.venbait.in');
children: [ children: [
Align( Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child:Padding(padding: EdgeInsets.only(right: 10), child: Padding(
child: padding: EdgeInsets.only(right: 10),
Text( child: Text(
'2/7', '2/7',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 14, fontSize: 14,
), ),
), ),
) )),
SizedBox(
height: 5,
), ),
SizedBox(height: 5,),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
ElevatedButton( ElevatedButton(
onPressed: () =>handleSkip(), onPressed: () => handleSkip(),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@ -600,17 +610,18 @@ final _pb = PocketBase('https://pb.venbait.in');
), ),
), ),
Row( Row(
children: [ children: [
Row( Row(
children: [ children: [
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2.0), border: Border.all(
color: Colors.white, width: 2.0),
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white), icon: const Icon(Icons.arrow_back,
color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.next(); tutorialCoachMark.next();
}, },
@ -621,15 +632,24 @@ final _pb = PocketBase('https://pb.venbait.in');
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Color(0xFF7DAFBC), color: Color(0xFF7DAFBC),
border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), border: Border.all(
color: Color(0xFF7DAFBC),
width: 1.5),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, color: Colors.white), icon: const Icon(Icons.arrow_forward,
color: Colors.white),
onPressed: () { onPressed: () {
ref.read(previousHomeTourProvider.notifier).state=true; ref
ref.read(chartsTourProvider.notifier).state=false; .read(previousHomeTourProvider
context.go('/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments'); .notifier)
.state = true;
ref
.read(chartsTourProvider.notifier)
.state = false;
context.go(
'/chartScreen/hotels?bgColor=0xFF90B0D5&mainTopic=ECONOMY&title=Hotel+Establishments');
tutorialCoachMark.finish(); tutorialCoachMark.finish();
}, },
), ),
@ -673,7 +693,7 @@ final _pb = PocketBase('https://pb.venbait.in');
paddingFocus: 16, paddingFocus: 16,
contents: [ contents: [
createTargetContent( createTargetContent(
text:AppLocalizations.of(context)!.home_topic, text: AppLocalizations.of(context)!.home_topic,
alignment: ContentAlign.bottom, alignment: ContentAlign.bottom,
gap: 0, gap: 0,
space: 43, space: 43,
@ -682,7 +702,7 @@ final _pb = PocketBase('https://pb.venbait.in');
align: ContentAlign.bottom, align: ContentAlign.bottom,
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
height: MediaQuery.of(context).size.height*0.69, height: MediaQuery.of(context).size.height * 0.69,
child: Stack( child: Stack(
children: [ children: [
Positioned( Positioned(
@ -694,7 +714,7 @@ final _pb = PocketBase('https://pb.venbait.in');
Align( Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,
child: Padding( child: Padding(
padding:EdgeInsets.only(right: 10), padding: EdgeInsets.only(right: 10),
child: Text( child: Text(
'1/7', '1/7',
style: const TextStyle( style: const TextStyle(
@ -735,11 +755,13 @@ final _pb = PocketBase('https://pb.venbait.in');
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: Color(0xFF7DAFBC), color: Color(0xFF7DAFBC),
border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), border: Border.all(
color: Color(0xFF7DAFBC), width: 1.5),
), ),
child: IconButton( child: IconButton(
iconSize: 20, iconSize: 20,
icon: const Icon(Icons.arrow_forward, color: Colors.white), icon: const Icon(Icons.arrow_forward,
color: Colors.white),
onPressed: () { onPressed: () {
tutorialCoachMark.previous(); tutorialCoachMark.previous();
}, },
@ -777,15 +799,13 @@ final _pb = PocketBase('https://pb.venbait.in');
]; ];
} }
@override
@override void initState() {
void initState() { super.initState();
super.initState(); final locale = ref.read(localeProvider);
final locale = ref.read(localeProvider); fetchData(locale?.languageCode ?? 'en');
fetchData(locale?.languageCode ?? 'en'); _fetchUserData();
_fetchUserData(); }
}
// @override // @override
// void didChangeDependencies() { // void didChangeDependencies() {
@ -795,43 +815,38 @@ _fetchUserData();
// fetchData(locale); // Pass the locale to the fetchData method // fetchData(locale); // Pass the locale to the fetchData method
// } // }
Future<String?> getUserId() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString('userId'); // Retrieve the userId
}
Future<String?> getUserId() async { Future<void> _fetchUserData() async {
final prefs = await SharedPreferences.getInstance(); try {
return prefs.getString('userId'); // Retrieve the userId final userId = await getUserId();
} print('EDIT PROFILE isPageLoad');
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
Future<void> _fetchUserData() async { final adminToken = adminAuth.token;
try { print('adminToken- $adminToken');
final userId = await getUserId(); final userDetailsResponse = await _pb.collection('users').getOne(
print('EDIT PROFILE isPageLoad'); userId!,
final adminAuth = await _pb.admins headers: {
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); 'Authorization': 'Bearer $adminToken',
final adminToken = adminAuth.token; },
print('adminToken- $adminToken'); );
final userDetailsResponse = await _pb.collection('users').getOne( final loginCount = userDetailsResponse.data['login_count'];
userId!, print(loginCount);
headers: { if (loginCount == 1) {
'Authorization': 'Bearer $adminToken', setState(() {
}, WidgetsBinding.instance.addPostFrameCallback((_) {
); _starTourRender();
final loginCount = userDetailsResponse.data['login_count']; });
print(loginCount); });
if (loginCount == 1) { }
WidgetsBinding.instance.addPostFrameCallback((_) { } catch (e) {
_starTourRender(); print('Error fetching user details: $e');
}); }
} }
} catch (e) {
print('Error fetching user details: $e');
}
}
Future<void> fetchData(locale) async { Future<void> fetchData(locale) async {
const baseUrl = 'https://pb.venbait.in/api/getHomePageData'; const baseUrl = 'https://pb.venbait.in/api/getHomePageData';
@ -940,7 +955,7 @@ print('Error fetching user details: $e');
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
RoundedCornerContainer( RoundedCornerContainer(
key: mainTopic['main_topic'] =='ECONOMY' key: mainTopic['main_topic'] == 'ECONOMY'
? cardTopicKey ? cardTopicKey
: null, : null,
text: mainTopic['main_topic'], text: mainTopic['main_topic'],
@ -954,7 +969,7 @@ print('Error fetching user details: $e');
SizedBox( SizedBox(
height: myheight / 4.8, // Set dynamic height height: myheight / 4.8, // Set dynamic height
child: Container( child: Container(
key:mainTopic['main_topic'] == 'ECONOMY' key: mainTopic['main_topic'] == 'ECONOMY'
? cardsKey ? cardsKey
: null, : null,
// color: Colors.grey[200], // Set a background color for the scrollable container // 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 encodedTitle = Uri.encodeComponent(title);
final encodedKey = Uri.encodeQueryComponent('home'); final encodedKey = Uri.encodeQueryComponent('home');
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
context.go( context.go(

View File

@ -11,6 +11,7 @@ import 'package:intl/intl.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.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'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class EditProfile extends StatefulWidget { class EditProfile extends StatefulWidget {
@ -424,11 +425,11 @@ class _EditProfileState extends State<EditProfile> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BaseScaffold( return BaseScaffold(
title: Text(AppLocalizations.of(context)!.my_profile), title: Text(AppLocalizations.of(context)!.my_profile,
style: TextStyle(color: Color(0xFF985400)),),
body: SingleChildScrollView( body: SingleChildScrollView(
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0), padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
child: Column( child: Column(
children: [ children: [
SingleChildScrollView( SingleChildScrollView(
@ -436,8 +437,9 @@ class _EditProfileState extends State<EditProfile> {
key: _formKey, key: _formKey,
child: Padding( child: Padding(
// padding: const EdgeInsets.all(20.0), // padding: const EdgeInsets.all(20.0),
padding: const EdgeInsets.only(top: 20.0,bottom: 20.0, left: 25,right: 25), padding: const EdgeInsets.only(
child: isPageLoad top: 20.0, bottom: 20.0, left: 25, right: 25),
child: isPageLoad
? Center( ? Center(
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
) )
@ -727,11 +729,11 @@ class _EditProfileState extends State<EditProfile> {
suffixIcon: Container( suffixIcon: Container(
width: 45, width: 45,
padding: EdgeInsets.only(right: 1), padding: EdgeInsets.only(right: 1),
alignment: Alignment.center, // Center the icon vertically alignment: Alignment
.center, // Center the icon vertically
child: Icon( child: Icon(
Icons.keyboard_arrow_down_sharp, Icons.keyboard_arrow_down_sharp,
color: Colors.grey, color: Colors.grey,
), ),
), ),
enabled: !_isProfileCompleted, enabled: !_isProfileCompleted,
@ -755,8 +757,10 @@ class _EditProfileState extends State<EditProfile> {
), ),
SizedBox(height: 10), SizedBox(height: 10),
MouseRegion( MouseRegion(
onEnter: (_) => setState(() => _isHoveringDropdown = true), onEnter: (_) =>
onExit: (_) => setState(() => _isHoveringDropdown = false), setState(() => _isHoveringDropdown = true),
onExit: (_) =>
setState(() => _isHoveringDropdown = false),
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
value: _selectedCountry, value: _selectedCountry,
decoration: InputDecoration( decoration: InputDecoration(
@ -766,7 +770,9 @@ class _EditProfileState extends State<EditProfile> {
labelText: 'Select', labelText: 'Select',
), ),
icon: Icon(Icons.keyboard_arrow_down_sharp, icon: Icon(Icons.keyboard_arrow_down_sharp,
color: _isHoveringDropdown ? Colors.black : Colors.grey ), color: _isHoveringDropdown
? Colors.black
: Colors.grey),
items: _countries items: _countries
.map( .map(
(item) => DropdownMenuItem<String>( (item) => DropdownMenuItem<String>(
@ -781,7 +787,8 @@ class _EditProfileState extends State<EditProfile> {
}); });
}, },
validator: _validateDropdown, validator: _validateDropdown,
),), ),
),
SizedBox(height: 20), SizedBox(height: 20),
if (!_isProfileCompleted) // Conditional rendering if (!_isProfileCompleted) // Conditional rendering
Column( Column(
@ -827,7 +834,8 @@ class _EditProfileState extends State<EditProfile> {
.terms_conditions, .terms_conditions,
style: TextStyle( style: TextStyle(
// color: Colors.blue, // color: Colors.blue,
color: Color(0xFF648CBA), color:
Color(0xFF648CBA),
decoration: decoration:
TextDecoration TextDecoration
.underline, .underline,
@ -854,7 +862,7 @@ class _EditProfileState extends State<EditProfile> {
.privacy_policy, .privacy_policy,
style: TextStyle( style: TextStyle(
// color: Colors.blue, // color: Colors.blue,
color: Color(0xFF648CBA), color: Color(0xFF648CBA),
decoration: decoration:
TextDecoration TextDecoration
.underline, .underline,
@ -911,7 +919,8 @@ class _EditProfileState extends State<EditProfile> {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
final email = _emailController.text; final email = _emailController.text;
context.go('/createNewPw/$userId/$email?key=editProfile'); context.go(
'/createNewPw/$userId/$email?key=editProfile');
}, },
child: Text( child: Text(
AppLocalizations.of(context)! AppLocalizations.of(context)!
@ -949,14 +958,14 @@ class _EditProfileState extends State<EditProfile> {
// ), // ),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
if ((_formKey.currentState?.validate() ?? false) && (isChecked)) { // if ((_formKey.currentState?.validate() ?? false) && (isChecked)) {
_formKey.currentState?.save(); // _formKey.currentState?.save();
showConfirmationDialog(context); showConfirmationDialog(context);
} else { // } else {
setState(() { // setState(() {
showError = !isChecked; // Show error if the checkbox is not checked // showError = !isChecked; // Show error if the checkbox is not checked
}); // });
} // }
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF92722A), backgroundColor: Color(0xFF92722A),
@ -969,13 +978,15 @@ class _EditProfileState extends State<EditProfile> {
mainAxisAlignment: MainAxisAlignment.center, // Center the content mainAxisAlignment: MainAxisAlignment.center, // Center the content
children: [ children: [
Text( Text(
'Save', AppLocalizations.of(context)!.save,
style: TextStyle(color: Colors.white), style: TextStyle(color: Colors.white),
), ),
SizedBox(width: 8), // Add space between text and icon SizedBox(width: 8), // Add space between text and icon
Icon( Image.asset(
Icons.save_outlined, MiscIconAssetPath.save,
color: Colors.white, color: Colors.white,
width: 20,
height: 20,
), ),
], ],
), ),

View File

@ -11,6 +11,7 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:tutorial_coach_mark/tutorial_coach_mark.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/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/indicators/locale_provider.dart';
import 'package:uae_stat/presentation/components/my_toggle.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart';
@ -734,15 +735,25 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
), ),
if (userId != 'guest') if (userId != 'guest')
ListTile( ListTile(
leading: Icon(Icons.feedback), leading: Image.asset(
DrawerAssetIconPath.feedback,
color: Colors.black ,
width: 20,
height: 20,
),
// title: const Text('Feedback'), // title: const Text('Feedback'),
title: Text(AppLocalizations.of(context)!.feedback_title), title: Text(AppLocalizations.of(context)!.feedback_title),
onTap: () => context.go('/feedback'), onTap: () => context.go('/feedback'),
), ),
if (role == 'admin') if (role == 'admin')
ListTile( ListTile(
leading: Icon(Icons.manage_accounts), leading: Image.asset(
// title: Text('Manage User'), DrawerAssetIconPath.manageUser,
color: Colors.black ,
width: 20,
height: 20,
),
// title: Text('Manage User'),
title: Text( title: Text(
AppLocalizations.of(context)!.manage_user, AppLocalizations.of(context)!.manage_user,
), ),
@ -754,7 +765,12 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
onTap: () => context.go('/bookmark'), onTap: () => context.go('/bookmark'),
), ),
ListTile( ListTile(
leading: Icon(Icons.book), leading: Image.asset(
DrawerAssetIconPath.guide,
color: Colors.black ,
width: 20,
height: 20,
),
// title: const Text('User Guide'), // title: const Text('User Guide'),
title: Text(AppLocalizations.of(context)!.guide_title), title: Text(AppLocalizations.of(context)!.guide_title),
onTap: () => context.go('/user-guide'), onTap: () => context.go('/user-guide'),

View File

@ -2,7 +2,7 @@ name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness." description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none" publish_to: "none"
#version: 0.5.10 #version: 0.5.10
version: 1.0.6+7 version: 1.0.8+9
environment: environment:
sdk: ">=3.2.3 <4.0.0" sdk: ">=3.2.3 <4.0.0"
@ -120,6 +120,10 @@ flutter:
- assets/icons/misc/vector.png - assets/icons/misc/vector.png
- assets/icons/misc/visible_on.png - assets/icons/misc/visible_on.png
- assets/icons/misc/visibility_off.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: fonts:
- family: Segoe - family: Segoe