Flutter Passing Document ID in Firestore Query - firebase

I am trying to figure out how to do this.
If I pass the document ID hardcoded it works. But Since I have multiple pages, I am trying to figure out how to pass it and then query it..
My main page has the following.
import 'package:flutter/material.dart';
import 'package:onlytag2/pages/category.dart';
import 'package:onlytag2/widget/maincard.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference = Firestore.instance.collection("mainCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
passData(DocumentSnapshot snap, String cat, String title) {
print(cat);
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Category(snapshot: snap, category: cat, title: title,)));
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"#",
style: TextStyle(
fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(
"onlytags",
style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),
)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () => passData(snapshot[index], snapshot[index].documentID.toString(), snapshot[index].data["title"] ),
child: MainCard(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
),
);
}),
),
],
),
),
],
),
);
}
}
The category widget is where I am having the problem.
Comment Listed where I am having the problem.
import 'package:flutter/material.dart';
import 'package:onlytag2/widget/sub.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Category extends StatefulWidget {
DocumentSnapshot snapshot;
final String category;
final String title;
Category({this.snapshot, this.category, this.title});
#override
_CategoryState createState() => _CategoryState();
}
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
//How do I get the category passed properly? I know it is the Document ID, but since it changes based on what button is pressed before,
//I cant figure out how to pass it..
Query collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
iconTheme: IconThemeData(
color: Color(0xffff9900),
),
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
"#", style: TextStyle(fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(widget.title.toLowerCase(), style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return Sub(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
);
}),
),
Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 15),)
],
),
),
],
),
);
}
}

I have realised that the code looks shady on the comment so let me make an answer.
What you are trying to do is currently not supported in flutter as can be seen at these GitHub issues 1 and 2.
Change your code to,
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference;
void initState() {
collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
...
Hope this helps.

Related

firebase firestore chat timestamp order not working corectly

below is my code, i have a chat made in flutter and it should be sorted by timestamp however it is still seemingly random, on firebase it is recording the correct time stamp in json and i thought i had it coded correctly with the firestore.collection order by call. image attached shows the messages they should be ordered 1-6
import 'package:flutter/material.dart';
import 'package:bardsf/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
late String messageText;
class BodyBuildingChat extends StatefulWidget {
static const String id = 'body_building_chat';
#override
_BodyBuildingChatState createState() => _BodyBuildingChatState();
}
class _BodyBuildingChatState extends State<BodyBuildingChat> {
final messageTextController = TextEditingController();
final _firestore = FirebaseFirestore.instance;
final _auth = FirebaseAuth.instance;
late User loggedInUser;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
loggedInUser = user;
print(loggedInUser.email);
}
} catch (e) {
print (e);
}
}
// void getMessages() async{
// final messages = await _firestore.collection('messages').get();
// for (var message in messages.docs) {
// print(message.data().cast());
// }
// }
void messagesStream() async {
await for( var snapshot in _firestore.collection('bodybuilding').orderBy('timestamp').snapshots()) {
for (var message in snapshot.docs) {
print(message.data().cast());
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
messagesStream();
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('🏔Body Building'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('bodybuilding').snapshots(),
builder: (context, snapshot){
List<MessageBubble> messageBubbles = [];
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data!.docs.reversed;
for (var message in messages) {
final messageText = message['text'];
final messageSender = message['sender'];
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
children: messageBubbles,
),
);
},
),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
TextButton(
onPressed: () {
messageTextController.clear();
_firestore.collection('bodybuilding').add({
'text': messageText,
'sender': loggedInUser.email,
'timestamp': FieldValue.serverTimestamp(),
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({required this.sender,required this.text,required this.isMe});
final String sender;
final String text;
final bool isMe;
#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,
),
),
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: 8.0, horizontal: 8.0),
child: Text('$text',
style: TextStyle( fontSize: 15.0,
color: isMe ? Colors.white : Colors.black,),
),
),
),
],
),
);
}
}
You did not use the appropriate stream.
Change this line
stream: _firestore.collection('bodybuilding').snapshots(),
into this line
stream: _firestore.collection('bodybuilding').orderBy('timestamp').snapshots(),
You will notice that you used the correct stream in the messagesStream but not in the StremBuilder.
Let me know if this does not help.

Cant Figure Out How To display Only the post details for the post I have clicked on

So I have this code here and I would like to display post details from firebase for the post which I have clicked on, but instead, it lists post details for every single post in the database one after another.
Can anyone help me figure out how I can make it so that when A post is clicked, details will show for only the post which was clicked, and not for all of the posts? Any help would be greatly appreciated, thank you.
The Info I would like to display on the post is
postTitle
postDesc
postAuthor
Here is what the firebase looks like
Code Here:
import 'package:tennis_event_app/services/crud.dart';
import 'package:tennis_event_app/views/create_blog.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return BlogTile(
author: blogSnapshot!.docs[index].get('author'),
title: blogSnapshot!.docs[index].get('title'),
desc: blogSnapshot!.docs[index].get('desc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class BlogTile extends StatelessWidget {
final String imgUrl, title, desc, author;
BlogTile(
{required this.author,
required this.desc,
required this.imgUrl,
required this.title});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Stack(
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8)),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
height: 170,
),
),
),
Container(
height: 170,
decoration: BoxDecoration(
color: Colors.black45.withOpacity(0.3),
borderRadius: BorderRadius.circular(6)),
),
Container(
height: 170,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
SizedBox(height: 4),
Text(
'$desc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
SizedBox(
height: 4,
),
Text(author),
],
)),
Container(
child: SizedBox(
height: 170,
width: MediaQuery.of(context).size.width,
child: TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 20),
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage()));
},
child: const Text(''),
),
),
),
],
),
);
}
}
class DetailPage extends StatefulWidget {
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList2() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return PageContent(
postAuthor: blogSnapshot!.docs[index].get('postAuthor'),
postTitle: blogSnapshot!.docs[index].get('postTitle'),
postDesc: blogSnapshot!.docs[index].get('postDesc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList2()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class PageContent extends StatelessWidget {
final String imgUrl, postTitle, postDesc, postAuthor;
PageContent(
{required this.postAuthor,
required this.postDesc,
required this.imgUrl,
required this.postTitle});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Card(
child: ListTile(
title: Text(
postTitle,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
subtitle: Text(
'$postDesc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
)
)
);
}
}
I also reference crud.dart in that code, so incase you need it, here it is:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:collection';
class CrudMethods {
Future<void> addData(blogData) async {
print(blogData);
FirebaseFirestore.instance
.collection("blogs")
.add(blogData)
.then((value) => print(value))
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance
.collection("blogs")
.orderBy("ts", descending: true)
.get();
}
}
Thank you again for any help!
First I would recommend to modelize your data in an object for exemple a class Article that is easier to serialize and manipulate.
Then instead of requesting another time the database you should save your data in a List<Article> for example then you only update this list on refresh from your main page. That way you don'y manipulate a QuerySnapshot or Future but just your list of objects.
Finally and to answer your question, you could simply pass the clicked item Article to your details page and only display its content. Because here, you have the same construction as your main page with the same request that is resent.
Usually you can build your route like that (adding a parameter to your details with the index you clicked on for example)
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage(article: _data[i])));
},
Here is an article on serialization from Flutter docs, it shows how to build your model with the toMap, toJson and fromJson methods.

Download image to phone directory

I've created a flutter project that show a staggeredgridview of images from firestore database. Once i click on one of the images it shows that image. What i want is a download button thats saves the image to my device. Ath the moment I've just used pop.
I've read some about the path provider package but i can't figure out how to implement this in the code. Perhaps there is a better solution?
StaggeredGridView Page
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:proj/screens/home/instafull.dart';
import 'dart:async';
import 'package:proj/services/auth.dart';
import 'package:proj/shared/constants.dart';
class Instapage extends StatefulWidget {
#override
_InstapageState createState() => _InstapageState();
}
class _InstapageState extends State<Instapage> {
final AuthService _auth = AuthService();
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> wallpaperlist;
final CollectionReference collectionReference = FirebaseFirestore.instance.collection('mediapost');
#override
void initState() {
// TODO: implement initState
super.initState();
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
wallpaperlist = datasnapshot.docs;
});
});
}
#override
void dispose() {
subscription?.cancel();
// TODO: implement dispose
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bas,
body: wallpaperlist != null?
StaggeredGridView.countBuilder(
padding: const EdgeInsets.fromLTRB(10, 8, 10, 0),
crossAxisCount: 4,
itemCount: wallpaperlist.length,
itemBuilder: (context, index){
String imgPath = wallpaperlist[index].get('img');
return new Material(
elevation: 8,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InstaFull(imgPath: imgPath))),
child: Hero(
tag: imgPath,
child: FadeInImage(
image: NetworkImage(imgPath),
fit: BoxFit.cover,
placeholder: AssetImage('assets/wally2.jpg'),
),
),
),
);
},
staggeredTileBuilder: (index) => StaggeredTile.count(2, index.isEven?2:3),
mainAxisSpacing: 8,
crossAxisSpacing: 8,
): Center(
child: CircularProgressIndicator(),
),
);
}
}
Picture Page
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class InstaFull extends StatelessWidget {
String imgPath;
InstaFull({this.imgPath});
final LinearGradient backgroundGradient = LinearGradient(
colors: [Color(0x10000000), Color(0x30000000)],
begin: Alignment.topLeft,end: Alignment.bottomRight);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Hero(
tag: imgPath,
child: Image.network(imgPath),
),
),
Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(Icons.close,
color: Colors.black,
),
onPressed: () => Navigator.of(context).pop(),
),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Download')),
],),
)
],
),
),
);
}
}
You can use gallery_saver
Install it and enable this permissions:
iOS
Add the following keys to your Info.plist file, located in <project root>/ios/Runner/Info.plist:
NSPhotoLibraryUsageDescription - describe why your app needs permission for the photo library. This is called Privacy - Photo Library Usage Description in the visual editor.
Android
Android
android.permission.WRITE_EXTERNAL_STORAGE - Permission for usage of external storage
Official example of gallery_saver:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String firstButtonText = 'Take photo';
String secondButtonText = 'Record video';
double textSize = 20;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.blue,
onPressed: _takePhoto,
child: Text(firstButtonText,
style:
TextStyle(fontSize: textSize, color: Colors.white)),
),
),
),
),
Flexible(
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.white,
onPressed: _recordVideo,
child: Text(secondButtonText,
style: TextStyle(
fontSize: textSize, color: Colors.blueGrey)),
),
)),
flex: 1,
)
],
),
),
));
}
void _takePhoto() async {
ImagePicker.pickImage(source: ImageSource.camera)
.then((File recordedImage) {
if (recordedImage != null && recordedImage.path != null) {
setState(() {
firstButtonText = 'saving in progress...';
});
GallerySaver.saveImage(recordedImage.path).then((String path) {
setState(() {
firstButtonText = 'image saved!';
});
});
}
});
}
void _recordVideo() async {
ImagePicker.pickVideo(source: ImageSource.camera)
.then((File recordedVideo) {
if (recordedVideo != null && recordedVideo.path != null) {
setState(() {
secondButtonText = 'saving in progress...';
});
GallerySaver.saveVideo(recordedVideo.path).then((String path) {
setState(() {
secondButtonText = 'video saved!';
});
});
}
});
}
void _saveNetworkVideo() async {
String path =
'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4';
GallerySaver.saveVideo(path).then((bool success) {
setState(() {
print('Video is saved');
});
});
}
void _saveNetworkImage() async {
String path =
'https://image.shutterstock.com/image-photo/montreal-canada-july-11-2019-600w-1450023539.jpg';
GallerySaver.saveImage(path).then((bool success) {
setState(() {
print('Image is saved');
});
});
}
}

How can I add data from the Firebase database in a reversed order? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am currently developing a chat app. The problem is, that when someone types something it shows randomly on the chat screen (after a user registered and logged in).
I want it to look like a normal chat app, so the last message should be at the bottom of the screen. I even reversed the data and list view, but it didn't work.
My code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:naber/constants.dart';
final _firestore=FirebaseFirestore.instance;
User 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;
void initState(){
super.initState();
getCurrentUser();
}
void getCurrentUser()async{
try{
final currentUser = await _auth.currentUser;
if(currentUser!=null){
loggedInUser=currentUser;
}
}
catch(e){
print(e);
}
}
#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,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.docs.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data()['text'];
final messageSender = message.data()['sender'];
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
);
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});
final String sender;
final String text;
final bool isMe;
#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(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
elevation: 5.0,
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black54,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
You add messages with:
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
});
Firestore doesn't have any built-in default ordering for documents. If you want to be able to order the documents, you will need to add a value to each document to allow that.
For example, you could add a timestamp of when the document was created with:
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'createdAt': FieldValue.serverTimestamp()
});
By using FieldValue.serverTimestamp() the server will automatically populate this field, which you can then use when reading the data with:
stream: _firestore.collection('messages').orderBy('createdAt', descending: true).snapshots()

error:- Another exception was thrown: A RenderFlex overflowed by 33 pixels on the bottom

[enter image description here]
1Error showing when i run my app...My code is below ...can anyone tell what is wrong with my code
///////////////////////
Error showing when i run my app...My code is below ...can anyone tell what is wrong with my code
///////////////////////
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
import
'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
class OfferPage extends StatefulWidget {
#override
_OfferPageState createState() => new _OfferPageState();
}
class _OfferPageState extends State<OfferPage> {
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> offerpostList;
final CollectionReference collectionReference =
Firestore.instance.collection("todos");
#override
void initState() {
// TODO: implement initState
super.initState();
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
offerpostList = datasnapshot.documents;
});
});
// _currentScreen();
}
#override
void dispose() {
subscription?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: offerpostList != null? new StaggeredGridView.countBuilder(
padding: const EdgeInsets.all(8.0),
crossAxisCount: 4,
itemCount: offerpostList.length,
itemBuilder: (context, i) {
String imgPath = offerpostList[i].data['url'];
String title = offerpostList[i].data['productTitle'];
return new Material(
elevation: 8.0,
borderRadius:
new BorderRadius.all(new Radius.circular(8.0)),
child: new InkWell(
child:new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title,style: new TextStyle(
fontStyle: FontStyle.italic,
color: Colors.green[900],
fontSize: 16.0)),
new Hero(
tag: imgPath,
child:
new FadeInImage(
image: new NetworkImage(imgPath),
fit: BoxFit.cover,
placeholder: new AssetImage("assets/logo.png"),
),
),
],
),
),
);
},
staggeredTileBuilder: (i) =>
new StaggeredTile.count(2, i.isEven ? 2 : 3),
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
)
: new Center(
child: new CircularProgressIndicator(),
));
}
}
Column in flutter doesn't have scrolling ability. The issue is your data from firebase cannot be fit inside a single screen. That's why overflow error was thrown. Use ListView instead of Column which has the scrolling ability.
Column widget for available room in the device to get qll data in firebase and also to get scroll effect you can use FirebaseAnimatedList.
For an Olx like gridview with text over image, here is a sample. Try it out and change your question because it might be misleading.
main.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firestore_grid_view/product.dart';
import 'package:firestore_grid_view/product_details.dart';
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(
home: new MyApp(),
debugShowCheckedModeBanner: false,
));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Product> _products = [];
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Home'),
),
body: new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('products').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new GridView.count(
crossAxisCount: 2,
children: _buildGrid(snapshot.data.documents),
);
},
),
);
}
List<Widget> _buildGrid(List<DocumentSnapshot> documents) {
List<Widget> _gridItems = [];
_products.clear();
for (DocumentSnapshot document in documents) {
_products.add(new Product(
name: document['productTitle'],
category: document['category'],
imageUrl: document['url'],
contactNumber: document['contactNumber']));
}
for (Product product in _products) {
_gridItems.add(_buildGridItem(product));
}
return _gridItems;
}
Widget _buildGridItem(Product product) {
return new GestureDetector(
child: new Card(
child: new Stack(
alignment: Alignment.center,
children: <Widget>[
new Hero(
tag: product.name,
child: new Image.network(product.imageUrl, fit: BoxFit.cover),
),
new Align(
child: new Container(
padding: const EdgeInsets.all(10.0),
child: new Text(product.name,
style: new TextStyle(color: Colors.white)),
color: Colors.black.withOpacity(0.4),
width: double.infinity,
),
alignment: Alignment.bottomCenter,
),
],
),
),
onTap: () => onProductTapped(product),
);
}
onProductTapped(Product product) {
Navigator.of(context).push(new MaterialPageRoute(
builder: (context) => new ProductDetails(product)));
}
}
product_details.dart
import 'package:firestore_grid_view/product.dart';
import 'package:flutter/material.dart';
class ProductDetails extends StatelessWidget {
final Product product;
ProductDetails(this.product);
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
children: <Widget>[
new Expanded(child: new Container()),
new Hero(
tag: product.name,
child: new Image(
image: new NetworkImage(product.imageUrl),
fit: BoxFit.fill,
width: double.infinity,
height: 300.0,
)),
new Padding(
padding: const EdgeInsets.all(15.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(right: 8.0),
child: new Text(
'Category -',
style: new TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
new Text(
product.category,
style: new TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
],
),
),
new Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(right: 8.0),
child: new Text(
'Contact Number -',
style: new TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
new Text(
product.contactNumber,
style: new TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
),
],
),
),
new Expanded(child: new Container()),
],
),
);
}
}
product.dart
class Product {
final name, category, imageUrl, contactNumber;
Product({this.name, this.category, this.imageUrl, this.contactNumber});
}

Resources