Related
My Flutter is not able to connect to my Cloud Firestore. Everything works fine, I can register, I can login, and the user is saved in the auth in Firebase. But the Cloud Firestore is not recieving any data from the registration_page.dart
My code to add the user to firestore
// Adding User to Cloud Firestore
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
return users
.add({
'email': email,
'password': password,
'confirmPassword': confirmPassword
})
.then((value) => print('User Added'))
.catchError((error) => print('Failed to Add user: $error'));
}
This is my onPressed for the signUpButton
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (_formKey.currentState!.validate()) {
setState(() {
email = emailController.text;
password = passwordController.text;
confirmPassword = confirmPasswordController.text;
passwordRegistration();
addUser();
clearText();
});
}
},
This is my full code of registration_page.dart
// ignore_for_file: prefer_const_constructors, avoid_print
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:list_list_2/constants/color_constant.dart';
import 'package:list_list_2/page/login/login_page.dart';
class RegistrationPage extends StatefulWidget {
const RegistrationPage({Key? key}) : super(key: key);
#override
State<RegistrationPage> createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
//Form Key
final _formKey = GlobalKey<FormState>();
var email = "";
var password = "";
var confirmPassword = "";
final emailController = TextEditingController();
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
#override
void dispose() {
// Clean up the controller when the widget is disposed.
emailController.dispose();
passwordController.dispose();
confirmPasswordController.dispose();
super.dispose();
}
clearText() {
emailController.clear();
passwordController.clear();
confirmPasswordController.clear();
}
passwordRegistration() async {
if (password == confirmPassword) {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
print(userCredential);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: kSoftLimeGreen,
content: Text(
"Registered Successfully. Please Login..",
style: TextStyle(fontSize: 20.0),
),
),
);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => LoginPage(),
),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print("Password Provided is too Weak");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: lightOrange,
content: Text(
"Password Provided is too Weak",
style: GoogleFonts.dongle(fontSize: 18.0, color: blackColor),
),
),
);
} else if (e.code == 'email-already-in-use') {
print("Account Already exists");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: lightOrange,
content: Text(
"Account Already exists",
style: GoogleFonts.dongle(fontSize: 18.0, color: blackColor),
),
),
);
}
}
} else {
print("Password and Confirm Password doesn't match");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: lightOrange,
content: Text(
"Password and Confirm Password doesn't match",
style: GoogleFonts.dongle(fontSize: 16.0, color: blackColor),
),
),
);
}
}
// Adding User to Cloud Firestore
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
return users
.add({
'email': email,
'password': password,
'confirmPassword': confirmPassword
})
.then((value) => print('User Added'))
.catchError((error) => print('Failed to Add user: $error'));
}
#override
Widget build(BuildContext context) {
//Email Field
final emailField = TextFormField(
autofocus: false,
controller: emailController,
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Email';
} else if (!value.contains('#')) {
return 'Please Enter Valid Email';
}
return null;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
//Password Field
final passwordField = TextFormField(
autofocus: false,
controller: passwordController,
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Password';
}
return null;
},
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(Icons.vpn_key),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
//Confirm Password
final confirmPasswordField = TextFormField(
autofocus: false,
controller: confirmPasswordController,
obscureText: true,
validator: (value) {
if (confirmPasswordController.text != passwordController.text) {
return "Password Don't Match!";
}
return null;
},
textInputAction: TextInputAction.done,
decoration: InputDecoration(
prefixIcon: Icon(Icons.vpn_key),
contentPadding: EdgeInsets.fromLTRB(20, 15, 20, 15),
hintText: "Confirm Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
);
//Sign Up Button
final signUpButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(50),
child: Container(
width: MediaQuery.of(context).size.width,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
gradient: LinearGradient(
colors: const [kDarkModerateCyan, kModerateCyan],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
child: Material(
borderRadius: BorderRadius.circular(50),
color: Colors.transparent,
child: Center(
child: MaterialButton(
child: Text(
"SignUp",
textAlign: TextAlign.center,
style: GoogleFonts.dongle(
fontSize: 28,
color: defaultColor,
fontWeight: FontWeight.bold,
),
),
padding: EdgeInsets.fromLTRB(20, 10, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (_formKey.currentState!.validate()) {
setState(() {
email = emailController.text;
password = passwordController.text;
confirmPassword = confirmPasswordController.text;
passwordRegistration();
addUser();
clearText();
});
}
},
),
),
),
),
);
//Reset Button
final resetButton = Material(
elevation: 5,
borderRadius: BorderRadius.circular(50),
child: Container(
width: MediaQuery.of(context).size.width,
height: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: greyColor,
),
child: Material(
borderRadius: BorderRadius.circular(50),
color: Colors.transparent,
child: Center(
child: MaterialButton(
child: Text(
"Reset",
textAlign: TextAlign.center,
style: GoogleFonts.dongle(
fontSize: 28,
color: defaultColor,
fontWeight: FontWeight.bold,
),
),
padding: EdgeInsets.fromLTRB(20, 10, 20, 15),
minWidth: MediaQuery.of(context).size.width,
onPressed: () => {clearText()},
),
),
),
),
);
return Scaffold(
backgroundColor: whiteColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: kVeryDarkCyan,
),
onPressed: () {
//passing this to our root
Navigator.of(context).pop();
},
),
),
body: Stack(
children: <Widget>[
SingleChildScrollView(
child: Column(
children: [
Material(
borderRadius: BorderRadius.circular(55),
color: kDarkModerateCyan,
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 180,
child: SvgPicture.asset(
"assets/logo.svg",
fit: BoxFit.contain,
),
),
emailField,
SizedBox(
height: 15,
),
passwordField,
SizedBox(
height: 15,
),
confirmPasswordField,
SizedBox(
height: 15,
),
signUpButton,
SizedBox(
height: 15,
),
resetButton,
SizedBox(
height: 15,
),
],
),
),
),
),
],
),
),
],
),
);
}
}
And this is my GitHub https://github.com/MonsterEat90/List-List
In my app, any user can add an Ad and, in home screen, with all Ads showing up in a list view, I get info of every single Ad from the table of cars in firebase; but I want to show the profile images of this user by sending the user id and getting the image from users table.
My function to get data from firebase:
Future<DocumentSnapshot> getAdData(String uid)async{
return await FirebaseFirestore.instance.collection('users').doc(uid).
get();
}
My homescreen:
import 'package:cargaaaalery/functions.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'globalVar.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
FirebaseAuth auth = FirebaseAuth.instance;
String? username;
String? userNumber;
String? carPrice;
String? carModel;
String? description;
String? urlImage;
String? carLocation;
String? carColor;
QuerySnapshot? cars;
// DocumentSnapshot? users;
String? usersImg;
CarMethods carobj = new CarMethods();
dynamic carUserId;
Future<bool?> showDialogForAddingData() async {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"post a new AD",
style: TextStyle(
fontSize: 22, fontFamily: "Bebas", letterSpacing: 2),
),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
decoration: InputDecoration(hintText: "Enter your number"),
onChanged: (val) {
userNumber = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car price"),
onChanged: (val) {
carPrice = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car name"),
onChanged: (val) {
carModel = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Color"),
onChanged: (val) {
carColor = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car description"),
onChanged: (val) {
description = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Image"),
onChanged: (val) {
urlImage = val;
},
),
SizedBox(
height: 5,
),
TextField(
decoration:
InputDecoration(hintText: "Enter your car Location"),
onChanged: (val) {
carLocation = val;
},
),
SizedBox(
height: 5,
),
],
),
),
actions: [
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text("Cancel"),
),
ElevatedButton(
onPressed: () {
Map<String, dynamic> carData = {
'username': getUsername,
'uId': userId,
'userNumber': this.userNumber,
'carPrice': this.carPrice,
'carModel': this.carModel,
'carLocation': this.carLocation,
'carColor': this.carColor,
'description': this.description,
'urlImage': this.urlImage,
'imgPro': userImageUrl,
'time': DateTime.now(),
};
carobj.addData(carData).then((value) {
print("data add successfuly");
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
}).catchError((onError) {
print(onError);
});
},
child: Text("Add Now"),
),
],
);
});
}
getimage()async{
await carobj.getAdData(carUserId).then((res){
setState(() {
usersImg=(res.data() as Map)['imgPro'].toString();
});
});
}
getMyData() async {
await FirebaseFirestore.instance
.collection('users')
.doc(userId)
.get()
.then((result) {
setState(() {
userImageUrl = result.data()!['imgPro'];
getUsername = result.data()!['username'];
});
});
}
#override
void initState() {
super.initState();
userId = FirebaseAuth.instance.currentUser!.uid;
userEmail = FirebaseAuth.instance.currentUser!.email!;
print("userid is $userId and email is $userEmail");
carobj.getData().then((results) {
setState(() {
cars = results;
});
});
getMyData();
}
#override
Widget build(BuildContext context) {
Widget? showCarsList() {
if (cars != null) {
return ListView.builder(
itemCount: cars!.docs.length,
padding: EdgeInsets.all(8),
itemBuilder: (context,index) {
carUserId= (cars!.docs[index].data() as Map)['uId'];
getimage();
return Card(
child: Column(
children: [
ListTile(
leading:GestureDetector(
onTap: (){},
child: Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
) ,
title: GestureDetector(
onTap: (){
},
child: Text((cars!.docs[index].data() as Map)['username'].toString()),
),
subtitle: GestureDetector(
onTap: (){},
child:
Row(
children: [
((cars!.docs[index].data() as Map)['carLocation'] != null)
? Text((cars!.docs[index].data() as Map)['carLocation'] ,
style:TextStyle(color: Colors.black.withOpacity(0.6))
):Text("unknown" ,
style:TextStyle(color: Colors.black.withOpacity(0.6))
),
SizedBox(width: 4.0,),
Icon(Icons.location_pin,color: Colors.grey,)
],
),
),
trailing:
(cars!.docs[index].data() as Map)['uId']==userId?
Row(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: (){
},
child: Icon(Icons.edit),
),
SizedBox(width: 20,),
GestureDetector(
onDoubleTap: (){
},
child: Icon(Icons.delete_forever),
),
],
):
Row( mainAxisSize: MainAxisSize.min,
children: [],
)
,
)
],
),
);
},
);
}
}
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.refresh, color: Colors.white),
onPressed: () {},
),
actions: [
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.person,
color: Colors.white,
),
)),
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.search,
color: Colors.white,
),
)),
TextButton(
onPressed: () {},
child: Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.login_outlined,
color: Colors.white,
),
))
],
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blueAccent, Colors.redAccent])),
),
title: Text("home page"),
),
body: Center(
child: showCarsList(),
),
floatingActionButton: FloatingActionButton(
tooltip: 'add post',
child: Icon(Icons.add),
onPressed: () {
showDialogForAddingData();
},
),
);
}
}
Where I get image (from home screen code):
getimage()async{
await carobj.getAdData(carUserId).then((res){
setState(() {
usersImg=(res.data() as Map)['imgPro'].toString();
});
});
}
Where I set image to listview (from home screen code):
#override
Widget build(BuildContext context) {
Widget? showCarsList() {
if (cars != null) {
return ListView.builder(
itemCount: cars!.docs.length,
padding: EdgeInsets.all(8),
itemBuilder: (context,index) {
carUserId= (cars!.docs[index].data() as Map)['uId'];
getimage();
return Card(
child: Column(
children: [
ListTile(
leading:GestureDetector(
onTap: (){},
child: Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
) ,
Output of the code:
You're getting the behaviour because you are calling setState in the build method. This causes the build method to get called again and it makes the network request and calls the build method again...
You can fix this by using a FutureBuilder to get the data. Follow these steps:
Update the getimage method to return the image url instead of changing the state:
Future<String> getimage() async {
var res = await carobj.getAdData(carUserId);
return (res.data() as Map)['imgPro'].toString();
}
Declare a variable _imageFuture to hold the result of the getimage network request:
Future<String> _imageFuture;
Assign the getimage method to _imageFuture in the initState:
#override
void initState() {
...
_imageFuture = getimage();
}
Update the ListTile to use a FutureBuilder which gets the image from the _imageFuture Future:
ListTile(
leading:GestureDetector(
onTap: (){},
child: FutureBuilder<String>(
future: _imageFuture,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
} else {
String usersImg = snapshot.data;
return Container(
width: 60,
height:60,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
((usersImg!)),scale: 0.9),
fit:BoxFit.fill
)
),
),
);
}
}
),
),
)
I am trying to built a social app,Where I am going to post images.When I run the code, I am facing some issues in retrieving data from the firebase.
firebase_auth: ^3.1.1
firebase_core: ^1.6.0
google_sign_in: ^5.1.0
firebase_storage: ^10.0.3
cloud_firestore: ^2.5.3
firebase_analytics: ^8.3.2
lottie: ^1.1.0
image_picker: ^0.8.4
Above is the pubspec.yaml file dependencies.
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _currentIndex = 0;
final List<Widget> _children = [
WeCareHomeScreen(),
WeCareReminder(),
Feed(),
Chatroom(),
Profile(),
];
#override
void initState() {
super.initState();
Provider.of<FirebaseOperations>(context, listen: false)
.initUserData(context)
.whenComplete(() {
setState(() {});
});
}
Widget build(BuildContext context) {
return Scaffold(
body: _children[_currentIndex],
bottomNavigationBar: CurvedNavigationBar(
index: 0,
height: 50.0,
items: <Widget>[
Icon(
Icons.home,
size: 25,
color: Colors.white,
),
Icon(
Icons.home,
size: 25,
color: Colors.white,
),
Icon(
Icons.home,
size: 25,
color: Colors.white,
),
Icon(
Icons.home,
size: 25,
color: Colors.white,
),
Icon(
Icons.home,
size: 25,
color: Colors.white,
),
],
color: Color.fromRGBO(241, 201, 57, 1.0),
buttonBackgroundColor: Colors.black,
backgroundColor: Colors.white,
animationCurve: Curves.easeInOut,
animationDuration: Duration(milliseconds: 600),
onTap: (index) {
setState(() {
_currentIndex = index;
});
}),
);
}
}
Above is the homescreen.dart file code.
class Authentication with ChangeNotifier {
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
late String userUid;
String get getUserUid => userUid;
Future logIntoAccount(String email, String password) async {
UserCredential userCredential = await firebaseAuth
.signInWithEmailAndPassword(email: email, password: password);
String userUid;
User? user = userCredential.user;
userUid = user!.uid;
print(userUid);
notifyListeners();
}
Future createAccount(String email, String password) async {
UserCredential userCredential = await firebaseAuth
.createUserWithEmailAndPassword(email: email, password: password);
User? user = userCredential.user;
userUid = user!.uid;
print('Created Account Uid => $userUid');
notifyListeners();
}
Future logoutViaEmail() {
return firebaseAuth.signOut();
}
Future signInWithGoogle() async {
final GoogleSignInAccount? googleSignInAccount =
await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount!.authentication;
final AuthCredential authCredential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken);
final UserCredential userCredential =
await firebaseAuth.signInWithCredential(authCredential);
final User? user = userCredential.user;
assert(user!.uid != null);
userUid = user!.uid;
print('Google User Uid => $userUid');
notifyListeners();
}
Future signOutWithGoogle() async {
return googleSignIn.signOut();
}
}
Above is Authentification.dart file.
class FirebaseOperations with ChangeNotifier {
late UploadTask imageUploadTask;
late String initUserEmail;
late String initUserImage;
late String initUserName;
String get getInitUserImage => initUserImage;
String get getInitUserName => initUserName;
String get getInitUserEmail => initUserEmail;
Future uploadUserAvatar(BuildContext context) async {
Reference imageReference = FirebaseStorage.instance.ref().child(
'userProfileAvatar/${Provider.of<LandingUtils>(context, listen:
false).getUserAvatar.path}/${TimeOfDay.now()}');
imageUploadTask = imageReference.putFile(
Provider.of<LandingUtils>(context, listen: false).getUserAvatar);
await imageUploadTask.whenComplete(() {
print('Image uploaded!');
});
imageReference.getDownloadURL().then((url) {
Provider.of<LandingUtils>(context, listen: false).userAvatarUrl =
url.toString();
print(
'the user profile avatar url => ${Provider.of<LandingUtils>(context, listen:
false).userAvatarUrl}');
notifyListeners();
});
}
Future createUserCollection(BuildContext context, dynamic data) async {
return FirebaseFirestore.instance
.collection('users')
.doc(Provider.of<Authentication>(context, listen: false).getUserUid)
.set(data);
}
Future initUserData(BuildContext context) async {
return FirebaseFirestore.instance
.collection('users')
.doc(Provider.of<Authentication>(context, listen: false).getUserUid)
.get()
.then((doc) {
print('Fetching user data');
initUserName = doc.data()!['username'];
initUserEmail = doc.data()!['useremail'];
initUserImage = doc.data()!['userimage'];
print(initUserName);
print(initUserEmail);
print(initUserImage);
notifyListeners();
});
}
Future uploadPostData(String postId, dynamic data) async {
return FirebaseFirestore.instance.collection('posts').doc(postId).set(data);
}
}
Above is the firebaseoperations.dart file.
Here once it printed 'Fetching user Data' in the console,it is showing 'Unhandled Exception: Null check operator used on a null value' error.
Also once the image is uploaded ,instead of printing the url of image, '*************' is printed.
And 'Unhandled Exception: LateInitializationError: Field 'initUserName' has not been initialized.' is also printed.
It will me more helpful,if anyone pointout my mistakes and give me a solution.
Unhandled Exception: LateInitializationError: Field 'initUserName' has not been
initialized.
.
.
.
I/flutter (18214): Post image uploaded to storage
I/flutter (18214): Image uploaded
I/flutter (18214):
*************************************************************************************
*************************************************************************************
*********************************************
.
.
.
E/flutter (18214): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception:
LateInitializationError: Field 'initUserName' has not been initialized.
This is how the error looks.
class ProfileHelpers with ChangeNotifier {
ConstantColors constantColors = ConstantColors();
Widget headerProfile(
BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
print(snapshot.data);
return SizedBox(
height: MediaQuery.of(context).size.height * 0.26,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
height: 150.0,
width: 170.0,
child: Column(
children: [
GestureDetector(
onTap: () {},
child: CircleAvatar(
backgroundColor: constantColors.transparent,
radius: 38.0,
backgroundImage: NetworkImage(
'${Provider.of<FirebaseOperations>
(context).getInitUserImage}'),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'Vijay',
//snapshot.data?['username'],
//snapshot.data!.data()['username'],
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 20.0),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(EvaIcons.email,
color: constantColors.greenColor, size: 16),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'username#gmail.com',
// snapshot.data!.get('useremail'),
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 12.0),
),
),
],
),
)
],
),
),
Above is the profile page code.
enter code here
class FeedHelpers with ChangeNotifier {
ConstantColors constantColors = ConstantColors();
Widget appBar(BuildContext context) {
return AppBar(
backgroundColor: constantColors.darkColor.withOpacity(0.6),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.camera_enhance_rounded,
color: constantColors.greenColor),
onPressed: () {
Provider.of<UploadPost>(context, listen: false)
.selectPostImageType(context);
})
],
title: RichText(
text: TextSpan(
text: 'Social ',
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
children: <TextSpan>[
TextSpan(
text: 'Feed',
style: TextStyle(
color: constantColors.blueColor,
fontWeight: FontWeight.bold,
fontSize: 20.0,
))
]),
),
);
}
Widget feedBody(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
child: StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream:
FirebaseFirestore.instance.collection('posts').snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>
snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
{
return Center(
child: SizedBox(
height: 500.0,
width: 400.0,
child:
Lottie.asset('assets/animations/loading.json'),
),
);
} else {
return loadPosts(context, snapshot);
}
},
),
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: constantColors.darkColor.withOpacity(0.6),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(18.0),
topRight: Radius.circular(18.0))),
),
),
);
}
Widget loadPosts(
BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot
documentSnapshot) {
Map<String, dynamic> data =
documentSnapshot.data()! as Map<String, dynamic>;
return Container(
height: MediaQuery.of(context).size.height * 0.62,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 8.0),
child: Row(
children: [
GestureDetector(
child: CircleAvatar(
backgroundColor: constantColors.blueGreyColor,
radius: 20.0,
backgroundImage: NetworkImage(
'${Provider.of<UploadPost>
(context).getUploadPostImage}'),
// NetworkImage(documentSnapshot['userimage']),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: RichText(
text: TextSpan(
text: data['username'],
style: TextStyle(
color: constantColors.blueColor,
fontSize: 14.0,
fontWeight: FontWeight.bold),
children: <TextSpan>[
TextSpan(
text: ' , 12 hours ago',
style: TextStyle(
color:
constantColors.lightColor
.withOpacity(0.8)))
]),
)),
Container(
child: Text(
data['username'],
style: TextStyle(
color: constantColors.greenColor,
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
),
],
),
),
)
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
height: MediaQuery.of(context).size.height * 0.46,
width: MediaQuery.of(context).size.width,
child: FittedBox(
// child: Image.network(downloadURL.toString()),
child: Image.network(data['postimage'], scale:
2))),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 80.0,
child: Row(
children: [
GestureDetector(
child: Icon(
FontAwesomeIcons.heart,
color: constantColors.redColor,
size: 22.0,
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'0',
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 18.0),
),
)
],
),
),
Above is feed_helper file.
class UploadPost with ChangeNotifier {
TextEditingController captionController = TextEditingController();
ConstantColors constantColors = ConstantColors();
late File uploadPost;
late File uploadPostImage;
File get getUploadPostImage => uploadPostImage;
late String uploadPostImageUrl;
String get getUploadPostImageUrl => uploadPostImageUrl;
final picker = ImagePicker();
late UploadTask imagePostUploadTask;
Future pickUploadPostImage(BuildContext context, ImageSource
source) async {
final uploadPostImageVal = await picker.pickImage(source: source);
uploadPostImageVal == null
? print('Select Image')
: uploadPostImage = File(uploadPostImageVal.path);
print(uploadPostImageVal!.path);
uploadPostImage != null
? showPostImage(context)
: print('Image upload error');
notifyListeners();
}
Future uploadPostImageToFirebase() async {
Reference imageReference = FirebaseStorage.instance
.ref()
.child('posts/${uploadPostImage!.path}/${TimeOfDay.now()}');
imagePostUploadTask = imageReference.putFile(uploadPostImage!);
await imagePostUploadTask.whenComplete(() {
print('Post image uploaded to storage');
});
imageReference.getDownloadURL().then((imageUrl) {
uploadPostImageUrl = imageUrl;
print(uploadPostImageUrl);
});
notifyListeners();
}
Above file is the uploadpost.dart file
The problem is that you're declaring the initUserName field as late and trying to access it before initializing it (giving it a value)
The late keyword tells the compiler not to worry about the variable being null because you guarantee that you'll have given it a value before trying to access it.
You could either declare initUserName as String? initUserName
This way you'll have initialized it with the null value;
Otherwise you can make sure you set a value to it like that: FirebaseOperations.initUserName = 'username'; before you try to read it's value
I am new to flutter. I am having a flutter and firebase authentication system where users will input their phone number and an otp will be sent to them. I then want to implement a functionality whereby there will be a countdown shown for the otp timeout, so that a users can resend an otp again after timeout.
Currently my code is sending otp to users perfectly, what i want to implement is how to show a timer countdown for the otp timeout.
This is my code
LoginScreen.dart
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Phone Auth'),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(children: [
Container(
margin: EdgeInsets.only(top: 60),
child: Center(
child: Text(
'Phone Authentication',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 28),
),
),
),
Container(
margin: EdgeInsets.only(top: 40, right: 10, left: 10),
child: TextField(
decoration: InputDecoration(
hintText: 'Phone Number',
prefix: Padding(
padding: EdgeInsets.all(4),
child: Text('+234'),
),
),
maxLength: 10,
keyboardType: TextInputType.number,
controller: _controller,
),
)
]),
Container(
margin: EdgeInsets.all(10),
width: double.infinity,
child: FlatButton(
color: Colors.blue,
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => OTPScreen(_controller.text)));
},
child: Text(
'Next',
style: TextStyle(color: Colors.white),
),
),
)
],
),
),
);
}
}
OTP process Screen
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pinput/pin_put/pin_put.dart';
class OTPScreen extends StatefulWidget {
final String phoneNumber;
OTPScreen({#required this.phoneNumber});
#override
_OTPScreenState createState() => _OTPScreenState();
}
class _OTPScreenState extends State<OTPScreen> {
final GlobalKey<ScaffoldState> _scaffoldkey = GlobalKey<ScaffoldState>();
String _verificationCode;
final TextEditingController _pinPutController = TextEditingController();
final FocusNode _pinPutFocusNode = FocusNode();
final BoxDecoration pinPutDecoration = BoxDecoration(
color: const Color.fromRGBO(43, 46, 66, 1),
borderRadius: BorderRadius.circular(10.0),
border: Border.all(
color: const Color.fromRGBO(126, 203, 224, 1),
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldkey,
appBar: AppBar(
title: Text(
'OTP Verification',
style: TextStyle(fontWeight: FontWeight.normal),
),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: 35),
child: Column(
children: [
Text(
"Code is sent to " + widget.phoneNumber,
style: TextStyle(
fontSize: 20,
color: Color(0xFF818181),
),
),
SizedBox(
height: 20,
),
Text(
'Enter your 6-digit code',
style: TextStyle(fontSize: 20),
),
],
),
),
Padding(
padding: const EdgeInsets.all(30.0),
child: PinPut(
fieldsCount: 6,
textStyle: const TextStyle(fontSize: 25.0, color: Colors.white),
eachFieldWidth: 40.0,
eachFieldHeight: 55.0,
focusNode: _pinPutFocusNode,
controller: _pinPutController,
submittedFieldDecoration: pinPutDecoration,
selectedFieldDecoration: pinPutDecoration,
followingFieldDecoration: pinPutDecoration,
pinAnimationType: PinAnimationType.fade,
onSubmit: (pin) async {
try {
await FirebaseAuth.instance
.signInWithCredential(PhoneAuthProvider.credential(
verificationId: _verificationCode, smsCode: pin))
.then((value) async {
if (value.user != null) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => Home()),
(route) => false);
}
});
} catch (e) {
FocusScope.of(context).unfocus();
_scaffoldkey.currentState
.showSnackBar(SnackBar(content: Text('invalid OTP')));
}
},
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
//Check if timeout has elaspsed, if true then enable button for user to click
},
child: Text(
'Resend Code',
style: TextStyle(color: Color(0xFF81C784)),
)),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SetupProfile()));
},
borderRadius: BorderRadius.circular(33),
child: Image.asset(
'assets/images/forward.png',
height: 50,
width: 50,
),
),
],
),
),
],
),
),
);
}
_verifyPhone() async {
await FirebaseAuth.instance.verifyPhoneNumber(
phoneNumber: '+234${widget.phoneNumber}',
verificationCompleted: (PhoneAuthCredential credential) async {
await FirebaseAuth.instance
.signInWithCredential(credential)
.then((value) async {
if (value.user != null) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => Home()),
(route) => false);
}
});
},
verificationFailed: (FirebaseAuthException e) {
print(e.message);
},
codeSent: (String verficationID, int resendToken) {
setState(() {
_verificationCode = verficationID;
});
},
codeAutoRetrievalTimeout: (String verificationID) {
setState(() {
_verificationCode = verificationID;
});
},
timeout: Duration(seconds: 120));
}
#override
void initState() {
// TODO: implement initState
super.initState();
_verifyPhone();
}
}
When the user starts my app the first time, he can toggle between the registration form and the sign in form. After completing one of this forms, he should see the loading screen until the user is created or signed in. In my case, unfortunately, the loading screen doesn't disappear, although the user is created.
How can I fix this problem?
the sign in form:
class SignIn extends StatefulWidget {
final Function toggleView;
SignIn({this.toggleView});
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
// text field state
String email = '';
String password = '';
String error = '';
static const color = const Color(0xFF2F80ED);
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
child: Positioned(
top: 0,
right: 0,
child: Image.asset(
'assets/canvas-1-ws.png',
),
),
),
Positioned(
top: 25.0,
left: 5.0,
child: IconButton(
icon: Icon(
Icons.close,
color: Colors.black,
size: 35.0,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Welcome(),
),
);
},
),
),
Container(
child: Positioned(
bottom: 0,
left: 0,
child: Image.asset(
'assets/canvas-2-ws.png',
),
),
),
Center(
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(
left: 50.0,
right: 50.0,
),
child: Container(
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Login',
style: TextStyle(
color: Colors.black,
fontFamily: 'Roboto Black',
fontSize: 35.0,
),
),
SizedBox(
height: 30.0,
),
TextFormField(
style: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
cursorColor: Colors.black,
decoration: InputDecoration(
fillColor: Colors.black,
hintText: 'Email',
hintStyle: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
),
validator: (val) => val.isEmpty
? 'Bitte gültige Email'
: null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(
height: 20.0,
),
TextFormField(
style: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
cursorColor: Colors.black,
decoration: InputDecoration(
fillColor: Colors.black,
hintText: 'Passwort',
hintStyle: TextStyle(
fontFamily: 'Roboto Light',
color: Colors.black,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1.0,
),
),
),
obscureText: true,
validator: (val) => val.isEmpty
? 'Bitte gültiges Passwort'
: null,
onChanged: (val) {
setState(() => password = val);
}),
SizedBox(
height: 45.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Login',
style: TextStyle(
fontFamily: 'Roboto Light',
fontSize: 25.0),
),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.signInWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
error = 'Falsche Email/Password';
loading = false;
});
}
}
},
),
),
],
),
),
),
),
],
),
),
],
),
);
}
}
the registration form is almost similar...
the file, where the user can toggle between the forms:
class Welcome extends StatefulWidget {
final Function toggleView;
Welcome({this.toggleView});
#override
_WelcomeState createState() => _WelcomeState();
}
class _WelcomeState extends State<Welcome> {
static const color = const Color(0xFF2F80ED);
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: <Widget>[
Positioned(
top: 0,
right: 0,
child: Image.asset('assets/canvas-1-ws.png'),
),
Positioned(
bottom: 0,
left: 0,
child: Image.asset('assets/canvas-2-ws.png'),
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset(
'assets/Skiclublogo_transparent.png',
scale: 4,
),
SizedBox(
height: 40.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Registrieren',
style: TextStyle(
fontFamily: 'Roboto Light', fontSize: 25.0),
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Register(),
),
);
}),
),
SizedBox(
height: 40.0,
),
ButtonTheme(
minWidth: 200,
height: 50,
child: RaisedButton(
elevation: 0,
color: color,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
side: BorderSide(color: color),
),
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: color,
spreadRadius: 10.0,
blurRadius: 20.0,
offset: Offset(0, 3),
),
],
),
child: Text(
'Login',
style: TextStyle(
fontFamily: 'Roboto Light', fontSize: 25.0),
),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SignIn(),
),
);
}),
),
],
),
),
],
),
);
}
}
the auth file, where the user is created or logged in:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on FirrebaseUser
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 anonmously
Future signInAnon() async {
try {
AuthResult result = await _auth.signInAnonymously();
FirebaseUser user = result.user;
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(
user.displayName, user.email, user.photoUrl, user.uid);
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in 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, String name) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
// update user info
UserUpdateInfo userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = name;
await user.updateProfile(userUpdateInfo);
await user.reload();
user = await FirebaseAuth.instance.currentUser();
// create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData(
user.displayName, user.email, user.photoUrl, user.uid);
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;
}
}
// current user
void inputData() async {
final FirebaseUser user = await _auth.currentUser();
final uid = user.uid;
// here you write the codes to input the data into firestore
}
}
the wrapper file, where the app checks if the user is new:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
print(user);
// return either Home or Authenticate widget
if (user == null) {
return Welcome();
} else {
return DrawerNav();
}
}
}
the loading screen file:
class Loading extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: SpinKitWave(
color: Colors.black,
size: 50.0,
),
),
);
}
}
Thank you very much when you've read through all of this!
You don't always call setState after the user is created.
This will work
onPressed: (){ if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result = await _auth
.signInWithEmailAndPassword(
email, password);
setState(() => loading = false);
if (result == null) {
setState(() {
error = 'Falsche Email/Password';
});
}
}},
Ill explain you my friend
set a boolean variable named loading
loading = false;
if loading is true display loading screen else display your form ui using ternary operator
while creating user change the state of loading so that loading screen will appear
setState(() { loading=true; });
after user is created change the state of loading again to false
setState(() { loading=false; });
This is the template in build function
loading==false?yourui():loading()