How to edit a user in flutter firestore - firebase

I have been learning how does flutter work with firestore and now I am working in user auth with password, email and username, when a user is created the email and password are saved with an uid but the username and the email(again) are saved in firestore with a different uid, by the way I have tried a lot of things to make it have the same id but I currently cant find the way. in addition to this, there is also a function that is supposed to edit the username and save those changes. The problem comes when trying to implement the edit functinality because the edit form doesnt return anything as an output except the loading screen, I think this error is happening because of the uids. How can I fix this problem?
models/user.dart
class CustomUser {
final String uid;
CustomUser({this.uid});
}
class UserData {
final String uid;
final String name;
UserData({this.uid, this.name});
}
models/username.dart
class Username {
final String name;
Username({this.name});
}
services/auth.dart
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on fb user
CustomUser _userFromFirebaseUser(User user) {
return user != null ? CustomUser(uid: user.uid) : null;
}
Stream<CustomUser> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
//signin email 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;
}
}
//signup
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
//signout
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
services/database.dart
class DatabaseService {
final String uid;
DatabaseService({this.uid});
final CollectionReference userCollection = FirebaseFirestore.instance.collection('usernames');
Future updateUserData(String name) async { // this is the function that has to edit the username
return await userCollection.doc(uid).set({
'name': name,
});
}
Future uploadUserInfo(userMap) async { // this function adds username and email to firestore
return await userCollection.doc(uid).set(userMap);
}
List<Username> _usernameListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return Username(
name: doc.data()['name'] ?? '',
);
}).toList();
}
// userData from snapshot
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.data()['name'],
);
}
Stream<List<Username>> get usernames {
return userCollection.snapshots().map(_usernameListFromSnapshot);
}
Stream<UserData> get userData {
return userCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
}
register.dart(code that registers the user with a username)
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password).then((val) {
Map<String, String> userInfoMap = {
"name": name,
"email": email,
};
databaseService.uploadUserInfo(userInfoMap);
});
if (result == null) {
setState(() {
error = 'please suply a valid email';
loading = false;
});
}
}
}),
editForm.dart
final _formKey = GlobalKey<FormState>();
String _currentName;
final user = Provider.of<CustomUser>(context);
StreamBuilder<UserData>(
stream: DatabaseService(uid: user.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData userData = snapshot.data;
return Form(
key: _formKey,
child: Column(
children: <Widget>[
Text('edit username!'),
SizedBox(
height: 30,
),
TextFormField(
// initialValue: userData.user gives a initial text to the input
validator: (val) => val.isEmpty ? 'Please enter a name' : null,
onChanged: (val) => setState(() => _currentName = val),
),
RaisedButton(
child: Text('Save'),
onPressed: () async {
if (_formKey.currentState.validate()) {
print('update if good');
await DatabaseService(uid: user.uid).updateUserData(
_currentName ?? userData.name,
);
}
Navigator.pop(context);
})
],
));
} else {
return Loading();
}
},
);
If you have any questions please let me know;)

In your register.dart, the registerWithEmailAndPassword method returns a User object which contains the uid internally created by FirebaseAuth however, it doesn't seem like you took used this uid to update your Firestore user document. I've implemented a sample of what should have been done below.
dynamic result = await _auth.registerWithEmailAndPassword(email, password).then((val) {
Map<String, String> userInfoMap = {
"name": name,
"email": email,
};
DatabaseService(uid: val.uid).uploadUserInfo(userInfoMap);
});
I just realized that your registerWithEmailAndPassword function returns a CustomUser instead of a Firebase User. I just modified it to make it work.
//signup
Future<User> registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
return result.user;
} catch (e) {
print(e.toString());
return null;
}
}
//editFrom.dart
//form validation function
Map<String, String> userMap = {'name': currentName};
await DatabaseService(uid: user.uid).uploadUserInfo(userMap);
Side note: when working with Futures, it helps if you specify the expected return type as this will help you with debugging. I've done it for the function above

Related

Set state inside auth class?

I have the following problem. I want the message to be the correct exception type. i can only use set state within my sign in (because my auth class is not a statlesswidget)class and pass a message there with set state(), but the same for all errors. I've been trying for 9 hours and I can't figure it out. Please help. so I just want the correct exception to be displayed.Something like „The Email adress is badly formated“.the problem is i it dont let me to set the error message be the real error message and i dont know how to fix it
Widget _buildLoginBtn() {
return Container(
padding: EdgeInsets.symmetric(vertical: 25.0),
width: double.infinity,
child: RawMaterialButton(
elevation: 5.0,
padding: EdgeInsets.all(15.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
fillColor: Colors.white,
child: Text(
'LOGIN',
style: TextStyle(
color: Color(0xFF527DAA),
letterSpacing: 1.5,
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
print('valid');
setState(() => loading = false);
dynamic result =
await _auth.signIN(email, password);
if (result == null) {
setState(() => error = 'Check your Input');
loading= false;
}
}
}),
);
}
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(), password: password)).user;
} catch (e) {
return null;
}
if (user != null) {
print(user);
}
return null;
}
So after im following # Gerpea advice I Get the following error when im just trying to catch the error without the statement on FIREBASEAUTHERROR and when im trying with the statement. When im trying to update my auth and cloud and core it gets me another error.And I can really say if the he ignored the catch block because it don't starts actually when im starting I get as I said before the error in console Im using:
cupertino_icons: ^1.0.2
firebase_auth: ^0.14.0+5
cloud_firestore: ^0.12.9+4
firebase_core_web: ^0.2.1+3
provider: ^4.3.3
flutter_svg: ^0.19.2+1
flutter_spinkit: "^4.1.2"
auto_size_text: ^2.1.0
firebase_core: ^0.4.0
get_it: ^5.0.6
The error ist this:
Invalid depfile: /Users/MYUSERNAME/Desktop/project neu2/flutter_application_2/.dart_tool/flutter_build/7e96e6ced6aa40f9bcd60c2328bbea3e/kernel_snapshot.d
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/js.dart:8:1: Error: Not found: 'dart:js'
export 'dart:js' show allowInterop, allowInteropCaptureThis;
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/js-0.6.3/lib/js_util.dart:8:1: Error: Not found: 'dart:js_util'
export 'dart:js_util';
^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/js_interop.dart:24:7: Error: Method not found: 'hasProperty'.
if (util.hasProperty(jsObject, 'toDateString')) {
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:39:26: Error: Method not found: 'getProperty'.
map[key] = dartify(util.getProperty(jsObject, key), customDartify);
^^^^^^^^^^^
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:65:17: Error: Method not found: 'newObject'.
var jsMap = util.newObject();
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:67:7: Error: Method not found: 'setProperty'.
util.setProperty(jsMap, key, jsify(value, customJsify));
../../../flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core_web-0.2.1+3/lib/src/interop/utils/utils.dart:73:12: Error: Method not found: 'allowInterop'.
OKafter trying the second correction that #Gerpea send I get the same error so I decide to update to the newest versions go auth.
No I got some problems but I think that's maybe be easyler to correct
but don't really how maybe you know?
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core_web/firebase_core_web_interop.dart';
import 'package:flutter_application_2/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
String error;
//create user obj based on FirebasedUser
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 in 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 in with passwort and email
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
//register with passwort an email
Future<String> signUp(String email, String password) async {
FirebaseUser user = (await _auth.createUserWithEmailAndPassword(
email: email, password: password)) .user;
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print(e.toString);
return null;
}
}
//sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
//resetpassword
Future<void> sendPasswordResetEmail(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
return null;
}
}
}
that's the exceptions
enter image description here
OK now it logs very good I just have 2 exceptions. Code looks like that:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_application_2/models/user.dart' as Model;
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
String error;
//create user obj based on FirebasedUser
Model.User _userFromFirebaseUser(Model.User user) {
return user != null ? Model.User(uid: user.uid) : null;
}
//auth change user stream
Stream<Model.User> get user {
return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
}
//sign in anon
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 passwort and email
Future<String> signIN(String email, String password) async {
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
//register with passwort an email
Future<String> signUp(String email, String password) async {
User user = (await _auth.createUserWithEmailAndPassword(
email: email, password: password)) .user;
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print(e.toString);
return null;
}
}
//sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
//resetpassword
Future<void> sendPasswordResetEmail(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
return null;
}
}
}
And EXCEptions like that:
enter image description here
#Gerpea
So here's my code
Future<String> signUp(String email, String password, String fullname,String user) async {
try {
( await _auth.createUserWithEmailAndPassword(
email: email.trim(), password: password,)).user.sendEmailVerification();
await DatbaseService(uid: user.uid).updateUserData('username', 'fullname', 'Passwort', 'Email');
} on FirebaseAuthException catch (e) {
And the method from YouTube:
Future registerWithEmailAndAPassword(String email, String,Passwort)async {
try{
AuthResult result = await.createUserWithEmailAndPassowrd(email:email,password:password);
FirebaseUser user =result.user;
await DatabaseService(uid:user.uid).updateUserData('0','new crew member',100);
return _userFromFirebaseUser(user);
}catch (e){
signInWithEmailAndPassword() method in case of error will throw a FirebaseAuthException which contain code field with error code.
The full list of errors for this method can be found here.
So you can rewrite you method a bit, to return an error message instead just null.
Future<String> signIN(String email, String password) async {
try {
User user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on FirebaseAuthException catch (e) {
switch(e.code) {
case 'user-not-found': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
}
return null;
}
Now this method return null if there is no error and String if some error occurs.
Use this in onPressed callback.
onPressed: () async {
if (_formKey.currentState.validate()) {
print('valid');
String authError = await _auth.signIN(email, password);
if (authError != null) {
setState(() => error = authError);
}
setState(() => loading = false);
}
}
firebase_auth: ^0.14.0+5
This is a bit outdated and has some problems, so it will be better if you
will upgrade your dependencies.
But if you can't upgrade. This should work.
Future<String> signIN(String email, String password) async {
try {
FirebaseUser user = (await _auth.signInWithEmailAndPassword(
email: email.trim(),
password: password,
)).user;
} on AuthException catch (e) {
switch(e.code) {
case 'ERROR_USER_NOT_FOUND': {
return 'No user found';
}
default: {
return 'Unexpected error!';
}
}
} catch(e) {
return 'Some error that FirebaseAuth do not catch'!;
}
return null;
}
List of error codes can be found here.

I have some problems in Flutter Firebase Login

I am coding an app for my company and I tried to add firebase authentication for login and registration to my app. The app shows no error and runs successfully.
But when a user tries to login with the wrong email and password, it is showing an internal flutter error instead of the toast I have programmed. And also I have used shared preferences to make users stay logged in.
So when a user tried to log in with the wrong credential it is showing an internal flutter error and when the app is re-opened, instead of going to the login screen, it is using the wrong credential and navigates user to Home Screen which is ridiculous.
These are the declared variables:
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final _formKey = GlobalKey<FormState>();
TextEditingController _emailcontroller = TextEditingController();
TextEditingController _passwordcontroller = TextEditingController();
bool passvis = true;
bool loading = false;
And this is the function for login:
Future loginForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
setState(() {
loading = true;
});
usersRef.child(firebaseUser.uid).once().then((DataSnapshot snap) {
if (snap.value != null) {
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
displayToast("Succesfully LoggedIn!", context);
} else {
firebaseAuth.signOut();
displayToast("No user found! Please try SignUp", context);
}
});
} else {
displayToast("Error Occured! Cannot log you in", context);
}
}
}
}
And for Registration the code is below:
Future validateForm() async {
FormState formSate = _formKey.currentState;
if (formSate.validate()) {
final User firebaseUser = (await firebaseAuth
.createUserWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text)
.catchError((errMsg) {
displayToast("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
Map userDataMap = {
"name": _namecontroller.text.trim(),
"email": _emailcontroller.text.trim(),
"phone": _phonecontroller.text.trim(),
};
usersRef.child(firebaseUser.uid).set(userDataMap);
displayToast("Succesfully Registered!", context);
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) {
return LocationHome();
}));
} else {
displayToast("User was unable to create", context);
}
}
}
}
The main.dart file is also coded correctly:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
SharedPreferences preferences = await SharedPreferences.getInstance();
var circle = preferences.getString("circle");
runApp(MaterialApp(
title: 'TaakStore',
home: circle == null ? Login() : Home(),
));
}
DatabaseReference usersRef =
FirebaseDatabase.instance.reference().child("users");
Dont worry about the displayToast function. It is a function manually created with flutter toast.
To display a toast, try the following:
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text
);
} on FirebaseAuthException catch (e) {
displayToast("Error: " + e.message.toString(), context);
print(e.message);
}
To check if the user is logged in or not use the following:
FirebaseAuth.instance
.authStateChanges()
.listen((User user) {
if (user == null) {
print('User is currently signed out!');
} else {
print('User is signed in!');
}
});
authStateChanges() is of type Stream<User> which will listen for any changes on the state of a user. So if user is logged in, it will return a valid user object and you can navigate to the home screen. Therefore no need to use shared preferences.
To display a toast
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _emailcontroller.text,
password: _passwordcontroller.text
);
} on FirebaseAuthException catch (e) {
displayToast("Error: " + e.message.toString(), context);
print(e.message);
}
To check if the user is logged in
//inside the main.dart in the "MaterialApp" widget
MaterialApp(home:buildHome(),)
buildHome(){return StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (snapshot.hasData) {
print(snapshot);
//if the user is logged in return what you want
return "";
} else {
//else return what you want also
return"";
}
},
);}

Check if phone exists before signup/signin - Flutter Phone Authentication [duplicate]

This question already exists:
Firebase Authentication using Phone number (Error: Missing Session Info)
Closed 2 years ago.
I want to check if phone exists before signing in or signing up a user. With email registration, I used the following and I was able to tell if an email exists or not.
final url =
'https://www.googleapis.com/identitytoolkit/v3/relyingparty/$verifyPassword?key={API_KEY}';
Similarly, for phone numbers, I used the following:
final url ='https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key={API_KEY}';
final response = await http.post(
url,
body: json.encode(
{
'phoneNumber': number
},
),
);
However, I am getting the following error message:
Extracted data is {error: {code: 400, message: MISSING_SESSION_INFO, errors: [{message: MISSING_SESSION_INFO, domain: global, reason: invalid}]}}
I want to know why does it work for email but not for phone registration?
Also, is this the right way to check if a phone exists?
Here's my full code:
enum Status { Uninitialized, Authenticated, Authenticating, Unauthenticated }
class AuthProvider with ChangeNotifier {
FirebaseAuth _auth = FirebaseAuth.instance;
User _user;
Status _status = Status.Uninitialized;
TextEditingController phoneNo;
String smsOTP;
String verificationId;
String errorMessage = '';
bool logedIn = false;
bool loading = false;
Status get status => _status;
TextEditingController address = TextEditingController();
AuthProvider.initialize() {
readPrefs();
}
Future signOut() async {
_auth.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
Future<void> readPrefs() async {
await Future.delayed(Duration(seconds: 3)).then((v) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
logedIn = prefs.getBool('logedIn') ?? false;
if (!logedIn) {
print('User is not logged in');
_status = Status.Unauthenticated;
} else {
print('User is logged in');
_user = _auth.currentUser;
_status = Status.Authenticated;
}
notifyListeners();
});
}
Future<void> verifyPhone(BuildContext context, String number,String password) async {
//To be used in the verifyPhone method
final PhoneCodeSent smsOTPSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsOTPDialog(context, number,password).then((value) {
_status = Status.Authenticated;
});
};
try {
await _auth.verifyPhoneNumber(
phoneNumber: number.trim(),
codeAutoRetrievalTimeout: (String verId) {
//Starts the phone number verification process for the given phone number.
//Either sends an SMS with a 6 digit code to the phone number specified, or sign's the user in and [verificationCompleted] is called.
this.verificationId = verId;
},
codeSent: smsOTPSent,
// timeout: const Duration(seconds: 20),
//If user is automatically verified (without having to type the code)
verificationCompleted: (AuthCredential credential) async {
Navigator.of(context).pop();
UserCredential result =
await _auth.signInWithCredential(credential);
User user = result.user;
if (user != null) {
//TO DO:// Here you need to save the phone and password to DB
print('Adding user to DB');
final url = 'https://mobile-12.firebaseio.com/users/$number.json';
try {
await http.post(
url,
body: json.encode({
'password': password,
'phoneNumber':user.phoneNumber,
}),
);
_status = Status.Authenticated;
} catch (error) {
print(error);
}
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
} else {
print("Error");
}
},
verificationFailed: (FirebaseAuthException exceptio) {
print('${exceptio.message} + something is wrong');
});
} catch (e) {
handleError(e, context,number,password);
errorMessage = e.toString();
notifyListeners();
}
notifyListeners();
}
Future<bool> smsOTPDialog(BuildContext context,String number,String password) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter SMS Code'),
content: Container(
height: 85,
child: Column(children: [
TextField(
onChanged: (value) {
this.smsOTP = value;
},
),
(errorMessage != ''
? Text(
errorMessage,
style: TextStyle(color: Colors.red),
)
: Container())
]),
),
contentPadding: EdgeInsets.all(10),
actions: <Widget>[
FlatButton(
child: Text("Confirm"),
textColor: Colors.white,
color: Colors.blue,
onPressed: () async {
final code = this.smsOTP.trim();
AuthCredential credential = PhoneAuthProvider.credential(
verificationId: verificationId, smsCode: code);
UserCredential result =
await _auth.signInWithCredential(credential);
User user = result.user;
if (user != null) {
print('user already exist');
// //TO DO:// Save the phone number and password to DB
print('Adding user to Db in the manual OTP route');
final url = 'https://mobile-12.firebaseio.com/users/$number.json';
try {
await http.post(
url,
body: json.encode({
'password': password,
'phoneNumber':user.phoneNumber,
}),
);
} catch (error) {
print('INSIDE ERROR');
print(error);
}
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("logedIn", true);
logedIn = true;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
loading = false;
notifyListeners();
} else {
print("No OTP was added");
loading = true;
notifyListeners();
Navigator.of(context).pop();
}
},
)
],
);
});
}
//Sign-In Method checks to see if a phone exists.
signIn(BuildContext context, String number, String password,AuthMode authMode) async {
try {
//Check to see if the phone number is available
final url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPhoneNumber?key=';
final response = await http.post(
url,
body: json.encode(
{
'phoneNumber': number
},
),
);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
print('Extracted data is ' + extractedData.toString());
//Register and send OTP if new user
if (extractedData == null && authMode == AuthMode.Signup) {
print('Inside NULL no errors');
// //Verify phone
verifyPhone(context, number, password);
}
//If tries to login but phone not available
else if(extractedData == null && authMode == AuthMode.Login)
{
_showErrorDialog('Phone number does not exist. Please Sign Up', context);
}
else if (extractedData['error'] != null) {
_showErrorDialog('Something went wrong! Please try again!', context);
}
//If someone signup but their phone already exist
else if(extractedData != null && authMode == AuthMode.Signup)
{
_showErrorDialog('Your phone already exists. Please Login!', context);
}
//If available, proceed to homepage
else {
print('User found');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
)));
}
} catch (e) {
handleError(e, context,number,password);
}
}
handleError(error, BuildContext context,String number,String password) {
errorMessage = error.toString();
print('ERROR IS ' + errorMessage);
notifyListeners();
}
Future<bool> _showErrorDialog(String message,BuildContext context) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text('An Error Occurred!'),
content: Text(message),
actions: <Widget>[
FlatButton(
child: Text('Okay'),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
),
);
}
}

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();
}
},
);
}
}

Failed to return to login page/screen after signing out (Not sure if sign out is successful or not)

I'm new in flutter and dealing with backend. I faced problem in signing out and I don't know how to fix it due to lack of experience. When I sign out, it would not return to the login screen (Authenticate). I'm not quite sure if the problem lies at the function I wrote at the wrapper or somewhere in auth.
The wrapper widget will be executed everytime the app runs:
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: new MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home: Wrapper(),
),
);
}
}
The wrapper code is as below:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
if (user == null) {
return Authenticate();
} else {
return MyBottomNavigationBar();
}
}
}
Sign out button function:
onPressed: () async {
await _auth.signOut();
print('signing out');
},
Auth code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:mudah_replica/models/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//Create 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((FirebaseUser user) => _userFromFirebaseUser(user));
.map(_userFromFirebaseUser);
}
//Sign in anonymously
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
return user;
} catch(e) {
print(e.toString());
return null;
}
}
//Sign in with Email & Password
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 & Password
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('Fail to sign out');
print(e.toString());
return null;
}
}
}
in your wrapper class, you are returning auth widget instead of navigate to the right screen, so it doesn't route. Instead, you might wanna navigate to the Auth screen. Do something like this:
onPressed: () async {
await _auth.signOut();
Navigator.push(context,
MaterialPageRoute(builder: (context) => Authenticate())
},

Resources