Validation message arabic Translated

This commit is contained in:
Kalonkarthik 2025-02-20 17:53:18 +05:30
parent 84c62a4cc7
commit 704c2d409f
20 changed files with 251 additions and 351 deletions

View File

@ -98,7 +98,7 @@
"failed_to_update_password": "", "failed_to_update_password": "",
"password_update_successfully": "تم تحديث كلمة المرور بنجاح.", "password_update_successfully": "تم تحديث كلمة المرور بنجاح.",
"new_password_not_same_as_old": "كلمة المرور الجديدة يجب ألا تكون نفس كلمة المرور القديمة", "new_password_not_same_as_old": "كلمة المرور الجديدة يجب ألا تكون نفس كلمة المرور القديمة",
"password_between_8_to_40": "يجب أن تتراوح كلمة المرور بين 8 و64 حرفًا", "password_between_8_to_40": "يجب أن تتراوح كلمة المرور بين 8 و40 حرفًا",
"new_password_required": "كلمة المرور الجديدة مطلوبة", "new_password_required": "كلمة المرور الجديدة مطلوبة",
"old_password_is_required": "كلمة المرور القديمة مطلوبة", "old_password_is_required": "كلمة المرور القديمة مطلوبة",
"confirm_password_is_required": "تأكيد كلمة المرور مطلوب", "confirm_password_is_required": "تأكيد كلمة المرور مطلوب",

View File

@ -99,7 +99,7 @@
"failed_to_update_password": "", "failed_to_update_password": "",
"password_update_successfully": "Password updated successfully.", "password_update_successfully": "Password updated successfully.",
"new_password_not_same_as_old": "New password must not be the same as the old password", "new_password_not_same_as_old": "New password must not be the same as the old password",
"password_between_8_to_40": "Password must be between 8 and 64 characters", "password_between_8_to_40": "Password must be between 8 and 40 characters",
"new_password_required": "New password is required", "new_password_required": "New password is required",
"old_password_is_required": "Old password is required", "old_password_is_required": "Old password is required",
"confirm_password_is_required": "Confirm password is required", "confirm_password_is_required": "Confirm password is required",

View File

@ -220,14 +220,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
children: [ children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () {
context.pop();
if (widget.keyParam == 'editProfile') {
context.go('/editProfile');
}else
{
context.go('/profile/${widget.userId}');
}
}, },
child: Container( child: Container(
margin: EdgeInsets.only(top: 10,left: 1,bottom: 16,right: 1), // Add margin for positioning margin: EdgeInsets.only(top: 10,left: 1,bottom: 16,right: 1), // Add margin for positioning
@ -249,7 +242,13 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) {
formState?.validate();
}
});
}, },
); );
}, },
@ -658,7 +657,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
SizedBox(height: 10), SizedBox(height: 10),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
context.go('/'); context.go('/login');
}, },
style: ButtonStyle( style: ButtonStyle(
shape: WidgetStatePropertyAll( shape: WidgetStatePropertyAll(
@ -697,6 +696,14 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
'Login', 'Login',
'تسجيل الدخول', 'تسجيل الدخول',
), ),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'Roboto',
),
fontSize: 17,
fontWeight: FontWeight.w500,
),
), ),
6.horizontalSpace, 6.horizontalSpace,
const Icon(Icons.chevron_right_outlined,color:Colors.white), const Icon(Icons.chevron_right_outlined,color:Colors.white),

View File

@ -7,12 +7,13 @@ import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:uae_stat/config/my_theme.dart'; import 'package:uae_stat/config/my_theme.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/banner_asset_path.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/misc_icon_asset_path.dart';
import 'package:uae_stat/presentation/Screens/profilepage.dart'; import 'package:uae_stat/presentation/Screens/profilepage.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart';
import '../../components/my_toggle.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart';
import '../../routes/auth_routes/login_route.dart'; import '../../routes/auth_routes/login_route.dart';
class RegisterScreen extends ConsumerStatefulWidget { class RegisterScreen extends ConsumerStatefulWidget {
@ -120,10 +121,10 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} else if (value.length > 40) { } else if (value.length > 40) {
return 'Must not exceed 40 characters'; return AppLocalizations.of(context)!.only40charac;
} else if (!RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$") } else if (!RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$")
.hasMatch(value)) { .hasMatch(value)) {
return 'Invalid Characters'; return AppLocalizations.of(context)!.invalid_characters;
} }
return null; return null;
} }
@ -138,7 +139,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} else if (!RegExp(emailRegex).hasMatch(value)) { } else if (!RegExp(emailRegex).hasMatch(value)) {
return 'Invalid Email'; return AppLocalizations.of(context)!.invalid_email;
} }
return null; return null;
} }
@ -157,38 +158,38 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} else if (value.length < 8) { } else if (value.length < 8) {
return 'Password must be at least 8characters'; return AppLocalizations.of(context)!.only8charac;
} }
// Check the length constraint // Check the length constraint
if (value.length < 8 || value.length > 64) { if (value.length < 8 || value.length > 40) {
return 'Password must be between 8 and 64 characters'; return AppLocalizations.of(context)!.password_between_8_to_40;
} }
// Check the regular expression // Check the regular expression
if (!regex.hasMatch(value)) { if (!regex.hasMatch(value)) {
return 'Password contains invalid characters'; return AppLocalizations.of(context)!.password_invalid;
} }
// Track missing constraints // Track missing constraints
List<String> missingConstraints = []; List<String> missingConstraints = [];
if (!hasUppercase.hasMatch(value)) { if (!hasUppercase.hasMatch(value)) {
missingConstraints.add('uppercase letter'); missingConstraints.add(context.translate('uppercase letter','حرف كبير'));
} }
if (!hasLowercase.hasMatch(value)) { if (!hasLowercase.hasMatch(value)) {
missingConstraints.add('lowercase letter'); missingConstraints.add(context.translate('lowercase letter','حرف صغير'));
} }
if (!hasDigit.hasMatch(value)) { if (!hasDigit.hasMatch(value)) {
missingConstraints.add('numeric digit'); missingConstraints.add(context.translate('numeric digit','رقم'));
} }
if (!hasSpecialCharacter.hasMatch(value)) { if (!hasSpecialCharacter.hasMatch(value)) {
missingConstraints.add('special character'); missingConstraints.add(context.translate('special character','رمز خاص'));
} }
// If there are missing constraints, return a consolidated message // If there are missing constraints, return a consolidated message
if (missingConstraints.isNotEmpty) { if (missingConstraints.isNotEmpty) {
return 'At least one ${missingConstraints.join(', ')}'; return context.translate('At least one ${missingConstraints.join(', ')}','${missingConstraints.join(', ')}على الأقل واحد ');
} }
_password = value; // Store the password for confirm password validation _password = value; // Store the password for confirm password validation
@ -203,11 +204,12 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} else if (value.length < 8 || value.length > 40) { } else if (value.length < 8 || value.length > 40) {
return 'Password must be at least 8characters'; return AppLocalizations.of(context)!.password_between_8_to_40;
} else if (!regex.hasMatch(value)) { } else if (!regex.hasMatch(value)) {
return 'Password contains invalid characters'; return AppLocalizations.of(context)!.password_invalid;
} else if (value != _password) { } else if (value != _password) {
return 'Passwords do not match'; return AppLocalizations.of(context)!.password_match;
;
} }
return null; return null;
@ -261,7 +263,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
// Check if the error is due to an invalid or already used email // Check if the error is due to an invalid or already used email
if (e if (e
.toString() .toString()
.contains('The email is invalid or already in use.')) { .contains(AppLocalizations.of(context)!.email_invalid)) {
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
@ -321,6 +323,11 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
} }
} }
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 40,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenheight = MediaQuery.of(context).size.height; double screenheight = MediaQuery.of(context).size.height;
@ -376,7 +383,13 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) {
formState?.validate();
}
});
}, },
); );
}, },
@ -1224,17 +1237,19 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 10, height: 10,
), ),
Center( Center(
child: Container( // child: Container(
height: screenheight / 16, // height: screenheight / 16,
width: screenwidth / 3, // width: screenwidth / 3,
decoration: BoxDecoration( // decoration: BoxDecoration(
image: DecorationImage( // image: DecorationImage(
image: AssetImage( // image: AssetImage(
"assets/splash_screen/logo.png"), // Background image asset // "assets/splash_screen/logo.png"), // Background image asset
fit: BoxFit.fill, // fit: BoxFit.fill,
), // ),
), // ),
)), // )
child: fcscBanner,
),
SizedBox( SizedBox(
height: 20, height: 20,
), ),

View File

@ -273,7 +273,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// Function to validate the DOB field // Function to validate the DOB field
String? _validateDob(String? value) { String? _validateDob(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
final DateTime selectedDate = _selectedDate!; final DateTime selectedDate = _selectedDate!;
@ -281,14 +281,14 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
// Check if the selected date is in the future // Check if the selected date is in the future
if (selectedDate.isAfter(today)) { if (selectedDate.isAfter(today)) {
return 'Date of birth cannot be in the future'; return context.translate('Date of birth cannot be in the future','لا يمكن أن يكون تاريخ الميلاد في المستقبل');
} }
return null; return null;
} }
String? _validateDropdown(String? value) { String? _validateDropdown(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
return null; return null;
} }
@ -657,7 +657,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
enabled: true, enabled: true,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
//RegExp(r"^[a-zA-Z\s]+$"); //RegExp(r"^[a-zA-Z\s]+$");
@ -665,7 +665,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$"); r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
if (!nameRegex.hasMatch(value)) { if (!nameRegex.hasMatch(value)) {
return 'Invalid Characters'; return AppLocalizations.of(context)!.invalid_characters;
} }
return null; return null;
}, },
@ -912,7 +912,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
Padding( Padding(
padding: const EdgeInsets.only(left: 10.0), padding: const EdgeInsets.only(left: 10.0),
child: Text( child: Text(
'Required', context.translate('Required', 'مطلوب'),
style: TextStyle( style: TextStyle(
color: Color(0xFFb22222), color: Color(0xFFb22222),
fontSize: 12, fontSize: 12,
@ -928,7 +928,7 @@ class _ProfileScreenState extends ConsumerState<ProfileScreen> {
final userId = widget.userId; final userId = widget.userId;
final email = _emailController.text; final email = _emailController.text;
context.go('/createNewPw/$userId/$email'); context.push('/createNewPw/$userId/$email');
}, },
child: Text( child: Text(
AppLocalizations.of(context)!.change_password, AppLocalizations.of(context)!.change_password,

View File

@ -24,6 +24,8 @@ import 'package:uae_stat/presentation/routes/bottom_bar_routes/tab_routes/home_r
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';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../components/indicators/locale_provider.dart'; import '../../components/indicators/locale_provider.dart';
import '../../components/my_toggle.dart'; import '../../components/my_toggle.dart';
@ -451,7 +453,7 @@ class LoginRoute extends HookConsumerWidget {
), ),
fontSize: locale?.languageCode == 'ar' ? 12: 18, fontSize: locale?.languageCode == 'ar' ? 12: 18,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
) ),
), ),
6.horizontalSpace, 6.horizontalSpace,
const Icon( const Icon(
@ -473,10 +475,14 @@ class LoginRoute extends HookConsumerWidget {
), ),
validator: (value) { validator: (value) {
final emailRegex =
r'^[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+@[a-zA-Z0-9àèìòùÀÈÌÒÙéàç~!#$%^&*()_+=-{}|;,.?<>]+\.[a-zA-Z]{2,}$';
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return context.translate('Required', 'مطلوب'); return context.translate('Required', 'مطلوب');
} }
return FieldValidator.email()(value); else if (!RegExp(emailRegex).hasMatch(value)) {
return AppLocalizations.of(context)!.invalid_email;
} return null;
}, },
imgPath: MiscIconAssetPath.person, imgPath: MiscIconAssetPath.person,
controller: emailCtl, controller: emailCtl,
@ -487,7 +493,7 @@ class LoginRoute extends HookConsumerWidget {
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 AppLocalizations.of(context)!.only8charac;
} }
return FieldValidator.password(minLength: 8)(text); return FieldValidator.password(minLength: 8)(text);
}, },
@ -668,7 +674,13 @@ class LoginRoute extends HookConsumerWidget {
pathColorWhenOn: Colors.grey.shade300, pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
final formState = formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (formState?.validate() == false) {
formState?.validate();
}
});
}, },
), ),
), ),

View File

@ -140,90 +140,96 @@ class _BookMarkState extends ConsumerState<BookMark> {
} }
/// Show confirmation dialog before removing bookmark /// Show confirmation dialog before removing bookmark
// void showRemoveBookmarkDialog(id) { void showRemoveBookmarkDialog(id) {
// double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
// showDialog( showDialog(
// context: context, context: context,
// barrierDismissible: false, // User must tap button to dismiss dialog barrierDismissible: false, // User must tap button to dismiss dialog
// builder: (context) => AlertDialog( builder: (context) => AlertDialog(
// shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(5.0), // Rounded corners borderRadius: BorderRadius.circular(5.0), // Rounded corners
// ), ),
// contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
// content: Stack( content: Stack(
// children: [ children: [
// Padding( Padding(
// padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
// child: Column( child: Column(
// mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
// children: [ children: [
// SizedBox( SizedBox(
// height: myheight / 30, height: myheight / 30,
// ), ),
// Text( Text(
// context.translate( context.translate(
// 'Are you sure you want to remove this bookmark?', 'Are you sure you want to remove this bookmark?',
// 'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'), 'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'),
// textAlign: TextAlign.center, textAlign: TextAlign.center,
// style: TextStyle( style: TextStyle(
// fontSize: 18, fontSize: 18,
// color: Color(0xFF898C81), color: Color(0xFF898C81),
// ), ),
// ) )
// ], ],
// ), ),
// ), ),
// ], ],
// ), ),
// actions: [ actions: [
// SizedBox(height: 20), SizedBox(height: 20),
// SizedBox( Row(
// width: 100, // Set the desired width mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// child: TextButton( children: [
// onPressed: () => Navigator.pop(context), SizedBox(
// style: TextButton.styleFrom( width: 100, // Set the desired width
// shape: RoundedRectangleBorder( child: TextButton(
// borderRadius: BorderRadius.circular( onPressed: () => Navigator.pop(context),
// 10.0), // Adjust the radius as needed style: TextButton.styleFrom(
// ), shape: RoundedRectangleBorder(
// side: BorderSide( borderRadius: BorderRadius.circular(
// color: Color(0xFFAA8E83), // Set the outline color 10.0), // Adjust the radius as needed
// width: 1, // Set the border width ),
// ), side: BorderSide(
// ), color: Color(0xFFAA8E83), // Set the outline color
// child: Text( width: 1, // Set the border width
// context.translate('No', 'لا'), ),
// style: TextStyle( ),
// color: Color(0xFFAA8E83), child: Text(
// fontSize: 16, context.translate('No', 'لا'),
// ), style: TextStyle(
// ), color: Color(0xFFAA8E83),
// ), fontSize: 16,
// ), ),
// SizedBox( ),
// width: 100, // Set the desired width ),
// child: TextButton( ),
// onPressed: () { SizedBox(
// Navigator.pop(context); width: 100, // Set the desired width
// removeBookmark(id); // Close dialog child: TextButton(
// }, onPressed: () {
// style: TextButton.styleFrom( Navigator.pop(context);
// backgroundColor: Color(0xFFAA8E83), // Set background color removeBookmark(id); // Close dialog
// foregroundColor: Colors.white, },
// shape: RoundedRectangleBorder( style: TextButton.styleFrom(
// borderRadius: BorderRadius.circular(10.0), // Set text color backgroundColor: Color(0xFFAA8E83), // Set background color
// ), foregroundColor: Colors.white,
// ), shape: RoundedRectangleBorder(
// child: Text( borderRadius: BorderRadius.circular(10.0), // Set text color
// context.translate('Yes', 'نعم'), ),
// style: TextStyle(color: Colors.white, fontSize: 16), ),
// ), child: Text(
// ), context.translate('Yes', 'نعم'),
// ), style: TextStyle(color: Colors.white, fontSize: 16),
// ], ),
// ), ),
// ); ),
// } ],
)
],
),
);
}
String colorToHex(Color color) { String colorToHex(Color color) {
return '0xFF${color.red.toRadixString(16).padLeft(2, '0').toUpperCase()}' return '0xFF${color.red.toRadixString(16).padLeft(2, '0').toUpperCase()}'
@ -322,19 +328,31 @@ class _BookMarkState extends ConsumerState<BookMark> {
), ),
), ),
), ),
// GestureDetector(
// onTap: () {
// debugPrint("Icon clicked in: ${data['title']}");
// removeBookmark(data['id']);
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// 'The bookmark is removed successfully',
// ),
// backgroundColor: Colors.green,
// duration: Duration(seconds: 2),
// ),
// );
// },
// child: const Icon(
// Icons.delete,
// color: Colors.black,
// size: 20,
// ),
// ),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
debugPrint("Icon clicked in: ${data['title']}"); debugPrint("Icon clicked in: ${data['title']}");
removeBookmark(data['id']); showRemoveBookmarkDialog(data['id']);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'The bookmark is removed successfully',
),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
}, },
child: const Icon( child: const Icon(
Icons.bookmarks_rounded, Icons.bookmarks_rounded,
@ -342,18 +360,6 @@ class _BookMarkState extends ConsumerState<BookMark> {
size: 20, size: 20,
), ),
), ),
// GestureDetector(
// onTap: () {
// debugPrint("Icon clicked in: ${data['title']}");
// // showRemoveBookmarkDialog(data['id']);
// },
// child: const Icon(
// Icons.bookmarks_rounded,
// color: Colors.black,
// size: 20,
// ),
// ),
], ],
), ),
Text( Text(

View File

@ -13,6 +13,7 @@ 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/config/my_theme.dart'; import 'package:uae_stat/config/my_theme.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/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';
@ -298,7 +299,7 @@ class _EditProfileState extends State<EditProfile> {
// Function to validate the DOB field // Function to validate the DOB field
String? _validateDob(String? value) { String? _validateDob(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
final DateTime selectedDate = _selectedDate!; final DateTime selectedDate = _selectedDate!;
@ -306,14 +307,14 @@ class _EditProfileState extends State<EditProfile> {
// Check if the selected date is in the future // Check if the selected date is in the future
if (selectedDate.isAfter(today)) { if (selectedDate.isAfter(today)) {
return 'Date of birth cannot be in the future'; return context.translate('Date of birth cannot be in the future','لا يمكن أن يكون تاريخ الميلاد في المستقبل');
} }
return null; return null;
} }
String? _validateDropdown(String? value) { String? _validateDropdown(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
return null; return null;
} }
@ -689,7 +690,7 @@ class _EditProfileState extends State<EditProfile> {
enabled: false, enabled: false,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Required'; return context.translate('Required', 'مطلوب');
} }
//RegExp(r"^[a-zA-Z\s]+$"); //RegExp(r"^[a-zA-Z\s]+$");
@ -697,7 +698,7 @@ class _EditProfileState extends State<EditProfile> {
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$", r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$",
); );
if (!nameRegex.hasMatch(value)) { if (!nameRegex.hasMatch(value)) {
return 'Invalid Characters'; return AppLocalizations.of(context)!.invalid_characters;
} }
return null; return null;
}, },
@ -956,7 +957,7 @@ class _EditProfileState extends State<EditProfile> {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
final email = _emailController.text; final email = _emailController.text;
context.go( context.push(
'/createNewPw/$userId/$email?key=editProfile'); '/createNewPw/$userId/$email?key=editProfile');
}, },
child: Text( child: Text(

View File

@ -3,18 +3,11 @@ import 'package:uae_stat/domain/use_cases/language.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';
import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart';
class aboutFCSC extends StatelessWidget { class aboutFCSC extends StatelessWidget {
const aboutFCSC({super.key}); const aboutFCSC({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
return BaseScaffold( return BaseScaffold(
showDivider: true, showDivider: true,
showBackButton: true, showBackButton: true,
@ -86,15 +79,10 @@ class aboutFCSC extends StatelessWidget {
], ],
), ),
), ),
SizedBox(height: MediaQuery.of(context).size.height*0.15),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox( SizedBox(
height: 25, height: 20,
), ),
]), ],),
), ),
), ),
); );

View File

@ -3,18 +3,12 @@ import 'package:uae_stat/domain/use_cases/language.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';
import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart';
class GetStarted extends StatelessWidget { class GetStarted extends StatelessWidget {
const GetStarted({super.key}); const GetStarted({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
return Theme( return Theme(
data: ThemeData( data: ThemeData(
fontFamily: 'Roboto', // Set default font family for this page fontFamily: 'Roboto', // Set default font family for this page
@ -84,12 +78,7 @@ class GetStarted extends StatelessWidget {
SizedBox( SizedBox(
height:MediaQuery.of(context).size.height * 0.12, height:MediaQuery.of(context).size.height * 0.12,
), ),
Align( SizedBox(height: 20,),
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(height: 25,),
], ],
), ),
), ),

View File

@ -6,11 +6,7 @@ import '../../../custom_drawer_routes.dart';
class AppFeatures extends StatelessWidget { class AppFeatures extends StatelessWidget {
AppFeatures({super.key}); AppFeatures({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -205,12 +201,7 @@ class AppFeatures extends StatelessWidget {
], ],
), ),
), ),
SizedBox(height: 25,), SizedBox(height: 20,),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(height: 25,),
], ],
), ),
), ),

View File

@ -1,16 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart';
import '../../../custom_drawer_routes.dart';
class ChangeMyPassword extends StatelessWidget { class ChangeMyPassword extends StatelessWidget {
ChangeMyPassword({super.key}); const ChangeMyPassword({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -116,7 +109,7 @@ class ChangeMyPassword extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF414042), color: Color(0xFF414042),
fontFamily: 'Roboto' fontFamily: 'Roboto',
),), ),),
TextSpan(text:context.translate( TextSpan(text:context.translate(
' link at the bottom.', ' link at the bottom.',
@ -295,9 +288,9 @@ class ChangeMyPassword extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF414042), color: Color(0xFF414042),
fontFamily: 'Roboto' fontFamily: 'Roboto',
),), ),),
TextSpan(text: context.translate('button',''),) TextSpan(text: context.translate('button',''),),
], ],
), ),
), ),
@ -360,14 +353,7 @@ class ChangeMyPassword extends StatelessWidget {
], ],
), ),
), ),
SizedBox(height: 20,),
SizedBox(height: 25,),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(height: 25,),
], ],
), ),

View File

@ -1,16 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart';
import '../../../custom_drawer_routes.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class EditMyProfile extends StatelessWidget { class EditMyProfile extends StatelessWidget {
EditMyProfile({super.key}); const EditMyProfile({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -457,14 +453,7 @@ class EditMyProfile extends StatelessWidget {
], ],
), ),
), ),
SizedBox(height: 20,),
SizedBox(height: 25,),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(height: 25,),
], ],
), ),

View File

@ -1,16 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart';
import '../../../custom_drawer_routes.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
class HowUseTheApp extends StatelessWidget { class HowUseTheApp extends StatelessWidget {
HowUseTheApp({super.key}); const HowUseTheApp({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -203,14 +199,7 @@ class HowUseTheApp extends StatelessWidget {
], ],
), ),
SizedBox( SizedBox(
height: 25, height: 20,
),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(
height: 25,
), ),
], ],
), ),

View File

@ -1,16 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../../../custom_drawer_routes.dart';
class Purpose extends StatelessWidget { class Purpose extends StatelessWidget {
Purpose({super.key}); const Purpose({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -151,14 +145,7 @@ class Purpose extends StatelessWidget {
], ],
), ),
SizedBox( SizedBox(
height: 40, height: 20,
),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(
height: 25,
), ),
], ],
), ),

View File

@ -1,16 +1,11 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../../../custom_drawer_routes.dart';
class StayUpdate extends StatelessWidget { class StayUpdate extends StatelessWidget {
StayUpdate({super.key}); const StayUpdate({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -91,14 +86,7 @@ class StayUpdate extends StatelessWidget {
], ],
), ),
SizedBox( SizedBox(
height: 150, height: 20,
),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(
height: 25,
), ),
], ],
), ),

View File

@ -1,16 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
import '../../../../../../infrastructure/services/img_asset_paths/banner_asset_path.dart';
import '../../../custom_drawer_routes.dart';
class WhoUseTheApp extends StatelessWidget { class WhoUseTheApp extends StatelessWidget {
WhoUseTheApp({super.key}); const WhoUseTheApp({super.key});
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Theme( return Theme(
@ -141,15 +135,9 @@ class WhoUseTheApp extends StatelessWidget {
), ),
], ],
), ),
SizedBox( SizedBox(
height: 50, height: 20,
),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(
height: 25,
), ),
], ],
), ),

View File

@ -3,18 +3,12 @@ import 'package:go_router/go_router.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.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';
import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.dart';
class aboutTheApp extends StatelessWidget { class aboutTheApp extends StatelessWidget {
const aboutTheApp({super.key}); const aboutTheApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
return BaseScaffold( return BaseScaffold(
showDivider: true, showDivider: true,
showBackButton: true, showBackButton: true,
@ -67,7 +61,7 @@ class aboutTheApp extends StatelessWidget {
border: Border( border: Border(
bottom: BorderSide( bottom: BorderSide(
color: Colors.grey.shade300, color: Colors.grey.shade300,
width: 0.5), // Grey bottom line width: 0.5,), // Grey bottom line
), ),
), ),
child: ListTile( child: ListTile(
@ -87,17 +81,12 @@ class aboutTheApp extends StatelessWidget {
trailing: Icon(Icons.keyboard_arrow_right), trailing: Icon(Icons.keyboard_arrow_right),
shape: Border( shape: Border(
bottom: BorderSide( bottom: BorderSide(
color: Colors.black, width: 3), // Grey bottom line color: Colors.black, width: 3,), // Grey bottom line
), ),
), ),
), ),
Spacer(),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox( SizedBox(
height: 25, height: 20,
), ),
], ],
), ),

View File

@ -1,7 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.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/banner_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 FAQPage extends StatefulWidget { class FAQPage extends StatefulWidget {
@ -12,11 +10,7 @@ class FAQPage extends StatefulWidget {
} }
class _FAQPageState extends State<FAQPage> { class _FAQPageState extends State<FAQPage> {
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BaseScaffold( return BaseScaffold(
@ -44,14 +38,7 @@ class _FAQPageState extends State<FAQPage> {
radius: Radius.circular(10), radius: Radius.circular(10),
interactive: true, interactive: true,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: QuestionAnswerScrollView(),
children: [
QuestionAnswerScrollView(),
SizedBox(height: 25,),
fcscBanner,
SizedBox(height: 25,),
],
),
), ),
), ),
), ),
@ -83,24 +70,24 @@ class QuestionAnswerScrollView extends StatelessWidget {
text: text:
'Yes, the app is strictly for registered and approved users. To access the data:\n\n', 'Yes, the app is strictly for registered and approved users. To access the data:\n\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: text:
' 1. You need to sign up using the Register Now option on the login screen.\n', ' 1. You need to sign up using the Register Now option on the login screen.\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: ' 2. Your registration must be approved by the admin.\n', text: ' 2. Your registration must be approved by the admin.\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: text:
" 3. Once approved, you can log in to access the app's features and datasets.\n\nGuest access is not available for this application.\n ", " 3. Once approved, you can log in to access the app's features and datasets.\n\nGuest access is not available for this application.\n ",
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
], ],
), ),
@ -112,24 +99,24 @@ class QuestionAnswerScrollView extends StatelessWidget {
text: text:
'نعم، التطبيق مخصص فقط للمستخدمين المسجلين والمعتمدين. للوصول إلى البيانات:\n\n', 'نعم، التطبيق مخصص فقط للمستخدمين المسجلين والمعتمدين. للوصول إلى البيانات:\n\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: text:
' 1. يجب عليك التسجيل باستخدام خيار "التسجيل الآن" في شاشة تسجيل الدخول.\n', ' 1. يجب عليك التسجيل باستخدام خيار "التسجيل الآن" في شاشة تسجيل الدخول.\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: ' 2. يجب أن يتم الموافقة على تسجيلك من قبل المسؤول.\n', text: ' 2. يجب أن يتم الموافقة على تسجيلك من قبل المسؤول.\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
TextSpan( TextSpan(
text: text:
" بعد الموافقة، يمكنك تسجيل الدخول للوصول إلى ميزات التطبيق وبياناته.\n\n لا يتوفر الوصول للزوار في هذا التطبيق.\n", ' بعد الموافقة، يمكنك تسجيل الدخول للوصول إلى ميزات التطبيق وبياناته.\n\n لا يتوفر الوصول للزوار في هذا التطبيق.\n',
style: TextStyle( style: TextStyle(
color: Colors.grey, fontSize: 16, fontFamily: 'Roboto'), color: Colors.grey, fontSize: 16, fontFamily: 'Roboto',),
), ),
], ],
), ),
@ -140,7 +127,7 @@ class QuestionAnswerScrollView extends StatelessWidget {
'question-ar': 'كيف يمكنني التنقل عبر التطبيق؟', 'question-ar': 'كيف يمكنني التنقل عبر التطبيق؟',
'answer': 'answer':
'• Use the main categories on the homepage (e.g., Economy, Environment) to access subcategories and detailed KPIs.\n• Drill down into specific metrics or graphical views by tapping on a KPI.\n• Access additional features like Bookmarks or Profile through the navigation bar.\n', '• Use the main categories on the homepage (e.g., Economy, Environment) to access subcategories and detailed KPIs.\n• Drill down into specific metrics or graphical views by tapping on a KPI.\n• Access additional features like Bookmarks or Profile through the navigation bar.\n',
'answer-ar': '•استخدم الفئات الرئيسية الموجودة على الصفحة الرئيسية (مثل: الاقتصاد، البيئة) للوصول إلى الفئات الفرعية ومؤشرات الأداء الرئيسية التفصيلية •\n\ قم بالتعمق في مؤشرات معينة أو عرض الرسوم البيانية من خلال النقر على مؤشر الأداء الرئيسي (KPI). \n • للوصول إلى ميزات إضافية مثل الإشارات المرجعية أو الملف الشخصي، استخدم شريط التنقل.\n', 'answer-ar': '•استخدم الفئات الرئيسية الموجودة على الصفحة الرئيسية (مثل: الاقتصاد، البيئة) للوصول إلى الفئات الفرعية ومؤشرات الأداء الرئيسية التفصيلية •\n قم بالتعمق في مؤشرات معينة أو عرض الرسوم البيانية من خلال النقر على مؤشر الأداء الرئيسي (KPI). \n • للوصول إلى ميزات إضافية مثل الإشارات المرجعية أو الملف الشخصي، استخدم شريط التنقل.\n',
}, },
{ {
'question': 'What types of data are available?', 'question': 'What types of data are available?',

View File

@ -11,11 +11,7 @@ class UsingFeatures extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 56,
alignment: Alignment.center,
);
return BaseScaffold( return BaseScaffold(
showDivider: true, showDivider: true,
showBackButton: true, showBackButton: true,
@ -237,14 +233,6 @@ class UsingFeatures extends StatelessWidget {
), ),
), ),
), ),
Spacer(),
Align(
alignment: Alignment.bottomCenter,
child: fcscBanner,
),
SizedBox(
height: 30,
),
], ],
), ),
), ),