Firestore and google auth with role base authorization in Flutter - firebase

At the time when user sign in to my app using google sign in with firebase how can I check that if user already have data or not in firestore database if yes then my app will check for user role and redirect user to the screen acc. to the role else it will create a document in firestore database with name, email, role and uid stored. but the problem is we cannot differentiate between signup and sign in with google auth like we can do in email and password auth. when user make purchase in our app his/her role will be changed to expert but due calling the signinwithgoogle in login page the user role is again being set to basic in database.
hope you understood the problem.
Here is my auth.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:gfd_official/User/User.dart';
import 'package:gfd_official/services/database.dart';
import 'package:google_sign_in/google_sign_in.dart';
String photoUrl;
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Userdat _userFromFirebaseUser(User user) {
return user != null ? Userdat(uid: user.uid) : null;
}
// auth change user stream
Stream<Userdat> get user {
return _auth
.authStateChanges()
//.map((FirebaseUser user) => _userFromFirebaseUser(user));
.map(_userFromFirebaseUser);
}
Future signInWithGoogle() async {
GoogleSignIn googleSignIn = GoogleSignIn();
final acc = await googleSignIn.signIn();
final auth = await acc.authentication;
final credential = GoogleAuthProvider.credential(
accessToken: auth.accessToken, idToken: auth.idToken);
try {
final res = await _auth.signInWithCredential(credential);
User user = res.user;
photoUrl = user.photoURL;
//create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData(user.displayName, user.email, 'basic', user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
Future logOut() {
try {
GoogleSignIn().signOut();
return _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
class UserHelper {
static FirebaseFirestore _db = FirebaseFirestore.instance;
static saveUser(User user) async {
Map<String, dynamic> userData = {
"name": user.displayName,
"email": user.email,
"role": "basic",
};
try {
final userRef = _db.collection("users").doc(user.uid);
if ((await userRef.get()).exists) {
await userRef.update({});
} else {
await _db.collection("users").doc(user.uid).set(userData);
}
} catch (e) {
print(e.toString());
}
}
}
This is my loginpage.dart
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_auth_buttons/flutter_auth_buttons.dart';
import 'package:gfd_official/Login_data/auth.dart';
class Loginpage extends StatefulWidget {
#override
_LoginpageState createState() => _LoginpageState();
}
class _LoginpageState extends State<Loginpage> {
final AuthService _authService = AuthService();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.red[50],
body: Container(
child: Column(
children: [
SizedBox(
height: 360,
),
Text(
'Yaha par Login Kare',
style: TextStyle(
fontSize: 30,
color: Colors.grey[800],
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 50,
),
Center(
child: GoogleSignInButton(
onPressed: () async {
dynamic result = await _authService.signInWithGoogle();
if (result == null) {
} else {
}
},
darkMode: true,
textStyle: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
fontFamily: "Roboto",
color: Colors.white),
borderRadius: 20,
),
),
],
),
),
);
}
}
this is my database class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:gfd_official/User/User.dart';
class DatabaseService {
final String uid;
DatabaseService({this.uid});
//collection reference
final CollectionReference userCollection =
FirebaseFirestore.instance.collection('users');
Future updateUserData(String name, String email, String role, String
userId)
async {
return await userCollection.doc(uid).set({
'name': name,
'email': email,
'role': role,
'userId': userId,
},
SetOptions(merge: true));
}
//user data from snapshot
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
final usersn = snapshot.data();
return UserData(
uid: uid,
name: usersn['name'],
email: usersn['email'],
role: usersn['role'],
);
}
//get user data
Stream<QuerySnapshot> get userrole {
return userCollection.snapshots();
}
//get user doc stream
Stream<UserData> get userData {
return userCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
}

Related

How to create a new Firestore user collection directly from Flutter code

I have been able to get Firebase Authentication to work for Google sign in, Anonymous sign in and from Email and Password sign in, including sending a verification email during email and password sign in thanks to help on stackoverflow.  Everything works as intended.  Now for my next step I am trying to create a user collection in Firestore using the uid created by Firebase Authentication.  I am confident my code is written correctly because I have tested it with (unsecure) Security Rules and the process worked exactly as desired.
I have reviewed the Firebase documentation several times but I cannot figure out what is wrong with my Security Rules code. How can I fix my Security rules to allow a new user to create a Screen name that will be added to the user collection in Firestore?  Thanks in advance for the help. 
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid}/jobs/{document=**} {
allow read, write: if request.auth.uid == uid;
}
match /users/{uid}/{document=**} {
allow read, write: if request.auth.uid == uid;
}
}
}
class HomePage extends StatefulWidget {
const HomePage({
Key? key,
}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
createUserInFirestore();
}
Future<void> createUserInFirestore() async {
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? user = googleSignIn.currentUser;
final usersRef = FirebaseFirestore.instance.collection('users');
final DocumentSnapshot doc = await usersRef.doc(user?.id).get();
if (!doc.exists) {
final userName = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const CreateAccountPage(),
),
);
usersRef.doc(user?.id).set({
'id': user?.id,
'userName': userName,
'photoUrl': user?.photoUrl,
'email': user?.email,
'displayName': user?.displayName,
'bio': '',
'timestamp': documentIdFromCurrentDate(),
});
doc = await usersRef.doc(user?.id).get();
}
}
#override
Widget build(BuildContext context) {
return AdaptiveLayoutScaffold(
drawer: const SideSheet(
userImage: FakeUserAvatars.stacy,
userName: 'Stacy James',
),
landscapeBodyWidget: Container(),
portraitBodyWidget: Container(),
);
}
}
class CreateAccountPage extends StatefulWidget {
const CreateAccountPage({
Key? key,
}) : super(key: key);
#override
_CreateAccountPageState createState() => _CreateAccountPageState();
}
class _CreateAccountPageState extends State<CreateAccountPage> {
final _formKey = GlobalKey<FormState>();
late String userName;
void submit() {
_formKey.currentState?.save();
Navigator.pop(context, userName);
}
#override
Widget build(BuildContext context) {
return AdaptiveLayoutScaffold(
appBar: const Header(
automaticallyImplyLeading: false,
pageName: 'User Name',
),
landscapeBodyWidget: Container(),
portraitBodyWidget: ListView(
children: [
Column(
children: [
const Padding(
padding: EdgeInsets.only(top: 16.0),
child: Center(
child: Text('Create a User Name'),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: TextFormField(
autovalidateMode: AutovalidateMode.always,
decoration: InputDecoration(
hintText: 'Must be between 3 and 20 characters',
labelText: 'User Name',
prefixIcon: Icon(
Icons.person,
color: Theme.of(context).iconTheme.color,
),
),
keyboardType: TextInputType.text,
onSaved: (val) => userName = val as String,
),
),
),
PlatformElevatedButton(
onPressed: submit,
buttonText: 'Create User Name',
),
],
),
],
),
);
}
}
After reading what has been suggested and a few other things I used the Firestore Rules Playground to fix my code and then updated my Auth class to include a new method called createUserInFirestore() to handle the creation of a new user in Firestore using the uid after the user is created by Firebase Authentication.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid}/{document=**} {
allow read, create, update, delete: if request.auth.uid == uid;
}
}
}
abstract class AuthBase {
User? get currentUser;
Stream<User?> authStateChanges();
Future<User?> signInWithGoogle();
Future<User?> createUserWithEmailAndPassword(
String email,
String password,
);
Future<void> checkEmailVerified(BuildContext context, Timer timer);
Future<User?> signInWithEmailAndPassword(String email, String password);
Future<User?> signInAnonymously();
Future<void> resetPassword(BuildContext context, String email);
Future<void> confirmSignOut(BuildContext context);
Future<void> signOut();
}
class Auth implements AuthBase {
final _firebaseAuth = FirebaseAuth.instance;
#override
User? get currentUser => _firebaseAuth.currentUser;
#override
Stream<User?> authStateChanges() => _firebaseAuth.authStateChanges();
void _createNewUserInFirestore() {
final User? user = currentUser;
final CollectionReference<Map<String, dynamic>> usersRef =
FirebaseFirestore.instance.collection('users');
usersRef.doc(user?.uid).set({
'id': user?.uid,
'screenName': '',
'displayName': user?.displayName,
'photoUrl': user?.photoURL,
'bio': '',
'darkMode': false,
'timestamp': documentIdFromCurrentDate(),
});
}
#override
Future<User?> signInWithGoogle() async {
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? googleUser = await googleSignIn.signIn();
if (googleUser != null) {
final googleAuth = await googleUser.authentication;
if (googleAuth.idToken != null) {
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(
GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
),
);
_createNewUserInFirestore();
return userCredential.user;
} else {
throw FirebaseAuthException(
code: FirebaseExceptionString.missingGoogleIDTokenCode,
message: FirebaseExceptionString.missingGoogleIDTokenMessage,
);
}
} else {
throw FirebaseAuthException(
code: FirebaseExceptionString.abortedByUserCode,
message: FirebaseExceptionString.canceledByUserMessage,
);
}
}
#override
Future<User?> createUserWithEmailAndPassword(
String email,
String password,
) async {
final UserCredential userCredential =
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
_createNewUserInFirestore();
return userCredential.user;
}
#override
Future<void> checkEmailVerified(BuildContext context, Timer timer) async {
final User? user = currentUser;
await user?.reload();
final User? signedInUser = user;
if (signedInUser != null && signedInUser.emailVerified) {
timer.cancel();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const HomePage(),
),
);
}
}
#override
Future<User?> signInWithEmailAndPassword(
String email,
String password,
) async {
final UserCredential userCredential =
await _firebaseAuth.signInWithCredential(
EmailAuthProvider.credential(
email: email,
password: password,
),
);
return userCredential.user;
}
#override
Future<void> resetPassword(
BuildContext context,
String email,
) async {
try {
await _firebaseAuth.sendPasswordResetEmail(email: email);
Navigator.of(context).pop();
} catch (e) {
print(
e.toString(),
);
}
}
#override
Future<User?> signInAnonymously() async {
final UserCredential userCredential =
await _firebaseAuth.signInAnonymously();
return userCredential.user;
}
Future<void> _signOut(BuildContext context) async {
try {
final AuthBase auth = Provider.of<AuthBase>(
context,
listen: false,
);
await auth.signOut();
Navigator.pushAndRemoveUntil<dynamic>(
context,
MaterialPageRoute<dynamic>(
builder: (BuildContext context) => const LandingPage(),
),
(route) => false,
);
} catch (e) {
print(
e.toString(),
);
}
}
#override
Future<void> confirmSignOut(BuildContext context) async {
final bool? didRequestSignOut = await showAlertDialog(
context,
cancelActionText: DialogString.cancel,
content: DialogString.signOutAccount,
defaultActionText: DialogString.signOut,
title: DialogString.signOut,
);
if (didRequestSignOut == true) {
_signOut(context);
}
}
#override
Future<void> signOut() async {
final GoogleSignIn googleSignIn = GoogleSignIn();
await googleSignIn.signOut();
await _firebaseAuth.signOut();
}
}

After Signing In Not Navigating to main page

i am following a tutorial from Youtube. when i go with the flow everything works fine but when i add my code it gives errors.
when user is sign in for the first time after logout it stucks to the signin page and doesnot navigate to main page. but when we close and open app again it takes user to main page. please help me with this i googled it and i asked questions in fb groups but could not found a solution.
here is my code.
from auth.dart file
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:twitter_clone/models/user.dart';
class AuthService {
FirebaseAuth auth = FirebaseAuth.instance;
UserModel _userFromFirebaseUser(User user) {
return user != null ? UserModel(id: user.uid) : null;
}
Stream<UserModel> get user {
return auth.authStateChanges().map(_userFromFirebaseUser);
}
Future signUp(email, password) async {
try {
UserCredential user = await auth.createUserWithEmailAndPassword(
email: email, password: password);
await FirebaseFirestore.instance
.collection('users')
.doc(user.user.uid)
.set({'name': email, 'email': email});
_userFromFirebaseUser(user.user);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
}
Future signIn(email, password) async {
try {
User user = (await auth.signInWithEmailAndPassword(
email: email, password: password)) as User;
_userFromFirebaseUser(user);
} on FirebaseAuthException catch (e) {
print(e);
} catch (e) {
print(e);
}
}
Future signOut() async {
try {
return await auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
from Signin.dart file
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:twitter_clone/screens/auth/signup.dart';
import 'package:twitter_clone/services/auth.dart';
import 'package:twitter_clone/utilities/constants.dart';
class SignIn extends StatefulWidget {
SignIn({Key key}) : super(key: key);
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _authService = AuthService();
///variables to store email and password
String email = '';
String password = '';
bool _rememberMe = false;
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
width: double.infinity,
child: ElevatedButton(
// elevation: 5.0,
onPressed:()
async =>
{
_authService.signIn(email, password)
},
// padding: EdgeInsets.all(15.0),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.circular(30.0),
// ),
// color: Colors.white,
child: Text(
'LOGIN',
style: TextStyle(
color: Color(0xFF527DAA),
letterSpacing: 1.5,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
),
);
}

Google authentication problem (Flutter and Firebase)

I am flutter-newbie and I have one problem: I want to add Google authentication to my flutter app with firebase. This is my code for login screen:
import 'package:PixiCall/resources/firebase_repository.dart';
import 'package:PixiCall/screens/home_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
FirebaseRepository _repository = FirebaseRepository();
#override
Widget build(BuildContext context) {
return Scaffold(
body: loginButton(),
);
}
Widget loginButton() {
return FlatButton(
padding: EdgeInsets.all(35),
child: Text(
'Login',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.w900,
letterSpacing: 1.2,
),
),
onPressed: () => performLogin,
);
}
void performLogin() {
_repository.signIn().then((User user) {
if (user != null) {
authenticateUser(user);
} else {
print('There was an error');
}
});
}
void authenticateUser(User user, BuildContext context) {
_repository.authenticateUser(user).then((isNewUser) {
if (isNewUser) {
_repository.addDataToDb(user).then((value) {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
});
} else {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
}
});
}
}
I have this error here:
lib/screens/login_screen.dart:39:25: Error: Too few positional arguments: 2 required, 1 given.
authenticateUser(user);
What is the other parameter which I have to add?
Also I think that I have one more mistake in other file. This is the code from other file:
import 'package:PixiCall/models/user.dart';
import 'package:PixiCall/utils/utilities.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class FirebaseMethods {
final FirebaseAuth _auth = FirebaseAuth.instance;
GoogleSignIn _googleSignIn = GoogleSignIn();
static final FirebaseFirestore firestore = FirebaseFirestore.instance;
//user class
User1 user = User1();
Future<User> getCurrentUser() async {
User currentUser;
currentUser = await _auth.currentUser;
return currentUser;
}
Future<User> signIn() async {
GoogleSignInAccount _signInAccount = await _googleSignIn.signIn();
GoogleSignInAuthentication _signInAuthentication =
await _signInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: _signInAuthentication.accessToken,
idToken: _signInAuthentication.idToken,
);
User user = await _auth.signInWithCredential(credential);
return user;
}
Future<bool> authenicateUser(User user) async {
QuerySnapshot result = await firestore
.collection('users')
.where('email', isEqualTo: user.email)
.get();
final List<DocumentSnapshot> docs = result.docs;
//if user is registered then length of list > 0 or else less than 0
return docs.length == 0 ? true : false;
}
Future<void> addDataToDb(User currentUser) async {
String username = Utils.getUsername(currentUser.email);
user = User1(
uid: currentUser.uid,
email: currentUser.email,
name: currentUser.displayName,
profilePhoto: currentUser.photoURL,
username: username);
firestore.collection('users').doc(currentUser.uid).set(user.toMap(user));
}
}
This is the mistake in console:
lib/resources/firebase_methods.dart:32:17: Error: A value of type 'UserCredential' can't be assigned to a variable of type 'User'.
Sorry if I confused you, as I said, I am newbie. If you want any other informations please ask here.
For the first mistake , you defined a function void authenticateUser(User user, BuildContext context) so when you use it, it expects 2 arguments a User type object and a BuildContext object
Then you are calling this function in
void performLogin() {
_repository.signIn().then((User user) {
if (user != null) {
authenticateUser(user);
} else {
print('There was an error');
}
});
}
You are passing only the User object, missing the BuildContext
For GoogleSingIn this was my solution:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
//create user object based on FB json
User _userFromFirebaseUser(FirebaseUser user) {
return user != null
? User(uid: user.uid, emailVerified: user.isEmailVerified)
: null;
}
//auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
Future<User> singInUsingGoogle() async {
int age;
String email;
String name;
String lastname;
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleAuth.idToken, accessToken: googleAuth.accessToken);
final result = await _auth.signInWithCredential(credential);
FirebaseUser user = result.user;
print(result.user.providerData);
await DatabaseService(uid: user.uid).createUserData(
//user info
)

Cannot sign-in after signing out - Firebase Google Signin with Flutter

I am able to sign-in and sign-out using Google. However, when I sign back in, I am not redirected to the page that I have specified. It get's stuck on the Login Page.
Here's the onPressed method for the login button:
onPressed: () async {
await Provider.of<Auth>(context, listen: false).signInWithGoogle();
},
The signInWithGoogle() method is in the Auth class below.
Here's the Auth class:
class Auth with ChangeNotifier {
String _token;
String _userId;
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
bool get isAuth {
return token != null;
}
String get token {
if(_token != null)
return _token;
return null;
}
String get userId {
return _userId;
}
Future<void> signInWithGoogle() async {
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 authResult =
await _auth.signInWithCredential(credential);
final User user = authResult.user;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = _auth.currentUser;
assert(user.uid == currentUser.uid);
print('User is ' + user.displayName);
_token = await currentUser.getIdToken();
print('Token is ' + _token);
_userId = currentUser.uid;
notifyListeners();
}
Future<void> signOutGoogle() async {
await googleSignIn.signOut();
_token = null;
_userId = null;
notifyListeners();
print("User Sign Out");
}
Future<bool> tryAutoLogin() async {
//will implement later
return false;
}
}
Here's the main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => Auth(),
),
ChangeNotifierProxyProvider<Auth,Categories>(
create:null,
update:(ctx,auth, previousCategories) => Categories(auth.token, auth.userId)),
],
//The consumer ensures that the material app gets built whenever Auth object changes
child: Consumer<Auth>(builder: (ctx, auth, _) =>
MaterialApp(
title: 'MyShop',
theme: ThemeData(
textTheme: Theme.of(context).textTheme.apply(
bodyColor: Colors.black,
displayColor: Colors.black,
),
primaryColor: Colors.orange,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
),
home: auth.isAuth ? CategoriesScreen()
: FutureBuilder(
future: auth.tryAutoLogin(),
builder: (ctx, authResultSnapshot) =>
authResultSnapshot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: LoginPage(),
),
routes: {
CategoriesScreen.routeName: (ctx) => CategoriesScreen(),
LoginPage.routeName: (ctx) => LoginPage()
}
),
)
);
}
}
Here's the logout button:
ListTile(
leading: Icon(Icons.exit_to_app),
title: Text('Logout'),
onTap: () {
Provider.of<Auth>(context, listen:false).signOutGoogle();
Navigator.of(context).pushReplacementNamed(LoginPage.routeName);
},
),
When I sign-in for the first time, I get redirected to the CategoriesScreen() page. However, when log out and log back in, I do not get redirected.

Flutter : Save user id from firestore using Shared Preferences and retrieve the value into class

So first of all I'm new in Flutter. I want to use current sign in user id from firebase as filter from data that i want to show in apps.Please Help Me.
here is the user id from wrapper.dart I want to use.
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final User user = Provider.of<User>(context);
print(user.uid);
and here i want to pass the value as uid from database.dart
Stream<List<InitialRPP>> get dataInitRPP {
return dbRPP
.where('uid', isEqualTo: uid)
.snapshots()
.map(_initRPPFromSnapshot);
}
Here is the full source code
wrapper.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:rppapps/models/user.dart';
import 'package:rppapps/screens/authenticate/authenticate.dart';
import 'package:rppapps/screens/home/home.dart';
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final User user = Provider.of<User>(context);
print(user.uid);
// Login or Home
if (user == null) {
return Authenticate();
} else {
return Home();
}
}
}
database.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:rppapps/models/model.dart';
class DatabaseService {
// the code should be in here "String uid;" like that
//collection reference
final CollectionReference dbRPP = Firestore.instance.collection('rpp');
Future addinitialRPP(String uid, String nama, String tahun, String kelas,
String semester, String mapel, String materi) async {
return await dbRPP.add({
'uid': uid,
'nama': nama,
'tahun': tahun,
'kelas': kelas,
'semester': semester,
'mapel': mapel,
'materi': materi
});
}
List<InitialRPP> _initRPPFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return InitialRPP(
uid: doc.data['uid'] ?? '',
nama: doc.data['nama'] ?? '',
tahun: doc.data['tahun'] ?? '',
kelas: doc.data['kelas'] ?? '',
semester: doc.data['semester'] ?? '',
mapel: doc.data['mapel'] ?? '',
materi: doc.data['materi'] ?? '');
}).toList();
}
Stream<List<InitialRPP>> get dataInitRPP {
return dbRPP
.where('uid', isEqualTo: uid)
.snapshots()
.map(_initRPPFromSnapshot);
}
}
EDIT: (sign in sign out method and firebase_auth)
auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:rppapps/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// created user object based on FirebaseUser
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
// auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
// sign anon
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign with email and pass
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// register with email and pass
Future registerWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
pubspec.yaml
firebase_auth: ^0.14.0+5
cloud_firestore: ^0.12.9+4
provider: ^3.1.0
Try using onAuthStateChanged() instead. You can check if the user is logged in by adding this Stream to a Streambuilder. Any time the user logs out or in, the Stream automatically updates. Then wrap your Home widgets with a FutureBuilder and pass the currentUser() future. This will return a snapshot containing the user information, such as email and uid.
Finally, you can filter widgets by checking if the uid is the same as the given one. For example, if a user is admin or not.
wrapper.dart
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<FirebaseUser>(
stream: AuthService().authStateChanges(),
builder: (context, AsyncSnapshot snapshot) {
// if the stream has data, the user is logged in
if (snapshot.hasData) {
// isLoggedIn
return Home();
} else if (snapshot.hasData == false &&
snapshot.connectionState == ConnectionState.active) {
// isLoggedOut
return Authenticate();
} else {
return CircularProgressIndicator();
}
},
),
);
}
}
auth.dart
class AuthService {
final FirebaseAuth _firebaseInstance = FirebaseAuth.instance;
final CollectionReference _usersCollection =
Firestore.instance.collection("users");
// User State
Stream<FirebaseUser> authStateChanges() {
FirebaseAuth _firebaseInstance = FirebaseAuth.instance;
return _firebaseInstance.onAuthStateChanged;
}
// Current User
Future<FirebaseUser> currentUser() async {
FirebaseAuth _firebaseInstance = FirebaseAuth.instance;
return _firebaseInstance.currentUser();
}
// Sign Out
Future<void> signOut() async {
FirebaseAuth _firebaseInstance = FirebaseAuth.instance;
return _firebaseInstance.signOut();
}
// Sign In Anonymously
Future<AuthResult> signInAnon() async {
return await _firebaseInstance.signInAnonymously().catchError((error) {
print(error);
});
}
// Sign In With Email And Password
Future<AuthResult> signIn(String email, String password) async {
return await _firebaseInstance
.signInWithEmailAndPassword(email: email, password: password)
.catchError((error) {
switch (error.code) {
case "ERROR_INVALID_EMAIL":
print("ERROR_INVALID_EMAIL");
break;
case "ERROR_WRONG_PASSWORD":
print("ERROR_WRONG_PASSWORD");
break;
case "ERROR_USER_NOT_FOUND":
print("ERROR_USER_NOT_FOUND");
break;
case "ERROR_USER_DISABLED":
print("ERROR_USER_DISABLED");
break;
case "ERROR_TOO_MANY_REQUESTS":
print("ERROR_TOO_MANY_REQUESTS");
break;
case "ERROR_NETWORK_REQUEST_FAILED":
print("ERROR_NETWORK_REQUEST_FAILED");
break;
}
});
}
// Create User With Email And Password
Future<AuthResult> signUp(String email, String password) async {
return await _firebaseInstance
.createUserWithEmailAndPassword(email: email, password: password)
.catchError(
(error) {
switch (error.code) {
case "ERROR_INVALID_EMAIL":
print("ERROR_INVALID_EMAIL");
break;
case "ERROR_WEAK_PASSWORD":
print("ERROR_WEAK_PASSWORD");
break;
case "ERROR_EMAIL_ALREADY_IN_USE":
print("ERROR_EMAIL_ALREADY_IN_USE");
break;
case "ERROR_NETWORK_REQUEST_FAILED":
print("ERROR_NETWORK_REQUEST_FAILED");
break;
}
},
).then((user) {
if (user != null) {
_usersCollection.document(user.user.uid).setData(
{
"email": user.user.email,
"uid": user.user.uid,
},
);
return null;
} else {
return null;
}
});
}
}
authenticate.dart
class Authenticate extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(child: Text("Authenticate")),
// Sign In Button
RaisedButton(
onPressed: () => AuthService().signIn("testemail01#gmail.com", "password"),
child: Text("Sign In as user 01"),
),
RaisedButton(
onPressed: () => AuthService().signIn("testemail02#gmail.com", "password"),
child: Text("Sign In as user 02"),
)
],
);
}
}
home.dart
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder<FirebaseUser>(
future: AuthService().currentUser(),
builder: (context, snapshot) {
if (snapshot.hasData) {
String userEmail = snapshot.data.email;
String userUid = snapshot.data.uid;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(child: Text("Home")),
// Get Current User Email
Center(child: Text(userEmail)),
// Get Current User UID
Center(child: Text(userUid)),
// Filter By UID
Builder(
builder: (context) {
if (userUid == "X6Ibch8OwmZWrYIB1F3IPpbBQbk2") {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.admin_panel_settings),
Text("Admin"),
],
);
}
return Container();
},
),
// Sign Out Button
RaisedButton(
onPressed: () => AuthService().signOut(),
child: Text("Sign Out"),
)
],
);
} else {
return CircularProgressIndicator();
}
},
);
}
}

Resources