【问题标题】:Read and Unread Message feature已读和未读消息功能
【发布时间】:2021-09-05 18:21:39
【问题描述】:

我正在尝试在我的聊天应用程序中创建已读和未读消息功能。

到目前为止,我只能创建未读,这意味着当我将消息发送到 firebase 集合时,我取消了我的 READ 属性字段为FALSE,

我很困惑如果第二个用户检查聊天室,他将如何将“READ: TRUE”的值更改回来,如果第二个用户当前在聊天室中,他仍然应该更改 READ: true。

这是我发送的消息数据:

    sender_id:12233,
    reciever_id: 6767,
    message:'hello please help',
    read: false,

这是我的代码

StreamBuilder(
                      stream: firestore
                          .collection('chat')
                          .doc(widget.peerid)
                          .collection('Messages')
                          .snapshots(),
                      builder: (context, snapshot) {
                        if (snapshot.hasData) {
                          return Center(
                            child: CircularProgressIndicator(),
                          );
                        }
                        if (snapshot.data.docs.isEmpty) {
                          return Center(
                            child: Column(
                              children: [
                                Container(
                                  child: Icon(
                                    FontAwesomeIcons.comments,
                                    size: 40,
                                  ),
                                ),
                                Text(
                                  'Say Hello',
                                  style: TextStyle(
                                    fontWeight: FontWeight.bold,
                                    fontSize: 15,
                                  ),
                                )
                              ],
                            ),
                          );
                        }
                        return ListView.builder(
                            shrinkWrap: true,
                            itemCount: snapshot.data.docs.length,
                            itemBuilder: (context, index) {
                              final authid =
                                  snapshot.data.docs[index].data()['idFrom'];
                              final msg =
                                  snapshot.data.docs[index].data()['content'];
                              bool check =
                                  authid == auth.currentUser.uid ? true : false;
                              return Padding(
                                padding: EdgeInsets.symmetric(
                                  horizontal: 15,
                                  vertical: 10,
                                ),
                                child: Column(
                                  crossAxisAlignment: check
                                      ? CrossAxisAlignment.end
                                      : CrossAxisAlignment.start,
                                  children: [
                                    Container(
                                      padding: EdgeInsets.all(10),
                                      decoration: BoxDecoration(
                                        color: check
                                            ? Colors.indigo
                                            : Colors.white,
                                        borderRadius: check
                                            ? BorderRadius.only(
                                                bottomLeft: Radius.circular(30),
                                                topLeft: Radius.circular(30),
                                                topRight: Radius.circular(30),
                                              )
                                            : BorderRadius.only(
                                                bottomRight:
                                                    Radius.circular(30),
                                                topLeft: Radius.circular(30),
                                                topRight: Radius.circular(30),
                                              ),
                                      ),
                                      child: ConstrainedBox(
                                        constraints:
                                            BoxConstraints(maxWidth: 150),
                                        child: Column(
                                          children: [
                                            Text(
                                              msg,
                                              style: GoogleFonts.raleway(
                                                textStyle: TextStyle(
                                                  color: check
                                                      ? Colors.white
                                                      : Colors.black,
                                                ),
                                              ),
                                            ),
                                            Text('')
                                          ],
                                        ),
                                      ),
                                    )
                                  ],
                                ),
                              );
                            });
                      }),
                ),
              ),
              Container(
                height: Platform.isIOS ? 95 : 80,
                padding: EdgeInsets.only(top: 8.0),
                decoration: BoxDecoration(
                  borderRadius:
                      BorderRadius.only(topRight: Radius.circular(70)),
                  color: Theme.of(context).backgroundColor,
                ),
                child: ListTile(
                  leading: Icon(
                    Icons.add,
                    color: Theme.of(context).primaryColor,
                  ),
                  title: TextFormField(
                    controller: messagesController,
                    onChanged: (value) {
                      messagesController.text = value;
                    },
                    decoration: InputDecoration(
                      hintText: 'Enter your messgae here...',
                      border: InputBorder.none,
                    ),
                    maxLines: null,
                  ),
                  trailing: messagesController.text.trim() == null
                      ? Container(
                          width: 40,
                          height: 45,
                          decoration: BoxDecoration(
                            shape: BoxShape.circle,
                            gradient: LinearGradient(
                              begin: Alignment.topRight,
                              end: Alignment.bottomLeft,
                              colors: [
                                Constants.color1,
                                Constants.color2,
                              ],
                            ),
                          ),
                          child: GestureDetector(
                            onTap: () async {
                              await ControllerApi().sendMessage(
                                content: messagesController.text.trim(),
                                chatID: widget.peerid,
                                messageType: 'text',
                                myID: auth.currentUser.uid,
                                selectedUserID: widget.userid,
                              );
                            },
                            child: Icon(
                              Icons.send,
                              size: 20,
                              color: Colors.white,
                            ),
                          ),
                        )
                      : Container(),
                ),
              )
            ],

谢谢。

【问题讨论】:

  • 会有一个聊天ID,我猜两者会在哪里互动。 :)
  • 是的...我将这两个 id 放在一起创建集合
  • 如果接收者看到然后为真,则最初添加假然后两者都会知道它的真..
  • 我不明白你最后的评论,你能解释一下吗?
  • 当第二个用户将他的消息从流加载到他的聊天屏幕时,你 .map 在每个快照上设置一个函数,如果 Read 字段的值等于 FALSE,则将其设置为 TRUE。

标签: android firebase flutter dart google-cloud-firestore


【解决方案1】:

使用这个颤振库 visibility_detector

请看下面的代码,它将帮助您实现已读和未读消息。

@override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemBuilder: (ctx, index) {
        ChatModel chatModel =
            ChatModel.fromJson(snapshot.data.docs[index].data());
        switch (chatModel.messageType) {
          case MessageType.TEXT:
            {
              return VisibilityDetector(
                key: Key(snapshot.data.docs[index].id),
                onVisibilityChanged: (VisibilityInfo visibilityInfo) {
                  var visiblePercentage = visibilityInfo.visibleFraction * 100;
                  if (visiblePercentage == 100 &&
                      !chatModel.isSeen &&
                      chatModel.sender != userController.userModel.value.uid) {
                    FirebaseFirestore.instance
                        .collection(FirebaseKeys.chatRoom)
                        .doc(AppHelper.getChatID(
                            userController.userModel.value.uid, userModel.uid))
                        .collection(FirebaseKeys.messages)
                        .doc(snapshot.data.docs[index].id)
                        .update({
                      "isSeen": true,
                    });
                  }
                },
                child:
                    TextMessage(chatModel, snapshot.data.docs[index].reference),
              );
            }
          case MessageType.GIF:
            {
              return GifMessage(chatModel, userModel.uid);
            }
          case MessageType.IMAGE:
            {
              return ImageMessage(snapshot.data.docs[index].reference,
                  chatModel, userModel.uid);
            }
          case MessageType.AUDIO:
            {
              break;
            }
          case MessageType.VIDEO:
            {
              break;
            }
          case MessageType.PDF:
            {
              break;
            }
          case MessageType.FILE:
            {
              break;
            }
          case MessageType.OTHER:
            {
              break;
            }
        }
        return FlutterLogo();
      },
      shrinkWrap: true,
      itemCount: snapshot.data.docs.length,
      controller: scrollController,
      reverse: true,
      physics: ClampingScrollPhysics(),
      separatorBuilder: (BuildContext context, int index) {
        return Container(
          height: 5,
          margin: EdgeInsets.only(top: 2, bottom: 2),
        );
      },
    );
  }

【讨论】:

  • 这个userController.userModel.value.uid是哪个id?
  • userController.userModel.value.uid 为登录用户UID
【解决方案2】:

让我们编写一个函数,将对手的消息标记为已读。

Future<void> seeMsg(int peerId) async{
     final query = await FirebaseFirestore.instance
        .collection('chat')
        .doc(peerId)
        .collection('Messages')
        .where('sender_id', isEqualTo: peerId)
        .where('read', isEqualTo: false)
        .get();

    query.docs.forEach((doc) {
      doc.reference.update({'read': true});
    });
}

然后,在StreamBuilder body 中调用这个函数。 每次,此聊天集合中都会生成一条新消息,此函数会检查来自您的同伴的未读消息并将其标记为已读。

【讨论】:

  • 能否请您查看问题代码并更新此问题的答案。
【解决方案3】:

在您的聊天应用程序中,当您向用户加载消息时,假设您已经加载了消息并拥有List&lt;Message&gt; messages。 假设您使用ListView.builder 显示消息:

return ListView.builder(
                shrinkWrap: true,
                controller: _controller,
                reverse: true,
                itemCount: messages.length,
                itemBuilder: (context, index) {
                  final message = messages[index];
                  // We check if message is new (dont know your entity so lets say it has boolean `read`, that false when new.
                  final bool isNew = !message.read;
                  // Given that you store your fire id in myId variable we check if message is received and not sent.
                  final bool toMe = message.recieverId == myId;
                  // Check that we need to mark message as read
                  if (isNew && toMe) {
                    return FutureBuilder<void>(
                        future: markAsRead(), // markAsRead is a Future function to change your FIELD value in firestore.
                         builder: (context, snapshot) {
                          if (snapshot.connectionState ==
                              ConnectionState.done) {
                            return YourMessageWidgetThatWasSeen()
                            }
                            return YourMessageWidgetThatWasNotSeen();}); //FutureBuilder ends here.
                  return MessageBubble(); // or this message is already seen by user and we return message bubble like usually do.

markAsRead() 函数的实现取决于数据库的结构,例如,当您的每个用户都有自己的消息集合要存储时,并且如果您有一个用于显示最后一条消息的对话框预览的集合,您将需要创建一个包含 4 个更新操作的批处理。

【讨论】:

  • 我现在得到它......所以我只会制作一个 futureBuilder 来改变 bool,比如 return FutureBuilder(future: firebase.collection('chat').doc(peerid)。 update({read: 'true'}); 或者我没有得到什么。因为 futurebuilder 接受 .get()
  • 请你给我看完整的回答代码..这样我会很清楚请
  • @GbengaBAyannuga 关于未来 是的,你明白了,FirebaseFirestore.instance..collection('chat').doc(peerid).update({read: 'true'});
  • 好的,我现在试试,我会回复你的。请问我怎样才能让你快速访问..因为我的系统现在很低
  • @GbengaBAyannuga 我也需要工作,写在这里,我会定期检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多