I would like to show all the fields of a document in firebase, but I'm having different troubles.
My intention is to show the info like a chat. I tried with a ListView.builder inside a StreamBuilder.
This is my Firestore document:

I managed to get the horizontal information using doc.data().toString but what I am trying to do is to get the whole information as a ListTile so when I add new messages they are automatically added to the ListView.builder.
This is my current code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({Key? key}) : super(key: key);
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final textController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: StreamBuilder(
stream:
FirebaseFirestore.instance.collection("messages").snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return ListTile(
title: Text(doc.data().toString()),
);
},
);
}),
),
);
}
}
And this is what I get with my current code: DeviceImage
P.S. I can get the data manually if I use this but it's not what I want:
return ListTile(
title: Text(doc['sender']),
);
CodePudding user response:
Try to use an Object like below.
class Message {
final String sender;
final String text;
const Message({
required this.sender,
required this.text,
});
Map<String, dynamic> toMap() {
return {
'sender': sender,
'text': text,
};
}
factory Message.fromMap(Map<String, dynamic> map) {
return Message(
sender: map['sender'] as String,
text: map['text'] as String,
);
}
}
class ChatScreen extends StatelessWidget {
const ChatScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder<List<Message>>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots()
.map((query) =>
query.docs.map((map) => Message.fromMap(map.data())).toList()),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final msgList = snapshot.data!;
return ListView.builder(
itemCount: msgList.length,
itemBuilder: (context, index) {
final message = msgList[index];
return ListTile(
title: Text(message.text),
leading: Text(message.sender),
);
},
);
});
}
}
CodePudding user response:
Try with this.
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: snapshot.hasData ? snapshot.data.docs.length : 0,
itemBuilder: (context, index) {
final data = MessageModel.fromSnapshot(snapshot.data.docs[index]);
return ListTile(
title: Text(data.text),
subtitle: Text(data.sender),
);
},
);
},
);
MessageModel
class MessageModel {
MessageModel({
this.sender,
this.text,
});
String sender;
String text;
String toRawJson() => json.encode(toJson());
factory MessageModel.fromSnapshot(DocumentSnapshot snapshot) {
final model =
MessageModel.fromJson(snapshot.data() as Map<String, dynamic>);
return model;
}
factory MessageModel.fromJson(Map<String, dynamic> json) => MessageModel(
sender: json["sender"] == null ? null : json["sender"],
text: json["text"] == null ? null : json["text"],
);
Map<String, dynamic> toJson() => {
"sender": sender == null ? null : sender,
"text": text == null ? null : text,
};
}
