loader added all page
This commit is contained in:
parent
ef761a8d0a
commit
f6de75f0c8
@ -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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
@ -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;
|
||||||
@ -216,15 +238,36 @@ class _CreateNewPwState extends ConsumerState<CreateNewPw> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
body: SingleChildScrollView(
|
body: Stack(children: [
|
||||||
child: SafeArea(
|
SingleChildScrollView(
|
||||||
child: _isPasswordUpdated
|
child: SafeArea(
|
||||||
? _buildSuccessContent(screenHeight, screenWidth)
|
child: _isPasswordUpdated
|
||||||
: _buildPasswordForm(ref, screenHeight, screenWidth),
|
? _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(
|
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,
|
||||||
|
|||||||
632
lib/presentation/Screens/auth_verification/forgot_password.dart
Normal file
632
lib/presentation/Screens/auth_verification/forgot_password.dart
Normal 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,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -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,28 +2178,29 @@ 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(
|
||||||
key: _scaffoldKey,
|
key: _scaffoldKey,
|
||||||
title: Text(
|
title: Text(
|
||||||
context.translate(
|
context.translate(
|
||||||
'UAE Numbers',
|
'UAE Numbers',
|
||||||
'أرقام الإمارات',
|
'أرقام الإمارات',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
// appbarColor: Color(int.parse(widget.bgColor)), // Example color
|
||||||
// appbarColor: Color(int.parse(widget.bgColor)), // Example color
|
appbarColor: Color(int.parse(
|
||||||
appbarColor: Color(int.parse(
|
(chartScreenData['header_color'] ?? '#ffffff')
|
||||||
(chartScreenData['header_color'] ?? '#ffffff')
|
.replaceFirst('#', '0xff'))),
|
||||||
.replaceFirst('#', '0xff'))),
|
// Example color
|
||||||
// Example color
|
showBackButton: true,
|
||||||
showBackButton: true,
|
colorChange: true,
|
||||||
colorChange: true,
|
navBackArrow: Text(widget.keyParam ?? 'Default Value'),
|
||||||
navBackArrow: Text(widget.keyParam ?? 'Default Value'),
|
body: Stack(children: [
|
||||||
body: isLoading
|
if (!isLoading)
|
||||||
? Center(child: CircularProgressIndicator())
|
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
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
])),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,11 +264,16 @@ 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,
|
// title,
|
||||||
style: const TextStyle(
|
// style: const TextStyle(
|
||||||
// fontSize: 11,
|
// // fontSize: 11,
|
||||||
fontSize: 11 * 1.1,
|
// fontSize: 12 * 1.1,
|
||||||
fontWeight: FontWeight.w400,
|
// fontWeight: FontWeight.w500,
|
||||||
// color: Colors.black,
|
// // color: Colors.black,
|
||||||
fontFamily: 'Roboto',
|
// fontFamily: 'Roboto',
|
||||||
color: Color(0xFF000000),
|
// color: Color(0xFF000000),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
// fontSize: 11,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
// color: Colors.black,
|
||||||
|
fontFamily: 'Roboto',
|
||||||
|
color: Color(0xFF000000),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 0.5),
|
const SizedBox(height: 0.3),
|
||||||
|
|
||||||
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),
|
||||||
|
|||||||
@ -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,154 +375,179 @@ class _BookMarkState extends ConsumerState<BookMark> {
|
|||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context)!.bookmarks,
|
AppLocalizations.of(context)!.bookmarks,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: isLoading
|
||||||
children: [
|
? Container(
|
||||||
TabBarHeader(
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
tabs: tabs,
|
child: Column(
|
||||||
selectedIndex: selectedTabIndex,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
onTabSelected: (index) {
|
children: [
|
||||||
setState(() {
|
Container(
|
||||||
selectedTabIndex = index;
|
margin: EdgeInsets.symmetric(
|
||||||
});
|
horizontal: 40), // Left & Right space
|
||||||
},
|
child: LinearProgressIndicator(
|
||||||
),
|
minHeight: 5, // Adjust thickness
|
||||||
Expanded(
|
backgroundColor:
|
||||||
child: selectedTabIndex == 0
|
Colors.grey[100], // Optional: Background color
|
||||||
? (bookmarks.isNotEmpty
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
? SingleChildScrollView(
|
Color(0xFFAA8E83)), // Loader color
|
||||||
child: Column(
|
),
|
||||||
children: List.generate(transformedList.length, (i) {
|
),
|
||||||
final mainTopic = transformedList[i];
|
],
|
||||||
print('oustside1 $mainTopic');
|
),
|
||||||
final list = List.from(mainTopic['SubTopic'] ?? []);
|
)
|
||||||
print('oustside2 $list');
|
: Column(
|
||||||
return CustomExpandableTile(
|
children: [
|
||||||
index: i,
|
TabBarHeader(
|
||||||
isExpanded: expandedIndex == i,
|
tabs: tabs,
|
||||||
onTap: (int index) {
|
selectedIndex: selectedTabIndex,
|
||||||
// 🔹 Expecting an index
|
onTabSelected: (index) {
|
||||||
setState(() {
|
setState(() {
|
||||||
expandedIndex =
|
selectedTabIndex = index;
|
||||||
(expandedIndex == index) ? null : index;
|
});
|
||||||
});
|
},
|
||||||
},
|
),
|
||||||
title: mainTopic['main_topic'] ?? 'No Topic',
|
Expanded(
|
||||||
childWidget: Container(
|
child: selectedTabIndex == 0
|
||||||
decoration: BoxDecoration(
|
? (bookmarks.isNotEmpty
|
||||||
color: Colors.white,
|
? SingleChildScrollView(
|
||||||
// borderRadius: BorderRadius.all(Radius.circular(20))
|
child: Column(
|
||||||
),
|
children:
|
||||||
padding: const EdgeInsets.all(16),
|
List.generate(transformedList.length, (i) {
|
||||||
child: GridView.builder(
|
final mainTopic = transformedList[i];
|
||||||
shrinkWrap: true,
|
print('oustside1 $mainTopic');
|
||||||
physics: NeverScrollableScrollPhysics(),
|
final list =
|
||||||
gridDelegate:
|
List.from(mainTopic['SubTopic'] ?? []);
|
||||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
print('oustside2 $list');
|
||||||
crossAxisCount: 2,
|
return CustomExpandableTile(
|
||||||
crossAxisSpacing: 10.0,
|
index: i,
|
||||||
mainAxisSpacing: 10.0,
|
isExpanded: expandedIndex == i,
|
||||||
mainAxisExtent: 100,
|
onTap: (int index) {
|
||||||
),
|
// 🔹 Expecting an index
|
||||||
itemCount: list.length,
|
setState(() {
|
||||||
itemBuilder: (context, index) {
|
expandedIndex = (expandedIndex == index)
|
||||||
return _buildBoxes(
|
? null
|
||||||
mainTopic['SubTopic'][index],
|
: index;
|
||||||
context,
|
});
|
||||||
mainTopic['valueColor']);
|
},
|
||||||
},
|
title:
|
||||||
),
|
mainTopic['main_topic'] ?? 'No Topic',
|
||||||
|
childWidget: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
// borderRadius: BorderRadius.all(Radius.circular(20))
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: GridView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate:
|
||||||
|
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
crossAxisSpacing: 10.0,
|
||||||
|
mainAxisSpacing: 10.0,
|
||||||
|
mainAxisExtent: 100,
|
||||||
|
),
|
||||||
|
itemCount: list.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _buildBoxes(
|
||||||
|
mainTopic['SubTopic'][index],
|
||||||
|
context,
|
||||||
|
mainTopic['valueColor']);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
filteredBookmarks:
|
||||||
|
List.from(mainTopic['SubTopic'] ?? []),
|
||||||
|
titleBackgroundColor:
|
||||||
|
mainTopic['valueColor'],
|
||||||
|
// Ensure it's a new list
|
||||||
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
filteredBookmarks:
|
)
|
||||||
List.from(mainTopic['SubTopic'] ?? []),
|
: Center(
|
||||||
titleBackgroundColor: mainTopic['valueColor'],
|
child: Column(
|
||||||
// Ensure it's a new list
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.info_outline,
|
|
||||||
size: 100, color: Colors.grey[400]),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
context.translate('No BookMark Added',
|
|
||||||
'لم يتم إضافة أي علامة مرجعية'),
|
|
||||||
style:
|
|
||||||
TextStyle(fontSize: 16, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
))
|
|
||||||
: filteredBookmarks.isEmpty
|
|
||||||
? Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.info_outline,
|
|
||||||
size: 100, color: Colors.grey[400]),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
'No Bookmark is added',
|
|
||||||
style:
|
|
||||||
TextStyle(fontSize: 16, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: tabs[selectedTabIndex]['color'],
|
|
||||||
borderRadius:
|
|
||||||
BorderRadius.all(Radius.circular(35))),
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
left: 16, bottom: 5, top: 5, right: 10),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
children: [
|
||||||
|
Icon(Icons.info_outline,
|
||||||
|
size: 100, color: Colors.grey[400]),
|
||||||
|
SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
tabs[selectedTabIndex]['title'],
|
context.translate('No BookMark Added',
|
||||||
|
'لم يتم إضافة أي علامة مرجعية'),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
fontSize: 16, color: Colors.grey),
|
||||||
fontWeight: FontWeight.w600,
|
),
|
||||||
fontSize: 20,
|
],
|
||||||
|
),
|
||||||
|
))
|
||||||
|
: filteredBookmarks.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.info_outline,
|
||||||
|
size: 100, color: Colors.grey[400]),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'No Bookmark is added',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16, color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: tabs[selectedTabIndex]['color'],
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(35))),
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 16, bottom: 5, top: 5, right: 10),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
tabs[selectedTabIndex]['title'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: GridView.builder(
|
||||||
|
gridDelegate:
|
||||||
|
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 2,
|
||||||
|
crossAxisSpacing: 10.0,
|
||||||
|
mainAxisSpacing: 10.0,
|
||||||
|
mainAxisExtent: 100,
|
||||||
|
),
|
||||||
|
itemCount: filteredBookmarks.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _buildBox(
|
||||||
|
filteredBookmarks[index], context);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
height: 20,
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
|
||||||
child: GridView.builder(
|
|
||||||
gridDelegate:
|
|
||||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 2,
|
|
||||||
crossAxisSpacing: 10.0,
|
|
||||||
mainAxisSpacing: 10.0,
|
|
||||||
mainAxisExtent: 100,
|
|
||||||
),
|
|
||||||
itemCount: filteredBookmarks.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return _buildBox(
|
|
||||||
filteredBookmarks[index], context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,23 +485,40 @@ 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
|
||||||
child: Padding(
|
? Container(
|
||||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
SingleChildScrollView(
|
children: [
|
||||||
child: Form(
|
Container(
|
||||||
key: _formKey,
|
margin: EdgeInsets.symmetric(
|
||||||
child: Padding(
|
horizontal: 40), // Left & Right space
|
||||||
// padding: const EdgeInsets.all(20.0),
|
child: LinearProgressIndicator(
|
||||||
padding: const EdgeInsets.only(
|
minHeight: 5, // Adjust thickness
|
||||||
top: 20.0, bottom: 20.0, left: 25, right: 25),
|
backgroundColor:
|
||||||
child: isPageLoad
|
Colors.grey[100], // Optional: Background color
|
||||||
? Center(
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
child: CircularProgressIndicator(),
|
Color(0xFFAA8E83)), // Loader color
|
||||||
)
|
),
|
||||||
: Column(
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 10.0, right: 10.0, top: 3.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: Padding(
|
||||||
|
// padding: const EdgeInsets.all(20.0),
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 20.0, bottom: 20.0, left: 25, right: 25),
|
||||||
|
child: 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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -1150,13 +1165,13 @@ class _EditProfileState extends ConsumerState<EditProfile> {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
//bottomNavigationBar: MyBottomNavBar(),
|
//bottomNavigationBar: MyBottomNavBar(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,17 +278,37 @@ class _FeedbackFormState extends ConsumerState<FeedbackForm>
|
|||||||
// ),
|
// ),
|
||||||
// ],
|
// ],
|
||||||
// ),
|
// ),
|
||||||
body: Padding(
|
body: isLoading
|
||||||
padding: const EdgeInsets.only(
|
? Container(
|
||||||
top: 8.0, bottom: 16.0, left: 23.0, right: 23.0),
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
child: SingleChildScrollView(
|
child: Column(
|
||||||
child: _isFeedbackSubmitted
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
? _buildThankYouMessage(userName)
|
children: [
|
||||||
: _isFeedbackFailed
|
Container(
|
||||||
? _buildFailureMessage()
|
margin: EdgeInsets.symmetric(
|
||||||
: _buildFeedbackForm(),
|
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(
|
||||||
|
child: _isFeedbackSubmitted
|
||||||
|
? _buildThankYouMessage(userName)
|
||||||
|
: _isFeedbackFailed
|
||||||
|
? _buildFailureMessage()
|
||||||
|
: _buildFeedbackForm(),
|
||||||
|
),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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) {
|
||||||
|
|||||||
@ -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,249 +311,273 @@ class _ManageUserRouterState extends ConsumerState<ManageUserRouter> {
|
|||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context)!.manage_user,
|
AppLocalizations.of(context)!.manage_user,
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: isLoading
|
||||||
child: Padding(
|
? Container(
|
||||||
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
// TextField(
|
children: [
|
||||||
// decoration: InputDecoration(
|
Container(
|
||||||
// prefixIcon: const Icon(Icons.search),
|
margin: EdgeInsets.symmetric(
|
||||||
// hintText: 'Search',
|
horizontal: 40), // Left & Right space
|
||||||
// border: OutlineInputBorder(
|
child: LinearProgressIndicator(
|
||||||
// borderRadius: BorderRadius.all(Radius.circular(20)),
|
minHeight: 5, // Adjust thickness
|
||||||
// ),
|
backgroundColor:
|
||||||
// ),
|
Colors.grey[100], // Optional: Background color
|
||||||
// onChanged: filterUsers,
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
// ),
|
Color(0xFFAA8E83)), // Loader color
|
||||||
// Container(
|
),
|
||||||
// height: 40,
|
),
|
||||||
// decoration: BoxDecoration(
|
],
|
||||||
// color: Colors.white,
|
),
|
||||||
// borderRadius: BorderRadius.circular(30.0),
|
)
|
||||||
// border: Border.all(width: 2, color: Color(0xFFAA8E83)),
|
: SingleChildScrollView(
|
||||||
// ),
|
child: Padding(
|
||||||
// child: TextField(
|
padding:
|
||||||
// decoration: InputDecoration(
|
const EdgeInsets.only(left: 10.0, right: 10.0, top: 3.0),
|
||||||
// hintText: AppLocalizations.of(context)!.search,
|
child: Column(
|
||||||
// hintStyle: TextStyle(color: Color(0xFFC3C6CB)),
|
children: [
|
||||||
// prefixIcon: Image.asset(
|
// TextField(
|
||||||
// MiscIconAssetPath.search,
|
// decoration: InputDecoration(
|
||||||
// width: 20,
|
// prefixIcon: const Icon(Icons.search),
|
||||||
// height: 20,
|
// hintText: 'Search',
|
||||||
// ),
|
// border: OutlineInputBorder(
|
||||||
// // ,prefixIcon: Icon(
|
// borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||||
// // Icons.search,
|
// ),
|
||||||
// // color: Color(0xFFAA8E83),
|
// ),
|
||||||
// // ),
|
// onChanged: filterUsers,
|
||||||
// border: InputBorder.none,
|
// ),
|
||||||
// contentPadding: EdgeInsets.symmetric(
|
// Container(
|
||||||
// vertical: 15.0, horizontal: 20.0),
|
// height: 40,
|
||||||
// ),
|
// decoration: BoxDecoration(
|
||||||
// onChanged: filterUsers,
|
// color: Colors.white,
|
||||||
// ),
|
// borderRadius: BorderRadius.circular(30.0),
|
||||||
// ),
|
// border: Border.all(width: 2, color: Color(0xFFAA8E83)),
|
||||||
Container(
|
// ),
|
||||||
height: 40,
|
// child: TextField(
|
||||||
decoration: BoxDecoration(
|
// decoration: InputDecoration(
|
||||||
color: Colors.white,
|
// hintText: AppLocalizations.of(context)!.search,
|
||||||
borderRadius: BorderRadius.circular(30.0),
|
// hintStyle: TextStyle(color: Color(0xFFC3C6CB)),
|
||||||
border: Border.all(width: 1, color: Color(0xFFAA8E83)),
|
// prefixIcon: Image.asset(
|
||||||
),
|
// MiscIconAssetPath.search,
|
||||||
child: Padding(
|
// width: 20,
|
||||||
padding: EdgeInsets.only(left: 12.0),
|
// height: 20,
|
||||||
child: TextField(
|
// ),
|
||||||
decoration: InputDecoration(
|
// // ,prefixIcon: Icon(
|
||||||
hintText: AppLocalizations.of(context)!.search,
|
// // Icons.search,
|
||||||
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
// // color: Color(0xFFAA8E83),
|
||||||
// hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
// // ),
|
||||||
prefixIconConstraints:
|
// border: InputBorder.none,
|
||||||
BoxConstraints(maxWidth: 42, maxHeight: 42),
|
// contentPadding: EdgeInsets.symmetric(
|
||||||
prefixIcon: Container(
|
// vertical: 15.0, horizontal: 20.0),
|
||||||
padding: EdgeInsets.only(right: 5),
|
// ),
|
||||||
child: SvgPicture.asset(
|
// onChanged: filterUsers,
|
||||||
MiscIconAssetPath.Search,
|
// ),
|
||||||
semanticsLabel: 'Search',
|
// ),
|
||||||
colorFilter: ColorFilter.mode(
|
Container(
|
||||||
Color(0xFFAA8E83), BlendMode.srcIn),
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
|
border:
|
||||||
|
Border.all(width: 1, color: Color(0xFFAA8E83)),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(left: 12.0),
|
||||||
|
child: TextField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: AppLocalizations.of(context)!.search,
|
||||||
|
hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
||||||
|
// hintStyle: TextStyle(color: Color(0xFFAA8E83)),
|
||||||
|
prefixIconConstraints:
|
||||||
|
BoxConstraints(maxWidth: 42, maxHeight: 42),
|
||||||
|
prefixIcon: Container(
|
||||||
|
padding: EdgeInsets.only(right: 5),
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
MiscIconAssetPath.Search,
|
||||||
|
semanticsLabel: 'Search',
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
Color(0xFFAA8E83), BlendMode.srcIn),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// prefixIcon: Image.asset(
|
||||||
|
// MiscIconAssetPath.search,
|
||||||
|
// // fit: BoxFit.contain,
|
||||||
|
// ),
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
vertical: 0.5, horizontal: 18.0),
|
||||||
|
),
|
||||||
|
onChanged: filterUsers,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// prefixIcon: Image.asset(
|
|
||||||
// MiscIconAssetPath.search,
|
|
||||||
// // fit: BoxFit.contain,
|
|
||||||
// ),
|
|
||||||
border: InputBorder.none,
|
|
||||||
contentPadding: EdgeInsets.symmetric(
|
|
||||||
vertical: 0.5, horizontal: 18.0),
|
|
||||||
),
|
),
|
||||||
onChanged: filterUsers,
|
SizedBox(height: myheight / 40),
|
||||||
),
|
filteredUserData.isEmpty
|
||||||
),
|
? Center(
|
||||||
),
|
child: Padding(
|
||||||
SizedBox(height: myheight / 40),
|
padding: const EdgeInsets.all(16.0),
|
||||||
isLoading
|
child: Column(
|
||||||
? Center(child: CircularProgressIndicator())
|
mainAxisSize: MainAxisSize.min,
|
||||||
: filteredUserData.isEmpty
|
children: [
|
||||||
? Center(
|
SizedBox(height: myheight / 5),
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(height: myheight / 5),
|
|
||||||
|
|
||||||
// Icon(Icons.search,
|
// Icon(Icons.search,
|
||||||
// size: 60, color: Colors.grey),
|
// size: 60, color: Colors.grey),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
MiscIconAssetPath.group,
|
MiscIconAssetPath.group,
|
||||||
width: 60,
|
width: 60,
|
||||||
height: 60,
|
height: 60,
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(height: 15),
|
|
||||||
// Space between icon and text
|
|
||||||
Text(
|
|
||||||
"No results found",
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.grey[700],
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
SizedBox(height: 12), // Space between texts
|
SizedBox(height: 15),
|
||||||
FittedBox(
|
// Space between icon and text
|
||||||
child: Text(
|
Text(
|
||||||
"We couldn't find anything matching your search.",
|
"No results found",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 24,
|
||||||
color: Color(0xFF898C81)),
|
fontWeight: FontWeight.bold,
|
||||||
textAlign: TextAlign.center,
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
SizedBox(height: 12), // Space between texts
|
||||||
|
FittedBox(
|
||||||
|
child: Text(
|
||||||
|
"We couldn't find anything matching your search.",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
color: Color(0xFF898C81)),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
: SingleChildScrollView(
|
||||||
: SingleChildScrollView(
|
scrollDirection: Axis.horizontal,
|
||||||
scrollDirection: Axis.horizontal,
|
child: ConstrainedBox(
|
||||||
child: ConstrainedBox(
|
constraints: BoxConstraints(
|
||||||
constraints: BoxConstraints(
|
minWidth: MediaQuery.of(context).size.width,
|
||||||
minWidth: MediaQuery.of(context).size.width,
|
),
|
||||||
),
|
child: DataTable(
|
||||||
child: DataTable(
|
sortColumnIndex: _sortColumnIndex,
|
||||||
sortColumnIndex: _sortColumnIndex,
|
sortAscending: _isAscending,
|
||||||
sortAscending: _isAscending,
|
columns: [
|
||||||
columns: [
|
DataColumn(
|
||||||
DataColumn(
|
label: Text(
|
||||||
label: Text(
|
AppLocalizations.of(context)!.user_name,
|
||||||
AppLocalizations.of(context)!.user_name,
|
),
|
||||||
|
onSort: (columnIndex, ascending) {
|
||||||
|
_sort(
|
||||||
|
(user) =>
|
||||||
|
user.userName.toLowerCase(),
|
||||||
|
columnIndex,
|
||||||
|
ascending);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
onSort: (columnIndex, ascending) {
|
DataColumn(
|
||||||
_sort(
|
label: Text(
|
||||||
(user) => user.userName.toLowerCase(),
|
AppLocalizations.of(context)!.email_id,
|
||||||
|
),
|
||||||
|
onSort: (columnIndex, ascending) {
|
||||||
|
_sort(
|
||||||
|
(user) =>
|
||||||
|
user.emailId.toLowerCase(),
|
||||||
|
columnIndex,
|
||||||
|
ascending);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: Text(
|
||||||
|
AppLocalizations.of(context)!.reg_date,
|
||||||
|
),
|
||||||
|
onSort: (columnIndex, ascending) {
|
||||||
|
_sort(
|
||||||
|
(user) => DateFormat('dd/MM/yyyy')
|
||||||
|
.parse(user.registrationDate),
|
||||||
columnIndex,
|
columnIndex,
|
||||||
ascending);
|
ascending,
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
DataColumn(
|
|
||||||
label: Text(
|
|
||||||
AppLocalizations.of(context)!.email_id,
|
|
||||||
),
|
),
|
||||||
onSort: (columnIndex, ascending) {
|
DataColumn(
|
||||||
_sort(
|
label: Text(
|
||||||
(user) => user.emailId.toLowerCase(),
|
AppLocalizations.of(context)!.status,
|
||||||
columnIndex,
|
),
|
||||||
ascending);
|
onSort: (columnIndex, ascending) {
|
||||||
},
|
_sort(
|
||||||
),
|
(user) => user.status.toLowerCase(),
|
||||||
DataColumn(
|
columnIndex,
|
||||||
label: Text(
|
ascending);
|
||||||
AppLocalizations.of(context)!.reg_date,
|
},
|
||||||
),
|
),
|
||||||
onSort: (columnIndex, ascending) {
|
],
|
||||||
_sort(
|
rows: filteredUserData.isEmpty
|
||||||
(user) => DateFormat('dd/MM/yyyy')
|
? [
|
||||||
.parse(user.registrationDate),
|
DataRow(
|
||||||
columnIndex,
|
cells: List<DataCell>.generate(
|
||||||
ascending,
|
4, // Ensure it matches the number of DataColumns
|
||||||
);
|
(index) => DataCell(
|
||||||
},
|
index == 0
|
||||||
),
|
? Text(
|
||||||
DataColumn(
|
'No results found',
|
||||||
label: Text(
|
style: TextStyle(
|
||||||
AppLocalizations.of(context)!.status,
|
fontStyle: FontStyle
|
||||||
),
|
.italic),
|
||||||
onSort: (columnIndex, ascending) {
|
)
|
||||||
_sort((user) => user.status.toLowerCase(),
|
: const Text(
|
||||||
columnIndex, ascending);
|
''), // Empty cells for other columns
|
||||||
},
|
placeholder: true,
|
||||||
),
|
|
||||||
],
|
|
||||||
rows: filteredUserData.isEmpty
|
|
||||||
? [
|
|
||||||
DataRow(
|
|
||||||
cells: List<DataCell>.generate(
|
|
||||||
4, // Ensure it matches the number of DataColumns
|
|
||||||
(index) => DataCell(
|
|
||||||
index == 0
|
|
||||||
? Text(
|
|
||||||
'No results found',
|
|
||||||
style: TextStyle(
|
|
||||||
fontStyle:
|
|
||||||
FontStyle.italic),
|
|
||||||
)
|
|
||||||
: const Text(
|
|
||||||
''), // Empty cells for other columns
|
|
||||||
placeholder: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
: filteredUserData.map((user) {
|
|
||||||
return DataRow(
|
|
||||||
cells: [
|
|
||||||
DataCell(Text(user.userName)),
|
|
||||||
DataCell(Text(user.emailId)),
|
|
||||||
DataCell(
|
|
||||||
Text(user.registrationDate)),
|
|
||||||
DataCell(
|
|
||||||
DropdownButton<String>(
|
|
||||||
value: user.status,
|
|
||||||
items: statusOptions.entries
|
|
||||||
.map((status) {
|
|
||||||
return DropdownMenuItem<
|
|
||||||
String>(
|
|
||||||
value: status.key,
|
|
||||||
child: Text(
|
|
||||||
status.value,
|
|
||||||
style: TextStyle(
|
|
||||||
color: getStatusColor(
|
|
||||||
status.key),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
onChanged: (newStatus) {
|
|
||||||
print(user);
|
|
||||||
if (newStatus != null) {
|
|
||||||
_showConfirmationDialog(
|
|
||||||
user, newStatus);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
]
|
||||||
}).toList(),
|
: filteredUserData.map((user) {
|
||||||
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(Text(user.userName)),
|
||||||
|
DataCell(Text(user.emailId)),
|
||||||
|
DataCell(
|
||||||
|
Text(user.registrationDate)),
|
||||||
|
DataCell(
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: user.status,
|
||||||
|
items: statusOptions.entries
|
||||||
|
.map((status) {
|
||||||
|
return DropdownMenuItem<
|
||||||
|
String>(
|
||||||
|
value: status.key,
|
||||||
|
child: Text(
|
||||||
|
status.value,
|
||||||
|
style: TextStyle(
|
||||||
|
color: getStatusColor(
|
||||||
|
status.key),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: (newStatus) {
|
||||||
|
print(user);
|
||||||
|
if (newStatus != null) {
|
||||||
|
_showConfirmationDialog(
|
||||||
|
user, newStatus);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,60 +178,83 @@ class _NotificationPageState extends ConsumerState<NotificationPage> {
|
|||||||
'إشعار',
|
'إشعار',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: isLoading
|
||||||
children: [
|
? Container(
|
||||||
TabBarHeader(
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
tabs: tabs.map((tab) => tab['title'] as String).toList(),
|
child: Column(
|
||||||
selectedIndex: selectedTabIndex,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
onTabSelected: (index) {
|
children: [
|
||||||
setState(() {
|
Container(
|
||||||
selectedTabIndex = index;
|
margin: EdgeInsets.symmetric(
|
||||||
});
|
horizontal: 40), // Left & Right space
|
||||||
},
|
child: LinearProgressIndicator(
|
||||||
),
|
minHeight: 5, // Adjust thickness
|
||||||
Expanded(
|
backgroundColor:
|
||||||
child: filteredNotifications.isEmpty
|
Colors.grey[100], // Optional: Background color
|
||||||
? Center(
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
child: Column(
|
Color(0xFFAA8E83)), // Loader color
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.info_outline,
|
|
||||||
size: 100, color: Colors.grey[400]),
|
|
||||||
SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
'No notifications available.',
|
|
||||||
style: TextStyle(fontSize: 16, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
)
|
|
||||||
: ListView.builder(
|
|
||||||
itemCount: filteredNotifications.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final notification = filteredNotifications[index];
|
|
||||||
return Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
color: Color(0xFFDEDEDE),
|
|
||||||
width: 1), // Bottom border only
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: NotificationTile(
|
|
||||||
title: notification['title'] ?? 'No Title',
|
|
||||||
date: formatDate(notification['created'] ?? ''),
|
|
||||||
category: notification['category'] ?? 'Unknown',
|
|
||||||
message: notification['message'] ?? '',
|
|
||||||
id: notification['id'],
|
|
||||||
pushedNotification: pushedNotification,
|
|
||||||
userID: userID,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
)
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
TabBarHeader(
|
||||||
|
tabs: tabs.map((tab) => tab['title'] as String).toList(),
|
||||||
|
selectedIndex: selectedTabIndex,
|
||||||
|
onTabSelected: (index) {
|
||||||
|
setState(() {
|
||||||
|
selectedTabIndex = index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: filteredNotifications.isEmpty
|
||||||
|
? Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.info_outline,
|
||||||
|
size: 100, color: Colors.grey[400]),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
Text(
|
||||||
|
'No notifications available.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16, color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: filteredNotifications.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final notification = filteredNotifications[index];
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: Color(0xFFDEDEDE),
|
||||||
|
width: 1), // Bottom border only
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: NotificationTile(
|
||||||
|
title: notification['title'] ?? 'No Title',
|
||||||
|
date:
|
||||||
|
formatDate(notification['created'] ?? ''),
|
||||||
|
category:
|
||||||
|
notification['category'] ?? 'Unknown',
|
||||||
|
message: notification['message'] ?? '',
|
||||||
|
id: notification['id'],
|
||||||
|
pushedNotification: pushedNotification,
|
||||||
|
userID: userID,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,53 +139,73 @@ 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
|
||||||
padding: const EdgeInsets.all(16.0),
|
? Container(
|
||||||
child: Column(
|
color: Color(0x98FFFCE5), // Semi-transparent background
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
notification?['title'] ?? '',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: Color(0xFF414042)),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 20),
|
|
||||||
Center(
|
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
Container(
|
||||||
notification?['category'] == 'App updates'
|
margin: EdgeInsets.symmetric(
|
||||||
? 'assets/backgrounds/Notification/App-Update.png'
|
horizontal: 40), // Left & Right space
|
||||||
: 'assets/backgrounds/Notification/Update_notific.png',
|
child: LinearProgressIndicator(
|
||||||
height: 200,
|
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,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
notification?['title'] ?? '',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Color(0xFF414042)),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
notification?['category'] == 'App updates'
|
||||||
|
? 'assets/backgrounds/Notification/App-Update.png'
|
||||||
|
: 'assets/backgrounds/Notification/Update_notific.png',
|
||||||
|
height: 200,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
notification?['message'] ??
|
||||||
|
"No additional details available.",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Color(0xFF414042)),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
"Date: ${notification != null ? formatDate(notification!['created'] ?? '') : 'N/A'}",
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Color(0xFF8E8E8E),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
|
||||||
Text(
|
|
||||||
notification?['message'] ??
|
|
||||||
"No additional details available.",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: Color(0xFF414042)),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
Text(
|
|
||||||
"Date: ${notification != null ? formatDate(notification!['created'] ?? '') : 'N/A'}",
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: Color(0xFF8E8E8E),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1244,9 +1244,14 @@ void _showLogoutConfirmationDialog(BuildContext context) {
|
|||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: FittedBox(
|
||||||
context.translate('Log Out', 'تسجيل الخروج'),
|
fit: BoxFit
|
||||||
style: TextStyle(color: Colors.white, fontSize: 16),
|
.scaleDown, // Prevents wrapping while adjusting text size
|
||||||
|
child: Text(
|
||||||
|
context.translate('Log Out', 'تسجيل الخروج'),
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 16),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user