From e40bd964186cf3acd5e44044662e4b77620ac44f Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Mon, 23 Nov 2020 18:03:59 +0200 Subject: [PATCH] ES-185:forget password function works --- lib/app-icons/config.json | 32 +- lib/app-icons/driver_app_icons.dart | 60 ++- lib/app-icons/fonts/DriverApp.ttf | Bin 11572 -> 11992 bytes lib/config/config.dart | 7 + lib/config/localized_values.dart | 17 +- lib/core/service/authentication_service.dart | 66 +++ .../viewModels/authentication_view_model.dart | 48 ++ .../authentication/forget_password_page.dart | 195 ++++++++ lib/pages/authentication/login_page.dart | 51 ++- .../authentication/reset_password_page.dart | 200 +++++++++ .../authentication/verification_page.dart | 425 ++++++++++++++++++ lib/uitl/cupertino_picker.dart | 3 +- lib/uitl/translations_delegate_base.dart | 12 + lib/widgets/buttons/secondary_button.dart | 3 +- 14 files changed, 1078 insertions(+), 41 deletions(-) create mode 100644 lib/pages/authentication/forget_password_page.dart create mode 100644 lib/pages/authentication/reset_password_page.dart create mode 100644 lib/pages/authentication/verification_page.dart diff --git a/lib/app-icons/config.json b/lib/app-icons/config.json index 964f71c..6c4f6bc 100644 --- a/lib/app-icons/config.json +++ b/lib/app-icons/config.json @@ -261,9 +261,9 @@ { "uid": "d755ac5bb912e95877e670a67bf4528d", "css": "phone_call", - "code": 59398, + "code": 59401, "src": "custom_icons", - "selected": false, + "selected": true, "svg": { "path": "M907.5 618.9L829.1 540.7A45.6 45.6 0 0 0 764.4 540.7L764.4 540.7 719.7 585.5A9.9 9.9 0 0 1 707 586.6 517.6 517.6 0 0 1 586 467.8 9.9 9.9 0 0 1 586.9 455.1L633 409A45.7 45.7 0 0 0 633 344.4L554.6 265.9A46.7 46.7 0 0 0 489.9 265.9L465.1 290.8A139.5 139.5 0 0 0 430.3 433.2 417.6 417.6 0 0 0 481.3 536.8 544.9 544.9 0 0 0 638.1 690.9 400.4 400.4 0 0 0 754.2 742.5 134.2 134.2 0 0 0 786.7 746.4 141.4 141.4 0 0 0 886.1 704.6L907.4 683.2A45.6 45.6 0 0 0 907.5 618.9Z", "width": 1344 @@ -271,6 +271,34 @@ "search": [ "phone_call" ] + }, + { + "uid": "3ee830f1177337ad723625ace69b886b", + "css": "qustion_mark", + "code": 59411, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M215.2 420.5C344.6 414.9 436 362.9 436 295.4 436 236.3 381.2 185.6 295.4 185.6 226.4 185.6 163.2 222.2 118.1 272.9L0 151.9C80.1 61.9 191.2 0 330.5 0 517.5 0 646.9 116.7 646.9 275.7 646.9 402.3 542.9 516.2 398 549.9V651.2H215.2ZM175.8 869.2A129.5 129.5 0 0 1 306.6 744 128 128 0 0 1 306.6 1000 130.6 130.6 0 0 1 175.8 869.2Z", + "width": 647 + }, + "search": [ + "group-8" + ] + }, + { + "uid": "e4101bb9283eee95eea80812a39424cc", + "css": "exclamation_mark", + "code": 59412, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M0 867A131.7 131.7 0 0 1 133 739.6 130.2 130.2 0 0 1 133 1000 132.8 132.8 0 0 1 0 867ZM15.7 0H251.8L204.6 636.6H63Z", + "width": 260 + }, + "search": [ + "group-14" + ] } ] } \ No newline at end of file diff --git a/lib/app-icons/driver_app_icons.dart b/lib/app-icons/driver_app_icons.dart index d21725b..4ff76ff 100644 --- a/lib/app-icons/driver_app_icons.dart +++ b/lib/app-icons/driver_app_icons.dart @@ -21,22 +21,46 @@ class DriverApp { static const _kFontFam = 'DriverApp'; static const _kFontPkg = null; - static const IconData location_1 = IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData logo = IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData logout_icon = IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData closed_box = IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData location = IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData open_box = IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData settings_icon = IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData qr = IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData language_icon = IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData not_available = IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData rejected_icon = IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData not_reachable_icon = IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData group_74 = IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData message = IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData whatsapp = IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData call = IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bell_icon = IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData deliverd_icon = IconData(0xe812, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData location_1 = + IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData logo = + IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData logout_icon = + IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData closed_box = + IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData location = + IconData(0xe804, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData open_box = + IconData(0xe805, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData settings_icon = + IconData(0xe806, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData qr = + IconData(0xe807, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData language_icon = + IconData(0xe808, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData phone_call = + IconData(0xe809, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData not_available = + IconData(0xe80a, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData rejected_icon = + IconData(0xe80b, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData not_reachable_icon = + IconData(0xe80c, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData group_74 = + IconData(0xe80d, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData message = + IconData(0xe80e, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData whatsapp = + IconData(0xe80f, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData call = + IconData(0xe810, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData bell_icon = + IconData(0xe811, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData deliverd_icon = + IconData(0xe812, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData qustion_mark = + IconData(0xe813, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData exclamation_mark = + IconData(0xe814, fontFamily: _kFontFam, fontPackage: _kFontPkg); } diff --git a/lib/app-icons/fonts/DriverApp.ttf b/lib/app-icons/fonts/DriverApp.ttf index f1209f20d09f05ba32d8a42b58c26d627a54ac31..9252c60c27114866121bb9117946e33dc88d98e7 100644 GIT binary patch delta 983 zcmYk4T}TvB6vxlGv+daK&VG+tZK8A69g|ga*EY*_*Qd3jR3wZfwZXPl+7C@Di^zu} zdx$9JDe5^2q7MuTk*McB2zp2=!iS(K3PS27sO`+IMKk>Fob$i`d(W9WbANDg=n|iq z1HcOaFff|a#y>rQodB$zIDaU6;^6z6->v~zz5vwU&7`#h>z6?%?-CKqkYGDxJxlQd z5zOSKrgz^d(j0!Ee0R1ms%Z=PXSDt?<>8z*J&s?kbu?d1d2L?HrEfi7>s0|7sfgeh zFHBBdReVGA?k%7El09zC6ZG2)8<0J~t20&kawkNXYj6T9^h=mTzy1>AY*m+TV@f}pC4;5pTScQlgb7mcRB0u^F;dMv!t}J2bPMb# zc`T-G_=`mv!5k^K=%?8_Spo+*!3A#cfERq=rzxv`kNwmiv(+vKIRQ%}1+qRb6lPY_ z9)wxJSOM%5uR!~Ou>wdGuTavRloM1D3|ASd4Tif6bpeK_4D|zsw+wX#hOf+4YLZ^1 zjM*+-DXhi}er63U&wkt9+ppUVsaAUDJm<2xzPb0izk8>>550?X3zl6~Gv*0_aD@#( z1N|dvND*5_C#oSe)Rx3pTMLF17do-3vV2D)u_Pu?xX>%9QkYc;sVEbgC8@_*?_3k` zIlOhr;aI}$2}J#}gdck(DJ&psO$j2oREhF6ft{iDjYFN>ZIS(zf>aN4VnC5*=(88c z*sRbG0oVZGOR!CC&BzteDyp%~v1p{K24%k!MVX5U7O6psm1cb1m2T%Z*nl-D+cypYBae^n228_?9}wwDEY- z{O^imSV0Xq%#)Y@E8>d^9P8t$IOp;1&Y=5C%S8|GsN<#*>=b5yoq;)ZL$iRgJ`fIC z(T_4#>LtL3zRg841r5B3qp Ak^lez delta 561 zcmXw#%}X0m6vfY*nM`axr*EOs)(|nMl_*{KwGiBNQLruqDNR7ipvHhn6N!|#P$_N& zE#pe)U(ixY)2>tyQ4k@JO`%XI3Ryg)t5Ua)XEONU$9?zSbMAdJzvjMYcY8K30kI9> z)qK$|SKj^n1ZZiJTPm#O)~&B+fN=<<3i(BQp=*5PF}3tyG|xh4$$ZZ{`$*-BtJSHd z%bsX5e^DsS+cVFm8uafm?=9NZvbZ+8+3#eYd}|jMKi410KHzCTphwE3%Ie8jrVgZs zDY*S`*fS|1cqOwt&8s)@i5rA<#R`6JRS)i?`_IhHFFD{Ax@ zoNOYtZnF{2$CXuZQONkAORd3v!+S diff --git a/lib/config/config.dart b/lib/config/config.dart index dbe681a..d9f9a35 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -5,6 +5,13 @@ import 'package:flutter/material.dart'; const BASE_URL = 'https://uat.hmgwebservices.com/Services'; const GET_PROJECT = '/Lists.svc/REST/GetProject'; const LOGIN = "/Authentication.svc/REST/CheckDriverAuthentication"; +const GET_OPT = + "/Patients.svc/REST/PatientER_Delivery_SendSMSForForgetPassword"; +const CHECK_ACTIVATION_CODE = + "/Patients.svc/REST/PatientER_Delivery_CheckActivationCodeForForgetPassword"; +const CHANGE_FORGOT_PASSWORD = + "/Patients.svc/REST/PatientER_Delivery_ChangeForgetedPasswordForDriver"; + const GET_ALL_ORDERS = '/Patients.svc/REST/PatientER_Delivery_GetAllOrder'; const SCAN_QR = '/Patients.svc/REST/PatientER_Delivery_OrderInsert'; const UPDATE_ORDER_STATUS = diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index ac744a0..ad8ed64 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -4,7 +4,7 @@ const Map> localizedValues = { 'language': {'en': 'App Language', 'ar': 'لغة التطبيق'}, 'lanEnglish': {'en': 'English', 'ar': 'English'}, 'lanArabic': {'en': 'العربية', 'ar': 'العربية'}, - 'cancel': {'en': 'CANCEL', 'ar': 'الغاء'}, + 'cancel': {'en': 'Cancel', 'ar': 'الغاء'}, 'done': {'en': 'DONE', 'ar': 'تأكيد'}, 'replay2': {'en': 'Replay', 'ar': 'رد الطبيب'}, 'home': {'en': 'Home', 'ar': 'الرئيسية'}, @@ -14,7 +14,7 @@ const Map> localizedValues = { 'booking': {'en': 'Booking', 'ar': 'حجز'}, 'enterId': {'en': 'User Name', 'ar': 'اسم المستخدم'}, 'pleaseEnterYourID': { - 'en': 'Please enter your ', + 'en': 'Please enter your user name', 'ar': 'الرجاء ادخال اسم المستخدم' }, 'enterPassword': {'en': 'Password', 'ar': 'كلمه السر'}, @@ -26,6 +26,10 @@ const Map> localizedValues = { 'en': 'Please insert username and password to login', 'ar': 'الرجاء إدخال اسم المستخدم وكلمة المرور لتسجيل الدخول' }, + 'enterForgetIdMsg': { + 'en': 'We will send a One Time Password (OTP) to your Mobile Number to reset your password.', + 'ar': 'سنرسل كلمة مرور لمرة واحدة (OTP) إلى حسابك رقم الهاتف المحمول لإعادة تعيين كلمة المرور الخاصة بك.' + }, 'forgotPassword': {'en': 'Forgot Password?', 'ar': 'هل نسيت كلمة المرور ؟'}, 'login': {'en': 'Login', 'ar': 'تسجيل الدخول'}, 'haveGreatDay': {'en': 'have a great day,', 'ar': 'أتمنى لك يوما جميلا '}, @@ -69,6 +73,11 @@ const Map> localizedValues = { 'youHaveSelected': {'en': 'You have selected:', 'ar': 'لقد قمت باختيار:'}, 'confirm': {'en': 'Confirm', 'ar': 'تأكيد'}, 'areYouSure': {'en': 'Are you sure?', 'ar': 'هل أنت واثق؟'}, - 'languageText':{'en':'Language','ar':'اللغة'}, - 'notification':{'en':'Notification','ar':'تنبيهات'}, + 'languageText': {'en': 'Language', 'ar': 'اللغة'}, + 'notification': {'en': 'Notification', 'ar': 'تنبيهات'}, + 'getOPT': {'en': 'Get OPT', 'ar': 'OPT الحصول على'}, + 'enterVerificationMsg': { + 'en': 'Please Enter your OPT code sent to your phone', + 'ar': 'الرجاء إدخال رمز OPT الخاص بك المرسل إلى هاتفك' + }, }; diff --git a/lib/core/service/authentication_service.dart b/lib/core/service/authentication_service.dart index 266f2ae..851e03d 100644 --- a/lib/core/service/authentication_service.dart +++ b/lib/core/service/authentication_service.dart @@ -9,6 +9,9 @@ class AuthenticationService extends BaseService { bool isLoading = true; AuthenticatedUser authenticatedUser; String token; + String loginTokenId; + String tokenID; + int userID; AuthenticationService() { // getUserAuthentication(); @@ -32,4 +35,67 @@ class AuthenticationService extends BaseService { throw error; } } + + getOpt(int driverId) async { + hasError = false; + userID = driverId; + try { + await baseAppClient.post(GET_OPT, + onSuccess: (dynamic response, int statusCode) { + loginTokenId = response['LogInTokenID']; + print(response['ActivationCode']); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: {"DriverID": driverId}); + } catch (error) { + hasError = true; + super.error = error; + throw error; + } + } + + changePassword(String password, String confirmPassword) async { + hasError = false; + try { + await baseAppClient.post(CHANGE_FORGOT_PASSWORD, + onSuccess: (dynamic response, int statusCode) { + loginTokenId = response['LogInTokenID']; + print(response['ActivationCode']); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "TokenID": tokenID, + "NewPassword": password, + "ConfirmPassword": confirmPassword, + "UserID": userID + }); + } catch (error) { + hasError = true; + super.error = error; + throw error; + } + } + + checkActivationCode(int activationCode) async { + hasError = false; + try { + await baseAppClient.post(CHECK_ACTIVATION_CODE, + onSuccess: (dynamic response, int statusCode) { + tokenID = response['TokenID']; + print(response['ActivationCode']); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: { + "LogInTokenID": loginTokenId, + "activationCode": activationCode + }); + } catch (error) { + hasError = true; + super.error = error; + throw error; + } + } } diff --git a/lib/core/viewModels/authentication_view_model.dart b/lib/core/viewModels/authentication_view_model.dart index 4d94ec4..d0ba4f0 100644 --- a/lib/core/viewModels/authentication_view_model.dart +++ b/lib/core/viewModels/authentication_view_model.dart @@ -80,6 +80,54 @@ class AuthenticationViewModel with ChangeNotifier { } } + getOpt(int driverID) async { + isLoading = true; + notifyListeners(); + await _authenticationService.getOpt(driverID); + if (_authenticationService.hasError) { + error = _authenticationService.error; + isLoading = false; + isError = true; + notifyListeners(); + } else { + isLoading = false; + isError = false; + notifyListeners(); + } + } + + changePassword(String password, String confirmPassword) async { + isLoading = true; + notifyListeners(); + await _authenticationService.changePassword(password, confirmPassword); + if (_authenticationService.hasError) { + error = _authenticationService.error; + isLoading = false; + isError = true; + notifyListeners(); + } else { + isLoading = false; + isError = false; + notifyListeners(); + } + } + + checkActivationCode(int driverID) async { + isLoading = true; + notifyListeners(); + await _authenticationService.checkActivationCode(driverID); + if (_authenticationService.hasError) { + error = _authenticationService.error; + isLoading = false; + isError = true; + notifyListeners(); + } else { + isLoading = false; + isError = false; + notifyListeners(); + } + } + logout() async { isLoading = false; isError = false; diff --git a/lib/pages/authentication/forget_password_page.dart b/lib/pages/authentication/forget_password_page.dart new file mode 100644 index 0000000..5e515f1 --- /dev/null +++ b/lib/pages/authentication/forget_password_page.dart @@ -0,0 +1,195 @@ +import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/core/viewModels/project_view_model.dart'; +import 'package:driverapp/pages/authentication/verification_page.dart'; +import 'package:driverapp/uitl/translations_delegate_base.dart'; +import 'package:driverapp/uitl/utils.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/input/text_field.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +import '../../root_page.dart'; + +// ignore: must_be_immutable +class ForgetPasswordPage extends StatelessWidget { + final forgetPasswordFormKey = GlobalKey(); + int driverID; + ProjectViewModel projectViewModel; + AuthenticationViewModel authenticationViewModel; + + getOpt(BuildContext context) async { + if (forgetPasswordFormKey.currentState.validate()) { + forgetPasswordFormKey.currentState.save(); + await authenticationViewModel.getOpt(driverID); + if (authenticationViewModel.isError) { + Utils.showErrorToast(authenticationViewModel.error); + } else { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => VerificationPage()), + ); + } + } + } + + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + authenticationViewModel = Provider.of(context); + + return AnimatedSwitcher( + duration: Duration(microseconds: 350), + child: AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + widthFactor: 0.80, + child: Column( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.25, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Icon( + DriverApp.qustion_mark, + size: 150, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + top: 20, + ), + ), + ], + ), + SizedBox( + height: 20, + ), + Column( + children: [ + Center( + child: Text( + "Forgot Password?", + style: TextStyle( + fontSize: 25, + letterSpacing: 1, + fontWeight: FontWeight.w600), + ), + ), + ], + ), + SizedBox( + height: 30, + ), + SizedBox( + height: 10, + ), + Form( + key: forgetPasswordFormKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Expanded( + child: Text( + TranslationBase.of(context) + .enterForgetIdMsg, + style: TextStyle( + fontSize: 13, color: Colors.grey), + ), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + SizedBox( + height: 10, + ), + Container( + child: TextFields( + hintText: TranslationBase.of(context).enterId, + keyboardType: TextInputType.number, + validator: (value) { + if (value.isEmpty) { + return TranslationBase.of(context) + .pleaseEnterYourID; + } + return null; + }, + onSaved: (value) { + driverID = int.parse(value.trim()); + }, + ), + ), + SizedBox( + height: 20, + ), + ], + ), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + SizedBox( + height: 10, + ), + Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.22, + child: Column( + children: [ + SecondaryButton( + label: TranslationBase.of(context).getOPT, + onTap: () async { + await getOpt(context); + }, + disabled: authenticationViewModel.isLoading, + loading: authenticationViewModel.isLoading, + ), + SizedBox( + height: 30, + ), + SecondaryButton( + label: TranslationBase.of(context).cancel, + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => RootPage()), + ); + }, + color: Color(0xffE9F1F1), + borderColor: Colors.black54, + textColor: Theme.of(context).primaryColor, + ), + ], + )) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/authentication/login_page.dart b/lib/pages/authentication/login_page.dart index c9ed541..cba5ba9 100644 --- a/lib/pages/authentication/login_page.dart +++ b/lib/pages/authentication/login_page.dart @@ -13,6 +13,8 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; +import 'forget_password_page.dart'; + class LoginPage extends StatelessWidget { LoginRequest loginRequest = LoginRequest(); final loginFormKey = GlobalKey(); @@ -60,13 +62,20 @@ class LoginPage extends StatelessWidget { color: Theme.of(context).primaryColor, ), margin: EdgeInsets.only( + top: 20, right: projectViewModel.isArabic ? 0 - : MediaQuery.of(context).size.width * + : MediaQuery + .of(context) + .size + .width * 0.15, left: !projectViewModel.isArabic ? 0 - : MediaQuery.of(context).size.width * + : MediaQuery + .of(context) + .size + .width * 0.15), ), ], @@ -214,18 +223,32 @@ class LoginPage extends StatelessWidget { SizedBox( height: 25, ), -//ToDo when forget page functions ready -// Row( -// mainAxisAlignment: MainAxisAlignment.end, -// children: [ -// Text( -// TranslationBase.of(context).forgotPassword, -// style: TextStyle( -// fontSize: 14, -// color: Theme.of(context).primaryColor), -// ), -// ], -// ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + ForgetPasswordPage() + ), + ); + }, + child: Text( + TranslationBase + .of(context) + .forgotPassword, + style: TextStyle( + fontSize: 14, + color: Theme + .of(context) + .primaryColor), + ), + ), + ], + ), ], ), ), diff --git a/lib/pages/authentication/reset_password_page.dart b/lib/pages/authentication/reset_password_page.dart new file mode 100644 index 0000000..9b8b303 --- /dev/null +++ b/lib/pages/authentication/reset_password_page.dart @@ -0,0 +1,200 @@ +import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/core/viewModels/project_view_model.dart'; +import 'package:driverapp/root_page.dart'; +import 'package:driverapp/uitl/app_toast.dart'; +import 'package:driverapp/uitl/translations_delegate_base.dart'; +import 'package:driverapp/uitl/utils.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/input/text_field.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +// ignore: must_be_immutable +class RestPasswordPage extends StatelessWidget { + final forgetPasswordFormKey = GlobalKey(); + + // String password; + // String confirmedPassword; + ProjectViewModel projectViewModel; + AuthenticationViewModel authenticationViewModel; + TextEditingController password = TextEditingController(text: ""); + TextEditingController confirmedPassword = TextEditingController(text: ""); + + changePassword(BuildContext context) async { + if (forgetPasswordFormKey.currentState.validate()) { + forgetPasswordFormKey.currentState.save(); + await authenticationViewModel.changePassword( + password.text, confirmedPassword.text); + if (authenticationViewModel.isError) { + Utils.showErrorToast(authenticationViewModel.error); + } else { + AppToast.showSuccessToast( + message: "Your Password changed successfully"); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (context) => RootPage()), + ); + } + } + } + + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + authenticationViewModel = Provider.of(context); + + return AnimatedSwitcher( + duration: Duration(microseconds: 350), + child: AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + widthFactor: 0.80, + child: Column( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.25, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Icon( + DriverApp.qustion_mark, + size: 150, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + top: 20, + ), + ), + ], + ), + SizedBox( + height: 20, + ), + Column( + children: [ + Center( + child: Text( + "Rest Password", + style: TextStyle( + fontSize: 25, + letterSpacing: 1, + fontWeight: FontWeight.w600), + ), + ), + ], + ), + SizedBox( + height: 30, + ), + SizedBox( + height: 10, + ), + Form( + key: forgetPasswordFormKey, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + child: TextFields( + hintText: "Password", + controller: password, + keyboardType: TextInputType.number, + validator: (value) { + if (value.isEmpty) { + return "Please enter your password"; + } + return null; + }, + onSaved: (value) { + // password = value; + }, + ), + ), + SizedBox( + height: 20, + ), + Container( + child: TextFields( + controller: confirmedPassword, + hintText: "Confirm Password", + keyboardType: TextInputType.text, + validator: (value) { + if (value.isEmpty) { + return "Please enter your confirm password"; + } + if (confirmedPassword.text != password.text) { + return "Password your doesn't match your confirm password"; + } + return null; + }, + onSaved: (value) { + // confirmedPassword = value; + }, + ), + ), + SizedBox( + height: 20, + ), + ], + ), + ), + ], + ), + ), + SizedBox( + height: 20, + ), + SizedBox( + height: 10, + ), + Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.22, + child: Column( + children: [ + SecondaryButton( + label: "Change Password", + onTap: () async { + await changePassword(context); + }, + disabled: authenticationViewModel.isLoading, + loading: authenticationViewModel.isLoading, + ), + SizedBox( + height: 30, + ), + SecondaryButton( + label: TranslationBase.of(context).cancel, + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => RootPage()), + ); + }, + color: Color(0xffE9F1F1), + borderColor: Colors.black54, + textColor: Theme.of(context).primaryColor, + ), + ], + )) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/pages/authentication/verification_page.dart b/lib/pages/authentication/verification_page.dart new file mode 100644 index 0000000..8d0d36b --- /dev/null +++ b/lib/pages/authentication/verification_page.dart @@ -0,0 +1,425 @@ +import 'package:driverapp/app-icons/driver_app_icons.dart'; +import 'package:driverapp/config/size_config.dart'; +import 'package:driverapp/core/model/authentication/login_request.dart'; +import 'package:driverapp/core/viewModels/authentication_view_model.dart'; +import 'package:driverapp/core/viewModels/project_view_model.dart'; +import 'package:driverapp/pages/authentication/reset_password_page.dart'; +import 'package:driverapp/uitl/translations_delegate_base.dart'; +import 'package:driverapp/uitl/utils.dart'; +import 'package:driverapp/widgets/buttons/secondary_button.dart'; +import 'package:driverapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +import 'forget_password_page.dart'; + +// ignore: must_be_immutable +class VerificationPage extends StatelessWidget { + LoginRequest loginRequest = LoginRequest(); + final loginFormKey = GlobalKey(); + ProjectViewModel projectViewModel; + AuthenticationViewModel authenticationViewModel; + final verifyAccountForm = GlobalKey(); + + Map verifyAccountFormValue = { + 'digit1': null, + 'digit2': null, + 'digit3': null, + 'digit4': null, + }; + + FocusNode focusD1; + FocusNode focusD2; + FocusNode focusD3; + FocusNode focusD4; + bool _isInit = true; + var model; + TextEditingController digit1 = TextEditingController(text: ""); + TextEditingController digit2 = TextEditingController(text: ""); + TextEditingController digit3 = TextEditingController(text: ""); + TextEditingController digit4 = TextEditingController(text: ""); + + login() async { + if (loginFormKey.currentState.validate()) { + loginFormKey.currentState.save(); + await authenticationViewModel.login(loginRequest); + if (authenticationViewModel.isError) { + Utils.showErrorToast(authenticationViewModel.error); + } + } + } + + SizedBox buildSizedBox([double height = 20]) { + return SizedBox( + height: height, + ); + } + + @override + Widget build(BuildContext context) { + projectViewModel = Provider.of(context); + authenticationViewModel = Provider.of(context); + focusD1 = FocusNode(); + focusD2 = FocusNode(); + focusD3 = FocusNode(); + focusD4 = FocusNode(); + + String validateCodeDigit(value) { + if (value.isEmpty) { + return 'Please enter your Password'; + } + + return null; + } + + return AnimatedSwitcher( + duration: Duration(microseconds: 350), + child: AppScaffold( + isShowAppBar: false, + body: SingleChildScrollView( + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + widthFactor: 0.80, + child: Column( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.25, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Icon( + DriverApp.exclamation_mark, + size: 150, + color: Theme.of(context).primaryColor, + ), + margin: EdgeInsets.only( + top: 20, + ), + ), + ], + ), + SizedBox( + height: 20, + ), + Column( + children: [ + Center( + child: Text( + "Verification", + style: TextStyle( + fontSize: 25, + letterSpacing: 1, + fontWeight: FontWeight.w600), + ), + ), + ], + ), + SizedBox( + height: 30, + ), + SizedBox( + height: 10, + ), + Form( + key: verifyAccountForm, + child: Container( + width: SizeConfig.realScreenWidth * 0.90, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 20), + child: Row( + mainAxisAlignment: + MainAxisAlignment.end, + children: [ + Expanded( + child: Text( + TranslationBase.of(context) + .enterVerificationMsg, + style: TextStyle( + fontSize: 13, + color: Colors.grey), + ), + ), + SizedBox( + height: 10, + ) + ], + ), + ), + buildSizedBox(30), + Center( + child: FractionallySizedBox( + widthFactor: 0.80, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceAround, + children: [ + Container( + width: 55, + height: 55, + color: Colors.white, + child: TextFormField( + textInputAction: + TextInputAction.next, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + focusNode: focusD1, + controller: digit1, + textAlign: TextAlign.center, + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + onSaved: (val) { + verifyAccountFormValue[ + 'digit1'] = val; + }, + validator: validateCodeDigit, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD2); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD2); + } + }, + ), + ), + Container( + width: 55, + height: 55, + color: Colors.white, + child: TextFormField( + focusNode: focusD2, + controller: digit2, + textInputAction: + TextInputAction.next, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + verifyAccountFormValue[ + 'digit2'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD3); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus(focusD3); + } + }, + ), + ), + Container( + width: 55, + height: 55, + color: Colors.white, + child: TextFormField( + focusNode: focusD3, + controller: digit3, + textInputAction: + TextInputAction.next, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + verifyAccountFormValue[ + 'digit3'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus( + focusD4); + } + }, + )), + Container( + width: 55, + height: 55, + color: Colors.white, + child: TextFormField( + focusNode: focusD4, + controller: digit4, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeConfig + .textMultiplier * + 3, + ), + keyboardType: + TextInputType.number, + decoration: + buildInputDecoration( + context), + validator: validateCodeDigit, + onSaved: (val) { + verifyAccountFormValue[ + 'digit4'] = val; + }, + onFieldSubmitted: (_) { + FocusScope.of(context) + .requestFocus(focusD4); + submit(model, context); + }, + onChanged: (val) { + if (val.length == 1) { + FocusScope.of(context) + .requestFocus( + focusD4); + submit(model, context); + } + }), + ) + ], + ), + ), + ), + buildSizedBox(20), + // ShowTimerText(model: model), + ]))) + ], + ), + ), + SizedBox( + height: 20, + ), + SizedBox( + height: 10, + ), + Container( + margin: EdgeInsets.all(10), + height: MediaQuery.of(context).size.height * 0.22, + child: Column( + children: [ + SecondaryButton( + label: "Verify", + onTap: () { + submit(model, context); + }, + disabled: authenticationViewModel.isLoading, + loading: authenticationViewModel.isLoading, + ), + SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => + ForgetPasswordPage()), + ); + }, + child: Text( + "Resend OPT?", + style: TextStyle( + fontSize: 14, + color: Theme.of(context).primaryColor), + ), + ), + ], + ), + ], + )) + ], + ), + ), + ), + ), + ); + } + + TextStyle buildTextStyle() { + return TextStyle( + fontSize: SizeConfig.textMultiplier * 3, + ); + } + + InputDecoration buildInputDecoration(BuildContext context) { + return InputDecoration( + // ts/images/password_icon.png + contentPadding: EdgeInsets.only(top: 30, bottom: 30), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).primaryColor), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10.0)), + borderSide: BorderSide(color: Theme.of(context).errorColor), + ), + ); + } + + void submit(AuthenticationViewModel model, BuildContext context) async { + if (verifyAccountForm.currentState.validate()) { + final activationCode = + digit1.text + digit2.text + digit3.text + digit4.text; + + await authenticationViewModel + .checkActivationCode(int.parse(activationCode)); + if (authenticationViewModel.isError) { + Utils.showErrorToast(authenticationViewModel.error); + } else { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => RestPasswordPage()), + ); + } + } + } +} diff --git a/lib/uitl/cupertino_picker.dart b/lib/uitl/cupertino_picker.dart index 608ef80..f537a0b 100644 --- a/lib/uitl/cupertino_picker.dart +++ b/lib/uitl/cupertino_picker.dart @@ -46,7 +46,8 @@ class CupertinoPickerUtils { mainAxisAlignment: MainAxisAlignment.end, children: [ CupertinoButton( - child: Text(TranslationBase.of(context).cancel, + child: Text( + TranslationBase.of(context).cancel.toUpperCase(), style: TextStyle(color: Theme.of(context).primaryColor)), onPressed: () { diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 3210cc5..31a8b4a 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -42,10 +42,13 @@ class TranslationBase { String get enterId => localizedValues['enterId'][locale.languageCode]; String get pleaseEnterYourID => localizedValues['pleaseEnterYourID'][locale.languageCode]; + String get enterPassword => localizedValues['enterPassword'][locale.languageCode]; + String get pleaseEnterPassword => localizedValues['pleaseEnterPassword'][locale.languageCode]; + String get english => localizedValues['english'][locale.languageCode]; String get arabic => localizedValues['arabic'][locale.languageCode]; @@ -53,10 +56,19 @@ class TranslationBase { String get enterCredentialsMsg => localizedValues['enterCredentialsMsg'][locale.languageCode]; + String get enterForgetIdMsg => + localizedValues['enterForgetIdMsg'][locale.languageCode]; + + String get enterVerificationMsg => + localizedValues['enterVerificationMsg'][locale.languageCode]; + String get forgotPassword => localizedValues['forgotPassword'][locale.languageCode]; + String get login => localizedValues['login'][locale.languageCode]; + String get getOPT => localizedValues['getOPT'][locale.languageCode]; + String get haveGreatDay => localizedValues['haveGreatDay'][locale.languageCode]; diff --git a/lib/widgets/buttons/secondary_button.dart b/lib/widgets/buttons/secondary_button.dart index 152ddd6..2fd2bdc 100644 --- a/lib/widgets/buttons/secondary_button.dart +++ b/lib/widgets/buttons/secondary_button.dart @@ -147,8 +147,7 @@ class _SecondaryButtonState extends State child: Container( decoration: BoxDecoration( border: widget.borderColor != null - ? Border.all( - color: widget.borderColor.withOpacity(0.1), width: 2.0) + ? Border.all(color: widget.borderColor, width: 2.0) : null, borderRadius: BorderRadius.all(Radius.circular(100.0)), boxShadow: [