Flutter Firebase auth phone and Firestore database - flutter

I would like when connecting by phone via OTP verification, to know if the account already exists and in this case retrieve its information. But if the account does not exist, create a collection in Firestore database with default information
My functional code for the telephone connection:
class AuthenticateScreen extends StatefulWidget {
#override
_AuthenticateScreenState createState() => _AuthenticateScreenState();
}
class _AuthenticateScreenState extends State<AuthenticateScreen> {
TextEditingController phoneController = TextEditingController();
TextEditingController otpController = TextEditingController();
FirebaseAuth auth = FirebaseAuth.instance;
bool otpVisibility = false;
User? user;
String verificationID = "";
String phoneNumber = "";
final DocumentReference documentReference =
FirebaseFirestore.instance.doc("users/{users}");
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Phone Auth",
style: TextStyle(
fontSize: 30,
),
),
backgroundColor: Colors.indigo[900],
),
body: Container(
margin: EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: phoneController,
decoration: InputDecoration(
hintText: 'Phone Number',
prefix: Padding(
padding: EdgeInsets.all(4),
child: Text('+33'),
),
),
maxLength: 10,
keyboardType: TextInputType.phone,
),
Visibility(
child: TextField(
controller: otpController,
decoration: InputDecoration(
hintText: 'OTP',
prefix: Padding(
padding: EdgeInsets.all(4),
child: Text(''),
),
),
maxLength: 6,
keyboardType: TextInputType.number,
),
visible: otpVisibility,
),
SizedBox(
height: 10,
),
MaterialButton(
color: Colors.indigo[900],
onPressed: () {
if (otpVisibility) {
verifyOTP();
} else {
loginWithPhone();
}
},
child: Text(
otpVisibility ? "Verify" : "Login",
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
],
),
),
);
}
void loginWithPhone() async {
auth.verifyPhoneNumber(
phoneNumber: "+33" + phoneController.text,
verificationCompleted: (PhoneAuthCredential credential) async {
await auth.signInWithCredential(credential).then((value) {
print("You are logged in successfully");
});
},
verificationFailed: (FirebaseAuthException e) {
print(e.message);
},
codeSent: (String verificationId, int? resendToken) {
otpVisibility = true;
verificationID = verificationId;
setState(() {});
},
codeAutoRetrievalTimeout: (String verificationId) {},
);
}
void verifyOTP() async {
PhoneAuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationID, smsCode: otpController.text);
await auth.signInWithCredential(credential).then(
(value) {
setState(() {
phoneNumber = phoneController.text;
print("Connecte avec le compte " + "+33" + phoneController.text,);
user = FirebaseAuth.instance.currentUser;
});
},
).whenComplete(
() {
if (user != null) {
Fluttertoast.showToast(
msg: "Vous êtes maintenant connecté",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Blue2Color,
textColor: Colors.white,
fontSize: 16.0,
);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home_Screen(),
),
);
} else {
Fluttertoast.showToast(
msg: "La connexion a échoué.",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0,
);
}
},
);
}
}
And here is my old code for login by mail to create a collection on firestore database :
class AuthenticationService {
final FirebaseAuth _auth = FirebaseAuth.instance;
AppUser? _userFromFirebaseUser(User? user) {
initUser(user);
return user != null ? AppUser(user.uid) : null;
}
void initUser(User? user) async {
if(user == null) return;
NotificationService.getToken().then((value) {
DatabaseService(user.uid).saveToken(value);
});
}
Stream<AppUser?> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result =
await _auth.signInWithEmailAndPassword(email: email, password: password);
User? user = result.user;
return _userFromFirebaseUser(user);
} catch (exception) {
print(exception.toString());
return null;
}
}

Related

how to hide email field when a user logged with phone authentication in flutter firebase?

i have an buying and selling app in which a user can sign up with different methods like google, phone authentication and email so my question is when a user log in with phone authentication how to hide the email field from user profile.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:mobihub_2/Screens/email_verifcation_screen.dart';
import 'package:mobihub_2/Screens/search_screens/search_filter.dart';
import '../../Models/user_model.dart';
import '../home_page.dart';
class ProfileDetailScreen extends StatefulWidget {
final String? name;
final String? email;
final String? location;
final String? gender;
final bool number;
const ProfileDetailScreen(
{Key? key, required this.name, this.email, this.location, required this.gender,required this.number})
: super(key: key);
#override
State<ProfileDetailScreen> createState() => _ProfileDetailScreenState();
}
class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
final _auth=FirebaseAuth.instance;
var collectionRef = FirebaseFirestore.instance.collection('UsersDetails');
var dropDownValue;
bool loading = false;
var name = TextEditingController();
var emailC = TextEditingController();
var passwordC =TextEditingController();
var city = TextEditingController();
#override
void initState() {
if (widget.location != null && widget.location!.isNotEmpty) {
setState(() {
city = TextEditingController(text: widget.location);
});
}
if (widget.name != null && widget.name!.isNotEmpty) {
setState(() {
name = TextEditingController(text: widget.name);
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
foregroundColor: Colors.blueGrey,
title: Text('Profile'),
elevation: 0,
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
TextFormField(
onChanged: (value) {
setState(() {
name = TextEditingController(text: (value));
});
},
initialValue: name.text,
decoration: InputDecoration(
hintText: 'Name',
prefixIcon: Icon(Icons.person_outline_outlined),
suffixIcon: Icon(Icons.edit_outlined),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
showDialog(context: context, builder: (context) {
return AlertDialog(
content: Text('Want to change your email?'),
actions: [
Padding(padding:EdgeInsets.all(10),
child: Column(
children: [
TextFormField(
controller:emailC,
decoration: InputDecoration(
hintText: 'new email',
prefixIcon: Icon(Icons.email_outlined),
),
),
SizedBox(height: 10,),
TextFormField(
controller: passwordC,
decoration: InputDecoration(
hintText: 'old Password',
prefixIcon: Icon(Icons.lock_open_outlined),
),
),
SizedBox(height: 5,),
ElevatedButton(onPressed: ()async{
loading=true;
await changeEmail(
email: emailC.text,password: passwordC.text
);
loading=false;
}, child:loading?Center(child: CircularProgressIndicator(color:Colors.black,),): Text('Submit'))
],
),
)
],
);
}
);
},
readOnly: true,
initialValue: widget.email,
// onChanged: (value) {
// setState(() {
// email = value;
// });
// },
decoration: InputDecoration(
hintText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
readOnly: true,
initialValue: widget.number.toString(),
decoration: InputDecoration(
hintText: 'Phone number',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
setState(() async {
city.text = await Navigator.push(context,
MaterialPageRoute(builder: (_) => SearchScreen()));
});
},
readOnly: true,
controller: city,
decoration: InputDecoration(
hintText: 'Address',
prefixIcon: Icon(Icons.location_city_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.arrow_drop_down_circle_outlined)),
),
),
SizedBox(
height: 20,
),
DropdownButtonFormField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person,),
),
hint: Text(widget.gender!.isNotEmpty
? widget.gender!
: 'Select Gender'),
items: ['Male', 'Female'].map(
(val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val),
);
},
).toList(), onChanged: (String? val) {
setState(
() {
dropDownValue = val;
},
);
},),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
OutlinedButton(onPressed: () {}, child: Text('Cancel')),
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Colors.amberAccent),
onPressed: () async {
setState(() {
loading = true;
});
await postDetailsToFirestore();
setState(() {
loading = false;
});
},
child: loading
? Center(
child: CircularProgressIndicator(color: Colors.blue,))
: Text('Save')),
],
),
],
),
),
),
);
}
Future<void> changeEmail(
{required String email, required String password}) async {
//showLoadingDialog(message: AppTexts.updating);
try {
User user = _auth.currentUser!;
DocumentReference ref=collectionRef.doc(user.uid);
final cred =
EmailAuthProvider.credential(email: user.email!, password: passwordC.text);
user.reauthenticateWithCredential(cred).then((value) {
user.updateEmail(email).then((_) async {
await ref.update({'email': email}).then((value) async {
// go to root page
await _auth.currentUser!.sendEmailVerification();
Fluttertoast.showToast(msg: 'Verification Email has been sent to you');
await _auth.signOut();
});
setState(() {
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_)=>VerificationScreen()), (route) => false);
});
}).catchError((error) {
Fluttertoast.showToast(msg: error.toString());
});
}).catchError((err) {
Fluttertoast.showToast(msg: err.toString());
});
} on Exception catch (err) {
Fluttertoast.showToast(msg: err.toString());
// showErrorDialog(err.toString());
}
}
postDetailsToFirestore() async {
var auth = FirebaseAuth.instance;
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = auth.currentUser;
UserModel userModel = UserModel();
// writing all the values
userModel.email = user!.email;
userModel.uid = user.uid;
userModel.fullName = name.text;
userModel.phone = user.phoneNumber;
userModel.location = city.text;
userModel.joindate = '';
userModel.gender = dropDownValue;
await firebaseFirestore
.collection("UsersDetails")
.doc(user.uid)
.update(userModel.toMap());
Fluttertoast.showToast(msg: "Account Updated successfully :) ");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => const Home()),
(route) => false);
}
}
when a user login with email the phone field will hide and when user login with phone the email field will hide. If anybody can help me it would be very appreciable.Thank you

State not triggering while clicking login button

Every thing is working fine except that the page is not navigating while I press login button. The user is logged in and The screen is changing once I reload it. But the screen has to change when I click the login button. I used the setState fuction But still not working.Please help me solve this. Thanks in advance.
This is my root page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
class Root extends StatefulWidget {
const Root({Key? key}) : super(key: key);
#override
State<Root> createState() => _RootState();
}
enum AuthState { signedIn, signedOut }
class _RootState extends State<Root> {
AuthState _authState = AuthState.signedOut;
AuthService auth = AuthService();
String authuser = "ghnfgjy";
void signOut() async {
await auth.signOut();
setState(() {
_authState = AuthState.signedOut;
});
}
void signIn() async {
setState(() {
_authState = AuthState.signedIn;
});
}
#override
void initState() {
super.initState();
auth.currentUser().then((user) {
print("check check $user ");
setState(() {
_authState = user == null ? AuthState.signedOut : AuthState.signedIn;
});
});
}
#override
Widget build(BuildContext context) {
if (_authState == AuthState.signedOut) {
return Login();
} else {
return Scaffold(
body: Center(
child: Column(
children: [
SizedBox(
height: 69,
),
Text("Helllloooooooo $authuser"),
SizedBox(
height: 45,
),
FlatButton(
onPressed: () {
signOut();
},
child: Text("Sign out"))
],
),
));
}
}
}
This is my login.dart page
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:login/main.dart';
import 'package:login/services/auth_service.dart';
import 'package:login/share/constant.dart';
class Login extends StatefulWidget {
const Login({Key? key}) : super(key: key);
#override
_LoginState createState() => _LoginState();
}
enum FormType {
login,
register,
}
class _LoginState extends State<Login> {
dynamic _email;
dynamic _password;
final formkey = GlobalKey<FormState>();
FormType _formType = FormType.login;
dynamic result;
AuthService auth = AuthService();
bool validateandsave() {
final form = formkey.currentState;
if (form!.validate()) {
form.save();
print('form is valid');
print('$_email $_password');
return true;
} else {
print('form is not valid');
return false;
}
}
Future validateandsumit() async {
if (validateandsave()) {
if (_formType == FormType.register) {
auth.register(_email, _password);
setState(() {
_formType = FormType.login;
});
} else {
auth.signIn(_email, _password);
}
}
}
void moveToRegister() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.register;
});
}
void moveToLogin() {
formkey.currentState!.reset();
setState(() {
_formType = FormType.login;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
decoration: BoxDecoration(
gradient: const LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [
Colors.blueAccent,
Colors.purple,
],
),
),
padding: EdgeInsets.all(16),
child: Form(
key: formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: openText() + inputFields() + buttons(),
),
),
),
);
}
List<Widget> openText() {
if (_formType == FormType.register) {
return [
Text(
'Please Register to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
SizedBox(
height: 40,
),
];
} else {
return [
Text('Please Login to continue',
style: TextStyle(
fontSize: 35, color: Colors.white, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
SizedBox(
height: 40,
),
];
}
}
List<Widget> inputFields() {
return [
TextFormField(
decoration: inputDecoration.copyWith(
labelText: 'Email Address',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the email address' : null,
onSaved: (val) => _email = val),
SizedBox(
height: 20,
),
TextFormField(
obscureText: true,
decoration: inputDecoration.copyWith(
labelText: 'Password',
),
style: TextStyle(color: Colors.black),
validator: (val) => val!.isEmpty ? 'Enter the password' : null,
onSaved: (val) => _password = val),
SizedBox(
height: 60,
),
];
}
List<Widget> buttons() {
if (_formType == FormType.register) {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToLogin,
child: Text(
'Have an account? Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
} else {
return [
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: validateandsumit,
child: Text(
'Login',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
SizedBox(
height: 20,
),
FlatButton(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 60),
onPressed: moveToRegister,
child: Text(
'Register',
style: TextStyle(fontSize: 20, color: Colors.white),
),
color: Colors.pinkAccent,
),
];
}
}
}
This is my authservice file
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
//Stream <User>? get authStateChanges => _auth.authStateChanges();
Stream<User?> get authStateChanges => _auth.authStateChanges();
CollectionReference users = FirebaseFirestore.instance.collection('users');
late User user;
//register in with email and password
Future register(email, password) async {
try {
UserCredential userCredential = await _auth
.createUserWithEmailAndPassword(email: email, password: password);
user = userCredential.user!;
print('Registered ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
//sign in with email and password
Future signIn(email, password) async {
try {
UserCredential userCredential = await _auth.signInWithEmailAndPassword(
email: email, password: password);
user = userCredential.user!;
print('logged in ${user.uid}');
var userdata = {
'email': email,
'password': password,
'role': 'user',
};
users.doc(user.uid).get().then((doc) {
if (doc.exists) {
doc.reference.update(userdata);
} else {
users.doc(user.uid).set(userdata);
}
});
} catch (e) {
print(e);
}
}
Future currentUser() async {
try {
User user = await _auth.currentUser!;
return user.uid;
} catch (e) {
print(e);
}
}
//sign out
Future signOut() async {
try {
await _auth.signOut();
} catch (e) {
print(e);
}
}
}
I think the problem is that the build function in _RootState does not rebuild when you login.
One possible solution is to use StreamBuilder to rebuild whenever auth changes (login/logout).
Add this function to your AuthService class:
class AuthService {
final _auth = FirebaseAuth.instance;
...
Stream<User?> authStream() => _auth.authStateChanges(); // add this line
}
Then write your build function (in _RootState) as below:
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: auth.authStream(), // auth here is AuthService.
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
// StreamBuilder will automatically rebuild anytime you log in or log
// logout. No need for your initState or signout & signin functions.
if (snapshot.hasError) return const Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.data == null) return Login();
// snapshot.data is User.
// print(snapshot.data?.email); print(snapshot.data?.displayName);
return Scaffold(
body: Center(
child: Column(
children: [
const SizedBox(height: 69),
Text('Hello ${snapshot.data?.email}'),
const SizedBox(height: 45),
FlatButton(
onPressed: () async {
// no need to call sign out here.
await auth.signOut();
},
child: const Text('Sign out'),
)
],
),
),
);
},
);
// you can delete your initState, signin and signout functions in _RootState

I don't get the OTP with this error messsage: I/flutter ( 4095): Pinput: App Signature for SMS Retriever API Is: zkeJurf+MDa

I have been trying to add firebase phone number authentication but the android device is not receiving the firebase OTP. I have already added the SHA1 and SHA2 fingerprints to firebase project and redownloaded the google services.json file and also enabled android device properties in Google cloud platform. Below is my code.
class OtpControllerScreen extends StatefulWidget {
final String phone;
final String codeDigits;
const OtpControllerScreen({required this.phone, required this.codeDigits});
#override
State<OtpControllerScreen> createState() => _OtpControllerScreenState();
}
class _OtpControllerScreenState extends State<OtpControllerScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final TextEditingController _editingController = TextEditingController();
final FocusNode _pinCodeFocus = FocusNode();
String? verificationCode;
#override
void initState() {
super.initState();
verifyPhoneNumber();
}
verifyPhoneNumber() async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: widget.codeDigits + widget.phone,
verificationCompleted: (PhoneAuthCredential credential) async {
await FirebaseAuth.instance
.signInWithCredential(credential)
.then((value) {
if (value.user != null) {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return const HomePage();
}));
}
});
},
verificationFailed: (FirebaseAuthException error) {
Fluttertoast.showToast(msg: error.toString());
},
codeSent: (String verifyId, int? resendToken) {
setState(() {
verifyId = verificationCode!;
});
},
codeAutoRetrievalTimeout: (String verifyId) {
setState(() {
verifyId = verificationCode!;
});
},
timeout: const Duration(seconds: 90));
// ignore: avoid_print
print(verificationCode);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
key: _scaffoldKey,
appBar: AppBar(
centerTitle: true,
backgroundColor: const Color.fromARGB(255, 207, 19, 5),
title: const Text(
'OTP Verification',
style: TextStyle(fontSize: 25),
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Logo(width: 250, height: 250, radius: 100),
Container(
margin: const EdgeInsets.only(top: 40),
child: GestureDetector(
onDoubleTap: () {
verifyPhoneNumber();
},
child: Text("Verifying: ${widget.codeDigits} -${widget.phone}",
style: const TextStyle(
fontSize: 25,
fontWeight: FontWeight.w600,
color: Colors.black)),
),
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Pinput(
focusNode: _pinCodeFocus,
controller: _editingController,
defaultPinTheme: PinTheme(
width: 56,
height: 56,
textStyle: const TextStyle(
fontSize: 25,
color: Colors.black,
fontWeight: FontWeight.w600),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: const Color.fromARGB(255, 207, 19, 5)),
),
),
onSubmitted: (pin) async {
try {
await FirebaseAuth.instance
.signInWithCredential(PhoneAuthProvider.credential(
verificationId: verificationCode!, smsCode: pin))
.then((value) {
if (value.user != null) {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return const HomePage();
}));
}
});
} catch (e) {
Fluttertoast.showToast(
toastLength: Toast.LENGTH_LONG,
msg: e.toString(),
);
}
},
pinAnimationType: PinAnimationType.fade,
length: 6,
androidSmsAutofillMethod:
AndroidSmsAutofillMethod.smsRetrieverApi,
),
),
],
),
),
);
}
}

Is it possible to POST Data using localhost woocommerce rest api in flutter

Is it possible to POST data from flutter app to woocommerce localhost using woocommerce localhost server rest api.
i have GET & POST data with private domain but i want to POST & GET data with localhost woocommerce rest api. i have setup my wordpress and woocommerce on localhost I am trying to make flutter ecommerce app and trying to GET & POST data from woocommerce localhost. but its not working and i dont want to send from private domain rest api, i can get data on postman if i select OAuth 1.0 but if i dont use OAuth 1.0 i cant get data.
Config.dart
class Config {
static String key =
'ck_00000000000000000000000000';
static String sceret =
'cs_00000000000000000000000000';
static String url = 'http://10.0.2.2:80/wordpress_new/wp-json/wc/v3/';
static String customerURL = 'customers';
}
customer.dart
class CustomerModel {
String email;
String firstName;
String lastName;
String password;
CustomerModel({
this.email,
this.firstName,
this.lastName,
this.password,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {};
map.addAll({
'email': email,
'first_name': firstName,
'last_name': lastName,
'password': password,
'username': email,
});
return map;
}
}
apiservice.dart
class APIService {
Future<bool> createCustomer(CustomerModel model) async {
var authToken = base64.encode(
utf8.encode(Config.key + ':' + Config.sceret),
);
bool ret = false;
try {
var response = await Dio().post(
Config.url +
Config.customerURL,
data: model.toJson(),
options: new Options(headers: {
HttpHeaders.authorizationHeader: 'Basic $authToken',
HttpHeaders.contentTypeHeader: 'application/json',
}));
if (response.statusCode == 201) {
ret = true;
}
} on DioError catch (e) {
if (e.response.statusCode == 404) {
print(e.response.statusCode);
ret = false;
} else {
print(e.message);
print(e.request);
ret = false;
}
}
return ret;
}
Future<LoginResponseModel> loginCustomer(
String username,
String password,
) async {
LoginResponseModel model;
try {
var response = await Dio().post(Config.tokenURL,
data: {
'username': username,
'password': password,
},
options: new Options(headers: {
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
}));
if (response.statusCode == 200) {
model = LoginResponseModel.fromJson(response.data);
}
} on DioError catch (e) {
print(e.message);
}
return model;
}
}
signuppage.dart
class SignupPage extends StatefulWidget {
#override
_SignupPageState createState() => _SignupPageState();
}
class _SignupPageState extends State<SignupPage> {
APIService apiService;
CustomerModel model;
GlobalKey<FormState> globalKey = GlobalKey<FormState>();
bool hidePassword = true;
bool isApiCallProcess = false;
#override
void initState() {
apiService = new APIService();
model = new CustomerModel();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
automaticallyImplyLeading: true,
title: Text('Sign Up'),
),
body: ProgressHUD(
child: Form(
key: globalKey,
child: _formUI(),
),
inAsyncCall: isApiCallProcess,
opacity: 0.3),
);
}
Widget _formUI() {
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(10.00),
child: Container(
child: Align(
alignment: Alignment.topLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FormHelper.fieldLabel('First Name'),
FormHelper.textInput(
context,
model.firstName,
(value) => {
this.model.firstName = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter First Name.';
}
return null;
},
),
FormHelper.fieldLabel('Last Name'),
FormHelper.textInput(
context,
model.lastName,
(value) => {
this.model.lastName = value,
},
onValidate: (value) {
return null;
},
),
FormHelper.fieldLabel('Email Id'),
FormHelper.textInput(
context,
model.email,
(value) => {
this.model.email = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Email id.';
}
if (value.isNotEmpty && !value.toString().isValidEmail()) {
return 'Please enter valid email id';
}
},
),
FormHelper.fieldLabel('Password'),
FormHelper.textInput(
context,
model.password,
(value) => {
this.model.password = value,
},
onValidate: (value) {
if (value.toString().isEmpty) {
return 'Please enter Password.';
}
return null;
},
obscureText: hidePassword,
suffixIcon: IconButton(
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
color: Theme.of(context).accentColor.withOpacity(0.4),
icon: Icon(
hidePassword ? Icons.visibility_off : Icons.visibility,
),
),
),
SizedBox(
height: 20,
),
Center(
child: FormHelper.saveButton(
'Register',
() {
if (validateAndSave()) {
print(model.toJson());
setState(() {
isApiCallProcess = true;
});
apiService.createCustomer(model).then(
(ret) {
setState(() {
isApiCallProcess = false;
});
if (ret) {
FormHelper.showMessage(
context,
'WooCommerce App',
'Registration Successfull',
'Ok',
() {
Navigator.of(context).pop();
},
);
} else {
FormHelper.showMessage(
context,
'WooCommerce App',
'Email Id already registered.',
'Ok',
() {
Navigator.of(context).pop();
},
);
}
},
);
}
},
),
)
],
),
),
),
),
);
}
bool validateAndSave() {
final form = globalKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
}
form_helper.dart
class FormHelper {
static Widget textInput(
BuildContext context,
Object initialValue,
Function onChanged, {
bool isTextArea = false,
bool isNumberInput = false,
obscureText: false,
Function onValidate,
Widget prefixIcon,
Widget suffixIcon,
}) {
return TextFormField(
initialValue: initialValue != null ? initialValue.toString() : "",
decoration: fieldDecoration(
context,
"",
"",
suffixIcon: suffixIcon,
),
obscureText: obscureText,
maxLines: !isTextArea ? 1 : 3,
keyboardType: isNumberInput ? TextInputType.number : TextInputType.text,
onChanged: (String value) {
return onChanged(value);
},
validator: (value) {
return onValidate(value);
},
);
}
static InputDecoration fieldDecoration(
BuildContext context,
String hintText,
String helperText, {
Widget prefixIcon,
Widget suffixIcon,
}) {
return InputDecoration(
contentPadding: EdgeInsets.all(6),
hintText: hintText,
helperText: helperText,
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
width: 1,
),
),
);
}
static Widget fieldLabel(String labelName) {
return new Padding(
padding: EdgeInsets.fromLTRB(0, 5, 0, 10),
child: Text(
labelName,
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
);
}
static Widget saveButton(String buttonText, Function onTap,
{String color, String textColor, bool fullWidth}) {
return Container(
height: 50.0,
width: 150,
child: GestureDetector(
onTap: () {
onTap();
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.redAccent,
style: BorderStyle.solid,
width: 1.0,
),
color: Colors.redAccent,
borderRadius: BorderRadius.circular(30.0),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(
buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
letterSpacing: 1,
),
),
),
],
),
),
),
);
}
static void showMessage(
BuildContext context,
String title,
String message,
String buttonText,
Function onPressed,
) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text(title),
content: new Text(message),
actions: [
new FlatButton(
onPressed: () {
return onPressed();
},
child: new Text(buttonText),
)
],
);
},
);
}
}
progressHUD.dart
class ProgressHUD extends StatelessWidget {
final Widget child;
final bool inAsyncCall;
final double opacity;
final Color color;
final Animation<Color> valueColor;
ProgressHUD({
Key key,
#required this.child,
#required this.inAsyncCall,
this.opacity = 0.3,
this.color = Colors.grey,
this.valueColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
List<Widget> widgetList = new List<Widget>();
widgetList.add(child);
if (inAsyncCall) {
final modal = new Stack(
children: [
new Opacity(
opacity: opacity,
child: ModalBarrier(dismissible: false, color: color),
),
new Center(child: new CircularProgressIndicator()),
],
);
widgetList.add(modal);
}
return Stack(
children: widgetList,
);
}
}

Authentication for only first time in a flutter app using phone number

I am new to mobile app development. I am trying to build an app that requires users to register with phone number. I am doing the authentication using Firebase. I have been able to register user with phone number. But, i want app to register user for the first time and upon further loading, homepage should be displayed. Also if the user changes his phone number in the mobile device then he should be again required to register with new phone number.
I have tried something here...
class _State extends State<MyAppPage> {
String phoneNo;
String smsOTP;
String verificationId;
String errorMessage = '';
FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> verifyPhone() async {
final PhoneCodeSent smsOTPSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsOTPDialog(context).then((value) {
print('Sign in');
});
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: this.phoneNo,
timeout: const Duration(seconds:20),
verificationCompleted: (AuthCredential phoneAuthCredential) {
print(phoneAuthCredential);
},
verificationFailed: (AuthException exceptio) {
print('${exceptio.message}');
},
codeSent: smsOTPSent,
codeAutoRetrievalTimeout: (String verId) {
this.verificationId = verId;
});
} catch(e) {
handleError(e);
}
}
Future<bool> smsOTPDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return new AlertDialog(
title: Text('Enter SMS Code'),
content: Container(
height: 85,
child: Column(children: [
TextField(
onChanged: (value) {
this.smsOTP = value;
},
),
(errorMessage != ''
? Text(
errorMessage,
style: TextStyle(color: Colors.red),
)
: Container()
)
]),
),
contentPadding: EdgeInsets.all(10),
actions: <Widget>[
FlatButton(
child: Text('Done'),
onPressed: () {
_auth.currentUser().then((user) {
if(user != null) {
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/homepage');
}
else {
signIn();
}
});
},
)
],
);
}
);
}
signIn() async {
try {
final AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsOTP,
);
final FirebaseUser user = (await _auth.signInWithCredential(credential)).user;
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/homepage');
}
catch (e) {
handleError(e);
}
}
handleError(PlatformException error) {
print(error);
switch (error.code) {
case 'ERROR_INVALID_VERIFICATION_CODE':
FocusScope.of(context).requestFocus(new FocusNode());
setState(() {
errorMessage = 'Invalid Code';
});
Navigator.of(context).pop();
smsOTPDialog(context).then((value) {
print('Sign In');
});
break;
default:
setState(() {
errorMessage = error.message;
});
break;
}
}
The UI is as follows..
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Phone Authentication'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(10),
child: TextField(
decoration: InputDecoration(
hintText: 'Enter Phone Number Eg. +910000000000'),
onChanged: (value) {
this.phoneNo = value;
},
),
),
(errorMessage != ''
? Text(
errorMessage,
style: TextStyle(color: Colors.red),
)
: Container()),
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
verifyPhone();
},
child: Text('Verify'),
textColor: Colors.white,
elevation: 7,
color: Colors.blue,
)
],
),
),
);
}
The problem is that firebase authenticated new user for the first time using phone number in the device, but it again asked for phone number when reopening app. Also on providing phone number firebase did not send OTP as user is already authenticated.
I will be grateful for your help. Thanks in advance..