From 305d5e97dd4b26a97562ad5dcfae372594b39261 Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Thu, 31 Mar 2022 10:33:30 +0300 Subject: [PATCH] Tab fix's on login 1.0 --- lib/api/api_client.dart | 2 +- lib/api/client/user_api_client.dart | 52 +++--- lib/classes/consts.dart | 4 + lib/pages/dashboard/dashboard_page.dart | 169 +++++++++++------- lib/pages/settings/define_license_page.dart | 17 +- lib/pages/user/complete_profile_page.dart | 17 +- lib/pages/user/forget_password_page.dart | 152 +++++++++------- .../user/login_method_selection_page.dart | 15 +- lib/pages/user/login_with_password_page.dart | 49 ++++- lib/pages/user/register_page.dart | 8 +- lib/widgets/count_down_timer.dart | 108 +++++++++++ lib/widgets/dialog/otp_dialog.dart | 64 ++++++- 12 files changed, 467 insertions(+), 190 deletions(-) create mode 100644 lib/widgets/count_down_timer.dart diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 2724eb2..173b262 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -75,7 +75,7 @@ class ApiClient { return factoryConstructor(jsonData); } catch (ex) { print(ex); - print("exception:" + ex.toString()); + print("exception121:" + ex.toString()); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } diff --git a/lib/api/client/user_api_client.dart b/lib/api/client/user_api_client.dart index 8bed061..1ca219c 100644 --- a/lib/api/client/user_api_client.dart +++ b/lib/api/client/user_api_client.dart @@ -23,8 +23,6 @@ import '../../classes/app_state.dart'; import '../../models/m_response.dart'; import '../api_client.dart'; - - class UserApiClent { static final UserApiClent _instance = UserApiClent._internal(); @@ -99,11 +97,9 @@ class UserApiClent { } Future ForgetPasswordOTPCompare(String userToken, String userOTP) async { - var postParams = - {"userToken": userToken, - "userOTP": userOTP}; + var postParams = {"userToken": userToken, "userOTP": userOTP}; return await ApiClient().postJsonForResponse(ApiConsts.ForgetPasswordOTPCompare, postParams); - // return await ApiClient().postJsonForObject((json) => PasswordOTPCompare.fromJson(json), ApiConsts.ForgetPasswordOTPCompare, postParams); + // return await ApiClient().postJsonForObject((json) => PasswordOTPCompare.fromJson(json), ApiConsts.ForgetPasswordOTPCompare, postParams); } Future ForgetPassword(String userToken, String newPassword) async { @@ -125,15 +121,14 @@ class UserApiClent { String t = AppState().getUser.data!.accessToken ?? ""; print("tokeen " + t); return await ApiClient().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.ChangePassword, postParams, token: t); - } - - Future ChangeMobileNoOTPRequest(countryID, String mobileNo, String password,) async { - var postParams = - { "countryID":1, - "mobileNo": mobileNo, - "password": password}; + Future ChangeMobileNoOTPRequest( + countryID, + String mobileNo, + String password, + ) async { + var postParams = {"countryID": 1, "mobileNo": mobileNo, "password": password}; String t = AppState().getUser.data!.accessToken ?? ""; return await ApiClient().postJsonForObject((json) => ChangeMobile.fromJson(json), ApiConsts.ChangeMobileNoOTPRequest, postParams, token: t); } @@ -148,19 +143,13 @@ class UserApiClent { } Future ChangeEmailOTPRequest(String email, String password) async { - var postParams = - {"email": email, - "password":password - }; + var postParams = {"email": email, "password": password}; String t = AppState().getUser.data!.accessToken ?? ""; return await ApiClient().postJsonForObject((json) => ChanEmail.fromJson(json), ApiConsts.ChangeEmailOTPRequest, postParams, token: t); } Future ChangeEmail(String userToken, String userOTP) async { - var postParams = - {"userToken": userToken, - "userOTP": userOTP - }; + var postParams = {"userToken": userToken, "userOTP": userOTP}; String t = AppState().getUser.data!.accessToken ?? ""; return await ApiClient().postJsonForObject((json) => ConfirmEmail.fromJson(json), ApiConsts.ChangeEmail, postParams, token: t); } @@ -178,12 +167,27 @@ class UserApiClent { } Future EmailVerifyOTPVerify(String userToken, String userOTP) async { - var postParams = - {"userToken": userToken, - "userOTP": userOTP}; + var postParams = {"userToken": userToken, "userOTP": userOTP}; String t = AppState().getUser.data!.accessToken ?? ""; return await ApiClient().postJsonForObject((json) => VerifyEmailOTP.fromJson(json), ApiConsts.EmailVerifyOTPVerify, postParams, token: t); } + Future UpdateUserImage(String image) async { + var postParams = {"userID": AppState().getUser.data!.userInfo!.userId, "userImage": image}; + // return await ApiClient().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppState().getUser.data!.accessToken ?? ""; + print("tokeen " + t); + return await ApiClient().postJsonForResponse(ApiConsts.UpdateUserImage, postParams, token: t); + } + + Future GetUserImage(String image) async { + var postParams = {}; + // return await ApiClient().postJsonForResponse(ApiConsts.ChangePassword, postParams); + + String t = AppState().getUser.data!.accessToken ?? ""; + print("tokeen " + t); + return await ApiClient().postJsonForResponse(ApiConsts.GetUserImage, postParams, token: t); + } } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 16a90ca..bda0cac 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -27,6 +27,10 @@ class ApiConsts { static String ChangeEmail = baseUrlServices + "api/Account/ChangeEmail"; static String EmailVerify = baseUrlServices + "api/Account/EmailVerify"; static String EmailVerifyOTPVerify = baseUrlServices + "api/Account/EmailVerifyOTPVerify"; + static String UpdateUserImage = baseUrlServices + "api/User_UpdateProfileImage"; + static String GetUserImage = baseUrlServices + "api/ProfileImage"; + + //Profile static String GetProviderDocument = baseUrlServices + "api/ServiceProviders/ServiceProviderDocument_Get"; static String ServiceProviderDocument_Update = baseUrlServices + "api/ServiceProviders/ServiceProviderDocument_Update"; diff --git a/lib/pages/dashboard/dashboard_page.dart b/lib/pages/dashboard/dashboard_page.dart index 6abd4db..d8cc7c7 100644 --- a/lib/pages/dashboard/dashboard_page.dart +++ b/lib/pages/dashboard/dashboard_page.dart @@ -1,7 +1,14 @@ +import 'package:car_provider_app/api/api_client.dart'; +import 'package:car_provider_app/api/client/user_api_client.dart'; import 'package:car_provider_app/api/shared_prefrence.dart'; +import 'package:car_provider_app/classes/app_state.dart'; +import 'package:car_provider_app/classes/consts.dart'; +import 'package:car_provider_app/classes/utils.dart'; import 'package:car_provider_app/config/routes.dart'; +import 'package:car_provider_app/models/m_response.dart'; import 'package:car_provider_app/theme/colors.dart'; import 'package:car_provider_app/utils/navigator.dart'; +import 'package:car_provider_app/utils/utils.dart'; import 'package:car_provider_app/widgets/app_bar.dart'; import 'package:car_provider_app/widgets/show_fill_button.dart'; import 'package:car_provider_app/extensions/int_extensions.dart'; @@ -9,6 +16,7 @@ import 'package:car_provider_app/extensions/string_extensions.dart'; import 'package:car_provider_app/extensions/widget_extensions.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:http/http.dart'; import 'package:image_picker/image_picker.dart'; import 'dart:io'; @@ -28,10 +36,9 @@ class _DashboardPageState extends State { // } File? imagePicked; + String image64 = ""; final _picker = ImagePicker(); - - @override void initState() { // TODO: implement initState @@ -54,7 +61,7 @@ class _DashboardPageState extends State { body: Container( child: Container( child: Center( - child: "Dashboard/Main Page".toText24(), + child: "Dashboard/Main Page".toText24(), ), ), ), @@ -66,24 +73,21 @@ class _DashboardPageState extends State { child: Container( child: Column( children: [ - Stack( - children:[ - Container( - width: double.infinity, - height: 200, - color: accentColor.withOpacity(0.3), - child: Icon( - Icons.person, - size: 80, - color: accentColor.withOpacity(0.3), - ), - ), - Positioned( - top: 10, - right: 10, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + Stack(children: [ + Container( + width: double.infinity, + height: 200, + color: accentColor.withOpacity(0.3), + child: Image.network(ApiConsts.baseUrlServices + AppState().getUser.data!.userInfo!.userImageUrl.toString()), + ), + Positioned( + top: 10, + right: 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( children: [ Container( width: 40, @@ -92,16 +96,40 @@ class _DashboardPageState extends State { color: Colors.grey[200], borderRadius: BorderRadius.circular(30), ), - child: Icon(Icons.edit, - color: Colors.blue,).onPress(() { + child: Icon( + Icons.edit, + color: Colors.blue, + ).onPress(() { _openImagePicker(); - // _handleURLButtonPress(context, ImageSourceType.camera); + // _handleURLButtonPress(context, ImageSourceType.camera); + }), + ), + 12.height, + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(30), + ), + child: Icon( + Icons.delete, + color: Colors.blue, + ).onPress(() async { + Utils.showLoading(context); + Response response = await UserApiClent().UpdateUserImage(""); + if (response.statusCode == 201 || response.statusCode == 200) { + Utils.showToast("Image is uploaded"); + } + Utils.hideLoading(context); }), ), ], ), - ) - ] ), + ], + ), + ) + ]), // Container( // width: double.infinity, // height: 200, @@ -148,14 +176,14 @@ class _DashboardPageState extends State { ListTile( leading: SvgPicture.asset("assets/images/ic_notes.svg"), title: "Define Licenses".toText12(), - onTap: (){ + onTap: () { navigateWithName(context, AppRoutes.defineLicense); }, ), ListTile( leading: SvgPicture.asset("assets/images/ic_car.svg"), title: "Dealership Settings".toText12(), - onTap: (){ + onTap: () { navigateWithName(context, AppRoutes.dealershipSetting); }, ), @@ -208,26 +236,16 @@ class _DashboardPageState extends State { void _openImagePicker() { showDialog( context: context, - builder: (context) => AlertDialog( - content: Text("Choose image source"), - actions: [ - FlatButton( - child: Text("Camera"), - onPressed: () => - cameraImage() - ), - FlatButton( - child: Text("Gallery"), - onPressed: () => gallaryImage() - ), - ] - ), - // .then((ImageSource source) async { - // if (source != null) { - // final pickedFile = await ImagePicker().getImage(source: source); - // setState(() => imagePicked = File(pickedFile.path)); - // } - // } + builder: (context) => AlertDialog(content: Text("Choose image source"), actions: [ + FlatButton(child: Text("Camera"), onPressed: () => cameraImage()), + FlatButton(child: Text("Gallery"), onPressed: () => gallaryImage()), + ]), + // .then((ImageSource source) async { + // if (source != null) { + // final pickedFile = await ImagePicker().getImage(source: source); + // setState(() => imagePicked = File(pickedFile.path)); + // } + // } ); } @@ -237,23 +255,48 @@ class _DashboardPageState extends State { source: ImageSource.gallery, ); final pickedImageFile = File(pickedImage!.path); - setState(() { - imagePicked = pickedImageFile; - }); + int sizeInBytes = pickedImageFile.lengthSync(); + // double sizeInMb = sizeInBytes / (1024 * 1024); + if (sizeInBytes > 1000) { + Utils.showToast("File is larger then 1KB"); + } else { + image64 = convertFileToBase64(pickedImageFile); + + Utils.showLoading(context); + Response response = await UserApiClent().UpdateUserImage(image64); + if (response.statusCode == 201 || response.statusCode == 200) { + Utils.showToast("Image is uploaded"); + } + Utils.hideLoading(context); + setState(() { + imagePicked = pickedImageFile; + }); + } } void cameraImage() async { - final picker = ImagePicker(); - final pickedImage = await picker.pickImage( - source: ImageSource.camera, - ); - final pickedImageFile = File(pickedImage!.path); - setState(() { - imagePicked = pickedImageFile; - }); + // final picker = ImagePicker(); + // final pickedImage = await picker.pickImage( + // source: ImageSource.camera, + // ); + // final pickedImageFile = File(pickedImage!.path); + // int sizeInBytes = pickedImageFile.lengthSync(); + // // double sizeInMb = sizeInBytes / (1024 * 1024); + // if (sizeInBytes > 1000) { + // Utils.showToast("File is larger then 1KB"); + // } else { + // image64 = convertFileToBase64(pickedImageFile); + // + // Utils.showLoading(context); + // Response response = await UserApiClent().UpdateUserImage(image64); + // if (response.statusCode == 201 || response.statusCode == 200) { + // Utils.showToast("Image is uploaded"); + // } + // Utils.hideLoading(context); + // setState(() { + // imagePicked = pickedImageFile; + // }); + // } + UserApiClent().GetUserImage("image"); } } - - - - diff --git a/lib/pages/settings/define_license_page.dart b/lib/pages/settings/define_license_page.dart index 2bbee50..9b41b2d 100644 --- a/lib/pages/settings/define_license_page.dart +++ b/lib/pages/settings/define_license_page.dart @@ -113,12 +113,19 @@ class _DefineLicensePageState extends State { if (result != null) { File file = File(result.files.single.path ?? ""); + int sizeInBytes = file.lengthSync(); + // double sizeInMb = sizeInBytes / (1024 * 1024); + if (sizeInBytes > 1000){ + Utils.showToast("File is larger then 1KB"); + }else{ + document!.data![index].document = convertFileToBase64(file); + document!.data![index].fileExt = checkFileExt(file.path); + setState(() { + document!.data![index].documentUrl = result.files.single.path ?? ""; + }); + } + - document!.data![index].document = convertFileToBase64(file); - document!.data![index].fileExt = checkFileExt(file.path); - setState(() { - document!.data![index].documentUrl = result.files.single.path ?? ""; - }); } else { // User canceled the picker } diff --git a/lib/pages/user/complete_profile_page.dart b/lib/pages/user/complete_profile_page.dart index a63aeaf..ac01995 100644 --- a/lib/pages/user/complete_profile_page.dart +++ b/lib/pages/user/complete_profile_page.dart @@ -52,7 +52,7 @@ class _CompleteProfilePageState extends State { 12.height, TxtField( - hint: "First Name", + hint: "First Name*", value: firstName, onChanged: (v) { firstName = v; @@ -60,7 +60,7 @@ class _CompleteProfilePageState extends State { ), 12.height, TxtField( - hint: "Surname", + hint: "Surname*", value: lastName, onChanged: (v) { lastName = v; @@ -70,15 +70,13 @@ class _CompleteProfilePageState extends State { TxtField( hint: "Email", value: email, - isButtonEnable: email!.length > 0 ? true : false, - buttonTitle: "Verify", onChanged: (v) { email = v; }, ), 12.height, TxtField( - hint: "Create Password", + hint: "Create Password*", isPasswordEnabled: true, maxLines: 1, value: password, @@ -88,7 +86,7 @@ class _CompleteProfilePageState extends State { ), 12.height, TxtField( - hint: "Confirm Password", + hint: "Confirm Password*", isPasswordEnabled: true, maxLines: 1, value: confirmPassword, @@ -199,7 +197,12 @@ class _CompleteProfilePageState extends State { } else if (lastName!.isEmpty) { Utils.showToast("Surname is mandatory"); isValid = false; - } else if (password!.isEmpty) { + } else if (email!.isNotEmpty) { + if(!isEmail(email!)){ + Utils.showToast("Enter Valid Email"); + isValid = false; + } + }else if (password!.isEmpty) { Utils.showToast("Password is mandatory"); isValid = false; } else if (!isChecked) { diff --git a/lib/pages/user/forget_password_page.dart b/lib/pages/user/forget_password_page.dart index 1b83423..438cb50 100644 --- a/lib/pages/user/forget_password_page.dart +++ b/lib/pages/user/forget_password_page.dart @@ -25,6 +25,10 @@ import 'package:car_provider_app/models/user/user.dart'; import 'dart:convert'; import 'package:http/http.dart'; +import '../../models/user/country.dart'; +import '../../widgets/dropdown/dropdow_field.dart'; +import '../../widgets/tab/login_email_tab.dart'; + class ForgetPasswordPage extends StatefulWidget { @override State createState() => _ForgetPasswordPageState(); @@ -34,8 +38,20 @@ class _ForgetPasswordPageState extends State { int otpType = 1; String userName = ""; - bool _email = true; - bool _mobile = true; + ClassType type = ClassType.NUMBER; + Country? _country; + String countryCode = ""; + + @override + void initState() { + super.initState(); + getCountryList(); + } + + getCountryList() async { + _country = await UserApiClent().getAllCountries(); + setState(() {}); + } @override @@ -48,62 +64,41 @@ class _ForgetPasswordPageState extends State { padding: EdgeInsets.all(40), child: Column( children: [ - "Verify New Password".toText24(), mFlex(1), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - RaisedButton( - onPressed: () { - setState(() { - _mobile = true; - _email = false; - }); - },child: - Text("Mobile Number", - style: TextStyle(fontSize: 14, - fontWeight: FontWeight.w600,), - ),color: _mobile ? Colors.blue : Colors.transparent,textColor: _mobile ? Colors.white : Colors.blue, - padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), - - RaisedButton(onPressed: () { - setState(() { - _mobile = false; - _email = true; - }); - },child: - Text("Email Address", - style: TextStyle(fontSize: 14, - fontWeight: FontWeight.w600,),),color: _email? Colors.blue : Colors.transparent - ,textColor: _email ? Colors.white : Colors.blue, - padding: EdgeInsets.symmetric(horizontal: 18, vertical: 12),), - ], + LoginEmailTab( + onSelection: (ClassType type) { + setState(() { + this.type = type; + }); + }, ), 50.height, "Retrieve Password".toText24(), 12.height, - _mobile ? TxtField( - hint: "Phone Number" , - value: userName, - onChanged: (v) { - userName = v; - }, - ): - _email ? TxtField( + type == ClassType.NUMBER ? Column(children: [ + getCountry(), + TxtField( + hint: "5********", + value: userName, + onChanged: (v) { + userName = v; + }, + ) + ],) : TxtField( hint: "Email Address", value: userName, onChanged: (v) { userName = v; }, - ): Container(), + ), 50.height, ShowFillButton( title: "Continue", width: double.infinity, onPressed: () { - if(userName.isNum() && _mobile) { + if (userName.isNum() && type==ClassType.NUMBER) { forgetPasswordPhoneOTP(context); - }else if (!userName.isNum() && _email) { + } else if (!userName.isNum() && type==ClassType.EMAIL) { forgetPasswordEmailOTP(context); } }, @@ -115,9 +110,28 @@ class _ForgetPasswordPageState extends State { ); } + Widget getCountry() { + if (_country != null) { + List dropList = []; + _country!.data?.forEach((element) { + dropList.add(new DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); + }); + return Padding( + padding: const EdgeInsets.all(2.0), + child: DropdownField((DropValue value) { + countryCode = value.subValue; + }, list: dropList, hint: "Chose Country"), + ); + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + } + Future forgetPasswordPhoneOTP(BuildContext context) async { Utils.showLoading(context); - Response response = await UserApiClent().ForgetPasswordOTPRequest(userName, otpType); + Response response = await UserApiClent().ForgetPasswordOTPRequest(countryCode+userName, otpType); Utils.hideLoading(context); PasswordOTPRequest otpRequest = PasswordOTPRequest.fromJson(jsonDecode(response.body)); if (otpRequest.messageStatus == 1) { @@ -129,31 +143,31 @@ class _ForgetPasswordPageState extends State { } Future forgetPasswordEmailOTP(BuildContext context) async { - Utils.showLoading(context); - Response response = await UserApiClent().ForgetPasswordOTPRequest(userName, otpType); - Utils.hideLoading(context); - PasswordOTPRequest otpRequest = PasswordOTPRequest.fromJson(jsonDecode(response.body)); - if (otpRequest.messageStatus == 1) { - Utils.showToast("Code is sent to email"); - showMDialog(context, child: OtpDialog( - onClick: (String code) async { - pop(context); - Utils.showLoading(context); - Response res = await UserApiClent().ForgetPasswordOTPCompare(otpRequest.data!.userToken ?? "", code); - Utils.hideLoading(context); - PasswordOTPCompare otpCompare = PasswordOTPCompare.fromJson(jsonDecode(res.body)); - if (otpCompare.messageStatus == 1) { - var userToken = otpCompare.data!.userToken; - print("token is ________"); - print(userToken); - navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); - } else { - Utils.showToast(otpCompare.message ?? ""); - } - }, - )); - } else { - Utils.showToast(otpRequest.message ?? ""); + Utils.showLoading(context); + Response response = await UserApiClent().ForgetPasswordOTPRequest(userName, otpType); + Utils.hideLoading(context); + PasswordOTPRequest otpRequest = PasswordOTPRequest.fromJson(jsonDecode(response.body)); + if (otpRequest.messageStatus == 1) { + Utils.showToast("Code is sent to email"); + showMDialog(context, child: OtpDialog( + onClick: (String code) async { + pop(context); + Utils.showLoading(context); + Response res = await UserApiClent().ForgetPasswordOTPCompare(otpRequest.data!.userToken ?? "", code); + Utils.hideLoading(context); + PasswordOTPCompare otpCompare = PasswordOTPCompare.fromJson(jsonDecode(res.body)); + if (otpCompare.messageStatus == 1) { + var userToken = otpCompare.data!.userToken; + print("token is ________"); + print(userToken); + navigateWithName(context, AppRoutes.confirmNewPasswordPage, arguments: userToken); + } else { + Utils.showToast(otpCompare.message ?? ""); + } + }, + )); + } else { + Utils.showToast(otpRequest.message ?? ""); + } } } -} diff --git a/lib/pages/user/login_method_selection_page.dart b/lib/pages/user/login_method_selection_page.dart index e477b12..7a891ae 100644 --- a/lib/pages/user/login_method_selection_page.dart +++ b/lib/pages/user/login_method_selection_page.dart @@ -108,12 +108,19 @@ class LoginMethodSelectionPage extends StatelessWidget { Response response2 = await UserApiClent().login_V2_OTPVerify(user.data!.userToken??"", code); Utils.hideLoading(context); RegisterUser verifiedUser = RegisterUser.fromJson(jsonDecode(response2.body)); + if (verifiedUser.messageStatus == 1) { User user = User.fromJson(jsonDecode(response2.body)); - AppState().setUser = user; - SharedPrefManager.setUserToken(user.data!.accessToken ?? ""); - SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? ""); - navigateReplaceWithName(context, AppRoutes.dashboard); + if(user.data!.userInfo!.roleId==5||user.data!.userInfo!.roleId==6){ + + AppState().setUser = user; + SharedPrefManager.setUserToken(user.data!.accessToken ?? ""); + SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? ""); + navigateReplaceWithName(context, AppRoutes.dashboard); + }else{ + Utils.showToast("Sorry, Only Provider's can log in this app"); + } + } else { Utils.showToast(verifiedUser.message??""); } diff --git a/lib/pages/user/login_with_password_page.dart b/lib/pages/user/login_with_password_page.dart index 9ec5d43..8d8a97d 100644 --- a/lib/pages/user/login_with_password_page.dart +++ b/lib/pages/user/login_with_password_page.dart @@ -24,6 +24,9 @@ import 'package:car_provider_app/widgets/txt_field.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; +import '../../models/user/country.dart'; +import '../../widgets/dropdown/dropdow_field.dart'; + class LoginWithPassword extends StatefulWidget { @override State createState() => _LoginWithPasswordState(); @@ -33,10 +36,21 @@ class _LoginWithPasswordState extends State { int otpType = 1; ClassType type = ClassType.NUMBER; - String phoneNum = "", password = ""; - String email = ""; + String countryCode = ""; + Country? _country; + + @override + void initState() { + super.initState(); + getCountryList(); + } + + getCountryList() async { + _country = await UserApiClent().getAllCountries(); + setState(() {}); + } @override Widget build(BuildContext context) { @@ -60,14 +74,17 @@ class _LoginWithPasswordState extends State { mFlex(1), Column( children: [ + if (type == ClassType.NUMBER) + getCountry(), + 6.height, TxtField( - hint: type == ClassType.NUMBER ? "Enter phone number" : "Enter Email", + hint: type == ClassType.NUMBER ? "5********" : "Enter Email", value: phoneNum, onChanged: (v) { phoneNum = v; }, ), - 12.height, + 6.height, TxtField( hint: "Enter Password?", value: password, @@ -83,7 +100,7 @@ class _LoginWithPasswordState extends State { Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - "Forget Password".toText12(color: Colors.blue).onPress(() { + "Forget Password?".toText12(color: Colors.blue).onPress(() { navigateWithName(context, AppRoutes.forgetPassword); }), ], @@ -103,9 +120,28 @@ class _LoginWithPasswordState extends State { ); } + Widget getCountry() { + if (_country != null) { + List dropList = []; + _country!.data?.forEach((element) { + dropList.add(new DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); + }); + return Padding( + padding: const EdgeInsets.all(2.0), + child: DropdownField((DropValue value) { + countryCode = value.subValue; + }, list: dropList, hint: "Chose Country"), + ); + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + } + Future performBasicOtp(BuildContext context) async { Utils.showLoading(context); - Response response = await UserApiClent().login_V1(phoneNum, password); + Response response = await UserApiClent().login_V1(type == ClassType.NUMBER ? countryCode + phoneNum : phoneNum, password); Utils.hideLoading(context); LoginPassword user = LoginPassword.fromJson(jsonDecode(response.body)); if (user.messageStatus == 1) { @@ -117,5 +153,4 @@ class _LoginWithPasswordState extends State { } } - Future performBasicOtpEmail(BuildContext context) async {} } diff --git a/lib/pages/user/register_page.dart b/lib/pages/user/register_page.dart index f20f2f9..ee22e6c 100644 --- a/lib/pages/user/register_page.dart +++ b/lib/pages/user/register_page.dart @@ -64,14 +64,14 @@ class RegisterPage extends StatelessWidget { return DropdownField((DropValue value) { countryCode = value.subValue; countryId = value.id; - }, list: dropList, hint: "Chosse Country"); + }, list: dropList, hint: "Chose Country"); } else { return CircularProgressIndicator(); } }, ), TxtField( - hint: "Enter Phone number to Register", + hint: "5********", onChanged: (v) { phoneNum = v; }, @@ -92,7 +92,7 @@ class RegisterPage extends StatelessWidget { Future performBasicOtp(BuildContext context) async { Utils.showLoading(context); - BasicOtp basicOtp = await UserApiClent().basicOtp(countryCode + phoneNum,roleId: role); + BasicOtp basicOtp = await UserApiClent().basicOtp(countryCode + phoneNum, roleId: role); Utils.hideLoading(context); if (basicOtp.messageStatus == 1) { showMDialog(context, child: OtpDialog( @@ -128,6 +128,4 @@ class RegisterPage extends StatelessWidget { } return isValid; } - - } diff --git a/lib/widgets/count_down_timer.dart b/lib/widgets/count_down_timer.dart new file mode 100644 index 0000000..3817e3c --- /dev/null +++ b/lib/widgets/count_down_timer.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; + +class CountDownTimer extends StatefulWidget { + const CountDownTimer({ + Key? key, + int? secondsRemaining, + this.countDownTimerStyle, + this.whenTimeExpires, + this.countDownFormatter, + }) + : secondsRemaining = secondsRemaining, + super(key: key); + + final int? secondsRemaining; + final Function? whenTimeExpires; + final Function? countDownFormatter; + final TextStyle ?countDownTimerStyle; + + State createState() => new _CountDownTimerState(); +} + +class _CountDownTimerState extends State + with TickerProviderStateMixin { + late AnimationController _controller; + late Duration duration; + + String get timerDisplayString { + Duration duration = _controller.duration! * _controller.value; + return widget.countDownFormatter != null + ? widget.countDownFormatter!(duration.inSeconds) + : formatHHMMSS(duration.inSeconds); + // In case user doesn't provide formatter use the default one + // for that create a method which will be called formatHHMMSS or whatever you like + } + + @override + void initState() { + super.initState(); + duration = new Duration(seconds: widget.secondsRemaining ?? 0); + _controller = new AnimationController( + vsync: this, + duration: duration, + ); + _controller.reverse(from: widget.secondsRemaining!.toDouble()); + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { + widget.whenTimeExpires!(); + } + }); + } + + @override + void didUpdateWidget(CountDownTimer oldWidget) { + if (widget.secondsRemaining != oldWidget.secondsRemaining) { + setState(() { + duration = new Duration(seconds: widget.secondsRemaining ?? 0); + _controller.dispose(); + _controller = new AnimationController( + vsync: this, + duration: duration, + ); + _controller.reverse(from: widget.secondsRemaining?.toDouble()); + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed) { + widget.whenTimeExpires!(); + } else if (status == AnimationStatus.dismissed) { + print("Animation Complete"); + } + }); + }); + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return new Center( + child: AnimatedBuilder( + animation: _controller, + builder: (_, Widget? child) { + return Text( + timerDisplayString ??"", + style: widget.countDownTimerStyle, + ); + }),); + } +} + +String formatHHMMSS(int seconds) { + int hours = (seconds / 3600).truncate(); + seconds = (seconds % 3600).truncate(); + int minutes = (seconds / 60).truncate(); + + String hoursStr = (hours).toString().padLeft(2, '0'); + String minutesStr = (minutes).toString().padLeft(2, '0'); + String secondsStr = (seconds % 60).toString().padLeft(2, '0'); + + if (hours == 0) { + return "$minutesStr:$secondsStr"; + } + + return "$hoursStr:$minutesStr:$secondsStr"; +} \ No newline at end of file diff --git a/lib/widgets/dialog/otp_dialog.dart b/lib/widgets/dialog/otp_dialog.dart index 5dffc7a..1cb2043 100644 --- a/lib/widgets/dialog/otp_dialog.dart +++ b/lib/widgets/dialog/otp_dialog.dart @@ -7,14 +7,22 @@ import 'package:car_provider_app/extensions/string_extensions.dart'; import 'package:car_provider_app/extensions/int_extensions.dart'; import 'package:flutter/material.dart'; +import '../count_down_timer.dart'; import '../otp_widget.dart'; -class OtpDialog extends StatelessWidget { +class OtpDialog extends StatefulWidget { Function(String) onClick; - OtpDialog({required this.onClick}); - String code=""; + + @override + State createState() => _OtpDialogState(); +} + +class _OtpDialogState extends State { + String code = ""; + bool hasTimerStopped = false; + final TextEditingController _pinPutController = TextEditingController(); @override @@ -83,12 +91,58 @@ class OtpDialog extends StatelessWidget { // ), // ], // ), + if (!hasTimerStopped) + Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + children: [ + Expanded( + child: Text("Time will expire in"), + ), + CountDownTimer( + secondsRemaining: 60, + whenTimeExpires: () { + setState(() { + hasTimerStopped = true; + }); + }, + countDownTimerStyle: TextStyle( + color: Colors.blue, + fontSize: 17.0, + height: 1.2, + ), + ), + ], + ), + ), + if (hasTimerStopped) + Align( + alignment: Alignment.topRight, + child: InkWell( + onTap: () { + setState(() { + hasTimerStopped = false; + }); + }, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + "Resend Code", + style: TextStyle( + decoration: TextDecoration.underline, + fontWeight: FontWeight.bold, + color: Colors.blue, + ), + ), + ), + ), + ), 40.height, ShowFillButton( title: "Check Code", width: double.infinity, onPressed: () { - onClick(code); + widget.onClick(code); }, ) ], @@ -99,7 +153,7 @@ class OtpDialog extends StatelessWidget { _onOtpCallBack(String otpCode, bool? isAutofill) { if (otpCode.length == 4) { // onSuccess(otpCode); - code=otpCode; + code = otpCode; } } }