First Sorry about my bad English and I just started to learn Flutter.
So I want to get all the informations in Firestore and I cant solve these problems.
Question 1:
If i click the select button, Cupertinopicker will show up and the result will show right next to the button. So If I pick b, i want the result sended to the Firestore. and I have no idea how i can...with the CupertinoPicker...
I would also like to know how i can use the validator and show the error sign too
enter image description here
This is the code below with the Cupertinopicker. I want the
Text(_countryType[_selectedIndex] sendend to Firebase.
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CupertinoButton(
borderRadius: BorderRadius.circular(29.0),
color: kPrimaryColor,
padding: const EdgeInsets.all(12.0),
child: Text(
"select",
style: TextStyle(fontSize: 16.0),
),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 170.0,
child: CupertinoPicker(
scrollController:
new FixedExtentScrollController(
initialItem: _selectedIndex,
),
itemExtent: 32.0,
onSelectedItemChanged: (int index) {
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
children: new List<Widget>.generate(
_countryType.length, (int index) {
return new Center(
child: new Text(_countryType[index]),
);
})),
);
});
},
),
Container(
margin: EdgeInsets.symmetric(vertical: 17),
width: 70,
child: Center(
child: Text(
_countryType[_selectedIndex],
style: TextStyle(fontSize: 16.0),
),
),
),
SizedBox(
height: 20.0,
),
],
),
Question2: I want all email, password, name, alphabet(the one with the cupertinopicker) sended to the firestore User. So i want to put it in [User- uid- fields ]I'm also stucked here too.
This is the Signup button below.
Container(
margin: EdgeInsets.symmetric(vertical: 10),
width: size.width * 0.8,
child: ClipRRect(
borderRadius: BorderRadius.circular(29),
child: FlatButton(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 40),
color: kPrimaryColor,
onPressed: () async {
try {
FirebaseUser user = (await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
))
.user;
if (user != null) {
UserUpdateInfo updateUser = UserUpdateInfo();
updateUser.displayName = _usernameController.text;
user.updateProfile(updateUser);
Navigator.of(context).pushNamed(AppRoutes.authLogin);
}
} catch (e) {
print(e);
_usernameController.text = "";
_passwordController.text = "";
_repasswordController.text = "";
_emailController.text = "";
}
setState(() {
saveAttempted = true;
});
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
}
},
child: Text(
"Sign Up",
style: TextStyle(color: Colors.white),
),
),
),
),
Which code do I need to use....
It would be super helpful if someone help me..Im so stressed out.
Thank you very much
I am assuming that you are aware of the basics of how to use Firebase with Flutter.
For the first question, all you need to do is call a function inside
onSelectedItemChanged: (int index) {
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
What happens here is, whenever you select an item. onSelectedItemChanged is called. So all you need to do is call a function here
Example -
onSelectedItemChanged: (int index) {
addToFirebase(_countryType[_selectedIndex]);
setState(() {
_country = _countryType[index];
_selectedIndex = index;
});
},
For your second question, Firebase authentication doesn't work like that. User details are stored in the Authentication area of Firebase. You cannot see the password as well. To store the country type attached with the user, you can use the User's Id as the key as it will be unique.
FirebaseUser user = (await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
))
.user;
String uid = user.uid;
Related
Trying to get current user info after creating a new user but getting this error " The function can't be unconditionally invoked because it can be 'null' " while trying to invoke ".currentUser()" method how to fix this?
here is the code the error occurs when trying to call " final user=await _auth.currentUser();"
enter code here
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class RegistrationScreen extends StatefulWidget {
#override
_RegistrationScreenState createState() => _RegistrationScreenState();
}
class _RegistrationScreenState extends State<RegistrationScreen> {
final _auth =FirebaseAuth.instance;
late String eMail;
late String password;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
SizedBox(
height: 48.0,
),
TextField(
onChanged: (value) {
//Do something with the user input.
eMail=value;
},
),
SizedBox(
height: 8.0,
),
TextField(
onChanged: (value) {
//Do something with the user input.
password=value;
},
),
SizedBox(
height: 24.0,
),
Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Material(
color: Colors.blueAccent,
borderRadius: BorderRadius.all(Radius.circular(30.0)),
elevation: 5.0,
child: MaterialButton(
onPressed: () async {
try{
final _newUser= await _auth.createUserWithEmailAndPassword(email: eMail, password: password);
if(_newUser!=null)
{
final user=await _auth.currentUser();
}
}
catch(e)
{
print(e);
}
},
minWidth: 200.0,
height: 42.0,
child: Text(
'Register',
style: TextStyle(color: Colors.white),
),
),
),
),
],
),
),
);
}
}
solved it the problem was i was calling "final user =_auth.currentUser()" function which had been changed to "final user =_auth.currentUser" currentUser was a getter and also no need of await keyword and to get email ,uid etc from user we should check
if user is null then acess email and uid etc.
enter code here
final _newUser= await _auth.createUserWithEmailAndPassword(email: eMail, password: password);
if(_newUser!=null)
{
final user =_auth.currentUser;
if(user!=null)
{
final email = user.email;
print(email);
}
}
As the error says, you should add a null check as below:
filan user = await _auth!.currentUser();
Because _auth can be null. Also you can use this code:
filan user = await _auth?.currentUser() ?? User(); // the name of user class
In my app, I have a login page connected to Firebase. I can successfully log in but when logging in, I want to display a CircularProgressIndicator until login is a success.
void signIn(String email, String password) async {
if (_formKey.currentState!.validate()) {
await _auth
.signInWithEmailAndPassword(email: email, password: password)
.then((_userDoc) => {
checkUserType(_userDoc.user!.uid),
})
.catchError((e) {
print('Error');
);
});
}
}
create a isLoading variable, set its state to true at the start of the sign-in, and false after the promise has been fulfilled.
then show the CircularProgressIndicator while isLoading = true
This will replace login button with CircularProgressIndicator while loading.
void signIn() async {
setState(() {
isLoading = true;
});
Future.delayed(Duration(seconds: 1)).then((value) {
/// loginOperationhere
//end of login set false, also include on catch method
setState(() {
isLoading = false;
});
});
}
bool isLoading = false; // on state class level
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
isLoading
? CircularProgressIndicator()
: ElevatedButton(
onPressed: () {
signIn();
},
child: Text("login"),
)
],
));
}
}
Try below code hope its helpful to you.
Create bool variable
bool _isLoading = false;
Your Widget:
Center(
child: !_isLoading
? Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
// ignore: deprecated_member_use
child: ElevatedButton(
child: Text(
'Sign In',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
onPressed: () {
// Your Login function call
setState(() {
_isLoading = true;
});
},
),
)
: CircularProgressIndicator(),
),
Your Widget using Center:
!_isLoading
? Center(
child: Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
padding: EdgeInsets.symmetric(horizontal: 15.0),
margin: EdgeInsets.only(top: 15.0),
// ignore: deprecated_member_use
child: ElevatedButton(
child: Text(
'Sign In',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
textAlign: TextAlign.center,
),
onPressed: () {
// Your Login function call
setState(() {
_isLoading = true;
});
},
),
),
)
: Center(
child: CircularProgressIndicator(),
),
Your result screen before pressed on button ->
Your result screen after button pressed->
I'm working on a project with Firebase (Realtime database). In this project I will have a main screen with will have several buttons according to the user. The Buttons info are going to be stored inside the realtime database. This is basically a Home Automation project.
This is how my db looks:
The quantity, means how many buttons does that user have. button1 and button2 have the button characteristics. So what I'm attempting to do is.
When the user logs in. I have a Streambuilder that will check if the quantity has data. If I has if will run inside a For loop which will create the buttons in the user screen.
I having problem getting the specific values from the database, for example, getting the quantity and storing into a variable in the main screen.
This is how I'm attempting to get the quantity (I will use this code for getting other values too, later on) but it isn't working:
Future<int> receive_quantity() async{
final FirebaseUser user = await _auth.currentUser();
var snapshot = databaseReference.child(user.uid+"/buttons"+"/quantity").once();
var result;
await snapshot.then((value) => result = value);
print(result);
return result;
}
Error that I get:
_TypeError (type 'DataSnapshot' is not a subtype of type 'FutureOr<int>')
My StreamBuilder:
body: StreamBuilder(
stream: _auth.getButtonQuantity(),
initialData: 0,
builder: (context, snapshot) {
if (snapshot.hasError || snapshot.hasError){
return Container(color: Colors.red);
}
if (!snapshot.hasData || !snapshot.hasData){
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasData || snapshot.hasData){
return GridView.count(
padding: EdgeInsets.all(15),
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
crossAxisCount: 3,
children: [
for (int i = 0; i < buttonquant; i++){
Button(),
},
GestureDetector(
onTap: () async{
_auth.receive_quantity();
},
child: Container(
color: Colors.black,
width: 150,
height: 150,
child: Icon(Icons.add, color: Colors.white,),
),
),
],
);
}
}
),
My Button:
class Button extends StatelessWidget {
const Button({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
},
child: Container(
width: 150,
height: 150,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(15)
),
child: Stack(
children: [
Positioned(
top: 10,
left: 10,
child: Icon(
Icons.lightbulb,
size: 35,
color: Colors.white,
),
),
Positioned(
top: 95,
left: 15,
child: Text("Televisao", style: TextStyle(color: Colors.white),),
),
],
),
),
);
}
}```
What you need to do is you need to get the value of the snapshot not using it directly:
Future<int> receive_quantity() async{
final FirebaseUser user = await _auth.currentUser();
var snapshot = await databaseReference.child(user.uid+"/buttons"+"/quantity").once();
var result = snapshot.value; //get the value here
print(result);
return result;
}
This is how you get the value in general:
databaseReference.once().then((DataSnapshot snapshot) {
print('Data : ${snapshot.value}');
});
If you would like some context I asked a similar question here. In my flutter app you are able to send emails
static getEmailCredentials(String email1, String password1) {
email = email1;
passw = password1;
}
sendMail() async {
String username = email;//gets email from db
String password = passw;//gets password for email from db
final SmtpServer = gmail(username, password); //fix one day
final message = Message()
..from = Address(username)
..recipients.add("xxx#gmail.com")
..subject = "From "+name //need name here from db
..html = "<h3>" + emailContent.text + "</h3>";
try {
final SendReport = await send(message, SmtpServer);
Fluttertoast.showToast(
msg: "Message sent! Hang in there!",
gravity: ToastGravity.CENTER,
);
} on MailerException catch (e) {
e.toString();
Fluttertoast.showToast(
msg: "Message failed to send! Try again?",
gravity: ToastGravity.CENTER,
);
}
}
}
As seen above. I know it's probably not the best to store the email and password but it works (well it would work if the data came in time). So my problem is I'll run this function at the beginning of the app but sometimes it won't load in on time.
UI Code:
class EmergencyReport extends StatelessWidget {
EmergencyReport();
static String email;
static String passw;
final TextEditingController emailContent = TextEditingController();
#override
Widget build(BuildContext context) {
getEmailCredentialsF();//function that calls to db
DateTime now = DateTime.now();
DateTime weekAgo = now.subtract(new Duration(days: 7));
DateFormat formadate = DateFormat('dd-MM');
String formatedDate = formadate.format(now); // current date formatted
String weekAgoForm =
formadate.format(weekAgo); // date from week ago formatted
countDocuments();
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.blueGrey,
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Align(
alignment: Alignment.topLeft,
child: Container(
width: 54,
margin: EdgeInsets.only(top: 44),
child: FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Column(
children: <Widget>[Icon(Icons.arrow_back_ios)],
),
),
),
),
Text(
"Emergency Report",
style: new TextStyle(
color: Colors.white,
fontSize: MediaQuery.of(context).size.width / 10,
),
),
Card(
margin: EdgeInsets.only(top: 30),
color: Colors.white,
child: Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
controller: emailContent,
maxLines: 8,
decoration: InputDecoration.collapsed(
hintText: "Enter what happened here..."),
),
)),
Container(
width: 260,
height: 70,
padding: EdgeInsets.only(top: 20),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),
),
child: Text(
"Send",
style: new TextStyle(
color: Colors.white,
fontSize: 38.0,
),
),
color: Colors.grey[850],
onPressed: () {
if (emailContent.text != "") {
sendMail();
Navigator.of(context).pop();
} else {
Fluttertoast.showToast(
msg: "You need to put a message!",
gravity: ToastGravity.CENTER,
);
}
},
),
),
],
),
),
),
),
);
}
void getEmailCredentialsF() {
print("Attemping to get email!");
final firestoreInstance = FirebaseFirestore.instance;
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
firestoreInstance.collection("SendMailCredentials").doc("w1HsHFRgq7Oc3X9xUEnH").get().then((value) {
EmergencyReport.getEmailCredentials((value.data()["email"]),(value.data()["password"]));
});
}
Is there a way to make the code wait for that information to be gathered from the db before running the rest? I've tried await and async and future builders (could have used them wrong I am fairly new to flutter)
Thank you for all the help you give
Pic of UI if it helps UI
yesterday I've answered you this
FutureBuilder<DocumentSnapshot>(
future: firestoreInstance.collection("Users").doc(uid).get(),
builder: (_,snap){
return snap.hasData ? Text(snap.data.data()["firstName"]):CircularProgressIndicator();
},)
now implement the same like
Lets say you have a Object which you keep saperate from UI
class MyDB{
//...
}
and you need to get document in users collection
class MyDB{
MyDB();
Map<String,dynamic> userData;
Future<void> getUser() async {
userData = //...set
}
}
and you want to get something else
class MyDB{
MyDB();
Map<String,dynamic> userData;
Map<String,dynamic> someThingElse;
Future<void> getUser() async {
userData = //...set
}
Future<void> getSomeThingElse() async {
someThingElse = //...set
}
}
and you want to wait for all these data to be available before you show anything
class MyDB{
MyDB();
Map<String,dynamic> userData;
Map<String,dynamic> someThingElse;
Future<void> getUser() async {
userData = //...set
}
Future<void> getSomeThingElse() async {
someThingElse = //...set
}
Future getEveryThing() async {
await getUser();
await getSomeThingElse();
}
}
now use that getEverything future in UI
final myDB = MyDB();
build(){
return FutureBuilder<bool>(
future: myDB.getEveryThing(),
builder: (_,snap){
if(snap.hasData){
//myDB.userData and myDB.someThingElse will not be null
}
//if we are still waiting for the data
return CircularProgressIndicator();
},);
}
i have developed an login page,if the email and password matches from the database it successfully login's and moves to the new page,but if its wrong i want to display an error message email or password doesn't match.
Here's my code:
class _AdminLoginState extends State<AdminLogin> {
String _username, _password;
TextEditingController _email = TextEditingController();
final GlobalKey<FormState> _formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LOGIN'),
backgroundColor: Colors.indigo[900],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 50),
child: SizedBox(
height: 150.0,
width: 300,
child: Image.asset("assets/admin.png",
fit: BoxFit.contain,),
),
),
Container(
child: Text("ADMIN",style: TextStyle(fontSize: 15,fontWeight: FontWeight.bold,color: Colors.indigo),),
),
Container(
padding: const EdgeInsets.only(bottom: 50),
child: Column(
children: <Widget>[
SingleChildScrollView(
child: Form(
key: _formkey,
child: Column(
children: <Widget>[
SizedBox(
height: 60,
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: false,
keyboardType: TextInputType.emailAddress,
validator:(input){
if(input.isEmpty){
return 'please type username';
}
return null;
},
onSaved: (input) => _username =input ,
decoration: InputDecoration(
labelText: 'Email',
hintText: "Email",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 400,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: true,
validator:(input){
if(input.isEmpty){
return 'please type Password';
}
return null;
},
onSaved: (input) => _password =input ,
decoration: InputDecoration(
labelText: 'Password',
hintText: "Password",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: RaisedButton(
onPressed: login,
textColor: Colors.white,
color: Colors.indigo[900],
child: Text('Login'),
),
)
],
),
),
),
],
),
),
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
print(e.message);
}
}
}
}
it will be really helpful if someone also helps me in validating the right email format and give give the proper validation for password
signInWithEmailAndPassword() returns an exception with a special code if the attempt is unsuccessful.
In order to print a message you need to add a catch block to your signInWithEmailAndPassword() method. Then you can use the error message.
Example:
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
alert('Wrong password.');
} else {
alert(errorMessage);
}
console.log(error);
});
For security purposes I would suggest combining some of the messages together instead of giving a possible attacker a hint about if the email is already in the system or not.
I do not know how to use flutter so I can only give an idea;
In here you are directly trying to get the user from the method.
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Instead I would suggest using something like this (this is angular but I think you can easily apply to flutter with some modification)
final FirebaseUser user;
await firebase.auth().signInWithEmailAndPassword(email, password)
.then((data) => {
this.user = data.user;
})
.catch((error) => {
switch (error.code) {
case "auth/invalid-email":
case "auth/wrong-password":
case "auth/user-not-found":
{
this.accountErrorMessage = "Wrong email address or password.";
break;
}
case "auth/user-disabled":
case "user-disabled":
{
this.accountErrorMessage = "This account is disabled";
break;
}
}
You can find which kind of errors it may return from here:
https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#signinwithemailandpassword
Use errortext in InputDecoration
here is demo
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'email',
errorText: loginfail ? 'email not match' : null,
),
),
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'password',
errorText: loginfail ? 'password not match' : null,
),
),
RaisedButton(
onPressed: () {
login();
},
child: Text('Submit'),
textColor: Colors.white,
color: Colors.blueAccent,
)
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
if(!user.uid.isEmpty()){
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}else{
setState((){
loginfail = true; //loginfail is bool
});
}
}catch(e){
print(e.message);
}
}
hope it helps..
Following #Jaydeepchatrola answer's
I used a try catch block and checked if password was invalid or email, for better results!
try {
setState(() {
wrongEmail = false;
wrongPassword = false;
});
final newUser = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, Done.id);
}
} catch (e) {
print(e.code);
if (e.code == 'ERROR_WRONG_PASSWORD') {
setState(() {
wrongPassword = true;
});
} else {
setState(() {
emailText = 'User doesn\'t exist';
passwordText = 'Please check your email';
wrongPassword = true;
wrongEmail = true;
});
}
}
You need to catch the specific error. I had the problem by myself, with this code I solved the problem.
try {
final user = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (user != null) {
Navigator.pushNamed(context, HomeScreen.id);
}
} on auth.FirebaseAuthException catch (e) {
//Here you catch the specific error
if (e.code == 'wrong-password') {
//The thing that should happen if the password is incorrect
//In my case it will the change the hinttext
setState(() {
hintTextPassword = 'Password incorrect. Please try again';
passwordHintColor = Colors.red;
});
} else if (e.code == 'user-not-found') {
setState(() {
hintTextEmail = 'No user found for that email.';
emailHintColor = Colors.red;
});
}
} catch (e) {
print(e);
}
add rflutter_alert: ^2.0.4 in your project file pubspec.yaml under dependencies: and save it
add import 'package:rflutter_alert/rflutter_alert.dart'; in your file of your auth screen
add
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
in catch(e){}
like that:
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
}
}