API's implemented
parent
0c5d43c04b
commit
2d7ef46d27
@ -0,0 +1,34 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SharedPrefManager {
|
||||
static String USER_ID = "user.id";
|
||||
static String USER_TOKEN = "user.token";
|
||||
|
||||
|
||||
|
||||
static Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
|
||||
|
||||
static setUserId(String cookie) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString(USER_ID, cookie) ?? "NA";
|
||||
}
|
||||
|
||||
static Future<String> getUserId() async {
|
||||
SharedPreferences prefs = await _prefs;
|
||||
return prefs.getString(USER_ID) ?? "";
|
||||
}
|
||||
|
||||
static setUserToken(String cookie) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString(USER_TOKEN, cookie) ?? "NA";
|
||||
}
|
||||
|
||||
static Future<String> getUserToken() async {
|
||||
SharedPreferences prefs = await _prefs;
|
||||
return prefs.getString(USER_TOKEN) ?? "";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
import 'dart:async';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:car_customer_app/classes/consts.dart';
|
||||
import 'package:car_customer_app/models/content_info_model.dart';
|
||||
import 'package:car_customer_app/models/member_model.dart';
|
||||
import 'package:car_customer_app/models/surah_model.dart';
|
||||
import 'package:car_customer_app/models/user/basic_otp.dart';
|
||||
import 'package:car_customer_app/models/user/register_user.dart';
|
||||
|
||||
import 'api_client.dart';
|
||||
|
||||
class UserApiClent {
|
||||
static final UserApiClent _instance = UserApiClent._internal();
|
||||
|
||||
UserApiClent._internal();
|
||||
|
||||
factory UserApiClent() => _instance;
|
||||
|
||||
Future<BasicOtp> basicOtp(String phoneNo,{int otpType=1}) async {
|
||||
var postParams = {"countryID": 1, "userMobileNo": phoneNo, "otpType": otpType, "userRole": 4};
|
||||
return await ApiClient().postJsonForObject((json) => BasicOtp.fromJson(json), ApiConsts.BasicOTP, postParams);
|
||||
}
|
||||
|
||||
Future<RegisterUser> basicVerify(String phoneNo, String otp, String userToken) async {
|
||||
var postParams = {
|
||||
"userMobileNo": phoneNo,
|
||||
"userOTP": otp,
|
||||
"userToken": userToken,
|
||||
};
|
||||
return await ApiClient().postJsonForObject((json) => RegisterUser.fromJson(json), ApiConsts.BasicVerify, postParams);
|
||||
}
|
||||
|
||||
Future<RegisterUser> basicComplete(String userId, String firstName, String lastName,String email,String password) async {
|
||||
var postParams = {
|
||||
"userID": userId,
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"email": email,
|
||||
"companyName": "string",
|
||||
"isEmailVerified": true,
|
||||
"password": password
|
||||
};
|
||||
return await ApiClient().postJsonForObject((json) => RegisterUser.fromJson(json), ApiConsts.BasicComplete, postParams);
|
||||
}
|
||||
|
||||
Future<Response> login_V1(String phoneNo, String password) async {
|
||||
var postParams = {
|
||||
"mobileorEmail": phoneNo,
|
||||
"password": password,
|
||||
};
|
||||
return await ApiClient().postJsonForResponse(ApiConsts.Login_V1, postParams);
|
||||
//return await ApiClient().postJsonForObject((json) => BasicOtp.fromJson(json), ApiConsts.Login_V1, postParams);
|
||||
}
|
||||
|
||||
Future<Response> login_V2_OTP(String userToken, String loginType) async {
|
||||
var postParams = {
|
||||
"userToken": userToken,
|
||||
"loginType": loginType,
|
||||
};
|
||||
return await ApiClient().postJsonForResponse(ApiConsts.Login_V2_OTP, postParams);
|
||||
}
|
||||
|
||||
Future<Response> login_V2_OTPVerify(String userToken, String otp) async {
|
||||
var postParams = {
|
||||
"userToken": userToken,
|
||||
"userOTP": otp
|
||||
};
|
||||
return await ApiClient().postJsonForResponse(ApiConsts.Login_V2_OTPVerify, postParams);
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
class User {
|
||||
int id;
|
||||
|
||||
User(this.id, this.userName, this.userImage, this.createdDate);
|
||||
|
||||
String userName;
|
||||
String userImage;
|
||||
String createdDate;
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final basicOtp = basicOtpFromJson(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
BasicOtp basicOtpFromJson(String str) => BasicOtp.fromJson(json.decode(str));
|
||||
|
||||
String basicOtpToJson(BasicOtp data) => json.encode(data.toJson());
|
||||
|
||||
class BasicOtp {
|
||||
BasicOtp({
|
||||
this.totalItemsCount,
|
||||
this.data,
|
||||
this.messageStatus,
|
||||
this.message,
|
||||
});
|
||||
|
||||
dynamic totalItemsCount;
|
||||
Data? data;
|
||||
int? messageStatus;
|
||||
String? message;
|
||||
|
||||
factory BasicOtp.fromJson(Map<String, dynamic> json) => BasicOtp(
|
||||
totalItemsCount: json["totalItemsCount"],
|
||||
data: json["data"] == null ? null : Data.fromJson(json["data"]),
|
||||
messageStatus: json["messageStatus"] == null ? null : json["messageStatus"],
|
||||
message: json["message"] == null ? null : json["message"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"totalItemsCount": totalItemsCount,
|
||||
"data": data == null ? null : data!.toJson(),
|
||||
"messageStatus": messageStatus == null ? null : messageStatus,
|
||||
"message": message == null ? null : message,
|
||||
};
|
||||
}
|
||||
|
||||
class Data {
|
||||
Data({
|
||||
this.userToken,
|
||||
});
|
||||
|
||||
String? userToken;
|
||||
|
||||
factory Data.fromJson(Map<String, dynamic> json) => Data(
|
||||
userToken: checkValue(json),
|
||||
);
|
||||
|
||||
static String checkValue(Map<String, dynamic> json) {
|
||||
try {
|
||||
return json["userToken"] == null ? null : json["userToken"];
|
||||
} catch (e) {
|
||||
return json["token"] == null ? null : json["token"];
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"userToken": userToken == null ? null : userToken,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final user = userFromMap(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
RegisterUser userFromMap(String str) => RegisterUser.fromJson(json.decode(str));
|
||||
|
||||
String userToMap(RegisterUser data) => json.encode(data.toMap());
|
||||
|
||||
class RegisterUser {
|
||||
RegisterUser({
|
||||
this.totalItemsCount,
|
||||
this.data,
|
||||
this.messageStatus,
|
||||
this.message,
|
||||
});
|
||||
|
||||
dynamic totalItemsCount;
|
||||
Data? data;
|
||||
int? messageStatus;
|
||||
String? message;
|
||||
|
||||
factory RegisterUser.fromJson(Map<String, dynamic> json) => RegisterUser(
|
||||
totalItemsCount: json["totalItemsCount"],
|
||||
data: json["data"] == null ? null : Data.fromMap(json["data"]),
|
||||
messageStatus: json["messageStatus"] == null ? null : json["messageStatus"],
|
||||
message: json["message"] == null ? null : json["message"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
"totalItemsCount": totalItemsCount,
|
||||
"data": data == null ? null : data!.toMap(),
|
||||
"messageStatus": messageStatus == null ? null : messageStatus,
|
||||
"message": message == null ? null : message,
|
||||
};
|
||||
}
|
||||
|
||||
class Data {
|
||||
Data({
|
||||
this.id,
|
||||
this.userId,
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.mobileNo,
|
||||
this.email,
|
||||
this.userImageUrl,
|
||||
this.roleId,
|
||||
this.roleName,
|
||||
this.isEmailVerified,
|
||||
this.serviceProviderBranch,
|
||||
this.isVerified,
|
||||
this.userRoles,
|
||||
this.isCustomer,
|
||||
this.isProvider,
|
||||
this.providerId,
|
||||
this.customerId,
|
||||
});
|
||||
|
||||
int? id;
|
||||
String? userId;
|
||||
dynamic? firstName;
|
||||
dynamic? lastName;
|
||||
String? mobileNo;
|
||||
String? email;
|
||||
dynamic? userImageUrl;
|
||||
int? roleId;
|
||||
dynamic? roleName;
|
||||
bool? isEmailVerified;
|
||||
List<dynamic>? serviceProviderBranch;
|
||||
bool? isVerified;
|
||||
List<dynamic>? userRoles;
|
||||
bool? isCustomer;
|
||||
bool? isProvider;
|
||||
dynamic? providerId;
|
||||
dynamic? customerId;
|
||||
|
||||
factory Data.fromMap(Map<String, dynamic> 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"] == null ? null : json["mobileNo"],
|
||||
email: json["email"] == null ? null : json["email"],
|
||||
userImageUrl: json["userImageUrl"],
|
||||
roleId: json["roleID"] == null ? null : json["roleID"],
|
||||
roleName: json["roleName"],
|
||||
isEmailVerified: json["isEmailVerified"] == null ? null : json["isEmailVerified"],
|
||||
serviceProviderBranch: json["serviceProviderBranch"] == null ? null : List<dynamic>.from(json["serviceProviderBranch"].map((x) => x)),
|
||||
isVerified: json["isVerified"] == null ? null : json["isVerified"],
|
||||
userRoles: json["userRoles"] == null ? null : List<dynamic>.from(json["userRoles"].map((x) => x)),
|
||||
isCustomer: json["isCustomer"] == null ? null : json["isCustomer"],
|
||||
isProvider: json["isProvider"] == null ? null : json["isProvider"],
|
||||
providerId: json["providerID"],
|
||||
customerId: json["customerID"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
"id": id == null ? null : id,
|
||||
"userID": userId == null ? null : userId,
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"mobileNo": mobileNo == null ? null : mobileNo,
|
||||
"email": email == null ? null : email,
|
||||
"userImageUrl": userImageUrl,
|
||||
"roleID": roleId == null ? null : roleId,
|
||||
"roleName": roleName,
|
||||
"isEmailVerified": isEmailVerified == null ? null : isEmailVerified,
|
||||
"serviceProviderBranch": serviceProviderBranch == null ? null : List<dynamic>.from(serviceProviderBranch!.map((x) => x)),
|
||||
"isVerified": isVerified == null ? null : isVerified,
|
||||
"userRoles": userRoles == null ? null : List<dynamic>.from(userRoles!.map((x) => x)),
|
||||
"isCustomer": isCustomer == null ? null : isCustomer,
|
||||
"isProvider": isProvider == null ? null : isProvider,
|
||||
"providerID": providerId,
|
||||
"customerID": customerId,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,117 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final user = userFromMap(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
User userFromMap(String str) => User.fromMap(json.decode(str));
|
||||
|
||||
String userToMap(User data) => json.encode(data.toMap());
|
||||
|
||||
class User {
|
||||
User({
|
||||
this.accessToken,
|
||||
this.refreshToken,
|
||||
this.expiryDate,
|
||||
this.userInfo,
|
||||
});
|
||||
|
||||
String? accessToken;
|
||||
String? refreshToken;
|
||||
DateTime? expiryDate;
|
||||
UserInfo? userInfo;
|
||||
|
||||
factory User.fromMap(Map<String, dynamic> json) => User(
|
||||
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"] == null ? null : UserInfo.fromMap(json["userInfo"]),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
"accessToken": accessToken == null ? null : accessToken,
|
||||
"refreshToken": refreshToken == null ? null : refreshToken,
|
||||
"expiryDate": expiryDate == null ? null : expiryDate!.toIso8601String(),
|
||||
"userInfo": userInfo == null ? null : userInfo!.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
class UserInfo {
|
||||
UserInfo({
|
||||
this.id,
|
||||
this.userId,
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.mobileNo,
|
||||
this.email,
|
||||
this.userImageUrl,
|
||||
this.roleId,
|
||||
this.roleName,
|
||||
this.isEmailVerified,
|
||||
this.serviceProviderBranch,
|
||||
this.isVerified,
|
||||
this.userRoles,
|
||||
this.isCustomer,
|
||||
this.isProvider,
|
||||
this.providerId,
|
||||
this.customerId,
|
||||
});
|
||||
|
||||
int? id;
|
||||
String? userId;
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
String? mobileNo;
|
||||
String? email;
|
||||
dynamic? userImageUrl;
|
||||
int? roleId;
|
||||
String? roleName;
|
||||
bool? isEmailVerified;
|
||||
List<dynamic>? serviceProviderBranch;
|
||||
bool? isVerified;
|
||||
List<dynamic>? userRoles;
|
||||
bool? isCustomer;
|
||||
bool? isProvider;
|
||||
dynamic? providerId;
|
||||
int? customerId;
|
||||
|
||||
factory UserInfo.fromMap(Map<String, dynamic> json) => UserInfo(
|
||||
id: json["id"] == null ? null : json["id"],
|
||||
userId: json["userID"] == null ? null : json["userID"],
|
||||
firstName: json["firstName"] == null ? null : json["firstName"],
|
||||
lastName: json["lastName"] == null ? null : json["lastName"],
|
||||
mobileNo: json["mobileNo"] == null ? null : json["mobileNo"],
|
||||
email: json["email"] == null ? null : json["email"],
|
||||
userImageUrl: json["userImageUrl"],
|
||||
roleId: json["roleID"] == null ? null : json["roleID"],
|
||||
roleName: json["roleName"] == null ? null : json["roleName"],
|
||||
isEmailVerified: json["isEmailVerified"] == null ? null : json["isEmailVerified"],
|
||||
serviceProviderBranch: json["serviceProviderBranch"] == null ? null : List<dynamic>.from(json["serviceProviderBranch"].map((x) => x)),
|
||||
isVerified: json["isVerified"] == null ? null : json["isVerified"],
|
||||
userRoles: json["userRoles"] == null ? null : List<dynamic>.from(json["userRoles"].map((x) => x)),
|
||||
isCustomer: json["isCustomer"] == null ? null : json["isCustomer"],
|
||||
isProvider: json["isProvider"] == null ? null : json["isProvider"],
|
||||
providerId: json["providerID"],
|
||||
customerId: json["customerID"] == null ? null : json["customerID"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
"id": id == null ? null : id,
|
||||
"userID": userId == null ? null : userId,
|
||||
"firstName": firstName == null ? null : firstName,
|
||||
"lastName": lastName == null ? null : lastName,
|
||||
"mobileNo": mobileNo == null ? null : mobileNo,
|
||||
"email": email == null ? null : email,
|
||||
"userImageUrl": userImageUrl,
|
||||
"roleID": roleId == null ? null : roleId,
|
||||
"roleName": roleName == null ? null : roleName,
|
||||
"isEmailVerified": isEmailVerified == null ? null : isEmailVerified,
|
||||
"serviceProviderBranch": serviceProviderBranch == null ? null : List<dynamic>.from(serviceProviderBranch!.map((x) => x)),
|
||||
"isVerified": isVerified == null ? null : isVerified,
|
||||
"userRoles": userRoles == null ? null : List<dynamic>.from(userRoles!.map((x) => x)),
|
||||
"isCustomer": isCustomer == null ? null : isCustomer,
|
||||
"isProvider": isProvider == null ? null : isProvider,
|
||||
"providerID": providerId,
|
||||
"customerID": customerId == null ? null : customerId,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
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/utils.dart';
|
||||
import 'package:car_customer_app/config/constants.dart';
|
||||
import 'package:car_customer_app/config/routes.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/widgets/app_bar.dart';
|
||||
import 'package:car_customer_app/widgets/button/show_image_button.dart';
|
||||
import 'package:car_customer_app/widgets/dialog/dialogs.dart';
|
||||
import 'package:car_customer_app/widgets/dialog/message_dialog.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:car_customer_app/widgets/dialog/otp_dialog.dart';
|
||||
import 'package:car_customer_app/widgets/txt_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class LoginMethodSelectionPage extends StatelessWidget {
|
||||
String userToken;
|
||||
|
||||
LoginMethodSelectionPage(this.userToken);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: appBar(title: "Log In"),
|
||||
body: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(40),
|
||||
child: Column(
|
||||
children: [
|
||||
"Login Selection".toText24(),
|
||||
mFlex(2),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowImageButton(
|
||||
onClick: () {
|
||||
performBasicOtp(context);
|
||||
},
|
||||
title: 'Finger Print',
|
||||
icon: icons + "ic_fingerprint.png",
|
||||
),
|
||||
),
|
||||
20.width,
|
||||
Expanded(
|
||||
child: ShowImageButton(
|
||||
onClick: () {
|
||||
performBasicOtp(context);
|
||||
},
|
||||
title: 'Face Recognition',
|
||||
icon: icons + "ic_face_id.png",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
40.height,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowImageButton(
|
||||
onClick: () {
|
||||
performBasicOtp(context);
|
||||
},
|
||||
title: 'With SMS',
|
||||
icon: icons + "ic_sms.png",
|
||||
),
|
||||
),
|
||||
20.width,
|
||||
Expanded(
|
||||
child: ShowImageButton(
|
||||
onClick: () {
|
||||
// navigateWithName(context, AppRoutes.dashboard);
|
||||
performBasicOtp(context);
|
||||
},
|
||||
title: 'With Whatsapp',
|
||||
icon: icons + "ic_whatsapp.png",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
mFlex(10),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> performBasicOtp(BuildContext context) async {
|
||||
Utils.showLoading(context);
|
||||
Response response = await UserApiClent().login_V2_OTP(userToken, "1");
|
||||
Utils.hideLoading(context);
|
||||
if (response.statusCode == 200) {
|
||||
String userToken = jsonDecode(response.body)["token"];
|
||||
showMDialog(context, child: OtpDialog(
|
||||
onClick: (String code) async {
|
||||
pop(context);
|
||||
Utils.showLoading(context);
|
||||
Response response2 = await UserApiClent().login_V2_OTPVerify(userToken, code);
|
||||
Utils.hideLoading(context);
|
||||
if (response2.statusCode == 200) {
|
||||
User user = User.fromMap(jsonDecode(response2.body));
|
||||
SharedPrefManager.setUserToken(user.accessToken ?? "");
|
||||
SharedPrefManager.setUserId(user.userInfo!.userId ?? "");
|
||||
navigateWithName(context, AppRoutes.dashboard);
|
||||
} else {
|
||||
Utils.showToast("Something went wrong");
|
||||
}
|
||||
},
|
||||
));
|
||||
} else {
|
||||
String res = jsonDecode(response.body)["errors"][0] ?? "";
|
||||
Utils.showToast(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:car_customer_app/api/user_api_client.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';
|
||||
import 'package:car_customer_app/models/user/basic_otp.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/button/show_image_button.dart';
|
||||
import 'package:car_customer_app/widgets/dialog/dialogs.dart';
|
||||
import 'package:car_customer_app/widgets/dialog/message_dialog.dart';
|
||||
import 'package:car_customer_app/widgets/dialog/otp_dialog.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:car_customer_app/widgets/show_fill_button.dart';
|
||||
import 'package:car_customer_app/widgets/txt_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class LoginWithPassword extends StatelessWidget {
|
||||
int otpType = 1;
|
||||
String phoneNum = "", password = "";
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: appBar(title: "Log In"),
|
||||
body: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(40),
|
||||
child: Column(
|
||||
children: [
|
||||
"Login".toText24(),
|
||||
mFlex(1),
|
||||
TxtField(
|
||||
hint: "Enter Phone number to verify",
|
||||
onChanged: (v) {
|
||||
phoneNum = v;
|
||||
},
|
||||
),
|
||||
12.height,
|
||||
TxtField(
|
||||
hint: "Password",
|
||||
onChanged: (v) {
|
||||
password = v;
|
||||
},
|
||||
),
|
||||
50.height,
|
||||
ShowFillButton(
|
||||
title: "Continue",
|
||||
width: double.infinity,
|
||||
onPressed: () {
|
||||
performBasicOtp(context);
|
||||
},
|
||||
),
|
||||
mFlex(10),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> performBasicOtp(BuildContext context) async {
|
||||
Utils.showLoading(context);
|
||||
Response response = await UserApiClent().login_V1(phoneNum, password);
|
||||
Utils.hideLoading(context);
|
||||
if (response.statusCode == 200) {
|
||||
String userToken = jsonDecode(response.body)["userToken"];
|
||||
navigateWithName(context, AppRoutes.loginMethodSelection, arguments: userToken);
|
||||
} else {
|
||||
String res = jsonDecode(response.body)["errors"][0] ?? "";
|
||||
Utils.showToast(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
class LoadingDialog extends StatefulWidget {
|
||||
LoadingDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LoadingDialogState createState() {
|
||||
return _LoadingDialogState();
|
||||
}
|
||||
}
|
||||
|
||||
class _LoadingDialogState extends State<LoadingDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 24.0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
elevation: 0,
|
||||
backgroundColor: Colors.transparent,
|
||||
child: Directionality(
|
||||
textDirection: TextDirection.rtl,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,373 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/animation.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
typedef OnDone = void Function(String text);
|
||||
|
||||
class ProvidedPinBoxTextAnimation {
|
||||
static AnimatedSwitcherTransitionBuilder scalingTransition = (child, animation) {
|
||||
return ScaleTransition(
|
||||
child: child,
|
||||
scale: animation,
|
||||
);
|
||||
};
|
||||
|
||||
static AnimatedSwitcherTransitionBuilder defaultNoTransition = (Widget child, Animation<double> animation) {
|
||||
return child;
|
||||
};
|
||||
}
|
||||
|
||||
class OTPWidget extends StatefulWidget {
|
||||
final int maxLength;
|
||||
final TextEditingController? controller;
|
||||
|
||||
final Color defaultBorderColor;
|
||||
final Color pinBoxColor;
|
||||
final double pinBoxBorderWidth;
|
||||
final double pinBoxRadius;
|
||||
final bool hideDefaultKeyboard;
|
||||
|
||||
final TextStyle? pinTextStyle;
|
||||
final double pinBoxHeight;
|
||||
final double pinBoxWidth;
|
||||
final OnDone? onDone;
|
||||
final bool hasError;
|
||||
final Color errorBorderColor;
|
||||
final Color textBorderColor;
|
||||
final Function(String)? onTextChanged;
|
||||
final bool autoFocus;
|
||||
final FocusNode? focusNode;
|
||||
final AnimatedSwitcherTransitionBuilder? pinTextAnimatedSwitcherTransition;
|
||||
final Duration pinTextAnimatedSwitcherDuration;
|
||||
final TextDirection textDirection;
|
||||
final TextInputType keyboardType;
|
||||
final EdgeInsets pinBoxOuterPadding;
|
||||
|
||||
const OTPWidget({
|
||||
Key? key,
|
||||
this.maxLength: 4,
|
||||
this.controller,
|
||||
this.pinBoxWidth: 70.0,
|
||||
this.pinBoxHeight: 70.0,
|
||||
this.pinTextStyle,
|
||||
this.onDone,
|
||||
this.defaultBorderColor: Colors.black,
|
||||
this.textBorderColor: Colors.black,
|
||||
this.pinTextAnimatedSwitcherTransition,
|
||||
this.pinTextAnimatedSwitcherDuration: const Duration(),
|
||||
this.hasError: false,
|
||||
this.errorBorderColor: Colors.red,
|
||||
this.onTextChanged,
|
||||
this.autoFocus: false,
|
||||
this.focusNode,
|
||||
this.textDirection: TextDirection.ltr,
|
||||
this.keyboardType: TextInputType.number,
|
||||
this.pinBoxOuterPadding = const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
this.pinBoxColor = Colors.white,
|
||||
this.pinBoxBorderWidth = 2.0,
|
||||
this.pinBoxRadius = 0,
|
||||
this.hideDefaultKeyboard = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return OTPWidgetState();
|
||||
}
|
||||
}
|
||||
|
||||
class OTPWidgetState extends State<OTPWidget> with SingleTickerProviderStateMixin {
|
||||
AnimationController? _highlightAnimationController;
|
||||
FocusNode? focusNode;
|
||||
String text = "";
|
||||
int currentIndex = 0;
|
||||
List<String> strList = [];
|
||||
bool hasFocus = false;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(OTPWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
focusNode = widget.focusNode ?? focusNode;
|
||||
|
||||
if (oldWidget.maxLength < widget.maxLength) {
|
||||
setState(() {
|
||||
currentIndex = text.length;
|
||||
});
|
||||
widget.controller?.text = text;
|
||||
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
|
||||
} else if (oldWidget.maxLength > widget.maxLength && widget.maxLength > 0 && text.length > 0 && text.length > widget.maxLength) {
|
||||
setState(() {
|
||||
text = text.substring(0, widget.maxLength);
|
||||
currentIndex = text.length;
|
||||
});
|
||||
widget.controller?.text = text;
|
||||
widget.controller?.selection = TextSelection.collapsed(offset: text.length);
|
||||
}
|
||||
}
|
||||
|
||||
_calculateStrList() {
|
||||
if (strList.length > widget.maxLength) {
|
||||
strList.length = widget.maxLength;
|
||||
}
|
||||
while (strList.length < widget.maxLength) {
|
||||
strList.add("");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
focusNode = widget.focusNode ?? FocusNode();
|
||||
|
||||
_initTextController();
|
||||
_calculateStrList();
|
||||
widget.controller?.addListener(_controllerListener);
|
||||
focusNode?.addListener(_focusListener);
|
||||
}
|
||||
|
||||
void _controllerListener() {
|
||||
if (mounted == true) {
|
||||
setState(() {
|
||||
_initTextController();
|
||||
});
|
||||
var onTextChanged = widget.onTextChanged;
|
||||
if (onTextChanged != null) {
|
||||
onTextChanged(widget.controller?.text ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _focusListener() {
|
||||
if (mounted == true) {
|
||||
setState(() {
|
||||
hasFocus = focusNode?.hasFocus ?? false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _initTextController() {
|
||||
if (widget.controller == null) {
|
||||
return;
|
||||
}
|
||||
strList.clear();
|
||||
var text = widget.controller?.text ?? "";
|
||||
if (text.isNotEmpty) {
|
||||
if (text.length > widget.maxLength) {
|
||||
throw Exception("TextEditingController length exceeded maxLength!");
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
strList.add(text[i]);
|
||||
}
|
||||
}
|
||||
|
||||
double get _width {
|
||||
var width = 0.0;
|
||||
for (var i = 0; i < widget.maxLength; i++) {
|
||||
width += widget.pinBoxWidth;
|
||||
if (i == 0) {
|
||||
width += widget.pinBoxOuterPadding.left;
|
||||
} else if (i + 1 == widget.maxLength) {
|
||||
width += widget.pinBoxOuterPadding.right;
|
||||
} else {
|
||||
width += widget.pinBoxOuterPadding.left;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.focusNode == null) {
|
||||
focusNode?.dispose();
|
||||
} else {
|
||||
focusNode?.removeListener(_focusListener);
|
||||
}
|
||||
_highlightAnimationController?.dispose();
|
||||
widget.controller?.removeListener(_controllerListener);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
_otpTextInput(),
|
||||
_touchPinBoxRow(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _touchPinBoxRow() {
|
||||
return widget.hideDefaultKeyboard
|
||||
? _pinBoxRow(context)
|
||||
: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
if (hasFocus) {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
Future.delayed(Duration(milliseconds: 100), () {
|
||||
FocusScope.of(context).requestFocus(focusNode);
|
||||
});
|
||||
} else {
|
||||
FocusScope.of(context).requestFocus(focusNode);
|
||||
}
|
||||
},
|
||||
child: _pinBoxRow(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _otpTextInput() {
|
||||
var transparentBorder = OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.transparent,
|
||||
width: 0.0,
|
||||
),
|
||||
);
|
||||
return Container(
|
||||
width: _width,
|
||||
height: widget.pinBoxHeight,
|
||||
child: TextField(
|
||||
autofocus: !kIsWeb ? widget.autoFocus : false,
|
||||
enableInteractiveSelection: false,
|
||||
focusNode: focusNode,
|
||||
controller: widget.controller,
|
||||
keyboardType: widget.keyboardType,
|
||||
inputFormatters: widget.keyboardType == TextInputType.number ? <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly] : null,
|
||||
style: TextStyle(
|
||||
height: 0.1,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.all(0),
|
||||
focusedErrorBorder: transparentBorder,
|
||||
errorBorder: transparentBorder,
|
||||
disabledBorder: transparentBorder,
|
||||
enabledBorder: transparentBorder,
|
||||
focusedBorder: transparentBorder,
|
||||
counterText: null,
|
||||
counterStyle: null,
|
||||
helperStyle: TextStyle(
|
||||
height: 0.0,
|
||||
color: Colors.transparent,
|
||||
),
|
||||
labelStyle: TextStyle(height: 0.1),
|
||||
fillColor: Colors.transparent,
|
||||
border: InputBorder.none,
|
||||
),
|
||||
cursorColor: Colors.transparent,
|
||||
showCursor: false,
|
||||
maxLength: widget.maxLength,
|
||||
onChanged: _onTextChanged,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onTextChanged(text) {
|
||||
var onTextChanged = widget.onTextChanged;
|
||||
if (onTextChanged != null) {
|
||||
onTextChanged(text);
|
||||
}
|
||||
setState(() {
|
||||
this.text = text;
|
||||
if (text.length >= currentIndex) {
|
||||
for (int i = currentIndex; i < text.length; i++) {
|
||||
strList[i] = text[i];
|
||||
}
|
||||
}
|
||||
currentIndex = text.length;
|
||||
});
|
||||
if (text.length == widget.maxLength) {
|
||||
FocusScope.of(context).requestFocus(FocusNode());
|
||||
var onDone = widget.onDone;
|
||||
if (onDone != null) {
|
||||
onDone(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _pinBoxRow(BuildContext context) {
|
||||
_calculateStrList();
|
||||
List<Widget> pinCodes = List.generate(widget.maxLength, (int i) {
|
||||
return _buildPinCode(i, context);
|
||||
});
|
||||
return Row(children: pinCodes, mainAxisSize: MainAxisSize.min);
|
||||
}
|
||||
|
||||
Widget _buildPinCode(int i, BuildContext context) {
|
||||
Color borderColor;
|
||||
Color pinBoxColor = widget.pinBoxColor;
|
||||
|
||||
if (widget.hasError) {
|
||||
borderColor = widget.errorBorderColor;
|
||||
} else if (i < text.length) {
|
||||
borderColor = widget.textBorderColor;
|
||||
} else {
|
||||
borderColor = widget.defaultBorderColor;
|
||||
pinBoxColor = widget.pinBoxColor;
|
||||
}
|
||||
|
||||
EdgeInsets insets;
|
||||
if (i == 0) {
|
||||
insets = EdgeInsets.only(
|
||||
left: 0,
|
||||
top: widget.pinBoxOuterPadding.top,
|
||||
right: widget.pinBoxOuterPadding.right,
|
||||
bottom: widget.pinBoxOuterPadding.bottom,
|
||||
);
|
||||
} else if (i == strList.length - 1) {
|
||||
insets = EdgeInsets.only(
|
||||
left: widget.pinBoxOuterPadding.left,
|
||||
top: widget.pinBoxOuterPadding.top,
|
||||
right: 0,
|
||||
bottom: widget.pinBoxOuterPadding.bottom,
|
||||
);
|
||||
} else {
|
||||
insets = widget.pinBoxOuterPadding;
|
||||
}
|
||||
return Container(
|
||||
key: ValueKey<String>("container$i"),
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.symmetric(vertical: 4.0, horizontal: 1.0),
|
||||
margin: insets,
|
||||
child: _animatedTextBox(strList[i], i),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: borderColor,
|
||||
width: widget.pinBoxBorderWidth,
|
||||
),
|
||||
color: pinBoxColor,
|
||||
borderRadius: BorderRadius.circular(widget.pinBoxRadius),
|
||||
),
|
||||
width: widget.pinBoxWidth,
|
||||
height: widget.pinBoxHeight,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _animatedTextBox(String text, int i) {
|
||||
if (widget.pinTextAnimatedSwitcherTransition != null) {
|
||||
return AnimatedSwitcher(
|
||||
duration: widget.pinTextAnimatedSwitcherDuration,
|
||||
transitionBuilder: widget.pinTextAnimatedSwitcherTransition ??
|
||||
(Widget child, Animation<double> animation) {
|
||||
return child;
|
||||
},
|
||||
child: Text(
|
||||
text,
|
||||
key: ValueKey<String>("$text$i"),
|
||||
style: widget.pinTextStyle,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Text(
|
||||
text,
|
||||
key: ValueKey<String>("${strList[i]}$i"),
|
||||
style: widget.pinTextStyle,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue