From ea2a9c541c916068ad7ea16f87e36649adcb9ba7 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Mon, 19 Sep 2022 14:39:42 +0300 Subject: [PATCH] change password screen added. --- lib/api/login_api_client.dart | 10 ++ lib/config/routes.dart | 9 +- lib/provider/dashboard_provider_model.dart | 2 +- lib/ui/login/change_password_screen.dart | 174 +++++++++++++++++++++ lib/ui/login/new_password_screen.dart | 92 +++++------ 5 files changed, 235 insertions(+), 52 deletions(-) create mode 100644 lib/ui/login/change_password_screen.dart diff --git a/lib/api/login_api_client.dart b/lib/api/login_api_client.dart index cd6a948..79b7783 100644 --- a/lib/api/login_api_client.dart +++ b/lib/api/login_api_client.dart @@ -135,4 +135,14 @@ class LoginApiClient { return responseData; }, url, postParams); } + + Future changePasswordFromActiveSession(String pOldPassword, String pNewPassword, String pConfirmNewPassword) async { + String url = "${ApiConsts.erpRest}ChangePassword_FromActiveSession"; + Map postParams = {"P_OLD_PASSWORD": pOldPassword, "P_Confirm_NEW_PASSWORD": pConfirmNewPassword, "P_NEW_PASSWORD": pNewPassword}; + postParams.addAll(AppState().postParamsJson); + return await ApiClient().postJsonForObject((json) { + GenericResponseModel responseData = GenericResponseModel.fromJson(json); + return responseData; + }, url, postParams); + } } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 5f78298..ffafbc7 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -7,6 +7,7 @@ import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart'; import 'package:mohem_flutter_app/ui/landing/today_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/leave_balance/add_leave_balance_screen.dart'; import 'package:mohem_flutter_app/ui/leave_balance/leave_balance_screen.dart'; +import 'package:mohem_flutter_app/ui/login/change_password_screen.dart'; import 'package:mohem_flutter_app/ui/login/forgot_password_screen.dart'; import 'package:mohem_flutter_app/ui/login/login_screen.dart'; import 'package:mohem_flutter_app/ui/login/new_password_screen.dart'; @@ -16,6 +17,7 @@ import 'package:mohem_flutter_app/ui/misc/request_submit_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_input_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/dynamic_screens/dynamic_listview_screen.dart'; import 'package:mohem_flutter_app/ui/my_attendance/services_menu_list_screen.dart'; + // import 'package:mohem_flutter_app/ui/my_attendance/my_attendance_screen.dart'; import 'package:mohem_flutter_app/ui/my_team/create_request.dart'; import 'package:mohem_flutter_app/ui/my_team/employee_details.dart'; @@ -57,8 +59,6 @@ import 'package:mohem_flutter_app/ui/work_list/item_history_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/itg_detail_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/work_list_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/worklist_detail_screen.dart'; -import 'package:mohem_flutter_app/ui/my_team/my_team.dart'; -import 'package:mohem_flutter_app/ui/my_team/create_request.dart'; import 'package:mohem_flutter_app/ui/work_list/worklist_settings.dart'; class AppRoutes { @@ -148,6 +148,7 @@ class AppRoutes { //performance evaluation static const String performanceEvaluation = "/performanceEvaluation"; + //My Team static const String myTeam = "/myTeam"; static const String employeeDetails = "/employeeDetails"; @@ -157,6 +158,8 @@ class AppRoutes { static const String createRequest = "/createRequest"; static const String subordinateLeave = "/subordinateLeave"; + static const String changePassword = "/changePassword"; + static final Map routes = { login: (context) => LoginScreen(), verifyLogin: (context) => VerifyLoginScreen(), @@ -247,5 +250,7 @@ class AppRoutes { teamMembers: (context) => TeamMembers(), createRequest: (context) => CreateRequest(), subordinateLeave: (context) => SubordinateLeave(), + + changePassword: (context) => ChangePasswordScreen(), }; } diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index 17f90d2..1e39588 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -155,7 +155,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { DrawerMenuItem("assets/images/drawer/performance_evaluation.svg", LocaleKeys.performanceEvaluation.tr(), AppRoutes.performanceEvaluation), DrawerMenuItem("assets/images/drawer/mowadhafi.svg", LocaleKeys.mowadhafhi.tr(), AppRoutes.mowadhafhi), DrawerMenuItem("assets/images/drawer/pending_trasactions.svg", LocaleKeys.pendingTransactions.tr(), AppRoutes.pendingTransactions), - DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), ""), + DrawerMenuItem("assets/images/drawer/change_password.svg", LocaleKeys.changePassword.tr(), AppRoutes.changePassword), ]; void fetchListMenu() async { diff --git a/lib/ui/login/change_password_screen.dart b/lib/ui/login/change_password_screen.dart new file mode 100644 index 0000000..0409500 --- /dev/null +++ b/lib/ui/login/change_password_screen.dart @@ -0,0 +1,174 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:mohem_flutter_app/api/login_api_client.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/classes/utils.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/button/default_button.dart'; +import 'package:mohem_flutter_app/widgets/input_widget.dart'; + +class ChangePasswordScreen extends StatefulWidget { + ChangePasswordScreen({Key? key}) : super(key: key); + + @override + _ChangePasswordScreenState createState() { + return _ChangePasswordScreenState(); + } +} + +class _ChangePasswordScreenState extends State { + TextEditingController oldPassword = TextEditingController(); + TextEditingController password = TextEditingController(); + TextEditingController confirmPassword = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + void setNewPassword() async { + Utils.showLoading(context); + try { + var genericResponseModel = await LoginApiClient().changePasswordFromActiveSession(oldPassword.text, password.text, confirmPassword.text); + Utils.hideLoading(context); + Utils.showToast(LocaleKeys.passwordChangedSuccessfully.tr()); + Navigator.pop(context); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, context, (msg) { + Utils.confirmDialog(context, msg); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.transparent, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: MyColors.darkIconColor), + onPressed: () => Navigator.pop(context), + ), + ), + body: Column( + children: [ + ListView( + padding: const EdgeInsets.all(21), + children: [ + "Change Password".toText24(isBold: true), + "Type Your Current password below".toText16(), + 16.height, + InputWidget( + "Current password", + "**********", + oldPassword, + onChange: (value) { + setState(() {}); + }, + ), + 16.height, + LocaleKeys.typeYourNewPasswordBelow.tr().toText16(), + 16.height, + InputWidget( + LocaleKeys.password.tr(), + "**********", + password, + onChange: (value) { + setState(() {}); + }, + ), + 12.height, + InputWidget( + LocaleKeys.confirmPassword.tr(), + "**********", + confirmPassword, + isObscureText: true, + onChange: (value) { + setState(() {}); + }, + ), + 16.height, + passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), + 8.height, + passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), + 8.height, + passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), + 8.height, + passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), + 8.height, + passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), + ], + ).expanded, + DefaultButton(LocaleKeys.changePassword.tr(), (!isPasswordCompliant(password.text, 8)) ? null : setNewPassword).insideContainer + ], + ), + ); + } + + bool checkRegEx(String pattern) { + return RegExp(pattern).hasMatch(password.text); + } + + String recentPassword = ""; + + 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 hasLowercase = password.contains(RegExp(r'[a-z]')); + bool hasSpecialCharacters = password.contains(RegExp(r'[!@#$%^&*(),.?":{}|<>]')); + bool hasMinLength = password.length >= minLength; + bool isMatched = password == confirmPassword.text; + + return hasDigits && hasUppercase && hasLowercase && hasSpecialCharacters && hasMinLength && isMatched && checkRepeatedChars(password); + } + + bool checkRepeatedChars(String password) { + bool isNonRepeatedLetters = true; + if (password.length > 2) { + for (int i = 0; i < password.length; i++) { + String char = password[i]; + try { + if (char == password[i + 1]) { + isNonRepeatedLetters = false; + break; + } + } catch (ex) {} + } + } + return isNonRepeatedLetters; + } + + Widget passwordConstraintsUI(String description, bool check) { + return Row( + children: [ + 4.width, + SizedBox( + width: 12, + height: 12, + child: Checkbox(fillColor: MaterialStateProperty.all(MyColors.gradiantEndColor), shape: const CircleBorder(), value: check, onChanged: null), + ), + 8.width, + description.toText14() + ], + ); + } +} diff --git a/lib/ui/login/new_password_screen.dart b/lib/ui/login/new_password_screen.dart index 7f011e7..e2ef55d 100644 --- a/lib/ui/login/new_password_screen.dart +++ b/lib/ui/login/new_password_screen.dart @@ -46,7 +46,7 @@ class _NewPasswordScreenState extends State { } catch (ex) { print(ex); Utils.hideLoading(context); - Utils.handleException(ex, context, (msg) { + Utils.handleException(ex, context, (msg) { Utils.confirmDialog(context, msg); }); } @@ -66,54 +66,48 @@ class _NewPasswordScreenState extends State { ), body: Column( children: [ - //const SizedBox(height: 23), - Expanded( - child: ListView( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.center, - children: [ - LocaleKeys.setTheNewPassword.tr().toText24(isBold: true), - LocaleKeys.typeYourNewPasswordBelow.tr().toText16(), - 16.height, - InputWidget( - LocaleKeys.password.tr(), - "**********", - password, - onChange: (value) { - setState(() {}); - }, - ), - 12.height, - InputWidget( - LocaleKeys.confirmPassword.tr(), - "**********", - confirmPassword, - isObscureText: true, - onChange: (value) { - setState(() {}); - }, - ), - 12.height, - passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), - 8.height, - passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), - 8.height, - passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), - 8.height, - passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), - 8.height, - passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), - 8.height, - passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), - 8.height, - passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), - 8.height, - passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), - 12.height, - ], - ).paddingAll(21), - ), + ListView( + padding: const EdgeInsets.all(21), + children: [ + LocaleKeys.setTheNewPassword.tr().toText24(isBold: true), + LocaleKeys.typeYourNewPasswordBelow.tr().toText16(), + 16.height, + InputWidget( + LocaleKeys.password.tr(), + "**********", + password, + onChange: (value) { + setState(() {}); + }, + ), + 12.height, + InputWidget( + LocaleKeys.confirmPassword.tr(), + "**********", + confirmPassword, + isObscureText: true, + onChange: (value) { + setState(() {}); + }, + ), + 16.height, + passwordConstraintsUI(LocaleKeys.doNotUseRecentPassword.tr(), true), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneLowercase.tr(), checkRegEx(r'[a-z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneUppercase.tr(), checkRegEx(r'[A-Z]')), + 8.height, + passwordConstraintsUI(LocaleKeys.atLeastOneNumeric.tr(), checkRegEx(r'[0-9]')), + 8.height, + passwordConstraintsUI(LocaleKeys.minimum8Characters.tr(), password.text.length >= 8), + 8.height, + passwordConstraintsUI(LocaleKeys.doNotAddRepeatingLetters.tr(), checkRepeatedChars(password.text)), + 8.height, + passwordConstraintsUI(LocaleKeys.itShouldContainSpecialCharacter.tr(), checkRegEx(r'[!@#$%^&*(),.?":{}|<>]')), + 8.height, + passwordConstraintsUI(LocaleKeys.confirmPasswordMustMatch.tr(), password.text.isNotEmpty && password.text == confirmPassword.text), + ], + ).expanded, DefaultButton( LocaleKeys.update.tr(), (!isPasswordCompliant(password.text, 8))