From 01c4baf04d46b95c7a06e26a288f734bad18682f Mon Sep 17 00:00:00 2001 From: xyz <2050965275@qq.com> Date: Wed, 25 Jun 2025 13:00:28 +0800 Subject: [PATCH] add Message received --- SelfInfoWidget.cpp | 7 +++++ SelfInfoWidget.h | 2 -- mainwidget.cpp | 2 +- messageeditarea.cpp | 20 +++++++++++- messageeditarea.h | 1 + model/datacenter.cpp | 25 +++++++++++++-- model/datacenter.h | 13 +++++++- network/netclient.cpp | 72 +++++++++++++++++++++++++++++++++++++++++-- network/netclient.h | 7 ++++- sessionfriendarea.cpp | 47 +++++++++++++++++++++++----- sessionfriendarea.h | 2 ++ 11 files changed, 180 insertions(+), 18 deletions(-) diff --git a/SelfInfoWidget.cpp b/SelfInfoWidget.cpp index 67e90bb..d9bfbc9 100644 --- a/SelfInfoWidget.cpp +++ b/SelfInfoWidget.cpp @@ -1,5 +1,12 @@ #include "selfinfowidget.h" +#include +#include + +#include "model/datacenter.h" + + + SelfInfoWidget::SelfInfoWidget(QWidget *parent) : QDialog(parent) { diff --git a/SelfInfoWidget.h b/SelfInfoWidget.h index 1e35d15..c1dc263 100644 --- a/SelfInfoWidget.h +++ b/SelfInfoWidget.h @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include "debug.h" diff --git a/mainwidget.cpp b/mainwidget.cpp index 2776af6..acc6ee7 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -493,7 +493,7 @@ void MainWidget::loadRecentMessage(const QString& chatSessionId) //本地没有数据,从网络加载 LOG() << "好友聊天数据不存在,正在从网络获取..."; connect(dataCenter, &DataCenter::getRecentMessageListDone, this, &MainWidget::updateRecentMessage, Qt::UniqueConnection); - dataCenter->getRecnetMessageListAsync(chatSessionId); + dataCenter->getRecnetMessageListAsync(chatSessionId, true); } } diff --git a/messageeditarea.cpp b/messageeditarea.cpp index 392868c..1d7e94e 100644 --- a/messageeditarea.cpp +++ b/messageeditarea.cpp @@ -198,8 +198,10 @@ void MessageEditArea::initSignalSlot() //关联“发送文本消息”信号槽 connect(sendTextButton, &QPushButton::clicked, this, &MessageEditArea::sendTextMessage); - connect(dataCenter, &DataCenter::sendMessageDone, this, &MessageEditArea::addSelfMessage); + + //关联收到消息的信号槽 + connect(dataCenter, &DataCenter::receiveMessageDone, this, &MessageEditArea::addOtherMessage); } void MessageEditArea::sendTextMessage() @@ -249,6 +251,22 @@ void MessageEditArea::addSelfMessage(MessageType messageType, const QByteArray& emit dataCenter->updateLastMessage(currentChatSessionId); } +void MessageEditArea::addOtherMessage(const model::Message& message) +{ + //通过主界面,拿到消息展示区 + MainWidget* mainWidget = MainWidget::getInstance(); + MessageShowArea* messageShowArea = mainWidget->getMessageShowArea(); + + //把收到的新消息,添加到消息展示区 + messageShowArea->addMessage(true, message); + + //控制消息展示区的滚动条,把窗口滚动到末尾 + messageShowArea->scrollToEnd(); + + //提示一个收到消息 + Toast::showMessage("收到新消息!"); +} + //bool MessageEditArea::eventFilter(QObject* obj, QEvent* event) //{ diff --git a/messageeditarea.h b/messageeditarea.h index e3f9960..7443a0c 100644 --- a/messageeditarea.h +++ b/messageeditarea.h @@ -26,6 +26,7 @@ public: void initSignalSlot(); void sendTextMessage(); void addSelfMessage(MessageType messageType, const QByteArray& content, const QString& extraInfo); + void addOtherMessage(const model::Message& message); //花式按钮事件 //bool eventFilter(QObject* obj, QEvent* event) override; diff --git a/model/datacenter.cpp b/model/datacenter.cpp index 52814c3..0f70921 100644 --- a/model/datacenter.cpp +++ b/model/datacenter.cpp @@ -142,6 +142,27 @@ namespace model file.close(); } + void DataCenter::clearUnread(const QString& chatSessionId) + { + (*unreadMessageCount)[chatSessionId] = 0; + + //手动保存一下结果到文件中 + saveDataFile(); + } + + void DataCenter::addUnread(const QString& chatSessionId) + { + ++(*unreadMessageCount)[chatSessionId]; + + //手动保存一下结果到文件 + saveDataFile(); + } + + int DataCenter::getUnread(const QString& chatSessionId) + { + return (*unreadMessageCount)[chatSessionId]; + } + void DataCenter::getMyselfAsync() { //DataCenter 只是负责“处理数据”, @@ -239,9 +260,9 @@ namespace model } } - void DataCenter::getRecnetMessageListAsync(const QString& chatSessionId) + void DataCenter::getRecnetMessageListAsync(const QString& chatSessionId, bool updateUI) { - netClient.getRecentMessageList(loginSessionId, chatSessionId); + netClient.getRecentMessageList(loginSessionId, chatSessionId, updateUI); } QList* DataCenter::getRecentMessageList(const QString& chatSessionId) diff --git a/model/datacenter.h b/model/datacenter.h index e078649..8afd343 100644 --- a/model/datacenter.h +++ b/model/datacenter.h @@ -87,6 +87,15 @@ namespace model //从数据文件中加载数据到内存 void loadDataFile(); + //清空未读消息数目 + void clearUnread(const QString& chatSessionId); + + //增加未读消息的数目 + void addUnread(const QString& chatSessionId); + + //获取未读消息的数目 + int getUnread(const QString& chatSessionId); + //获取到当前的登录会话Id const QString& getLoginSessionId() const{ return loginSessionId; @@ -118,7 +127,7 @@ namespace model void resetApplyList(std::shared_ptr resp); //获取最近的消息列表 - void getRecnetMessageListAsync(const QString& chatSessionId); + void getRecnetMessageListAsync(const QString& chatSessionId, bool updateUI); QList* getRecentMessageList(const QString& chatSessionId); void resetRecentMessageList(const QString& chatSessionId, std::shared_ptr resp); @@ -149,7 +158,9 @@ namespace model void getChatSessionListDone(); void getApplyListDone(); void getRecentMessageListDone(const QString& chatSessionId); + void getRecentMessageListDoneNoUI(const QString& chatSessionId); void sendMessageDone(MessageType messageType, const QByteArray& content, const QString& extraInfo); void updateLastMessage(const QString& chatSessionId); + void receiveMessageDone(const Message& lastMessage); }; } //end namespace model diff --git a/network/netclient.cpp b/network/netclient.cpp index bcdb2b3..d42486d 100644 --- a/network/netclient.cpp +++ b/network/netclient.cpp @@ -50,13 +50,55 @@ namespace network { connect(&websocketClient, &QWebSocket::binaryMessageReceived, this, [=](const QByteArray& byteArray) { LOG() << "webSocket 收到二进制的消息" << byteArray.length(); - //TODO + bite_im::NotifyMessage notifyMessage; + notifyMessage.deserialize(&serializer, byteArray); + handleWsResponse(notifyMessage); }); //和服务器真正建立连接 websocketClient.open(WEBSOCKET_URL); } + void NetClient::handleWsResponse(const bite_im::NotifyMessage& notifyMessage) + { + if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_MESSAGE_NOTIFY) { + //收到消息 + //把pb中的MessageInfo转成客户端自己的message + Message message; + message.load(notifyMessage.newMessageInfo().messageInfo()); + //针对自己的message做进一步的处理 + handleWsMessage(message); + } + else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY) { + + } + else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY) { + + } + else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY) { + + } + else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY) { + + } + } + + void NetClient::handleWsMessage(const model::Message& message) + { + // 这里要考虑两种情况 + QList* messageList = dataCenter->getRecentMessageList(message.chatSessionId); + if (messageList == nullptr) { + //如果当前这个消息所属的会话,里面的消息列表没有在本地加载,此时需要通过网络先加载整个消息列表 + connect(dataCenter, &DataCenter::getRecentMessageListDoneNoUI, this, &NetClient::receiveMessage, Qt::UniqueConnection); + dataCenter->getRecnetMessageListAsync(message.chatSessionId, false); + } + else { + //若已经在本地加载了,直接把这个消息尾插到消息列表中即可 + messageList->push_back(message); + this->receiveMessage(message.chatSessionId); + } + } + void NetClient::sendAuth() { bite_im::ClientAuthenticationReq req; @@ -250,7 +292,7 @@ namespace network { } - void NetClient::getRecentMessageList(const QString& loginSessionId, const QString& chatSessionId) + void NetClient::getRecentMessageList(const QString& loginSessionId, const QString& chatSessionId, bool updateUI) { //通过protobuf构造请求body bite_im::GetRecentMsgReq req; @@ -281,7 +323,12 @@ namespace network { dataCenter->resetRecentMessageList(chatSessionId, pbResp); //发送信号,告知界面进行更新 - emit dataCenter->getRecentMessageListDone(chatSessionId); + if (updateUI) { + emit dataCenter->getRecentMessageListDone(chatSessionId); + } + else { + emit dataCenter->getRecentMessageListDoneNoUI(chatSessionId); + } }); } @@ -367,4 +414,23 @@ namespace network { LOG() << "发送消息->响应处理完毕 requestId=" << pbResp->requestId(); }); } + + void NetClient::receiveMessage(const QString& chatSessionId) + { + //要先判定一下,这个收到消息对应的会话是否是正在被用户选中的“当前会话” + //当前会话,就需要把消息显示到消息展示区,也需要更新会话列表消息预览 + //若不是,只更新消息预览,并且更新“未读消息数目” + if (chatSessionId == dataCenter->getCurrentSessionId()) { + //说明是选中的会话 + const Message& lastMessage = dataCenter->getRecentMessageList(chatSessionId)->back(); + //通过信号,让NetClient模块能够通知界面 + emit dataCenter->receiveMessageDone(lastMessage); + } + else { + //说明不是 + dataCenter->addUnread(chatSessionId); + } + //统一更新会话列表的消息预览 + emit dataCenter->updateLastMessage(chatSessionId); + } } //end namespace network \ No newline at end of file diff --git a/network/netclient.h b/network/netclient.h index d1a0ab8..0198a51 100644 --- a/network/netclient.h +++ b/network/netclient.h @@ -36,6 +36,9 @@ namespace network { //初始化websocket void initWebSocket(); + void handleWsResponse(const bite_im::NotifyMessage& notifyMessage); + void handleWsMessage(const model::Message& message); + //发送身份认证请求 void sendAuth(); @@ -83,9 +86,11 @@ namespace network { void getFriendList(const QString& loginSessionId); void getChatSessionList(const QString& loginSessionId); void getApplyList(const QString& loginSessionId); - void getRecentMessageList(const QString& loginSessionId, const QString& chatSessionId); + void getRecentMessageList(const QString& loginSessionId, const QString& chatSessionId, bool updateUI); void sendMessage(const QString& loginSessionId, const QString& chatSessionId, model::MessageType messageType, const QByteArray& content, const QString& extraInfo); + + void receiveMessage(const QString& chatSessionId); private: model::DataCenter* dataCenter; diff --git a/sessionfriendarea.cpp b/sessionfriendarea.cpp index a568e8e..329829a 100644 --- a/sessionfriendarea.cpp +++ b/sessionfriendarea.cpp @@ -263,11 +263,24 @@ void SessionFriendArea::clickItem(int index) //////////////////////////////////////// SessionItem::SessionItem(QWidget *owner, const QString &chatSessionId, const QIcon &avatar, const QString &name, const QString &lastmessage) - :SessionFriendItem(owner, avatar, name, lastmessage), chatSessionId(chatSessionId) + :SessionFriendItem(owner, avatar, name, lastmessage), chatSessionId(chatSessionId), text(lastmessage) { //处理更新最后一个消息的信号 DataCenter* dataCenter = DataCenter::getInstance(); connect(dataCenter, &DataCenter::updateLastMessage, this, &SessionItem::updateLastMessage); + + //需要显示出未读消息的数目,需持久化,否则重启即丢失 + int unread = dataCenter->getUnread(chatSessionId); + if (unread > 0) { + //说明存在未读消息 + //this->messageLabel->setText(QString("[未读%1条]").arg(unread) + lastmessage); + QString coloredPart = QString("[未读%1条]").arg(unread).toHtmlEscaped(); + QString escapedText = lastmessage.toHtmlEscaped(); + messageLabel->setText(QString( + "%1" + "%2" + ).arg(coloredPart, escapedText)); + } } void SessionItem::updateLastMessage(const QString& chatSessionId) @@ -289,7 +302,6 @@ void SessionItem::updateLastMessage(const QString& chatSessionId) const Message& lastMessage = messageList->back(); //明确显示的文本内容 - QString text; if (lastMessage.messageType == TEXT_TYPE) { text = lastMessage.content; } @@ -309,8 +321,22 @@ void SessionItem::updateLastMessage(const QString& chatSessionId) //把这个内容显示到界面上 //后续还要考虑到“未读消息”情况, - //TODO - this->messageLabel->setText(text); + if (chatSessionId == dataCenter->getCurrentSessionId()) { + this->messageLabel->setText(text); + } + else { + int unread = dataCenter->getUnread(chatSessionId); + if (unread > 0) { + //说明存在未读消息 + //this->messageLabel->setText(QString("[未读%1条]").arg(unread) + text); + QString coloredPart = QString("[未读%1条]").arg(unread).toHtmlEscaped(); + QString escapedText = text.toHtmlEscaped(); + messageLabel->setText(QString( + "%1" + "%2" + ).arg(coloredPart, escapedText)); + } + } } void SessionItem::active() @@ -321,6 +347,13 @@ void SessionItem::active() //加载会话历史消息,会涉及到当前内存数据的操作,又会涉及到网络通信,以及UI界面的变更 MainWidget* mainWidget = MainWidget::getInstance(); mainWidget->loadRecentMessage(chatSessionId); + + //清空未读消息数据,并更新显示 + DataCenter* dataCenter = DataCenter::getInstance(); + dataCenter->clearUnread(chatSessionId); + + //更新界面的显示->把未读x条干掉 + this->messageLabel->setText(text); } //////////////////////////////////////// @@ -353,7 +386,7 @@ ApplyItem::ApplyItem(QWidget *owner, const QString &userId, const QIcon &avatar, QGridLayout* layout = dynamic_cast(this->layout()); layout->removeWidget(messageLabel); //要记得释放内存,否则会内存泄露 - // delete messageLabel; + delete messageLabel; //创建两个按钮 QPushButton* acceptBtn = new QPushButton(); @@ -364,8 +397,8 @@ ApplyItem::ApplyItem(QWidget *owner, const QString &userId, const QIcon &avatar, rejectBtn->setText("拒绝"); //添加到布局管理器中 - layout->addWidget(acceptBtn, 1, 2, 1, 1); - layout->addWidget(rejectBtn, 1, 3, 1, 1); + layout->addWidget(acceptBtn, 1, 2, 1, 3); + layout->addWidget(rejectBtn, 1, 5, 1, 3); } diff --git a/sessionfriendarea.h b/sessionfriendarea.h index ae01ccb..ea9bbd1 100644 --- a/sessionfriendarea.h +++ b/sessionfriendarea.h @@ -104,6 +104,8 @@ private: //当前会话Id QString chatSessionId; + //最后一条消息的文本预览 + QString text; }; ////////////////////////////////////////