how to streambuilder auto scroll in send new message - firebase

I'm creating an app that has a group chat section and I'm facing a problem I need when I send a new message it automatically scrolls to the last message I sent like chat apps ? This is my code
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').orderBy('time').snapshots(),
builder: (context, snapshot){
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Container(
height: 40,
width: 40,
child: CircularProgressIndicator(),
),
);
}
List<messageLine> messageWidgets = [];
final messages = snapshot.data!.docs;
for(var message in messages){
final messageText = message.data().toString().contains('text') ? message.get('text') : '';
final messagesender = message.data().toString().contains('sender') ? message.get('sender') : '';
final currentUser = Signinuser.email;
if (currentUser == messagesender){
}
final messageWidget = messageLine(sender: messagesender,text: messageText,isme: currentUser == messagesender,);
messageWidgets.add(messageWidget);
}
return Expanded(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/chatBack.png'),
fit: BoxFit.cover
)
),
child: ListView(
padding: EdgeInsets.symmetric(
horizontal: 10,vertical: 20
),
children: messageWidgets
),
),
);
},),

Related

how to reduce number of reads in firebase?

i have created a chat app and everything works fine except two things
1- in fire base store i get too much reads even if i do nothing, for example i just used my chat app for 5 minuets i got around 6000 reads
2- when i chat to any person some messages don't get received, this is an example
the other person(wiliam) did not receive three messages( yeah, k , now).
///////////
this is the stream builder code to display messages
class Streambuild extends StatelessWidget {
final String roomid;
Streambuild({#required this.roomid});
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _store
.collection('FCHATROOM')
.doc(roomid)
.collection("CHAT")
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snap) {
if (!snap.hasData) {
return Center(
child: Text('No Messages'),
);
}
return Expanded(
child: ListView.builder(
itemCount: snap.data.docs.length,
reverse: true,
shrinkWrap: true,
itemBuilder: (context, index) {
return Bubblemsg(
txt: snap.data.docs[index].data()['message'],
sender: snap.data.docs[index].data()['sender'],
realtime: snap.data.docs[index].data()['realtime'],
isMe: (snap.data.docs[index].data()['sender'] ==
_auth.currentUser.email),
);
}),
);
});
}
}
bubble message code:
class Bubblemsg extends StatelessWidget {
Bubblemsg({this.sender, this.txt, this.isMe, this.realtime});
final String txt;
final String sender;
final bool isMe;
final String realtime;
#override
Widget build(BuildContext context) {
var myprov = Provider.of<Help>(context, listen: false);
return Container(
width: double.infinity,
child: Bubble(
elevation: 5,
padding: BubbleEdges.all(10),
margin: isMe
? BubbleEdges.only(top: 10, right: 5, left: 30)
: BubbleEdges.only(top: 10, left: 5, right: 30),
alignment: isMe ? Alignment.topRight : Alignment.topLeft,
nip: isMe ? BubbleNip.rightTop : BubbleNip.leftTop,
color: isMe ? myprov.mid : Colors.grey[900],
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
txt != null
? txt.startsWith("https://firebasestorage.googleapis.com/v0")
? Imagecontainer(
url: txt,
)
: SelectableText(
txt != null ? txt : "",
style: TextStyle(
color: myprov.word,
fontSize: 20,
),
)
: Text(""),
Padding(
padding: EdgeInsets.only(top: 10.0),
child: Text(
realtime != null ? realtime : "",
style: TextStyle(fontSize: 15, color: myprov.word),
textAlign: TextAlign.end,
),
)
],
),
),
);
}
}

error trying to get a document from firebase using UID, Flutter app

Im getting 2 error in my code trying to get a document from a Firebase collection /users using UID,
base on this document FlutterFire
First one => error: Too many positional arguments: 0 expected, but 1 found. (extra_positional_arguments_could_be_named at [calfran_app] lib/pages/home.dart:49)`
Second one => error: Undefined name 'users'. (undefined_identifier at [calfran_app] lib/pages/home.dart:37)
class _HomeState extends State<Home> {
Widget build(BuildContext context) {
Stream documentStream = FirebaseFirestore.instance.collection('users').doc('user.uid').snapshots();
int _currentIndex = 0;
final tabs = [
//TAB DE MANUAIS
Center(
child: (Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return Container(
padding: EdgeInsets.all(16),
child: ListView(
snapshot.data.documents.map((DocumentSnapshot document) {
var dio = Dio();
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset(
'Images/pdflogo.png', width: 32,
),
Center(
child: Text(
(document.data()['nome'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text(
'Compartilhar / Download'),
onPressed: () async {
var request = await HttpClient()
.getUrl(Uri.parse(
document.data()['documento']));
var response = await request
.close();
Uint8List bytes = await consolidateHttpClientResponseBytes(
response);
await Share.file(
'ESYS AMLOG',
'Manual.pdf',
bytes,
'image/jpg');
}),
],
),
],
),
),
);
}),
));
})))),

How to get it from userUid() to the StreamBuilder Flutter

i was wondering how can i pass my function userUid() to the StreamBuilder {
FirebaseAuth auth = FirebaseAuth.instance;
userUid() async {
final FirebaseUser user = await auth.currentUser;
final uid = user.uid;
return uid;
}
Where I want to pass it, to get the document base on the logged user UID.
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
When I Pass the function final documentId = await useruid();inside the final tabs =[
I get the error
error: Expected an identifier. (missing_identifier at lib/pages/home.dart:39)
error: Expected to find ']'. (expected_token at lib/pages/home.dart:39)
idk what I can do to pass this function...
with someone know a document of example so i can study how to do it,
full code:
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot manuais =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset('Images/pdflogo.png', width: 32,
),
Center(
child: Text(
(manuais.data()['nome'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Compartilhar / Download'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(manuais.data()['documento']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'Manual.pdf',
bytes,
'image/jpg');
}),
],
),
],
),
),
);
}),
);
})))),
Center(
child: (Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('producao').snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot producao =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image.network(producao.data()['img'].toString(), width: 260,
),
),
Text(
(producao.data()['data'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 22),
),
Text(
(producao.data()['detail'].toString()),
style: TextStyle(fontSize: 16),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('DETALHES'),
onPressed: () {
ImageViewer.showImageSlider(
images: [
(producao.data()['img']),
//List of images' URLs
],
);
}),
FlatButton(
child: const Text('COMPARTILHAR'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(producao.data()['img']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'amlog.jpg',
bytes,
'image/jpg'
);
}),
],
),
],
),
),
);
}),
);
})))),
Center(child: Text('Documentos')),
]; //<<<<<<<<<<<<<<< here closes the tab
````
You cannot define a variable inside a List. You could do two things:
Declare the documentId before the List instantiation:
final documentId = await userUid();
final tabs = [
...
];
Create a function that returns a list:
/// ... simulates the parameters of the function
List<Widget> getWidgetList(...) async {
final documentId = await userUid();
final List<Widget> list = [];
// To insert in a final list use the method add(...)
...
// Do your logic here
...
return list;
}
final tabs = getWidgetList(...);

Flutter Firestore How To Listen For Changes To ONE Document

I just want to get notified whenever ONE document is changed or updated. Every example of getting updates is always using collections. I tried to implement that with only using one document and it never gets any updates. Here is what I have right now that doesn't work:
#override
Widget build(BuildContext context) {
StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance
.collection("users")
.document(widget.uid)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
user = snapshot.data.data as User;
});
I've debugged this 100 times and it never gets to the "builder:" section. And this is not a problem with the document reference by the way. What am I doing wrong here?
Here's an example
Firestore.instance
.collection('Users')
.document(widget.uid)
.snapshots()
.listen((DocumentSnapshot documentSnapshot) {
Map<String, dynamic> firestoreInfo = documentSnapshot.data;
setState(() {
money = firestoreInfo['earnings'];
});
})
.onError((e) => print(e));
but what you did wrong is here:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
user = snapshot.data.data as User;
});
replace that with
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
var firestoreData = snapshot.data;
String info = firestoreData['info'];
});
This is my experience and working fine. (StreamBUilder with BLoC pattern).
Step1 => Filter by Query & limit
var userQuery = Firestore.instance
.collection('tbl_users')
.where('id', isEqualTo: id)
.limit(1);
Step2 => Listening
userQuery.snapshots().listen((data) {
data.documentChanges.forEach((change) {
print('documentChanges ${change.document.data}');
});
});
BLoC
class HomeBloc {
final userSc = StreamController<UserEntity>();
Future doGetProfileFireStore() async {
await SharedPreferencesHelper.getUserId().then((id) async {
print('$this SharedPreferencesHelper.getUserId() ${id}');
var userQuery = Firestore.instance
.collection('tbl_users')
.where('id', isEqualTo: id)
.limit(1);
await userQuery.getDocuments().then((data) {
print('$this userQuery.getDocuments()');
if (data.documents.length > 0) {
print('$this data found');
userQuery.snapshots().listen((data) {
data.documentChanges.forEach((change) {
print('documentChanges ${change.document.data}');
userSc.sink.add(new UserEntity.fromSnapshot(data.documents[0]));
});
});
} else {
print('$this data not found');
}
});
});
}
void dispose() {
userSc.close();
}
}
View
new StreamBuilder(
stream: bloc.userSc.stream,
builder: (BuildContext context, AsyncSnapshot<UserEntity> user) {
return new Center(
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
user.hasData
? new Container(
width: 80,
height: 80,
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
image: new DecorationImage(
image: NetworkImage(user.data.photo),
fit: BoxFit.cover,
),
),
)
: new Container(
width: 50,
height: 50,
child: new CircularProgressIndicator(
strokeWidth: 2,
valueColor:
AlwaysStoppedAnimation<Color>(ColorsConst.base),
),
),
new Container(
margin: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text(
user.hasData
? '${user.data.username.toUpperCase()}'
: 'loading',
style: TextStyleConst.b16(
color: Colors.black
.withOpacity(user.hasData ? 1.0 : 0.2),
letterSpacing: 2),
),
new Container(
margin: EdgeInsets.all(5),
),
new Text(
user.hasData ? '${user.data.bio}' : 'loading',
style: TextStyleConst.n14(
color: Colors.black
.withOpacity(user.hasData ? 1.0 : 0.2)),
),
new Container(
margin: EdgeInsets.fromLTRB(0, 10, 0, 0),
padding: EdgeInsets.all(10),
decoration: new BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(100.0),
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Row(
children: <Widget>[
new Icon(
Icons.trending_up,
color: Colors.white,
size: 20,
),
new Text(
'145K',
style:
TextStyleConst.b14(color: Colors.white),
),
],
),
new Container(
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
),
new Row(
children: <Widget>[
new Icon(
Icons.trending_down,
color: Colors.white,
size: 20,
),
new Text(
'17',
style:
TextStyleConst.b14(color: Colors.white),
),
],
),
],
),
),
],
),
),
],
),
);
},
),
String collPath = 'books';
String docPath= 'auNEAjG276cQ1C9IUltJ';
DocumentReferance documentReferance = firestoreInstance.collection(collPath).document(docPath);
documentReference.snapshots().listen((snapshot) {
print(snapshot.data);
}
Here's the solution that uses StreamBuilder:
StreamBuilder(
stream: Firestore.instance
.collection("sightings")
.doc(sighting.sightingID)
.snapshots(),
builder: (context, snapshot) {
sighting = Sighting.fromMap(snapshot.data.data()); // Gives you the data map
return Scaffold(
appBar: AppBar(
title: Text('Document Details'),
),
body: Column(
children: [
Text(sighting.type)
],
),
);
});
The key is the snapshot.data.data() line which returns the map of data from the document.

Stream builder from firestore to flutter

I am wondering how to get data from firestore to flutter app using the streambuilder. I created the necessary Boilerplate code I have the widget built and working and in the below code
headimageassetpath is nothing but a URL string which exists in the firestore.
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
My firestore:
full code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class LostPage extends StatefulWidget {
#override
_LostPage createState() => new _LostPage();
}
class _LostPage extends State<LostPage> {
//temp vars
final String firebasetest = "Test";
//firestore vars
final DocumentReference documentReference =
Firestore.instance.document("Items/Rusty");
//CRUD operations
void _add() {
Map<String, String> data = <String, String>{
"name": firebasetest,
"desc": "Flutter Developer"
};
documentReference.setData(data).whenComplete(() {
print("Document Added");
}).catchError((e) => print(e));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body:
new StreamBuilder(
stream: Firestore.instance.collection('Items').snapshots(),
builder: (_, AsyncSnapshot<QuerySnapshot> snapshot) {
var items = snapshot.data?.documents ?? [];
return new Lost_Card(
headImageAssetPath : snapshot.data.documents.map()(['url'],)
);
},
)
/*new Lost_Card(
headImageAssetPath: "https://i.imgur.com/FtaGNck.jpg" ,
title: "Mega Dish",
noro: "old",
)*/,
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: _add),
);
}
}
class Lost_Card extends StatelessWidget
{
//All the card variables
final String headImageAssetPath;
final IconData icon;
final Color iconBackgroundColor;
final String title;
final String noro;
final int price;
final ShapeBorder shape;
Lost_Card({
this.headImageAssetPath, //used
this.icon,
this.iconBackgroundColor,
this.title, //used
this.noro, //used
this.price,
});
#override
Widget build(BuildContext context) {
// TODO: implement build
return GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
children: <Widget>[
Card(
child: Column(
// mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 4,
width: MediaQuery.of(context).size.height / 2.5,
child: DecoratedBox(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
headImageAssetPath),
fit: BoxFit.cover),
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: FractionalOffset.topLeft,
child: CircleAvatar(
backgroundColor: Colors.redAccent,
radius: 15.0,
child: Text(
noro,
textScaleFactor: 0.5,
),
),
),
),
Align(
alignment: FractionalOffset.topRight,
child: Container(
color: Colors.blueAccent,
height: 35.0,
width: 35.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.account_circle),
Text(
"1P",
textScaleFactor: 0.5,
),
],
),
),
),
),
],
),
),
Center(
child: Container(
padding: const EdgeInsets.all(8.0),
alignment: FractionalOffset.bottomCenter,
child: Text(
title,
style: TextStyle(
fontWeight: FontWeight.w700,
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
FlatButton(
child: Text(
"Add To Cart",
style: TextStyle(color: Colors.grey[500]),
),
onPressed: () => null,
),
Text(
"\$5",
style: TextStyle(color: Colors.grey[500]),
)
],
)
],
),
),
],
);
}
}
Actual App
Please shed some light on this. Tks.
This should work for one item
body: new StreamBuilder(
stream: Firestore.instance.collection("collection").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text(
'No Data...',
);
} else {
<DocumentSnapshot> items = snapshot.data.documents;
return new Lost_Card(
headImageAssetPath : items[0]["url"]
);
}
If you want to create list builder from many documents use it like this
return new ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.documents[index];
return new Lost_Card(
headImageAssetPath : ds["url"];
);
Accessing documents using StreamBuilder in Flutter 2
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('products').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return Text(doc['name']);
});
} else {
return Text("No data");
}
},
)
As per new changes 2021 in Firebase FireStore you can retrieve data from collection using StreamBuilder as below
final _mFirestore = FirebaseFirestore.instance;
return StreamBuilder<QuerySnapshot>(
stream:
_mFirestore.collection(kFirebaseCollectionName).snapshots(),
builder: (context, snapshots) {
if (!snapshots.hasData) {
return Center(
child: Text('Data not available',),
);
}
final messages = snapshots.data.docs;
List<Text> textWidgets = [];
messages.forEach((element) {
final messageText = element['text'];
final messageSender = element['sender'];
final textWidget = Text('$messageText, $messageSender');
textWidgets.add(messageBubbleWidget);
});
},
);
Card buildItem(DocumentSnapshot doc) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'name: ${doc.data['name']}',
style: TextStyle(fontSize: 24),
),
Text(
'todo: ${doc.data['todo']}',
style: TextStyle(fontSize: 20),
),
Text(
'Age: ${doc.data['age']}',
style: TextStyle(fontSize: 10),
),
SizedBox(
height: 12,
),
],
)
],
),
),
); }
For other persons who will face the same problem, the card and stream builder will represent a solution. The Widget has the Card just before it declaration and has inside the body the next part:
body: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Form(
key: _formKey,
child: buildTextFormField(),
),
StreamBuilder<QuerySnapshot>(
stream: db
.collection('CRUD')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return SizedBox();
}
},
)
],
),
Update for 2022, Flutter 2.10, cloud_firestore: ^3.1.11. You can retrieve data from collection using StreamBuilder
Stream collectionStream = FirebaseFirestore.instance.collection('users').snapshots();
StreamBuilder<QuerySnapshot>(
builder: (context, snapshot) {
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWidgets = [];
for (var element in messages) {
final messageText = element['text'];
final messageSender = element['sender'];
final messageWidget =
Text('$messageText from $messageSender');
messageWidgets.add(messageWidget);
}
return Column(
children: messageWidgets,
);
}
return const Text('Error');
},
stream:collectionStream),
StreamBuilder<List<UData>>(
stream: AdminData().getDrivers,
builder: (context, snapshot) {
return ListView(
children: snapshot.data.map((document) {
return hadCard(
widget: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
hadText(title: document.name),
hadText(title: document.phone),
hadText(title: document.Driver),
],
),
);
}).toList(),
);
}),

Resources