loader added all page

This commit is contained in:
venbaittech 2025-03-15 17:32:05 +05:30
parent ef761a8d0a
commit f6de75f0c8
15 changed files with 2461 additions and 1440 deletions

View File

@ -20,12 +20,12 @@ if (project.hasProperty('google-services.json')) {
def flutterVersionCode = localProperties.getProperty("flutter.versionCode") def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
if (flutterVersionCode == null) { if (flutterVersionCode == null) {
flutterVersionCode = "36" flutterVersionCode = "37"
} }
def flutterVersionName = localProperties.getProperty("flutter.versionName") def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) { if (flutterVersionName == null) {
flutterVersionName = "1.0.35" flutterVersionName = "1.0.36"
} }
def keystorePropertiesFile = rootProject.file("key.properties") def keystorePropertiesFile = rootProject.file("key.properties")
@ -72,6 +72,7 @@ android {
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.release signingConfig signingConfigs.release
minifyEnabled true // Enable code shrinking for smaller APKs minifyEnabled true // Enable code shrinking for smaller APKs
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }

View File

@ -182,12 +182,38 @@ class _UaenumberWidgetState extends ConsumerState<uaenumberWidget> {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchData(localeCode); fetchData(localeCode);
}); });
double myheight = MediaQuery.of(context).size.height; double myheight = MediaQuery.of(context).size.height;
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
if (isLoading) {
return Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin:
EdgeInsets.symmetric(horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor: Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
);
} else if (filteredData.isEmpty) {
return Center(child: Text("No data available"));
}
return Padding( return Padding(
padding: padding:
const EdgeInsets.only(left: 16.0, right: 16.0, top: 5.0, bottom: 5.0), const EdgeInsets.only(left: 16.0, right: 16.0, top: 5.0, bottom: 5.0),

View File

@ -3,10 +3,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart'; import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/config/api_config.dart'; import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/config/my_router.dart'; import 'package:uae_stat/config/my_router.dart';
import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/data/p_auth_repo.dart';
import 'package:uae_stat/infrastructure/services/img_asset_paths/banner_asset_path.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';
@ -34,6 +36,7 @@ class CreateNewPw extends ConsumerStatefulWidget {
class _CreateNewPwState extends ConsumerState<CreateNewPw> { class _CreateNewPwState extends ConsumerState<CreateNewPw> {
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
bool isLoading = false;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
bool _obscureOldPassword = true; bool _obscureOldPassword = true;
bool _obscureNewPassword = true; bool _obscureNewPassword = true;
@ -139,6 +142,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
Future<void> updatePassword( Future<void> updatePassword(
String userId, String oldPassword, String newPassword) async { String userId, String oldPassword, String newPassword) async {
try { try {
setState(() {
isLoading = true;
});
// Authenticate as admin // Authenticate as admin
final adminAuth = await _pb.admins final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
@ -164,6 +170,11 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
headers: headers, headers: headers,
); );
setState(() {
isLoading = false;
_isPasswordUpdated = true;
});
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content: Text(
@ -172,9 +183,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
), ),
); );
setState(() { print('_isPasswordUpdated $_isPasswordUpdated');
_isPasswordUpdated = true; // Toggle UI on success
});
// Navigator.push( // Navigator.push(
// context, // context,
@ -183,6 +192,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
// ); // );
} else { } else {
setState(() { setState(() {
isLoading = false;
_formKey.currentState?.validate(); _formKey.currentState?.validate();
}); });
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@ -195,6 +205,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
return; return;
} }
} catch (e) { } catch (e) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Failed to update password: $e'), content: Text('Failed to update password: $e'),
@ -204,6 +217,15 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
} }
} }
final PAuthRepo _authRepo = PAuthRepo();
Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await _authRepo.logout();
prefs.clear();
context.go('/login'); // Redirect to login after logout
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height; double screenHeight = MediaQuery.of(context).size.height;
@ -217,14 +239,35 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: SingleChildScrollView( body: Stack(children: [
SingleChildScrollView(
child: SafeArea( child: SafeArea(
child: _isPasswordUpdated child: _isPasswordUpdated
? _buildSuccessContent(screenHeight, screenWidth) ? _buildSuccessContent(screenHeight, screenWidth)
: _buildPasswordForm(ref, screenHeight, screenWidth), : _buildPasswordForm(ref, screenHeight, screenWidth),
), ),
), ),
); if (isLoading)
Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
]));
} }
Widget _buildPasswordForm( Widget _buildPasswordForm(
@ -626,8 +669,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
} }
Widget _buildSuccessContent(double screenHeight, double screenWidth) { Widget _buildSuccessContent(double screenHeight, double screenWidth) {
print('IN');
return Padding( return Padding(
padding: const EdgeInsets.all(20.0), padding: EdgeInsets.all(20.0),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@ -647,16 +691,14 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
), ),
SizedBox(height: 20), SizedBox(height: 20),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () => logout(context),
context.go('/login');
},
style: ButtonStyle( style: ButtonStyle(
shape: WidgetStatePropertyAll( shape: WidgetStatePropertyAll(
RoundedRectangleBorder( RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
), ),
padding: const WidgetStatePropertyAll( padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 10.5), EdgeInsets.symmetric(vertical: 10.5),
), ),
textStyle: WidgetStatePropertyAll( textStyle: WidgetStatePropertyAll(
@ -675,7 +717,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
// surfaceTintColor: MaterialStatePropertyAll( // surfaceTintColor: MaterialStatePropertyAll(
// MyTheme.economy[800], // MyTheme.economy[800],
// ), // ),
foregroundColor: const WidgetStatePropertyAll( foregroundColor: WidgetStatePropertyAll(
Colors.white, Colors.white,
), ),
), ),
@ -697,12 +739,12 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
), ),
), ),
6.horizontalSpace, 6.horizontalSpace,
const Icon(Icons.chevron_right_outlined, color: Colors.white), Icon(Icons.chevron_right_outlined, color: Colors.white),
], ],
), ),
), ),
SizedBox(height: screenHeight / 2.2), SizedBox(height: screenHeight / 2.2),
Spacer(), // Spacer(),
Center( Center(
// child: Container( // child: Container(
// height: 40, // height: 40,

View File

@ -0,0 +1,632 @@
import 'package:external_repos/external_repos.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uae_stat/config/api_config.dart';
import 'package:uae_stat/config/connectivity_provider.dart';
import 'package:uae_stat/config/my_router.dart';
import 'package:uae_stat/domain/use_cases/language.dart';
import 'package:uae_stat/infrastructure/data/p_auth_repo.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/presentation/Screens/profilepage.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/space.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:uae_stat/config/my_theme.dart';
class ForgotPassword extends ConsumerStatefulWidget {
final String userId;
const ForgotPassword({Key? key, required this.userId});
@override
ConsumerState<ForgotPassword> createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends ConsumerState<ForgotPassword> {
final _pb = PocketBase(apiUrl);
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;
bool _isPasswordUpdated = false; // Variable to toggle UI
bool hasValidated = false;
String? _oldPassword;
String? _newPassword;
String? _confirmPassword;
final fcscBanner = Image.asset(
BannerAssetPath.fcsc,
height: 40,
);
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 AppLocalizations.of(context)!.new_password_required;
} else if (value.length < 8 || value.length > 64) {
return AppLocalizations.of(context)!.password_between_8_to_40;
} else if (value == _oldPassword) {
// return 'New password must not be the same as the old password';
return AppLocalizations.of(context)!.new_password_not_same_as_old;
}
// Check the regular expression for allowed characters
if (!regex.hasMatch(value)) {
return AppLocalizations.of(context)!.password_invalid;
}
// Track missing constraints
List<String> missingConstraints = [];
if (!hasUppercase.hasMatch(value)) {
missingConstraints.add(context.translate('uppercase letter', 'حرف كبير'));
}
if (!hasLowercase.hasMatch(value)) {
missingConstraints.add(context.translate('lowercase letter', 'حرف صغير'));
}
if (!hasDigit.hasMatch(value)) {
missingConstraints.add(context.translate('numeric digit', 'رقم'));
}
if (!hasSpecialCharacter.hasMatch(value)) {
missingConstraints.add(context.translate('special character', 'رمز خاص'));
}
// If there are missing constraints, return a consolidated message
if (missingConstraints.isNotEmpty) {
return context.translate('At least one ${missingConstraints.join(', ')}',
'${missingConstraints.join(', ')}على الأقل واحد ');
}
_newPassword = value; // Store for validation
return null;
}
String? _validateConfirmPassword(String? value) {
if (value == null || value.isEmpty) {
return AppLocalizations.of(context)!.confirm_new_password;
} else if (value != _newPassword) {
// return 'Passwords do not match';
return AppLocalizations.of(context)!.password_match;
}
_confirmPassword = value;
return null;
}
Future<void> updatePassword(
String userId, String oldPassword, String newPassword) async {
try {
setState(() {
isLoading = true;
});
// Authenticate as admin
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final token = adminAuth.token;
final headers = {
'Authorization': 'Bearer $token',
};
// Update password
await _pb.collection('users').update(
userId,
body: {
'password': newPassword,
'passwordConfirm': newPassword,
},
headers: headers,
);
setState(() {
isLoading = false;
_isPasswordUpdated = true;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(AppLocalizations.of(context)!.password_update_successfully),
backgroundColor: Colors.green,
),
);
print('_isPasswordUpdated $_isPasswordUpdated');
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => ProfileScreen(userId: userId)),
// );
} catch (e) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to update password: $e'),
backgroundColor: Colors.red,
),
);
}
}
final PAuthRepo _authRepo = PAuthRepo();
Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
await _authRepo.logout();
prefs.clear();
context.go('/login'); // Redirect to login after logout
}
@override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
double screenWidth = MediaQuery.of(context).size.width;
ref.listen<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.push('/internetcheck');
}
});
return Scaffold(
backgroundColor: Colors.white,
body: Stack(children: [
SingleChildScrollView(
child: SafeArea(
child: _isPasswordUpdated
? _buildSuccessContent(screenHeight, screenWidth)
: _buildPasswordForm(ref, screenHeight, screenWidth),
),
),
if (isLoading)
Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
]));
}
Widget _buildPasswordForm(
WidgetRef ref, double screenHeight, double screenWidth) {
final passwordLocale = ref.watch(localeProvider);
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
children: [
// SizedBox(height: screenHeight / 7),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
context.pop();
},
child: Container(
margin: EdgeInsets.only(
top: 10,
left: 1,
bottom: 16,
right: 1), // Add margin for positioning
child: Icon(
// Icons.close,
Icons.arrow_back_ios,
size: 24, // Icon size
color: Colors.black, // Icon color
),
),
), // Left icon
Consumer(
builder: (context, ref, _) {
final locale = ref.watch(localeProvider); // Current locale
return MyToggle(
isOn: locale?.languageCode == 'en',
knobTextWhenOn: 'ع',
knobTextWhenOff: 'EN',
pathColorWhenOn: Colors.grey.shade300,
pathColorWhenOff: Colors.grey.shade300,
onTap: () {
print('has validated $hasValidated');
final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated && formState?.validate() == false) {
print('has validated $hasValidated');
formState?.validate();
}
});
},
);
},
), // Right icon
],
),
SizedBox(height: screenHeight / 30),
Text(
// "Create New Password",
AppLocalizations.of(context)!.create_new_password,
style: TextStyle(
fontSize: passwordLocale?.languageCode == 'ar' ? 24 : 26,
fontWeight: FontWeight.w300,
),
),
SizedBox(height: 10),
Text.rich(
TextSpan(
children: [
TextSpan(
text: context.translate(
'Your New Password Must Be Different\n',
'يجب أن تكون كلمة المرور الجديدة مختلفة\n',
),
style: TextStyle(
fontSize:
passwordLocale?.languageCode == 'ar' ? 14 : 15,
fontWeight: FontWeight.w700,
color: Color(0xFF898C81)),
),
TextSpan(
text: context.translate('from Previously Used Password',
'عن كلمة المرور المستخدمة سابقًا'),
style: TextStyle(
fontSize:
passwordLocale?.languageCode == 'ar' ? 14 : 15,
color: Color(0xFF898C81),
fontWeight: FontWeight.w700),
),
],
),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
TextFormField(
obscureText: _obscureNewPassword,
decoration: InputDecoration(
// hintText: 'Enter new password',
hintText: AppLocalizations.of(context)!.enter_new_password,
// prefixIcon: Icon(Icons.lock, color: Colors.blue),
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontWeight: FontWeight.w400,
fontFamily: 'Roboto'),
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional.only(
start: 16,
end: 10,
),
child: Image.asset(
MiscIconAssetPath.lock,
fit: BoxFit.fitHeight,
height: 25,
width: 25,
color: MyTheme.topicColor(IndicatorTopic.economy).shade300,
),
),
suffixIcon: IconButton(
// icon: Icon(
// _obscureNewPassword
// ? Icons.visibility_off
// : Icons.visibility,
// color: Colors.blue,
// ),
icon: Image.asset(
_obscureNewPassword
? MiscIconAssetPath.visibilityOff
: MiscIconAssetPath.visibleOn,
color: Color(
0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly.
width: 24,
height: 24,
),
onPressed: () {
setState(() {
_obscureNewPassword = !_obscureNewPassword;
});
},
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color:
MyTheme.topicColor(IndicatorTopic.economy).shade400,
width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Colors.deepPurple, width: 2), // Focused border
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Color(0xFFb22222), width: 1), // Error border
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Color(0xFFb22222),
width: 1), // Match the error color
),
),
validator: _validateNewPassword,
),
SizedBox(height: screenHeight / 35),
TextFormField(
obscureText: _obscureConfirmPassword,
decoration: InputDecoration(
// hintText: 'Confirm new password',
hintText: AppLocalizations.of(context)!.confirm_new_password,
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontWeight: FontWeight.w400,
fontFamily: 'Roboto'),
prefixIconConstraints: const BoxConstraints(
maxWidth: 25 + 16 + 10,
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional.only(
start: 16,
end: 10,
),
child: Image.asset(
MiscIconAssetPath.lock,
fit: BoxFit.fitHeight,
height: 25,
width: 25,
color: MyTheme.topicColor(IndicatorTopic.economy).shade300,
),
),
suffixIcon: IconButton(
// icon: Icon(
// _obscureConfirmPassword
// ? Icons.visibility_off
// : Icons.visibility,
// color: Colors.blue,
// ),
icon: Image.asset(
_obscureConfirmPassword
? MiscIconAssetPath.visibilityOff
: MiscIconAssetPath.visibleOn,
color: Color(
0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly.
width: 24,
height: 24,
),
onPressed: () {
setState(() {
_obscureConfirmPassword = !_obscureConfirmPassword;
});
},
),
// border: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color:
MyTheme.topicColor(IndicatorTopic.economy).shade400,
width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Colors.deepPurple, width: 2), // Focused border
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Color(0xFFb22222), width: 1), // Error border
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Color(0xFFb22222),
width: 1), // Match the error color
),
),
validator: _validateConfirmPassword,
),
SizedBox(height: screenHeight / 35),
SizedBox(
width: screenWidth / 1.1,
child: ElevatedButton(
onPressed: () async {
setState(() {
hasValidated = true;
});
if ((_formKey.currentState?.validate() ?? false)) {
await updatePassword(
widget.userId,
_oldPassword ?? '',
_newPassword ?? '',
);
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.brown[300],
padding: EdgeInsets.symmetric(horizontal: 80, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppLocalizations.of(context)!.save,
style: TextStyle(
fontSize:
passwordLocale?.languageCode == 'ar' ? 14 : 18,
color: Colors.white),
),
SizedBox(width: 2),
Icon(
Icons.arrow_forward_ios,
color: Colors.white,
size: 18,
),
],
),
),
),
SizedBox(height: screenHeight / 5),
Center(
// child: Container(
// height: screenHeight / 16,
// width: screenWidth / 2.5,
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage("assets/splash_screen/logo.png"),
// fit: BoxFit.fill,
// ),
// ),
// ),
child: fcscBanner,
),
],
),
),
);
}
Widget _buildSuccessContent(double screenHeight, double screenWidth) {
print('IN');
return Padding(
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: screenHeight / 8),
Icon(Icons.check_circle_outlined, color: Color(0xFF8AC681), size: 80),
SizedBox(height: 20),
Text(
// "Password Changed Successfully",
AppLocalizations.of(context)!.password_changed_successfully,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Color(0xFF414042),
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () => logout(context),
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 10.5),
),
textStyle: WidgetStatePropertyAll(
TextStyle(
fontFamily: context.translate(
'Roboto',
'NotoKufi',
),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
backgroundColor: WidgetStatePropertyAll(
MyTheme.topicColor(IndicatorTopic.social),
),
// surfaceTintColor: MaterialStatePropertyAll(
// MyTheme.economy[800],
// ),
foregroundColor: WidgetStatePropertyAll(
Colors.white,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.translate(
'Login',
'تسجيل الدخول',
),
style: TextStyle(
fontFamily: context.translate(
'Roboto',
'Roboto',
),
fontSize: 17,
fontWeight: FontWeight.w500,
),
),
6.horizontalSpace,
Icon(Icons.chevron_right_outlined, color: Colors.white),
],
),
),
SizedBox(height: screenHeight / 2.2),
// Spacer(),
Center(
// child: Container(
// height: 40,
// width: screenWidth / 2.5,
// decoration: BoxDecoration(
// image: DecorationImage(
// image: AssetImage("assets/splash_screen/logo.png"),
// fit: BoxFit.fill,
// ),
// ),
// ),
child: fcscBanner,
),
],
),
);
}
}

View File

@ -24,6 +24,7 @@ class RegisterScreen extends ConsumerStatefulWidget {
} }
class _RegisterScreenState extends ConsumerState<RegisterScreen> { class _RegisterScreenState extends ConsumerState<RegisterScreen> {
bool isLoading = false;
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController(); final _usernameController = TextEditingController();
final _emailController = TextEditingController(); final _emailController = TextEditingController();
@ -225,6 +226,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (_formKey.currentState?.validate() ?? false) { if (_formKey.currentState?.validate() ?? false) {
if (isChecked) { if (isChecked) {
setState(() { setState(() {
isLoading = true;
isRegistering = true; // Disable the button isRegistering = true; // Disable the button
}); });
try { try {
@ -254,6 +256,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
registrationSuccess = true; registrationSuccess = true;
registrationFailed = false; // Show success message on success registrationFailed = false; // Show success message on success
isRegistering = false; isRegistering = false;
isLoading = false;
}); });
// Navigate to ProfileScreen after successful registration // Navigate to ProfileScreen after successful registration
@ -263,9 +266,14 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
// builder: (context) => ProfileScreen(userId: response.id)), // builder: (context) => ProfileScreen(userId: response.id)),
// ); // );
} else { } else {
isLoading = false;
throw Exception('User registration failed: missing user ID'); throw Exception('User registration failed: missing user ID');
} }
} catch (e) { } catch (e) {
setState(() {
isLoading = false;
});
// 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()
@ -383,7 +391,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
child: SafeArea( child: SafeArea(
child: Scaffold( child: Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: SingleChildScrollView( body: Stack(children: [
SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
Align( Align(
@ -402,7 +411,9 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
pathColorWhenOff: Colors.grey.shade300, pathColorWhenOff: Colors.grey.shade300,
onTap: () { onTap: () {
final formState = _formKey.currentState; final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale(); ref
.read(localeProvider.notifier)
.toggleLocale();
Future.delayed(Duration(milliseconds: 100), () { Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated && if (hasValidated &&
formState?.validate() == false) { formState?.validate() == false) {
@ -459,8 +470,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
), ),
), ),
child: Text( child: Text(
context.translate( context.translate('Go to Login',
'Go to Login', 'اذهب إلى تسجيل الدخول'), 'اذهب إلى تسجيل الدخول'),
style: TextStyle( style: TextStyle(
color: Colors.white, // Text color color: Colors.white, // Text color
), ),
@ -489,7 +500,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox(height: screenheight / 8), SizedBox(height: screenheight / 8),
buildIconContainer(Icons.report, Colors.red), buildIconContainer(
Icons.report, Colors.red),
SizedBox(height: 20), SizedBox(height: 20),
Text( Text(
context.translate( context.translate(
@ -550,7 +562,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
key: _formKey, key: _formKey,
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
SizedBox(height: screenheight / 60), SizedBox(height: screenheight / 60),
Text( Text(
@ -566,7 +579,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
AppLocalizations.of(context)! AppLocalizations.of(context)!
.register_details, .register_details,
style: TextStyle( style: TextStyle(
fontSize: context.translate(18.0, 14.0), fontSize:
context.translate(18.0, 14.0),
color: const Color(0xff898C81), color: const Color(0xff898C81),
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@ -586,7 +600,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
decoration: InputDecoration( decoration: InputDecoration(
// hintText: _showHints[0] ? 'Username' : null, // hintText: _showHints[0] ? 'Username' : null,
hintText: _showHints[0] hintText: _showHints[0]
? AppLocalizations.of(context)! ? AppLocalizations.of(
context)!
.register_name .register_name
: null, : null,
prefixIconConstraints: prefixIconConstraints:
@ -595,7 +610,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2), maxHeight: 25 + (8 * 2),
), ),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsetsDirectional padding:
const EdgeInsetsDirectional
.only( .only(
start: 16, start: 16,
end: 10, end: 10,
@ -606,7 +622,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25, height: 25,
width: 25, width: 25,
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade300, .shade300,
), ),
), ),
@ -622,7 +639,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10), BorderRadius.circular(10),
borderSide: BorderSide( borderSide: BorderSide(
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade400, .shade400,
width: 1), // Enabled border width: 1), // Enabled border
), ),
@ -652,8 +670,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '', counterText: '',
hintStyle: TextStyle( hintStyle: TextStyle(
color: Color(0xFFC3C6CB), color: Color(0xFFC3C6CB),
fontSize: fontSize: registerLocale
registerLocale?.languageCode == ?.languageCode ==
'ar' 'ar'
? 14 ? 14
: 16, : 16,
@ -679,7 +697,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
decoration: InputDecoration( decoration: InputDecoration(
// hintText: 'Enter your email', // hintText: 'Enter your email',
hintText: _showHints[1] hintText: _showHints[1]
? AppLocalizations.of(context)! ? AppLocalizations.of(
context)!
.enter_your_email .enter_your_email
: null, : null,
// _showHints[1] ? 'Enter your email' : null, // _showHints[1] ? 'Enter your email' : null,
@ -689,7 +708,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2), maxHeight: 25 + (8 * 2),
), ),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsetsDirectional padding:
const EdgeInsetsDirectional
.only( .only(
start: 16, start: 16,
end: 10, end: 10,
@ -700,7 +720,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 20, height: 20,
width: 25, width: 25,
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade100, .shade100,
), ),
), ),
@ -711,7 +732,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10), BorderRadius.circular(10),
borderSide: BorderSide( borderSide: BorderSide(
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade400, .shade400,
width: 1), width: 1),
), ),
@ -741,8 +763,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '', counterText: '',
hintStyle: TextStyle( hintStyle: TextStyle(
color: Color(0xFFC3C6CB), color: Color(0xFFC3C6CB),
fontSize: fontSize: registerLocale
registerLocale?.languageCode == ?.languageCode ==
'ar' 'ar'
? 14 ? 14
: 16, : 16,
@ -771,7 +793,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
obscureText: _obscurePassword, obscureText: _obscurePassword,
decoration: InputDecoration( decoration: InputDecoration(
hintText: _showHints[2] hintText: _showHints[2]
? AppLocalizations.of(context)! ? AppLocalizations.of(
context)!
.enter_your_password .enter_your_password
: null, : null,
// _showHints[2] ? 'Enter your password' : null, // _showHints[2] ? 'Enter your password' : null,
@ -781,7 +804,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2), maxHeight: 25 + (8 * 2),
), ),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsetsDirectional padding:
const EdgeInsetsDirectional
.only( .only(
start: 16, start: 16,
end: 10, end: 10,
@ -792,7 +816,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25, height: 25,
width: 25, width: 25,
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade300, .shade300,
), ),
), ),
@ -813,7 +838,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
_obscurePassword _obscurePassword
? MiscIconAssetPath ? MiscIconAssetPath
.visibilityOff .visibilityOff
: MiscIconAssetPath.visibleOn, : MiscIconAssetPath
.visibleOn,
color: Color( color: Color(
0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly.
@ -834,7 +860,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10), BorderRadius.circular(10),
borderSide: BorderSide( borderSide: BorderSide(
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade400, .shade400,
width: 1), width: 1),
), ),
@ -865,8 +892,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '', counterText: '',
hintStyle: TextStyle( hintStyle: TextStyle(
color: Color(0xFFC3C6CB), color: Color(0xFFC3C6CB),
fontSize: fontSize: registerLocale
registerLocale?.languageCode == ?.languageCode ==
'ar' 'ar'
? 14 ? 14
: 16, : 16,
@ -886,12 +913,15 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
left: 30, left: 30,
right: 30), right: 30),
child: TextFormField( child: TextFormField(
controller: _confirmpasswordController, controller:
_confirmpasswordController,
// focusNode: _focusNodes[3], // focusNode: _focusNodes[3],
obscureText: _obscureConfirmPassword, obscureText:
_obscureConfirmPassword,
decoration: InputDecoration( decoration: InputDecoration(
hintText: _showHints[3] hintText: _showHints[3]
? AppLocalizations.of(context)! ? AppLocalizations.of(
context)!
.register_Confirm_password .register_Confirm_password
: null, : null,
// _showHints[3] ? 'Confirm password' : null, // _showHints[3] ? 'Confirm password' : null,
@ -901,7 +931,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2), maxHeight: 25 + (8 * 2),
), ),
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsetsDirectional padding:
const EdgeInsetsDirectional
.only( .only(
start: 16, start: 16,
end: 10, end: 10,
@ -912,7 +943,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25, height: 25,
width: 25, width: 25,
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade300, .shade300,
), ),
), ),
@ -922,7 +954,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
_obscureConfirmPassword _obscureConfirmPassword
? MiscIconAssetPath ? MiscIconAssetPath
.visibilityOff .visibilityOff
: MiscIconAssetPath.visibleOn, : MiscIconAssetPath
.visibleOn,
color: Color( color: Color(
0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly. 0xFF9EA2A9), // Apply color if needed, but keep in mind `Image.asset` might not support color directly.
@ -944,7 +977,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10), BorderRadius.circular(10),
borderSide: BorderSide( borderSide: BorderSide(
color: MyTheme.topicColor( color: MyTheme.topicColor(
IndicatorTopic.economy) IndicatorTopic
.economy)
.shade400, .shade400,
width: 1), width: 1),
), ),
@ -974,8 +1008,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '', counterText: '',
hintStyle: TextStyle( hintStyle: TextStyle(
color: Color(0xFFC3C6CB), color: Color(0xFFC3C6CB),
fontSize: fontSize: registerLocale
registerLocale?.languageCode == ?.languageCode ==
'ar' 'ar'
? 14 ? 14
: 16, : 16,
@ -1024,7 +1058,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding:
const EdgeInsets.only(
top: 0, top: 0,
), ),
child: Text.rich( child: Text.rich(
@ -1035,7 +1070,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
.agree, .agree,
// text: 'I agree to ', // text: 'I agree to ',
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w500, fontWeight:
FontWeight.w500,
fontSize: registerLocale fontSize: registerLocale
?.languageCode == ?.languageCode ==
'ar' 'ar'
@ -1052,31 +1088,34 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
..onTap = () => ..onTap = () =>
context.push( context.push(
'/terms&conditions'), '/terms&conditions'),
text: AppLocalizations.of( text: AppLocalizations
context)! .of(context)!
.terms_conditions, .terms_conditions,
// text: 'Terms & Conditions', // text: 'Terms & Conditions',
style: TextStyle( style: TextStyle(
fontSize: registerLocale fontSize:
registerLocale
?.languageCode == ?.languageCode ==
'ar' 'ar'
? 12 ? 12
: 14, : 14,
fontWeight: fontWeight:
FontWeight.bold, FontWeight
color: .bold,
Color(0xFF985400), color: Color(
0xFF985400),
// Makes the text bold // Makes the text bold
// decoration: // decoration:
// TextDecoration.underline, // TextDecoration.underline,
decorationColor: decorationColor:
Color(0xFF985400), Color(
0xFF985400),
decorationThickness: decorationThickness:
1), 1),
), ),
TextSpan( TextSpan(
text: AppLocalizations.of( text: AppLocalizations
context)! .of(context)!
.t_and, .t_and,
style: TextStyle( style: TextStyle(
color: Color( color: Color(
@ -1089,30 +1128,34 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
..onTap = () => ..onTap = () =>
context.push( context.push(
'/privacy_policy'), '/privacy_policy'),
text: AppLocalizations.of( text: AppLocalizations
context)! .of(context)!
.privacy_policy, .privacy_policy,
style: TextStyle( style: TextStyle(
fontWeight: fontWeight:
FontWeight.bold, FontWeight
fontSize: registerLocale .bold,
fontSize:
registerLocale
?.languageCode == ?.languageCode ==
'ar' 'ar'
? 12 ? 12
: 14, : 14,
fontFamily: 'Roboto', fontFamily:
color: 'Roboto',
Color(0xFF985400), color: Color(
0xFF985400),
// decoration: // decoration:
// TextDecoration.underline, // TextDecoration.underline,
decorationColor: decorationColor:
Color(0xFF648CBA), Color(
0xFF648CBA),
decorationThickness: decorationThickness:
1), 1),
), ),
TextSpan( TextSpan(
text: AppLocalizations.of( text: AppLocalizations
context)! .of(context)!
.conditions, .conditions,
style: TextStyle( style: TextStyle(
fontWeight: fontWeight:
@ -1193,7 +1236,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
children: [ children: [
Text( Text(
// "Register", // "Register",
AppLocalizations.of(context)! AppLocalizations.of(
context)!
.register_title, .register_title,
style: TextStyle( style: TextStyle(
fontSize: registerLocale fontSize: registerLocale
@ -1205,7 +1249,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
), ),
SizedBox(width: 8), SizedBox(width: 8),
const Icon( const Icon(
Icons.chevron_right_outlined, Icons
.chevron_right_outlined,
color: Colors color: Colors
.white, // Set your desired color here .white, // Set your desired color here
) )
@ -1221,7 +1266,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
fontSize: fontSize:
registerLocale?.languageCode == 'ar' registerLocale?.languageCode ==
'ar'
? 12 ? 12
: 14, : 14,
color: Color(0xFF898C81), color: Color(0xFF898C81),
@ -1252,7 +1298,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text( Text(
AppLocalizations.of(context)! AppLocalizations.of(
context)!
.login_title, .login_title,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
@ -1260,7 +1307,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
), ),
SizedBox(width: 8), SizedBox(width: 8),
const Icon( const Icon(
Icons.chevron_right_outlined, Icons
.chevron_right_outlined,
color: Colors color: Colors
.white, // Set your desired color here .white, // Set your desired color here
) )
@ -1301,8 +1349,28 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
], ],
), ),
), ),
if (isLoading)
Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
), ),
), ),
],
),
)
])),
),
); );
} }
} }

View File

@ -2110,6 +2110,10 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
print('isLoadingref $isLoading');
});
// fetchChartData(widget.dataSets, localeCode); // fetchChartData(widget.dataSets, localeCode);
print('Saving currentTab: $tabWiseKpi before locale change'); print('Saving currentTab: $tabWiseKpi before locale change');
@ -2174,7 +2178,8 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
canPop: false, // 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;
context.go('/uaenumbers'); // Show exit confirmation dialog context.pop();
// context.go('/uaenumbers'); // Show exit confirmation dialog
}, },
child: BaseScaffold( child: BaseScaffold(
@ -2193,9 +2198,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
showBackButton: true, showBackButton: true,
colorChange: true, colorChange: true,
navBackArrow: Text(widget.keyParam ?? 'Default Value'), navBackArrow: Text(widget.keyParam ?? 'Default Value'),
body: isLoading body: Stack(children: [
? Center(child: CircularProgressIndicator()) if (!isLoading)
: Container( Container(
color: color, color: color,
child: Column( child: Column(
children: [ children: [
@ -2599,7 +2604,27 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
], ],
), ),
), ),
if (isLoading)
Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
), ),
),
],
),
)
])),
); );
} }

View File

@ -230,7 +230,8 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
MainAxisAlignment.spaceEvenly, // Space buttons evenly MainAxisAlignment.spaceEvenly, // Space buttons evenly
children: [ children: [
SizedBox( SizedBox(
width: 120, // Set button width width:
MediaQuery.of(context).size.width * 0.3, // Set button width
child: TextButton( child: TextButton(
onPressed: () => Navigator.pop(dialogContext), onPressed: () => Navigator.pop(dialogContext),
style: TextButton.styleFrom( style: TextButton.styleFrom(
@ -252,7 +253,8 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
), ),
), ),
SizedBox( SizedBox(
width: 120, // Set button width width:
MediaQuery.of(context).size.width * 0.3, // Set button width
child: TextButton( child: TextButton(
onPressed: () => logout(context), onPressed: () => logout(context),
style: TextButton.styleFrom( style: TextButton.styleFrom(
@ -262,9 +264,14 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),
), ),
child: FittedBox(
fit: BoxFit
.scaleDown, // Prevents wrapping while adjusting text size
child: Text( child: Text(
context.translate('Log Out', 'تسجيل الخروج'), context.translate('Log Out', 'تسجيل الخروج'),
style: TextStyle(color: Colors.white, fontSize: 16), style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
), ),
), ),
), ),
@ -1147,6 +1154,9 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchData(localeCode); fetchData(localeCode);
}); });
@ -1163,7 +1173,24 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
double mywidth = MediaQuery.of(context).size.width; double mywidth = MediaQuery.of(context).size.width;
if (isLoading) { if (isLoading) {
return Center(child: CircularProgressIndicator()); return Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin:
EdgeInsets.symmetric(horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor: Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
);
} else if (data.isEmpty) { } else if (data.isEmpty) {
return Center(child: Text("No data available")); return Center(child: Text("No data available"));
} }
@ -1469,28 +1496,39 @@ class InfoCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Flexible( // Flexible(
fit: FlexFit.loose, // fit: FlexFit.loose,
child: FittedBox( // child: FittedBox(
fit: BoxFit.contain, // Adjust text to fit within the bounds // fit: BoxFit.contain, // Adjust text to fit within the bounds
child: Padding( // child: Padding(
// padding: const EdgeInsets.all(4.0), // // padding: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 4, bottom: 0), // padding: const EdgeInsets.only(top: 4, bottom: 0),
child: Text( // child: Text(
// title,
// style: const TextStyle(
// // fontSize: 11,
// fontSize: 12 * 1.1,
// fontWeight: FontWeight.w500,
// // color: Colors.black,
// fontFamily: 'Roboto',
// color: Color(0xFF000000),
// ),
// ),
// ),
// ),
// ),
Text(
title, title,
style: const TextStyle( style: const TextStyle(
// fontSize: 11, // fontSize: 11,
fontSize: 11 * 1.1, fontSize: 12,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
// color: Colors.black, // color: Colors.black,
fontFamily: 'Roboto', fontFamily: 'Roboto',
color: Color(0xFF000000), color: Color(0xFF000000),
), ),
), ),
), const SizedBox(height: 0.3),
),
),
const SizedBox(height: 0.5),
Flexible( Flexible(
fit: FlexFit.loose, fit: FlexFit.loose,
@ -1503,7 +1541,7 @@ class InfoCard extends StatelessWidget {
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: const TextStyle( style: const TextStyle(
// fontSize: 11, // fontSize: 11,
fontSize: 11 * 1.1, fontSize: 12 * 1.1,
fontFamily: 'Roboto', fontFamily: 'Roboto',
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Color(0xFF8E8E8E), color: Color(0xFF8E8E8E),

View File

@ -187,6 +187,9 @@ class _BookMarkState extends ConsumerState<BookMark> {
Future<void> removeBookmark(bookmarkId) async { Future<void> removeBookmark(bookmarkId) async {
try { try {
setState(() {
isLoading = true;
});
final adminAuth = await _pb.admins final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
final adminToken = adminAuth.token; final adminToken = adminAuth.token;
@ -219,6 +222,10 @@ class _BookMarkState extends ConsumerState<BookMark> {
duration: Duration(seconds: 2), duration: Duration(seconds: 2),
); );
print("Error removing bookmark: $e"); print("Error removing bookmark: $e");
} finally {
setState(() {
isLoading = false;
});
} }
} }
@ -342,6 +349,9 @@ class _BookMarkState extends ConsumerState<BookMark> {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchBookmarks(localeCode); fetchBookmarks(localeCode);
}); });
@ -365,7 +375,27 @@ class _BookMarkState extends ConsumerState<BookMark> {
title: Text( title: Text(
AppLocalizations.of(context)!.bookmarks, AppLocalizations.of(context)!.bookmarks,
), ),
body: Column( body: isLoading
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: Column(
children: [ children: [
TabBarHeader( TabBarHeader(
tabs: tabs, tabs: tabs,
@ -381,10 +411,12 @@ class _BookMarkState extends ConsumerState<BookMark> {
? (bookmarks.isNotEmpty ? (bookmarks.isNotEmpty
? SingleChildScrollView( ? SingleChildScrollView(
child: Column( child: Column(
children: List.generate(transformedList.length, (i) { children:
List.generate(transformedList.length, (i) {
final mainTopic = transformedList[i]; final mainTopic = transformedList[i];
print('oustside1 $mainTopic'); print('oustside1 $mainTopic');
final list = List.from(mainTopic['SubTopic'] ?? []); final list =
List.from(mainTopic['SubTopic'] ?? []);
print('oustside2 $list'); print('oustside2 $list');
return CustomExpandableTile( return CustomExpandableTile(
index: i, index: i,
@ -392,11 +424,13 @@ class _BookMarkState extends ConsumerState<BookMark> {
onTap: (int index) { onTap: (int index) {
// 🔹 Expecting an index // 🔹 Expecting an index
setState(() { setState(() {
expandedIndex = expandedIndex = (expandedIndex == index)
(expandedIndex == index) ? null : index; ? null
: index;
}); });
}, },
title: mainTopic['main_topic'] ?? 'No Topic', title:
mainTopic['main_topic'] ?? 'No Topic',
childWidget: Container( childWidget: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -424,7 +458,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
), ),
filteredBookmarks: filteredBookmarks:
List.from(mainTopic['SubTopic'] ?? []), List.from(mainTopic['SubTopic'] ?? []),
titleBackgroundColor: mainTopic['valueColor'], titleBackgroundColor:
mainTopic['valueColor'],
// Ensure it's a new list // Ensure it's a new list
); );
}), }),
@ -440,8 +475,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
Text( Text(
context.translate('No BookMark Added', context.translate('No BookMark Added',
'لم يتم إضافة أي علامة مرجعية'), 'لم يتم إضافة أي علامة مرجعية'),
style: style: TextStyle(
TextStyle(fontSize: 16, color: Colors.grey), fontSize: 16, color: Colors.grey),
), ),
], ],
), ),
@ -456,8 +491,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
SizedBox(height: 16), SizedBox(height: 16),
Text( Text(
'No Bookmark is added', 'No Bookmark is added',
style: style: TextStyle(
TextStyle(fontSize: 16, color: Colors.grey), fontSize: 16, color: Colors.grey),
), ),
], ],
), ),
@ -469,8 +504,8 @@ class _BookMarkState extends ConsumerState<BookMark> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: tabs[selectedTabIndex]['color'], color: tabs[selectedTabIndex]['color'],
borderRadius: borderRadius: BorderRadius.all(
BorderRadius.all(Radius.circular(35))), Radius.circular(35))),
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 16, bottom: 5, top: 5, right: 10), left: 16, bottom: 5, top: 5, right: 10),
child: Row( child: Row(

View File

@ -31,7 +31,6 @@ class _EditProfileState extends ConsumerState<EditProfile> {
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
// final _pb = PocketBase('http://127.0.0.1:8090'); // final _pb = PocketBase('http://127.0.0.1:8090');
bool _isProfileCompleted = false; bool _isProfileCompleted = false;
bool _isLoading = false;
// Add focus nodes and hint states // Add focus nodes and hint states
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode()); final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
@ -85,7 +84,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
final _picker = ImagePicker(); final _picker = ImagePicker();
File? _profileImage; File? _profileImage;
String _avatarUrl = ''; String _avatarUrl = '';
bool isPageLoad = false; bool isLoader = true;
// 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]+$');
@ -174,10 +173,6 @@ class _EditProfileState extends ConsumerState<EditProfile> {
Future<void> _fetchUserData() async { Future<void> _fetchUserData() async {
try { try {
setState(() {
isPageLoad = true; // Show loader
print('Im isPageLoad');
});
print('EDIT PROFILE isPageLoad'); print('EDIT PROFILE isPageLoad');
final adminAuth = await _pb.admins final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
@ -229,7 +224,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} else { } else {
_avatarUrl = ''; // Reset to default or empty _avatarUrl = ''; // Reset to default or empty
} }
isPageLoad = false; isLoader = false;
}); });
} catch (e) { } catch (e) {
print('Error fetching user details: $e'); print('Error fetching user details: $e');
@ -261,7 +256,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
await _picker.pickImage(source: ImageSource.gallery); await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) { if (pickedFile != null) {
setState(() { setState(() {
_isLoading = true; // Start loading isLoader = true; // Start loading
}); });
print(pickedFile); print(pickedFile);
final String fileExtension = final String fileExtension =
@ -272,7 +267,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
fileExtension == 'png' || fileExtension == 'png' ||
fileExtension == 'heic') { fileExtension == 'heic') {
setState(() { setState(() {
_isLoading = false; isLoader = false;
_profileImage = File(pickedFile.path); _profileImage = File(pickedFile.path);
}); });
} else { } else {
@ -283,7 +278,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} }
setState(() { setState(() {
_isLoading = false; // Hide loader isLoader = false; // Hide loader
}); });
} }
@ -356,6 +351,9 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} }
void showConfirmationDialog(BuildContext context) async { void showConfirmationDialog(BuildContext context) async {
setState(() {
isLoader = true;
});
// final result = await showDialog<bool>( // final result = await showDialog<bool>(
// context: context, // context: context,
// builder: (context) => const ConfirmationDialog(), // builder: (context) => const ConfirmationDialog(),
@ -404,12 +402,18 @@ class _EditProfileState extends ConsumerState<EditProfile> {
// Handle response // Handle response
if (response.statusCode == 200) { if (response.statusCode == 200) {
_resetFormFields(); _resetFormFields();
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Profile updated successfully!')), SnackBar(content: Text('Profile updated successfully!')),
); );
// print('ShowConfirmation userData - $userData '); // print('ShowConfirmation userData - $userData ');
context.go('/myhomepage'); context.go('/myhomepage');
} else { } else {
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Failed to update profile: ${response.statusCode}'), content: Text('Failed to update profile: ${response.statusCode}'),
@ -417,6 +421,9 @@ class _EditProfileState extends ConsumerState<EditProfile> {
); );
} }
} catch (error) { } catch (error) {
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to update profile: $error')), SnackBar(content: Text('Failed to update profile: $error')),
); );
@ -424,6 +431,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} else { } else {
// Show an error if the country is invalid // Show an error if the country is invalid
setState(() { setState(() {
isLoader = false;
showError = true; showError = true;
}); });
} }
@ -477,9 +485,30 @@ class _EditProfileState extends ConsumerState<EditProfile> {
AppLocalizations.of(context)!.my_profile, AppLocalizations.of(context)!.my_profile,
style: TextStyle(color: Color(0xFF985400)), style: TextStyle(color: Color(0xFF985400)),
), ),
body: SingleChildScrollView( body: isLoader
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: 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(
@ -489,11 +518,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
// padding: const EdgeInsets.all(20.0), // padding: const EdgeInsets.all(20.0),
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: isPageLoad child: Column(
? Center(
child: CircularProgressIndicator(),
)
: Column(
children: [ children: [
// CircleAvatar( // CircleAvatar(
// radius: 50, // radius: 50,
@ -643,16 +668,6 @@ class _EditProfileState extends ConsumerState<EditProfile> {
), ),
), ),
), ),
if (_isLoading)
Positioned(
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(
Colors.grey,
),
),
),
], ],
), ),

View File

@ -32,6 +32,7 @@ class FeedbackForm extends ConsumerStatefulWidget {
class _FeedbackFormState extends ConsumerState<FeedbackForm> class _FeedbackFormState extends ConsumerState<FeedbackForm>
with WidgetsBindingObserver { with WidgetsBindingObserver {
final _pb = PocketBase(apiUrl); // Initialize PocketBase client final _pb = PocketBase(apiUrl); // Initialize PocketBase client
bool isLoading = false;
// final _pb = // final _pb =
// PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client // PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
@ -277,7 +278,27 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
// ), // ),
// ], // ],
// ), // ),
body: Padding( body: isLoading
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 8.0, bottom: 16.0, left: 23.0, right: 23.0), top: 8.0, bottom: 16.0, left: 23.0, right: 23.0),
child: SingleChildScrollView( child: SingleChildScrollView(
@ -747,6 +768,9 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
} }
Future<void> _submitFeedback() async { Future<void> _submitFeedback() async {
setState(() {
isLoading = true;
});
if (_selectedEmojiIndex == null) { if (_selectedEmojiIndex == null) {
setState(() { setState(() {
_isSmileySelected = false; _isSmileySelected = false;
@ -802,6 +826,7 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
_isFeedbackSubmitted = true; _isFeedbackSubmitted = true;
_isFeedbackFailed = false; _isFeedbackFailed = false;
_resetFeedbackForm(); _resetFeedbackForm();
isLoading = false;
}); });
} }
} catch (e) { } catch (e) {

View File

@ -57,7 +57,6 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
); );
setState(() { setState(() {
isLoading = true;
userData = result.map((record) { userData = result.map((record) {
final createdDate = DateTime.parse(record.created) final createdDate = DateTime.parse(record.created)
.add(Duration(hours: 4)); // Parse the created date .add(Duration(hours: 4)); // Parse the created date
@ -82,6 +81,7 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
isLoading = false; isLoading = false;
}); });
} catch (e) { } catch (e) {
isLoading = false;
print('Error fetching unverified users: $e'); print('Error fetching unverified users: $e');
} }
} }
@ -123,6 +123,43 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
}); });
} }
Future<void> changeStatus(userID, newStatus) async {
try {
setState(() {
isLoading = true;
});
// Update status in PocketBase
await _pb.collection('users').update(
userID, // User's unique ID
body: {
'status': newStatus, // Update status
'verified': newStatus == 'Approved' ? true : false,
'reviewed': true,
},
);
// Update local state
// setState(() {
// user.status = newStatus;
// });
fetchUnverifiedUsers();
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Status updated successfully!')),
);
} catch (e) {
setState(() {
isLoading = false;
});
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error updating status: $e')),
);
}
}
//Method to show a confirmation dialog when status is changed //Method to show a confirmation dialog when status is changed
Future<void> _showConfirmationDialog(User user, String newStatus) async { Future<void> _showConfirmationDialog(User user, String newStatus) async {
print('user $user'); print('user $user');
@ -219,32 +256,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
width: 100, // Set the desired width width: 100, // Set the desired width
child: TextButton( child: TextButton(
onPressed: () async { onPressed: () async {
try { Navigator.of(context).pop();
// Update status in PocketBase changeStatus(user.id, newStatus);
await _pb.collection('users').update( // Close dialog
user.id, // User's unique ID
body: {
'status': newStatus, // Update status
'verified': newStatus == 'Approved' ? true : false,
'reviewed': true,
},
);
// Update local state
// setState(() {
// user.status = newStatus;
// });
fetchUnverifiedUsers();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Status updated successfully!')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error updating status: $e')),
);
}
Navigator.of(context).pop(); // Close dialog
}, },
style: TextButton.styleFrom( style: TextButton.styleFrom(
backgroundColor: backgroundColor:
@ -297,9 +311,30 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
title: Text( title: Text(
AppLocalizations.of(context)!.manage_user, AppLocalizations.of(context)!.manage_user,
), ),
body: SingleChildScrollView( body: isLoading
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: 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: [
// TextField( // TextField(
@ -344,7 +379,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(30.0), borderRadius: BorderRadius.circular(30.0),
border: Border.all(width: 1, color: Color(0xFFAA8E83)), border:
Border.all(width: 1, color: Color(0xFFAA8E83)),
), ),
child: Padding( child: Padding(
padding: EdgeInsets.only(left: 12.0), padding: EdgeInsets.only(left: 12.0),
@ -378,9 +414,7 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
), ),
), ),
SizedBox(height: myheight / 40), SizedBox(height: myheight / 40),
isLoading filteredUserData.isEmpty
? Center(child: CircularProgressIndicator())
: filteredUserData.isEmpty
? Center( ? Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@ -438,7 +472,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
), ),
onSort: (columnIndex, ascending) { onSort: (columnIndex, ascending) {
_sort( _sort(
(user) => user.userName.toLowerCase(), (user) =>
user.userName.toLowerCase(),
columnIndex, columnIndex,
ascending); ascending);
}, },
@ -449,7 +484,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
), ),
onSort: (columnIndex, ascending) { onSort: (columnIndex, ascending) {
_sort( _sort(
(user) => user.emailId.toLowerCase(), (user) =>
user.emailId.toLowerCase(),
columnIndex, columnIndex,
ascending); ascending);
}, },
@ -472,8 +508,10 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
AppLocalizations.of(context)!.status, AppLocalizations.of(context)!.status,
), ),
onSort: (columnIndex, ascending) { onSort: (columnIndex, ascending) {
_sort((user) => user.status.toLowerCase(), _sort(
columnIndex, ascending); (user) => user.status.toLowerCase(),
columnIndex,
ascending);
}, },
), ),
], ],
@ -487,8 +525,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
? Text( ? Text(
'No results found', 'No results found',
style: TextStyle( style: TextStyle(
fontStyle: fontStyle: FontStyle
FontStyle.italic), .italic),
) )
: const Text( : const Text(
''), // Empty cells for other columns ''), // Empty cells for other columns

View File

@ -22,6 +22,7 @@ class NotificationPage extends ConsumerStatefulWidget {
class _NotificationPageState extends ConsumerState<NotificationPage> { class _NotificationPageState extends ConsumerState<NotificationPage> {
// Example notification data // Example notification data
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
bool isLoading = true;
List<Map<String, dynamic>> notifications = []; List<Map<String, dynamic>> notifications = [];
List<String> pushedNotification = []; List<String> pushedNotification = [];
@ -109,15 +110,25 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
notifications = List<Map<String, dynamic>>.from( notifications = List<Map<String, dynamic>>.from(
jsonResponse['data']); // Assign decoded data jsonResponse['data']); // Assign decoded data
print('notifications $notifications'); print('notifications $notifications');
isLoading = false;
}); });
} else { } else {
setState(() {
isLoading = false;
});
throw Exception('Failed to load data'); throw Exception('Failed to load data');
} }
} else { } else {
setState(() {
isLoading = false;
});
throw Exception( throw Exception(
'Failed to load data with status code ${response.statusCode}'); 'Failed to load data with status code ${response.statusCode}');
} }
} catch (e) { } catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e'); print('Error fetching data: $e');
} }
} }
@ -132,6 +143,9 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchNotifications(localeCode); fetchNotifications(localeCode);
}); });
final List<Map<String, dynamic>> tabs = [ final List<Map<String, dynamic>> tabs = [
@ -164,7 +178,27 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
'إشعار', 'إشعار',
), ),
), ),
body: Column( body: isLoading
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: Column(
children: [ children: [
TabBarHeader( TabBarHeader(
tabs: tabs.map((tab) => tab['title'] as String).toList(), tabs: tabs.map((tab) => tab['title'] as String).toList(),
@ -186,7 +220,8 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
SizedBox(height: 16), SizedBox(height: 16),
Text( Text(
'No notifications available.', 'No notifications available.',
style: TextStyle(fontSize: 16, color: Colors.grey), style: TextStyle(
fontSize: 16, color: Colors.grey),
), ),
], ],
), ),
@ -205,8 +240,10 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
), ),
child: NotificationTile( child: NotificationTile(
title: notification['title'] ?? 'No Title', title: notification['title'] ?? 'No Title',
date: formatDate(notification['created'] ?? ''), date:
category: notification['category'] ?? 'Unknown', formatDate(notification['created'] ?? ''),
category:
notification['category'] ?? 'Unknown',
message: notification['message'] ?? '', message: notification['message'] ?? '',
id: notification['id'], id: notification['id'],
pushedNotification: pushedNotification, pushedNotification: pushedNotification,

View File

@ -37,6 +37,7 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
// Example notification data // Example notification data
final _pb = PocketBase(apiUrl); final _pb = PocketBase(apiUrl);
Map<String, dynamic>? notification; Map<String, dynamic>? notification;
bool isLoading = true;
// Current selected tab index // Current selected tab index
int selectedTabIndex = 0; int selectedTabIndex = 0;
@ -77,6 +78,7 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
setState(() { setState(() {
final data = jsonResponse['data']; final data = jsonResponse['data'];
notification = data; notification = data;
isLoading = false;
// if (data is Map<String, dynamic>) { // if (data is Map<String, dynamic>) {
// notification = data; // notification = data;
// } else { // } else {
@ -86,13 +88,22 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
print('notification $notification'); print('notification $notification');
}); });
} else { } else {
setState(() {
isLoading = false;
});
throw Exception('Failed to load data'); throw Exception('Failed to load data');
} }
} else { } else {
setState(() {
isLoading = false;
});
throw Exception( throw Exception(
'Failed to load data with status code ${response.statusCode}'); 'Failed to load data with status code ${response.statusCode}');
} }
} catch (e) { } catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e'); print('Error fetching data: $e');
} }
} }
@ -107,6 +118,9 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
ref.listen<Locale?>(localeProvider, (previous, next) { ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchNotifications(localeCode); fetchNotifications(localeCode);
}); });
@ -125,7 +139,27 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
), ),
showBackButton: true, showBackButton: true,
navBackArrow: Text(widget.backNavigation ?? 'Default Value'), navBackArrow: Text(widget.backNavigation ?? 'Default Value'),
body: Padding( body: isLoading
? Container(
color: Color(0x98FFFCE5), // Semi-transparent background
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 40), // Left & Right space
child: LinearProgressIndicator(
minHeight: 5, // Adjust thickness
backgroundColor:
Colors.grey[100], // Optional: Background color
valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFFAA8E83)), // Loader color
),
),
],
),
)
: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -1244,9 +1244,14 @@ void _showLogoutConfirmationDialog(BuildContext context) {
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
), ),
), ),
child: FittedBox(
fit: BoxFit
.scaleDown, // Prevents wrapping while adjusting text size
child: Text( child: Text(
context.translate('Log Out', 'تسجيل الخروج'), context.translate('Log Out', 'تسجيل الخروج'),
style: TextStyle(color: Colors.white, fontSize: 16), style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
), ),
), ),
), ),

View File

@ -1,7 +1,7 @@
name: uae_stat 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: 1.0.35+36 version: 1.0.36+37
environment: environment:
sdk: ">=3.2.3 <4.0.0" sdk: ">=3.2.3 <4.0.0"