username and upload file changes

This commit is contained in:
Surendiran 2025-11-27 11:32:19 +05:30
parent 521bd49a17
commit 45eb1d4c36
17 changed files with 2323 additions and 838 deletions

View File

@ -8,13 +8,25 @@ import 'package:nhance_app_pwa/customAppBar/responsive.dart';
import '../pages/postEnrollment/service/api_service.dart';
import '../pages/service/SessionManager.dart';
import '../pages/service/popup_helper.dart';
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
@override
_CustomAppBarState createState() => _CustomAppBarState();
class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
}
class _CustomAppBarState extends State<CustomAppBar> {
@override
Size get preferredSize => Size.fromHeight(kToolbarHeight);
late ApiService apiService;
final session = SessionManager();
@override
void initState() {
super.initState();
apiService = ApiService(context);
}
Future<void> logout(BuildContext context) async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('_postToken');
@ -28,107 +40,179 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
apiService = ApiService(context);
final sw = MediaQuery.of(context).size.width;
final isPoliciesPage = Uri.base.fragment == 'policies';
return ClipRRect(
borderRadius: Responsive.isDesktop(context) || isPoliciesPage
? BorderRadius.zero
: BorderRadius.only(
bottomLeft: Radius.circular(32.0),
bottomRight: Radius.circular(32.0),
return Scaffold(
backgroundColor: Color(0xFFFFFCE5), // Set background color for AppBar
appBar: PreferredSize(
preferredSize: widget.preferredSize,
child: SafeArea(
child: Container(
// padding: Responsive.isDesktop(context)
// ? EdgeInsets.symmetric(horizontal: 46.0)
// : EdgeInsets.symmetric(horizontal: 0),
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width *
(Responsive.isDesktop(context) ? 0.03 : 0.02),
),
child: AppBar(
backgroundColor: const Color(0xFFFFFBDE),
elevation: 0, // Set background color for AppBar
toolbarHeight: kToolbarHeight,
titleSpacing: 0.0,
automaticallyImplyLeading: false,
title: Padding(
padding: Responsive.isDesktop(context)
? EdgeInsets.symmetric(horizontal: 16.0)
: EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: [
// Logo Column
Expanded(
flex: Responsive.isDesktop(context) ? 3 : 9,
child: Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Logo Column
// Expanded(
// // flex: Responsive.isDesktop(context) ? 1 : 9,
// child:
Row(
mainAxisAlignment: Responsive.isDesktop(context)
? MainAxisAlignment.spaceEvenly
: MainAxisAlignment
.start, // Adjust the alignment as needed
: MainAxisAlignment.start,
children: [
Container(
// margin: EdgeInsets.only(
// top: 10, bottom: 10, left: 10, right: 10),
// width: Responsive.isDesktop(context) ? 150 : 130,
// height: Responsive.isDesktop(context) ? 31 : 130,
child: SvgPicture.asset(
'assets/nhance_client_logo.svg',
width: 150,
margin: EdgeInsets.only(top: 10, bottom: 10),
width: 150,
height: 150,
child: Image.asset(
'assets/nhance_client_logo.png',
fit: BoxFit.contain,
),
// child: Image.asset(
// 'assets/nhance_logo.png',
// width: 250,
// ),
),
],
),
),
// AdaptiveNavBar Column
if (Responsive.isDesktop(context))
Expanded(
flex: Responsive.isDesktop(context) ? 9 : 3,
child: AdaptiveNavBar(
screenWidth: sw,
backgroundColor: const Color(0xFFFFFBDE),
leading:
Container(), // Set an empty container as we have the logo separately
title: Text(''),
navBarItems: [
NavBarItem(
text: "Home",
onTap: () {
context.push('/home');
},
),
NavBarItem(
text: "Claims",
onTap: () {
context.push('/claims');
},
),
NavBarItem(
text: "Help",
onTap: () {
context.push('/help');
},
),
NavBarItem(
text: "Wellness",
onTap: () {
// Wellness tab clicked show popup
PopupHelper.showRedirectPopup(
context: context,
apiService: apiService,
empPrimaryId: session.empPrimaryId,
);
},
),
NavBarItem(
text: "Profile",
onTap: () {
context.push('/profile');
},
),
],
),
// ),
// AdaptiveNavBar Column
// Expanded(
// // flex: Responsive.isDesktop(context) ? 1 : 9,
// child:
if(Responsive.isDesktop(context))
Row(
mainAxisSize: MainAxisSize.min,
children: [
NavBarItem(
text: "Home",
onTap: () {
context.push('/home');
},
),
NavBarItem(
text: "Claims",
onTap: () {
context.push('/claims');
},
),
NavBarItem(
text: "Help",
onTap: () {
context.push('/help');
},
),
NavBarItem(
text: "Wellness",
onTap: () {
// context.push('/wellness');
// Wellness tab clicked show popup
PopupHelper.showRedirectPopup(
context: context,
apiService: apiService,
empPrimaryId: session.empPrimaryId,
);
},
),
NavBarItem(
text: "Profile",
onTap: () {
context.push('/profile');
},
),
],
),
],
// )
// Expanded(
// flex: Responsive.isDesktop(context) ? 9 : 3,
// child: AdaptiveNavBar(
// screenWidth: sw,
// backgroundColor: Color(0xFFFFFCE5),
// leading:
// Container(), // Set an empty container as we have the logo separately
// title: Text(''),
// navBarItems: [
// // if (Responsive.isDesktop(context))
// // if (hideInactiveStatus)
// // NavBarItem(
// // text: "Inactive Policy",
// // onTap: () {
// // Navigator.pushNamed(context, 'oldPolicy');
// // },
// // ),
// // if (showBackToHR)
// NavBarItem(
// text: "Change Branch",
// onTap: () async {
// final prefs = await SharedPreferences.getInstance();
// await prefs.remove('selected_branch');
// await prefs.remove('decoded_token');
// await prefs.remove('clientLogo');
// await prefs.remove('clientName');
// await prefs.remove('empAllowed_modules');
// await prefs.remove('empClientBranchId');
// await prefs.remove('empClientId');
// await prefs.remove('empEmail');
// await prefs.remove('empHrId');
// await prefs.remove('empPrimaryId');
// await prefs.remove('enrollmentAllowed_modules');
// await prefs.remove('enrollmentClient_id');
// await prefs.remove('enrollmentEmpClientBranchId');
// await prefs.remove('enrollmentEmpPrimaryId');
// await prefs.remove('enrollmentHrId');
// await prefs.remove('token');
// Navigator.pushNamed(context, 'branchSelection');
// },
// ),
// NavBarItem(
// text: "Logout",
// onTap: () async {
// logout(context);
// },
// ),
// ],
// ),
// ),
],
),
),
),
),
);
}
}
class NavBarItem extends StatelessWidget {
final String text;
final VoidCallback? onTap;
const NavBarItem({
Key? key,
required this.text,
this.onTap,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return InkWell(
borderRadius: BorderRadius.circular(6),
onTap: onTap,
hoverColor: const Color(0xFFF4F3E7), // subtle hover background
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: Text(
text,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
);
}
}

View File

@ -41,12 +41,25 @@ class _changesPasswordState extends State<changesPassword> {
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;
late SessionManager session;
bool hasMinLength = false;
bool hasUpperLower = false;
bool hasNumber = false;
bool hasSpecialChar = false;
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
@override
void initState() {
super.initState();
}
void validatePassword(String password) {
setState(() {
hasMinLength = password.length >= 8;
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').hasMatch(password);
});
}
Future<void> resetYourPassword() async {
final oldpassword = oldPasswordController.text.trim();
@ -354,7 +367,7 @@ class _changesPasswordState extends State<changesPassword> {
MainAxisAlignment.center,
children: [
Text(
"Welcome to Nhance",
"Change Password",
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.bold,
@ -378,7 +391,7 @@ class _changesPasswordState extends State<changesPassword> {
children: [
Expanded(
child: Text(
"Login with your to review and enroll for exciting health benefits for you and your family",
"To change your password, please fill in the fields below.",
style: GoogleFonts.poppins(
fontSize: 12,
color: Color(0xFF000000)),
@ -466,70 +479,58 @@ class _changesPasswordState extends State<changesPassword> {
const SizedBox(height: 10),
Container(
height: 55,
margin: Responsive.isDesktop(
context)
? const EdgeInsets
.symmetric(
horizontal: 150)
: const EdgeInsets
.symmetric(
horizontal: 0),
margin: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: TextFormField(
controller:
newPasswordController,
obscureText:
_obscureNewPassword,
textAlignVertical:
TextAlignVertical
.center,
controller: newPasswordController,
obscureText: _obscureNewPassword,
onChanged: validatePassword,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText:
"New Password",
contentPadding:
const EdgeInsets
.symmetric(
horizontal: 10),
hintText: "New Password",
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
suffixIcon: IconButton(
icon: Icon(
_obscureNewPassword
? Icons
.visibility_off
: Icons
.visibility,
_obscureNewPassword ? Icons.visibility_off : Icons.visibility,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureNewPassword =
!_obscureNewPassword;
_obscureNewPassword = !_obscureNewPassword;
});
},
),
),
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Please enter your new password';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
if (!RegExp(
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$')
.hasMatch(value)) {
return 'Include at least 1 uppercase letter and 1 number';
}
return null;
},
),
),
const SizedBox(height: 8),
// 🔹 VALIDATION LIST
Padding(
padding: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
],
),
Row(
children: [
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
],
),
],
),
),
const SizedBox(height: 10),
@ -767,4 +768,28 @@ class _changesPasswordState extends State<changesPassword> {
)),
)));
}
Widget _buildCheckItem(bool status, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Icon(
status ? Icons.check : Icons.close,
color: status ? Colors.green : Colors.red,
size: 18,
),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(
color: status ? Colors.green : Colors.red,
fontSize: 14,
),
),
],
),
);
}
}

View File

@ -442,9 +442,9 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
// final SharedPreferences prefs = await SharedPreferences.getInstance();
// prefs.setString('empEmailid', widget.email);
ToastHelper.showSuccessToast(context, 'Successfully Login');
// checkPassword(context,session.empEmailCorporate,session.client_id,'home');
checkPassword(context,session.empEmailCorporate,session.client_id,'home');
// if (emp_status == 'enrolled' || emp_status == 'active') {
context.go('/home');
// context.go('/home');
// Navigator.pushReplacementNamed(context, 'home');
// } else {
// Navigator.pushReplacementNamed(context, 'empDetails');
@ -499,11 +499,11 @@ class _MyEmailVerifyState extends State<MyEmailVerify> {
} else {
if (_preToken != null && _preToken.isNotEmpty) {
ToastHelper.showSuccessToast(context, 'Successfully Login');
// checkPassword(context,session.enrollmentEmailCorporate,session.enrollmentClient_id,'empDetails');
checkPassword(context,session.enrollmentEmailCorporate,session.enrollmentClient_id,'empDetails');
// if (emp_status == 'enrolled' || emp_status == 'active') {
// Navigator.pushReplacementNamed(context, 'home');
// } else {
context.go('/empDetails');
// context.go('/empDetails');
// Navigator.pushReplacementNamed(context, 'empDetails');
// }
}

File diff suppressed because it is too large Load Diff

View File

@ -960,15 +960,25 @@ class _claimsState extends State<claims> {
print(claimStatus);
print(claimsDepartmentName);
final Map<String, Color> statusColors = {
'Received': Colors.blueGrey, // New / Received
'Under Process': Colors.orangeAccent, // Work in progress
'Approved': Colors.green, // Approved
'Settled': Colors.teal, // Completed successfully
'Returned': Colors.deepOrange, // Sent back for correction
'Rejected': Colors.red, // Rejected
'Cancelled': Colors.redAccent, // Cancelled
'Closed': Colors.grey, // Closed
'Claim Received': Colors.blueGrey,
'Under Process' : Colors.orangeAccent,
'Information Required': Colors.deepOrange,
'Approved': Colors.green,
'Settled': Colors.teal,
'Denial Review Awaited':Colors.redAccent,
'Rejected': Colors.red,
// 'Received': Colors.blueGrey, // New / Received
// 'Under Process': Colors.orangeAccent, // Work in progress
// 'Approved': Colors.green, // Approved
// 'Settled': Colors.teal, // Completed successfully
// 'Returned': Colors.deepOrange, // Sent back for correction
// 'Rejected': Colors.red, // Rejected
// 'Cancelled': Colors.redAccent, // Cancelled
// 'Closed': Colors.grey, // Closed
};
// Determine the color based on the claimStatus

View File

@ -601,6 +601,7 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
Widget _getStepTitleFromApi(String status, Map<String, dynamic> data) {
final modifiedBy = data['modified_by'] ?? '';
final modifiedAt = data['modified_at'] ?? '';
final symbol = (data['modified_by'] != null && data['modified_by'] != '') ? ' - ' : '';
final isDesktop = Responsive.isDesktop(context);
return RichText(
@ -615,7 +616,7 @@ class _ClaimHistoryPopupState extends State<ClaimHistoryPopup> {
),
),
TextSpan(
text: ' ($modifiedBy $modifiedAt)',
text: ' ($modifiedBy$symbol$modifiedAt)',
style: GoogleFonts.poppins(
fontSize: Responsive.isDesktop(context) ? 14 : 11,
fontWeight: FontWeight.w400,

View File

@ -1053,13 +1053,23 @@ class _HomeState extends State<Home> {
crossAxisCount: Responsive.isDesktop(context) ? 2 : 1,
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
childAspectRatio: Responsive.isDesktop(context) ? 3.2 : 2.8),
childAspectRatio: Responsive.isDesktop(context) ? 2.2 : 2.6),
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
var item = data[index];
String policyHeading = item['heading'];
String policyName = item['policy_name'];
String si_value = item['si_value'];
// String si_value = item['si_value'];
String siValueStr = item['si_value'] ?? '0';
String settledStr = item['total_settled_amount']?.toString() ?? '0';
double siValue = double.tryParse(siValueStr) ?? 0;
double settled = double.tryParse(settledStr) ?? 0;
// Main logic
double finalValue = (settled == 0) ? siValue : (siValue - settled);
print("Final Value: $finalValue");
String policyEndDate = item['policy_end_date'];
List<dynamic> employeePolicy = item['EmployeePolicy'];
String memberNames = getMemberNames(employeePolicy);
@ -1188,7 +1198,7 @@ class _HomeState extends State<Home> {
children: [
Text(
formatToCroresLakhsAndThousands(
si_value),
siValueStr),
textAlign: TextAlign.left,
style: GoogleFonts.poppins(
fontSize:
@ -1247,7 +1257,34 @@ class _HomeState extends State<Home> {
),
],
),
SizedBox(height: 7),
SizedBox(height: 20),
Row(
children: [
Expanded(
flex: 12,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.end,
children: [
Text(
'Remaining Amount: ${finalValue}',
textAlign: TextAlign.right,
style: GoogleFonts.poppins(
fontSize:
Responsive.isDesktop(
context)
? 10
: 10,
fontWeight: FontWeight.w400,
color: Color(0xFF747474),
),
),
],
),
),
],
),
// SizedBox(height: 7),
],
))),
],

View File

@ -24,6 +24,8 @@ import 'package:file_picker/file_picker.dart';
import '../service/SessionManager.dart';
import '../service/TokenService.dart';
import '../service/popup_helper.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
class planclaimsform extends StatefulWidget {
final Map<String, dynamic>? details;
@ -634,29 +636,73 @@ class _planclaimsformState extends State<planclaimsform> {
}
// NEW VALIDATION: At least one PDF must be uploaded
bool hasPdf = uploadedFiles.any((uf) {
final ext = uf.file.extension?.toLowerCase() ?? '';
return ext == 'pdf';
});
if (!hasPdf) {
ToastHelper.showErrorToast(context, 'Please upload at least one PDF document');
setState(() => isLoading = false);
return;
}
// bool hasPdf = uploadedFiles.any((uf) {
// final ext = uf.file.extension?.toLowerCase() ?? '';
// return ext == 'pdf';
// });
//
// if (!hasPdf) {
// ToastHelper.showErrorToast(context, 'Please upload at least one PDF document');
// setState(() => isLoading = false);
// return;
// }
// Add files
// for (var uf in uploadedFiles) {
// final pf = uf.file;
// if (pf.bytes != null) {
// request.files.add(http.MultipartFile.fromBytes(
// 'claim_docs[]',
// pf.bytes!,
// filename: pf.name,
// ));
// }
// }
// Add files convert images to PDF if needed
for (var uf in uploadedFiles) {
final pf = uf.file;
final ext = pf.extension?.toLowerCase() ?? '';
if (pf.bytes != null) {
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
pf.bytes!,
filename: pf.name,
));
Uint8List fileBytes = pf.bytes!;
if (['jpg', 'jpeg', 'png', 'heic'].contains(ext)) {
// Convert image PDF
final pdf = pw.Document();
final image = pw.MemoryImage(fileBytes);
pdf.addPage(
pw.Page(
build: (pw.Context context) => pw.Center(
child: pw.Image(image, fit: pw.BoxFit.contain),
),
),
);
fileBytes = await pdf.save(); // converted PDF bytes
// replace file name with .pdf extension
final pdfFileName = pf.name.replaceAll(RegExp(r'\.\w+$'), '.pdf');
print('📄 Converted image ${pf.name} → PDF ($pdfFileName)');
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
fileBytes,
filename: pdfFileName,
));
} else {
// Already a PDF
request.files.add(http.MultipartFile.fromBytes(
'claim_docs[]',
fileBytes,
filename: pf.name,
));
}
}
}
// Combine all names into a JSON array string
final claimDocNames = uploadedFiles.map((uf) => uf.label.trim()).toList();
final encodedNames = jsonEncode(claimDocNames);

View File

@ -787,10 +787,10 @@ class _profileState extends State<profile> {
mainAxisSize: MainAxisSize.min,
children: [
// Change Password Button
// if(Responsive.isDesktop(context))
// _buildChangePasswordButton(context),
if(Responsive.isDesktop(context))
_buildChangePasswordButton(context),
// const SizedBox(width: 10),
const SizedBox(width: 10),
// Logout Button
Responsive.isDesktop(context)

View File

@ -146,6 +146,7 @@ class ApiService {
await _initializeToken();
}
final url = Uri.parse('${Environment.apiUrl}getWellnessURL?emp_id=$empPrimaryId');
// final url = Uri.parse('${Environment.apiUrl}getWellnessURL?emp_id=$empPrimaryId&client_policy_id=$client_policy_id');
final headers = {
'Authorization': 'Bearer $_postToken' ?? '',
};

View File

@ -41,12 +41,25 @@ class _setPasswordState extends State<setPassword> {
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;
late SessionManager session;
bool hasMinLength = false;
bool hasUpperLower = false;
bool hasNumber = false;
bool hasSpecialChar = false;
bool get isPasswordValid => hasMinLength && hasUpperLower && hasNumber && hasSpecialChar;
@override
void initState() {
super.initState();
}
void validatePassword(String password) {
setState(() {
hasMinLength = password.length >= 8;
hasUpperLower = RegExp(r'(?=.*[A-Za-z])').hasMatch(password);
hasNumber = RegExp(r'(?=.*\d)').hasMatch(password);
hasSpecialChar = RegExp(r'(?=.*[@$!%*#?&])').hasMatch(password);
});
}
Future<void> resetYourPassword() async {
final newPassword = newPasswordController.text.trim();
@ -348,7 +361,7 @@ class _setPasswordState extends State<setPassword> {
MainAxisAlignment.center,
children: [
Text(
"Welcome to Nhance",
"Set a new password",
style: GoogleFonts.poppins(
fontSize: 16,
fontWeight: FontWeight.bold,
@ -372,7 +385,7 @@ class _setPasswordState extends State<setPassword> {
children: [
Expanded(
child: Text(
"Login with your to review and enroll for exciting health benefits for you and your family",
"Create a new password. Ensure it differs from previous ones for security",
style: GoogleFonts.poppins(
fontSize: 12,
color: Color(0xFF000000)),
@ -391,70 +404,58 @@ class _setPasswordState extends State<setPassword> {
// 🔹 Password Field
Container(
height: 55,
margin: Responsive.isDesktop(
context)
? const EdgeInsets
.symmetric(
horizontal: 150)
: const EdgeInsets
.symmetric(
horizontal: 0),
margin: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 0),
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
borderRadius:
BorderRadius.circular(
10),
border: Border.all(width: 1, color: Colors.grey),
borderRadius: BorderRadius.circular(10),
),
child: TextFormField(
controller:
newPasswordController,
obscureText:
_obscureNewPassword,
textAlignVertical:
TextAlignVertical
.center,
controller: newPasswordController,
obscureText: _obscureNewPassword,
onChanged: validatePassword,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
border: InputBorder.none,
hintText:
"New Password",
contentPadding:
const EdgeInsets
.symmetric(
horizontal: 10),
hintText: "New Password",
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
suffixIcon: IconButton(
icon: Icon(
_obscureNewPassword
? Icons
.visibility_off
: Icons
.visibility,
_obscureNewPassword ? Icons.visibility_off : Icons.visibility,
color: Colors.grey,
),
onPressed: () {
setState(() {
_obscureNewPassword =
!_obscureNewPassword;
_obscureNewPassword = !_obscureNewPassword;
});
},
),
),
validator: (value) {
if (value == null ||
value.isEmpty) {
return 'Please enter your new password';
}
if (value.length < 6) {
return 'Password must be at least 6 characters';
}
if (!RegExp(
r'^(?=.*[A-Z])(?=.*[0-9]).{6,}$')
.hasMatch(value)) {
return 'Include at least 1 uppercase letter and 1 number';
}
return null;
},
),
),
const SizedBox(height: 8),
// 🔹 VALIDATION LIST
Padding(
padding: Responsive.isDesktop(context)
? const EdgeInsets.symmetric(horizontal: 150)
: const EdgeInsets.symmetric(horizontal: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(child: _buildCheckItem(hasMinLength, "Minimum 8 characters")),
Expanded(child: _buildCheckItem(hasSpecialChar, "1 special character")),
],
),
Row(
children: [
Expanded(child: _buildCheckItem(hasUpperLower, "1 UPPER or lower case")),
Expanded(child: _buildCheckItem(hasNumber, "1 numerical")),
],
),
],
),
),
const SizedBox(height: 10),
@ -561,7 +562,7 @@ class _setPasswordState extends State<setPassword> {
),
)
: Text(
"Reset Password",
"Update Password",
style: GoogleFonts
.poppins(
color: Color(
@ -692,4 +693,28 @@ class _setPasswordState extends State<setPassword> {
)),
)));
}
Widget _buildCheckItem(bool status, String text) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
children: [
Icon(
status ? Icons.check : Icons.close,
color: status ? Colors.green : Colors.red,
size: 18,
),
const SizedBox(width: 6),
Text(
text,
style: TextStyle(
color: status ? Colors.green : Colors.red,
fontSize: 14,
),
),
],
),
);
}
}

View File

@ -8,6 +8,7 @@
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <printing/printing_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) printing_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
printing_plugin_register_with_registrar(printing_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
flutter_secure_storage_linux
printing
url_launcher_linux
)

View File

@ -13,6 +13,7 @@ import google_sign_in_ios
import local_auth_darwin
import package_info_plus
import path_provider_foundation
import printing
import shared_preferences_foundation
import sqflite_darwin
import url_launcher_macos
@ -28,6 +29,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

View File

@ -67,6 +67,7 @@ dependencies:
universal_html: ^2.2.4
go_router: ^16.2.2
flutter_secure_storage: ^9.2.4
printing: ^5.14.2
dev_dependencies:
flutter_test:

View File

@ -10,6 +10,7 @@
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <local_auth_windows/local_auth_plugin.h>
#include <printing/printing_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
@ -21,6 +22,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
LocalAuthPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
PrintingPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PrintingPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_inappwebview_windows
flutter_secure_storage_windows
local_auth_windows
printing
url_launcher_windows
)