Issue with the Firebase database and Page Routing - flutter

I am new with flutter and got stuck with an issue. In my code the scenario is:
first it authenticate the user through phone and otp verification.
After successful verification it must check if the logged in user has profile in the database.
If the user profile is available the flag is set to true and then it must route it to the dashboard page
or
If the user profile is not available it must route first to User Profile page to create a profile and then route it to database.
i had written the same condition.On execution as their is user profile in the database still it is routing to User Profile page.
I am also providing the screenshot of the database and the console part.
Code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/cupertino.dart';
import 'package:udharibook/Screens/SignInPage.dart';
import 'package:udharibook/Screens/UserProfile.dart';
import 'package:udharibook/Screens/dashboard.dart';
class AuthService {
bool flag = false;
final FirebaseAuth _auth = FirebaseAuth.instance;
final DBRef = FirebaseDatabase.instance.reference().child('Users');
handleAuth(){
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext, snapshot){
if(snapshot.hasData){
readData();
print(flag);
if(flag ==true)
return DashboardPage();
else
return UserProfile();
}
else {
return SignIn();
}
},
);
}
void readData() async {
final FirebaseUser user = await _auth.currentUser();
final userid = user.uid;
DBRef.child(userid).once().then((DataSnapshot data){
print(userid);
if(data.value!=null)
{
flag = true;
print(data.key);
print(data.value);
}
else{
print('User not found');
flag = false;
}
});
}
signOut(){
FirebaseAuth.instance.signOut();
}
signIn(AuthCredential authCreds){
FirebaseAuth.instance.signInWithCredential(authCreds);
}
signInWithOTP(smsCode,verId){
AuthCredential authCreds = PhoneAuthProvider.getCredential(
verificationId: verId,
smsCode: smsCode
);
signIn(authCreds);
}
}

I would suggest you to move your flag variable to a global file and then try it. I guess since I dont know what those print statements say.

Related

Flutter - Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found

Flutter is not writing data to my firebase collection and has errors in the debug.
Steps to reproduce
https://www.youtube.com/watch?v=EA7973HI93E&list=PL4cUxeGkcC9j--TKIdkb3ISfRbJeJYQwC&index=18
Steps to reproduce the behavior:
Run the app,
register a user.
Expected behavior:
I expected that the user will be made and data to the collection added
the output
Ignoring header X-Firebase-Locale because its value was null. D/FirebaseAuth(17181): Notifying id token listeners about user ( fTnXUNwmPUajE9ybOeP3GLW0e392 ). D/FirebaseAuth(17181): Notifying auth state listeners about user ( fTnXUNwmPUajE9ybOeP3GLW0e392 ). W/DynamiteModule(17181): Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found. I/DynamiteModule(17181): Considering local module com.google.android.gms.providerinstaller.dynamite:0 and remote module com.google.android.gms.providerinstaller.dynamite:0 W/ProviderInstaller(17181): Failed to load providerinstaller module: No acceptable module com.google.android.gms.providerinstaller.dynamite found. Local version is 0 and remote version is 0. W/Firestore(17181): (24.4.0) [WriteStream]: (e9a00e8) Stream closed with status: Status{code=UNAVAILABLE, description=Channel shutdownNow invoked, cause=null}. W/DynamiteModule(17181): Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found.
my auth.dart code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:my_app/models/user.dart';
import 'package:my_app/services/database.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create MyUser object based on User
MyUser? _userFromFirebaseUser(User? user) {
return user != null ? MyUser(uid: user.uid) : null;
}
// auth change user stream
Stream<MyUser?> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
//sign in anonymously
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User? user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
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 (e) {
print(e.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
User? user = result.user;
// create new document for the user with uid
await DatabaseService(uid: user?.uid)
.updateUserData('How do you feel', 'I am mad', 'angry');
return _userFromFirebaseUser(user);
} on FirebaseAuthException catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
My database.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class DatabaseService {
// collection reference
final String? uid;
DatabaseService({this.uid});
final CollectionReference pollearnCollection =
FirebaseFirestore.instance.collection('Pollearn');
Future updateUserData(String question, String answer, String emotion) async {
Map<String, String> data = {
'question': question,
'answer': answer,
'emotion': emotion,
};
return await pollearnCollection.doc(uid).set(data);
}
}
I already tried the following:
turn the emulator on and off.
tried different emulator
updated google play services
turnt bluetooth off
turnt internet off and on
enabled sign in with mail and password
adding
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
I hope you guys can help me. Thanks in advance!

Page not disposed when signed up: Flutter

I am trying to implement provider package to signUp/signIn/signOut using Firebase Auth.
My ChangeNotifier class is-
import 'package:e_shoppie/db/authentication.dart';
import 'package:e_shoppie/db/user_services.dart';
import 'package:e_shoppie/structure/constants.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
//User can only be one of these states
/**
* uninitialized: User just opened the app (just opening)
* unauthenticated: Show the login screen to the user
* authenticating: Show a circular indicator the user
* authenticated: User is looged into the app
*/
enum Status { uninitialized, authenticated, authenticating, unauthenticated }
class UserProvider with ChangeNotifier {
FirebaseAuth _auth;
Auth _userAuth = Auth();
UserServices userServices = UserServices();
User? _user;
GoogleSignIn _googleSignIn = GoogleSignIn();
Status _status =
Status.uninitialized; //when the instance of the class is created
UserProvider.initialize() : _auth = FirebaseAuth.instance {
//subscribing to stream to listen to changes in user status
_auth.authStateChanges().listen(
(user) {
_onStatusChanged(user);
},
);
}
Status get status => _status;
User? get user => _user;
Future<bool> signUp(String username, String email, String password) async {
try {
//change the status of the user
_status = Status.authenticating;
//notify the listeners
notifyListeners();
// UserCredential credential =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
Map<String, dynamic> values = {
'name': username,
'email': email,
'id': user!.uid,
};
userServices.createUser(values);
_status = Status.authenticated;
notifyListeners();
return true;
} catch (e) {
_status = Status.unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
Future signOut() async {
print('entered signOut');
await _auth.signOut();
_status = Status.unauthenticated;
notifyListeners();
print('Exiting signOut');
return Future.delayed(Duration
.zero); //duration to return is set to zero (can work without it)
}
Future<void> _onStatusChanged(User? user) async {
if (user == null) {
_status = Status.unauthenticated;
} else {
_user = user;
_status = Status.authenticated;
}
notifyListeners();
}
}
The way I am navigating on state change is-
class ScreenController extends StatelessWidget {
const ScreenController({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
switch (user.status) {
case Status.uninitialized:
return SplashScreen();
case Status.unauthenticated:
return LoginScreen();
case Status.authenticating:
return LoadingScreen();
case Status.authenticated:
return HomePage();
default:
return LoginScreen();
}
}
}
Problem: in my SignUp page, I call the signUp method of the UserProvider class to signUp the user.
I expect the signup page gets destroyed and home page appears when user is created and sign up procedure is complete.
What I get: Home Page is built but the sign up page is not destroyed and remains on the screen unless I press the back button.
Sign Up button -
// minWidth: MediaQuery.of(context).size.width.,
child: Text(
'Sign Up and Register',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
onPressed: () async {
if (!await provider.signUp(
_nameTextController.text,
_emailTextController.text,
_passwordTextController.text)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Sign In Failed')));
}
// Navigator.pop(context);
// Navigator.pushReplacement(
// context,
// MaterialPageRoute(
// builder: (context) => HomePage()));
},
),
Also- my Sign Up class is wrapped with Consumer.
I am using the provider package for navigation. The problem I am facing is: that Debug mode shows that the login page is disposed of when the user logs in and Home Page appears. But when I sign in from the Sign Up page, the page is not disposed and Home Page is constructed below it.
Please help!!
You have to use Navigator.popAndPushNamed(context) or Navigator.pushReplacementNamed(context). This is work perfect in your scenario both have the same output difference is only animations. For signUp/signIn/signOut this is ideal way.

why Flutter login with facebook is not working

I'm trying to make a login screen with Facebook but end up with this error when I run my code. here is my code:
import 'package:facebook_login/services/auth_service.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_login_facebook/flutter_login_facebook.dart';
import 'package:auth/auth.dart';
class AuthBloc {
final authService = AuthService();
final fb = FacebookLogin();
Stream<User> get currentUser => authService.currentUser;
loginFacebook() async {
print('Starting Facebook Login');
final res = await fb.logIn(
permissions: [
FacebookPermission.publicProfile,
FacebookPermission.email
]
);
switch(res.status){
case FacebookLoginStatus.Success:
print('It worked');
//Get Token
final FacebookAccessToken fbToken = res.accessToken;
//Convert to Auth Credential
final AuthCredential credential
= FacebookAuthProvider.getCredential(accessToken: fbToken.token);
//User Credential to Sign in with Firebase
final result = await authService.signInWithCredentail(credential);
print('${result.user.displayName} is now logged in');
break;
case FacebookLoginStatus.Cancel:
print('The user canceled the login');
break;
case FacebookLoginStatus.Error:
print('There was an error');
break;
}
}
logout(){
authService.logout();
}
}
when i run this i get this error message
Invalid depfile: C:\Users\Main\OneDrive\stuff\Documents\seltech\st\.dart_tool\flutter_build\7b28b646cfa2e7424746c78d0801893a\kernel_snapshot.d
Error: Couldn't resolve the package 'facebook_login' in 'package:facebook_login/services/auth_service.dart'.
Error: Couldn't resolve the package 'auth' in 'package:auth/auth.dart'.
lib/src/bloc/auth_bloc:1:8: Error: Not found: 'package:facebook_login/services/auth_service.dart'
import 'package:facebook_login/services/auth_service.dart';
there are more errors that pop up.
if you need more of the code I can send some more of it
it's so much it won't fit in here
all of the error I get is from the auth_block. I have another login page made on a separate screen.
I also have a manual login with firebase auth there .
With these packages on the pubspec:
flutter_facebook_auth: ^3.5.1
firebase_auth: ^3.1.0
firebase_core: ^1.6.0
And this function:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<String?> facebookSignin() async {
try {
final _instance = FacebookAuth.instance;
final result = await _instance.login(permissions: ['email']);
if (result.status == LoginStatus.success) {
final OAuthCredential credential =
FacebookAuthProvider.credential(result.accessToken!.token);
final a = await _auth.signInWithCredential(credential);
await _instance.getUserData().then((userData) async {
await _auth.currentUser!.updateEmail(userData['email']);
});
return null;
} else if (result.status == LoginStatus.cancelled) {
return 'Login cancelled';
} else {
return 'Error';
}
} catch (e) {
return e.toString();
}
}
I'm able to login with facebook on my app
don't forget to also follow the configuration steps for android/ios and facebook for developers console
enter image description here
#enable this Permissions and features
then it will work

What to do after login but before essential user data gets returned in flutter

I have a flutter app that uses firebase for authentication.
return StreamBuilder<FirebaseUser>(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
return HomeScreen();
} else {
return LoginScreen();
}
},
);
so basically as soon as user authenticates, this will take to the home screen. but i dont want that, i want to wait on another piece of data from my api, say onboarded, if onboarded == true then HomeScreen otherwise OnboardingScreen.
So the tricky part is before that data comes in, i want to stay on the login screen. how do i have the user stay on the LoginScreen? it seems the best way is to have another stream listen to the onboardedLoading and combine these 2 streams?
Make a dart file auth.dart, in that, paste this line of code,
final FirebaseAuth auth = FirebaseAuth.instance;
Future<FirebaseUser> handleSignInEmail(String email, String password) async {
AuthResult result = await auth.signInWithEmailAndPassword(email: email, password: password);
final FirebaseUser user = result.user;
assert(user != null);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await auth.currentUser();
assert(user.uid == currentUser.uid);
print('signInEmail succeeded: $user');
return user;
}
Future<FirebaseUser> handleSignUp(email, password) async {
AuthResult result = await auth.createUserWithEmailAndPassword(email: email, password: password);
final FirebaseUser user = result.user;
assert (user != null);
assert (await user.getIdToken() != null);
return user;
}
In your login/ Sigup page, create an instance of my auth class:
var authHandler = new Auth();
In the onPressed () of your button
onPressed: () {
if(onboardedLoading==true){
authHandler.handleSignInEmail(emailController.text, passwordController.text)
.then((FirebaseUser user) {
Navigator.push(context, new MaterialPageRoute(builder: (context) => HomeScreen()));
}).catchError((e) => print(e));
}
}else{
//Show An Animation, such as CirclularProgressIndicator.
}
You can design a simple loading screen, then use Navigator.pushAndRemoveUntil() to whichever screen you need after getting AuthState.

Can't Logout and redirect to LoginPage when using Firebase/ Google Sign-in in Flutter

I am working on implementing a Flutter app that uses Firebase authentication as well as Google-Sign. I have successfully gotten firebaseauth working to sign-in/signout without issue. based on the authstate change, I direct to main page or login page. I then implemented Google Sign-in, which auto-signs in user to firebase.
This worked and I got the necessary permissions to be prompted,etc. But when I click to logout, the app doesn't redirect to login screen. I Am calling the await firebaseAuth.instance.Signout() ...and I believe it does remove the user..but it doesn't redirect. Then, when I try to sign-in again, nothing happens.
I have tried many different variations of logging in..I can't seem to figure out why it won't redirect on logout.
This is my Sign-in Logic which signs into Google and firebase:
try {
final GoogleSignInAccount googleSignInAccount =
await _googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final FirebaseUser user = await _firebaseAuth.signInWithCredential(credential);
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _firebaseAuth.currentUser();
assert(user.uid == currentUser.uid);
} catch (error) {
print(error);
}
notifyListeners();
}
This is my logic in main.dart to redirect to appropriate page:
home: StreamBuilder(
stream: _firebaseAuth.onAuthStateChanged,
builder: (context, snapshot) {
if(snapshot.hasData){
return HomePage();
} else {
return Login();
}
},
)
This is my logic to Signout()
Future<void> signOut() async {
await _firebaseAuth.signOut().catchError((error){
print(error.toString());
});
}
In my case, I don't want to log the user out of Google, just my app.
But I cannot figure out why this doesn't redirect. It worked correctly when I was using the standard firebase sign-in with email/password.
After a lot of digging around, it turns out that if you are calling SignOut() from the sideDrawer component, you can't just call Signout. you need to do this. Solved it for me.
FlatButton(
child: Text('Logout'),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/');
Provider.of<Auth>(context).signOut();
},
),
This works in FlutterFire. I used authStateChanges() method on a FirebaseAuth instance and Navigator.
authStateChanges() method allows you to get the user's authentication state.
Firebase Auth enables you to subscribe in realtime to this state via a
Stream. Once called, the stream provides an immediate event of the
user's current authentication state, and then provides subsequent
events whenever the authentication state changes.
Navigator is for navigating to main.dart
To switch to a new route, use the Navigator.push() method. The push()
method adds a Route to the stack of routes managed by the Navigator.
main.dart
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:flutter/material.dart';
import 'menu.dart';
import 'login.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MyApp()
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitUp]);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'TestApp',
theme: ThemeData(primarySwatch: Colors.blue),
home:
StreamBuilder<auth.User>(
stream: auth.FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<auth.User> snapshot) {
if(snapshot.hasData) {
print("There is a user logged in");
return HomePage();
}
else {
return LoginPage();
}
},
)
);
}
}
Sign out using Firebase Authentication
Future<void> signOut() async {
await _firebaseAuth.signOut().catchError((error){
print(error.toString());
});
Navigator.push(context, MaterialPageRoute(builder: (context) => MyApp()));
}
I think it's only to do singOut on _googleSignIn like this:
Future<void> signOut() async {
await _firebaseAuth.signOut().catchError((error){
print(error.toString());
});
await _googleSignIn.signOut();
}