How to obtain a specific field in a Firebase document - firebase

Trying to capture a specific field from my documents. Here is the code for the wrapper,
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
// return either the Home or Authenticate widget
if (user == null) {
return Authenticate();
} else {
return FirmHomePage();
}
}
}
and this is the code that we used for printing in the console.
void idss() async {
FirebaseUser userid = await FirebaseAuth.instance.currentUser();
var document = await Firestore.instance.collection('Users').getDocuments();
for (var document in document.documents) {
messagetext = document.data['JobType'];
usettype = messagetext;
print(messagetext);
}
}
We want to check our user to set a path for them.

FirebaseUser userid = await FirebaseAuth.instance.currentUser();
final QuerySnapshot result = await Firestore.instance.collection('Users')
.where('uid', isEqualTo: currentUser.uid) .getDocuments();
final List < DocumentSnapshot > documents = result.documents;
if (documents.length == 1) {
//your code here
}else{
//your code here
}

Related

How to fix circular wait progress while logging out in flutter app using Firebase authentication?

I have a LoginPage() for login and a DashBoard() page which comes after logging in succesfully.
I am using a Controller() page to provide the authetication which listens for any authentication changes in firebase, it looks like this :
class Controller extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
else if (snapshot.hasData) {
return DashBoard();
}
return LoginPage();
},
));
}
}
I also have a Log out button in another page. When I try to logout, it throws me first to DashBoard() page (which means that snapshot.hasData has some value) and after 2-3 seconds it throws me then to LoginPage() but the code never goes into this section
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
It first goes into this block conditon
else if (snapshot.hasData) {
return DashBoard();
}
And then the LoginPage() section. Also when I try to Login, it never shows me the Circularwait, but throws me to DashBoard() page.
What is the best way to achieve this ?
My fireBase auth file looks like this :
class GoogleSignInProvider extends ChangeNotifier {
final googleSignIn = GoogleSignIn();
GoogleSignInAccount _user;
GoogleSignInAccount get user => _user;
Future signInWithGoogle() async {
try {
final GoogleSignInAccount googleuser = await googleSignIn.signIn();
if (googleuser == null) return;
_user = googleuser;
final GoogleSignInAuthentication googleAuth =
await googleuser.authentication;
final GoogleAuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
// Fluttertoast.showToast(msg: "Account created");
await FirebaseAuth.instance.signInWithCredential(credential);
print(_user);
notifyListeners();
} catch (e) {
print(e.toString());
}
}
Future signOutGoogle() async {
await googleSignIn.disconnect();
FirebaseAuth.instance.signOut();
}
}
interact with the bloc using a streambuilder in your ui. the ui creates events which the bloc code handles and response with state output
abstract class LoginEvent extends Equatable{
const LoginEvent();
#override
List<Object>get props=>[];
}
class LoginUser{
final String email;
final String password;
const LoginUser(this.email,this.password);
String get getEmail { return this.email;}
String get getPassword{ return this.password;}
}
class AuthenticateEvent extends LoginEvent{
final LoginUser user;
const AuthenticateEvent(this.user);
#override
List<Object> get props => [user];
LoginUser get getUser{return this.user;}
}
class LoginState extends Equatable{
final LoginView _login;
const LoginState(this._login);
#override
List<Object> get props => [_login];
LoginView get getLogin {return this._login;}
}
class BlocLogin
{
Stream<LoginState> get loginStream => _loginController.stream;
final _loginController = BehaviorSubject<LoginState>();
void dispose()
{
_loginController.close();
}
authenticate(BuildContext context,LoginEvent loginEvent) async
{
if (loginEvent is AuthenticateEvent)
{
LoginView param =
new LoginView(loginEvent.getUser.getEmail, loginEvent.getUser.getPassword);
LoginView loginValue =await Provider.of<Api>(context, listen: false)
.addLogin(context, param);
if (loginValue.returnMessage == "Failed") {
DialogCaller.showIncorrectLoginDialog(context).then((value2) {});
} else {
Provider.of<Api>(context, listen: false).dataCache.login = loginValue;
LoginState loginState=new LoginState(loginValue);
_loginController.sink.add(loginState);
}
}
}
}

Trying to login with google but always return null

hey guys i trying to login with google using firebase in flutter but its always return null in the next page
how can i get the current user in the next page after login with google
i already connect with firebase and generate sha-1 and sha-256
here's the code
login button
onPressed: () async {
setState(() {
_isSigningIn = true;
});
try {
final user = await googleSignIn.signIn();
final googleAuth = await user.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken
);
final googleAccount = await FirebaseAuth.instance.signInWithCredential(credential);
if(googleAccount != null) {
Navigator.pushReplacementNamed(context, HomeScreen.id);
}
} catch (e) {
final snackbar = SnackBar(content: Text(e.toString()));
_scaffoldKey.currentState.showSnackBar(snackbar);
} finally {
setState(() {
_isSigningIn = false;
});
}
},
home_screen.dart
class _HomeScreenState extends State<HomeScreen> {
final _auth = FirebaseAuth.instance;
User _currentUser;
void getCurrentUser() async {
try {
var currentUser = await _auth.currentUser;
if (currentUser != null) {
_currentUser = currentUser;
}
} catch(e) {
print(e);
}
}
#override
void initState() {
super.initState();
getCurrentUser();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_currentUser.email),
),
);
}
}
thank you
This line is an asynchronous function, it is for this reason that you receive null, you must add an await.
final googleAccount = await FirebaseAuth.instance.signInWithCredential(credential);
In addition to this, to access the information of the current user you must do it this way.
googleAccount.user

How to use transaction with int data - Firestore Flutter

Upon creating an account the user's firestore creates a field that displays the current amount of plastics the user has. So far, I have a button that updates that amount using the user's text field input. I've heard of something called a transaction which apparently allows one to intsead add the input amount to the overall data for it to be displayed? How would I accomplish this in my case when the use inputs a new amount?
Code:
database.dart
Future<void> userSetup(String displayName) async {
int plastics = 0;
final CollectionReference users =
FirebaseFirestore.instance.collection('UserNames');
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
users.doc(uid).set({'displayName': displayName, 'uid': uid});
//This is the field for plastics amount starting at 0.
users.doc(uid).update({'plastics': plastics});
return;
}
How I retrieve the amount data:
final firestore = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
Future<String> getPlasticNum() async {
final CollectionReference users = firestore.collection('UserNames');
final String uid = auth.currentUser.uid;
final result = await users.doc(uid).get();
return result.data()['plastics'].toString();
}
How I display it:
FutureBuilder(
future: getPlasticNum(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Text(snapshot.data,
style: TextStyle(color: Colors.amber[400], fontSize: 20));
},
),
Currently how the user can replace the amount, but not add to it(The problem)
OnPressed: () async {
try {
final String uid = auth.currentUser.uid;
FirebaseFirestore.instance
.collection('UserNames')
.doc(uid)
.update({
"plastics": int.parse(_plasticController.text),
});
Navigator.of(context).pop();
} catch (e) {}
},
I made a separate future to take care of adding:
final firestore = FirebaseFirestore.instance; //
FirebaseAuth auth = FirebaseAuth.instance;
Future<bool> addPlastic(String amount) async {
try {
String uid = auth.currentUser.uid;
var value = double.parse(amount);
DocumentReference documentReference =
FirebaseFirestore.instance.collection('UserNames').doc(uid);
FirebaseFirestore.instance.runTransaction((transaction) async {
DocumentSnapshot snapshot = await transaction.get(documentReference);
if (!snapshot.exists) {
documentReference.set({'plastics': value});
return true;
}
double newAmount = snapshot.data()['plastics'] + value;
transaction.update(documentReference, {'plastics': newAmount});
return true;
});
} catch (e) {
return false;
}
}
Then I just called it when the button was pressed
onPressed(){
addPlastics(_plasticController.text);
}

Flutter App stuck at splash screen not moving to login page or homepage

I tried to add splash screen to add splash screen to my app but it gets stuck at splash screen itsalf and does not move to next screens
I have added the code here:-
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
getUserInfo();
}
Future getUserInfo() async {
await getUser();
setState(() {});
print(uid);
navigateUser();
}
navigateUser()
{
if(uid!=null && authSignedIn != false)
{
Timer(Duration(seconds: 2),
()=>Navigator.pushReplacementNamed(context, "/toprofilepage")
);
}
else{
Timer(Duration(seconds: 2),
()=>Navigator.pushReplacementNamed(context, "/tologinpage")
);
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Login',
initial route:'/',
routes: {
'/toprofilepage':(context)=>FirstScreen(),
'/tologinpage':(context)=>LoginPage(),
},
home: Scaffold(
body: Center(
child: Text("Saraswat",style: TextStyle(fontSize: 40,fontWeight: FontWeight.bold,fontStyle: FontStyle.italic),),
),
)
);
}
}
I am getting this following message in console also:-
E/flutter ( 5947): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
Code for sign in:-
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
bool authSignedIn;
String uid;
String name;
String imageUrl;
Future getUser() async {
// Initialize Firebase
await Firebase.initializeApp();
SharedPreferences prefs = await SharedPreferences.getInstance();
bool authSignedIn = prefs.getBool('auth') ?? false;
final User user = _auth.currentUser;
if (authSignedIn == true) {
if (user != null) {
uid = user.uid;
name = user.displayName;
imageUrl = user.photoURL;
}
}
}
Future<String> signInWithGoogle() async {
// Initialize Firebase
await Firebase.initializeApp();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential userCredential = await _auth.signInWithCredential(credential);
final User user = userCredential.user;
if (user != null) {
// Checking if email and name is null
assert(user.uid != null);
assert(user.displayName != null);
assert(user.photoURL != null);
uid = user.uid;
name = user.displayName;
imageUrl = user.photoURL;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = _auth.currentUser;
assert(user.uid == currentUser.uid);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('auth', true);
return 'Google sign in successful, User UID: ${user.uid}';
}
return null;
}
void signOutGoogle() async {
await googleSignIn.signOut();
await _auth.signOut();
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('auth', false);
uid = null;
name = null;
imageUrl = null;
print("User signed out of Google account");
}
I tried a lot of things but did not get any solution pls help!.Should I place the navigator function anywhere else or is there some other error pls help!.
Try doing the flow conditions in initialRoute only
Since the firebase has updated the way we check the user is logged in or not. Its not a async task so you can use directly in the MyApp class.
initialRoute: FirebaseAuth.instance.currentUser != null
? HomeScreen.route_name
: AuthScreen.route_name
Or you can use the listener for auth change
FirebaseAuth.instance.onAuthStateChanged.listen((firebaseUser) {
// do whatever you want based on the firebaseUser state
});
so when the auth is changed it will re-direct it to the page you want to, like this
home: StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (streamContext, userSnapshot) {
if (userSnapshot.connectionState == ConnectionState.waiting)
return SplashScreen();
if (userSnapshot.hasData) {
return HomeScreen();
}
return AuthScreen();
},
),

Load Firestore document first in Flutter

Thanks in advance!
Flutter & Firestore
I'm checking if the user is an admin. I have a collection 'users', within: a bool: admin: true or false. If it's true it shows the admin Screen. Else it shows the main screen.
The problem: the first 1 second I get this Screen. (see screen shot, only 1 second visible) Is there an option to use a loading indicator when the app gets the data from firestore.
I tried adding if (currentUser.admin == null) {}
But that doesn't work.
User currentUser;
//I made a separate modal document
#override
void initState() {
super.initState();
pageController = PageController(initialPage: 0);
getUser();
}
getUser() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
DocumentSnapshot doc =
await Firestore.instance.collection("users").document(user.uid).get();
setState(() {
currentUser = User.fromDocument(doc);
});
print(currentUser.admin);
}
#override
Widget build(BuildContext context) {
if (currentUser.admin == true) {
return AdminScreen(
currentUser: currentUser,
);
} else {
return mainScreen();
}
}
}
Screenshot
UPDATE: tried this:
getUser() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
DocumentSnapshot doc =
await Firestore.instance.collection("users").document(user.uid).get();
if (doc.exists) {
try {
setState(() {
currentUser = User.fromDocument(doc);
});
} catch (e) {
print(e);
}
}
Found it!
For anyone having the same issue.
This was the problem:
if (currentUser.admin == true)
It should be: if (currentUser == null) or if (currentUser != null)
it doesn't work with currentUser.xxxx
You can also do as follows
Firestore.instance
.collection('driverListedRides')
.getDocuments()
.then((QuerySnapshot snapshot) => {
snapshot.documents.forEach((f) {
String _variableName = f.data["YourCollectionFieldId"];
})
});

Resources