diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 4bbed19..675aedb 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -2,10 +2,11 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:car_customer_app/exceptions/api_exception.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; -import 'package:car_customer_app/exceptions/api_exception.dart'; + typedef FactoryConstructor = U Function(dynamic); @@ -68,12 +69,14 @@ class ApiClient { var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); try { if (!kReleaseMode) { - print("res:"+response.body); + print("res121:" + response.body); + print("res121:" + response.statusCode.toString()); } var jsonData = jsonDecode(response.body); return factoryConstructor(jsonData); } catch (ex) { - print("exception:"+response.body); + print(ex); + print("exception:" + ex.toString()); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } @@ -92,7 +95,14 @@ class ApiClient { return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); } - Future _postForResponse(String url, requestBody, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + Future _postForResponse( + String url, + requestBody, { + String? token, + Map? queryParameters, + Map? headers, + int retryTimes = 0, + }) async { try { var _headers = {}; if (token != null) { @@ -107,12 +117,15 @@ class ApiClient { var queryString = new Uri(queryParameters: queryParameters).query; url = url + '?' + queryString; } - var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 100)); - if (!kReleaseMode) { + var response; + + response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 100)); + + if (!kReleaseMode) { print("Url:$url"); print("body:$requestBody"); - print("res: "+ response.body); + print("res: " + response.body); } if (response.statusCode >= 200 && response.statusCode < 500) { return response; @@ -145,6 +158,9 @@ class ApiClient { } else { throw APIException(APIException.OTHER, arguments: e); } + }catch (ex) { + print("exception1:" + ex.toString()); + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } } @@ -161,4 +177,93 @@ class ApiClient { } Future _post(url, {Map? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding)); + + Future getJsonForObject(FactoryConstructor factoryConstructor, String url, + {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + var _headers = {'Accept': 'application/json'}; + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + var response = await getJsonForResponse(url, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes); + try { + if (!kReleaseMode) { + print("res:" + response.body); + } + var jsonData = jsonDecode(response.body); + return factoryConstructor(jsonData); + } catch (ex) { + print("exception:" + response.body); + throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); + } + } + + Future getJsonForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + if (headers == null) { + headers = {'Content-Type': 'application/json'}; + } else { + headers['Content-Type'] = 'application/json'; + } + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } + + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { + try { + var _headers = {}; + if (token != null) { + _headers['Authorization'] = 'Bearer $token'; + } + + if (headers != null && headers.isNotEmpty) { + _headers.addAll(headers); + } + if (queryParameters != null) { + String queryString = new Uri(queryParameters: queryParameters).query; + url = url + '?' + queryString.toString(); + } + + if (!kReleaseMode) { + print("Url:$url"); + print("queryParameters:$queryParameters"); + } + var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60)); + + if (!kReleaseMode) { + print("res: " + response.body.toString()); + } + if (response.statusCode >= 200 && response.statusCode < 300) { + return response; + } else { + throw _throwAPIException(response); + } + } on SocketException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on HttpException catch (e) { + if (retryTimes > 0) { + print('will retry after 3 seconds...'); + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } on TimeoutException catch (e) { + throw APIException(APIException.TIMEOUT, arguments: e); + } on ClientException catch (e) { + if (retryTimes > 0) { + await Future.delayed(Duration(seconds: 3)); + return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1); + } else { + throw APIException(APIException.OTHER, arguments: e); + } + } catch (e) { + throw APIException(APIException.OTHER, arguments: e); + } + } + + Future _get(url, {Map? headers}) => _withClient((client) => client.get(url, headers: headers)); } diff --git a/lib/api/user_api_client.dart b/lib/api/user_api_client.dart index 7be0a58..1d644ef 100644 --- a/lib/api/user_api_client.dart +++ b/lib/api/user_api_client.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:car_customer_app/models/user/country.dart'; import 'package:http/http.dart'; import 'package:car_customer_app/classes/consts.dart'; import 'package:car_customer_app/models/content_info_model.dart'; @@ -57,6 +58,11 @@ class UserApiClent { return await ApiClient().postJsonForResponse(ApiConsts.Login_V2_OTPVerify, postParams); } + Future getAllCountries() async { + var postParams = {}; + return await ApiClient().getJsonForObject((json) => Country.fromJson(json), ApiConsts.GetAllCountry); + } + Future ForgetPasswordOTPRequest(String userName, int otpType) async { var postParams = { diff --git a/lib/app_state/app_state.dart b/lib/app_state/app_state.dart deleted file mode 100644 index 61ec706..0000000 --- a/lib/app_state/app_state.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:car_customer_app/models/content_info_model.dart'; -import 'package:car_customer_app/models/surah_model.dart'; - -class AppState { - static final AppState _instance = AppState._internal(); - - AppState._internal(); - - factory AppState() => _instance; - - SurahModel? _surahModel; - - SurahModel? get getSurahModel => _surahModel; - - void setSurahModel(SurahModel _surahModel) { - this._surahModel = _surahModel; - } - - ContentInfoDataModel? _copyRight; - - ContentInfoDataModel? get getContentInfoModel => _copyRight; - - void setContentInfoModel(ContentInfoDataModel _copyRight) { - this._copyRight = _copyRight; - } -} diff --git a/lib/classes/app_state.dart b/lib/classes/app_state.dart new file mode 100644 index 0000000..0b18a46 --- /dev/null +++ b/lib/classes/app_state.dart @@ -0,0 +1,23 @@ + + +import 'package:car_customer_app/models/user/user.dart'; + +class AppState { + static final AppState _instance = AppState._internal(); + + AppState._internal(); + + factory AppState() => _instance; + + bool isLogged = false; + + set setLogged(v) => isLogged = v; + + bool? get getIsLogged => isLogged; + + User? _user = null; + + set setUser(v) => _user = v; + + User get getUser => _user??User(); +} diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 5f6fdd4..09b8ad8 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -11,6 +11,7 @@ class ApiConsts { static String Login_V2_OTP = baseUrlServices + "api/Account/Login_V2_OTP"; static String Login_V2_OTPVerify = baseUrlServices + "api/Account/Login_V2_OTPVerify"; static String user = baseUrlServices + "api/User/"; + static String GetAllCountry = baseUrlServices + "api/Master/Country_Get"; static String ForgetPasswordOTPRequest = baseUrlServices + "api/Account/ForgetPasswordOTPRequest"; static String ForgetPasswordOTPCompare = baseUrlServices + "api/Account/ForgetPasswordOTPCompare"; diff --git a/lib/models/user/country.dart b/lib/models/user/country.dart new file mode 100644 index 0000000..f4036cf --- /dev/null +++ b/lib/models/user/country.dart @@ -0,0 +1,81 @@ +// To parse this JSON data, do +// +// final country = countryFromJson(jsonString); + +import 'dart:convert'; + +Country countryFromJson(String str) => Country.fromJson(json.decode(str)); + +String countryToJson(Country data) => json.encode(data.toJson()); + +class Country { + Country({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + int? totalItemsCount; + List? data; + int? messageStatus; + String? message; + + factory Country.fromJson(Map json) => Country( + totalItemsCount: json["totalItemsCount"] == null ? null : json["totalItemsCount"], + data: json["data"] == null ? null : List.from(json["data"].map((x) => CountryData.fromJson(x))), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount == null ? null : totalItemsCount, + "data": data == null ? null : List.from(data!.map((x) => x.toJson())), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class CountryData { + CountryData({ + this.id, + this.countryName, + this.countryNameN, + this.nationality, + this.nationalityN, + this.countryCode, + this.alpha2Code, + this.alpha3Code, + }); + + int? id; + String? countryName; + String? countryNameN; + String? nationality; + String? nationalityN; + String? countryCode; + String? alpha2Code; + String? alpha3Code; + + factory CountryData.fromJson(Map json) => CountryData( + id: json["id"] == null ? null : json["id"], + countryName: json["countryName"] == null ? null : json["countryName"], + countryNameN: json["countryNameN"] == null ? null : json["countryNameN"], + nationality: json["nationality"] == null ? null : json["nationality"], + nationalityN: json["nationalityN"] == null ? null : json["nationalityN"], + countryCode: json["countryCode"] == null ? null : json["countryCode"], + alpha2Code: json["alpha2Code"] == null ? null : json["alpha2Code"], + alpha3Code: json["alpha3Code"] == null ? null : json["alpha3Code"], + ); + + Map toJson() => { + "id": id == null ? null : id, + "countryName": countryName == null ? null : countryName, + "countryNameN": countryNameN == null ? null : countryNameN, + "nationality": nationality == null ? null : nationality, + "nationalityN": nationalityN == null ? null : nationalityN, + "countryCode": countryCode == null ? null : countryCode, + "alpha2Code": alpha2Code == null ? null : alpha2Code, + "alpha3Code": alpha3Code == null ? null : alpha3Code, + }; +} diff --git a/lib/pages/user/complete_profile_page.dart b/lib/pages/user/complete_profile_page.dart index 187d011..162cf22 100644 --- a/lib/pages/user/complete_profile_page.dart +++ b/lib/pages/user/complete_profile_page.dart @@ -116,9 +116,9 @@ class _CompleteProfilePageState extends State { RegisterUser user = await UserApiClent().basicComplete(widget.user.data?.userId ?? "", firstName!, lastName!, email!, password!); Utils.hideLoading(context); if (user.messageStatus == 1) { - Utils.showToast(user.message ?? ""); + Utils.showToast( "Successfully Registered, Please login once"); pop(context); - navigateReplaceWithName(context, AppRoutes.dashboard,arguments: user); + // navigateReplaceWithName(context, AppRoutes.dashboard,arguments: user); } else { Utils.showToast(user.message ?? ""); } diff --git a/lib/pages/user/login_method_selection_page.dart b/lib/pages/user/login_method_selection_page.dart index 32b2fd1..9f5d7e0 100644 --- a/lib/pages/user/login_method_selection_page.dart +++ b/lib/pages/user/login_method_selection_page.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:car_customer_app/api/shared_prefrence.dart'; import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/app_state.dart'; import 'package:car_customer_app/classes/utils.dart'; import 'package:car_customer_app/config/constants.dart'; import 'package:car_customer_app/config/routes.dart'; @@ -109,6 +110,7 @@ class LoginMethodSelectionPage extends StatelessWidget { 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); diff --git a/lib/pages/user/login_verification_page.dart b/lib/pages/user/login_verification_page.dart index c602fab..cc95b05 100644 --- a/lib/pages/user/login_verification_page.dart +++ b/lib/pages/user/login_verification_page.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:car_customer_app/api/shared_prefrence.dart'; import 'package:car_customer_app/api/user_api_client.dart'; +import 'package:car_customer_app/classes/app_state.dart'; import 'package:car_customer_app/classes/utils.dart'; import 'package:car_customer_app/config/constants.dart'; import 'package:car_customer_app/config/routes.dart'; @@ -47,6 +48,7 @@ class _LoginVerificationPageState extends State { LoginPassword user = LoginPassword.fromJson(jsonDecode(response.body)); if (user.messageStatus == 1) { userToken = user.data!.userToken ?? ""; + // navigateWithName(context, AppRoutes.loginMethodSelection, arguments: user.data!.userToken); } else { Utils.showToast(user.message ?? ""); @@ -69,6 +71,7 @@ class _LoginVerificationPageState extends State { RegisterUser verifiedUser = RegisterUser.fromJson(jsonDecode(response2.body)); if (verifiedUser.messageStatus == 1) { User user = User.fromJson(jsonDecode(response2.body)); + AppState().setUser = user; navigateReplaceWithName(context, AppRoutes.dashboard); } else { Utils.showToast(verifiedUser.message ?? ""); diff --git a/lib/pages/user/register_page.dart b/lib/pages/user/register_page.dart index 1d9c359..3d94e1b 100644 --- a/lib/pages/user/register_page.dart +++ b/lib/pages/user/register_page.dart @@ -3,12 +3,14 @@ import 'package:car_customer_app/api/user_api_client.dart'; import 'package:car_customer_app/classes/utils.dart'; import 'package:car_customer_app/config/routes.dart'; import 'package:car_customer_app/models/user/basic_otp.dart'; +import 'package:car_customer_app/models/user/country.dart'; import 'package:car_customer_app/models/user/register_user.dart'; import 'package:car_customer_app/utils/navigator.dart'; import 'package:car_customer_app/utils/utils.dart'; import 'package:car_customer_app/widgets/app_bar.dart'; import 'package:car_customer_app/widgets/dialog/dialogs.dart'; import 'package:car_customer_app/widgets/dialog/otp_dialog.dart'; +import 'package:car_customer_app/widgets/dropdown/dropdow_field.dart'; import 'package:car_customer_app/widgets/show_fill_button.dart'; import 'package:car_customer_app/extensions/int_extensions.dart'; import 'package:car_customer_app/extensions/string_extensions.dart'; @@ -17,8 +19,8 @@ import 'package:car_customer_app/widgets/txt_field.dart'; import 'package:flutter/material.dart'; class RegisterPage extends StatelessWidget { - String phoneNum = ""; - + String phoneNum = "", countryCode = ""; + int role = -1, countryId = -1; @override Widget build(BuildContext context) { return Scaffold( @@ -31,6 +33,23 @@ class RegisterPage extends StatelessWidget { children: [ "Enter Phone Number".toText24(), 12.height, + FutureBuilder( + future: UserApiClent().getAllCountries(), + builder: (context, snapshot) { + if (snapshot.hasData) { + List dropList = []; + snapshot.data?.data?.forEach((element) { + dropList.add(new DropValue(element.id ?? 0, (element.countryName ?? "") + " " + (element.countryCode ?? ""), element.countryCode ?? "")); + }); + return DropdownField((DropValue value) { + countryCode = value.subValue; + countryId = value.id; + }, list: dropList, hint: "Chosse Country"); + } else { + return CircularProgressIndicator(); + } + }, + ), TxtField( hint: "Enter Phone number to Register", onChanged: (v) { @@ -53,14 +72,14 @@ class RegisterPage extends StatelessWidget { Future performBasicOtp(BuildContext context) async { Utils.showLoading(context); - BasicOtp basicOtp = await UserApiClent().basicOtp(phoneNum); + BasicOtp basicOtp = await UserApiClent().basicOtp(countryCode + phoneNum,); Utils.hideLoading(context); if (basicOtp.messageStatus == 1) { showMDialog(context, child: OtpDialog( onClick: (String code) async { pop(context); Utils.showLoading(context); - RegisterUser user = await UserApiClent().basicVerify(phoneNum, code, basicOtp.data!.userToken ?? ""); + RegisterUser user = await UserApiClent().basicVerify(countryCode + phoneNum, code, basicOtp.data!.userToken ?? ""); Utils.hideLoading(context); if (user.messageStatus == 1) { Utils.showToast(user.message ?? ""); diff --git a/lib/widgets/dropdown/dropdow_field.dart b/lib/widgets/dropdown/dropdow_field.dart new file mode 100644 index 0000000..05d7190 --- /dev/null +++ b/lib/widgets/dropdown/dropdow_field.dart @@ -0,0 +1,74 @@ + +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/theme/colors.dart'; +import 'package:car_customer_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +class DropValue { + int id; + String value; + String subValue; + + DropValue(this.id, this.value,this.subValue); +} + +class DropdownField extends StatefulWidget { + String? hint; + List? list; + Function(DropValue) onSelect; + + DropdownField(this.onSelect, {this.hint, this.list}); + + @override + State createState() => _DropdownFieldState(); +} + +class _DropdownFieldState extends State { + DropValue? dropdownValue; + List defaultV = [ + new DropValue(1, "One",""), + new DropValue(2, "Two",""), + ]; + + @override + Widget build(BuildContext context) { + return Container( + decoration: containerColorRadiusBorderWidth( + Colors.transparent, + 4, + borderColor, + 0.5, + ), + margin: EdgeInsets.all(2), + padding: EdgeInsets.only(left: 8, right: 8), + child: DropdownButton( + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down_sharp), + elevation: 16, + iconSize: 16, + iconEnabledColor: borderColor, + iconDisabledColor: borderColor, + isExpanded: true, + style: const TextStyle(color: Colors.black), + hint: (widget.hint ?? "").toText12(color: borderColor), + underline: Container( + height: 0, + ), + onChanged: (DropValue? newValue) { + setState(() { + dropdownValue = newValue!; + widget.onSelect(newValue); + }); + }, + items: (widget.list ?? defaultV).map>( + (DropValue value) { + return DropdownMenuItem( + value: value, + child: value.value.toText12(), + ); + }, + ).toList(), + ), + ); + } +} diff --git a/lib/widgets/dropdown/dropdown_text.dart b/lib/widgets/dropdown/dropdown_text.dart new file mode 100644 index 0000000..f560952 --- /dev/null +++ b/lib/widgets/dropdown/dropdown_text.dart @@ -0,0 +1,29 @@ +import 'package:car_customer_app/config/constants.dart'; +import 'package:car_customer_app/extensions/int_extensions.dart'; +import 'package:car_customer_app/extensions/string_extensions.dart'; +import 'package:car_customer_app/theme/colors.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class DropDownText extends StatelessWidget { + String title; + + DropDownText(this.title); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title.toText16(color: accentColor), + 16.height, + SvgPicture.asset( + svgIcons + "ic_arrow_down.svg", + width: 10, + height: 10, + ), + ], + ); + } +}