How to update and delete a data in a list according to it's document id - flutter, firebase 2021 - firebase

I am trying to delete and update a list of details in flutter. For that i used doc('document_id') which was given as a solution in another stackoverflow question. I tried some another solutions given in stacker flow too. But nothing fork for me. But if I give a specific documentID I am able to delete that. Also how can I pass the selected data to update page too.
class addressProfile extends StatefulWidget {
const addressProfile({Key? key}) : super(key: key);
#override
_addressProfileState createState() => _addressProfileState();
}
class _addressProfileState extends State<addressProfile> {
var Default = 'unDefault';
delete() async {
try {
FirebaseFirestore.instance
.collection("address")
.doc('document_id')
.delete();
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade100,
appBar: AppBar(
centerTitle: true,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
title: Text(
'My Addresses',
style: TextStyle(color: Colors.black),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Colors.black,
),
onPressed: () {
Navigator.of(context).pushNamed('/profilePage');
},
),
),
body: ListView(
padding: EdgeInsets.all(16),
children: [
StreamBuilder<QuerySnapshot>(
stream:
FirebaseFirestore.instance.collection("address").snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Expanded(
child: SizedBox(
height: 700,
child: ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
QueryDocumentSnapshot x = snapshot.data!.docs[index];
return Container(
child: Card(
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(x['firstName']),
Text(' '),
Text(x['lastName']),
],
),
Text(""),
Row(
children: [
Text(x['primaryPhone']),
Text(" / "),
Text(x['secondaryPhone']),
],
),
Text(''),
Row(
children: [
Text(x['address1']),
Text(', '),
Text(x['address2']),
Text(', '),
Text(x['city']),
Text(', '),
Text(x['region']),
],
),
Divider(
color: Colors.black,
),
Row(
children: [
Container(
child: Radio(
value: 'default',
groupValue: Default,
onChanged: (String? val) {
setState(() {
if (val != null)
Default = val;
});
}),
),
Container(
child: Text("Default"),
),
Container(
padding: EdgeInsets.only(left: 60),
child: Align(
child: ElevatedButton.icon(
onPressed: () {
if (snapshot.data!.docs.length >
1) {
delete();
Fluttertoast.showToast(
msg:
"Address deleted successfully",
toastLength:
Toast.LENGTH_SHORT,
gravity:
ToastGravity.BOTTOM,
textColor: Colors.black,
backgroundColor:
Colors.green.shade400,
);
} else {
Fluttertoast.showToast(
msg:
"Main address cannot be deleted",
toastLength:
Toast.LENGTH_SHORT,
gravity:
ToastGravity.BOTTOM,
textColor: Colors.black,
backgroundColor:
Colors.green.shade400,
);
}
},
label: Text('Delete'),
style: ElevatedButton.styleFrom(
fixedSize: Size(90, 20),
primary: Colors.red.shade500,
padding: EdgeInsets.symmetric(
horizontal: 5,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10))),
icon: Icon(
Icons.delete_outline_sharp),
),
),
),
Container(
padding: EdgeInsets.only(left: 14),
child: Align(
child: ElevatedButton.icon(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (builder) =>
updateAddress(),
),
);
},
label: Text('Update'),
style: ElevatedButton.styleFrom(
fixedSize: Size(90, 20),
primary:
Colors.green.shade500,
padding: EdgeInsets.symmetric(
horizontal: 5,
),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
10))),
icon: Icon(Icons.edit),
),
),
),
],
),
],
),
),
),
);
},
),
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}),
Align(
alignment: AlignmentDirectional.bottomCenter,
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed('/addNewAddress');
},
child: Text(
"Add New Address",
style: TextStyle(
fontSize: 15,
letterSpacing: 2,
color: Colors.black,
),
),
style: ElevatedButton.styleFrom(
fixedSize: Size(250, 40),
primary: Colors.green.shade500,
padding: EdgeInsets.symmetric(
horizontal: 50,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))),
),
),
],
),
);
}
}
This is so far I did. Please help me to continue.

I don't know how you have saved the data. But I got an issue like this and what I did was, I added a variable as "id" to database while saving the data. There is an auto generated id plugin for flutter (nanoid). You can add that and save the data as following.
var id = nanoid(10) //10 is the length of the id. You can give as you wish
create() async {
try {
FirebaseFirestore.instance
.collection("address")
.doc(id)
.set({
"id":id,
//other inputs
});
} catch (e) {
print(e);
}
}
Then you can use that id as a key to update ad delete.
For example according to you code to delete you can use like this in the onPress(){} of delete button,
FirebaseFirestore.instance.collection("address").doc(x['id']).delete();
So the data related to id will be deleted.
Also better to use proper name rather than "x".

Can you please try this
delete(String docId) async {
try {
FirebaseFirestore.instance
.collection("address")
.doc(docId)
.delete();
} catch (e) {
print(e);
}
}
Your delete function call
delete(snapshot.data!.docs[index].id);
Update document
void update(String docId){
FirebaseFirestore.instance.collection("address").doc(docId) .update({"field1":"fieldValue1","field2":"fieldValue2"});
}
Let me know if you find any issues in comment

Related

Flutter update UI on button press

If I remove the awaits from my viewModel.sendMessage() it works as expected, however I can't set the state with the value returned. Is there a way to update the UI from setState?
I'm just not sure how to do both at the same time, the parent class for this widget is a StatefulWidget, Idk if that matters. My ConversationViewModel is just a changeNotifier.
#override
Widget build(BuildContext context) {
UsViewModel viewModel = Provider.of<UsViewModel>(context, listen: false);
viewModel.setUs();
var us = Provider.of<UsViewModel>(context, listen: true).us;
return Consumer<ConversationViewModel>(builder: (BuildContext context, viewModel, Widget child) {
return Scaffold(
key: viewModel.scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
List messages = snapshot.data.docs;
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data());
return ChatBubble(
message: '${message.content}',
time: message?.time,
isMe: message?.senderUid == us?.uid,
type: message?.type);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color:
Theme.of(context).textTheme.headline6.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Feather.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.trim().isNotEmpty) {
sendMessage(viewModel, us);
}
},
),
],
),
),
),
)
],
),
),
);
});
}
sendMessage(ConversationViewModel viewModel, var us,
{bool isImage = false, int imageType}) async {
String msg;
msg = messageController.text.trim();
messageController.clear();
Message message = Message(
content: '$msg',
senderUid: us?.uid,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
String id = await viewModel.sendMessage(widget.usId, message);
setState(() {
chatId = id;
});
}
}
If you using ChangeNotifier with Provider package you don't need setState method. You should read Provider documentation: https://pub.dev/packages/provider
ft: That you create listeners for each item in this line.
isMe: message?.senderUid == context.watch<UsViewModel>.us ?.uid,
How to use a provider according to your question, added an example;
#override
Widget build(BuildContext context) {
context.read<UsViewModel>().setUs();
return Scaffold(
key: context.read<UsViewModel>().scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
List messages = snapshot.data.docs;
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data());
return ChatBubble(
message: '${message.content}',
time: message?.time,
isMe: message?.senderUid == context.watch<UsViewModel>.us ?.uid,
type: message?.type);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color:
Theme.of(context).textTheme.headline6.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Feather.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.trim().isNotEmpty) {
sendMessage(context);
}
},
),
],
),
),
),
)
],
),
),
);
}
sendMessage(BuildContext context) async {
String msg;
msg = messageController.text.trim();
messageController.clear();
Message message = Message(
content: '$msg',
senderUid: context.read<UsViewModel>().us?.uid,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
String id = await context.read<UsViewModel>().sendMessage(widget.usId, message);
setState((){
chatId = id;
});
}
}

Error is not showing after scanning a item thats not on the firestore database

I did this personal project of mine where a barcode scanner would scan for data inside firestore database. I have this problem when I scanned a barcode thats not on the database it wont show the error message is just shows a empty scan item container which I made. Let me know if someone can figure why. I tried everything still couldnt fix it.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("products")
.where("barcode", isEqualTo: '$barcodeScanRes')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
#Scan Card
class ScanCard extends StatelessWidget {
const ScanCard({
Key? key,
required this.products,
}) : super(key: key);
final DocumentSnapshot products;
#override
Widget build(BuildContext context) {
final user = FirebaseAuth.instance.currentUser;
String _userId = user!.uid;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.all(10.0),
height: 180,
width: 160,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(16)),
child: Image.network(products['img']),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0 / 4),
child: Text(
products['name'],
style: TextStyle(
color: Colors.blueGrey,
fontSize: 18,
),
),
),
Column(
children: [
Text(
"Size: " + products['size'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: Colors.brown),
),
SizedBox(
width: 30,
),
],
),
Row(
children: [
Text(
"\tRs. " + products['price'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(
width: 40,
),
Icon(
Icons.add_shopping_cart,
color: Colors.black,
size: 25,
),
],
),
SizedBox(
width: 10,
),
SizedBox(
child: Padding(
padding: const EdgeInsets.all(10),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.red,
child: Text(
"Add to cart",
style: TextStyle(color: Colors.white),
),
onPressed: () {
DocumentReference documentReference = FirebaseFirestore.instance
.collection('userData')
.doc(_userId)
.collection('cartData')
.doc();
documentReference.set({
'uid': FirebaseAuth.instance.currentUser!.uid,
'barcode': products['barcode'],
'img': products['img'],
'name': products['name'],
'size': products['size'],
'price': products['price'],
'id': documentReference.id
}).then((result) {
addToCartMessage(context).then((value) => {
Navigator.pop(context)
});
}).catchError((e) {
print(e);
});
},
),
),
)
],
);
}
}
The thing is you are showing Product not found based on the condition:- !snapshot.hasData but this conditon means that data is being fetched so at this time rather show a progress indicator.
And to handle when data is not present in backend then add another condition:- if(snapshot.data.docs.isEmpty) and here show your dialogbox of Product not found...
Final Code Snippet will look like:-
if (!snapshot.hasData)
return Center(child:CircularProgressIndicator));//or return a black container if you don't want to show anything while fetching data from firestore
else if (snapshot.data.docs.isEmpty) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
}

type 'Future<dynamic>' is not a subtype of type 'Widget?'

IM trying to call on Tap method, what I want now is change it to a future method because on Tap the method is not ready because im calling a firebase query . So heres first my method
where the onTap function is
child: InkWell(
onTap: () async {
setState(() {
israting = true;
});
},
child: israting
? buildBody(videos.data()['likes'], videos.data()['id'])
: Icon(
Icons.star,
size: 37,
color: videos.data()['likes'].contains(uid)
? Colors.yellow
: Colors.white,
),
),
So im giving the buildBody 2 parameters from a streambuilder
and then thats the function
buildBody(videoid, video) async {
if (videoid.contains(uid)) {
await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get()
.then((value) {
votefromfirebase = value.data()["rating"];
});
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: votefromfirebase,
itemBuilder: (context, index) => InkWell(
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
print(video);
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
));
} else {
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: _userRating,
itemBuilder: (context, index) => InkWell(
onTap: () {
setState(() {
_userRating = index + 1.toDouble();
});
likevideo(video, _userRating);
},
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
),
);
}
}
buildprofile(String url) {
return Container(
width: 50,
height: 50,
child: Stack(
children: [
Positioned(
left: (50 / 2) - (50 / 2),
child: Container(
width: 50,
height: 50,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
),
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: url != null && url != "profilepictureer"
? Image.network(
url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(color: Colors.black, width: 4)),
),
),
),
],
),
);
}
}
At the moment im getting this error
The following _TypeError was thrown building:
type 'Future<dynamic>' is not a subtype of type 'Widget?'
When the exception was thrown, this was the stack
#0 _VideopageofcurrentuserState.build.<anonymous closure>.<anonymous closure> (package:wichtigdenyady/taking%20videos/currentuservideos.dart:310:47)
#1 SliverChildBuilderDelegate.build
package:flutter/…/widgets/sliver.dart:455
#2 SliverMultiBoxAdaptorElement._build
package:flutter/…/widgets/sliver.dart:1201
#3 SliverMultiBoxAdaptorElement.performRebuild.processElement
package:flutter/…/widgets/sliver.dart:1145
#4 Iterable.forEach (dart:core/iterable.dart:257:30)
The error throws in the onTap function
The buildBody function cannot be an async function.
You should move the call to Firebase out of this function and use the result of it in state, instead.
An async function always returns a Future. Because the return type isn't defined, it assumes it will return a Future<dynamic>. If you defined the return type as Widget buildBody(videoid, video) async, the IDE would show an error.
In your onTap function, you can make the call:
onTap: () async {
setState(() {
israting = true;
});
if(!videos.data()['likes'].contains(uid)) return; // don't call firebase if uid is not in videoid
final value = await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get();
setState(() {
votefromfirebase = value.data()["rating"];
});
},
Next, change the buildBody function to a non-async function and check if votefromfirebase is in the state
Widget buildBody(videoid, video) {
if (votefromfirebase == null) {
return Container(); // return empty container, progress indicator, or anything else
}
// else return the normal body
return Container(
child: Stack(
// rest of this widget

FLUTTER Profile picture disappears when user leaves page

Please guys I really need help with this, I implemented an upload profile picture in my user profile page, everything works fine, the only problem is that the uploaded image disappears immediately when the user navigate away from this screen and come back to this same particular screen.
Looking forward to you awesome folks response, Thanks
This is the code that handles file selected and picture upload
class _UserProfileState extends State<UserProfile> {
DocumentSnapshot userDoc;
File _image;
String _uploadedFileURL;
Future chooseFile() async {
await ImagePicker.pickImage(source: ImageSource.gallery).then((image) {
setState(() {
_image = image;
});
});
uploadImage(_image);
}
Future<String> uploadImage(var imageFile) async {
StorageReference ref = FirebaseStorage.instance
.ref()
.child('chats/${Path.basename(_image.path)}}');
StorageUploadTask uploadTask = ref.putFile(imageFile);
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();
_uploadedFileURL = dowurl.toString();
return _uploadedFileURL;
}
This is my user profile page screen
#override
Widget build(BuildContext context) {
var firebaseUser = FirebaseAuth.instance.currentUser;
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('user_profile')
.doc(firebaseUser.uid)
.snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
userDoc = snapshot.data;
return SafeArea(
child: Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.edit,
color: Colors.white,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return EditUserProfile(userData: userDoc);
},
),
);
},
),
body: SafeArea(
child: Container(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: IconButton(
onPressed: () {
Navigator.pushNamed(context, Homepage.id);
},
icon: Icon(
Icons.arrow_back,
color: Colors.white,
size: 30,
),
),
),
GestureDetector(
onTap: chooseFile,
child: Stack(
children: [
CircleAvatar(
radius: 70,
backgroundColor: Colors.transparent,
child: Container(
child: _uploadedFileURL == null
? ImageBeforeUpload(
image: _image, //This shows immediately when user chooses an image
// onTap: chooseFile,
)
: ImageUploaded(
uploadedFileURL: _uploadedFileURL // //This shows when image has been uploaded successfully but disappears when user leaves page and come back to this page
),
),
),
Positioned(
bottom: 0,
right: 0,
child: CircleAvatar(
backgroundColor: Colors.white60,
radius: 25,
child: IconButton(
onPressed: chooseFile,
icon: Icon(Icons.edit, color: Colors.blueGrey),
),
),
)
],
),
),
SizedBox(
height: 10,
),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userDoc.data()['nickname'] ?? '',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w900),
),
VerticalDivider(
thickness: 3,
width: 20,
color: Colors.white,
),
Text(
userDoc.data()['age'] ?? '',
style: TextStyle(
color: Colors.white,
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Card(
child: Column(
children: [
ListTile(
leading: Icon(
Icons.person,
size: 40,
),
title: Text("About me"),
isThreeLine: false,
dense: true,
subtitle: Text(userDoc.data()['aboutMe'] ?? ''),
trailing: Icon(Icons.arrow_right),
)
],
),
),
),
Expanded(
child: Container(
width: 400,
child: ListView(
children: [
ProfileListTile(
leading: Icons.phone_in_talk,
title: 'Phone Number',
subtitle: userDoc.data()['mobile'] ?? '',
),
ProfileListTile(
leading: Icons.add_location,
title: 'Current Location',
subtitle: userDoc.data()['location'] ?? '',
),
ProfileListTile(
leading: FontAwesomeIcons.heartbeat,
title: 'Relationship Status',
subtitle: userDoc.data()['maritalStatus'] ?? '',
),
ProfileListTile(
leading: Icons.people,
title: 'Gender',
subtitle: userDoc.data()['gender'] ?? '',
),
ProfileListTile(
leading: Icons.looks,
title: 'Interested In',
subtitle: userDoc.data()['interestedIn'] ?? '',
),
// Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 50.0, vertical: 10),
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Column(
// children: [
// IconButton(
// icon: Icon(Icons.phone,
// color: Colors.white),
// onPressed: null),
// Text(
// 'Call Me',
// style: klistTileTitle,
// ),
// ],
// ),
// Column(
// children: [
// IconButton(
// icon: Icon(Icons.message,
// color: Colors.white),
// onPressed: null),
// Text(
// 'Message',
// style: klistTileTitle,
// )
// ],
// ),
// Column(
// children: [
// IconButton(
// icon: FaIcon(
// FontAwesomeIcons.whatsapp,
// color: Colors.white,
// ),
// onPressed: () async {}),
// Text('Whatsapp', style: klistTileTitle)
// ],
// ),
// ],
// ),
// )
],
),
),
),
],
),
),
),
),
);
},
);
And finally this are the classes that handles what to display picture upload was success.
class ImageUploaded extends StatelessWidget {
ImageUploaded({this.uploadedFileURL});
final String uploadedFileURL;
#override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 80,
child: ClipOval(
child: uploadedFileURL != null
? Image.network(uploadedFileURL,
height: 200, width: 200, fit: BoxFit.fill)
: Image.asset('assets/avatar_profile.jpg'),
),
);
}
}
class ImageBeforeUpload extends StatelessWidget {
ImageBeforeUpload({this.image});
final File image;
#override
Widget build(BuildContext context) {
return GestureDetector(
child: CircleAvatar(
radius: 70,
child: ClipOval(
child: image != null
? Image.asset(image.path,
height: 200, width: 200, fit: BoxFit.fill)
: Image.asset('assets/avatar_profile.jpg'),
),
),
);
}
}

Error while returning the number of count of collections in firebase flutter?

i'm developing an admin app in that i'm tired to return the number of users from firebase, i got few help from stackoverflow and was able to print in the terminal but its returning null on the app can someone please help me.this my code
class _AdminState extends State<Admin> {
Future<String> getUsersCount() async{
var length = -1;
await Firestore.instance.collection('users').getDocuments().then((myDocuments){
print("${myDocuments.documents.length}");
length = myDocuments.documents.length;
});
return Future.value(length.toString());
}
Page _selectedPage = Page.dashboard;
MaterialColor active = Colors.indigo;
MaterialColor notActive = Colors.grey;
final databaseReference = Firestore.instance;
bool isDelete= true;
var values;
TextEditingController categoryController = TextEditingController();
TextEditingController brandController = TextEditingController();
GlobalKey<FormState> _categoryFormKey = GlobalKey();
//GlobalKey<FormState> _brandFormKey = GlobalKey();
// BrandService _brandService = BrandService();
CategoryService _categoryService = CategoryService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: <Widget>[
Expanded(
child: FlatButton.icon(
onPressed: () {
setState(() => _selectedPage = Page.dashboard);
},
icon: Icon(
Icons.dashboard,
color: _selectedPage == Page.dashboard
? active
: notActive,
),
label: Text('Dashboard'))),
Expanded(
child: FlatButton.icon(
onPressed: () {
setState(() => _selectedPage = Page.manage);
},
icon: Icon(
Icons.sort,
color:
_selectedPage == Page.manage ? active : notActive,
),
label: Text('Manage'))),
],
),
elevation: 0.0,
backgroundColor: Colors.white,
),
body: _loadScreen());
}
Widget _loadScreen() {
switch (_selectedPage) {
case Page.dashboard:
return FutureBuilder(
future: getUsersCount(),
builder: (BuildContext context, AsyncSnapshot<String> text) {
print(text);
if(text== "-1"){
return CircularProgressIndicator();
} else {
return Column(
children: <Widget>[
ListTile(
subtitle: Text('Admin View', textAlign: TextAlign.center,
style: TextStyle(fontSize: 29.0,
color: Colors.indigo,
fontWeight: FontWeight.bold),),
),
Expanded(child: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,),
children: <Widget>[
Padding(
padding: const EdgeInsets.all(18.0), child: Card(
child: ListTile(title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.directions_boat, color: Colors.black,),
label: Text("Boats", style: TextStyle(
fontSize: 9, color: Colors.indigo),)),
subtitle: Text('3', textAlign: TextAlign.center,
style: TextStyle(
color: active, fontSize: 50.0),)),
),
),
Padding(padding: const EdgeInsets.all(18.0),
child: Card(child: ListTile(
title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.people, color: Colors.black,),
label: Text("Users", style: TextStyle(
fontSize: 9, color: Colors.indigo),)),
subtitle: Text(text.data != null ? text.data : '',
textAlign: TextAlign.center,
style: TextStyle(color: active, fontSize: 50.0),
)),
),
),
Padding(
padding: const EdgeInsets.all(22.0),
child: Card(
child: ListTile(
title: FlatButton.icon(
onPressed: null,
icon: Icon(
Icons.bookmark, color: Colors.black,),
label: Text("Bookings", style: TextStyle(
fontSize: 8, color: Colors.indigo),)),
subtitle: Text(
'120',
textAlign: TextAlign.center,
style: TextStyle(
color: active, fontSize: 50.0),
)),
),
),
],
),
),
],
);
} })
i was returning a null string value but when include this set of lines Text(text.data??'default value') i was able to clear that error but still not able to clear my issue someone please help me
You need to add await before getting data from Firestore, since it is and async and you are not waiting for the result and returning the value which is initialized to 0
Future<String> getUsersCount() async {
var length = 0;
await Firestore.instance.collection('users').getDocuments().then((myDocuments){
print("${myDocuments.documents.length}");
length = myDocuments.documents.length;
});
return Future.value(length.toString());
}
As you can see the value of users count(36) is getting printed but it is not return because the return gets called before the async execution is getting finish..
Initialize your length to -1 in getUsersCount method and then in build method before returning the cloumn widget check the text (snapshot value) :
if (text == "-1"){
return Center(
child: CircularProgressIndicator(backgroundColor: Colors.red,)
);
} else{
return Column(....)
}

Resources