多个流到firebase文档,无需处理
我正在尝试将聊天添加到我的应用程序中。 当我的用户开始与新用户聊天时,我会在Firebase数据库中创建一个具有唯一id的聊天室。我希望聊天室文档的任何更新(例如:新消息)都会通知我的用户,因此当我创建聊天室时,我也会为该聊天室文档创建一个新流。在不处理流的情况下,不断地侦听具有不同流的多个文档是否有问题(因为我想获得用户所属聊天室的最新结果。) 这是我的聊天室屏幕代码:多个流到firebase文档,无需处理,firebase,flutter,google-cloud-firestore,stream,Firebase,Flutter,Google Cloud Firestore,Stream,我正在尝试将聊天添加到我的应用程序中。 当我的用户开始与新用户聊天时,我会在Firebase数据库中创建一个具有唯一id的聊天室。我希望聊天室文档的任何更新(例如:新消息)都会通知我的用户,因此当我创建聊天室时,我也会为该聊天室文档创建一个新流。在不处理流的情况下,不断地侦听具有不同流的多个文档是否有问题(因为我想获得用户所属聊天室的最新结果。) 这是我的聊天室屏幕代码: import 'package:flutter/material.dart'; import '../models/data
import 'package:flutter/material.dart';
import '../models/databse_management.dart';
class ChatroomScreen extends StatefulWidget {
static const String routeName = "/chatroom_screen";
@override
_ChatroomScreenState createState() => _ChatroomScreenState();
}
class _ChatroomScreenState extends State<ChatroomScreen> {
TextEditingController _messageTextEditingController = TextEditingController();
bool isChatroomExists;
Stream chatroomDocStream; //my initial stream variable which is null
@override
Widget build(BuildContext context) {
final Map<String, dynamic> passedArguments =
ModalRoute.of(context).settings.arguments;
//sedner details can be retrieved from currentUserDetails
final String senderId = passedArguments["senderId"];
final List<String> receiversIds = passedArguments["receiverIds"];
final String senderUsername = passedArguments["senderUsername"];
final List<String> receiverUsernames = passedArguments["receiverUsernames"];
final String chatroomId = passedArguments["chatroomId"];
if(chatroomDocStream == null){
chatroomDocStream = Firestore.instance.collection("chatrooms").document(chatroomId).snapshots(); //if no stream was created before (first time we build the widget), we connect a stream to this chatroom documentspecified with chatroomId
}
isChatroomExists = isChatroomExists == null
? passedArguments["isChatroomExists"]
: isChatroomExists;
final Image senderProfilePictureUrl =
passedArguments["senderProfilePicture"];
final List<Image> receiverProfilePictures =
passedArguments["receiverProfilePictures"];
final mediaQuery = MediaQuery.of(context).size;
final ThemeData theme = Theme.of(context);
//we get the values from the passed argument map
if (isChatroomExists) {
//load the previous chats
}
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
CircleAvatar(
backgroundImage: receiverProfilePictures[0]
.image, //right now only for 1 receiver but change it for multi members later
),
Container(
child: Text(receiverUsernames[0]),
margin: const EdgeInsets.only(left: 10),
),
],
),
),
body: //to do=> create a stream that is listening to the chatroom document for any changes
Stack(
children: <Widget>[
StreamBuilder(
//updates the chats whenever data of the chatroom document changes
stream: chatroomDocStream,
builder: (context, snapShot) {
return Column(
children: <Widget>[
Center(child: const Text("My chats"))
//message widgets go here
],
);
},
),
Positioned(
//positioned is used for positioning the widgets inside a stack. bottom: 10 means 10 pixel from bottom
bottom: 0,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
width: mediaQuery.width, //takes the total width of the screen
decoration: BoxDecoration(
color: theme.primaryColor.withOpacity(0.3),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
//always takes the remaining space (textField widget use this as its size https://stackoverflow.com/questions/45986093/textfield-inside-of-row-causes-layout-exception-unable-to-calculate-size)
child: Container(
padding: const EdgeInsets.symmetric(
horizontal:
10), //horizontal padding for the textfield widget
decoration: BoxDecoration(
color: theme.accentColor,
borderRadius: BorderRadius.circular(25),
border: Border.all(width: 2, color: theme.primaryColor),
),
child: TextField(
minLines: 1,
maxLines: 5,
controller: _messageTextEditingController,
decoration: const InputDecoration(
hintText: "Type something here...",
border: InputBorder
.none //removes all the border for textfield widget
),
),
),
),
Container(
child: Row(
//another row for buttons to be treated all toghether as a container in the parent row
children: <Widget>[
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
//add media like image or pictures
},
),
IconButton(
icon: const Icon(Icons.camera_alt),
onPressed: () {
//take picture or video
},
),
IconButton(
icon: const Icon(Icons.send),
onPressed: () async {
if (_messageTextEditingController.text
.trim()
.isEmpty) {
return;
}
try {
await DatabaseManagement().sendMessage(
membersIds: [
senderId,
...receiversIds
], //extracts all the members of the list as seperate String items
//to do=>later on we have to get a list of the members as well
isChatroomExists: isChatroomExists,
chatroomId: chatroomId,
messageContent:
_messageTextEditingController.text,
senderId: senderId,
timestamp: Timestamp
.now(), //it's from firebase and records the time stamp of the sending message
);
if (isChatroomExists != true) {
isChatroomExists =
true; //after we sent a messsage, we 100% created the chatroom so it becomes true
}
} catch (e) {
print(
e.toString(),
);
return;
}
},
)
],
),
)
],
),
),
),
],
),
);
}
}
导入“包装:颤振/材料.省道”;
导入“../models/database_management.dart”;
类聊天室屏幕扩展StatefulWidget{
静态常量字符串routeName=“/chatroom\u screen”;
@凌驾
_聊天室屏幕状态createState()=>\u聊天室屏幕状态();
}
类\u聊天室屏幕状态扩展状态{
TextEditingController_messageTextEditingController=TextEditingController();
布尔是存在的;
Stream chatroomDocStream;//我的初始流变量为null
@凌驾
小部件构建(构建上下文){
最终地图通过了辩论=
ModalRoute.of(context.settings.arguments);
//可以从currentUserDetails检索sedner详细信息
最后一个字符串senderId=passedArguments[“senderId”];
最终名单接收方=通过的参数[“接收方”];
最后一个字符串senderUsername=passedArguments[“senderUsername”];
最终列表接收者用户名=传递的参数[“接收者用户名”];
最后一个字符串chatroomId=passedArguments[“chatroomId”];
if(chatroomDocStream==null){
chatroomDocStream=Firestore.instance.collection(“chatrooms”).document(chatroomId).snapshots();//如果之前没有创建流(第一次构建小部件),我们会将一个流连接到使用chatroomId指定的这个chatroomdocument
}
isChatroomExists=isChatroomExists==null
?通过的参数[“isChatroomExists”]
:IsChatRoom存在;
最终图像发送者ProfilePictureUrl=
已通过的辩论[“发件人档案图片”];
最终接收名单=
通过的辩论[“接收者档案图片”];
final mediaQuery=mediaQuery.of(context).size;
最终主题数据主题=theme.of(上下文);
//我们从传递的参数映射中获取值
如果(isChatroomExists){
//加载以前的聊天记录
}
返回脚手架(
appBar:appBar(
标题:世界其他地区(
mainAxisAlignment:mainAxisAlignment.start,
儿童:[
圆形(
背景图片:receiverProfilePictures[0]
.image,//目前仅针对1个接收器,但稍后针对多个成员更改它
),
容器(
子项:文本(接收方用户名[0]),
边距:仅限常量边集(左:10),
),
],
),
),
body://to do=>创建一个正在侦听聊天室文档的流,以获取任何更改
堆叠(
儿童:[
StreamBuilder(
//每当聊天室文档的数据发生更改时,更新聊天室
流:聊天室docstream,
生成器:(上下文,快照){
返回列(
儿童:[
中心(子:常量文本(“我的聊天”))
//消息小部件放在这里
],
);
},
),
定位(
//定位用于在堆栈中定位小部件。底部:10表示距离底部10像素
底部:0,
子:容器(
填充:常量边集。对称(水平:10,垂直:5),
宽度:mediaQuery.width,//获取屏幕的总宽度
装饰:盒子装饰(
颜色:主题。原色。不透明度(0.3),
),
孩子:排(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:[
扩大(
//始终将剩余空间(textField小部件)用作其大小https://stackoverflow.com/questions/45986093/textfield-inside-of-row-causes-layout-exception-unable-to-calculate-size)
子:容器(
填充:const EdgeInsets.symmetric(
水平:
10) ,//textfield小部件的水平填充
装饰:盒子装饰(
颜色:theme.accentColor,
边界半径:边界半径。圆形(25),
边框:边框.all(宽度:2,颜色:主题.primaryColor),
),
孩子:TextField(
小姑娘:1,
最大行数:5,
控制器:_messageTextEditingController,
装饰:常量输入装饰(
hintText:“在此处键入内容…”,
边框:输入边框
.none//删除textfield小部件的所有边框
),
),
),
),
容器(
孩子:排(
//另一行按钮将作为父行中的容器一起处理
儿童:[
图标按钮(
图标:常量图标(Icons.add),
已按下:(){
//添加图像或图片等媒体
},
),
图标按钮(
图标:常量图标(Icons.camera\u alt),
已按下:(){
//拍照或录像