How to add a date header for my chat module in flutter with firebase? - firebase

I want to add a sticky date header for my chat module just like how WhatsApp has. I tried sticky headers dependency, but it didn't work out.
Chat Page Code:
Column(
crossAxisAlignment:
snapshot['senderUid'] == _senderuid
? CrossAxisAlignment.end
: CrossAxisAlignment.end,
children: [
new Text(
snapshot['message'],
style: TextStyle(
color: Colors.white, fontSize: 15.0),
),
Padding(
padding: const EdgeInsets.only(top: 5),
child: new Text(
snapshot['timestamp']
.toDate()
.toString()
.substring(10, 16),
style: TextStyle(
color: Colors.white.withOpacity(0.5),
fontSize: 9.0),
),
),
],
),

You can try with this package
https://pub.dev/packages/flutter_sticky_header
Or with Slivers and SliverPersistentHeaderDelegate

Related

fetch data from firebase firestore instead of constants

here in this code the data is being displayed from a constants file but i want to fetch it from firestore
what changes should i make to get data from firestore and also i dont want to fetch image from firestore
i want to fetch data from firebase firestore instance
Main.dart
List<Widget> itemsData = [];
void getPostsData() {
List<dynamic> responseList = FOOD_DATA;
List<Widget> listItems = [];
responseList.forEach((post) {
listItems.add(Container(
height: 150,
margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(20.0)), color: Colors.white, boxShadow: [
BoxShadow(color: Colors.black.withAlpha(100), blurRadius: 10.0),
]),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
post["name"],
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
Text(
post["brand"],
style: const TextStyle(fontSize: 17, color: Colors.grey),
),
SizedBox(
height: 10,
),
Text(
"\$ ${post["price"]}",
style: const TextStyle(fontSize: 25, color: Colors.black, fontWeight: FontWeight.bold),
)
],
),
Image.asset(
"assets/images/${post["image"]}",
height: double.infinity,
)
],
),
)));
});
setState(() {
itemsData = listItems;
});
}

How to navigate to a specific route in a list full of the same widget?

I have a an app which the user is able to add in books and it upload to the firestore database, and then I use a streamBuilder() to recieve all the data and display it in a list of GestureDetector() with the card() as a child.
Here is the code for the
final bookWidget = GestureDetector(
key: ValueKey(loggedInUser.email),
onTap: () {
print(title);
},
child: Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 100,
height: 140,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(bookCoverURL)),
),
),
Container(
width: 230,
//color: Colors.red,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
category.toString(),
style: TextStyle(
color: Colors.grey,
fontStyle: FontStyle.italic,
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
title.toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 17,
),
),
),
Container(
margin: EdgeInsets.only(top: 10),
child: Text(
(author),
style:
TextStyle(color: Colors.grey),
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
color: Colors.black,
size: 15,
)
],
),
],
),
//color: Colors.yellowAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 5,
margin: EdgeInsets.all(10),
),
);
bookWidgets.add(bookWidget);
And then I display all my code in the screen by :
Column(
children: bookWidgets,
)
But how can I make the app navigate to a new screen when the user pressed on a specific card()? Since all of them are the same widget and have no unique identifier?
Any help is greatly appreciated! Thank you!
GestureDetector(
key: ValueKey(loggedInUser.email),
onTap: () {
Navigator.pushNamed(
context,
'/routeNameHere',
arguments: id,
);
},
)
In parameter arguments: ID - you can change the id by the id of the card that you want to navigate to.
You must create a page for the display detail of the card, which just displays a card with same id in the argument. So on your new page, create a variable for receiving the argument, e.g.:
final cardId = ModalRoute.of(context).settings.arguments as String;
So the page can display the card depending on the cardId.
You will need to create an identifier to pass (in this case “book”). In Flutter, these are necessary when calling or passing an object.
However, in regards to using Named Routes , this can allow you to send the data without the identifier but is considered bad practice in coding as you would not have a reference to the call or be able to back trace through the data.
Keeping the above in mind, it is possible to use the OnTap() inside each child card container so that on handle clicks or tap gestures, the user is taken to a different screen using routes as it is part of the GestureDetector class.

How to know which card is tapped in flutter

I am making my first flutter app (A coffee shop), in this I have accessed data from Firebase Cloudstore and displayed it in the form of card.
Now I have provided the user with the feature of customizing order
for that I have to know which item he is customizing and hence I need to know which card the user has tapped.
Here is my code snippet:
child: GestureDetector(
onTap: (){
return showModalBottomSheet<void>(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(40.0),
topLeft: Radius.circular(40.0),
)
),
context: context,
builder: (BuildContext context) {
return Container(
child: CustomOrder(),
height: 400.0,
width: 350.0,
);
},
);
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0),
),
elevation: 10,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(25.0),
child: Image(
image: AssetImage('assets/coff1.PNG'),
),
),
Align(
alignment: Alignment.topLeft,
child: Text(
'${itemslist[index]["item_name"]}',
style: TextStyle(
fontSize: 38.0,
fontFamily: 'GrandHotel',
fontWeight: FontWeight.bold,
color: Colors.brown[800]
),
// textAlign: TextAlign.left
),
),
Align(
alignment: Alignment.topLeft,
child: Text(
'${itemslist[index]["price"]}',
style: TextStyle(
fontSize: 22.0,
fontFamily: 'GrandHotel',
color: Colors.brown[800]
),
),
),
Align(
alignment: Alignment.topLeft,
child: Text(
'${itemslist[index]["desc"]}',
style: TextStyle(
fontSize: 22.0,
fontFamily: 'GrandHotel',
color: Colors.brown[800]
),
),
),
SizedBox(height: 10.0),
FlatButton.icon(
color: Colors.brown[400],
onPressed: (){},
icon: Icon(Icons.add),
label: Text(
"Add to cart",
style: TextStyle(
fontSize: 20.0,
color: Colors.brown[800]
),
),
),
]
),
),
),
),
It appears that you are using a listView.builder but didn't attach it to your code properly, but you are accessing this [index] in your code.
Therefore, in your onpressed button in the bottom,
onPressed: (){
print(itemslist[index]["item_name"]);} // should print your tapped item's name, and then you can do whatever you want if you have reached this far.
I would wrap each separate card with their own GestureDetector. If you need more instruction for implementing this, just let me know in the comments.

'A non-null String must be provided to a Text widget' (Flutter)

I've tried to fix this with the following code but I'm afraid the error is still prevalent:
The following assertion was thrown building:
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 360 pos 10: 'data != null'
child: Row(
children: [
Text(
(contact.data()['rating'] == null)
? "n/a"
: contact.data()['rating'].toString(),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.tealAccent)),
Padding(
padding: const EdgeInsets.all(8.0),
child: CircleAvatar(
radius: 25,
backgroundImage: AssetImage("assets/girl2.jpg"),
),
),
Spacer(),
Text(
contact.data()['name'],
style: TextStyle(
fontWeight: FontWeight.w400, color: Colors.tealAccent),
),
Spacer(),
Text(
contact.data()['location'],
style: TextStyle(
letterSpacing: 1,
fontSize: 10,
fontWeight: FontWeight.w300,
color: Colors.tealAccent),
),
],
),
How would one go about solving this?
You can just add:
contact.data()['rating'] ?? "empty"
The above will check if the expression on the left is not null, if it is then "empty" will be added to the Text widget. You have to add the condition to the other Text widgets also.

How do I generate a list of widgets from firebase firestore database?

I'm trying to figure out how to iterate through documents in firestore and create a text widget for each one.
I've figured out how to access those elements. I used debugPrint() and got the results I'm expecting, but I can't get it to display below my other widgets. I get a red screen with a ton of errors (on phone).Below is my code for what I've tried so far.
QuerySnapshot querySnapshot = await
Firestore.instance.collection("users").document(user.uid).collection("trails").getDocuments();
var list = querySnapshot.documents;
list.forEach((doc) => debugPrint(doc.data["Trail Name"].toString()));//works
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
//these widgets are generating correctly
Text(
"First Name: $firstName",
style: TextStyle(color: Colors.white, ),
),
Text(
"Last Name: $lastName",
textAlign: TextAlign.left,
style: TextStyle(color: Colors.white,),
),
Text(
"Email: $email",
style: TextStyle(color: Colors.white, ),
),
//these ones are causing my errors.
list.forEach((doc) => Text(
"Trail Name: ${doc.data["Trail Name"].toString()}",
style: TextStyle(color: Colors.white, ),
),)
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.40,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
The screen on my device lights up red with errors on creating child widgets, when I'm expecting it to display the Trail Name(s) below the other info. I only included necessary code, but could include more (such as the widget's build method) if needed. Thanks for any assistance. I'm new to flutter.
Try using the map function:
List<Widget> _widgets = list.map((doc) => Text(
"Trail Name: ${doc.data["Trail Name"].toString()}",
style: TextStyle(color: Colors.white, ),
),).toList();
And then for the children of the column, just add that list to the list you specify, like:
children: [ ... ] + _widgets;

Resources