user guide
This commit is contained in:
commit
73f1e2e62e
@ -294,6 +294,7 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:uae_stat/presentation/Screens/auth_verification/registration.dart';
|
||||
import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart';
|
||||
|
||||
import '../domain/use_cases/preferences_use_case.dart';
|
||||
@ -304,6 +305,7 @@ import '../presentation/Screens/auth_verification/otp_verification.dart';
|
||||
import '../presentation/Screens/profilepage.dart';
|
||||
import '../presentation/routes/auth_routes/login_route.dart';
|
||||
import '../presentation/routes/bottom_bar_routes/tab_routes/home_route.dart';
|
||||
import '../presentation/routes/drawer_routes/Drawer Items/edit_profile.dart';
|
||||
import '../presentation/routes/drawer_routes/Drawer Items/feedback.dart';
|
||||
import '../presentation/routes/drawer_routes/Drawer Items/user_guide/features.dart';
|
||||
import '../presentation/routes/drawer_routes/Drawer Items/user_guide/user_guide.dart';
|
||||
@ -314,12 +316,16 @@ final GoRouter router = GoRouter(
|
||||
GoRoute(
|
||||
path: '/',
|
||||
//builder: (context, state) => LoginRoute(),
|
||||
builder: (context, state) => MyHomePage(),
|
||||
builder: (context, state) => LoginRoute(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/myhomepage',
|
||||
builder: (context, state) => MyHomePage(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/register',
|
||||
builder: (context, state) => RegisterScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/mailverification',
|
||||
builder: (context, state) => EmailVerificationScreen(
|
||||
@ -331,10 +337,11 @@ final GoRouter router = GoRouter(
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/changepassword',
|
||||
builder: (context, state) => Changepassword(
|
||||
userId: '',
|
||||
),
|
||||
path: '/changepassword/:userId',
|
||||
builder: (context, state) {
|
||||
final userId = state.pathParameters['userId']!;
|
||||
return Changepassword(userId: userId);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/createNewPw/:userId/:email',
|
||||
@ -359,10 +366,11 @@ final GoRouter router = GoRouter(
|
||||
),
|
||||
//Sub route
|
||||
GoRoute(
|
||||
path: '/profile',
|
||||
builder: (context, state) => ProfileScreen(
|
||||
userId: '',
|
||||
),
|
||||
path: '/profile/:userId',
|
||||
builder: (context, state) {
|
||||
final userId = state.pathParameters['userId']!;
|
||||
return ProfileScreen(userId: userId);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/user-guide',
|
||||
@ -382,10 +390,13 @@ final GoRouter router = GoRouter(
|
||||
// return ManageUserRouter(title: title);
|
||||
// },
|
||||
// ),
|
||||
GoRoute(
|
||||
path: '/editProfile',
|
||||
builder: (context, state) => EditProfile(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/manageuser',
|
||||
builder: (context, state) => ManageUserRouter(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ class _ResetPasswordScreenState extends State<Changepassword> {
|
||||
//print('userDetails ->: $userData');
|
||||
if (userData['items'].isNotEmpty) {
|
||||
// Email exists; retrieve user ID
|
||||
final userId = userData['items'][0]['id'];
|
||||
// final userId = userData['items'][0]['id'];
|
||||
|
||||
// Proceed with OTP request
|
||||
final otpResponse = await http.post(
|
||||
@ -87,17 +87,15 @@ class _ResetPasswordScreenState extends State<Changepassword> {
|
||||
);
|
||||
|
||||
// Navigate to the Email Verification screen
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => EmailVerificationScreen(
|
||||
email: email,
|
||||
userId: widget.userId, // Pass user ID to the next screen
|
||||
otp: otp,
|
||||
otpId: otpId,
|
||||
sendVerificationCode: sendVerificationCode,
|
||||
),
|
||||
),
|
||||
context.go(
|
||||
'/mailverification',
|
||||
extra: {
|
||||
'email': email,
|
||||
'userId': widget.userId, // Pass user ID to the next screen
|
||||
'otp': otp,
|
||||
'otpId': otpId,
|
||||
'sendVerificationCode': sendVerificationCode,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
final error =
|
||||
@ -132,6 +130,12 @@ class _ResetPasswordScreenState extends State<Changepassword> {
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
print(widget.userId);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_emailController.dispose();
|
||||
|
||||
@ -156,8 +156,8 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscurePassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
@ -184,8 +184,8 @@ class _ConfirmPasswordState extends State<ConfirmPassword> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscureConfirmPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
@ -38,13 +38,50 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
||||
}
|
||||
|
||||
String? _validateNewPassword(String? value) {
|
||||
// Define the regular expression for allowed characters
|
||||
final regex = RegExp(
|
||||
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
|
||||
|
||||
// Define regular expressions for password complexity requirements
|
||||
final hasUppercase = RegExp(r'[A-Z]');
|
||||
final hasLowercase = RegExp(r'[a-z]');
|
||||
final hasDigit = RegExp(r'\d');
|
||||
final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]');
|
||||
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'New password is required';
|
||||
} else if (value.length < 6) {
|
||||
return 'Password must be at least 6 characters';
|
||||
} else if (value.length < 8 || value.length > 64) {
|
||||
return 'Password must be between 8 and 64 characters';
|
||||
} else if (value == _oldPassword) {
|
||||
return 'New password must not be the same as the old password';
|
||||
}
|
||||
|
||||
// Check the regular expression for allowed characters
|
||||
if (!regex.hasMatch(value)) {
|
||||
return 'Password contains invalid characters';
|
||||
}
|
||||
|
||||
// Track missing constraints
|
||||
List<String> missingConstraints = [];
|
||||
|
||||
if (!hasUppercase.hasMatch(value)) {
|
||||
missingConstraints.add('uppercase letter');
|
||||
}
|
||||
if (!hasLowercase.hasMatch(value)) {
|
||||
missingConstraints.add('lowercase letter');
|
||||
}
|
||||
if (!hasDigit.hasMatch(value)) {
|
||||
missingConstraints.add('numeric digit');
|
||||
}
|
||||
if (!hasSpecialCharacter.hasMatch(value)) {
|
||||
missingConstraints.add('special character');
|
||||
}
|
||||
|
||||
// If there are missing constraints, return a consolidated message
|
||||
if (missingConstraints.isNotEmpty) {
|
||||
return 'At least one ${missingConstraints.join(', ')}';
|
||||
}
|
||||
|
||||
_newPassword = value; // Store for validation
|
||||
return null;
|
||||
}
|
||||
@ -184,8 +221,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscureOldPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
@ -208,8 +245,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscureNewPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
@ -231,8 +268,8 @@ class _CreateNewPwState extends State<CreateNewPw> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscureConfirmPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:pocketbase/pocketbase.dart';
|
||||
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||
import 'package:uae_stat/presentation/Screens/profilepage.dart';
|
||||
|
||||
import '../../../infrastructure/services/pocketbase_service.dart';
|
||||
import '../../routes/auth_routes/login_route.dart';
|
||||
|
||||
class RegisterScreen extends StatefulWidget {
|
||||
@ -135,27 +136,77 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
return null;
|
||||
}
|
||||
|
||||
// String? _validatePassword(String? value) {
|
||||
// // Define the regular expression for allowed characters
|
||||
// final regex = RegExp(
|
||||
// r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
|
||||
//
|
||||
// if (value == null || value.isEmpty) {
|
||||
// return 'Required';
|
||||
// } else if (value.length < 8) {
|
||||
// return 'Password must be at least 8characters';
|
||||
// }
|
||||
//
|
||||
// // Check the length constraint
|
||||
// if (value.length < 8 || value.length > 40) {
|
||||
// return 'Password must be between 8 and 64 characters';
|
||||
// }
|
||||
//
|
||||
// // Check the regular expression
|
||||
// if (!regex.hasMatch(value)) {
|
||||
// return 'Password contains invalid characters';
|
||||
// }
|
||||
//
|
||||
// _password = value; // Store the password for confirm password validation
|
||||
// return null;
|
||||
// }
|
||||
|
||||
String? _validatePassword(String? value) {
|
||||
// Define the regular expression for allowed characters
|
||||
final regex = RegExp(
|
||||
r'^[A-Za-z0-9~!@#$%^&*()_+=[\]{}|;:,.<>?/-àèìòùáéíóúÀÈÌÒÙÁÉÍÓÚ]*$');
|
||||
|
||||
// Define regular expressions for password complexity requirements
|
||||
final hasUppercase = RegExp(r'[A-Z]');
|
||||
final hasLowercase = RegExp(r'[a-z]');
|
||||
final hasDigit = RegExp(r'\d');
|
||||
final hasSpecialCharacter = RegExp(r'[~!@#$%^&*()_+=[\]{}|;:,.<>?/-]');
|
||||
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Required';
|
||||
} else if (value.length < 8) {
|
||||
return 'Password must be at least 8characters';
|
||||
}
|
||||
|
||||
// Check the length constraint
|
||||
if (value.length < 8 || value.length > 40) {
|
||||
if (value.length < 8 || value.length > 64) {
|
||||
return 'Password must be between 8 and 64 characters';
|
||||
}
|
||||
|
||||
// Check the regular expression
|
||||
// Check the regular expression for allowed characters
|
||||
if (!regex.hasMatch(value)) {
|
||||
return 'Password contains invalid characters';
|
||||
}
|
||||
|
||||
// Track missing constraints
|
||||
List<String> missingConstraints = [];
|
||||
|
||||
if (!hasUppercase.hasMatch(value)) {
|
||||
missingConstraints.add('uppercase letter');
|
||||
}
|
||||
if (!hasLowercase.hasMatch(value)) {
|
||||
missingConstraints.add('lowercase letter');
|
||||
}
|
||||
if (!hasDigit.hasMatch(value)) {
|
||||
missingConstraints.add('numeric digit');
|
||||
}
|
||||
if (!hasSpecialCharacter.hasMatch(value)) {
|
||||
missingConstraints.add('special character');
|
||||
}
|
||||
|
||||
// If there are missing constraints, return a consolidated message
|
||||
if (missingConstraints.isNotEmpty) {
|
||||
return 'At least one ${missingConstraints.join(', ')}';
|
||||
}
|
||||
|
||||
_password = value; // Store the password for confirm password validation
|
||||
return null;
|
||||
}
|
||||
@ -182,6 +233,30 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
if (isChecked) {
|
||||
try {
|
||||
final existingUsers = await pb.collection('users').getList(
|
||||
filter: 'email="${_emailController.text}"',
|
||||
);
|
||||
|
||||
if (existingUsers.items.isNotEmpty) {
|
||||
// Email already exists
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('Email Exists'),
|
||||
content: Text(
|
||||
'Email ID already exists. Please use a different email.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
return; // Stop registration process
|
||||
}
|
||||
final adminAuth = await pb.admins
|
||||
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
|
||||
|
||||
@ -194,6 +269,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
'password': _passwordController.text,
|
||||
'passwordConfirm': _passwordController.text,
|
||||
'status': 'Pending',
|
||||
'role': 'user',
|
||||
}, headers: {
|
||||
'Authorization': adminToken
|
||||
});
|
||||
@ -207,13 +283,6 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
registrationSuccess = true;
|
||||
registrationFailed = false; // Show success message on success
|
||||
});
|
||||
|
||||
// Navigate to ProfileScreen after successful registration
|
||||
// Navigator.pushReplacement(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => ProfileScreen(userId: response.id)),
|
||||
// );
|
||||
} else {
|
||||
throw Exception('User registration failed: missing user ID');
|
||||
}
|
||||
@ -275,7 +344,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
buildIconContainer(Icons.report, Color(0xFF7DAFBC)),
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
"Your registration is pending for Admin Approval.",
|
||||
"Your registration is pending for verification",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
@ -284,7 +353,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
"Access will be granted once your account is approved.",
|
||||
"Kindly verify your mail to proceed further.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
@ -293,14 +362,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: () => {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => LoginRoute()
|
||||
|
||||
//ProfileScreen(userId: userID)
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
context.go('/');
|
||||
},
|
||||
child: Text(
|
||||
'Go to Login',
|
||||
@ -455,8 +518,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscurePassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
@ -487,8 +550,8 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(
|
||||
_obscureConfirmPassword
|
||||
? Icons.visibility
|
||||
: Icons.visibility_off,
|
||||
? Icons.visibility_off
|
||||
: Icons.visibility,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onPressed: () {
|
||||
@ -628,12 +691,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Navigate to LoginRoute
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LoginRoute()),
|
||||
// MaterialPageRoute(builder: (context) => LoginRoute(userId: userID)),
|
||||
);
|
||||
context.go('/');
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
@ -53,6 +53,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
final TextEditingController _emailController = TextEditingController();
|
||||
// To keep track of the selected date
|
||||
DateTime? _selectedDate;
|
||||
String? role;
|
||||
|
||||
// Date format for the display
|
||||
final DateFormat _dateFormat = DateFormat('yyyy-MM-dd');
|
||||
@ -148,6 +149,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
setState(() {
|
||||
_usernameController.text = userDetailsResponse.data['username'] ?? '';
|
||||
_emailController.text = userDetailsResponse.data['email'] ?? '';
|
||||
role = userDetailsResponse.data['role'] ?? '';
|
||||
});
|
||||
} catch (e) {
|
||||
print('Error fetching user details: $e');
|
||||
@ -271,7 +273,11 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
_resetFormFields();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Profile updated successfully!")));
|
||||
context.go('/myhomepage');
|
||||
if (role == 'admin') {
|
||||
context.go('/manageuser');
|
||||
} else {
|
||||
context.go('/myhomepage');
|
||||
}
|
||||
} catch (error) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Failed to update profile: $error")));
|
||||
@ -306,7 +312,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back_ios_new, color: Colors.black),
|
||||
onPressed: () {
|
||||
context.go('/myhomepage');
|
||||
context.go('/');
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
@ -315,7 +321,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
context.go('/');
|
||||
},
|
||||
child: Text(
|
||||
'Logout',
|
||||
style: TextStyle(color: Colors.orange),
|
||||
@ -425,8 +433,9 @@ class _ProfileScreenState extends State<ProfileScreen> {
|
||||
}
|
||||
|
||||
//RegExp(r"^[a-zA-Z\s]+$");
|
||||
final nameRegex =
|
||||
RegExp(r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$");
|
||||
final nameRegex = RegExp(
|
||||
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
|
||||
|
||||
if (!nameRegex.hasMatch(value)) {
|
||||
return 'Invalid Characters';
|
||||
}
|
||||
@ -698,7 +707,7 @@ class ConfirmationDialog extends StatelessWidget {
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "name",
|
||||
text: "Name",
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.w700), // Bold for "name"
|
||||
),
|
||||
@ -706,7 +715,7 @@ class ConfirmationDialog extends StatelessWidget {
|
||||
text: " or ",
|
||||
),
|
||||
TextSpan(
|
||||
text: "date of birth",
|
||||
text: "Date of birth",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700), // Bold for "date of birth"
|
||||
),
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import 'package:external_repos/external_repos.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
@ -38,8 +37,8 @@ class ThemedFormField extends HookWidget {
|
||||
onPressed: () => isObscured.value = !isObscured.value,
|
||||
icon: Icon(
|
||||
isObscured.value
|
||||
? Icons.visibility_outlined
|
||||
: Icons.visibility_off_outlined,
|
||||
? Icons.visibility_off_outlined
|
||||
: Icons.visibility_outlined,
|
||||
color: const Color(0xff9EA2A9),
|
||||
),
|
||||
);
|
||||
|
||||
@ -740,206 +740,206 @@ class _LoginRouteState extends State<LoginRoute> {
|
||||
),
|
||||
),
|
||||
);
|
||||
// <<<<<<< HEAD
|
||||
// =======
|
||||
// final form = Form(
|
||||
// key: formKey,
|
||||
// child: Column(
|
||||
// children: [
|
||||
// ThemedFormField(
|
||||
// hintText: context.translate(
|
||||
// 'Email',
|
||||
// 'بريد إلكتروني',
|
||||
// ),
|
||||
// validator: FieldValidator.email(),
|
||||
// imgPath: MiscIconAssetPath.person,
|
||||
// controller: emailCtl,
|
||||
// ),
|
||||
// 15.verticalSpace,
|
||||
// ThemedFormField(
|
||||
// validator: (text) {
|
||||
// if (text!.length < 8) {
|
||||
// return 'The password must be at least 8 characters';
|
||||
// }
|
||||
// return FieldValidator.password(minLength: 8)(text);
|
||||
// },
|
||||
// hintText: context.translate(
|
||||
// 'Password',
|
||||
// 'كلمة المرور',
|
||||
// ),
|
||||
// imgPath: MiscIconAssetPath.lock,
|
||||
// controller: pwCtl,
|
||||
// isObscurable: true,
|
||||
// ),
|
||||
// // 6.verticalSpace,
|
||||
// Align(
|
||||
// alignment: AlignmentDirectional.topEnd,
|
||||
// child: forgotPwBtn,
|
||||
// ),
|
||||
// 10.verticalSpace,
|
||||
// loginBtn,
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// final helloAndPleaseLoginTexts = Column(
|
||||
// children: [
|
||||
// Text(
|
||||
// context.translate(
|
||||
// 'Hello Again!',
|
||||
// 'مرحبا مجددا!',
|
||||
// ),
|
||||
// style: TextStyle(
|
||||
// fontFamily: context.translate(
|
||||
// 'Roboto',
|
||||
// 'NotoKufi',
|
||||
// ),
|
||||
// fontSize: 40,
|
||||
// fontWeight: FontWeight.w300,
|
||||
// ),
|
||||
// ),
|
||||
// 10.verticalSpace,
|
||||
// Text(
|
||||
// context.translate(
|
||||
// 'Please login to access UAE’s key official statistics',
|
||||
// 'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة',
|
||||
// ),
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontFamily: context.translate(
|
||||
// 'Roboto',
|
||||
// 'NotoKufi',
|
||||
// ),
|
||||
// fontSize: 18,
|
||||
// color: const Color(0xff898C81),
|
||||
// fontWeight: FontWeight.w700,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// final dontHaveAnAccountRegisterBtn = TextButton(
|
||||
// onPressed: () => {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(builder: (context) => RegisterScreen()),
|
||||
// ),
|
||||
// },
|
||||
// child: Text.rich(
|
||||
// textAlign: TextAlign.center,
|
||||
// TextSpan(
|
||||
// style: TextStyle(
|
||||
// fontFamily: context.translate(
|
||||
// 'Roboto',
|
||||
// 'NotoKufi',
|
||||
// ),
|
||||
// fontSize: 18,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// ),
|
||||
// children: [
|
||||
// TextSpan(
|
||||
// text: context.translate(
|
||||
// 'Don\'t have an account? ',
|
||||
// 'ليس لديك حساب؟',
|
||||
// ),
|
||||
// style: const TextStyle(
|
||||
// color: Color(0xff898C81),
|
||||
// ),
|
||||
// ),
|
||||
// const TextSpan(
|
||||
// text: ' ',
|
||||
// ),
|
||||
// TextSpan(
|
||||
// text: context.translate(
|
||||
// 'Register Now',
|
||||
// 'سجل الان',
|
||||
// ),
|
||||
// style: TextStyle(
|
||||
// color: MyTheme.topicColor(IndicatorTopic.economy).shade600,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// final continueAsGuestBtn = SizedBox(
|
||||
// width: double.infinity,
|
||||
// child: ElevatedButton(
|
||||
// onPressed: () => context
|
||||
// .go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
||||
// style: ButtonStyle(
|
||||
// shape: WidgetStatePropertyAll(
|
||||
// RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(10),
|
||||
// ),
|
||||
// ),
|
||||
// padding: const WidgetStatePropertyAll(
|
||||
// EdgeInsets.symmetric(vertical: 10.5),
|
||||
// ),
|
||||
// textStyle: WidgetStatePropertyAll(
|
||||
// TextStyle(
|
||||
// fontFamily: context.translate(
|
||||
// 'Roboto',
|
||||
// 'NotoKufi',
|
||||
// ),
|
||||
// fontSize: 16,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// backgroundColor: WidgetStatePropertyAll(
|
||||
// MyTheme.topicColor(IndicatorTopic.environment),
|
||||
// ),
|
||||
// foregroundColor: const WidgetStatePropertyAll(
|
||||
// Colors.white,
|
||||
// ),
|
||||
// ),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// Text(
|
||||
// context.translate(
|
||||
// 'Continue as Guest',
|
||||
// 'استمر كضيف',
|
||||
// ),
|
||||
// ),
|
||||
// 6.horizontalSpace,
|
||||
// const Icon(Icons.chevron_right_outlined),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// final fcscBanner = Image.asset(
|
||||
// BannerAssetPath.fcsc,
|
||||
// height: 56,
|
||||
// );
|
||||
// final screenWidth = MediaQuery.of(context).size.width;
|
||||
// final listViewHorizontalPadding =
|
||||
// screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2;
|
||||
// final scaffoldBody = ListView(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: listViewHorizontalPadding.toDouble(),
|
||||
// ),
|
||||
// children: [
|
||||
// 36.verticalSpace,
|
||||
// const Align(
|
||||
// alignment: AlignmentDirectional.topEnd,
|
||||
// child: LangToggle(),
|
||||
// ),
|
||||
// 16.verticalSpace,
|
||||
// helloAndPleaseLoginTexts,
|
||||
// 42.verticalSpace,
|
||||
// form,
|
||||
// 20.verticalSpace,
|
||||
// dontHaveAnAccountRegisterBtn,
|
||||
// 36.verticalSpace,
|
||||
// continueAsGuestBtn,
|
||||
// 72.verticalSpace,
|
||||
// fcscBanner,
|
||||
// ],
|
||||
// );
|
||||
// final bgScaffold = Scaffold(
|
||||
// backgroundColor: Colors.white,
|
||||
// body: SafeArea(child: scaffoldBody),
|
||||
// );
|
||||
// return bgScaffold;
|
||||
// >>>>>>> b0c5ebce3deb7da2aa24b0ea5ffe684df7dfb7bf
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
final form = Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
ThemedFormField(
|
||||
hintText: context.translate(
|
||||
'Email',
|
||||
'بريد إلكتروني',
|
||||
),
|
||||
validator: FieldValidator.email(),
|
||||
imgPath: MiscIconAssetPath.person,
|
||||
controller: emailCtl,
|
||||
),
|
||||
15.verticalSpace,
|
||||
ThemedFormField(
|
||||
validator: (text) {
|
||||
if (text!.length < 8) {
|
||||
return 'The password must be at least 8 characters';
|
||||
}
|
||||
return FieldValidator.password(minLength: 8)(text);
|
||||
},
|
||||
hintText: context.translate(
|
||||
'Password',
|
||||
'كلمة المرور',
|
||||
),
|
||||
imgPath: MiscIconAssetPath.lock,
|
||||
controller: pwCtl,
|
||||
isObscurable: true,
|
||||
),
|
||||
// 6.verticalSpace,
|
||||
Align(
|
||||
alignment: AlignmentDirectional.topEnd,
|
||||
child: forgotPwBtn,
|
||||
),
|
||||
10.verticalSpace,
|
||||
loginBtn,
|
||||
],
|
||||
),
|
||||
);
|
||||
final helloAndPleaseLoginTexts = Column(
|
||||
children: [
|
||||
Text(
|
||||
context.translate(
|
||||
'Hello Again!',
|
||||
'مرحبا مجددا!',
|
||||
),
|
||||
style: TextStyle(
|
||||
fontFamily: context.translate(
|
||||
'Roboto',
|
||||
'NotoKufi',
|
||||
),
|
||||
fontSize: 40,
|
||||
fontWeight: FontWeight.w300,
|
||||
),
|
||||
),
|
||||
10.verticalSpace,
|
||||
Text(
|
||||
context.translate(
|
||||
'Please login to access UAE’s key official statistics',
|
||||
'يرجى تسجيل الدخول للوصول إلى الإحصاءات الرسمية الرئيسية لدولة الإمارات العربية المتحدة',
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: context.translate(
|
||||
'Roboto',
|
||||
'NotoKufi',
|
||||
),
|
||||
fontSize: 18,
|
||||
color: const Color(0xff898C81),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
final dontHaveAnAccountRegisterBtn = TextButton(
|
||||
onPressed: () => {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => RegisterScreen()),
|
||||
),
|
||||
},
|
||||
child: Text.rich(
|
||||
textAlign: TextAlign.center,
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontFamily: context.translate(
|
||||
'Roboto',
|
||||
'NotoKufi',
|
||||
),
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: context.translate(
|
||||
'Don\'t have an account? ',
|
||||
'ليس لديك حساب؟',
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Color(0xff898C81),
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: ' ',
|
||||
),
|
||||
TextSpan(
|
||||
text: context.translate(
|
||||
'Register Now',
|
||||
'سجل الان',
|
||||
),
|
||||
style: TextStyle(
|
||||
color: MyTheme.topicColor(IndicatorTopic.economy).shade600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
final continueAsGuestBtn = SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () => context
|
||||
.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
||||
style: ButtonStyle(
|
||||
shape: WidgetStatePropertyAll(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
padding: const WidgetStatePropertyAll(
|
||||
EdgeInsets.symmetric(vertical: 10.5),
|
||||
),
|
||||
textStyle: WidgetStatePropertyAll(
|
||||
TextStyle(
|
||||
fontFamily: context.translate(
|
||||
'Roboto',
|
||||
'NotoKufi',
|
||||
),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
MyTheme.topicColor(IndicatorTopic.environment),
|
||||
),
|
||||
foregroundColor: const WidgetStatePropertyAll(
|
||||
Colors.white,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
context.translate(
|
||||
'Continue as Guest',
|
||||
'استمر كضيف',
|
||||
),
|
||||
),
|
||||
6.horizontalSpace,
|
||||
const Icon(Icons.chevron_right_outlined),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
final fcscBanner = Image.asset(
|
||||
BannerAssetPath.fcsc,
|
||||
height: 56,
|
||||
);
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
final listViewHorizontalPadding =
|
||||
screenWidth < 700 ? 30 : 30 + (screenWidth - 700) / 2;
|
||||
final scaffoldBody = ListView(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: listViewHorizontalPadding.toDouble(),
|
||||
),
|
||||
children: [
|
||||
36.verticalSpace,
|
||||
const Align(
|
||||
alignment: AlignmentDirectional.topEnd,
|
||||
child: LangToggle(),
|
||||
),
|
||||
16.verticalSpace,
|
||||
helloAndPleaseLoginTexts,
|
||||
42.verticalSpace,
|
||||
form,
|
||||
20.verticalSpace,
|
||||
dontHaveAnAccountRegisterBtn,
|
||||
36.verticalSpace,
|
||||
continueAsGuestBtn,
|
||||
72.verticalSpace,
|
||||
fcscBanner,
|
||||
],
|
||||
);
|
||||
final bgScaffold = Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
body: SafeArea(child: scaffoldBody),
|
||||
);
|
||||
return bgScaffold;
|
||||
>>>>>>> b0c5ebce3deb7da2aa24b0ea5ffe684df7dfb7bf
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,72 +262,72 @@ class _EditProfileState extends State<EditProfile> {
|
||||
}
|
||||
|
||||
void showConfirmationDialog(BuildContext context) async {
|
||||
final result = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => const ConfirmationDialog(),
|
||||
);
|
||||
// final result = await showDialog<bool>(
|
||||
// context: context,
|
||||
// builder: (context) => const ConfirmationDialog(),
|
||||
// );
|
||||
|
||||
if (result == true) {
|
||||
// Validate only the country field
|
||||
if (_validateDropdown(_selectedCountry) == null) {
|
||||
try {
|
||||
String userID = userId;
|
||||
// if (result == true) {
|
||||
// Validate only the country field
|
||||
if (_validateDropdown(_selectedCountry) == null) {
|
||||
try {
|
||||
String userID = userId;
|
||||
|
||||
print("ShowConfirmationuserID - $userID ");
|
||||
// Retrieve data from the country/region field
|
||||
String countryRegion =
|
||||
_selectedCountry ?? ''; // Ensure the country is selected
|
||||
print("ShowConfirmationuserID - $userID ");
|
||||
// Retrieve data from the country/region field
|
||||
String countryRegion =
|
||||
_selectedCountry ?? ''; // Ensure the country is selected
|
||||
|
||||
// Create a multipart request
|
||||
final uri =
|
||||
Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
|
||||
final request = http.MultipartRequest('PATCH', uri);
|
||||
// Create a multipart request
|
||||
final uri =
|
||||
Uri.parse('${_pb.baseUrl}/api/collections/users/records/$userID');
|
||||
final request = http.MultipartRequest('PATCH', uri);
|
||||
|
||||
// Add fields to the request
|
||||
request.fields['country_region'] =
|
||||
countryRegion; // Only update country here
|
||||
// Add fields to the request
|
||||
request.fields['country_region'] =
|
||||
countryRegion; // Only update country here
|
||||
|
||||
// If profile image exists, add it
|
||||
if (_profileImage != null) {
|
||||
request.files.add(await http.MultipartFile.fromPath(
|
||||
'avatar',
|
||||
_profileImage!.path,
|
||||
));
|
||||
}
|
||||
// If profile image exists, add it
|
||||
if (_profileImage != null) {
|
||||
request.files.add(await http.MultipartFile.fromPath(
|
||||
'avatar',
|
||||
_profileImage!.path,
|
||||
));
|
||||
}
|
||||
|
||||
// Add headers (e.g., authorization)
|
||||
request.headers['Authorization'] = 'Bearer ${_pb.authStore.token}';
|
||||
// Add headers (e.g., authorization)
|
||||
request.headers['Authorization'] = 'Bearer ${_pb.authStore.token}';
|
||||
|
||||
// Send the request
|
||||
final response = await request.send();
|
||||
print(response);
|
||||
// Send the request
|
||||
final response = await request.send();
|
||||
print(response);
|
||||
|
||||
// Handle response
|
||||
if (response.statusCode == 200) {
|
||||
_resetFormFields();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Profile updated successfully!")),
|
||||
);
|
||||
context.go('/myhomepage');
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
Text("Failed to update profile: ${response.statusCode}")),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle response
|
||||
if (response.statusCode == 200) {
|
||||
_resetFormFields();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Failed to update profile: $error")),
|
||||
SnackBar(content: Text("Profile updated successfully!")),
|
||||
);
|
||||
context.go('/myhomepage');
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
Text("Failed to update profile: ${response.statusCode}")),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Show an error if the country is invalid
|
||||
setState(() {
|
||||
showError = true;
|
||||
});
|
||||
} catch (error) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text("Failed to update profile: $error")),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Show an error if the country is invalid
|
||||
setState(() {
|
||||
showError = true;
|
||||
});
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
void _resetFormFields() {
|
||||
@ -462,7 +462,7 @@ class _EditProfileState extends State<EditProfile> {
|
||||
|
||||
//RegExp(r"^[a-zA-Z\s]+$");
|
||||
final nameRegex = RegExp(
|
||||
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF]+$");
|
||||
r"^[a-zA-Z0-9'\-\u0627\u0639~\u00C0-\u00FF\s]+$");
|
||||
if (!nameRegex.hasMatch(value)) {
|
||||
return 'Invalid Characters';
|
||||
}
|
||||
|
||||
@ -177,6 +177,7 @@ class _ManageUserRouterState extends State<ManageUserRouter> {
|
||||
body: {
|
||||
'status': newStatus, // Update status
|
||||
'verified': newStatus == 'Approved' ? true : false,
|
||||
'reviewed': true,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ class BaseScaffold extends StatelessWidget {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: title, actions: [
|
||||
IconButton(onPressed: () {}, icon: Icon(Icons.toggle_off_outlined)),
|
||||
],),
|
||||
]),
|
||||
drawer: Drawer(
|
||||
child: ListView(
|
||||
children: [
|
||||
@ -39,19 +39,19 @@ class BaseScaffold extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: mywidth / 8,
|
||||
child: Image(
|
||||
image: AssetImage('assets/logos/fcsc.png'),),),
|
||||
image: AssetImage('assets/logos/fcsc.png'))),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
InkWell(
|
||||
onTap: () => context.go('/profile'),
|
||||
onTap: () => context.go('/editProfile'),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: mywidth / 8,
|
||||
child: Image(
|
||||
image: AssetImage(
|
||||
'assets/edit_profile/profile.png',),),),
|
||||
'assets/edit_profile/profile.png'))),
|
||||
SizedBox(
|
||||
width: mywidth / 20,
|
||||
),
|
||||
@ -59,12 +59,12 @@ class BaseScaffold extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Mohammad'),
|
||||
Text('Mohammad@fcsc.com'),
|
||||
Text('Mohammad@fcsc.com')
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -73,20 +73,10 @@ class BaseScaffold extends StatelessWidget {
|
||||
height: myheight / 15,
|
||||
width: mywidth / 15,
|
||||
child: Image(
|
||||
image: AssetImage('assets/icons/drawer/message.png'),),),
|
||||
image: AssetImage('assets/icons/drawer/message.png'))),
|
||||
title: Text('Feedback'),
|
||||
onTap: () => context.go('/feedback'),
|
||||
),
|
||||
//user Guide
|
||||
ListTile(
|
||||
leading: SizedBox(
|
||||
height: myheight / 15,
|
||||
width: mywidth / 15,
|
||||
child: Image(
|
||||
image: AssetImage('assets/icons/drawer/book.png'),),),
|
||||
title: Text('User Guide'),
|
||||
onTap: () => context.go('/user-guide'),
|
||||
),
|
||||
ListTile(
|
||||
leading: SizedBox(
|
||||
height: myheight / 15,
|
||||
|
||||
@ -27,7 +27,7 @@ class ResetPwRoute extends HookConsumerWidget {
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () => doObscureOld.value = !doObscureOld.value,
|
||||
icon: Icon(
|
||||
doObscureOld.value ? Icons.visibility : Icons.visibility_off,
|
||||
doObscureOld.value ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -51,7 +51,7 @@ class ResetPwRoute extends HookConsumerWidget {
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () => doObscureNew.value = !doObscureNew.value,
|
||||
icon: Icon(
|
||||
doObscureNew.value ? Icons.visibility : Icons.visibility_off,
|
||||
doObscureNew.value ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -72,7 +72,7 @@ class ResetPwRoute extends HookConsumerWidget {
|
||||
onPressed: () =>
|
||||
doObscureConfirmNew.value = !doObscureConfirmNew.value,
|
||||
icon: Icon(
|
||||
doObscureConfirmNew.value ? Icons.visibility : Icons.visibility_off,
|
||||
doObscureConfirmNew.value ? Icons.visibility_off : Icons.visibility,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
16
pubspec.lock
16
pubspec.lock
@ -1244,6 +1244,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
syncfusion_flutter_charts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: syncfusion_flutter_charts
|
||||
sha256: b2a9f0fd585ef96c081c37697b46d48d3b0f3fe6bddc5011a3542962814fafa8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "28.1.33"
|
||||
syncfusion_flutter_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: syncfusion_flutter_core
|
||||
sha256: b1071c698b502e7d55f91352a8b82d42f49f4c96e523d43b6fade5d5af710048
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "28.1.33"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -54,6 +54,7 @@ dependencies:
|
||||
provider: ^6.1.2
|
||||
mailer: ^6.2.0
|
||||
image_picker: ^1.1.2
|
||||
syncfusion_flutter_charts: ^28.1.33
|
||||
|
||||
dependency_overrides:
|
||||
fading_edge_scrollview: ^4.1.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user