cannot navigate form login screen to bottom_tab_screen with provider - flutter

I'm trying to navigate from login screen to the bottom tab screen but nothing happen and now i have no error
it is the main
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: UserProvider()),
ChangeNotifierProvider.value(value: AppProvider()),
],
child:MaterialApp(
key: key,
title: 'Voyager',
debugShowCheckedModeBanner: false,
theme: AppTheme.getTheme(),
routes: routes,
),
);
}
my dialog which has two cases if success or fail to login or sign up
import 'package:flutter/material.dart';
class Dialogs {
static showErrorDialog(BuildContext context,
{#required String message, #required int code}) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Ok'),
)
],
title: Text('error $code'),
content: Text(message),
backgroundColor: Colors.white,
);
},
);
}
}
my login method and it depend on user api provider
signIn() async {
var res = await userProvider.login(
_userNameController.text, _passwordController.text);
if (res is FailedRequest) {
Dialogs.showErrorDialog(widget._context , message: res.message, code: res.code);
print('results ${res.toString()}');
} else {
print("Signing in success");
Navigator.pushReplacement(
widget._context, MaterialPageRoute(builder: (context) => BottomTabScreen()));
}
userProvider.isLoading = false;
}
and the api provider which use in the login
Future<dynamic> login(String email, String password) async {
final Map<String, dynamic> body = {'email': email, 'password': password};
_isLoading = true;
notifyListeners();
print('Starting request');
http.Response response = await http.post(Environment.userLogin,
body: json.encode(body), headers: Environment.requestHeader);
print('Completed request');
print('user login response : ${response.body}');
Map<String, dynamic> res = json.decode(response.body);
var results;
if (res['code'] == 200) {
// login successful
_user = User.fromJson(res['message']);
results = true;
} else {
// login failed;
results =
FailedRequest(code: 400, message: res['error'], status: false);
}
_isLoading = false;
notifyListeners();
return results;
}
finally the failed request class if request not done
import 'package:flutter/foundation.dart';
class FailedRequest {
String message;
int code;
bool status;
FailedRequest({
#required this.message,
#required this.code,
#required this.status,
});
}

The Issue seems to be with the res['error'] can you verify that the field error actually exists and is not null.
At this block can you print the value of res['error']
else {
print(res['error']);
// login failed;
results =
FailedRequest(code: 400, message: res['error'], status: false);
}

Related

How to fix eternal loading when fetching data in flutter?

I am trying to make sign in in dart using cubit/bloc.
And when I try to change state of my cubit(auth) to Waiting => CircularProgressIndicator
Then my app is getting stuck when api returns statusCode == 400 and I call another emit to show dialog window
But if sign in is successful(statusCode == 200) then everything is ok, and I navigate to main_page.dart
How to fix this problem and transfer data reponse from api to widget(I want to send statusCode and message to widget)
My cubit file:
class AuthCubit extends Cubit<AuthState> {
AuthCubit() : super(AuthState(
email: "",
password: "",
));
final ApiService _apiService = ApiService();
void setEmail(String email) => emit(state.copyWith(email: email));
void setPassword(String password) => emit(state.copyWith(password: password));
Future signIn() async {
emit(WaitingSignInAuth(state.email, state.password));
try {
final data = await _apiService.signIn(
email: state.email ?? "",
password: state.password ?? ""
);
if (data['success']) {
print(data);
emit(const SuccessAutentification());
}
} on DioError catch (ex) {
print(ex.toString());
//I want to transfer to ErrorSignInAuth ex.response!.data['message'] but I don't know how
emit(ErrorSignInAuth(state.email, state.password));
} catch (e) {
print(e);
}
}
}
This is my state file:
class AuthState extends Equatable {
final String? email;
final String? password;
const AuthState({
this.email,
this.password,
});
AuthState copyWith({
String? email,
String? password,
}) {
return AuthState(
email: email ?? this.email,
password: password ?? this.password,
);
}
#override
List<Object?> get props =>
[email, password];
}
class SuccessAutentification extends AuthState {
const SuccessAutentification() : super();
}
class WaitingSignInAuth extends AuthState {
const WaitingSignInAuth(email, password) : super(email: email, password: password);
}
class ErrorSignInAuth extends AuthState {
const ErrorSignInAuth(email, password) : super(email: email, password: password);
}
And this is the widget where I use this cubit:
#override
Widget build(BuildContext context) {
return BlocConsumer<AuthCubit, AuthState>(
listener: (context, state) {
if (state is WaitingSignInAuth) {
showDialog(
context: context,
builder: (context) => Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.black.withOpacity(0.6),
child: const Center(
child: CircularProgressIndicator(
strokeWidth: 1,
color: Colors.black,
backgroundColor: Colors.white,
),
),
));
}
if (state is SuccessAutentification) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (_) => const MainWidget(),
),
);
}
if (state is ErrorAuthentification) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Bad request"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text("Error") // I want to show here error message
],
),
),
actions: <Widget>[
TextButton(
child: const Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}
);
}
},
builder: (context, state) {
return Scaffold(
LoginButton(
color: _isValid ? AppColors.white : AppColors.whiteA3A3A3,
text: "Login in",
textColor: Colors.black,
isButtonDisabled: _isValid ? false : true,
onPressed: () {
if (_key.currentState!.validate()) {
BlocProvider.of<AuthCubit>(context).setEmail(_email.text.trim());
BlocProvider.of<AuthCubit>(context).setPassword(_password.text.trim());
BlocProvider.of<AuthCubit>(context).signIn();
_key.currentState!.save();
}
},
)
);
},
);
}
In signIn() function, after you emit WaitingSignInAuth state, in some cases you are not emitting any other state, so your page is always loading.
Future signIn() async {
emit(WaitingSignInAuth(state.email, state.password));
try {
final data = await _apiService.signIn(
email: state.email ?? "",
password: state.password ?? ""
);
if (data['success']) {
print(data);
emit(const SuccessAutentification());
} else {
// emit state
emit(ErrorSignInAuth(state.email, state.password));
}
} on DioError catch (ex) {
print(ex.toString());
emit(ErrorSignInAuth(state.email, state.password));
} catch (e) {
print(e);
// emit state
emit(ErrorSignInAuth(state.email, state.password));
}
}

Consumer widget is not listening to update

I am not Abel to listen changes in my main.dart file while I am using consumer widget basically I am trying to login and save accessToken in variable and I want to redirect to home page from routes when it is true
following is mine main.dart file
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => UserBookings(),
),
ChangeNotifierProvider(
create: (context) => AuthenticationDetails(),
),
ChangeNotifierProvider(create: (context) => FetchPlaces()),
ChangeNotifierProvider(
create: (context) => Authclass(),
),
],
child: Consumer<AuthenticationDetails>(
builder: (context, value, _) => MaterialApp(
primarySwatch: Colors.red,
),
home: value.isAuth ? PrepareRide() : Otp(),
routes: {
'verifyotp': (context) =>
value.isAuth ? const PrepareRide() : const VerifyOtp(),
'mapview': (context) => const PrepareRide(),
},
following is my login class
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'cabapi.dart';
class AuthenticationDetails extends ChangeNotifier {
int? sessionId;
String? acessToken;
DateTime? acessTokenExpiryDate;
String? refreshToken;
DateTime? refreshTokenExpiryDate;
bool get isAuth {
return token != null;
}
String? get token {
if (acessTokenExpiryDate != null &&
acessTokenExpiryDate!.isAfter(DateTime.now()) &&
acessToken != null) {
return acessToken;
}
return null;
}
bool get refresh {
return refreshtoken != null;
}
String? get refreshtoken {
if (refreshTokenExpiryDate != null &&
refreshTokenExpiryDate!.isAfter(DateTime.now()) &&
refreshToken != null) {
return acessToken;
}
return null;
}
Future<void> registerUser(String? phoneNumber, BuildContext context) async {
final url = Ninecabsapi().urlHost + Ninecabsapi().login;
try {
var response = await http.post(Uri.parse(url),
headers: {'Content-Type': 'application/json; charset=UTF-8'},
body: json.encode({'mobileno': phoneNumber}));
var userDetails = json.decode(response.body);
//print(userDetails);
// switch (response.statusCode) {
// case 201:
// print(acessToken);
// //showsnackbar(context, "logged in");
// break;
// }
sessionId = userDetails['data']['session_id'];
acessToken = userDetails['data']['access_token'];
acessTokenExpiryDate = DateTime.now().add(
Duration(seconds: userDetails['data']['access_token_expires_in']),
);
refreshToken = userDetails['data']['refresh_token'];
refreshTokenExpiryDate = DateTime.now().add(
Duration(seconds: userDetails['data']['refresh_token_expires_in']),
);
print(isAuth);
notifyListeners();
} catch (e) {
print(e);
}
}
}
I am getting response and storing data in variables but not Abel to listen data can any one help me please
you can see here consumer is not listening to my listeners when auth is true

How to print error message from Backend in Flutter

Error message from backend appears in flutter terminal. How can I print this on the app?
I/flutter (16113): {"status":"Fail","error":{"code":1138,"message":"Kullanıcı zaten mevcut"}}
Service
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
throw Exception(response.body);
}
}
}
Res Model
class RegisterResModel {
String? message;
String? status;
RegisterResModel({this.message, this.status});
RegisterResModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
You need to add one class to store the error details.
class ErrorModel{
String? message;
int? code;
ErrorModel({this.message, this.code});
ErrorModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
code = json['code'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['code'] = code;
return data;
}
}
You can add this model to your own Register class.
class RegisterResModel {
String? message;
String? status;
ErrorModel? error;
RegisterResModel({this.message, this.status, this.error});
fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
error = ErrorModel.fromJson(json['error']);
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
similar to you have parse the response, you can now get the error information as well. Please check sample code as below.
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
return RegisterResModel.fromJson(json.decode(response.body));
}
}
}
Now you can return register class and check for status fail or pass based on the response and show the error.
To show the error, there are multiple options like Show Alert dialog, Show snackbar. Those are listed as below
Alert dialog:
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Snackbar :
import 'package:flutter/material.dart';
void main() => runApp(const SnackBarDemo());
class SnackBarDemo extends StatelessWidget {
const SnackBarDemo({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SnackBar Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('SnackBar Demo'),
),
body: const SnackBarPage(),
),
);
}
}
class SnackBarPage extends StatelessWidget {
const SnackBarPage({super.key});
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
final snackBar = SnackBar(
content: const Text('Yay! A SnackBar!'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
// Some code to undo the change.
},
),
);
// Find the ScaffoldMessenger in the widget tree
// and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: const Text('Show SnackBar'),
),
);
}
}
You can wrap your main code in try catch block and incase it shows an exception/error, you can show a toast or snackBar to show the message.
Learn more about-
Try-catch block
toast messages
snackbar messages
You could use an Alert Dialog to ensure that the error is seen and acknowledged for whatever reason you're doing this.

How to replace "notifyListeners()" with "update()" using GetX in Flutter?

I am trying to modify the following code that uses stateful widgets and provider package to use GetX package and stateless widgets instead. In a part of code it specifies if the user is authenticated or not to show the home or auth screen. This is the auth_controller.dart code:
class Auth with ChangeNotifier {
String? _token;
DateTime? _expiryDate;
String? _userId;
Timer? _authTimer;
bool get isAuth {
return token != null;
}
String? get token {
if (_expiryDate != null &&
_expiryDate!.isAfter(DateTime.now()) &&
_token != null) {
return _token;
}
return null;
}
String? get userId {
return _userId;
}
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final host = Platform.isAndroid ? '10.0.2.2' : '127.0.0.1';
final url = Uri.parse('http://$host:8080/api/$urlSegment');
// final url = Uri.parse('http://10.0.2.2:8000/api/$urlSegment');
// final url = Uri.parse('http://127.0.0.1:8000/api/$urlSegment');
try {
final http.Response response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: json.encode(
{
'email': email,
'password': password,
//'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if (responseData['error'] != null) {
throw HttpException(responseData['error']['message']);
} else {
_token = responseData['idToken'];
_userId = responseData['id'];
_expiryDate = DateTime.now().add(
Duration(
seconds: responseData['expiresIn'],
),
);
}
_autoLogout();
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode(
{
'token': _token,
'userId': _userId,
'expiryDate': _expiryDate!.toIso8601String(),
},
);
prefs.setString('userData', userData);
} catch (error) {
throw error;
}
}
Future<void> signup(String email, String password) async {
return _authenticate(email, password, 'register');
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'login');
}
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final Map<String, Object> extractedUserData = Map<String, Object>.from(
json.decode(prefs.getString('userData') as String));
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'] as String);
if (expiryDate.isBefore(DateTime.now())) {
return false;
}
_token = extractedUserData['token'] as String;
_userId = extractedUserData['userId'] as String;
_expiryDate = expiryDate;
notifyListeners();
_autoLogout();
return true;
}
Future<void> logout() async {
_token = null;
_userId = null;
_expiryDate = null;
if (_authTimer != null) {
_authTimer!.cancel();
_authTimer = null;
}
notifyListeners();
final prefs = await SharedPreferences.getInstance();
// prefs.remove('userData');
prefs.clear();
}
void _autoLogout() {
if (_authTimer != null) {
_authTimer!.cancel();
}
final timeToExpiry = _expiryDate!.difference(DateTime.now()).inSeconds;
_authTimer = Timer(Duration(seconds: timeToExpiry), logout);
}
}
and this is main.dart:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Auth(),
),
],
child: Consumer<Auth>(
builder: (ctx, auth, _) => MaterialApp(
title: 'MyShop',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: auth.isAuth
? MainScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: AuthScreen(),
),
routes: {
MainScreen.routeName: (ctx) => const MainScreen(),
UserAccountScreen.routeName: (ctx) => const UserAccountScreen(),
},
),
),
);
}
I tried to change the class to extend GetXController, also make some variables as observable by adding .obs at the end of them and listening to their changes by wrapping the listener part inside the Obx. But I don't know what should I do with isAuth variable? It seems my new code after modification can not update the isAuth state and it is always `false and this keeps the authentication page always up and no way to go into the application for users.
EDIT: This is the main.dart after modification:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: AuthController.instance.isAuth
? homeScreenRoute
: authenticationScreenRoute,
unknownRoute: GetPage(
name: '/not-found',
page: () => PageNotFound(),
transition: Transition.fadeIn),
getPages: [
GetPage(
name: rootRoute,
page: () {
return SiteLayout();
}),
GetPage(
name: authenticationScreenRoute,
page: () => const AuthenticationScreen()),
GetPage(name: homeScreenRoute, page: () => HomeScreen()),
],
debugShowCheckedModeBanner: false,
title: 'BasicCode',
theme: ThemeData(
scaffoldBackgroundColor: light,
textTheme: GoogleFonts.mulishTextTheme(Theme.of(context).textTheme)
.apply(bodyColor: Colors.black),
pageTransitionsTheme: const PageTransitionsTheme(builders: {
TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
}),
primarySwatch: Colors.blue,
),
// home: AuthenticationPage(),
);
}
}
You can wrap your stateless widget with GetBuilder(), like this:
GetBuilder<YourController>(
id: 'id_name',
builder: (controller) {
if (controller.isAuth) {
return OneWidget();
} else {
return SecondWidget();
}
}
Do you need use update(['id_name']) after change value of isAuth, this produce a rebuild of GetBuilder.

How to check user is logged in or not with phone authentication using firebase in flutter?

Here, I'm authenticated through the phone number with OTP code using firebase but
after login succeeded, it navigated through home page but when I click on back
it drags me login Screen.
here, the code I have tried, but it doesn't work
#override
void initState() {
super.initState();
isSignedIn();
}
void isSignedIn() async {
this.setState(() {
isLoading = true;
});
firebaseAuth.currentUser().then((user){
if(user !=null){
Navigator.of(context).pushReplacementNamed('/homepage');
}else{
verifyPhone();
}
});
this.setState(() {
isLoading = false;
});
}
Method for getting OTP code
Future<void> verifyPhone()async{
final PhoneCodeAutoRetrievalTimeout autoRetrieval=(String verId){
this.verificationId=verId;
};
final PhoneCodeSent smsCodeSent=(String verId, [int forceCodeResend]){
this.verificationId=verId;
smsCodeDialog(context).then((value){
print("Signed in");
});
};
final PhoneVerificationCompleted verificationCompleted = (AuthCredential credential) {
print("verified");
};
final PhoneVerificationFailed verfifailed=(AuthException exception){
print("${exception.message}");
};
await firebaseAuth.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieval,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 10),
verificationCompleted: verificationCompleted,
verificationFailed: verfifailed
);
}
here the dialog box for sign in with OTP code
Future<bool> smsCodeDialog(BuildContext context){
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
return new AlertDialog(
title: Text('Enter sms Code'),
content: TextField(
onChanged: (value){
this.smsCode=value;
},
),
contentPadding: const EdgeInsets.all(10.0),
actions: <Widget>[
new FlatButton(
child: Text("Done"),
onPressed: (){
firebaseAuth.currentUser().then((user){
if(user !=null){
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/homepage');
}else{
Navigator.of(context).pop();
signIn();
}
});
},
)
],
);
}
);
}
method for Sign in with phone number
signIn()async{
AuthCredential credential= PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode
);
await firebaseAuth.signInWithCredential(credential).then((user){
Navigator.of(context).pushReplacementNamed('/homepage');
print('signed in with phone number successful: user -> $user');
}).catchError((onError){
print(onError);
});
}
`
Welcome Shruti Ramnandan Sharma in Stackoverflow and Flutter dev.
Your code seems to working fine with me, I coded for you a one page dart that can test you the whole code with fixing your problem with going back to Login or VerifyPhone page.
Note: I changed your order of code in verifyPhone() method.
And Changed Navigator.of(context).pushReplacementNamed('/homepage'); to
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => HomeRoute()));
The whole code here
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
void main() => runApp(VerifyPhoneRoute());
class VerifyPhoneRoute extends StatefulWidget {
#override
_VerifyPhoneRouteState createState() {
return _VerifyPhoneRouteState();
}
}
class _VerifyPhoneRouteState extends State<VerifyPhoneRoute> {
bool isLoading = false;
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
String verificationId;
String phoneNo = "Your number here";
String smsCode;
#override
void initState() {
super.initState();
isSignedIn();
}
void isSignedIn() async {
this.setState(() {
isLoading = true;
});
firebaseAuth.currentUser().then((user) {
if (user != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
} else {
verifyPhone();
}
});
this.setState(() {
isLoading = false;
});
}
Future<void> verifyPhone() async {
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential credential) {
print("verified");
};
final PhoneVerificationFailed verifyFailed = (AuthException exception) {
print("${exception.message}");
};
final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsCodeDialog(context).then((value) {
print("Signed in");
});
};
final PhoneCodeAutoRetrievalTimeout autoRetrieval = (String verId) {
this.verificationId = verId;
};
await firebaseAuth.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieval,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 10),
verificationCompleted: verificationCompleted,
verificationFailed: verifyFailed);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Inapp Plugin by dooboolab'),
),
body: Center(
child: RaisedButton(
child: Text("Verify"),
onPressed: () {
verifyPhone();
}),
),
),
);
}
Future<bool> smsCodeDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return new AlertDialog(
title: Text('Enter sms Code'),
content: TextField(
onChanged: (value) {
this.smsCode = value;
},
),
contentPadding: const EdgeInsets.all(10.0),
actions: <Widget>[
new FlatButton(
child: Text("Done"),
onPressed: () {
firebaseAuth.currentUser().then((user) {
if (user != null) {
Navigator.of(context).pop();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
} else {
Navigator.of(context).pop();
signIn();
}
});
},
)
],
);
});
}
signIn() async {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId, smsCode: smsCode);
await firebaseAuth.signInWithCredential(credential).then((user) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
print('signed in with phone number successful: user -> $user');
}).catchError((onError) {
print(onError);
});
}
}
class HomeRoute extends StatefulWidget {
#override
_HomeRouteState createState() {
return _HomeRouteState();
}
}
class _HomeRouteState extends State<HomeRoute> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Inapp Plugin by dooboolab'),
),
body: Center(
child: Text("Welcome There."),
),
),
);
}
}
This code works fine with me. So if there's any problem happened with you again, don't be hesitate to comment on this answer. And if this answered your question and solve your problem, please make it as answer.
Use method below by pass verificationID come from API firebase when code sent and code enter by user, so if method return FirebaseUser the code is correct if return null the code enter by user is not correct
Future<FirebaseUser> getUserFromCodePhone(String code, String verificationID) async {
FirebaseAuth mAuth = FirebaseAuth.instance;
AuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(
verificationId: verificationID, smsCode: code);
try {
AuthResult result = await mAuth.signInWithCredential(phoneAuthCredential);
FirebaseUser currentUser = await mAuth.currentUser();
if (currentUser != null && result.user.uid == currentUser.uid) {
return currentUser;
} else {
return null;
}
} on PlatformException catch (_) {}
return null;
}
How it work ? : when use signInWithCredential method if code passed to
AuthCredential is false then the method will throw PlatformException
so out from try block and return null