API's implemented
parent
cb87d022fe
commit
0c5e325d80
@ -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_provider_app/classes/consts.dart';
|
||||||
|
import 'package:car_provider_app/models/content_info_model.dart';
|
||||||
|
import 'package:car_provider_app/models/member_model.dart';
|
||||||
|
import 'package:car_provider_app/models/surah_model.dart';
|
||||||
|
import 'package:car_provider_app/models/user/basic_otp.dart';
|
||||||
|
import 'package:car_provider_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": 5};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MyColors {
|
||||||
|
static const Color primaryColor = Colors.white;
|
||||||
|
static const Color accentColor = Colors.blue;
|
||||||
|
static const Color darkIconColor = Color(0xff28323A);
|
||||||
|
static const Color darkTextColor = Color(0xff2B353E);
|
||||||
|
static const Color normalTextColor = Color(0xff5A5A5A);
|
||||||
|
static const Color lightTextColor = Color(0xffBFBFBF);
|
||||||
|
static const Color gradiantStartColor = Color(0xff33c0a5);
|
||||||
|
static const Color gradiantEndColor = Color(0xff259db7 );
|
||||||
|
static const Color textMixColor = Color(0xff2BB8A6);
|
||||||
|
static const Color backgroundColor = Color(0xffF8F8F8);
|
||||||
|
static const Color grey57Color = Color(0xff575757);
|
||||||
|
static const Color grey77Color = Color(0xff777777);
|
||||||
|
static const Color grey70Color = Color(0xff707070);
|
||||||
|
static const Color greyACColor = Color(0xffACACAC);
|
||||||
|
static const Color grey98Color = Color(0xff989898);
|
||||||
|
static const Color lightGreyEFColor = Color(0xffEFEFEF);
|
||||||
|
static const Color lightGreyEDColor = Color(0xffEDEDED);
|
||||||
|
static const Color lightGreyEAColor = Color(0xffEAEAEA);
|
||||||
|
static const Color darkWhiteColor = Color(0xffE0E0E0);
|
||||||
|
static const Color redColor = Color(0xffD02127);
|
||||||
|
static const Color yellowColor = Color(0xffF4E31C);
|
||||||
|
static const Color backgroundBlackColor = Color(0xff202529);
|
||||||
|
static const Color black = Color(0xff000000);
|
||||||
|
static const Color white = Color(0xffffffff);
|
||||||
|
static const Color green = Color(0xffffffff);
|
||||||
|
static const Color borderColor = Color(0xffE8E8E8);
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
class ApiConsts {
|
||||||
|
//static String baseUrl = "http://10.200.204.20:2801/"; // Local server
|
||||||
|
static String baseUrl = "https://mdlaboratories.com"; // production server
|
||||||
|
static String baseUrlServices = baseUrl + "/mc/"; // production server
|
||||||
|
// static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server
|
||||||
|
static String BasicOTP = baseUrlServices + "api/Register/BasicOTP";
|
||||||
|
static String BasicVerify = baseUrlServices + "api/Register/BasicVerify";
|
||||||
|
static String BasicComplete = baseUrlServices + "api/Register/BasicComplete";
|
||||||
|
|
||||||
|
static String Login_V1 = baseUrlServices + "api/Account/Login_V1";
|
||||||
|
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/";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GlobalConsts {
|
||||||
|
static String isRememberMe = "remember_me";
|
||||||
|
static String email = "email";
|
||||||
|
static String password = "password";
|
||||||
|
static String bookmark = "bookmark";
|
||||||
|
static String fontZoomSize = "font_zoom_size";
|
||||||
|
static String welcomeVideoUrl = "welcomeVideoUrl";
|
||||||
|
static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo";
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
import 'package:car_provider_app/widgets/loading_dialog.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:car_provider_app/exceptions/api_exception.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
class Utils {
|
||||||
|
static bool _isLoadingVisible = false;
|
||||||
|
|
||||||
|
static bool get isLoading => _isLoadingVisible;
|
||||||
|
|
||||||
|
static void showToast(String message) {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dynamic getNotNullValue(List<dynamic> list, int index) {
|
||||||
|
try {
|
||||||
|
return list[index];
|
||||||
|
} catch (ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stringToHex(String colorCode) {
|
||||||
|
try {
|
||||||
|
return int.parse(colorCode.replaceAll("#", "0xff"));
|
||||||
|
} catch (ex) {
|
||||||
|
return (0xff000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showLoading(BuildContext context) {
|
||||||
|
WidgetsBinding.instance?.addPostFrameCallback((_) {
|
||||||
|
_isLoadingVisible = true;
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
barrierColor: Colors.black.withOpacity(0.5),
|
||||||
|
builder: (BuildContext context) => LoadingDialog(),
|
||||||
|
).then((value) {
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hideLoading(BuildContext context) {
|
||||||
|
if (_isLoadingVisible) {
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
_isLoadingVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleException(dynamic exception, Function(String)? onErrorMessage) {
|
||||||
|
String errorMessage;
|
||||||
|
if (exception is APIException) {
|
||||||
|
if (exception.message == APIException.UNAUTHORIZED) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
errorMessage = exception.error?.errorMessage ?? exception.message;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorMessage = APIException.UNKNOWN;
|
||||||
|
}
|
||||||
|
if (onErrorMessage != null) {
|
||||||
|
onErrorMessage(errorMessage);
|
||||||
|
} else {
|
||||||
|
showToast(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
extension IntExtensions on int {
|
||||||
|
Widget get height => SizedBox(height: toDouble());
|
||||||
|
|
||||||
|
Widget get width => SizedBox(width: toDouble());
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:car_provider_app/classes/colors.dart';
|
||||||
|
|
||||||
|
extension EmailValidator on String {
|
||||||
|
Widget get toWidget => Text(this);
|
||||||
|
|
||||||
|
Widget toText({Color? color, bool isBold = false,double? fontSize}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: fontSize??10, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText10({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 10, fontWeight: isBold ? FontWeight.bold : FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.4),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText11({Color? color, bool isUnderLine = false, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: -0.33,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText12({Color? color, bool isUnderLine = false, bool isBold = false, bool isCenter = false, int maxLine = 0}) => Text(
|
||||||
|
this,
|
||||||
|
textAlign: isCenter ? TextAlign.center : null,
|
||||||
|
maxLines: (maxLine > 0) ? maxLine : null,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: isBold ? FontWeight.bold : FontWeight.w600,
|
||||||
|
color: color ?? MyColors.darkTextColor,
|
||||||
|
letterSpacing: -0.72,
|
||||||
|
decoration: isUnderLine ? TextDecoration.underline : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText13({Color? color, bool isUnderLine = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600, color: color ?? MyColors.darkTextColor, letterSpacing: -0.52, decoration: isUnderLine ? TextDecoration.underline : null),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText14({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 14, letterSpacing: -0.48, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText16({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 16, letterSpacing: -0.64, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText17({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(color: color ?? MyColors.darkTextColor, fontSize: 17, letterSpacing: -0.68, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText22({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText24({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget toText32({Color? color, bool isBold = false}) => Text(
|
||||||
|
this,
|
||||||
|
style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600),
|
||||||
|
);
|
||||||
|
|
||||||
|
bool isValidEmail() {
|
||||||
|
return RegExp(r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$').hasMatch(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toFormattedDate() {
|
||||||
|
String date = this.split("T")[0];
|
||||||
|
String time = this.split("T")[1];
|
||||||
|
var dates = date.split("-");
|
||||||
|
return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}";
|
||||||
|
}
|
||||||
|
|
||||||
|
getMonth(int month) {
|
||||||
|
switch (month) {
|
||||||
|
case 1:
|
||||||
|
return "January";
|
||||||
|
case 2:
|
||||||
|
return "February";
|
||||||
|
case 3:
|
||||||
|
return "March";
|
||||||
|
case 4:
|
||||||
|
return "April";
|
||||||
|
case 5:
|
||||||
|
return "May";
|
||||||
|
case 6:
|
||||||
|
return "June";
|
||||||
|
case 7:
|
||||||
|
return "July";
|
||||||
|
case 8:
|
||||||
|
return "August";
|
||||||
|
case 9:
|
||||||
|
return "September";
|
||||||
|
case 10:
|
||||||
|
return "October";
|
||||||
|
case 11:
|
||||||
|
return "November";
|
||||||
|
case 12:
|
||||||
|
return "December";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
extension WidgetExtensions on Widget {
|
||||||
|
Widget onPress(VoidCallback onTap) => InkWell(onTap: onTap, child: this);
|
||||||
|
|
||||||
|
Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this);
|
||||||
|
|
||||||
|
Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) =>
|
||||||
|
Padding(padding: EdgeInsets.only(left: left, right: right, top: top, bottom: bottom), child: this);
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
class ContentInfoModel {
|
||||||
|
int? totalItemsCount;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
List<ContentInfoDataModel>? data;
|
||||||
|
|
||||||
|
ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||||
|
|
||||||
|
ContentInfoModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
totalItemsCount = json['totalItemsCount'];
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
if (json['data'] != null) {
|
||||||
|
data = [];
|
||||||
|
json['data'].forEach((v) {
|
||||||
|
data?.add(new ContentInfoDataModel.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['totalItemsCount'] = this.totalItemsCount;
|
||||||
|
data['statusCode'] = this.statusCode;
|
||||||
|
data['message'] = this.message;
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContentInfoDataModel {
|
||||||
|
int? contentInfoId;
|
||||||
|
int? contentTypeId;
|
||||||
|
String? content;
|
||||||
|
String? contentTypeNameEn;
|
||||||
|
String? contentTypeNameAr;
|
||||||
|
String? fileName;
|
||||||
|
String? exposeFilePath;
|
||||||
|
|
||||||
|
ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath});
|
||||||
|
|
||||||
|
ContentInfoDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
contentInfoId = json['contentInfoId'];
|
||||||
|
contentTypeId = json['contentTypeId'];
|
||||||
|
content = json['content'];
|
||||||
|
contentTypeNameEn = json['contentTypeNameEn'];
|
||||||
|
contentTypeNameAr = json['contentTypeNameAr'];
|
||||||
|
fileName = json['fileName'];
|
||||||
|
exposeFilePath = json['exposeFilePath'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['contentInfoId'] = this.contentInfoId;
|
||||||
|
data['contentTypeId'] = this.contentTypeId;
|
||||||
|
data['content'] = this.content;
|
||||||
|
data['contentTypeNameEn'] = this.contentTypeNameEn;
|
||||||
|
data['contentTypeNameAr'] = this.contentTypeNameAr;
|
||||||
|
data['fileName'] = this.fileName;
|
||||||
|
data['exposeFilePath'] = this.exposeFilePath;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
class MemberModel {
|
||||||
|
int? totalItemsCount;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
List<MemberDataModel>? data;
|
||||||
|
|
||||||
|
MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||||
|
|
||||||
|
MemberModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
totalItemsCount = json['totalItemsCount'];
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
if (json['data'] != null) {
|
||||||
|
data = [];
|
||||||
|
json['data'].forEach((v) {
|
||||||
|
data?.add(new MemberDataModel.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['totalItemsCount'] = this.totalItemsCount;
|
||||||
|
data['statusCode'] = this.statusCode;
|
||||||
|
data['message'] = this.message;
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemberDataModel {
|
||||||
|
int? committeeId;
|
||||||
|
String? firstName;
|
||||||
|
String? lastName;
|
||||||
|
String? description;
|
||||||
|
String? picture;
|
||||||
|
int? orderNo;
|
||||||
|
|
||||||
|
MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo});
|
||||||
|
|
||||||
|
MemberDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
committeeId = json['committeeId'];
|
||||||
|
firstName = json['firstName'];
|
||||||
|
lastName = json['lastName'];
|
||||||
|
description = json['description'];
|
||||||
|
picture = json['picture'];
|
||||||
|
orderNo = json['orderNo'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['committeeId'] = this.committeeId;
|
||||||
|
data['firstName'] = this.firstName;
|
||||||
|
data['lastName'] = this.lastName;
|
||||||
|
data['description'] = this.description;
|
||||||
|
data['picture'] = this.picture;
|
||||||
|
data['orderNo'] = this.orderNo;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
class SurahModel {
|
||||||
|
int? totalItemsCount;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
List<SurahModelData>? data;
|
||||||
|
|
||||||
|
SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||||
|
|
||||||
|
SurahModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
totalItemsCount = json['totalItemsCount'];
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
if (json['data'] != null) {
|
||||||
|
data = [];
|
||||||
|
json['data'].forEach((v) {
|
||||||
|
data?.add(SurahModelData.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['totalItemsCount'] = totalItemsCount;
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SurahModelData {
|
||||||
|
int? id;
|
||||||
|
int? surahID;
|
||||||
|
String? nameAR;
|
||||||
|
String? nameEN;
|
||||||
|
int? numberOfAyahs;
|
||||||
|
String? englishNameTranslation;
|
||||||
|
int? revelationID;
|
||||||
|
String? revelationType;
|
||||||
|
int? startPageNo;
|
||||||
|
int? endPageNo;
|
||||||
|
|
||||||
|
SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo});
|
||||||
|
|
||||||
|
SurahModelData.fromJson(Map<String, dynamic> json) {
|
||||||
|
id = json['id'];
|
||||||
|
surahID = json['surahID'];
|
||||||
|
nameAR = json['nameAR'];
|
||||||
|
nameEN = json['nameEN'];
|
||||||
|
numberOfAyahs = json['numberOfAyahs'];
|
||||||
|
englishNameTranslation = json['englishNameTranslation'];
|
||||||
|
revelationID = json['revelation_ID'];
|
||||||
|
revelationType = json['revelationType'];
|
||||||
|
startPageNo = json['startPageNo'];
|
||||||
|
endPageNo = json['endPageNo'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||||
|
data['id'] = this.id;
|
||||||
|
data['surahID'] = this.surahID;
|
||||||
|
data['nameAR'] = this.nameAR;
|
||||||
|
data['nameEN'] = this.nameEN;
|
||||||
|
data['numberOfAyahs'] = this.numberOfAyahs;
|
||||||
|
data['englishNameTranslation'] = this.englishNameTranslation;
|
||||||
|
data['revelation_ID'] = this.revelationID;
|
||||||
|
data['revelationType'] = this.revelationType;
|
||||||
|
data['startPageNo'] = this.startPageNo;
|
||||||
|
data['endPageNo'] = this.endPageNo;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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_provider_app/api/shared_prefrence.dart';
|
||||||
|
import 'package:car_provider_app/api/user_api_client.dart';
|
||||||
|
import 'package:car_provider_app/classes/utils.dart';
|
||||||
|
import 'package:car_provider_app/config/constants.dart';
|
||||||
|
import 'package:car_provider_app/config/routes.dart';
|
||||||
|
import 'package:car_provider_app/models/user/user.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/button/show_image_button.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/dialogs.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/message_dialog.dart';
|
||||||
|
import 'package:car_provider_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:car_provider_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:car_provider_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/otp_dialog.dart';
|
||||||
|
import 'package:car_provider_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_provider_app/api/user_api_client.dart';
|
||||||
|
import 'package:car_provider_app/classes/utils.dart';
|
||||||
|
import 'package:car_provider_app/config/constants.dart';
|
||||||
|
import 'package:car_provider_app/config/routes.dart';
|
||||||
|
import 'package:car_provider_app/models/user/basic_otp.dart';
|
||||||
|
import 'package:car_provider_app/models/user/register_user.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/button/show_image_button.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/dialogs.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/message_dialog.dart';
|
||||||
|
import 'package:car_provider_app/widgets/dialog/otp_dialog.dart';
|
||||||
|
import 'package:car_provider_app/extensions/int_extensions.dart';
|
||||||
|
import 'package:car_provider_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:car_provider_app/extensions/widget_extensions.dart';
|
||||||
|
import 'package:car_provider_app/widgets/show_fill_button.dart';
|
||||||
|
import 'package:car_provider_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,70 +1,102 @@
|
|||||||
|
import 'package:car_provider_app/classes/colors.dart';
|
||||||
import 'package:car_provider_app/theme/colors.dart';
|
import 'package:car_provider_app/theme/colors.dart';
|
||||||
import 'package:car_provider_app/widgets/extensions/int_extensions.dart';
|
import 'package:car_provider_app/utils/navigator.dart';
|
||||||
import 'package:car_provider_app/widgets/extensions/string_extensions.dart';
|
import 'package:car_provider_app/utils/utils.dart';
|
||||||
import 'package:car_provider_app/widgets/show_fill_button.dart';
|
import 'package:car_provider_app/widgets/show_fill_button.dart';
|
||||||
|
import 'package:car_provider_app/extensions/string_extensions.dart';
|
||||||
|
import 'package:car_provider_app/extensions/int_extensions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../otp_widget.dart';
|
||||||
|
|
||||||
class OtpDialog extends StatelessWidget {
|
class OtpDialog extends StatelessWidget {
|
||||||
VoidCallback onClick;
|
Function(String) onClick;
|
||||||
|
|
||||||
|
|
||||||
OtpDialog({required this.onClick});
|
OtpDialog({required this.onClick});
|
||||||
|
String code="";
|
||||||
|
final TextEditingController _pinPutController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
padding: EdgeInsets.all(30),
|
padding: EdgeInsets.all(24),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
"Please insert OTP Code".toText16(),
|
"Please insert OTP Code".toText24(),
|
||||||
20.height,
|
20.height,
|
||||||
Row(
|
OTPWidget(
|
||||||
children: [
|
autoFocus: true,
|
||||||
Expanded(
|
controller: _pinPutController,
|
||||||
child: Container(
|
defaultBorderColor: const Color(0xffD8D8D8),
|
||||||
width: double.infinity,
|
maxLength: 4,
|
||||||
height: 60,
|
onTextChanged: (text) {},
|
||||||
color: accentColor.withOpacity(0.3),
|
pinBoxColor: Colors.white,
|
||||||
),
|
onDone: (code) => _onOtpCallBack(code, null),
|
||||||
),
|
textBorderColor: const Color(0xffD8D8D8),
|
||||||
12.height,
|
pinBoxWidth: 60,
|
||||||
Expanded(
|
pinBoxHeight: 60,
|
||||||
child: Container(
|
pinTextStyle: const TextStyle(fontSize: 24.0, color: MyColors.darkTextColor),
|
||||||
width: double.infinity,
|
pinTextAnimatedSwitcherTransition: ProvidedPinBoxTextAnimation.scalingTransition,
|
||||||
height: 60,
|
pinTextAnimatedSwitcherDuration: const Duration(milliseconds: 300),
|
||||||
color: accentColor.withOpacity(0.3),
|
pinBoxRadius: 10,
|
||||||
),
|
keyboardType: TextInputType.number,
|
||||||
),
|
|
||||||
12.height,
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 60,
|
|
||||||
color: accentColor.withOpacity(0.3),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
12.height,
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
width: double.infinity,
|
|
||||||
height: 60,
|
|
||||||
color: accentColor.withOpacity(0.3),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
// Row(
|
||||||
|
// children: [
|
||||||
|
// Expanded(
|
||||||
|
// child: Container(
|
||||||
|
// width: double.infinity,
|
||||||
|
// height: 60,
|
||||||
|
// color: accentColor.withOpacity(0.3),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// 12.width,
|
||||||
|
// Expanded(
|
||||||
|
// child: Container(
|
||||||
|
// width: double.infinity,
|
||||||
|
// height: 60,
|
||||||
|
// color: accentColor.withOpacity(0.3),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// 12.width,
|
||||||
|
// Expanded(
|
||||||
|
// child: Container(
|
||||||
|
// width: double.infinity,
|
||||||
|
// height: 60,
|
||||||
|
// color: accentColor.withOpacity(0.3),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// 12.width,
|
||||||
|
// Expanded(
|
||||||
|
// child: Container(
|
||||||
|
// width: double.infinity,
|
||||||
|
// height: 60,
|
||||||
|
// color: accentColor.withOpacity(0.3),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
40.height,
|
40.height,
|
||||||
ShowFillButton(
|
ShowFillButton(
|
||||||
title: "Check Code",
|
title: "Check Code",
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
onClick();
|
onClick(code);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onOtpCallBack(String otpCode, bool? isAutofill) {
|
||||||
|
if (otpCode.length == 4) {
|
||||||
|
// onSuccess(otpCode);
|
||||||
|
code=otpCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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