login pages changes

merge-requests/13/merge
Sultan Khan 4 years ago
parent 76aeeffad7
commit b0989d6ca0

@ -2,8 +2,6 @@ import 'package:diplomaticquarterapp/models/Request.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'dart:io';
const MAX_SMALL_SCREEN = 660;
const BASE_URL = 'https://hmgwebservices.com/Services';
@ -12,35 +10,35 @@ const GET_PROJECT = '/Lists.svc/REST/GetProject';
//const BASE_URL = 'https://hmgwebservices.com/'; // Production Environment
//const BASE_URL = 'https://uat.hmgwebservices.com/'; // UAT Environment
//URL to get clinic list
const GET_CLINICS_LIST_URL = "Services/lists.svc/REST/GetClinicCentralized";
//URL to get doctors list
const GET_DOCTORS_LIST_URL = "Services/Doctors.svc/REST/SearchDoctorsByTime";
const CHANNEL = 3;
const GENERAL_ID = 'Cs2020@2016\$2958';
const IP_ADDRESS = '10.20.10.20';
const VERSION_ID = 5.5;
var DeviceTypeID = Platform.isIOS ? 1 : 2;
class AppGlobal {
static var context;
AppSharedPreferences sharedPref = AppSharedPreferences();
Request getPublicRequest() {
Request request = new Request();
request.VersionID = 5.3; //3.6;
request.Channel = 3;
request.VersionID = VERSION_ID; //5.3; //3.6;
request.Channel = CHANNEL; //3;
// request.LanguageID = await sharedPref.getString(APP_LANGUAGE);
request.IPAdress = "10.20.10.20";
request.generalid = 'Cs2020@2016\$2958';
request.IPAdress = IP_ADDRESS; //"10.20.10.20";
request.generalid = GENERAL_ID; //'Cs2020@2016\$2958';
request.PatientOutSA = 0;
request.SessionID = null;
request.isDentalAllowedBackend = false;
request.DeviceTypeID = Platform.isIOS ? 1 : 2;
request.DeviceTypeID = DeviceTypeID;
// Platform.isIOS ? 1 : 2;
return request;
}
}
const CHANNEL = 3;
const GENERAL_ID = 'Cs2020@2016\$2958';
const IP_ADDRESS = '10.20.10.20';
const VERSION_ID = 5.5;

@ -97,4 +97,10 @@ const Map<String, Map<String, String>> localizedValues = {
"verify-with-whatsapp": {"en": "Whatsapp", "ar": " الواتس اب"},
"last-login": {"en": "LAST LOGIN AT:", "ar": "آخر تسجيل دخول"},
"last-login-with": {"en": "VERIFICATION TYPE:", "ar": "نوع التحقق:"},
"verify-fingerprint": {
"en":
"To activate the fingerprint login service, please verify data by using one of the following options.",
"ar":
"لتفعيل خدمة الدخول بالبصمة، يرجى اختيار احدى القنوات التالية للتحقق من البيانات"
}
};

@ -6,3 +6,4 @@ const REGISTER_DATA_FOR_REGISTER = 'register-data-for-register';
const LOGIN_TOKEN_ID = 'register-data-for-register';
const REGISTER_DATA_FOR_LOGIIN = 'register-data-for-login';
const LAST_LOGIN = 'last-login';
const ONLY_SMS = 'only-sms';

@ -41,10 +41,14 @@ class BaseAppClient {
} else {
var parsed = json.decode(response.body.toString());
if (!parsed['IsAuthenticated']) {
if (parsed['isSMSSent'] == true) {
onSuccess(parsed, statusCode);
}
// await helpers.logout();
//helpers.showErrorToast('Your session expired Please login agian');
// TODO create logout fun
} else if (parsed['MessageStatus'] == 1) {
} else if (parsed['MessageStatus'] == 1 ||
parsed['SMSLoginRequired'] == true) {
onSuccess(parsed, statusCode);
} else {
onFailure(parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'],

@ -9,6 +9,7 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:diplomaticquarterapp/widgets/card/rounded_container.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:diplomaticquarterapp/widgets/otp/sms-popup.dart';
import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -47,7 +48,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
int selectedOption;
bool onlySMSBox;
bool onlySMSBox = false;
@override
void initState() {
@ -59,7 +60,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
@override
Widget build(BuildContext context) {
return AppScaffold(
appBarTitle: TranslationBase.of(context).welcome,
appBarTitle: TranslationBase.of(context).confirm,
isShowAppBar: true,
body: Padding(
padding: EdgeInsets.all(20),
@ -76,105 +77,121 @@ class _ConfirmLogin extends State<ConfirmLogin> {
height: 80,
width: 80,
),
AppText(
TranslationBase.of(context).verifyLoginWith,
fontSize: SizeConfig.textMultiplier * 3.5,
textAlign: TextAlign.left,
),
this.onlySMSBox == false
? AppText(
TranslationBase.of(context).verifyLoginWith,
fontSize: SizeConfig.textMultiplier * 3.5,
textAlign: TextAlign.left,
)
: AppText(
TranslationBase.of(context)
.verifyFingerprint2,
fontSize: SizeConfig.textMultiplier * 2.5,
textAlign: TextAlign.left,
),
])),
Expanded(
flex: 4,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: InkWell(
onTap: () => {
authenticateUser(
3, BiometricType.face.index)
},
child: RoundedContainer(
backgroundColor:
BiometricType.face.index == 1
? Colors.white
: Colors.white.withOpacity(.7),
borderColor: Colors.grey,
showBorder: true,
child: Padding(
padding: EdgeInsets.fromLTRB(
20, 10, 20, 10),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/images/login/101.png',
height: SizeConfig
.imageSizeMultiplier *
13,
width: SizeConfig
.imageSizeMultiplier *
16,
),
SizedBox(
height: 20,
),
AppText(
TranslationBase.of(context)
.verifyFaceID,
fontSize:
SizeConfig.textMultiplier *
2,
)
],
),
)))),
Expanded(
child: InkWell(
onTap: () => {
authenticateUser(2,
BiometricType.fingerprint.index)
},
child: RoundedContainer(
backgroundColor:
BiometricType.fingerprint.index == 1
? Colors.white
: Colors.white.withOpacity(.7),
borderColor: Colors.grey,
showBorder: true,
child: Padding(
padding: EdgeInsets.fromLTRB(
25, 10, 25, 10),
child: Column(
children: <Widget>[
Image.asset(
'assets/images/login/102.png',
height: SizeConfig
.imageSizeMultiplier *
13,
width: SizeConfig
.imageSizeMultiplier *
16,
),
SizedBox(
height: 20,
),
AppText(
TranslationBase.of(context)
.verifyFingerprint,
fontSize:
SizeConfig.textMultiplier *
2,
)
],
),
))))
],
),
onlySMSBox == false
? Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: InkWell(
onTap: () => {
authenticateUser(
3, BiometricType.face.index)
},
child: RoundedContainer(
backgroundColor:
BiometricType.face.index == 1
? Colors.white
: Colors.white
.withOpacity(.7),
borderColor: Colors.grey,
showBorder: true,
child: Padding(
padding: EdgeInsets.fromLTRB(
20, 10, 20, 10),
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/images/login/101.png',
height: SizeConfig
.imageSizeMultiplier *
13,
width: SizeConfig
.imageSizeMultiplier *
16,
),
SizedBox(
height: 20,
),
AppText(
TranslationBase.of(
context)
.verifyFaceID,
fontSize: SizeConfig
.textMultiplier *
2,
)
],
),
)))),
Expanded(
child: InkWell(
onTap: () => {
authenticateUser(
2,
BiometricType
.fingerprint.index)
},
child: RoundedContainer(
backgroundColor: BiometricType
.fingerprint.index ==
1
? Colors.white
: Colors.white
.withOpacity(.7),
borderColor: Colors.grey,
showBorder: true,
child: Padding(
padding: EdgeInsets.fromLTRB(
25, 10, 25, 10),
child: Column(
children: <Widget>[
Image.asset(
'assets/images/login/102.png',
height: SizeConfig
.imageSizeMultiplier *
13,
width: SizeConfig
.imageSizeMultiplier *
16,
),
SizedBox(
height: 20,
),
AppText(
TranslationBase.of(
context)
.verifyFingerprint,
fontSize: SizeConfig
.textMultiplier *
2,
)
],
),
))))
],
)
: SizedBox(),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
@ -251,7 +268,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
]),
),
Expanded(
flex: 2,
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
@ -316,7 +333,50 @@ class _ConfirmLogin extends State<ConfirmLogin> {
type); //this.cs.sharedService.setStorage(this.selectedOption, AuthenticationService.LAST_LOGIN);
}
loginWithSMS(type, isActive) {}
loginWithSMS(type, isActive) {
//if (!el.disabled) {
if (this.user != null && this.registerd_data != null) {
this.checkUserAuthentication(type);
} else {
if (this.loginTokenID != null) {
this.sendActivationCode(type);
} else {
this.checkUserAuthentication(type);
}
}
}
checkUserAuthentication(type) {}
sendActivationCode(type) {
// const imeiData = this.cs.sharedService.getSharedData(AuthenticationService.IMEI_USER_DATA, false);
this.startSMSService(type);
return false;
var request = this.getCommonRequest();
this.authService.sendActivationCode(request).then((result) => {
if (result['isSMSSent'] == true)
{
// this.sharedService.setSharedData({
// MobileNumber: this.mobileNumber,
// loginType: type
// },
// CheckActivation.SHARED_DATA
// );
this.startSMSService(type)
}
});
}
startSMSService(type) {
new SMSOTP(
context,
type,
this.mobileNumber,
(value) => {this.checkActivationCode(value: value)},
() => {print('Faild..')}).displayDialog(context);
}
loginWithFingurePrintFace(type, isActive) async {
if (isActive == 1) {
// this.startBiometricLoginIfAvailable();
@ -334,41 +394,40 @@ class _ConfirmLogin extends State<ConfirmLogin> {
loginWithWhatsapp(type, isActive) {}
getMobileInfo(request) {
this
.authService
.getLoginInfo(request)
.then((GetMobileLoginInfoResponse result) => {
if (!result.sMSLoginRequired)
this.authService.getLoginInfo(request).then((result) => {
if (!result['SMSLoginRequired'])
{
this.loginTokenID = result.logInTokenID,
this.patientOutSA = result.patientOutSA,
// sms for register the biometric
if (result.isSMSSent)
{
this.loginTokenID = result.logInTokenID,
this.patientOutSA = result.patientOutSA,
// sms for register the biometric
if (result.isSMSSent)
{
this.onlySMSBox = false,
//this.button();
}
else
{
//this.checkActivationCode();
}
this.onlySMSBox = false,
//this.button();
}
else
{checkActivationCode()}
}
else
{
if (result['IsAuthenticated'])
{
if (result.isAuthenticated)
{
// this.onlySMSBox = false;
// this.cs.sharedService.setSharedData(true, AuthenticationService.ONLY_SMS);
// this.cs.sharedService.setSharedData(this.selectedOption, AuthenticationService.FINGUREPRINT_BEFORE);
// this.cs.confirmLogin();
// this.button();
}
else
{
// this.cs.presentAlert(result.ErrorEndUserMessage);
}
setState(() {
this.onlySMSBox = true;
}),
//sharedPref.setBool(ONLY_SMS, true),
// this.cs.sharedService.setSharedData(true, AuthenticationService.ONLY_SMS);
//this.cs.sharedService.setSharedData(this.selectedOption, AuthenticationService.FINGUREPRINT_BEFORE);
// this.cs.confirmLogin();
//this.button();
}
});
// else
// {
// // this.cs.presentAlert(result.ErrorEndUserMessage);
// }
}
});
}
setDefault() async {
@ -376,7 +435,9 @@ class _ConfirmLogin extends State<ConfirmLogin> {
// AuthenticationService.IMEI_USER_DATA,
// false
// );
this.registerd_data = await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN);
this.registerd_data = CheckPatientAuthenticationReq.fromJson(
await sharedPref.getObject(REGISTER_DATA_FOR_LOGIIN));
this.mobileNumber = this.registerd_data != null
? this.registerd_data.patientMobileNumber
: int.parse(this.user.Mobile);
@ -387,11 +448,11 @@ class _ConfirmLogin extends State<ConfirmLogin> {
? this.registerd_data.zipCode == "966" ? 0 : 1
: this.user.OutSA;
if (this.registerd_data != null) {
this.loginTokenID = sharedPref.getString(LOGIN_TOKEN_ID);
this.loginTokenID = await sharedPref.getString(LOGIN_TOKEN_ID);
this.loginType = this.registerd_data.searchType;
}
this.deviceToken = sharedPref.getString(PUSH_TOKEN);
this.lastLogin = sharedPref.getInt(
this.deviceToken = await sharedPref.getString(PUSH_TOKEN);
this.lastLogin = await sharedPref.getInt(
LAST_LOGIN); //this.cs.sharedService.getStorage(AuthenticationService.LAST_LOGIN);
}
@ -402,6 +463,7 @@ class _ConfirmLogin extends State<ConfirmLogin> {
request.deviceToken = this.deviceToken;
request.projectOutSA = this.patientOutSA;
request.loginType = this.selectedOption;
request.oTPSendType = this.selectedOption;
request.zipCode = this.zipCode;
request.isRegister = false;
request.logInTokenID = this.loginTokenID ?? "";
@ -422,4 +484,6 @@ class _ConfirmLogin extends State<ConfirmLogin> {
}
return request;
}
checkActivationCode({value}) {}
}

@ -44,19 +44,19 @@ class _Login extends State<Login> {
: SingleChildScrollView(
child: Container(
padding:
EdgeInsets.only(top: 10, left: 20, right: 20, bottom: 20),
EdgeInsets.only(top: 10, left: 20, right: 20, bottom: 30),
height: SizeConfig.realScreenHeight * .9,
width: SizeConfig.realScreenWidth,
child: Column(children: <Widget>[
Expanded(
flex: 1,
flex: 2,
child: AppText(
TranslationBase.of(context).enterNationalId,
fontSize: SizeConfig.textMultiplier * 3.5,
textAlign: TextAlign.left,
)),
Expanded(
flex: 2,
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[

@ -30,7 +30,7 @@ class _Register extends State<Register> {
isShowAppBar: true,
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(top: 10, left: 20, right: 20, bottom: 20),
padding: EdgeInsets.only(top: 10, left: 20, right: 20, bottom: 30),
height: SizeConfig.realScreenHeight * .9,
width: SizeConfig.realScreenWidth,
child: Column(children: <Widget>[

@ -18,7 +18,7 @@ class WelcomeLogin extends StatelessWidget {
child: Column(
children: <Widget>[
Expanded(
flex: 4,
flex: 6,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
@ -49,10 +49,10 @@ class WelcomeLogin extends StatelessWidget {
]),
),
Expanded(
flex: 1,
flex: 2,
child: Column(
// mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
//mainAxisAlignment: MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
children: <Widget>[

@ -19,6 +19,8 @@ const String SELECT_DEVICE_IMEI =
const String CHECK_PATIENT_AUTH =
'/Authentication.svc/REST/CheckPatientAuthentication';
const GET_MOBILE_INFO = '/Authentication.svc/REST/GetMobileLoginInfo';
const SEND_ACTIVATION_CODE =
'/Authentication.svc/REST/SendActivationCodebyOTPNotificationType';
class AuthProvider with ChangeNotifier {
bool isLogin = false;
@ -125,14 +127,15 @@ class AuthProvider with ChangeNotifier {
}
}
Future<GetMobileLoginInfoResponse> getLoginInfo(
GetMobileLoginInfoRequest request) async {
Future<dynamic> getLoginInfo(request) async {
request.versionID = VERSION_ID;
request.channel = CHANNEL;
request.iPAdress = IP_ADDRESS;
request.generalid = GENERAL_ID;
request.languageID = 2;
request.deviceTypeID = DeviceTypeID;
request.patientOutSA = request.zipCode == '966' ? 0 : 1;
request.isDentalAllowedBackend = false;
try {
dynamic localRes;
await new BaseAppClient().post(GET_MOBILE_INFO,
@ -147,4 +150,28 @@ class AuthProvider with ChangeNotifier {
throw error;
}
}
Future<dynamic> sendActivationCode(request) async {
request.versionID = VERSION_ID;
request.channel = CHANNEL;
request.iPAdress = IP_ADDRESS;
request.generalid = GENERAL_ID;
request.languageID = 2;
request.deviceTypeID = DeviceTypeID;
request.patientOutSA = request.zipCode == '966' ? 0 : 1;
request.isDentalAllowedBackend = false;
try {
dynamic localRes;
await new BaseAppClient().post(SEND_ACTIVATION_CODE,
onSuccess: (dynamic response, int statusCode) {
localRes = response;
}, onFailure: (String error, int statusCode) {
throw error;
}, body: request.toJson());
return Future.value(localRes);
} catch (error) {
print(error);
throw error;
}
}
}

@ -144,6 +144,8 @@ class TranslationBase {
String get lastLoginAt => localizedValues['last-login'][locale.languageCode];
String get lastLoginWith =>
localizedValues['last-login-with'][locale.languageCode];
String get verifyFingerprint2 =>
localizedValues['verify-fingerprint'][locale.languageCode];
}
class TranslationBaseDelegate extends LocalizationsDelegate<TranslationBase> {

@ -0,0 +1,208 @@
import 'package:diplomaticquarterapp/config/size_config.dart';
import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart';
import 'package:flutter/material.dart';
class SMSOTP {
final type;
final mobileNo;
final Function onSuccess;
final Function onFailure;
final context;
SMSOTP(
this.context, this.type, this.mobileNo, this.onSuccess, this.onFailure);
Map verifyAccountFormValue = {
'digit1': null,
'digit2': null,
'digit3': null,
'digit4': null,
};
final focusD1 = FocusNode();
final focusD2 = FocusNode();
final focusD3 = FocusNode();
final focusD4 = FocusNode();
displayDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () => {
Navigator.pop(context),
this.onSuccess(verifyAccountFormValue)
},
)
],
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0))),
content: Builder(builder: (context) {
return Container(
color: Colors.white,
height: SizeConfig.realScreenHeight * 0.5,
width: SizeConfig.realScreenWidth * 0.8,
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Image.asset('assets/images/login/103.png'),
Padding(
padding: EdgeInsets.only(top: 20),
child: AppText(
'Enter The Varification sent to XXXXXXX144',
textAlign: TextAlign.center,
)),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
width: SizeConfig.realScreenWidth * 0.15,
child: TextFormField(
textInputAction: TextInputAction.next,
style: buildTextStyle(),
autofocus: true,
maxLength: 1,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
decoration: buildInputDecoration(context),
onSaved: (val) {
verifyAccountFormValue['digit1'] = val;
},
validator: validateCodeDigit,
onFieldSubmitted: (_) {
FocusScope.of(context).requestFocus(focusD2);
},
onChanged: (val) {
if (val.length == 1) {
FocusScope.of(context)
.requestFocus(focusD2);
}
},
),
),
Container(
width: SizeConfig.realScreenWidth * 0.15,
child: TextFormField(
focusNode: focusD2,
textInputAction: TextInputAction.next,
maxLength: 1,
textAlign: TextAlign.center,
style: buildTextStyle(),
keyboardType: TextInputType.number,
decoration: buildInputDecoration(context),
onSaved: (val) {
verifyAccountFormValue['digit2'] = val;
},
onFieldSubmitted: (_) {
FocusScope.of(context)
.requestFocus(focusD3);
},
onChanged: (val) {
if (val.length == 1) {
FocusScope.of(context)
.requestFocus(focusD3);
}
},
validator: validateCodeDigit),
),
Container(
width: SizeConfig.realScreenWidth * 0.15,
child: TextFormField(
focusNode: focusD3,
textInputAction: TextInputAction.next,
maxLength: 1,
textAlign: TextAlign.center,
style: buildTextStyle(),
keyboardType: TextInputType.number,
decoration: buildInputDecoration(context),
onSaved: (val) {
verifyAccountFormValue['digit3'] = val;
},
onFieldSubmitted: (_) {
FocusScope.of(context)
.requestFocus(focusD4);
},
onChanged: (val) {
if (val.length == 1) {
FocusScope.of(context)
.requestFocus(focusD4);
}
},
validator: validateCodeDigit)),
Container(
width: SizeConfig.realScreenWidth * 0.15,
child: TextFormField(
focusNode: focusD4,
maxLength: 1,
textAlign: TextAlign.center,
style: buildTextStyle(),
keyboardType: TextInputType.number,
decoration: buildInputDecoration(context),
onSaved: (val) {
verifyAccountFormValue['digit4'] = val;
},
validator: validateCodeDigit))
],
))
],
)),
);
}),
// actions: <Widget>[
// new FlatButton(
// child: new Text('SUBMIT'),
// onPressed: () {
// Navigator.of(context).pop();
// },
// )
// ],
);
});
}
TextStyle buildTextStyle() {
return TextStyle(
fontSize: SizeConfig.textMultiplier * 3,
);
}
InputDecoration buildInputDecoration(BuildContext context) {
return InputDecoration(
// ts/images/password_icon.png
contentPadding: EdgeInsets.only(top: 20, bottom: 20),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderSide: BorderSide(color: Theme.of(context).primaryColor),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderSide: BorderSide(color: Theme.of(context).errorColor),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
borderSide: BorderSide(color: Theme.of(context).errorColor),
),
);
}
String validateCodeDigit(value) {
if (value.isEmpty) {
return 'Please enter your Password';
} else if (value.length == 3) {
print(value);
} else {
return null;
}
}
}
Loading…
Cancel
Save