英文:
Flutter FireStore: Unable to reverse a firebase snapshot list
问题
I am developing a chat app using firebase and flutter. When i type a msg the order of the message appearing is random. I want the messages to appear by timestamp. I am really new to coding. Can someone help me out?
For ex:
I just typed-this
And the messaged just appeared at some random place-Should have appeared after last message
Here's the code:-
class MessagesStream extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
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['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.0, vertical: 20.0),
children: messageBubbles,
),
);
},
stream: _firestore.collection('messages').snapshots(),
);
}
}
class MessageBubble extends StatelessWidget {
const MessageBubble({
super.key,
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: [
Text(
sender,
style: TextStyle(
fontSize: 12,
color: Colors.black54,
),
),
Material(
elevation: 5,
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
)
: BorderRadius only(
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black,
fontSize: 15,
),
),
),
),
],
),
);
}
}
I tried .reverese but didn't work!
final messages = snapshot.data!.docs.reversed;
But it didn't work. I am really new to this, Please help me on this stackoverflow gods.
英文:
I am developing a chat app using firebase and flutter. When i type a msg the order of the message appearing is random. I want the messages to appear by timestamp. I am really new to coding. Can someone help me out?
For ex:
I just typed-this
And the messaged just appeared at some random place-Should have appeared after last message
Here's the code:-
class MessagesStream extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
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['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.0, vertical: 20.0),
children: messageBubbles,
),
);
},
stream: _firestore.collection('messages').snapshots(),
);
}
}
class MessageBubble extends StatelessWidget {
const MessageBubble({
super.key,
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: [
Text(
sender,
style: TextStyle(
fontSize: 12,
color: Colors.black54,
),
),
Material(
elevation: 5,
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
)
: BorderRadius.only(
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black,
fontSize: 15,
),
),
),
),
],
),
);
}
}
I tried .reverese but didn't work!
final messages = snapshot.data!.docs.reversed;
But it didn't work. I am really new to this, Please help me on this stackoverflow gods.
答案1
得分: 1
你需要为你的消息添加一个时间戳字段,然后在查询中使用.orderBy()
方法来获取最新的消息。
时间戳字段可以是DateTime类型或int类型。
DateTime
这种方法稍微复杂一些,但可以直接在代码中使用DateTime类型。
- 创建一个DateTime转换器
class DateTimestampConverter implements JsonConverter<DateTime?, Timestamp?> {
const DateTimestampConverter();
@override
DateTime? fromJson(Timestamp? timestamp) => timestamp?.toDate();
@override
Timestamp? toJson(DateTime? dateTime) => dateTime != null ? Timestamp.fromDate(dateTime) : null;
}
-
安装 json_serializable 包。
-
在你的消息类上使用 @JsonSerializable 注解
part 'message.g.dart';
@JsonSerializable(
explicitToJson: true,
converters: [DateTimestampConverter()],
)
class Message {
String id;
...
factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
Map<String, dynamic> toJson() => _$MessageToJson(this);
}
- 运行构建命令
flutter packages pub run build_runner build --delete-conflicting-outputs
Int
另外一种方法是将timeCreated字段保存为一个int,如下所示:
Message newMessage = Message(
timeCreated: DateTime.now().millisecondsSinceEpoch,
)
英文:
You need to add a timestamp field to your messages and then use the .orderBy() method in your query to get the latest messages.
https://firebase.google.com/docs/firestore/query-data/order-limit-data
The timestamp field can either be a DateTime or an int.
DateTime
This way is a little more involved but it let's you directly use the DateTime type in your code.
- Create a DateTimeConverter
class DateTimestampConverter implements JsonConverter<DateTime?, Timestamp?> {
const DateTimestampConverter();
@override
DateTime? fromJson(Timestamp? timestamp) => timestamp?.toDate();
@override
Timestamp? toJson(DateTime? dateTime) => dateTime != null ? Timestamp.fromDate(dateTime) : null;
}
-
Install the json_serializable package.
-
Annotate your message class with the @JsonSerializable annotation
part 'message.g.dart';
@JsonSerializable(
explicitToJson: true,
converters: [DateTimestampConverter()],
)
class Message {
String id;
...
factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
Map<String, dynamic> toJson() => _$MessageToJson(this);
}
- Run the build runner
flutter packages pub run build_runner build --delete-conflicting-outputs
Int
Alternatively, save the timeCreated field as an int like this:
Message newMessage = Message(
timeCreated: DateTime.now().millisecondsSinceEpoch,
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论