Flutter: CRUD clarifications over Firebase - firebase

I've been working on a little project on flutter since I just started learning it a week ago and I'm just wondering how I could retrieve a specific snippet of data from Firebase's Firestore database.
Here is the code on the relevant files:
database.dart
import 'package:plannus/models/user.dart';
class DatabaseMethods {
final String uid;
DatabaseMethods({this.uid});
final CollectionReference users = Firestore.instance.collection("users");
Future<void> updateUserData(String name, String handle) async {
print(uid);
return await users.document(uid).updateData({
'name' : name,
'handle' : handle,
});
}
Future<void> updateSpecificUserData(String uid, String name, String handle) async {
print(uid);
return await users.document(uid).updateData({
'name' : name,
'handle' : handle,
});
}
Future<Set<Set<String>>> getUserData() {
return users.document(uid).get().then((value) => {
if (value.exists) {
value.data['handle']
}
});
}
void getSpecificUserData(String uid, String capture) async {
DocumentSnapshot snapshot = await users.document(uid).get();
capture = snapshot.data['handle'];
print(capture);
}
Future<String> retrieveData(String uid) async {
DocumentSnapshot snap = await users.document(uid).get();
Map<String, String> map = snap.data;
String handle = map['name'];
return handle;
}
//
uploadUserInfo(userMap) {
Firestore.instance.collection("users").add(userMap);
}
// user data from snapshot
Stream<QuerySnapshot> get userInfo {
return users.snapshots();
}
}
profile.dart
import 'package:flutter/material.dart';
import 'package:plannus/messages/database.dart';
import 'package:plannus/models/user.dart';
import 'package:plannus/services/auth.dart';
import 'package:provider/provider.dart';
class Profile extends StatefulWidget {
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
final AuthService auth = AuthService();
final formKey = GlobalKey<FormState>(); // 'id' of form
bool loading = false;
// text field state
String name = '';
String password = '';
String handle = '';
String error = '';
DatabaseMethods databaseMethods = new DatabaseMethods();
QuerySnapshot currentUser;
#override
Widget build(BuildContext context) {
User user = Provider.of<User>(context);
String handle = '';
print(user.uid);
Future<String> str = databaseMethods.retrieveData(user.uid);
str.then((value) => {
handle = value
});
print(handle);
return new Scaffold(
// appBar: AppBar(
// title:
// ),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 50),
child: Form(
key: formKey, // keep track of form and its state
child : Column (
children: <Widget>[
Image.asset('assets/profilepicture.png', height: 300, width: 300),
SizedBox(height: 20),
TextFormField(
decoration: InputDecoration(
hintText: 'Name',
icon: Icon(Icons.person_outline, color: Colors.blue),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[300], width: 2),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
)
),
validator: (val) => val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
SizedBox(height: 20),
TextFormField(
decoration: InputDecoration(
hintText: 'Handle',
icon: Icon(Icons.alternate_email, color: Colors.blue),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[300], width: 2),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
)
),
obscureText: false,
validator: (val) => val[0] != '#' ? 'Handle starts with #!' : null,
onChanged: (val) {
setState(() => handle = val);
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget> [
RaisedButton(
color: Colors.blueAccent,
child: Text(
'Update',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if(formKey.currentState.validate()) {
print(user.uid);
await databaseMethods.updateSpecificUserData(user.uid, name, handle);
setState(() {
error = 'Update successful!';
});
}
},
),
],
),
SizedBox(height: 12),
Text(
error,
style: TextStyle(color: Colors.black, fontSize: 16),
)
],
),
),
),
);
}
}
My code can be real messy (for which I apologise because I have been stuck on this for a quite long time and have been rigorously attempting various methods to extract the data out).
Ultimately, my main objective is to get the value(handle) from my data stored in firebase and then to dynamically display it on my appbar.
My firebase database collection is named 'users' and carries only data { name: "...", handle: "..."}.
Thanks for bearing with my long post.
Profile page

Here is how you can get data from firebase's firestore. I think its best to rename your "name" as "n" to make the size of your data stored in the database smaller.
await Firestore.instance
.collection('users')
.document(uid)
.get()
.then((DocumentSnapshot ds) {
username = ds["name"];
});

Related

The getter 'data' was called on null. Receiver: null Tried calling: data

Tried signing up user with Firebase but got the above error instead, and the code is formatted in such a way that it should redirect the user to homepage after a successful signup.
My main.dart
import 'package:bedc_app/home_page.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:bedc_app/auth/login_page.dart';
void main() async{
//solution study
WidgetsFlutterBinding.ensureInitialized();
FirebaseAuth.instance.currentUser()
.then((FirebaseUser user) {
if(user != null){
Firestore.instance.collection('users').document(user.uid).get().then((DocumentSnapshot doc){
runApp(MyApp(true, doc));
});
return;
}
runApp(MyApp(false, null));
});
}
// void main() =>runApp(MyApp());
class MyApp extends StatelessWidget {
bool isLoggedIn;
DocumentSnapshot doc;
MyApp(this.isLoggedIn, this.doc);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Multifunctional bedc project App',
debugShowCheckedModeBanner: false,
home: isLoggedIn ? HomePage(userDoc: doc) : loginPage(),
);
}
}
My Signup_page.dart
import 'package:bedc_app/auth/login_page.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:bedc_app/utils/constants.dart';
import '../home_page.dart';
class SignUpPage extends StatefulWidget {
#override
_SignUpPageState createState() => _SignUpPageState();
}
class _SignUpPageState extends State<SignUpPage> {
String email, password;
bool isLoggedIn = false;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ListView(
children: [
SizedBox(
height: 50,
),
Align(
alignment: Alignment.topCenter,
child: (
Image.asset(
'assets/bedclogo.jpg'
)),
),
SizedBox(
height: 100,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 26.0),
child: TextField(
decoration: InputDecoration(
hintText: 'email',
border: OutlineInputBorder(),
labelText: 'Email',
suffixIcon: Icon(Icons.email, color: Colors.green)
),
keyboardType: TextInputType.emailAddress,
onChanged: (String val){
email = val;
},
),
),
SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 26.0),
child: TextField(
decoration: InputDecoration(
hintText: 'Password',
border: OutlineInputBorder(),
labelText: 'Password',
suffixIcon: Icon(Icons.lock, color: Colors.green)
),
obscureText: true,
obscuringCharacter: '!',
keyboardType: TextInputType.emailAddress,
onChanged: (String val){
password = val;
},
),),
SizedBox(
height: 5,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 26),
child: MaterialButton(
color: Color(0xFF88C540),
child: isLoading ? Container(
height: 24,
width: 24,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.black),
strokeWidth: 2,
)
):Text(
'SignUp'.toUpperCase(),
style: TextStyle(fontWeight: FontWeight.bold),
),
onPressed: (){
checkUserInput();
},
),
),
SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 20),
child: RichText(
text: TextSpan(
text: 'Already have an Account ?',
style: TextStyle(color: Colors.black),
children: [
TextSpan(
text: 'Login here',
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()..onTap = (){
Navigator.of(context).pushReplacement(CupertinoPageRoute(builder: (_) => loginPage()));
},
)
]
)),
)
],
));
}
//SIGNUP FUNCTION USING FIREBASE
bool isLoading = false;
signUpUserWithFirebase(){
FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password
).then((AuthResult result){
//Authresult cant be stored to string.....
storeUserDataToFirestore(result.user.uid);
if(result.user.uid != null){
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => HomePage()));
}
}).catchError((e){
print(e);
isLoading = false;
setState(() { });
});
}
//storeUserDataToFirestore
storeUserDataToFirestore(String userId){
Map<String, dynamic> userData = Map<String, dynamic>();
userData = {
Constants.USERNAME: '#username',
Constants.USER_ID: userId,
Constants.EMAIL : email,
Constants.ACCOUNT_NUM : '00000000',
Constants.IS_ADMIN: false,
Constants.PROFILE_IMAGE: '',
Constants.PROFILE_IMAGE_THUMB: '',
};
CollectionReference usersRef = Firestore.instance.collection(Constants.USERS_COLLECTION);
usersRef.document(userId).setData(userData).then((_){
isLoading = false;
setState(() { });
}).catchError((e){
print(e);
});
}
//FUNCTION TO CHECK USER ENTRY
checkUserInput(){
isLoading = true;
setState(() { });
if(email == null || email.isEmpty){
print('Enter email');
isLoading = false;
setState(() { });
return;
}
if(password == null || email.isEmpty){
print('Enter password');
isLoading = false;
setState(() { });
}
//SIGNUP THE USER
signUpUserWithFirebase();
}
getUserData(String UserId){
Firestore.instance.collection(Constants.USERS_COLLECTION)
.document(UserId)
.get().then((DocumentSnapshot userDoc){
Navigator.of(context).pop();
Navigator.of(context).pushReplacement(CupertinoPageRoute(builder: (_) => HomePage(userDoc: userDoc)));
}).catchError((e){
print(e);
});
}
}
My Home_page.dart
import 'dart:ui';
import 'package:bedc_app/auth/login_page.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:bedc_app/auth/signup_page.dart';
import 'model/user.dart';
User currentUser;
class HomePage extends StatefulWidget {
DocumentSnapshot userDoc;
HomePage({this.userDoc,});
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//user cant access this page unless logged in
bool userIsLoggedIn = true;
#override
void initState() {
// TODO: implement initState
super.initState();
currentUser = User.fromSnapshot(widget.userDoc);
}
//HERE IS BUILDING PROFILE IMAGE
Widget buildProfileImage(){
if(currentUser.profileImage == ''){
return CircleAvatar(
backgroundColor: Colors.white70,
radius: 20,
child: Icon(Icons.person, size: 30),
);
}else{
return CircleAvatar(
backgroundImage: NetworkImage(currentUser.profileImage),
);
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.brown,
title: Text('Homepage'),
),
body: ListView(
children: [
SizedBox(height: 20),
Align(
alignment: Alignment.topRight,
child: (
Image.asset(
'assets/bedclogo.jpg',
scale: 2,
)),
),
ListTile(
title: Text(currentUser.username, style: TextStyle(color: Colors.brown, fontWeight: FontWeight.bold),),
leading: buildProfileImage(),
),
SizedBox(height: 30),
//CAPTURE METER READING UI
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: GestureDetector(
onTap: (){
//print(currentUser.isAdmin);
},
child: Row(
children: [
//CAPTURE METR READING
Container(
width: 100,
height: 100,
color: Colors.green,
child: Align(
alignment: Alignment.center,
child: (
Image.asset(
'assets/meterIcon.png',
scale: 3,
)),
),
),
Container(
width: 100,
height: 100,
child: Align(
alignment: Alignment.center,
child: Text('Capture Meter Reading'.toUpperCase()),
),
),
],
),
),
),
SizedBox(height: 30),
//UPDATE PROFILE UI DESIGN
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: GestureDetector(
onTap:(){
//print(currentUser.isAdmin);
},
child: Row(
children: [
Container(
width: 100,
height: 100,
color: Colors.green,
child: Align(
alignment: Alignment.center,
child: (
Image.asset(
'assets/profileAvatar.png',
scale: 3,
)),
),
),
Container(
width: 100,
height: 100,
child: Align(
alignment: Alignment.center,
child: Text('Update Profile'.toUpperCase()),
),
),
],
),
),
),
// TextButton (
// onPressed: (){
// //just logout, implement pop dialog later
// // FirebaseAuth.instance.signOut();
// // Navigator.of(context).pushReplacement(CupertinoPageRoute(builder: (_)=> loginPage()));
// // currentUser = null;
// // setState(() {
// // });
// // still showing error... try to fix asap
// FirebaseAuth.instance.signOut().then((_){
// userIsLoggedIn = false;
// Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_)=> loginPage()));
// //currentUser = null;
// setState(() {
//
// });
// });
// },
// child: Text('SignOut'))
],
)
);
}
}
User.dart for user Model
import 'package:bedc_app/utils/constants.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class User{
String username;
String email;
String userId;
String accountNum;
bool isAdmin;
String profileImage;
String profileImageThumb;
User({
this.username,
this.email,
this.userId,
this.accountNum,
this.isAdmin,
this.profileImage,
this.profileImageThumb
});
factory User.fromSnapshot(DocumentSnapshot doc){
return User(
username: doc.data[Constants.USERNAME],
email: doc.data[Constants.EMAIL],
userId: doc.data[Constants.USER_ID],
accountNum: doc.data[Constants.ACCOUNT_NUM],
isAdmin: doc.data[Constants.IS_ADMIN],
profileImage: doc.data[Constants.PROFILE_IMAGE],
profileImageThumb: doc.data[Constants.PROFILE_IMAGE_THUMB]
);
}
}
Having signed the user up, im getting error The getter 'data' was called on null. Receiver: null Tried calling: data.
i dont know which part of the code is causing this exception
This error generally show when you try to get some attribute on null object.
In your case, call one of doc.data[..] in file User.dart generate the error that means doc == null is true.
Verify that widget.userDoc is not null at this line currentUser = User.fromSnapshot(widget.userDoc); on initState method of Home_page.dart file
So error provide in one of HomePage call who require a non null userDoc (todo: make sure your data is not null using assert and add #required before required variable on your class exp: HomePage({#required this.userDoc,}): assert(userDoc != null, "BOooh my userDoc may be not null"); that help very much when you debug your app)
finaly your problem provide in signUpUserWithFirebase() method of your Signup_page.dart file... here Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => HomePage()));
Try to replace by this getUserData(result.user.uid) so your methode should become
signUpUserWithFirebase(){
FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email,
password: password
).then((AuthResult result){
//Authresult cant be stored to string.....
storeUserDataToFirestore(result.user.uid);
if(result.user.uid != null){
getUserData(result.user.uid); // replaced line
}
}).catchError((e){
print(e);
isLoading = false;
setState(() { });
});
}

How to Add the displayName While SigningUp using createUserWithEmailAndPassword

I was trying to add the display name to the user immediately after the signup(using createUserWithEmailAndPassword ) and store it in name field in firestore. But when I see it in firestore it says null, I am completely new to this,
Here is how I trying to do it:
UserSignUp.dart
class UserSignUp{
static FirebaseAuth _auth = FirebaseAuth.instance;
static signupWithEmail({String email, String password, String name}) async {
final res = await _auth.createUserWithEmailAndPassword(
email: email, password: password).then(
(value) async {
await FirebaseAuth.instance.currentUser.updateProfile(
displayName: name,
);
},
);
final User user = res.user;
return user;
}
class UserHelper {
static FirebaseFirestore _db = FirebaseFirestore.instance;
static saveUser(User user) async {
Map<String, dynamic> userData = {
"name": user.displayName,
"email": user.email,
"last_login": user.metadata.lastSignInTime.millisecondsSinceEpoch,
"created_at": user.metadata.creationTime.millisecondsSinceEpoch,
"role": "user",
};
final userRef = _db.collection("users").doc(user.uid);
if ((await userRef.get()).exists) {
await userRef.update({
"last_login": user.metadata.lastSignInTime.millisecondsSinceEpoch,
});
} else {
await _db.collection("users").doc(user.uid).set(userData);
}
await _saveDevice(user);
}
}
}
**
Signup_screen.dart
**
class Body extends StatefulWidget {
#override
_SignupPageState createState() => _SignupPageState();
}
class _SignupPageState extends State<Body> {
TextEditingController _emailController;
TextEditingController _passwordController;
TextEditingController _nameController;
#override
void initState() {
super.initState();
_emailController = TextEditingController(text: "");
_passwordController = TextEditingController(text: "");
_nameController = TextEditingController(text: "");
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Background(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"SIGNUP",
style: TextStyle(fontWeight: FontWeight.bold),
),
width: size.width * 0.8,
decoration: BoxDecoration(
color: kPrimaryLightColor,
borderRadius: BorderRadius.circular(29),
),
child: TextField(
controller: _nameController,
// onChanged: (value) {},
cursorColor: kPrimaryColor,
decoration: InputDecoration(
icon: Icon(
Icons.person,
color: kPrimaryColor,
),
hintText: "Full Name",
border: InputBorder.none,
),
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
width: size.width * 0.8,
decoration: BoxDecoration(
color: kPrimaryLightColor,
borderRadius: BorderRadius.circular(29),
),
child: TextField(
controller: _emailController,
// onChanged: (value) {},
cursorColor: kPrimaryColor,
decoration: InputDecoration(
icon: Icon(
Icons.person,
color: kPrimaryColor,
),
hintText: "Your Email",
border: InputBorder.none,
),
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 5),
width: size.width * 0.8,
decoration: BoxDecoration(
color: kPrimaryLightColor,
borderRadius: BorderRadius.circular(29),
),
child: TextField(
controller: _passwordController,
obscureText: true,
// onChanged: (value) {},
cursorColor: kPrimaryColor,
decoration: InputDecoration(
hintText: "Password",
icon: Icon(
Icons.lock,
color: kPrimaryColor,
),
suffixIcon: Icon(
Icons.visibility,
color: kPrimaryColor,
),
border: InputBorder.none,
),
),
),
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 {
if (_emailController.text.isEmpty ||
_passwordController.text.isEmpty) {
print("Email and password cannot be empty");
return;
}
try {
final user = await UserSignUp.signupWithEmail(
email: _emailController.text,
password: _passwordController.text,
name: _nameController.text);
if (user != null) {
print("signup successful");
// Navigator.pop(context);
}
} catch (e) {
print(e);
}
},
child: Text(
"SIGNUP",
style: TextStyle(color: Colors.white),
),
),
),
),
),
),
);
}
}
Main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Auth',
theme: ThemeData(
primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white,
),
home: MainScreen(),
);
}
}
class MainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<User>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if(snapshot.hasData && snapshot.data != null) {
UserHelper.saveUser(snapshot.data);
return StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection("users").doc(snapshot.data.uid).snapshots() ,
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot){
if(snapshot.hasData && snapshot.data != null) {
final userDoc = snapshot.data;
final user = userDoc.data();
if(user['role'] == 'user') {
return //;
}else{
return //;
}
}else{
return Material(
child: Center(child: CircularProgressIndicator(),),
);
}
},
);
}
return //;
}
);
}
}
but in my firestore the name filled is null
enter image description here
From shared code, I would like to share my understanding and thoughts which might help you to get your solution.
I know, you are already aware about this and that might be the reason you are storing user's info based on section 2's callback event.
Section 1
This part of the code will on save user's name on Firebase Auth only not on Firestore
You can just verify if user's name is updated on firebase auth user's list.
UserSignUp -> signupWithEmail -> currentUser.updateProfile
Section 2
UserHelper.saveUser is called based on authStateChanges not user profile info changes from Firebase.
So, there are higher probability user's display name will be updated on profile info after this callback..
Hence, user's displayName may be null while you are saving data on Firestore.
MainScreen -> StreamBuilder -> UserHelper.saveUser
Suggestion
I would suggest you to save user's info after updating the user's display name on profile to Firestore instead of authStateChanges event.

Retrieving Data From Firestore in time (outside of Widget build(BuildContext context) )

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 got exception caught by widget library error when creating record in firestore

i am working on online notice board project, I used following the code to upload notices uploading is workinging but it gives the following error.
class UploadNotice extends StatefulWidget {
#override
_UploadNoticeState createState() => _UploadNoticeState();
}
class _UploadNoticeState extends State<UploadNotice> {
final _formKey=GlobalKey<FormState>();
final List<String> noticrcategory=
['Exams','Mahapola/Bursary','TimeTables','Results','Other','General'];
File _noticepic;
String title;
String url;
String category;
String dateTime;
var uuid=Uuid();
bool loading = false;
DateTime now=new DateTime.now();
#override
Widget build(BuildContext context) {
Future getImage() async{
var image=await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_noticepic=image;
print('image path: $_noticepic');
});
}
Future uploadPic(BuildContext context)async{
String fileName=basename(_noticepic.path);
final StorageReference firebaseStorageRef=FirebaseStorage()
.ref().child('notices/$fileName');
final StorageUploadTask uploadTask=firebaseStorageRef.putFile(_noticepic);
StorageTaskSnapshot taskSnapshot= await uploadTask.onComplete;
String downloadurl = await taskSnapshot.ref.getDownloadURL();
url=downloadurl.toString();
}
final user = Provider.of<User>(context);
return StreamBuilder(
stream:UserService(uid: user.uid).userData,
builder: (context,snapshot){
User userData=snapshot.data;
String getDepartmentName(){
return userData.department.toString();
}
String department=getDepartmentName();
return loading ? Loading(): Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text('Notices App',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
backgroundColor: Colors.blue[800],
),
body:SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Container(child: Text('Add your notice here')
),
),
Container(
child:(_noticepic!=null)?Image.file(_noticepic,fit: BoxFit.fill):
Image.asset('',),
height: 450.0,
width:300.0,
color: Colors.grey[400],
),
Padding(
padding: const EdgeInsets.only(left: 280),
child: Container(
child: IconButton(
icon: Icon(Icons.add_photo_alternate),
color: Colors.grey[700],
iconSize: 40,
onPressed:(){
getImage().then((context){
uploadPic(context);
});
}
),
),
),
TextFormField(
decoration: new InputDecoration(labelText: 'Title'),
validator: (value) {
return value.isEmpty ? 'Title is Required' : null;
},
onChanged: (value) {
setState(() => title = value);
}),
DropdownButtonFormField(
value: category ?? 'General',
items: noticrcategory.map((noticrcategory){
return DropdownMenuItem(
value: noticrcategory,
child: Text('$noticrcategory Category'),
);
}).toList(),
onChanged: (value)=>setState(()=>category=value),
),
Text('${now.day}/${now.month}/${now.year}'),
SizedBox(height: 30.0,),
Container(
height: 30.0,
width: 100.0,
child: RaisedButton(
onPressed: () async {
setState(() => loading=true);
await NoticeService().updteNoticeData(
title,
url,
category,
'unapproved',
now,
'$department',
uuid.v4());
Navigator.of(context).pushReplacementNamed('/Upload Notices');
},
child: Text('Upload',style: TextStyle(color: Colors.white),),
color: Colors.blue[700],
),
)
],
),
),
),
),
);
}
);
}
here is the code in here I can upload notice as image and I can upload the current time to the firestore.
firestore record is created by this code. but it gives the following error.
════════ Exception caught by widgets library ═══════════════════════════════════
The getter 'department' was called on null.
Receiver: null
Tried calling: department
The relevant error-causing widget was
StreamBuilder<User>
lib\…\pages\uploadNotice.dart:56
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by image resource service ════════════════════════════
Unable to load asset:
════════════════════════════════════════════════════════════════════════════════
userData is null, you should do the following:
builder: (context,snapshot){
if(snapshot.hasData){
User userData = snapshot.data;
userData.department.toString();
return Text(userData.department.toString());
else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
}
Since StreamBuilder is asynchronous then first display a loading widget and use hasData to check if any data is returned

why sometime the imageUrl get saved inside cloud firestore database & sometime it does not get saved

I am creating a flutter application which will store Image-url inside cloud firestore database and that url get fetched in the form of image and display inside my flutter application. The problem is with image-url sometime it is get saved inside the database and sometime it does not. When it get saved the fetching process work properly and when it does not saved or unsaved it will reture a error value with null msg which is shown in the image.
I don't know why this is happening sometime the data get saved and sometime it is unsaved.
Pls see the below code for saving of Image inside the cloud firestore database.
import 'package:intl/intl.dart';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mi_card/duplicate.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mi_card/widget/provider_widget.dart';
import 'package:path/path.dart' as path;
import 'package:firebase_storage/firebase_storage.dart';
import '../sec.dart';
class EditProductScreen extends StatefulWidget {
#override
_EditProductScreenState createState() => _EditProductScreenState();
}
class _EditProductScreenState extends State<EditProductScreen> {
//for selecting picture from galary of phone
var sampleImage;
Future captureImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
sampleImage = tempImage;
});
String fileName = path.basename(sampleImage.path);
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('entry/student entry/'+fileName);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
var ImageUrl= await(await task.onComplete).ref.getDownloadURL();
url=ImageUrl.toString();
print("Image Url="+url);
//saveToDatabase(url);
}
void saveToDatabase(url){
}
//for camera opening and capturing the picture
Future getImage() async {
var tempImage = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
sampleImage = tempImage;
});
String fileName = path.basename(sampleImage.path);
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('entry/student entry/'+fileName);
final StorageUploadTask task =
firebaseStorageRef.putFile(sampleImage);
var ImageUrl= await(await task.onComplete).ref.getDownloadURL();
url=ImageUrl.toString();
print("Image Url="+url);
saveToDatabase(url);
}
final _priceFocusNode = FocusNode();
final _formKey = GlobalKey<FormState>();
final _firestore = Firestore.instance;
String url;
var _initValues = {
'title': '',
'description': '',
'price': '',
'imageUrl': '',
};
var _isInit = true;
#override
void didChangeDependencies() {
if (_isInit) {
final productId = ModalRoute.of(context).settings.arguments as String;
}
_isInit = false;
super.didChangeDependencies();
}
#override
void dispose() {
_priceFocusNode.dispose();
super.dispose();
}
void _saveForm() async{
final isValid = _formKey.currentState.validate();
if (!isValid) {
return;
}
_formKey.currentState.save();
var dbTimeKey = new DateTime.now();
var formatDate=new DateFormat('dd/MMMM/yyyy');
var formatTime=new DateFormat('dd/MMMM/yyyy &'' hh:mm aaa, EEEE');
String date = formatDate.format(dbTimeKey);
String time = formatTime.format(dbTimeKey);
final uid = await Provider.of(context).auth.getCurrentUID();
// collection reference for every user
DocumentReference Collection = Firestore.instance.collection(' entry').document();
Collection.setData({
"Entry-time": time,
'image': url,
});
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}
List<String> _locations = ['NA','1st year', '2 year', '3 year', '4 year']; // Option 2
String _selectedLocation;
#override
Widget build(BuildContext context) {
var _blankFocusNode = new FocusNode();
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
title: Text('ENTRY'),
centerTitle: true,
leading: new
IconButton(
icon: Icon(Icons.arrow_back),
color: Colors.white,
onPressed: () {
Navigator.pop(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: _saveForm,
child: Text("Save",),
),
],
),
backgroundColor: Colors.blueAccent,
body: GestureDetector (
onTap: () {
FocusScope.of(context).requestFocus(_blankFocusNode);
},
child: Form(
key: _formKey,
child: ListView(
scrollDirection: Axis.vertical,
children: <Widget>[
SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Align(
alignment: Alignment.center,
child: CircleAvatar(
radius:73 ,
backgroundColor: Colors.white,
child: ClipOval(
child: new SizedBox(
width: 125,
height:125,
child: sampleImage != null
? Image.file(
sampleImage,
height: 108,
fit: BoxFit.fill,
)
: IconButton(
icon: Icon(
Icons.person,
color: Colors.grey[400],
),
iconSize: 80.0,
//onPressed:_takePicture
),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 0.0),
child: IconButton(
icon: Icon(
Icons.camera_alt,
color: Colors.black,
size: 30.0,
),
onPressed: captureImage,
),
),
Padding(
padding: EdgeInsets.only(top: 00.0),
child: IconButton(
icon: Icon(
Icons.folder,
color: Colors.orangeAccent[100],
size: 30.0,
),
onPressed: getImage,
),
),
],
),
],
),
),
),
);
}
}
How to handle this error ?
Here is a better approach to uploading images to storage and getting url back
final StorageReference storageReference =
FirebaseStorage().ref().child("path/$name");
final StorageUploadTask uploadTask =
storageReference.putFile(imaeFile);
final StreamSubscription<StorageTaskEvent> streamSubscription =
uploadTask.events.listen((event) {
// You can use this to notify yourself or your user in any kind of way.
// For example: you could use the uploadTask.events stream in a StreamBuilder instead
// to show your user what the current status is. In that case, you would not need to cancel any
// subscription as StreamBuilder handles this automatically.
print('EVENT ${event.type}');
});
// Cancel your subscription when done.
await uploadTask.onComplete;
streamSubscription.cancel();
String url =
await (await uploadTask.onComplete).ref.getDownloadURL();
saveToDatabase(url);

Resources