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")
if (flutterVersionCode == null) {
flutterVersionCode = "36"
flutterVersionCode = "37"
}
def flutterVersionName = localProperties.getProperty("flutter.versionName")
if (flutterVersionName == null) {
flutterVersionName = "1.0.35"
flutterVersionName = "1.0.36"
}
def keystorePropertiesFile = rootProject.file("key.properties")
@ -72,6 +72,7 @@ android {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.release
minifyEnabled true // Enable code shrinking for smaller APKs
shrinkResources true
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) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchData(localeCode);
});
double myheight = MediaQuery.of(context).size.height;
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(
padding:
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: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';
@ -34,6 +36,7 @@ class CreateNewPw extends ConsumerStatefulWidget {
class _CreateNewPwState extends ConsumerState<CreateNewPw> {
final _pb = PocketBase(apiUrl);
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
bool _obscureOldPassword = true;
bool _obscureNewPassword = true;
@ -139,6 +142,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
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');
@ -164,6 +170,11 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
headers: headers,
);
setState(() {
isLoading = false;
_isPasswordUpdated = true;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
@ -172,9 +183,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
),
);
setState(() {
_isPasswordUpdated = true; // Toggle UI on success
});
print('_isPasswordUpdated $_isPasswordUpdated');
// Navigator.push(
// context,
@ -183,6 +192,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
// );
} else {
setState(() {
isLoading = false;
_formKey.currentState?.validate();
});
ScaffoldMessenger.of(context).showSnackBar(
@ -195,6 +205,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
return;
}
} catch (e) {
setState(() {
isLoading = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
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
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
@ -217,14 +239,35 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
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(
@ -626,8 +669,9 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
}
Widget _buildSuccessContent(double screenHeight, double screenWidth) {
print('IN');
return Padding(
padding: const EdgeInsets.all(20.0),
padding: EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
@ -647,16 +691,14 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
context.go('/login');
},
onPressed: () => logout(context),
style: ButtonStyle(
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
padding: const WidgetStatePropertyAll(
padding: WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 10.5),
),
textStyle: WidgetStatePropertyAll(
@ -675,7 +717,7 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
// surfaceTintColor: MaterialStatePropertyAll(
// MyTheme.economy[800],
// ),
foregroundColor: const WidgetStatePropertyAll(
foregroundColor: WidgetStatePropertyAll(
Colors.white,
),
),
@ -697,12 +739,12 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
),
),
6.horizontalSpace,
const Icon(Icons.chevron_right_outlined, color: Colors.white),
Icon(Icons.chevron_right_outlined, color: Colors.white),
],
),
),
SizedBox(height: screenHeight / 2.2),
Spacer(),
// Spacer(),
Center(
// child: Container(
// 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> {
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
final _usernameController = TextEditingController();
final _emailController = TextEditingController();
@ -225,6 +226,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
if (_formKey.currentState?.validate() ?? false) {
if (isChecked) {
setState(() {
isLoading = true;
isRegistering = true; // Disable the button
});
try {
@ -254,6 +256,7 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
registrationSuccess = true;
registrationFailed = false; // Show success message on success
isRegistering = false;
isLoading = false;
});
// Navigate to ProfileScreen after successful registration
@ -263,9 +266,14 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
// builder: (context) => ProfileScreen(userId: response.id)),
// );
} else {
isLoading = false;
throw Exception('User registration failed: missing user ID');
}
} catch (e) {
setState(() {
isLoading = false;
});
// Check if the error is due to an invalid or already used email
if (e
.toString()
@ -383,7 +391,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
child: SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
body: Stack(children: [
SingleChildScrollView(
child: Column(
children: [
Align(
@ -402,7 +411,9 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
pathColorWhenOff: Colors.grey.shade300,
onTap: () {
final formState = _formKey.currentState;
ref.read(localeProvider.notifier).toggleLocale();
ref
.read(localeProvider.notifier)
.toggleLocale();
Future.delayed(Duration(milliseconds: 100), () {
if (hasValidated &&
formState?.validate() == false) {
@ -459,8 +470,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
),
),
child: Text(
context.translate(
'Go to Login', 'اذهب إلى تسجيل الدخول'),
context.translate('Go to Login',
'اذهب إلى تسجيل الدخول'),
style: TextStyle(
color: Colors.white, // Text color
),
@ -489,7 +500,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: screenheight / 8),
buildIconContainer(Icons.report, Colors.red),
buildIconContainer(
Icons.report, Colors.red),
SizedBox(height: 20),
Text(
context.translate(
@ -550,7 +562,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
SizedBox(height: screenheight / 60),
Text(
@ -566,7 +579,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
AppLocalizations.of(context)!
.register_details,
style: TextStyle(
fontSize: context.translate(18.0, 14.0),
fontSize:
context.translate(18.0, 14.0),
color: const Color(0xff898C81),
fontWeight: FontWeight.w600,
),
@ -586,7 +600,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
decoration: InputDecoration(
// hintText: _showHints[0] ? 'Username' : null,
hintText: _showHints[0]
? AppLocalizations.of(context)!
? AppLocalizations.of(
context)!
.register_name
: null,
prefixIconConstraints:
@ -595,7 +610,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional
padding:
const EdgeInsetsDirectional
.only(
start: 16,
end: 10,
@ -606,7 +622,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25,
width: 25,
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade300,
),
),
@ -622,7 +639,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade400,
width: 1), // Enabled border
),
@ -652,8 +670,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '',
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontSize:
registerLocale?.languageCode ==
fontSize: registerLocale
?.languageCode ==
'ar'
? 14
: 16,
@ -679,7 +697,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
decoration: InputDecoration(
// hintText: 'Enter your email',
hintText: _showHints[1]
? AppLocalizations.of(context)!
? AppLocalizations.of(
context)!
.enter_your_email
: null,
// _showHints[1] ? 'Enter your email' : null,
@ -689,7 +708,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional
padding:
const EdgeInsetsDirectional
.only(
start: 16,
end: 10,
@ -700,7 +720,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 20,
width: 25,
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade100,
),
),
@ -711,7 +732,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
BorderRadius.circular(10),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade400,
width: 1),
),
@ -741,8 +763,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '',
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontSize:
registerLocale?.languageCode ==
fontSize: registerLocale
?.languageCode ==
'ar'
? 14
: 16,
@ -771,7 +793,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
obscureText: _obscurePassword,
decoration: InputDecoration(
hintText: _showHints[2]
? AppLocalizations.of(context)!
? AppLocalizations.of(
context)!
.enter_your_password
: null,
// _showHints[2] ? 'Enter your password' : null,
@ -781,7 +804,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional
padding:
const EdgeInsetsDirectional
.only(
start: 16,
end: 10,
@ -792,7 +816,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25,
width: 25,
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade300,
),
),
@ -813,7 +838,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
_obscurePassword
? MiscIconAssetPath
.visibilityOff
: MiscIconAssetPath.visibleOn,
: MiscIconAssetPath
.visibleOn,
color: Color(
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),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade400,
width: 1),
),
@ -865,8 +892,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '',
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontSize:
registerLocale?.languageCode ==
fontSize: registerLocale
?.languageCode ==
'ar'
? 14
: 16,
@ -886,12 +913,15 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
left: 30,
right: 30),
child: TextFormField(
controller: _confirmpasswordController,
controller:
_confirmpasswordController,
// focusNode: _focusNodes[3],
obscureText: _obscureConfirmPassword,
obscureText:
_obscureConfirmPassword,
decoration: InputDecoration(
hintText: _showHints[3]
? AppLocalizations.of(context)!
? AppLocalizations.of(
context)!
.register_Confirm_password
: null,
// _showHints[3] ? 'Confirm password' : null,
@ -901,7 +931,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
maxHeight: 25 + (8 * 2),
),
prefixIcon: Padding(
padding: const EdgeInsetsDirectional
padding:
const EdgeInsetsDirectional
.only(
start: 16,
end: 10,
@ -912,7 +943,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
height: 25,
width: 25,
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade300,
),
),
@ -922,7 +954,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
_obscureConfirmPassword
? MiscIconAssetPath
.visibilityOff
: MiscIconAssetPath.visibleOn,
: MiscIconAssetPath
.visibleOn,
color: Color(
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),
borderSide: BorderSide(
color: MyTheme.topicColor(
IndicatorTopic.economy)
IndicatorTopic
.economy)
.shade400,
width: 1),
),
@ -974,8 +1008,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
counterText: '',
hintStyle: TextStyle(
color: Color(0xFFC3C6CB),
fontSize:
registerLocale?.languageCode ==
fontSize: registerLocale
?.languageCode ==
'ar'
? 14
: 16,
@ -1024,7 +1058,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(
padding:
const EdgeInsets.only(
top: 0,
),
child: Text.rich(
@ -1035,7 +1070,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
.agree,
// text: 'I agree to ',
style: TextStyle(
fontWeight: FontWeight.w500,
fontWeight:
FontWeight.w500,
fontSize: registerLocale
?.languageCode ==
'ar'
@ -1052,31 +1088,34 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
..onTap = () =>
context.push(
'/terms&conditions'),
text: AppLocalizations.of(
context)!
text: AppLocalizations
.of(context)!
.terms_conditions,
// text: 'Terms & Conditions',
style: TextStyle(
fontSize: registerLocale
fontSize:
registerLocale
?.languageCode ==
'ar'
? 12
: 14,
fontWeight:
FontWeight.bold,
color:
Color(0xFF985400),
FontWeight
.bold,
color: Color(
0xFF985400),
// Makes the text bold
// decoration:
// TextDecoration.underline,
decorationColor:
Color(0xFF985400),
Color(
0xFF985400),
decorationThickness:
1),
),
TextSpan(
text: AppLocalizations.of(
context)!
text: AppLocalizations
.of(context)!
.t_and,
style: TextStyle(
color: Color(
@ -1089,30 +1128,34 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
..onTap = () =>
context.push(
'/privacy_policy'),
text: AppLocalizations.of(
context)!
text: AppLocalizations
.of(context)!
.privacy_policy,
style: TextStyle(
fontWeight:
FontWeight.bold,
fontSize: registerLocale
FontWeight
.bold,
fontSize:
registerLocale
?.languageCode ==
'ar'
? 12
: 14,
fontFamily: 'Roboto',
color:
Color(0xFF985400),
fontFamily:
'Roboto',
color: Color(
0xFF985400),
// decoration:
// TextDecoration.underline,
decorationColor:
Color(0xFF648CBA),
Color(
0xFF648CBA),
decorationThickness:
1),
),
TextSpan(
text: AppLocalizations.of(
context)!
text: AppLocalizations
.of(context)!
.conditions,
style: TextStyle(
fontWeight:
@ -1193,7 +1236,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
children: [
Text(
// "Register",
AppLocalizations.of(context)!
AppLocalizations.of(
context)!
.register_title,
style: TextStyle(
fontSize: registerLocale
@ -1205,7 +1249,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
),
SizedBox(width: 8),
const Icon(
Icons.chevron_right_outlined,
Icons
.chevron_right_outlined,
color: Colors
.white, // Set your desired color here
)
@ -1221,7 +1266,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize:
registerLocale?.languageCode == 'ar'
registerLocale?.languageCode ==
'ar'
? 12
: 14,
color: Color(0xFF898C81),
@ -1252,7 +1298,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
mainAxisSize: MainAxisSize.min,
children: [
Text(
AppLocalizations.of(context)!
AppLocalizations.of(
context)!
.login_title,
style: TextStyle(
fontSize: 16,
@ -1260,7 +1307,8 @@ class _RegisterScreenState extends ConsumerState<RegisterScreen> {
),
SizedBox(width: 8),
const Icon(
Icons.chevron_right_outlined,
Icons
.chevron_right_outlined,
color: Colors
.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) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
print('isLoadingref $isLoading');
});
// fetchChartData(widget.dataSets, localeCode);
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
onPopInvokedWithResult: (didPop, result) {
if (didPop) return;
context.go('/uaenumbers'); // Show exit confirmation dialog
context.pop();
// context.go('/uaenumbers'); // Show exit confirmation dialog
},
child: BaseScaffold(
@ -2193,9 +2198,9 @@ class _ChartScreen1State extends ConsumerState<ChartScreen1> {
showBackButton: true,
colorChange: true,
navBackArrow: Text(widget.keyParam ?? 'Default Value'),
body: isLoading
? Center(child: CircularProgressIndicator())
: Container(
body: Stack(children: [
if (!isLoading)
Container(
color: color,
child: Column(
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
children: [
SizedBox(
width: 120, // Set button width
width:
MediaQuery.of(context).size.width * 0.3, // Set button width
child: TextButton(
onPressed: () => Navigator.pop(dialogContext),
style: TextButton.styleFrom(
@ -252,7 +253,8 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
),
),
SizedBox(
width: 120, // Set button width
width:
MediaQuery.of(context).size.width * 0.3, // Set button width
child: TextButton(
onPressed: () => logout(context),
style: TextButton.styleFrom(
@ -262,9 +264,14 @@ class _MyHomePageState extends ConsumerState<MyHomePage> {
borderRadius: BorderRadius.circular(10.0),
),
),
child: FittedBox(
fit: BoxFit
.scaleDown, // Prevents wrapping while adjusting text size
child: Text(
context.translate('Log Out', 'تسجيل الخروج'),
style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
),
),
),
@ -1147,6 +1154,9 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
Widget build(BuildContext context) {
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchData(localeCode);
});
@ -1163,7 +1173,24 @@ class EconomyStatsState extends ConsumerState<EconomyStatsWidget> {
double mywidth = MediaQuery.of(context).size.width;
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) {
return Center(child: Text("No data available"));
}
@ -1469,28 +1496,39 @@ class InfoCard extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Flexible(
fit: FlexFit.loose,
child: FittedBox(
fit: BoxFit.contain, // Adjust text to fit within the bounds
child: Padding(
// padding: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 4, bottom: 0),
child: Text(
// Flexible(
// fit: FlexFit.loose,
// child: FittedBox(
// fit: BoxFit.contain, // Adjust text to fit within the bounds
// child: Padding(
// // padding: const EdgeInsets.all(4.0),
// padding: const EdgeInsets.only(top: 4, bottom: 0),
// 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,
style: const TextStyle(
// fontSize: 11,
fontSize: 11 * 1.1,
fontSize: 12,
fontWeight: FontWeight.w400,
// color: Colors.black,
fontFamily: 'Roboto',
color: Color(0xFF000000),
),
),
),
),
),
const SizedBox(height: 0.5),
const SizedBox(height: 0.3),
Flexible(
fit: FlexFit.loose,
@ -1503,7 +1541,7 @@ class InfoCard extends StatelessWidget {
textAlign: TextAlign.center,
style: const TextStyle(
// fontSize: 11,
fontSize: 11 * 1.1,
fontSize: 12 * 1.1,
fontFamily: 'Roboto',
fontWeight: FontWeight.w400,
color: Color(0xFF8E8E8E),

View File

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

View File

@ -31,7 +31,6 @@ class _EditProfileState extends ConsumerState<EditProfile> {
final _pb = PocketBase(apiUrl);
// final _pb = PocketBase('http://127.0.0.1:8090');
bool _isProfileCompleted = false;
bool _isLoading = false;
// Add focus nodes and hint states
final List<FocusNode> _focusNodes = List.generate(4, (_) => FocusNode());
@ -85,7 +84,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
final _picker = ImagePicker();
File? _profileImage;
String _avatarUrl = '';
bool isPageLoad = false;
bool isLoader = true;
// Regular expression to validate Full Name (no special characters)
final RegExp _nameRegExp = RegExp(r'^[a-zA-Z\s]+$');
@ -174,10 +173,6 @@ class _EditProfileState extends ConsumerState<EditProfile> {
Future<void> _fetchUserData() async {
try {
setState(() {
isPageLoad = true; // Show loader
print('Im isPageLoad');
});
print('EDIT PROFILE isPageLoad');
final adminAuth = await _pb.admins
.authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com');
@ -229,7 +224,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} else {
_avatarUrl = ''; // Reset to default or empty
}
isPageLoad = false;
isLoader = false;
});
} catch (e) {
print('Error fetching user details: $e');
@ -261,7 +256,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
await _picker.pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_isLoading = true; // Start loading
isLoader = true; // Start loading
});
print(pickedFile);
final String fileExtension =
@ -272,7 +267,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
fileExtension == 'png' ||
fileExtension == 'heic') {
setState(() {
_isLoading = false;
isLoader = false;
_profileImage = File(pickedFile.path);
});
} else {
@ -283,7 +278,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
}
setState(() {
_isLoading = false; // Hide loader
isLoader = false; // Hide loader
});
}
@ -356,6 +351,9 @@ class _EditProfileState extends ConsumerState<EditProfile> {
}
void showConfirmationDialog(BuildContext context) async {
setState(() {
isLoader = true;
});
// final result = await showDialog<bool>(
// context: context,
// builder: (context) => const ConfirmationDialog(),
@ -404,12 +402,18 @@ class _EditProfileState extends ConsumerState<EditProfile> {
// Handle response
if (response.statusCode == 200) {
_resetFormFields();
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Profile updated successfully!')),
);
// print('ShowConfirmation userData - $userData ');
context.go('/myhomepage');
} else {
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to update profile: ${response.statusCode}'),
@ -417,6 +421,9 @@ class _EditProfileState extends ConsumerState<EditProfile> {
);
}
} catch (error) {
setState(() {
isLoader = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to update profile: $error')),
);
@ -424,6 +431,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
} else {
// Show an error if the country is invalid
setState(() {
isLoader = false;
showError = true;
});
}
@ -477,9 +485,30 @@ class _EditProfileState extends ConsumerState<EditProfile> {
AppLocalizations.of(context)!.my_profile,
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(
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(
children: [
SingleChildScrollView(
@ -489,11 +518,7 @@ class _EditProfileState extends ConsumerState<EditProfile> {
// padding: const EdgeInsets.all(20.0),
padding: const EdgeInsets.only(
top: 20.0, bottom: 20.0, left: 25, right: 25),
child: isPageLoad
? Center(
child: CircularProgressIndicator(),
)
: Column(
child: Column(
children: [
// CircleAvatar(
// 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>
with WidgetsBindingObserver {
final _pb = PocketBase(apiUrl); // Initialize PocketBase client
bool isLoading = false;
// final _pb =
// 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(
top: 8.0, bottom: 16.0, left: 23.0, right: 23.0),
child: SingleChildScrollView(
@ -747,6 +768,9 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
}
Future<void> _submitFeedback() async {
setState(() {
isLoading = true;
});
if (_selectedEmojiIndex == null) {
setState(() {
_isSmileySelected = false;
@ -802,6 +826,7 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
_isFeedbackSubmitted = true;
_isFeedbackFailed = false;
_resetFeedbackForm();
isLoading = false;
});
}
} catch (e) {

View File

@ -57,7 +57,6 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
);
setState(() {
isLoading = true;
userData = result.map((record) {
final createdDate = DateTime.parse(record.created)
.add(Duration(hours: 4)); // Parse the created date
@ -82,6 +81,7 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
isLoading = false;
});
} catch (e) {
isLoading = false;
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
Future<void> _showConfirmationDialog(User user, String newStatus) async {
print('user $user');
@ -219,32 +256,9 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
width: 100, // Set the desired width
child: TextButton(
onPressed: () async {
try {
// Update status in PocketBase
await _pb.collection('users').update(
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
Navigator.of(context).pop();
changeStatus(user.id, newStatus);
// Close dialog
},
style: TextButton.styleFrom(
backgroundColor:
@ -297,9 +311,30 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
title: Text(
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(
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(
children: [
// TextField(
@ -344,7 +379,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30.0),
border: Border.all(width: 1, color: Color(0xFFAA8E83)),
border:
Border.all(width: 1, color: Color(0xFFAA8E83)),
),
child: Padding(
padding: EdgeInsets.only(left: 12.0),
@ -378,9 +414,7 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
),
),
SizedBox(height: myheight / 40),
isLoading
? Center(child: CircularProgressIndicator())
: filteredUserData.isEmpty
filteredUserData.isEmpty
? Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
@ -438,7 +472,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
),
onSort: (columnIndex, ascending) {
_sort(
(user) => user.userName.toLowerCase(),
(user) =>
user.userName.toLowerCase(),
columnIndex,
ascending);
},
@ -449,7 +484,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
),
onSort: (columnIndex, ascending) {
_sort(
(user) => user.emailId.toLowerCase(),
(user) =>
user.emailId.toLowerCase(),
columnIndex,
ascending);
},
@ -472,8 +508,10 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
AppLocalizations.of(context)!.status,
),
onSort: (columnIndex, ascending) {
_sort((user) => user.status.toLowerCase(),
columnIndex, ascending);
_sort(
(user) => user.status.toLowerCase(),
columnIndex,
ascending);
},
),
],
@ -487,8 +525,8 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
? Text(
'No results found',
style: TextStyle(
fontStyle:
FontStyle.italic),
fontStyle: FontStyle
.italic),
)
: const Text(
''), // Empty cells for other columns

View File

@ -22,6 +22,7 @@ class NotificationPage extends ConsumerStatefulWidget {
class _NotificationPageState extends ConsumerState<NotificationPage> {
// Example notification data
final _pb = PocketBase(apiUrl);
bool isLoading = true;
List<Map<String, dynamic>> notifications = [];
List<String> pushedNotification = [];
@ -109,15 +110,25 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
notifications = List<Map<String, dynamic>>.from(
jsonResponse['data']); // Assign decoded data
print('notifications $notifications');
isLoading = false;
});
} else {
setState(() {
isLoading = false;
});
throw Exception('Failed to load data');
}
} else {
setState(() {
isLoading = false;
});
throw Exception(
'Failed to load data with status code ${response.statusCode}');
}
} catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e');
}
}
@ -132,6 +143,9 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchNotifications(localeCode);
});
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: [
TabBarHeader(
tabs: tabs.map((tab) => tab['title'] as String).toList(),
@ -186,7 +220,8 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
SizedBox(height: 16),
Text(
'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(
title: notification['title'] ?? 'No Title',
date: formatDate(notification['created'] ?? ''),
category: notification['category'] ?? 'Unknown',
date:
formatDate(notification['created'] ?? ''),
category:
notification['category'] ?? 'Unknown',
message: notification['message'] ?? '',
id: notification['id'],
pushedNotification: pushedNotification,

View File

@ -37,6 +37,7 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
// Example notification data
final _pb = PocketBase(apiUrl);
Map<String, dynamic>? notification;
bool isLoading = true;
// Current selected tab index
int selectedTabIndex = 0;
@ -77,6 +78,7 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
setState(() {
final data = jsonResponse['data'];
notification = data;
isLoading = false;
// if (data is Map<String, dynamic>) {
// notification = data;
// } else {
@ -86,13 +88,22 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
print('notification $notification');
});
} else {
setState(() {
isLoading = false;
});
throw Exception('Failed to load data');
}
} else {
setState(() {
isLoading = false;
});
throw Exception(
'Failed to load data with status code ${response.statusCode}');
}
} catch (e) {
setState(() {
isLoading = false;
});
print('Error fetching data: $e');
}
}
@ -107,6 +118,9 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
ref.listen<Locale?>(localeProvider, (previous, next) {
final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null
setState(() {
isLoading = true;
});
fetchNotifications(localeCode);
});
@ -125,7 +139,27 @@ class _NotificationDetailsState extends ConsumerState<NotificationDetails> {
),
showBackButton: true,
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),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

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

View File

@ -1,7 +1,7 @@
name: uae_stat
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
publish_to: "none"
version: 1.0.35+36
version: 1.0.36+37
environment:
sdk: ">=3.2.3 <4.0.0"