mirror of
https://gitee.com/Zhaoxin59/my-chat_-client.git
synced 2026-02-13 16:41:48 +08:00
add sendMessage function
This commit is contained in:
@ -97,7 +97,7 @@ void MainWidget::initLeftWindow()
|
||||
sessionTabBtn->setFixedSize(45, 45);
|
||||
sessionTabBtn->setIconSize(QSize(35, 35));
|
||||
sessionTabBtn->setIcon(QIcon(":/resource/image/session_active.png"));
|
||||
sessionTabBtn->setStyleSheet("QPushButton {background-color: transparent; }");
|
||||
sessionTabBtn->setStyleSheet("QPushButton {background-color: transparent; border: none; }");
|
||||
layout->addWidget(sessionTabBtn, 1, Qt::AlignTop | Qt::AlignCenter);
|
||||
|
||||
//添加好友标签页按钮
|
||||
@ -105,7 +105,7 @@ void MainWidget::initLeftWindow()
|
||||
friendTabBtn->setFixedSize(45, 45);
|
||||
friendTabBtn->setIconSize(QSize(35, 35));
|
||||
friendTabBtn->setIcon(QIcon(":/resource/image/friend_inactive.png"));
|
||||
friendTabBtn->setStyleSheet("QPushButton {background-color: transparent; }");
|
||||
friendTabBtn->setStyleSheet("QPushButton {background-color: transparent; border: none; }");
|
||||
layout->addWidget(friendTabBtn, 1, Qt::AlignTop | Qt::AlignCenter);
|
||||
|
||||
//添加好友申请标签页按钮
|
||||
@ -113,7 +113,7 @@ void MainWidget::initLeftWindow()
|
||||
applyTabBtn->setFixedSize(45, 45);
|
||||
applyTabBtn->setIconSize(QSize(35, 35));
|
||||
applyTabBtn->setIcon(QIcon(":/resource/image/apply_inactive.png"));
|
||||
applyTabBtn->setStyleSheet("QPushButton {background-color: transparent; }");
|
||||
applyTabBtn->setStyleSheet("QPushButton {background-color: transparent; border: none; }");
|
||||
layout->addWidget(applyTabBtn, 1, Qt::AlignTop | Qt::AlignCenter);
|
||||
|
||||
layout->addStretch(20);
|
||||
@ -529,4 +529,30 @@ void MainWidget::updateRecentMessage(const QString& chatSessionId)
|
||||
messageShowArea->scrollToEnd();
|
||||
}
|
||||
|
||||
void MainWidget::switchSession(const QString& userId)
|
||||
{
|
||||
//找到对应的会话元素
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionByUserId(userId);
|
||||
if (chatSessionInfo == nullptr) {
|
||||
//每个好友都会有一个对应的会话(即便没有说过话)
|
||||
//添加好友的时候,就创建出来的会话
|
||||
LOG() << "严重错误->当前选中的好友对应的会话不存在";
|
||||
return;
|
||||
}
|
||||
//把选中的会话置顶
|
||||
dataCenter->topCurrentChatSessionId(*chatSessionInfo);
|
||||
|
||||
//切换到会话列表标签页
|
||||
switchTabToSession();
|
||||
|
||||
// 加载这个会话对应的历史消息
|
||||
sessionFriendArea->clickItem(0);
|
||||
}
|
||||
|
||||
MessageShowArea* MainWidget::getMessageShowArea()
|
||||
{
|
||||
return messageShowArea;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -104,5 +104,10 @@ public:
|
||||
|
||||
void loadRecentMessage(const QString& chatSessionId);
|
||||
void updateRecentMessage(const QString& chatSessionId);
|
||||
|
||||
//点击好友项后,切换到会话列表的总函数,上方的switchTabToSession只是其中的一个环节
|
||||
void switchSession(const QString& userId);
|
||||
|
||||
MessageShowArea* getMessageShowArea();
|
||||
};
|
||||
#endif // MAINWIDGET_H
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
#include "messageeditarea.h"
|
||||
|
||||
#include "mainwidget.h"
|
||||
|
||||
#include "model/datacenter.h"
|
||||
#include "toast.h"
|
||||
using namespace model;
|
||||
|
||||
MessageEditArea::MessageEditArea(QWidget *parent)
|
||||
: QWidget{parent}
|
||||
@ -174,13 +179,74 @@ MessageEditArea::MessageEditArea(QWidget *parent)
|
||||
// sendTextButton->installEventFilter(this);
|
||||
|
||||
|
||||
|
||||
|
||||
vlayout->addWidget(sendTextButton, 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||
|
||||
//统一初始化信号槽
|
||||
initSignalSlot();
|
||||
}
|
||||
|
||||
void MessageEditArea::initSignalSlot()
|
||||
{
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
|
||||
//关联“显示历史消息窗口”信号槽
|
||||
connect(showHistoryBtn, &QPushButton::clicked, this, [=]() {
|
||||
HistoryMessageWidget* historyMessageWidget = new HistoryMessageWidget(this);
|
||||
historyMessageWidget->exec();
|
||||
});
|
||||
|
||||
//关联“发送文本消息”信号槽
|
||||
connect(sendTextButton, &QPushButton::clicked, this, &MessageEditArea::sendTextMessage);
|
||||
|
||||
connect(dataCenter, &DataCenter::sendMessageDone, this, &MessageEditArea::addSelfMessage);
|
||||
}
|
||||
|
||||
void MessageEditArea::sendTextMessage()
|
||||
{
|
||||
//先确认当前是否有会话被选中
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||
LOG() << "当前未选中任何会话,不发送任何消息";
|
||||
//上述日志只是在开发阶段能看到,程序发布出去,就无法看到了
|
||||
//因此需要让普通用户也能看到提示
|
||||
Toast::showMessage("当前未选中会话,不发送任何消息");
|
||||
return;
|
||||
}
|
||||
|
||||
//获取到输入框的内容,没输入,则不做任何操作
|
||||
const QString& content = textEdit->toPlainText().trimmed();
|
||||
if (content.isEmpty()) {
|
||||
LOG() << "输入框为空";
|
||||
return;
|
||||
}
|
||||
|
||||
//清空输入框已有的内容
|
||||
textEdit->setPlainText("");
|
||||
|
||||
//通过网络发送数据给服务器
|
||||
dataCenter->sendTextMessageAsync(dataCenter->getCurrentSessionId(), content);
|
||||
}
|
||||
|
||||
//针对自己发送消息的操作,做处理,把自己发送的消息显示到界面上
|
||||
void MessageEditArea::addSelfMessage(MessageType messageType, const QByteArray& content, const QString& extraInfo)
|
||||
{
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
const QString& currentChatSessionId = dataCenter->getCurrentSessionId();
|
||||
//构造出一个消息对象
|
||||
Message message = Message::makeMessage(messageType, currentChatSessionId, *dataCenter->getMyselfsync(), content, extraInfo);
|
||||
dataCenter->addMessage(message);
|
||||
|
||||
//把这个新的消息,显示到消息展示区
|
||||
MainWidget* mainWidget = MainWidget::getInstance();
|
||||
MessageShowArea* messageShowArea = mainWidget->getMessageShowArea();
|
||||
messageShowArea->addMessage(false, message);
|
||||
|
||||
//控制消息显示区,滚动条,滚动到末尾
|
||||
messageShowArea->scrollToEnd();
|
||||
|
||||
//发送信号,通知会话列表,更新最后一条消息
|
||||
emit dataCenter->updateLastMessage(currentChatSessionId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
//#include <QEvent>
|
||||
|
||||
#include "historymessagewidget.h"
|
||||
#include "model/data.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
//编辑消息的区域
|
||||
class MessageEditArea : public QWidget
|
||||
@ -20,8 +23,12 @@ class MessageEditArea : public QWidget
|
||||
public:
|
||||
explicit MessageEditArea(QWidget *parent = nullptr);
|
||||
|
||||
void initSignalSlot();
|
||||
void sendTextMessage();
|
||||
void addSelfMessage(MessageType messageType, const QByteArray& content, const QString& extraInfo);
|
||||
//花式按钮事件
|
||||
//bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
|
||||
private:
|
||||
QPushButton* sendImageBtn;
|
||||
|
||||
@ -125,6 +125,7 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
|
||||
avatarBtn->setFixedSize(40, 40);
|
||||
avatarBtn->setIconSize(QSize(40, 40));
|
||||
avatarBtn->setIcon(message.sender.avatar);
|
||||
avatarBtn->setStyleSheet("QPushButton { border: none; }");
|
||||
if(isLeft) {
|
||||
layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignCenter | Qt::AlignLeft);
|
||||
} else {
|
||||
@ -133,7 +134,7 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
|
||||
|
||||
//创建名字和时间
|
||||
QLabel* nameLabel = new QLabel();
|
||||
nameLabel->setText(message.sender.nickname + " | " + message.time);
|
||||
nameLabel->setText(message.sender.nickname + " " + message.time);
|
||||
nameLabel->setAlignment(Qt::AlignBottom);
|
||||
nameLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
|
||||
if(isLeft) {
|
||||
|
||||
@ -268,6 +268,11 @@ namespace model
|
||||
}
|
||||
}
|
||||
|
||||
void DataCenter::sendTextMessageAsync(const QString& chatSessionId, const QString& content)
|
||||
{
|
||||
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(), "");
|
||||
}
|
||||
|
||||
ChatSessionInfo* DataCenter::findChatSessionById(const QString& chatSessionId)
|
||||
{
|
||||
if (chatSessionList == nullptr) {
|
||||
@ -281,6 +286,46 @@ namespace model
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ChatSessionInfo* DataCenter::findChatSessionByUserId(const QString& userId)
|
||||
{
|
||||
if (chatSessionList == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto& info : *chatSessionList) {
|
||||
if (info.userId == userId) {
|
||||
return &info;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void DataCenter::topCurrentChatSessionId(const ChatSessionInfo& chatSessionInfo)
|
||||
{
|
||||
if (chatSessionList == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
//把这个元素从列表中找到
|
||||
auto it = chatSessionList->begin();
|
||||
for (; it != chatSessionList->end(); ++it) {
|
||||
if (it->chatSessionId == chatSessionInfo.chatSessionId) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (it == chatSessionList->end()) {
|
||||
//上面的循环没有找到匹配的元素,直接返回,正常来说,不会走这个逻辑
|
||||
return;
|
||||
}
|
||||
|
||||
//删除并重新插入头部
|
||||
ChatSessionInfo backup = chatSessionInfo;
|
||||
chatSessionList->erase(it);
|
||||
|
||||
//把备份的元素插入到头部
|
||||
chatSessionList->push_front(backup);
|
||||
}
|
||||
|
||||
void DataCenter::setCurrentChatSessionId(const QString& chatSessionId)
|
||||
{
|
||||
this->currentChatSessionId = chatSessionId;
|
||||
@ -291,4 +336,10 @@ namespace model
|
||||
return currentChatSessionId;
|
||||
}
|
||||
|
||||
void DataCenter::addMessage(const Message& message)
|
||||
{
|
||||
QList<Message>& messageList = (*recentMessages)[message.chatSessionId];
|
||||
messageList.push_back(message);
|
||||
}
|
||||
|
||||
} //end namespace model
|
||||
|
||||
@ -122,12 +122,26 @@ namespace model
|
||||
QList<Message>* getRecentMessageList(const QString& chatSessionId);
|
||||
void resetRecentMessageList(const QString& chatSessionId, std::shared_ptr<bite_im::GetRecentMsgRsp> resp);
|
||||
|
||||
//发送消息给服务器
|
||||
void sendTextMessageAsync(const QString& chatSessionId, const QString& content);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
///辅助函数
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//根据会话id查询会话信息
|
||||
ChatSessionInfo* findChatSessionById(const QString& chatSessionId);
|
||||
//根据用户ID查询会话信息
|
||||
ChatSessionInfo* findChatSessionByUserId(const QString& userId);
|
||||
//把指定的会话信息,放到列表头部
|
||||
void topCurrentChatSessionId(const ChatSessionInfo& chatSessionInfo);
|
||||
|
||||
//设置/获取当前选中的会话
|
||||
void setCurrentChatSessionId(const QString& chatSessionId);
|
||||
const QString& getCurrentSessionId();
|
||||
|
||||
//添加消息到DataCenter中
|
||||
void addMessage(const Message& message);
|
||||
signals:
|
||||
//自定义信号
|
||||
void getMyselfDone();
|
||||
@ -135,5 +149,7 @@ namespace model
|
||||
void getChatSessionListDone();
|
||||
void getApplyListDone();
|
||||
void getRecentMessageListDone(const QString& chatSessionId);
|
||||
void sendMessageDone(MessageType messageType, const QByteArray& content, const QString& extraInfo);
|
||||
void updateLastMessage(const QString& chatSessionId);
|
||||
};
|
||||
} //end namespace model
|
||||
|
||||
@ -30,6 +30,7 @@ namespace network {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void NetClient::initWebSocket()
|
||||
{
|
||||
//准备好所需要的信号槽
|
||||
@ -283,4 +284,87 @@ namespace network {
|
||||
emit dataCenter->getRecentMessageListDone(chatSessionId);
|
||||
});
|
||||
}
|
||||
|
||||
//此处的extraInfo,可以用来传递扩展信息,尤其是对文件消息来说,通过这个字段表示“文件名”
|
||||
//其他类型的消息暂时不涉及,就直接设置为空,如果后续有消息类型需要,都可以给这个参数,赋予一定的特殊意义
|
||||
void NetClient::sendMessage(const QString& loginSessionId, const QString& chatSessionId,
|
||||
model::MessageType messageType, const QByteArray& content, const QString& extraInfo)
|
||||
{
|
||||
//通过protobuf 构造 body
|
||||
bite_im::NewMessageReq req;
|
||||
req.setRequestId(makeRequestId());
|
||||
req.setSessionId(loginSessionId);
|
||||
req.setChatSessionId(chatSessionId);
|
||||
|
||||
//构造MessageContent
|
||||
bite_im::MessageContent messageContent;
|
||||
if (messageType == MessageType::TEXT_TYPE) {
|
||||
messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::STRING);
|
||||
|
||||
bite_im::StringMessageInfo stringMessageInfo;
|
||||
stringMessageInfo.setContent(content);
|
||||
messageContent.setStringMessage(stringMessageInfo);
|
||||
}
|
||||
else if (messageType == MessageType::IMAGE_TYPE) {
|
||||
messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::IMAGE);
|
||||
|
||||
bite_im::ImageMessageInfo imageMessageInfo;
|
||||
imageMessageInfo.setFileId("");
|
||||
imageMessageInfo.setImageContent(content);
|
||||
messageContent.setImageMessage(imageMessageInfo);
|
||||
}
|
||||
else if (messageType == MessageType::FILE_TYPE) {
|
||||
messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::FILE);
|
||||
|
||||
bite_im::FileMessageInfo fileMessageInfo;
|
||||
fileMessageInfo.setFileId("");
|
||||
fileMessageInfo.setFileSize(content.size());
|
||||
fileMessageInfo.setFileName(extraInfo);
|
||||
fileMessageInfo.setFileContents(content);
|
||||
messageContent.setFileMessage(fileMessageInfo);
|
||||
}
|
||||
else if (messageType == MessageType::SPEECH_TYPE) {
|
||||
messageContent.setMessageType(bite_im::MessageTypeGadget::MessageType::SPEECH);
|
||||
|
||||
bite_im::SpeechMessageInfo speechMessageInfo;
|
||||
speechMessageInfo.setFileId("");
|
||||
speechMessageInfo.setFileContents(content);
|
||||
messageContent.setSpeechMessage(speechMessageInfo);
|
||||
}
|
||||
else {
|
||||
LOG() << "错误的消息类型 messageType= " << messageType;
|
||||
}
|
||||
req.setMessage(messageContent);
|
||||
|
||||
//序列化操作
|
||||
QByteArray body = req.serialize(&serializer);
|
||||
LOG() << "发送消息->发送请求 requestId= " << req.requestId() << ", loginSessionId=" << req.sessionId() <<
|
||||
", chatSessionId= " << req.chatSessionId() << ", messageType=" << req.message().messageType();
|
||||
|
||||
//发送HTTP请求
|
||||
QNetworkReply* resp = this->sendHttpRequest("/service/message_transmit/new_message", body);
|
||||
|
||||
//处理HTTP响应
|
||||
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||
//针对响应结果,进行解析
|
||||
bool ok = false;
|
||||
QString reason;
|
||||
auto pbResp = this->handleHttpResponse<bite_im::NewMessageRsp>(resp, &ok, &reason);
|
||||
|
||||
//判定响应是否正确
|
||||
if (!ok) {
|
||||
LOG() << "发送消息->处理出错 reason= " << reason;
|
||||
return;
|
||||
}
|
||||
|
||||
//此处只是记录成功和失败,不需要把内写入到DataCenter中
|
||||
|
||||
|
||||
//通知调用者,响应处理完毕
|
||||
emit dataCenter->sendMessageDone(messageType, content, extraInfo);
|
||||
|
||||
//打印日志
|
||||
LOG() << "发送消息->响应处理完毕 requestId=" << pbResp->requestId();
|
||||
});
|
||||
}
|
||||
} //end namespace network
|
||||
@ -84,6 +84,8 @@ namespace network {
|
||||
void getChatSessionList(const QString& loginSessionId);
|
||||
void getApplyList(const QString& loginSessionId);
|
||||
void getRecentMessageList(const QString& loginSessionId, const QString& chatSessionId);
|
||||
void sendMessage(const QString& loginSessionId, const QString& chatSessionId, model::MessageType messageType,
|
||||
const QByteArray& content, const QString& extraInfo);
|
||||
private:
|
||||
model::DataCenter* dataCenter;
|
||||
|
||||
|
||||
@ -3,12 +3,15 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "model/data.h"
|
||||
#include "model/datacenter.h"
|
||||
#include "mainwidget.h"
|
||||
|
||||
using namespace model;
|
||||
|
||||
SessionFriendArea::SessionFriendArea(QWidget *parent)
|
||||
: QScrollArea {parent}
|
||||
{
|
||||
//设置必要属性
|
||||
//设置必要属性
|
||||
//设置这个才能有滚动效果
|
||||
this->setWidgetResizable(true);
|
||||
//设置滚动条相关样式
|
||||
@ -114,9 +117,9 @@ SessionFriendItem::SessionFriendItem(QWidget* owner, const QIcon& avatar, const
|
||||
nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
//创建消息预览的label
|
||||
QLabel* messageLabel = new QLabel();
|
||||
messageLabel = new QLabel();
|
||||
messageLabel->setText(text);
|
||||
messageLabel->setStyleSheet("QLabel { font-size: 18px; font-weight: 600; }");
|
||||
messageLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 600; color: rgb(153, 153, 153); }");
|
||||
messageLabel->setFixedHeight(35);
|
||||
messageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
@ -255,7 +258,6 @@ void SessionFriendArea::clickItem(int index)
|
||||
item->select();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
/// 会话Item的实现
|
||||
////////////////////////////////////////
|
||||
@ -263,7 +265,52 @@ SessionItem::SessionItem(QWidget *owner, const QString &chatSessionId, const QIc
|
||||
const QString &name, const QString &lastmessage)
|
||||
:SessionFriendItem(owner, avatar, name, lastmessage), chatSessionId(chatSessionId)
|
||||
{
|
||||
//处理更新最后一个消息的信号
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
connect(dataCenter, &DataCenter::updateLastMessage, this, &SessionItem::updateLastMessage);
|
||||
}
|
||||
|
||||
void SessionItem::updateLastMessage(const QString& chatSessionId)
|
||||
{
|
||||
DataCenter* dataCenter = DataCenter::getInstance();
|
||||
//先判定,信号中的会话id得和当前元素自身持有放到会话id一致,才真正处理
|
||||
if (this->chatSessionId != chatSessionId) {
|
||||
//当前SessionItem不是正在发消息的SessionItem
|
||||
return;
|
||||
}
|
||||
//chatSession匹配,真正更新最后一条消息
|
||||
|
||||
//把最后一条消息获取到
|
||||
QList<Message>* messageList = dataCenter->getRecentMessageList(chatSessionId);
|
||||
if (messageList == nullptr || messageList->size() == 0) {
|
||||
//当前会话没有任何消息,无需更新
|
||||
return;
|
||||
}
|
||||
const Message& lastMessage = messageList->back();
|
||||
|
||||
//明确显示的文本内容
|
||||
QString text;
|
||||
if (lastMessage.messageType == TEXT_TYPE) {
|
||||
text = lastMessage.content;
|
||||
}
|
||||
else if (lastMessage.messageType == IMAGE_TYPE) {
|
||||
text = "[图片]";
|
||||
}
|
||||
else if (lastMessage.messageType == FILE_TYPE) {
|
||||
text = "[文件]";
|
||||
}
|
||||
else if (lastMessage.messageType == SPEECH_TYPE) {
|
||||
text = "[语音]";
|
||||
}
|
||||
else {
|
||||
LOG() << "错误的消息类型";
|
||||
return;
|
||||
}
|
||||
|
||||
//把这个内容显示到界面上
|
||||
//后续还要考虑到“未读消息”情况,
|
||||
//TODO
|
||||
this->messageLabel->setText(text);
|
||||
}
|
||||
|
||||
void SessionItem::active()
|
||||
@ -290,6 +337,9 @@ void FriendItem::active()
|
||||
{
|
||||
//点击之后,要激活对应的会话列元素
|
||||
LOG() << "click FriendItem... userId: " << userId;
|
||||
|
||||
MainWidget* mainWidget = MainWidget::getInstance();
|
||||
mainWidget->switchSession(userId);
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
@ -98,6 +98,8 @@ public:
|
||||
const QString& name, const QString& lastmessage);
|
||||
|
||||
void active() override;
|
||||
|
||||
void updateLastMessage(const QString& chatSessionId);
|
||||
private:
|
||||
//当前会话Id
|
||||
QString chatSessionId;
|
||||
|
||||
Reference in New Issue
Block a user