I got exception caught by widget library error when creating record in firestore - firebase

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

Related

Add image from gallery to user document id using Flutter and Firebase

I am developing an app, and I want to create a user profile for each logged-in user. With my code now, I am able to get the user information from the cloud Firestore of each user uid document, but I want the user to be able to add an image to firebase storage, and then get this image, add to the specific user uid doc, and display on the app. Basically, I know how to get the data I have already, I just don't know how to update the user doc, especially with images.
Here is the code I have for the user profile:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:tradie_app/scr/providers/authService.dart';
import 'package:tradie_app/scr/screens/edit_company_email.dart';
import 'package:tradie_app/scr/widgets/loading.dart';
import 'home.dart';
class CompanyProfile extends StatefulWidget {
#override
_CompanyProfileState createState() => _CompanyProfileState();
}
class _CompanyProfileState extends State<CompanyProfile> {
// Keep track of the form for validation
final _formKey = GlobalKey<FormState>();
// Loading Icon
bool loading = false;
final AuthService _authService = AuthService();
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;
Future getCompanyNameData() async {
final CollectionReference users =
_firebaseFirestore.collection("Companies");
final String uid = _firebaseAuth.currentUser.uid;
final result = await users.doc(uid).get();
return result.data()["companyName"];
}
Future getCompanyEmailData() async {
final CollectionReference users =
_firebaseFirestore.collection("Companies");
final String uid = _firebaseAuth.currentUser.uid;
final result = await users.doc(uid).get();
return result.data()["companyEmail"];
}
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.white,
title: Text(
"Create the company profile",
style: TextStyle(
color: Colors.black,
),
),
elevation: 0.0,
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: FutureBuilder(
future: getCompanyNameData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(snapshot.data);
},
),
),
ListTile(
leading: Icon(Icons.logout),
title: Text(
"Log Out",
),
onTap: () async {
await _authService.signOut();
},
),
],
),
),
body: Padding(
padding: const EdgeInsets.all(18.0),
child: SingleChildScrollView(
child: Container(
child: Form(
key: _formKey,
child: Column(
children: [
Row(
children: [
Text(
"Company name: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: [
FutureBuilder(
future: getCompanyNameData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(
snapshot.data,
style: TextStyle(
color: Colors.black, fontSize: 15.0),
);
},
),
],
),
SizedBox(
height: 20.0,
),
Row(
children: [
Text(
"Company email: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 10.0,
),
Row(
children: [
FutureBuilder(
future: getCompanyEmailData(),
builder: (_, AsyncSnapshot snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Text("Loading");
}
return Text(
snapshot.data,
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
);
},
),
IconButton(
icon: Icon(Icons.edit),
onPressed: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =>
EditCompanyEmailScreen(),
),
),
),
],
),
SizedBox(
height: 20.0,
),
Row(
children: [
Text(
"Company phone number: ",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
),
),
],
),
SizedBox(
height: 20.0,
),
// Here is where I want to add the image
Row(
children: <Widget>[],
),
],
),
),
),
),
),
);
}
}
To select the image from gallery add this plugin. And then call this function to select the image.
File _image;
selectImageFromGallery() async
{
final picker=ImagePicker();
setState(() {
inProcess=true;
});
final imageFile= await picker.getImage(source: ImageSource.gallery);
if(imageFile!=null)
{
_image=File(imageFile.path);
}
setState(() {
inProcess=false;
});
}
after selecting the image run this function to store image to firebase and get url of the image.
Future<String> uploadFile(File image) async
{
String downloadURL;
String postId=DateTime.now().millisecondsSinceEpoch.toString();
Reference ref = FirebaseStorage.instance.ref().child("images").child("post_$postId.jpg");
await ref.putFile(image);
downloadURL = await ref.getDownloadURL();
return downloadURL;
}
now lets upload and update data in firestore docs and storage.
uploadToFirebase()async
{
String url=await uploadFile(_image); // this will upload the file and store url in the variable 'url'
await users.doc(uid).update({ //use update to update the doc fields.
'url':url
});
}
To show the selected image add this in your Ui:-
Container(
height: 200,
width: 200,
decoration: BoxDecoration(image: DecorationImage(image: FileImage(_image,),fit: BoxFit.contain)),
)
After adding this image make a button for upload:-
RaisedButton()
{
onPressed:(){
uploadToFirebase();
},
child:Text("Upload"),
}
After selecting the image user will click on this button to upload and save sata to firebase.
You need to upload the image chosen from gallery to your firebase storage and then use the url in your firestore.
here is a samle code to upload the image to storage
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
final ref = firebase_storage.FirebaseStorage.instance.ref().child("profile-pic/abc.jpg");
final imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
final uploadTask = ref.putFile(imageFile);
final snapshot = await uploadTask.whenComplete(() => null);
imageUrl = await snapshot.ref.getDownloadURL();
use the imageUrl and update it in your firestore collection for the user.
You can fetch the url and display image whenever you need.

The following NoSuchMethodError was thrown building MessageBubble(dirty): The getter 'millisecondsSinceEpoch' was called on null

So, i am creating an mobile chat app (only to learn). I am trying to make it push the timestamp of the message (from firebase) to display it on the screen using the time_formatter package. It is actually working, but everytime i send a message, the emulator screen gets red for about 1 second and this error is thrown:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building MessageBubble(dirty):
The getter 'millisecondsSinceEpoch' was called on null.
Receiver: null
Tried calling: millisecondsSinceEpoch
The relevant error-causing widget was:
MessageBubble file:///C:/Users/cauer/Desktop/Apps-Flutter/flash_chat_flutter/lib/screens/chat_screen.dart:141:33
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 MessageBubble.build (package:flash_chat/screens/chat_screen.dart:208:32)
#2 StatelessElement.build (package:flutter/src/widgets/framework.dart:4576:28)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
After this, it shows exactly what I want on the screen, but I do want to know what is going on and fix it. Sorry for anything, I'm knew here. If needed, I post more of my code or any other info, but I im quite certain that it is caused by something here.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:time_formatter/time_formatter.dart';
final _firestore = Firestore.instance;
FirebaseUser loggedInUser;
class ChatScreen extends StatefulWidget {
static String id = 'chat_screen';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextController = TextEditingController();
final _auth = FirebaseAuth.instance;
String messageText;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
void messageStream() async {
await for (var snapshot in _firestore.collection('messages').snapshots()) {
for (var message in snapshot.documents) {
print(message.data);
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextController.clear();
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'timestamp': FieldValue.serverTimestamp(),
}).then((value) => print('${value.documentID} added'));
messageTextController.clear();
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('messages')
.orderBy('timestamp', descending: false)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final messageTime = message.data['timestamp']; //add this
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
time: messageTime,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
children: messageBubbles,
),
);
},
);
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.sender, this.text, this.isMe, this.time});
final String sender;
final String text;
final bool isMe;
final Timestamp time;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
'$sender',
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0))
: BorderRadius.only(
topRight: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0)),
elevation: 5.0,
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 20.0),
child: Text(
'$text',
style: TextStyle(
color: isMe ? Colors.white : Colors.black54,
fontSize: 15,
),
),
),
),
Text(
'${formatTime(time.millisecondsSinceEpoch)}',
style: TextStyle(
fontSize: 11.0,
color: Colors.black54,
),
),
],
),
);
}
}
Any kind of help will be appreciated, already looked for an answer and couldn't find it.
This is what the screen displays in the moment that the message is sent
Modify your MessageBubble constructor as such
MessageBubble({this.sender, this.text, this.isMe, Timestamp time}):time = time ?? Timestamp.now();
The problem is FieldValue.serverTimestamp() is null when firestore writes the data locally
I think this should work.
Make a separate function, so that you can handle if time is null.
Widget handleerr() async{
await Future.delayed(const Duration(milliseconds: 2000), () {
setState(() {
Text(
'${formatTime(time.millisecondsSinceEpoch)}',
style: TextStyle(
fontSize: 11.0,
color: Colors.black54,
)
});
});
}

Flutter Firebase Iterator Error with FutureBuilder

Running my App on Android and iOS I get the Error shown below. What I want to do, give every Data that get's added a Author, the Author should be the Mail Adress the User Registers with, so by Inviting other Users get Access to this Data.
Another Problem is that in Line 302 the String "user" is unused.
Do i really need to use this String?
Error
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building FutureBuilder<FirebaseUser>(dirty, state: _FutureBuilderState<FirebaseUser>#7f7ed):
The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
The relevant error-causing widget was
FutureBuilder<FirebaseUser>
lib/…/MealPlan/mealTile.dart:92
When the exception was thrown, this was the stack
Code
import 'package:flutter/material.dart';
import 'package:mealapp/models/Widgets/whenAndWhatToEat.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:mealapp/models/global.dart';
import 'package:status_alert/status_alert.dart';
import 'package:firebase_auth/firebase_auth.dart';
class MealTile extends StatefulWidget {
final MealsAndWhen mealsAndWhen;
MealTile({this.mealsAndWhen});
#override
MealTileState createState() {
return MealTileState();
}
}
class MealTileState extends State<MealTile> {
String id;
final db = Firestore.instance;
String mail;
List<String> authors = [];
DateTime selectedDate = DateTime.now();
Future pickDate() async {
DateTime datepick = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime.now().add(Duration(days: 0)),
lastDate: new DateTime.now().add(Duration(days: 365)));
if (datepick != null)
setState(() {
selectedDate = datepick;
});
}
Future<String> inputData() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.uid : null;
}
Future<String> inputDataMail() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.email : null;
}
String userId;
void _getUserId() {
inputData().then((value) => setState(() {
userId = value;
}));
}
String currentMail;
void _getMail(doc) {
inputDataMail().then((value) => setState(() {
currentMail = value;
}));
}
/*void _getAuthors(DocumentSnapshot doc) async {
authors = [];
//if (await FirebaseAuth.instance.currentUser() != null) {
authors = List.from(doc.data['Authors']);
print(doc.data['authors']);
//authors.insert(0, currentMail);
//}
}*/
Widget buildItem(DocumentSnapshot doc) {
DateTime now = doc.data['Date'].toDate();
DateFormat formatter = DateFormat('dd-MM-yyyy');
String formatted = formatter.format(now);
_getUserId();
_getMail(doc);
if (doc.data['Authors'] != null) {
//_getAuthors(doc);
//print('Current mail: ' + currentMail + authors.toString() + doc.data['Author'] + doc.data['Meal']);
}
if (now.day == DateTime.now().day) { // If the Date of the meal is today
deleteData(doc, false); // Delete it!
}
// You could also change ".day" to ".hour".
// Example: if (now.day == DateTime.now().day && now.hour == DateTime.hour())
// So, if a meal is set for 2PM, it will delete at 2PM
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
margin: const EdgeInsets.all(8.0),
child: currentMail == doc.data['Author'] || // If the current mail is the author
List.from(doc.data['Authors']).contains(currentMail) // Or if the current mail is part of the authors
? Column( // then if true, show a Column
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Meal:',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Text(
'${doc.data['Meal']}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
Text(
'When:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () => updateData(doc),
color: lightBlueColor,
icon: Icon(Icons.calendar_today,
color: Colors.white),
tooltip: 'Update Date',
),
Text(
formatted,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(width: 8),
FlatButton(
color: Colors.red,
onPressed: () => deleteData(doc, true),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Delete',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.delete_forever, color: Colors.white),
]),
),
SizedBox(width: 8),
FlatButton(
color: Colors.blue,
onPressed: () => [
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
child: invite(doc),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12)),
),
);
})
],
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Invite',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.share, color: Colors.white),
]),
),
],
),
],
)
: Text(''), // if false, show an empty text widget
decoration: BoxDecoration(
color: lightBlueColor,
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
else {
return CircularProgressIndicator();
}
/*Navigator.pop(context);
return HomePage();*/
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: darkGreyColor,
body: ListView(
padding: EdgeInsets.only(top: 220),
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: db
.collection('mealList')
.orderBy('Date', descending: false) // Order by Date, not descending
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return Container();
}
},
),
],
),
);
}
/*share(BuildContext context, DocumentSnapshot doc) {
final RenderBox box = context.findRenderObject();
final dynamic date = timeago.format(doc['Date'].toDate());
Share.share(
"${doc['Meal']} - $date",
subject: doc['Meal'],
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}*/
Widget invite(DocumentSnapshot doc) {
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Center(
child: Text(
"Invite someone by mail",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
)),
SizedBox(
height: 24,
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
labelText: 'Enter the email address'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter an email address';
}
return null;
},
onSaved: (value) => mail = value,
),
FlatButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
saveInviteToFirestore(doc, mail);
}
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text("Save"),
color: redColor,
textColor: Colors.white,
),
]),
),
);
}
Future<String> getCurrentUser() async {
return await FirebaseAuth.instance.currentUser().then((value) => value.uid);
}
void saveInviteToFirestore(DocumentSnapshot doc, String email) async {
final String user = await getCurrentUser();
var list = List<String>();
list.add(email);
Firestore.instance
.collection('mealList')
.document(doc.documentID)
.updateData({"Authors": FieldValue.arrayUnion(list)});
//setState(() => id = doc.documentID);
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Added',
subtitle: 'You have Added your and the Date to your List',
configuration: IconConfiguration(icon: Icons.done),
);
//Navigator.pop(context);
}
void deleteData(DocumentSnapshot doc, bool showMessage) async {
await db.collection('mealList').document(doc.documentID).delete();
setState(() => id = null);
if (showMessage) {
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Deleted',
subtitle: 'You have Deleted your Meal',
configuration: IconConfiguration(icon: Icons.delete),
);
}
}
void updateData(DocumentSnapshot doc) async {
await pickDate();
await db
.collection('mealList')
.document(doc.documentID)
.updateData({'Date': selectedDate});
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Updated',
subtitle: 'You have updated your Meal Date',
configuration: IconConfiguration(icon: Icons.done),
);
}
}

Flutter & Firebase: Error with FutureBilder

Currently i develop a Meal and Shopping App. In this App you can Add what you want to Eat next and have the secound Tab, Shopping where you can Add your Items you want to buy next. Created is that a User can invite another User to edit together the List.
I get the Error shown below. I can't figure out how to return the Container. At the void saveInviteToFirestore the user is not used do I need that it used?
Code
import 'package:flutter/material.dart';
import 'package:mealapp/models/Widgets/whenAndWhatToEat.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:mealapp/models/global.dart';
import 'package:status_alert/status_alert.dart';
import 'package:firebase_auth/firebase_auth.dart';
class MealTile extends StatefulWidget {
final MealsAndWhen mealsAndWhen;
MealTile({this.mealsAndWhen});
#override
MealTileState createState() {
return MealTileState();
}
}
class MealTileState extends State<MealTile> {
String id;
final db = Firestore.instance;
String mail;
List<String> authors = [];
DateTime selectedDate = DateTime.now();
Future pickDate() async {
DateTime datepick = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime.now().add(Duration(days: -0)),
lastDate: new DateTime.now().add(Duration(days: 365)));
if (datepick != null)
setState(() {
selectedDate = datepick;
});
}
Future<String> inputData() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.uid : null;
}
Future<String> inputDataMail() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.email : null;
}
String userId;
void _getUserId() {
inputData().then((value) => setState(() {
userId = value;
}));
}
String currentMail;
void _getMail(doc) {
inputDataMail().then((value) => setState(() {
currentMail = value;
}));
}
/*void _getAuthors(DocumentSnapshot doc) async {
authors = [];
//if (await FirebaseAuth.instance.currentUser() != null) {
authors = List.from(doc.data['Authors']);
print(doc.data['authors']);
//authors.insert(0, currentMail);
//}
}*/
Widget buildItem(DocumentSnapshot doc) {
DateTime now = doc.data['Date'].toDate();
DateFormat formatter = DateFormat('dd-MM-yyyy');
String formatted = formatter.format(now);
_getUserId();
_getMail(doc);
if (doc.data['Authors'] != null) {
//_getAuthors(doc);
//print('Current mail: ' + currentMail + authors.toString() + doc.data['Author'] + doc.data['Meal']);
}
if (now.day == DateTime.now().day) { // If the Date of the meal is today
deleteData(doc, false); // Delete it!
}
// You could also change ".day" to ".hour".
// Example: if (now.day == DateTime.now().day && now.hour == DateTime.hour())
// So, if a meal is set for 2PM, it will delete at 2PM
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
margin: const EdgeInsets.all(8.0),
child: currentMail == doc.data['Author'] || // If the current mail is the author
List.from(doc.data['Authors']).contains(currentMail) // Or if the current mail is part of the authors
? Column( // then if true, show a Column
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Meal:',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Text(
'${doc.data['Meal']}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
Text(
'When:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () => updateData(doc),
color: lightBlueColor,
icon: Icon(Icons.calendar_today,
color: Colors.white),
tooltip: 'Update Date',
),
Text(
formatted,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(width: 8),
FlatButton(
color: Colors.red,
onPressed: () => deleteData(doc, true),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Delete',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.delete_forever, color: Colors.white),
]),
),
SizedBox(width: 8),
FlatButton(
color: Colors.blue,
onPressed: () => [
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
child: invite(doc),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12)),
),
);
})
],
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Invite',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.share, color: Colors.white),
]),
),
],
),
],
)
: Text(''), // if false, show an empty text widget
decoration: BoxDecoration(
color: lightBlueColor,
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
/*Navigator.pop(context);
return HomePage();*/
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: darkGreyColor,
body: ListView(
padding: EdgeInsets.only(top: 220),
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: db
.collection('mealList')
.orderBy('Date', descending: false) // Order by Date, not descending
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return Container();
}
},
),
],
),
);
}
/*share(BuildContext context, DocumentSnapshot doc) {
final RenderBox box = context.findRenderObject();
final dynamic date = timeago.format(doc['Date'].toDate());
Share.share(
"${doc['Meal']} - $date",
subject: doc['Meal'],
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}*/
Widget invite(DocumentSnapshot doc) {
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Center(
child: Text(
"Invite someone by mail",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
)),
SizedBox(
height: 24,
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
labelText: 'Enter the email address'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter an email address';
}
return null;
},
onSaved: (value) => mail = value,
),
FlatButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
saveInviteToFirestore(doc, mail);
}
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text("Save"),
color: redColor,
textColor: Colors.white,
),
]),
),
);
}
Future<String> getCurrentUser() async {
return await FirebaseAuth.instance.currentUser().then((value) => value.uid);
}
void saveInviteToFirestore(DocumentSnapshot doc, String email) async {
final String user = await getCurrentUser();
var list = List<String>();
list.add(email);
Firestore.instance
.collection('mealList')
.document(doc.documentID)
.updateData({"Authors": FieldValue.arrayUnion(list)});
//setState(() => id = doc.documentID);
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Added',
subtitle: 'You have Added your and the Date to your List',
configuration: IconConfiguration(icon: Icons.done),
);
//Navigator.pop(context);
}
void deleteData(DocumentSnapshot doc, bool showMessage) async {
await db.collection('mealList').document(doc.documentID).delete();
setState(() => id = null);
if (showMessage) {
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Deleted',
subtitle: 'You have Deleted your Meal',
configuration: IconConfiguration(icon: Icons.delete),
);
}
}
void updateData(DocumentSnapshot doc) async {
await pickDate();
await db
.collection('mealList')
.document(doc.documentID)
.updateData({'Date': selectedDate});
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Updated',
subtitle: 'You have updated your Meal Date',
configuration: IconConfiguration(icon: Icons.done),
);
}
}
Error
The following assertion was thrown building FutureBuilder<FirebaseUser>(dirty, state: _FutureBuilderState<FirebaseUser>#a4504):
A build function returned null.
The offending widget is: FutureBuilder<FirebaseUser>
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The relevant error-causing widget was
FutureBuilder<FirebaseUser>
lib/…/MealPlan/mealTile.dart:92
When the exception was thrown, this was the stack
#0 debugWidgetBuilderValue.<anonymous closure>
package:flutter/…/widgets/debug.dart:276
In your FutureBuilder you are not returning anything when the Future hasn't completed yet. A widget always needs to be returned whether there is data or not.
Example fix for your code:
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
...
);
}
//ADDED ELSE BLOCK
else {
return Container();
}
}
);
Or as #stacker suggested, you can return a CircularProgressIndicator().

Firestore value returns only one value

whenever I try to retrieve data from firestore,only one part is called
You can see that I have a ListTile with a title and a Subtitle
Now only the data in the subtitle is being displayed and it requires no null indication
But the title requires the null indication but still it does not returns the string This is my firestore
Thank You
// ...
class SearchPage extends StatefulWidget {
#override
_SearchPageState createState() => _SearchPageState();
}
class _SearchPageState extends State<SearchPage> {
TextEditingController searchController = TextEditingController();
Future<QuerySnapshot> searchResultsFuture;
handleSearch(String query){
Future<QuerySnapshot> users = usersReference.where("profilename",isGreaterThanOrEqualTo: query ).getDocuments();
setState(() {
searchResultsFuture = users;
});
//searchResultsFuture = users;
}
clearSearch(){
searchController.clear();
}
AppBar buildSearchField(){
return AppBar(
backgroundColor: Colors.white,
title: TextFormField(
controller: searchController,
decoration: InputDecoration(
hintText: "Search Your Friends",
filled: true,
prefixIcon: Icon(
Icons.account_box,
size: 28.0,
),
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: clearSearch,
),
),
onFieldSubmitted: handleSearch,
),
);
}
Container buildNoContent(){
final Orientation orientation = MediaQuery.of(context).orientation;
return Container(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Icon(Icons.group, color: Colors.white,size: orientation == Orientation.portrait ? 400.0 : 200.0 ,),
Text("Find Users",textAlign: TextAlign.center,style: TextStyle(color: Colors.white,fontStyle: FontStyle.italic,fontWeight: FontWeight.w600,fontSize: 65.0),),
],
),
);
}
buildSearchResults() {
return FutureBuilder(
future: searchResultsFuture,
builder: (context, snapshot){
if(!snapshot.hasData){
return circularProgress();
}
List<UserResult> searchResults = [];
snapshot.data.documents.forEach((doc){
User user = User.fromDocument(doc);
UserResult searchResult = UserResult(user);
searchResults.add(searchResult);
});
return ListView(
children: searchResults,
);
}
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor.withOpacity(0.8) ,
appBar: buildSearchField(),
body: searchResultsFuture == null ? buildNoContent() : buildSearchResults(),
);
}
}
class UserResult extends StatelessWidget {
final User eachUser;
UserResult(this.eachUser);
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).primaryColor.withOpacity(0.7),
child: Column(children: <Widget>[
GestureDetector(
onTap: ()=> print("tapped"),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.grey,
backgroundImage: CachedNetworkImageProvider(eachUser.url),
),
title: eachUser.profileName != null ? Text(eachUser.profileName,
style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold),): 'User',
subtitle: Text(eachUser.username,style: TextStyle(color: Colors.white),),
),
),
Divider(
height: 2.0,
color: Colors.white54,
),
],),
);
}
}
try uploading a more detailed code so as to get insights of what might be wrong.
I thinnk you shoud try to call setSate in
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((callback) async {
/// logic here!
eachUser = get data from firebase;
after that call setState();
});
}
I think the proplem is:
Future<QuerySnapshot> users = usersReference.where("profilename",isGreaterThanOrEqualTo: query ).getDocuments();
setState(() {
searchResultsFuture = users;
});
searchResultsFuture get value when users hadn't completed

Resources