|
|
|
|
@ -7,9 +7,11 @@ import 'package:test_sa/extensions/text_extensions.dart';
|
|
|
|
|
import 'package:test_sa/extensions/widget_extensions.dart';
|
|
|
|
|
import 'package:test_sa/models/new_models/general_response_model.dart';
|
|
|
|
|
import 'package:test_sa/models/new_models/update_password.dart';
|
|
|
|
|
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
|
|
|
|
|
import 'package:test_sa/new_views/app_style/app_color.dart';
|
|
|
|
|
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
|
|
|
|
|
import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
|
|
|
|
|
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
|
|
|
|
|
import 'package:test_sa/new_views/pages/login_page.dart';
|
|
|
|
|
import 'package:test_sa/views/widgets/item_views/info_header_widget.dart';
|
|
|
|
|
import 'package:test_sa/views/widgets/item_views/info_text_widget.dart';
|
|
|
|
|
@ -40,9 +42,14 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
|
|
|
|
|
return Form(
|
|
|
|
|
key: _formKey,
|
|
|
|
|
child: Scaffold(
|
|
|
|
|
appBar: const DefaultAppBar(
|
|
|
|
|
title: '',
|
|
|
|
|
backgroundColor: Colors.transparent,
|
|
|
|
|
),
|
|
|
|
|
body: Column(
|
|
|
|
|
children: [
|
|
|
|
|
SingleChildScrollView(
|
|
|
|
|
padding: const EdgeInsets.all(16),
|
|
|
|
|
child: Column(
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
@ -57,6 +64,10 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
|
|
|
|
|
validator: (value) => Validator.hasValue(value) ? null : context.translation.requiredField,
|
|
|
|
|
labelText: context.translation.password,
|
|
|
|
|
obscureText: !_passwordVisible,
|
|
|
|
|
onChange: (value) {
|
|
|
|
|
newPassword = value;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
suffixIcon: Icon(
|
|
|
|
|
// Based on passwordVisible state choose the icon
|
|
|
|
|
_passwordVisible ? Icons.visibility : Icons.visibility_off,
|
|
|
|
|
@ -67,9 +78,10 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
|
|
|
|
|
_passwordVisible = !_passwordVisible;
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
onSaved: (value) {
|
|
|
|
|
newPassword = value;
|
|
|
|
|
},
|
|
|
|
|
// onSaved: (value) {
|
|
|
|
|
//
|
|
|
|
|
// newPassword = value;
|
|
|
|
|
// },
|
|
|
|
|
),
|
|
|
|
|
16.height,
|
|
|
|
|
AppTextFormField(
|
|
|
|
|
@ -77,45 +89,108 @@ class _ResetPasswordViewState extends State<ResetPasswordView> {
|
|
|
|
|
labelText: context.translation.confirmPassword,
|
|
|
|
|
obscureText: !_confirmPasswordVisible,
|
|
|
|
|
showBorder: true,
|
|
|
|
|
validator: (value) => Validator.isValidPassword(value!)
|
|
|
|
|
? null
|
|
|
|
|
: value.isEmpty
|
|
|
|
|
? context.translation.requiredField
|
|
|
|
|
: context.translation.passwordLengthMessage,
|
|
|
|
|
onSaved: (value) {
|
|
|
|
|
onChange: (value) {
|
|
|
|
|
confirmPassword = value;
|
|
|
|
|
setState(() {});
|
|
|
|
|
},
|
|
|
|
|
// validator: (value) => Validator.isValidPassword(value!)
|
|
|
|
|
// ? null
|
|
|
|
|
// : value.isEmpty
|
|
|
|
|
// ? context.translation.requiredField
|
|
|
|
|
// : context.translation.passwordLengthMessage,
|
|
|
|
|
// onSaved: (value) {
|
|
|
|
|
// confirmPassword = value;
|
|
|
|
|
// },
|
|
|
|
|
suffixIcon: Icon(_confirmPasswordVisible ? Icons.visibility : Icons.visibility_off, color: AppColor.icon2Color(context)).paddingOnly(end: 12).onPress(() {
|
|
|
|
|
setState(() {
|
|
|
|
|
_confirmPasswordVisible = !_confirmPasswordVisible;
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
12.height,
|
|
|
|
|
passwordConstraintsUI('At least one upper case', checkRegEx(r'[A-Z]')),
|
|
|
|
|
8.height,
|
|
|
|
|
passwordConstraintsUI('At least one special character', checkRegEx(r'[^\w\s]')),
|
|
|
|
|
8.height,
|
|
|
|
|
passwordConstraintsUI('At least one numeric', checkRegEx(r'[0-9]')),
|
|
|
|
|
8.height,
|
|
|
|
|
passwordConstraintsUI('Minimum 8 characters', newPassword.length >= 8),
|
|
|
|
|
8.height,
|
|
|
|
|
passwordConstraintsUI('Confirm password must match', newPassword.isNotEmpty && newPassword == confirmPassword),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
).center.expanded,
|
|
|
|
|
AppFilledButton(label: context.translation.resetPassword, maxWidth: true, onPressed: () => _resetPassword(context)),
|
|
|
|
|
FooterActionButton.footerContainer(
|
|
|
|
|
safeAreaTop: false,
|
|
|
|
|
context: context,
|
|
|
|
|
child: AppFilledButton(label: context.translation.resetPassword, disableButton: !isPasswordCompliant(newPassword, 8), maxWidth: true, onPressed: () => _resetPassword(context))),
|
|
|
|
|
],
|
|
|
|
|
).paddingOnly(start: 16, end: 16, bottom: 24, top: 24),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool checkRegEx(String pattern) {
|
|
|
|
|
return RegExp(pattern).hasMatch(newPassword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isPasswordCompliant(String? password, int minLength) {
|
|
|
|
|
if (password == null || password.isEmpty) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool hasUppercase = password.contains(RegExp(r'[A-Z]'));
|
|
|
|
|
bool hasDigits = password.contains(RegExp(r'[0-9]'));
|
|
|
|
|
bool hasSpecialCharacter = password.contains(RegExp(r'[^\w\s]'));
|
|
|
|
|
// bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]'));
|
|
|
|
|
bool hasMinLength = password.length >= minLength;
|
|
|
|
|
bool isMatched = password == confirmPassword;
|
|
|
|
|
|
|
|
|
|
return hasDigits && hasUppercase && hasMinLength && isMatched && hasSpecialCharacter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Widget passwordConstraintsUI(String description, bool check) {
|
|
|
|
|
return Row(
|
|
|
|
|
children: [
|
|
|
|
|
4.width,
|
|
|
|
|
SizedBox(
|
|
|
|
|
width: 12,
|
|
|
|
|
height: 12,
|
|
|
|
|
// activeColor: AppColor.primary10,
|
|
|
|
|
// checkColor: AppColor.white10,
|
|
|
|
|
child: Checkbox(
|
|
|
|
|
fillColor: MaterialStateProperty.all(AppColor.primary10),
|
|
|
|
|
side: BorderSide(color: AppColor.icon2Color(context).withValues(alpha: .3), width: 1.0),
|
|
|
|
|
checkColor: AppColor.white10,
|
|
|
|
|
value: check,
|
|
|
|
|
onChanged: null,
|
|
|
|
|
activeColor: AppColor.blueStatus(context),
|
|
|
|
|
// side: BorderSide(color: AppColor.loadingColor(context), width: 1.0),
|
|
|
|
|
visualDensity: const VisualDensity(horizontal: -4.0, vertical: -4.0),
|
|
|
|
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
12.width,
|
|
|
|
|
InfoTextLabelWidget(label: description),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _resetPassword(BuildContext context) async {
|
|
|
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
|
_formKey.currentState?.save();
|
|
|
|
|
if (newPassword != confirmPassword) {
|
|
|
|
|
Fluttertoast.showToast(msg: 'Password not matched try again');
|
|
|
|
|
} else {
|
|
|
|
|
UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);
|
|
|
|
|
UpdatePasswordModel updatePasswordModel =
|
|
|
|
|
UpdatePasswordModel(password: newPassword, confirmPassword: confirmPassword, userId: userProvider.verifyOtpModel.userId, token: userProvider.verifyOtpModel.token);
|
|
|
|
|
GeneralResponseModel generalResponseModel = await userProvider.updateNewPassword(context: context, updatePasswordModel: updatePasswordModel);
|
|
|
|
|
if (generalResponseModel.isSuccess == true) {
|
|
|
|
|
newPassword = '';
|
|
|
|
|
confirmPassword = '';
|
|
|
|
|
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
|
|
|
|
|
}
|
|
|
|
|
// if (!_formKey.currentState!.validate()) return;
|
|
|
|
|
// _formKey.currentState?.save();
|
|
|
|
|
// if (newPassword != confirmPassword) {
|
|
|
|
|
// Fluttertoast.showToast(msg: 'Password not matched try again');
|
|
|
|
|
// } else {
|
|
|
|
|
UserProvider userProvider = Provider.of<UserProvider>(context, listen: false);
|
|
|
|
|
UpdatePasswordModel updatePasswordModel =
|
|
|
|
|
UpdatePasswordModel(password: newPassword, confirmPassword: confirmPassword, userId: userProvider.verifyOtpModel.userId, token: userProvider.verifyOtpModel.token);
|
|
|
|
|
GeneralResponseModel generalResponseModel = await userProvider.updateNewPassword(context: context, updatePasswordModel: updatePasswordModel);
|
|
|
|
|
if (generalResponseModel.isSuccess == true) {
|
|
|
|
|
newPassword = '';
|
|
|
|
|
confirmPassword = '';
|
|
|
|
|
Navigator.of(context).pushNamedAndRemoveUntil(LoginPage.routeName, (routes) => true);
|
|
|
|
|
}
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|