From e88b54407348a973de8815529b3a32c1ebc476b8 Mon Sep 17 00:00:00 2001 From: devmirza121 Date: Thu, 16 Jun 2022 14:17:52 +0300 Subject: [PATCH] Latest customer app updates --- assets/images/ic_world.png | Bin 0 -> 8960 bytes lib/api/api_client.dart | 34 +++-- lib/api/client/user_api_client.dart | 44 ++++-- lib/api/shared_prefrence.dart | 22 +++ lib/main.dart | 3 +- lib/models/user/refresh_token.dart | 65 ++++++++ lib/models/user/register_user.dart | 142 ++++++++---------- lib/models/user/user.dart | 10 +- lib/pages/dashboard/dashboard_page.dart | 21 ++- lib/pages/user/complete_profile_page.dart | 5 +- .../user/login_method_selection_page.dart | 6 +- lib/pages/user/splash_page.dart | 52 ++++++- lib/widgets/txt_field.dart | 4 + pubspec.lock | 9 +- resources/langs/en-US.json | 2 +- 15 files changed, 288 insertions(+), 131 deletions(-) create mode 100644 assets/images/ic_world.png create mode 100644 lib/models/user/refresh_token.dart diff --git a/assets/images/ic_world.png b/assets/images/ic_world.png new file mode 100644 index 0000000000000000000000000000000000000000..01ea6343db1796648d08a5f0a9ee6b5c08053a59 GIT binary patch literal 8960 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 literal 0 HcmV?d00001 diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 675aedb..f477d95 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; import 'package:http/io_client.dart'; +import 'client/user_api_client.dart'; typedef FactoryConstructor = U Function(dynamic); @@ -96,13 +97,13 @@ class ApiClient { } Future _postForResponse( - String url, - requestBody, { - String? token, - Map? queryParameters, - Map? headers, - int retryTimes = 0, - }) async { + String url, + requestBody, { + String? token, + Map? queryParameters, + Map? headers, + int retryTimes = 0, + }) async { try { var _headers = {}; if (token != null) { @@ -128,6 +129,11 @@ class ApiClient { print("res: " + response.body); } if (response.statusCode >= 200 && response.statusCode < 500) { + var jsonData = jsonDecode(response.body); + if (jsonData["StatusMessage"] != null && jsonData["StatusMessage"] == "Unauthorized user attempt to access API") { + String mToken = await UserApiClent().UpdateUserToken(); + return await _postForResponse(url, requestBody, token: mToken, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } return response; } else { throw _throwAPIException(response); @@ -158,7 +164,7 @@ class ApiClient { } else { throw APIException(APIException.OTHER, arguments: e); } - }catch (ex) { + } catch (ex) { print("exception1:" + ex.toString()); throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex); } @@ -206,6 +212,8 @@ class ApiClient { return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); } + bool isFirstCall = true; + Future _getForResponse(String url, {String? token, Map? queryParameters, Map? headers, int retryTimes = 0}) async { try { var _headers = {}; @@ -218,7 +226,7 @@ class ApiClient { } if (queryParameters != null) { String queryString = new Uri(queryParameters: queryParameters).query; - url = url + '?' + queryString.toString(); + if (isFirstCall) url = url + '?' + queryString.toString(); } if (!kReleaseMode) { @@ -230,7 +238,13 @@ class ApiClient { if (!kReleaseMode) { print("res: " + response.body.toString()); } - if (response.statusCode >= 200 && response.statusCode < 300) { + if (response.statusCode >= 200 && response.statusCode < 500) { + var jsonData = jsonDecode(response.body); + if (jsonData["StatusMessage"] != null && jsonData["StatusMessage"] == "Unauthorized user attempt to access API") { + String mToken = await UserApiClent().UpdateUserToken(); + isFirstCall = false; + return await _getForResponse(url, token: mToken, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes); + } return response; } else { throw _throwAPIException(response); diff --git a/lib/api/client/user_api_client.dart b/lib/api/client/user_api_client.dart index 5501ee3..1ac90c5 100644 --- a/lib/api/client/user_api_client.dart +++ b/lib/api/client/user_api_client.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:car_customer_app/models/user/change_email.dart'; import 'package:car_customer_app/models/user/change_mobile.dart'; import 'package:car_customer_app/models/user/cities.dart'; @@ -6,6 +7,8 @@ import 'package:car_customer_app/models/user/confirm_email.dart'; import 'package:car_customer_app/models/user/confirm_mobile.dart'; import 'package:car_customer_app/models/user/country.dart'; import 'package:car_customer_app/models/user/image_response.dart'; +import 'package:car_customer_app/models/user/refresh_token.dart'; +import 'package:car_customer_app/models/user/refresh_token.dart'; import 'package:car_customer_app/models/user/role.dart'; import 'package:car_customer_app/models/user/confirm_password.dart'; import 'package:car_customer_app/models/user/forget_password_otp_compare.dart'; @@ -22,9 +25,10 @@ import 'package:car_customer_app/models/user/register_user.dart'; import '../../classes/app_state.dart'; import '../../models/m_response.dart'; -import '../api_client.dart'; - +import '../../models/user/user.dart'; +import '../api_client.dart'; +import '../shared_prefrence.dart'; class UserApiClent { static final UserApiClent _instance = UserApiClent._internal(); @@ -49,9 +53,9 @@ class UserApiClent { Future basicComplete(String userId, String firstName, String lastName, String email, String password) async { var postParams; - if(email.isEmpty){ + if (email.isEmpty) { postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "companyName": "string", "isEmailVerified": true, "password": password}; - }else{ + } else { postParams = {"userID": userId, "firstName": firstName, "lastName": lastName, "email": email, "companyName": "string", "isEmailVerified": true, "password": password}; } @@ -80,13 +84,10 @@ class UserApiClent { return await ApiClient().postJsonForResponse(ApiConsts.Login_V2_OTPVerify, postParams); } - Future RefreshToken(String token, String refreshToken) async { - var postParams = { - "token": token, - "refreshToken": refreshToken - }; - String t = AppState().getUser.data!.accessToken ?? ""; - return await ApiClient().postJsonForResponse(ApiConsts.RefreshToken, postParams, token: t); + Future RefreshTokenAPI(String token, String refreshToken) async { + var postParams = {"token": token, "refreshToken": refreshToken}; + // String t = AppState().getUser.data!.accessToken ?? ""; + return await ApiClient().postJsonForObject((json) => RefreshToken.fromJson(json), ApiConsts.RefreshToken, postParams); } Future getAllCountries() async { @@ -117,7 +118,7 @@ class UserApiClent { Future ForgetPasswordOTPCompare(String userToken, String userOTP) async { 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 { @@ -139,7 +140,6 @@ 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( @@ -186,9 +186,7 @@ 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) => MResponse.fromJson(json), ApiConsts.EmailVerifyOTPVerify, postParams, token: t); @@ -211,4 +209,18 @@ class UserApiClent { print("tokeen " + t); return await ApiClient().postJsonForObject((json) => ImageResponse.fromJson(json), ApiConsts.UpdateUserImage, postParams, token: t); } + + Future UpdateUserToken() async { + String token = await SharedPrefManager.getUserToken(); + String refreshToken = await SharedPrefManager.getRefreshToken(); + RefreshToken refresh = await RefreshTokenAPI(token, refreshToken); + SharedPrefManager.setUserToken(refresh.data!.accessToken ?? ""); + SharedPrefManager.setRefreshToken(refresh.data!.refreshToken ?? ""); + String mdata = await SharedPrefManager.getData(); + UserInfo info = UserInfo.fromJson(jsonDecode(mdata)); + User user = new User(); + user.data = new UserData(accessToken: refresh.data!.accessToken ?? "", refreshToken: refresh.data!.refreshToken ?? "", userInfo: info); + AppState().setUser = user; + return refresh.data!.accessToken??""; + } } diff --git a/lib/api/shared_prefrence.dart b/lib/api/shared_prefrence.dart index 77b3953..2e46e42 100644 --- a/lib/api/shared_prefrence.dart +++ b/lib/api/shared_prefrence.dart @@ -7,6 +7,8 @@ class SharedPrefManager { static String USER_TOKEN = "user.token"; static String USER_NAME = "user.name"; static String PASSWORD = "user.password"; + static String REFRESH_TOKEN = "user.refresh.token"; + static String DATA = "data"; static Future _prefs = SharedPreferences.getInstance(); @@ -49,4 +51,24 @@ class SharedPrefManager { SharedPreferences prefs = await _prefs; return prefs.getString(PASSWORD) ?? ""; } + + static setRefreshToken(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(REFRESH_TOKEN, cookie) ?? "NA"; + } + + static Future getRefreshToken() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(REFRESH_TOKEN) ?? ""; + } + + static setData(String cookie) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(DATA, cookie) ?? "NA"; + } + + static Future getData() async { + SharedPreferences prefs = await _prefs; + return prefs.getString(DATA) ?? ""; + } } diff --git a/lib/main.dart b/lib/main.dart index 75cf83c..9368eab 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -22,7 +22,8 @@ Future main() async { ], fallbackLocale: Locale('en', 'US'), - startLocale: Locale('ar', 'SA'), + // startLocale: Locale('ar', 'SA'), + startLocale: Locale('en', 'US'), path: 'resources/langs', child: MyApp(), ), diff --git a/lib/models/user/refresh_token.dart b/lib/models/user/refresh_token.dart new file mode 100644 index 0000000..7de1e59 --- /dev/null +++ b/lib/models/user/refresh_token.dart @@ -0,0 +1,65 @@ +// To parse this JSON data, do +// +// final refreshToken = refreshTokenFromJson(jsonString); + +import 'dart:convert'; + +RefreshToken refreshTokenFromJson(String str) => RefreshToken.fromJson(json.decode(str)); + +String refreshTokenToJson(RefreshToken data) => json.encode(data.toJson()); + +class RefreshToken { + RefreshToken({ + this.totalItemsCount, + this.data, + this.messageStatus, + this.message, + }); + + final dynamic? totalItemsCount; + final RefreshData? data; + final int? messageStatus; + final String? message; + + factory RefreshToken.fromJson(Map json) => RefreshToken( + totalItemsCount: json["totalItemsCount"], + data: json["data"] == null ? null : RefreshData.fromJson(json["data"]), + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], + message: json["message"] == null ? null : json["message"], + ); + + Map toJson() => { + "totalItemsCount": totalItemsCount, + "data": data == null ? null : data!.toJson(), + "messageStatus": messageStatus == null ? null : messageStatus, + "message": message == null ? null : message, + }; +} + +class RefreshData { + RefreshData({ + this.accessToken, + this.refreshToken, + this.expiryDate, + this.userInfo, + }); + + final String? accessToken; + final String? refreshToken; + final DateTime? expiryDate; + final dynamic? userInfo; + + factory RefreshData.fromJson(Map json) => RefreshData( + accessToken: json["accessToken"] == null ? null : json["accessToken"], + refreshToken: json["refreshToken"] == null ? null : json["refreshToken"], + expiryDate: json["expiryDate"] == null ? null : DateTime.parse(json["expiryDate"]), + userInfo: json["userInfo"], + ); + + Map toJson() => { + "accessToken": accessToken == null ? null : accessToken, + "refreshToken": refreshToken == null ? null : refreshToken, + "expiryDate": expiryDate == null ? null : expiryDate!.toIso8601String(), + "userInfo": userInfo, + }; +} diff --git a/lib/models/user/register_user.dart b/lib/models/user/register_user.dart index 9edee72..71ef970 100644 --- a/lib/models/user/register_user.dart +++ b/lib/models/user/register_user.dart @@ -10,62 +10,34 @@ String registerUserToJson(RegisterUser data) => json.encode(data.toJson()); class RegisterUser { RegisterUser({ + this.messageStatus, this.totalItemsCount, this.data, - this.messageStatus, this.message, }); - dynamic? totalItemsCount; - Data? data; - int? messageStatus; - String? message; + final int? messageStatus; + final dynamic? totalItemsCount; + final Data? data; + final String? message; factory RegisterUser.fromJson(Map json) => RegisterUser( + messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], totalItemsCount: json["totalItemsCount"], - data: Data.fromJson(json["data"]), - messageStatus: json["messageStatus"], - message: json["message"], + data: json["data"] == null ? null : Data.fromJson(json["data"]), + message: json["message"] == null ? null : json["message"], ); Map toJson() => { + "messageStatus": messageStatus == null ? null : messageStatus, "totalItemsCount": totalItemsCount, - "data": data!.toJson(), - "messageStatus": messageStatus, - "message": message, + "data": data == null ? null : data!.toJson(), + "message": message == null ? null : message, }; } class Data { Data({ - this.accessToken, - this.refreshToken, - this.expiryDate, - this.userInfo, - }); - - String? accessToken; - String? refreshToken; - DateTime? expiryDate; - UserInfo? userInfo; - - factory Data.fromJson(Map json) => Data( - accessToken: json["accessToken"], - refreshToken: json["refreshToken"], - expiryDate: DateTime.parse(json["expiryDate"]), - userInfo: UserInfo.fromJson(json["userInfo"]), - ); - - Map toJson() => { - "accessToken": accessToken, - "refreshToken": refreshToken, - "expiryDate": expiryDate!.toIso8601String(), - "userInfo": userInfo!.toJson(), - }; -} - -class UserInfo { - UserInfo({ this.id, this.userId, this.firstName, @@ -81,71 +53,75 @@ class UserInfo { this.userRoles, this.isCustomer, this.isProviderDealership, + this.isProviderIndividual, this.isDealershipUser, this.providerId, this.customerId, this.dealershipId, }); - int? id; - String? userId; - String? firstName; - String? lastName; - String? mobileNo; - String? email; - String? userImageUrl; - int? roleId; - String? roleName; - bool? isEmailVerified; - List? serviceProviderBranch; - bool? isVerified; - List? userRoles; - bool? isCustomer; - bool? isProviderDealership; - bool? isDealershipUser; - dynamic? providerId; - int? customerId; - dynamic? dealershipId; + final int? id; + final String? userId; + final dynamic? firstName; + final dynamic? lastName; + final String? mobileNo; + final String? email; + final dynamic? userImageUrl; + final int? roleId; + final dynamic? roleName; + final bool? isEmailVerified; + final List? serviceProviderBranch; + final bool? isVerified; + final List? userRoles; + final bool? isCustomer; + final bool? isProviderDealership; + final bool? isProviderIndividual; + final bool? isDealershipUser; + final dynamic? providerId; + final dynamic? customerId; + final dynamic? dealershipId; - factory UserInfo.fromJson(Map json) => UserInfo( - id: json["id"], - userId: json["userID"], + factory Data.fromJson(Map json) => Data( + id: json["id"] == null ? null : json["id"], + userId: json["userID"] == null ? null : json["userID"], firstName: json["firstName"], lastName: json["lastName"], - mobileNo: json["mobileNo"], - email: json["email"], + mobileNo: json["mobileNo"] == null ? null : json["mobileNo"], + email: json["email"] == null ? null : json["email"], userImageUrl: json["userImageUrl"], - roleId: json["roleID"], + roleId: json["roleID"] == null ? null : json["roleID"], roleName: json["roleName"], - isEmailVerified: json["isEmailVerified"], - serviceProviderBranch: List.from(json["serviceProviderBranch"].map((x) => x)), - isVerified: json["isVerified"], - userRoles: List.from(json["userRoles"].map((x) => x)), - isCustomer: json["isCustomer"], - isProviderDealership: json["isProviderDealership"], - isDealershipUser: json["isDealershipUser"], + isEmailVerified: json["isEmailVerified"] == null ? null : json["isEmailVerified"], + serviceProviderBranch: json["serviceProviderBranch"] == null ? null : List.from(json["serviceProviderBranch"].map((x) => x)), + isVerified: json["isVerified"] == null ? null : json["isVerified"], + userRoles: json["userRoles"] == null ? null : List.from(json["userRoles"].map((x) => x)), + isCustomer: json["isCustomer"] == null ? null : json["isCustomer"], + isProviderDealership: json["isProviderDealership"] == null ? null : json["isProviderDealership"], + isProviderIndividual: json["isProviderIndividual"] == null ? null : json["isProviderIndividual"], + isDealershipUser: json["isDealershipUser"] == null ? null : json["isDealershipUser"], providerId: json["providerID"], customerId: json["customerID"], dealershipId: json["dealershipID"], ); Map toJson() => { - "id": id, - "userID": userId, + "id": id == null ? null : id, + "userID": userId == null ? null : userId, "firstName": firstName, "lastName": lastName, - "mobileNo": mobileNo, - "email": email, + "mobileNo": mobileNo == null ? null : mobileNo, + "email": email == null ? null : email, "userImageUrl": userImageUrl, - "roleID": roleId, + "roleID": roleId == null ? null : roleId, "roleName": roleName, - "isEmailVerified": isEmailVerified, - "serviceProviderBranch": List.from(serviceProviderBranch!.map((x) => x)), - "isVerified": isVerified, - "userRoles": List.from(userRoles!.map((x) => x)), - "isCustomer": isCustomer, - "isProviderDealership": isProviderDealership, - "isDealershipUser": isDealershipUser, + "isEmailVerified": isEmailVerified == null ? null : isEmailVerified, + "serviceProviderBranch": serviceProviderBranch == null ? null : List.from(serviceProviderBranch!.map((x) => x)), + "isVerified": isVerified == null ? null : isVerified, + "userRoles": userRoles == null ? null : List.from(userRoles!.map((x) => x)), + "isCustomer": isCustomer == null ? null : isCustomer, + "isProviderDealership": isProviderDealership == null ? null : isProviderDealership, + "isProviderIndividual": isProviderIndividual == null ? null : isProviderIndividual, + "isDealershipUser": isDealershipUser == null ? null : isDealershipUser, "providerID": providerId, "customerID": customerId, "dealershipID": dealershipId, diff --git a/lib/models/user/user.dart b/lib/models/user/user.dart index 46ff5b0..f1f0ee7 100644 --- a/lib/models/user/user.dart +++ b/lib/models/user/user.dart @@ -17,13 +17,13 @@ class User { }); dynamic totalItemsCount; - Data? data; + UserData? data; int? messageStatus; String? message; factory User.fromJson(Map json) => User( totalItemsCount: json["totalItemsCount"], - data: json["data"] == null ? null : Data.fromJson(json["data"]), + data: json["data"] == null ? null : UserData.fromJson(json["data"]), messageStatus: json["messageStatus"] == null ? null : json["messageStatus"], message: json["message"] == null ? null : json["message"], ); @@ -36,8 +36,8 @@ class User { }; } -class Data { - Data({ +class UserData { + UserData({ this.accessToken, this.refreshToken, this.expiryDate, @@ -49,7 +49,7 @@ class Data { DateTime? expiryDate; UserInfo? userInfo; - factory Data.fromJson(Map json) => Data( + factory UserData.fromJson(Map json) => UserData( accessToken: json["accessToken"] == null ? null : json["accessToken"], refreshToken: json["refreshToken"] == null ? null : json["refreshToken"], expiryDate: json["expiryDate"] == null ? null : DateTime.parse(json["expiryDate"]), diff --git a/lib/pages/dashboard/dashboard_page.dart b/lib/pages/dashboard/dashboard_page.dart index 88079cf..70d0f15 100644 --- a/lib/pages/dashboard/dashboard_page.dart +++ b/lib/pages/dashboard/dashboard_page.dart @@ -7,6 +7,7 @@ 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'; import 'package:car_customer_app/extensions/widget_extensions.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; @@ -143,7 +144,7 @@ class _DashboardPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ userName.toText24(), - LocaleKeys.userRoleOrTitle.tr().toText12(), + AppState().getUser.data!.userInfo!.roleName!.toText12(), ], ), ), @@ -157,19 +158,29 @@ class _DashboardPageState extends State { ), ), ListTile( - leading: Icon(Icons.notifications), + leading: Icon(Icons.notifications,color: Colors.blue,), title: LocaleKeys.notifications.tr().toText12(), ), ListTile( - leading: Icon(Icons.settings), + leading: Icon(Icons.settings,color: Colors.blue,), title: LocaleKeys.general.tr().toText12(), ), ListTile( - leading: Icon(Icons.person), + leading: Icon(Icons.person,color: Colors.blue,), title: LocaleKeys.account.tr().toText12(), ), ListTile( - leading: Icon(Icons.logout), + leading: Image.asset("assets/images/ic_world.png",width: 20,height: 20,color: Colors.blue,), + title: LocaleKeys.english.tr().toText12(), + onTap: () { + if (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA") + context.setLocale(const Locale("en", "US")); + else + context.setLocale(const Locale('ar', 'SA')); + }, + ), + ListTile( + leading: Icon(Icons.logout,color: Colors.blue,), title: LocaleKeys.signOut.tr().toText12(), onTap: () { pop(context); diff --git a/lib/pages/user/complete_profile_page.dart b/lib/pages/user/complete_profile_page.dart index 177e591..8ba249f 100644 --- a/lib/pages/user/complete_profile_page.dart +++ b/lib/pages/user/complete_profile_page.dart @@ -91,6 +91,7 @@ class _CompleteProfilePageState extends State { isPasswordEnabled: true, maxLines: 1, value: password, + isCursorEnd: true, onChanged: (value) => _checkPassword(value), // onChanged: (v) { // password = v; @@ -190,9 +191,9 @@ class _CompleteProfilePageState extends State { Future performCompleteProfile() async { if (validateStructure(password ?? "")) { if (password == confirmPassword) { - print(widget.user.data!.userInfo!.userId ?? "userId"); + print(widget.user.data!.userId?? "userId"); Utils.showLoading(context); - RegisterUser user = await UserApiClent().basicComplete(widget.user.data?.userInfo!.userId ?? "", firstName!, lastName!, email!, password!); + RegisterUser user = await UserApiClent().basicComplete(widget.user.data!.userId ?? "", firstName!, lastName!, email!, password!); Utils.hideLoading(context); if (user.messageStatus == 1) { Utils.showToast(LocaleKeys.successfullyRegistered.tr()); diff --git a/lib/pages/user/login_method_selection_page.dart b/lib/pages/user/login_method_selection_page.dart index 71f02fc..b84804b 100644 --- a/lib/pages/user/login_method_selection_page.dart +++ b/lib/pages/user/login_method_selection_page.dart @@ -111,15 +111,15 @@ class LoginMethodSelectionPage extends StatelessWidget { Utils.hideLoading(context); RegisterUser verifiedUser = RegisterUser.fromJson(jsonDecode(response2.body)); if (verifiedUser.messageStatus == 1) { - Utils.showLoading(context); - Response res = await UserApiClent().RefreshToken(verifiedUser.data.toString()??"", verifiedUser.data.toString()??""); - Utils.hideLoading(context); User user = User.fromJson(jsonDecode(response2.body)); if(user.data!.userInfo!.roleId==4){ + AppState().setUser = user; SharedPrefManager.setUserToken(user.data!.accessToken ?? ""); SharedPrefManager.setUserId(user.data!.userInfo!.userId ?? ""); + SharedPrefManager.setRefreshToken(user.data!.refreshToken??""); + SharedPrefManager.setData(jsonEncode(user.data!.userInfo!.toJson())); navigateReplaceWithName(context, AppRoutes.dashboard); }else{ Utils.showToast(LocaleKeys.onlyCustomerApp.tr()); diff --git a/lib/pages/user/splash_page.dart b/lib/pages/user/splash_page.dart index f688a92..e06133b 100644 --- a/lib/pages/user/splash_page.dart +++ b/lib/pages/user/splash_page.dart @@ -1,16 +1,25 @@ import 'dart:async'; +import 'dart:convert'; +import 'package:car_customer_app/api/client/user_api_client.dart'; +import 'package:car_customer_app/api/shared_prefrence.dart'; +import 'package:car_customer_app/classes/utils.dart'; import 'package:car_customer_app/config/routes.dart'; import 'package:car_customer_app/extensions/int_extensions.dart'; import 'package:car_customer_app/extensions/string_extensions.dart'; import 'package:car_customer_app/generated/locale_keys.g.dart'; +import 'package:car_customer_app/models/user/user.dart'; import 'package:car_customer_app/utils/navigator.dart'; import 'package:car_customer_app/utils/utils.dart'; import 'package:car_customer_app/extensions/widget_extensions.dart'; import 'package:car_customer_app/widgets/show_fill_button.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/src/public_ext.dart'; import 'package:flutter/material.dart'; +import '../../classes/app_state.dart'; +import '../../models/user/refresh_token.dart'; + class SplashPage extends StatelessWidget { @override Widget build(BuildContext context) { @@ -27,16 +36,51 @@ class SplashPage extends StatelessWidget { navigateWithName(context, AppRoutes.registerSelection); }), mFlex(1), - LocaleKeys.alreadySigned.tr().toText(fontSize: 18, isBold: true).onPress(() { - navigateWithName(context, AppRoutes.loginVerification); + LocaleKeys.alreadySigned.tr().toText(fontSize: 18, isBold: true).onPress(() async { + // navigateWithName(context, AppRoutes.loginVerification); + + String token = await SharedPrefManager.getUserToken(); + String refreshToken = await SharedPrefManager.getRefreshToken(); + Utils.showLoading(context); + RefreshToken refresh = await UserApiClent().RefreshTokenAPI(token, refreshToken); + Utils.hideLoading(context); + if (refresh.messageStatus == 1) { + SharedPrefManager.setUserToken(refresh.data!.accessToken ?? ""); + SharedPrefManager.setRefreshToken(refresh.data!.refreshToken ?? ""); + String mdata = await SharedPrefManager.getData(); + print(mdata); + UserInfo info = UserInfo.fromJson(jsonDecode(mdata)); + User user = new User(); + user.data = new UserData(accessToken: refresh.data!.accessToken ?? "", refreshToken: refresh.data!.refreshToken ?? "", userInfo: info); + AppState().setUser = user; + print(AppState().getUser.data?.userInfo?.roleName); + navigateWithName(context, AppRoutes.dashboard); + } else { + String accessToken = await SharedPrefManager.getUserToken(); + String refreshToken = await SharedPrefManager.getRefreshToken(); + String mdata = await SharedPrefManager.getData(); + UserInfo info = UserInfo.fromJson(jsonDecode(mdata)); + User user = new User(); + user.data = new UserData(accessToken: accessToken, refreshToken: refreshToken, userInfo: info); + AppState().setUser = user; + print(AppState().getUser.data?.userInfo?.roleName); + navigateWithName(context, AppRoutes.dashboard); + } }), 35.height, TextButton( style: TextButton.styleFrom( backgroundColor: Colors.white, ), - onPressed: () { }, - child: Text( LocaleKeys.english.tr(), ), + onPressed: () { + if (EasyLocalization.of(context)?.currentLocale?.countryCode == "SA") + context.setLocale(const Locale("en", "US")); + else + context.setLocale(const Locale('ar', 'SA')); + }, + child: Text( + LocaleKeys.english.tr(), + ), ), mFlex(5), ], diff --git a/lib/widgets/txt_field.dart b/lib/widgets/txt_field.dart index bfb4dcf..5b9d80a 100644 --- a/lib/widgets/txt_field.dart +++ b/lib/widgets/txt_field.dart @@ -22,6 +22,7 @@ class TxtField extends StatelessWidget { bool isSidePaddingZero; bool isNeedBorder; bool? isPasswordEnabled; + bool isCursorEnd; Function(String)? onChanged; TextInputType? keyboardType; @@ -44,11 +45,14 @@ class TxtField extends StatelessWidget { this.onChanged, this.isPasswordEnabled, this.keyboardType, + this.isCursorEnd=false, }); @override Widget build(BuildContext context) { controller.text = value ?? ""; + if(isCursorEnd) + controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length)); return InkWell( onTap: isNeedClickAll == false ? null diff --git a/pubspec.lock b/pubspec.lock index 2b2de22..f7f943a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -231,6 +231,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.3" meta: dependency: transitive description: @@ -494,7 +501,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.3" + version: "0.4.8" typed_data: dependency: transitive description: diff --git a/resources/langs/en-US.json b/resources/langs/en-US.json index 6fadabf..522b1be 100644 --- a/resources/langs/en-US.json +++ b/resources/langs/en-US.json @@ -1,6 +1,6 @@ { "firstTimeLogIn" : "First Time Log In", - "signUp": "Sing Up", + "signUp": "Sign Up", "changeMobile": "Change Mobile", "notifications": "Notifications", "general": "General",