mirror of
https://gitee.com/Zhaoxin59/my-chat_-client.git
synced 2026-03-31 05:41:49 +08:00
has been completed.
This commit is contained in:
@ -9,13 +9,14 @@ set(CMAKE_AUTORCC ON)
|
|||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
|
||||||
# 查找模块
|
# 查找模块
|
||||||
find_package(Qt6 COMPONENTS
|
find_package(Qt6 COMPONENTS
|
||||||
|
Core
|
||||||
Protobuf
|
Protobuf
|
||||||
Widgets
|
Widgets
|
||||||
Network
|
Network
|
||||||
WebSockets
|
WebSockets
|
||||||
|
Multimedia
|
||||||
QUIET)
|
QUIET)
|
||||||
|
|
||||||
set(QT_VERSION_MAJOR 6)
|
set(QT_VERSION_MAJOR 6)
|
||||||
@ -57,7 +58,9 @@ endif()
|
|||||||
|
|
||||||
# 链接动态库
|
# 链接动态库
|
||||||
target_link_libraries(ClientChat PRIVATE
|
target_link_libraries(ClientChat PRIVATE
|
||||||
|
Qt6::Core
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt6::Network
|
Qt6::Network
|
||||||
Qt6::WebSockets
|
Qt6::WebSockets
|
||||||
|
Qt6::Multimedia
|
||||||
)
|
)
|
||||||
@ -10,7 +10,7 @@
|
|||||||
"CMAKE_CXX_FLAGS": "-DQT_QML_DEBUG"
|
"CMAKE_CXX_FLAGS": "-DQT_QML_DEBUG"
|
||||||
},
|
},
|
||||||
"environment": {
|
"environment": {
|
||||||
"QML_DEBUG_ARGS": "-qmljsdebugger=file:{7e8c2a2f-a445-4c9b-bb42-24fd265a3e1e},block"
|
"QML_DEBUG_ARGS": "-qmljsdebugger=file:{74e0e0b6-0fbf-4a0d-93e9-c8349734743b},block"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -70,7 +70,7 @@
|
|||||||
],
|
],
|
||||||
"vendor": {
|
"vendor": {
|
||||||
"qt-project.org/Presets": {
|
"qt-project.org/Presets": {
|
||||||
"checksum": "0wzuyL8qCbVtFSbq9ZO9Fr8MNQU="
|
"checksum": "Dlc1I+gqV2Q029C9SawBnzSygCA="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,8 +368,12 @@ void SelfInfoWidget::clickGetVerifyCodeBtn()
|
|||||||
|
|
||||||
//给服务器发送请求
|
//给服务器发送请求
|
||||||
DataCenter* dataCenter = DataCenter::getInstance();
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
connect(dataCenter, &DataCenter::getVerifyCodeDone, this, [=]() {
|
connect(dataCenter, &DataCenter::getVerifyCodeDone, this, [=](bool ok) {
|
||||||
//不需要做其他的处理,只需要提示一下,验证码已经发送出去了
|
//不需要做其他的处理,只需要提示一下,验证码已经发送出去了
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG() << "ok: " << ok;
|
||||||
Toast::showMessage("验证码已发送,请注意查收");
|
Toast::showMessage("验证码已发送,请注意查收");
|
||||||
});
|
});
|
||||||
dataCenter->getVerifyCodeAsync(email);
|
dataCenter->getVerifyCodeAsync(email);
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#include "addfrienddialog.h"
|
#include "addfrienddialog.h"
|
||||||
|
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
//表示一个好友搜索的结果
|
//表示一个好友搜索的结果
|
||||||
@ -23,6 +26,7 @@ FriendResultItem::FriendResultItem(const UserInfo& userInfo)
|
|||||||
avatarBtn->setFixedSize(50, 50);
|
avatarBtn->setFixedSize(50, 50);
|
||||||
avatarBtn->setIconSize(QSize(50, 50));
|
avatarBtn->setIconSize(QSize(50, 50));
|
||||||
avatarBtn->setIcon(userInfo.avatar);
|
avatarBtn->setIcon(userInfo.avatar);
|
||||||
|
avatarBtn->setStyleSheet("QPushButton { background-color: transparent; }");
|
||||||
|
|
||||||
// 4. 创建昵称
|
// 4. 创建昵称
|
||||||
QLabel* nameLabel = new QLabel();
|
QLabel* nameLabel = new QLabel();
|
||||||
@ -55,10 +59,22 @@ FriendResultItem::FriendResultItem(const UserInfo& userInfo)
|
|||||||
layout->addWidget(addBtn, 0, 2, 2, 1);
|
layout->addWidget(addBtn, 0, 2, 2, 1);
|
||||||
|
|
||||||
// 8. 连接信号槽
|
// 8. 连接信号槽
|
||||||
//connect(addBtn, &QPushButton::clicked, this, &FriendResultItem::clickAddBtn);
|
connect(addBtn, &QPushButton::clicked, this, &FriendResultItem::clickAddBtn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FriendResultItem::clickAddBtn()
|
||||||
|
{
|
||||||
|
//发送好友申请
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->addFriendApplyAsync(this->userInfo.userId);
|
||||||
|
|
||||||
|
//设置按钮为禁用状态
|
||||||
|
addBtn->setEnabled(false);
|
||||||
|
addBtn->setText("申请已发送");
|
||||||
|
addBtn->setStyleSheet("QPushButton { border: none; color: rgb(255, 255, 255); background-color: rgb(200, 200, 200); border-radius: 10px;}");
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
//整个搜索好友的窗口
|
//整个搜索好友的窗口
|
||||||
/////////////////////////////////////////
|
/////////////////////////////////////////
|
||||||
@ -115,8 +131,8 @@ AddFriendDialog::AddFriendDialog(QWidget *parent)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//
|
//
|
||||||
// // 6. 连接信号槽
|
// 6. 连接信号槽
|
||||||
// connect(searchBtn, &QPushButton::clicked, this, &AddFriendDialog::clickSearchBtn);
|
connect(searchBtn, &QPushButton::clicked, this, &AddFriendDialog::clickSearchBtn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,3 +186,32 @@ void AddFriendDialog::setSearchKey(const QString& searcheKey)
|
|||||||
searchEdit->setText(searcheKey);
|
searchEdit->setText(searcheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AddFriendDialog::clickSearchBtn()
|
||||||
|
{
|
||||||
|
//拿到输入框的内容
|
||||||
|
const QString& text = searchEdit->text();
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//给服务器发送请求
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::searchUserDone, this, &AddFriendDialog::clickSearchDone, Qt::UniqueConnection);
|
||||||
|
dataCenter->searchUserAsync(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddFriendDialog::clickSearchDone()
|
||||||
|
{
|
||||||
|
//拿到DataCenter中的搜索结果
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
QList<UserInfo>* searchResult = dataCenter->getSearchUserResult();
|
||||||
|
if (searchResult == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->clear();
|
||||||
|
for (const auto& u : *searchResult) {
|
||||||
|
this->addResult(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ class FriendResultItem : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
FriendResultItem(const UserInfo& userInfo);
|
FriendResultItem(const UserInfo& userInfo);
|
||||||
|
void clickAddBtn();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const UserInfo& userInfo;
|
const UserInfo& userInfo;
|
||||||
@ -50,6 +51,9 @@ public:
|
|||||||
//
|
//
|
||||||
void setSearchKey(const QString& searcheKey);
|
void setSearchKey(const QString& searcheKey);
|
||||||
|
|
||||||
|
void clickSearchBtn();
|
||||||
|
void clickSearchDone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//整个窗口的网格布局
|
//整个窗口的网格布局
|
||||||
QGridLayout* layout;
|
QGridLayout* layout;
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#include "choosefrienddialog.h"
|
#include "choosefrienddialog.h"
|
||||||
|
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
#include "toast.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
/// 选择好友窗口中的一个 元素/好友项
|
/// 选择好友窗口中的一个 元素/好友项
|
||||||
@ -85,8 +89,9 @@ void ChooseFriendItem::leaveEvent(QEvent* event)
|
|||||||
this->update();
|
this->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
ChooseFriendDialog::ChooseFriendDialog(QWidget *parent)
|
ChooseFriendDialog::ChooseFriendDialog(QWidget* parent, const QString& userId)
|
||||||
: QDialog(parent)
|
: QDialog(parent),
|
||||||
|
userId(userId)
|
||||||
{
|
{
|
||||||
// 1. 设置窗口的基本属性
|
// 1. 设置窗口的基本属性
|
||||||
this->setWindowTitle("选择好友");
|
this->setWindowTitle("选择好友");
|
||||||
@ -107,7 +112,8 @@ ChooseFriendDialog::ChooseFriendDialog(QWidget *parent)
|
|||||||
// 4. 针对右侧窗口进行初始化
|
// 4. 针对右侧窗口进行初始化
|
||||||
initRight(layout);
|
initRight(layout);
|
||||||
|
|
||||||
|
//加载数据到窗口
|
||||||
|
initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChooseFriendDialog::initLeft(QHBoxLayout* layout)
|
void ChooseFriendDialog::initLeft(QHBoxLayout* layout)
|
||||||
@ -213,14 +219,75 @@ void ChooseFriendDialog::initRight(QHBoxLayout* layout)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//// 8. 添加信号槽, 处理 ok 和 cancel 的点击
|
// 8. 添加信号槽, 处理 ok 和 cancel 的点击
|
||||||
//connect(okBtn, &QPushButton::clicked, this, &ChooseFriendDialog::clickOkBtn);
|
connect(okBtn, &QPushButton::clicked, this, &ChooseFriendDialog::clickOkBtn);
|
||||||
//connect(cancelBtn, &QPushButton::clicked, this, [=]() {
|
connect(cancelBtn, &QPushButton::clicked, this, [=]() {
|
||||||
// this->close();
|
this->close();
|
||||||
// });
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChooseFriendDialog::clickOkBtn()
|
||||||
|
{
|
||||||
|
//根据选中好友列表中的元素,得到所有的要创建群聊会话的用户id列表
|
||||||
|
QList<QString> userIdList = generateMemberList();
|
||||||
|
if (userIdList.size() < 3) {
|
||||||
|
Toast::showMessage("群聊中的成员不足三个,无法创建群聊");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送网络请求,创建群聊
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->createGroupChatSessionAsync(userIdList);
|
||||||
|
|
||||||
|
//关闭当前窗口
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QString> ChooseFriendDialog::generateMemberList()
|
||||||
|
{
|
||||||
|
QList<QString> result;
|
||||||
|
|
||||||
|
//把自己添加到结果中
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
if (dataCenter->getMyselfsync() == nullptr) {
|
||||||
|
LOG() << "个人信息尚未加载...";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.push_back(dataCenter->getMyselfsync()->userId);
|
||||||
|
|
||||||
|
//遍历选中的列表
|
||||||
|
QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(selectedContainer->layout());
|
||||||
|
for (int i = 0; i < layout->count(); ++i) {
|
||||||
|
auto* item = layout->itemAt(i);
|
||||||
|
if (item == nullptr || item->widget() == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto* chooseFriendItem = dynamic_cast<ChooseFriendItem*>(item->widget());
|
||||||
|
result.push_back(chooseFriendItem->getUserId());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ChooseFriendDialog::initData()
|
||||||
|
{
|
||||||
|
//遍历好友列表,把好友列表中的元素添加到这个窗口界面上
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
QList<UserInfo>* friendList = dataCenter->getFriendList();
|
||||||
|
if (friendList == nullptr) {
|
||||||
|
LOG() << "加载数据时发现好友列表为空";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto it = friendList->begin(); it != friendList->end(); ++it) {
|
||||||
|
if (it->userId == this->userId) {
|
||||||
|
this->addSelectedFriend(it->userId, it->avatar, it->nickname);
|
||||||
|
this->addFriend(it->userId, it->avatar, it->nickname, true);
|
||||||
|
}
|
||||||
|
this->addFriend(it->userId, it->avatar, it->nickname, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChooseFriendDialog::addFriend(const QString& userId, const QIcon& avatar, const QString& name, bool checked)
|
void ChooseFriendDialog::addFriend(const QString& userId, const QIcon& avatar, const QString& name, bool checked)
|
||||||
{
|
{
|
||||||
ChooseFriendItem* item = new ChooseFriendItem(this, userId, avatar, name, checked);
|
ChooseFriendItem* item = new ChooseFriendItem(this, userId, avatar, name, checked);
|
||||||
|
|||||||
@ -50,17 +50,23 @@ class ChooseFriendDialog : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChooseFriendDialog(QWidget *parent);
|
ChooseFriendDialog(QWidget *parent, const QString& userId);
|
||||||
|
|
||||||
void initLeft(QHBoxLayout* layout);
|
void initLeft(QHBoxLayout* layout);
|
||||||
void initRight(QHBoxLayout* layout);
|
void initRight(QHBoxLayout* layout);
|
||||||
|
void initData();
|
||||||
|
|
||||||
void addFriend(const QString& userId, const QIcon& avatar, const QString& name, bool checked);
|
void addFriend(const QString& userId, const QIcon& avatar, const QString& name, bool checked);
|
||||||
void addSelectedFriend(const QString& userId, const QIcon& avatar, const QString& name);
|
void addSelectedFriend(const QString& userId, const QIcon& avatar, const QString& name);
|
||||||
void deleteSelectedFriend(const QString& userId);
|
void deleteSelectedFriend(const QString& userId);
|
||||||
|
|
||||||
|
void clickOkBtn();
|
||||||
|
QList<QString> generateMemberList();
|
||||||
private:
|
private:
|
||||||
QWidget* totalContainer;
|
QWidget* totalContainer;
|
||||||
QWidget* selectedContainer;
|
QWidget* selectedContainer;
|
||||||
|
|
||||||
|
//当前选择窗口是点击哪个用户弹出的
|
||||||
|
QString userId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
12
debug.h
12
debug.h
@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
#define TEST_UI 0
|
#define TEST_UI 0
|
||||||
|
|
||||||
#define TEST_SKIP_LOGIN 1
|
|
||||||
|
|
||||||
#define TEST_NETWORK 1
|
|
||||||
|
|
||||||
#define TEST_GROUP_SESSION_DETAIL 1
|
#define TEST_GROUP_SESSION_DETAIL 1
|
||||||
|
|
||||||
|
#define TEST_SKIP_LOGIN 0
|
||||||
|
|
||||||
|
#define TEST_NETWORK 0
|
||||||
|
|
||||||
|
#define TEST_GROUP_SESSION_DETAIL 0
|
||||||
|
|
||||||
|
#define DEPOLY 1
|
||||||
|
|
||||||
#endif // DEBUG_H
|
#endif // DEBUG_H
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
#include "groupsessiondetailwidget.h"
|
#include "groupsessiondetailwidget.h"
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
GroupSessionDetailWidget::GroupSessionDetailWidget(QWidget *parent)
|
GroupSessionDetailWidget::GroupSessionDetailWidget(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
@ -64,7 +67,7 @@ GroupSessionDetailWidget::GroupSessionDetailWidget(QWidget *parent)
|
|||||||
vlayout->addLayout(hlayout);
|
vlayout->addLayout(hlayout);
|
||||||
|
|
||||||
//创建群聊名字的label
|
//创建群聊名字的label
|
||||||
QLabel* groupNameLabel = new QLabel();
|
groupNameLabel = new QLabel();
|
||||||
groupNameLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
groupNameLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
groupNameLabel->setFixedHeight(50);
|
groupNameLabel->setFixedHeight(50);
|
||||||
groupNameLabel->setStyleSheet("QLabel { font-size: 18px; }");
|
groupNameLabel->setStyleSheet("QLabel { font-size: 18px; }");
|
||||||
@ -98,6 +101,35 @@ GroupSessionDetailWidget::GroupSessionDetailWidget(QWidget *parent)
|
|||||||
this->addMember(item);
|
this->addMember(item);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//从服务器加载数据
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupSessionDetailWidget::initData()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getMemberListDone, this, &GroupSessionDetailWidget::initMembers);
|
||||||
|
dataCenter->getMemberListAsync(dataCenter->getCurrentSessionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupSessionDetailWidget::initMembers(const QString& chatSessionId)
|
||||||
|
{
|
||||||
|
//根据刚才拿到的成员列表,把成员列表渲染在界面上
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
QList<UserInfo>* memberList = dataCenter->getMemberList(chatSessionId);
|
||||||
|
if (memberList == nullptr) {
|
||||||
|
LOG() << "获取的成员列表为空 chatSessionId= " << chatSessionId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//遍历成员列表
|
||||||
|
for (const auto& u : *memberList) {
|
||||||
|
AvatarItem* avatarItem = new AvatarItem(u.avatar, u.nickname);
|
||||||
|
this->addMember(avatarItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
//群聊名称,此处暂时先设置为固定值
|
||||||
|
groupNameLabel->setText("新的群聊");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupSessionDetailWidget::addMember(AvatarItem* avatarItem)
|
void GroupSessionDetailWidget::addMember(AvatarItem* avatarItem)
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <qscrollarea.h>
|
#include <qscrollarea.h>
|
||||||
@ -21,10 +22,14 @@ class GroupSessionDetailWidget : public QDialog
|
|||||||
public:
|
public:
|
||||||
GroupSessionDetailWidget(QWidget* parent);
|
GroupSessionDetailWidget(QWidget* parent);
|
||||||
|
|
||||||
|
void initData();
|
||||||
|
void initMembers(const QString& chatSessionId);
|
||||||
|
|
||||||
void addMember(AvatarItem* avatarItem);
|
void addMember(AvatarItem* avatarItem);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGridLayout* glayout;
|
QGridLayout* glayout;
|
||||||
|
QLabel* groupNameLabel;
|
||||||
|
|
||||||
//表示当前所要添加的AvatarItem处在的行和列
|
//表示当前所要添加的AvatarItem处在的行和列
|
||||||
int curRow = 0;
|
int curRow = 0;
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
#include "historymessagewidget.h"
|
#include "historymessagewidget.h"
|
||||||
|
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
#include "toast.h"
|
||||||
|
#include "soundrecorder.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
//工厂函数
|
//工厂函数
|
||||||
HistoryItem* HistoryItem::makeHistoryItem(const Message& message)
|
HistoryItem* HistoryItem::makeHistoryItem(const Message& message)
|
||||||
@ -43,15 +48,15 @@ HistoryItem* HistoryItem::makeHistoryItem(const Message& message)
|
|||||||
}
|
}
|
||||||
else if (message.messageType == model::MessageType::IMAGE_TYPE) {
|
else if (message.messageType == model::MessageType::IMAGE_TYPE) {
|
||||||
// 图片消息
|
// 图片消息
|
||||||
//contentWidget = new ImageButton(message.fileId, message.content);
|
contentWidget = new ImageButton(message.fileId, message.content);
|
||||||
}
|
}
|
||||||
else if (message.messageType == model::MessageType::FILE_TYPE) {
|
else if (message.messageType == model::MessageType::FILE_TYPE) {
|
||||||
// 文件消息
|
// 文件消息
|
||||||
//contentWidget = new FileLabel(message.fileId, message.fileName);
|
contentWidget = new FileLabel(message.fileId, message.fileName);
|
||||||
}
|
}
|
||||||
else if (message.messageType == model::MessageType::SPEECH_TYPE) {
|
else if (message.messageType == model::MessageType::SPEECH_TYPE) {
|
||||||
// 语音消息
|
// 语音消息
|
||||||
//contentWidget = new SpeechLabel(message.fileId);
|
contentWidget = new SpeechLabel(message.fileId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG() << "错误的消息类型! messageType=" << message.messageType;
|
LOG() << "错误的消息类型! messageType=" << message.messageType;
|
||||||
@ -168,7 +173,7 @@ HistoryMessageWidget::HistoryMessageWidget(QWidget *parent)
|
|||||||
endTimeEdit->show();
|
endTimeEdit->show();
|
||||||
});
|
});
|
||||||
|
|
||||||
//connect(searchBtn, &QPushButton::clicked, this, &HistoryMessageWidget::clickSearchBtn);
|
connect(searchBtn, &QPushButton::clicked, this, &HistoryMessageWidget::clickSearchBtn);
|
||||||
|
|
||||||
// 构造测试数据
|
// 构造测试数据
|
||||||
#if TEST_UI
|
#if TEST_UI
|
||||||
@ -211,6 +216,48 @@ void HistoryMessageWidget::clear()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryMessageWidget::clickSearchBtn()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::searchMessageDone, this, &HistoryMessageWidget::clickSearchBtnDone, Qt::UniqueConnection);
|
||||||
|
|
||||||
|
//此处需要根据单选框的选中情况,执行不同逻辑
|
||||||
|
if (keyRadioBtn->isChecked()) {
|
||||||
|
//按照关键词搜索
|
||||||
|
const QString& searchKey = searchEdit->text();
|
||||||
|
if (searchKey.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dataCenter->searchMessageAsync(searchKey);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//安时间搜索
|
||||||
|
auto begTime = begTimeEdit->dateTime();
|
||||||
|
auto endTime = endTimeEdit->dateTime();
|
||||||
|
if (begTime >= endTime) {
|
||||||
|
Toast::showMessage("时间设置有误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dataCenter->searchMessageByTimeAsync(begTime, endTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryMessageWidget::clickSearchBtnDone()
|
||||||
|
{
|
||||||
|
//从DataCenter中拿到消息搜索结果列表
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
QList<Message>* messageResult = dataCenter->getSearchMessageReuslt();
|
||||||
|
if (messageResult == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//把结果列表的数据,显示到界面上
|
||||||
|
this->clear();
|
||||||
|
for (const Message& m : *messageResult) {
|
||||||
|
this->addHistoryMessage(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryMessageWidget::initScrollArea(QGridLayout* layout)
|
void HistoryMessageWidget::initScrollArea(QGridLayout* layout)
|
||||||
{
|
{
|
||||||
// 1. 创建滚动区域对象
|
// 1. 创建滚动区域对象
|
||||||
@ -236,3 +283,134 @@ void HistoryMessageWidget::initScrollArea(QGridLayout* layout)
|
|||||||
layout->addWidget(scrollArea, 2, 0, 1, 9);
|
layout->addWidget(scrollArea, 2, 0, 1, 9);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageButton::ImageButton(const QString& fileId, const QByteArray& content)
|
||||||
|
:fileId(fileId)
|
||||||
|
{
|
||||||
|
this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
this->setStyleSheet("QPushButton { border: none; }");
|
||||||
|
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
// 直接显示到界面上
|
||||||
|
this->updateUI(fileId, content);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 通过网络来获取
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getSingleFileDone, this, &ImageButton::updateUI);
|
||||||
|
dataCenter->getSingleFileAsync(fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageButton::updateUI(const QString& fileId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
if (this->fileId != fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果图片尺寸太大, 需要进行缩放.
|
||||||
|
QImage image;
|
||||||
|
image.loadFromData(content);
|
||||||
|
|
||||||
|
int width = image.width();
|
||||||
|
int height = image.height();
|
||||||
|
if (image.width() >= 300) {
|
||||||
|
// 进行缩放, 缩放之后, 宽度就是固定的 300
|
||||||
|
width = 300;
|
||||||
|
height = ((double)image.height() / image.width()) * width;
|
||||||
|
}
|
||||||
|
this->resize(width, height);
|
||||||
|
this->setIconSize(QSize(width, height));
|
||||||
|
QPixmap pixmap = QPixmap::fromImage(image);
|
||||||
|
this->setIcon(QIcon(pixmap));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLabel::FileLabel(const QString& fileId, const QString& fileName)
|
||||||
|
:fileId(fileId), filename(fileName)
|
||||||
|
{
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
this->setText("[文件] " + fileName);
|
||||||
|
this->setWordWrap(true);
|
||||||
|
// 自动调整尺寸让能够显示下文字内容
|
||||||
|
this->adjustSize();
|
||||||
|
this->setAlignment(Qt::AlignTop | Qt::AlignLeft);
|
||||||
|
|
||||||
|
// if (!content.isEmpty()) {
|
||||||
|
// // 原则上来说, 这个条件不会触发. 因为这里的 content 是来自于请求服务器的 历史消息列表的 接口.
|
||||||
|
// // 请求这个接口的过程中, 拿到的 Message 对象(不是文本), content 必然为 空, 通过 fileId 做二次请求.
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 需要从网络加载数据了
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getSingleFileDone, this, &FileLabel::getContentDone);
|
||||||
|
dataCenter->getSingleFileAsync(this->fileId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLabel::getContentDone(const QString& fileId, const QByteArray& fileContent)
|
||||||
|
{
|
||||||
|
if (fileId != this->fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->content = fileContent;
|
||||||
|
this->loadDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLabel::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
if (!this->loadDone) {
|
||||||
|
// 说明数据还没准备好.
|
||||||
|
Toast::showMessage("文件内容加载中, 请稍后尝试!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹出一个对话框, 让用户来选择当前要保存的位置
|
||||||
|
QString filePath = QFileDialog::getSaveFileName(this, "另存为", QDir::homePath(), "*");
|
||||||
|
if (filePath.isEmpty()) {
|
||||||
|
// 用户取消了保存
|
||||||
|
LOG() << "用户取消了保存";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeByteArrayToFile(filePath, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpeechLabel::SpeechLabel(const QString& fileId)
|
||||||
|
:fileId(fileId)
|
||||||
|
{
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
this->setText("[语音]");
|
||||||
|
this->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
// 这两个操作不太需要了. 此处只有 语音 两个字
|
||||||
|
this->setWordWrap(true);
|
||||||
|
this->adjustSize();
|
||||||
|
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getSingleFileDone, this, &SpeechLabel::getContentDone);
|
||||||
|
dataCenter->getSingleFileAsync(fileId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeechLabel::getContentDone(const QString& fileId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
if (fileId != this->fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->content = content;
|
||||||
|
this->loadDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeechLabel::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
if (!this->loadDone) {
|
||||||
|
Toast::showMessage("文件内容加载中, 稍后重试");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SoundRecorder* soundRecorder = SoundRecorder::getInstance();
|
||||||
|
soundRecorder->startPlay(this->content);
|
||||||
|
}
|
||||||
|
|||||||
@ -43,6 +43,9 @@ public:
|
|||||||
//清空窗口中所有的历史消息
|
//清空窗口中所有的历史消息
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
void clickSearchBtn();
|
||||||
|
void clickSearchBtnDone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initScrollArea(QGridLayout* layout);
|
void initScrollArea(QGridLayout* layout);
|
||||||
|
|
||||||
@ -56,3 +59,50 @@ private:
|
|||||||
//持有所有的历史消息结果的容器对象
|
//持有所有的历史消息结果的容器对象
|
||||||
QWidget* container;
|
QWidget* container;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// 展示图片历史消息
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class ImageButton : public QPushButton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImageButton(const QString& fileId, const QByteArray& content);
|
||||||
|
void updateUI(const QString& fileId, const QByteArray& content);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString fileId;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// 展示文件历史消息
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class FileLabel : public QLabel {
|
||||||
|
public:
|
||||||
|
FileLabel(const QString& fileId, const QString& filename);
|
||||||
|
void getContentDone(const QString& fileId, const QByteArray& fileContent);
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString fileId;
|
||||||
|
QByteArray content;
|
||||||
|
QString filename;
|
||||||
|
bool loadDone = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
/// 展示语音历史消息
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class SpeechLabel : public QLabel {
|
||||||
|
public:
|
||||||
|
SpeechLabel(const QString& fileId);
|
||||||
|
|
||||||
|
void getContentDone(const QString& fileId, const QByteArray& content);
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString fileId;
|
||||||
|
QByteArray content;
|
||||||
|
bool loadDone = false;
|
||||||
|
};
|
||||||
140
loginwidget.cpp
140
loginwidget.cpp
@ -1,5 +1,10 @@
|
|||||||
#include "loginwidget.h"
|
#include "loginwidget.h"
|
||||||
|
|
||||||
|
#include "mainwidget.h"
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
LoginWidget::LoginWidget(QWidget *parent)
|
LoginWidget::LoginWidget(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
@ -46,12 +51,12 @@ LoginWidget::LoginWidget(QWidget *parent)
|
|||||||
verifyCodeEdit->setPlaceholderText("输入验证码");
|
verifyCodeEdit->setPlaceholderText("输入验证码");
|
||||||
verifyCodeEdit->setStyleSheet(editStyle);
|
verifyCodeEdit->setStyleSheet(editStyle);
|
||||||
|
|
||||||
// 7. 创建显示验证码图片的控件 (此处先用 QPushButton 来表示一下, 后续进一步编写这里的逻辑)
|
// 创建显示验证码图片的控件 (此处先用 QPushButton 来表示一下, 后续进一步编写这里的逻辑)
|
||||||
// 后续会自定义 QWidget, 通过画图 api 来实现这里的验证码功能.
|
// 后续会自定义 QWidget, 通过画图 api 来实现这里的验证码功能.
|
||||||
QPushButton* verifyCodeWidget = new QPushButton();
|
//* verifyCodeWidget = new QPushButton();
|
||||||
verifyCodeWidget->setText("验证码");
|
//idget->setText("验证码");
|
||||||
verifyCodeWidget->setStyleSheet("QWidget { border: none; }");
|
//idget->setStyleSheet("QWidget { border: none; }");
|
||||||
//verifyCodeWidget = new VerifyCodeWidget(this);
|
verifyCodeWidget = new VerifyCodeWidget(this);
|
||||||
|
|
||||||
// 创建登录按钮
|
// 创建登录按钮
|
||||||
submitBtn = new QPushButton();
|
submitBtn = new QPushButton();
|
||||||
@ -88,8 +93,42 @@ LoginWidget::LoginWidget(QWidget *parent)
|
|||||||
|
|
||||||
|
|
||||||
// 处理信号槽
|
// 处理信号槽
|
||||||
//connect(switchModeBtn, &QPushButton::clicked, this, &LoginWidget::switchMode);
|
connect(switchModeBtn, &QPushButton::clicked, this, &LoginWidget::switchMode);
|
||||||
connect(switchModeBtn, &QPushButton::clicked, this, [=]() {
|
//connect(switchModeBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
// if (isLoginMode) {
|
||||||
|
// //切换到注册模式
|
||||||
|
// this->setWindowTitle("注册");
|
||||||
|
// titleLabel->setText("注册");
|
||||||
|
// submitBtn->setText("注册");
|
||||||
|
// switchModeBtn->setText("登录");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// //切换到登录模式
|
||||||
|
// this->setWindowTitle("登录");
|
||||||
|
// titleLabel->setText("登录");
|
||||||
|
// submitBtn->setText("登录");
|
||||||
|
// switchModeBtn->setText("注册");
|
||||||
|
// }
|
||||||
|
// isLoginMode = !isLoginMode;
|
||||||
|
// });
|
||||||
|
|
||||||
|
connect(phoneModeBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
// 此处还可以把 isLoginMode 这个值传到新的窗口中, 让新的窗口决定自己是登录状态还是注册状态. 大家自行尝试实现.
|
||||||
|
PhoneLoginWidget* phoneLoginWidget = new PhoneLoginWidget(nullptr);
|
||||||
|
phoneLoginWidget->show();
|
||||||
|
|
||||||
|
// 关闭当前窗口
|
||||||
|
this->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(submitBtn, &QPushButton::clicked, this, &LoginWidget::clickSubmitBtn);
|
||||||
|
/*connect(submitBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
Toast::showMessage("Just a test message...");
|
||||||
|
});*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginWidget::switchMode()
|
||||||
|
{
|
||||||
if (isLoginMode) {
|
if (isLoginMode) {
|
||||||
//切换到注册模式
|
//切换到注册模式
|
||||||
this->setWindowTitle("注册");
|
this->setWindowTitle("注册");
|
||||||
@ -105,19 +144,76 @@ LoginWidget::LoginWidget(QWidget *parent)
|
|||||||
switchModeBtn->setText("注册");
|
switchModeBtn->setText("注册");
|
||||||
}
|
}
|
||||||
isLoginMode = !isLoginMode;
|
isLoginMode = !isLoginMode;
|
||||||
});
|
}
|
||||||
|
|
||||||
connect(phoneModeBtn, &QPushButton::clicked, this, [=]() {
|
void LoginWidget::clickSubmitBtn()
|
||||||
// 此处还可以把 isLoginMode 这个值传到新的窗口中, 让新的窗口决定自己是登录状态还是注册状态. 大家自行尝试实现.
|
{
|
||||||
PhoneLoginWidget* phoneLoginWidget = new PhoneLoginWidget(nullptr);
|
//先从输入框拿到必要的内容
|
||||||
phoneLoginWidget->show();
|
const QString& username = usernameEdit->text();
|
||||||
|
const QString& password = passwordEdit->text();
|
||||||
// 关闭当前窗口
|
const QString& verifyCode = verifyCodeEdit->text();
|
||||||
this->close();
|
if (username.isEmpty()) {
|
||||||
});
|
Toast::showMessage("用户名不能为空");
|
||||||
|
return;
|
||||||
//connect(submitBtn, &QPushButton::clicked, this, &LoginWidget::clickSubmitBtn);
|
}
|
||||||
connect(submitBtn, &QPushButton::clicked, this, [=]() {
|
else if (password.isEmpty()) {
|
||||||
Toast::showMessage("Just a test message...");
|
Toast::showMessage("密码不能为空");
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
else if (verifyCode.isEmpty()) {
|
||||||
|
Toast::showMessage("验证码不能为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//对比验证码是否正确
|
||||||
|
if (!verifyCodeWidget->checkVerifyCode(verifyCode)) {
|
||||||
|
Toast::showMessage("验证码不正确");
|
||||||
|
verifyCodeEdit->clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//真正发送网络请求
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
if (isLoginMode) {
|
||||||
|
//登录
|
||||||
|
connect(dataCenter, &DataCenter::userLoginDone, this, &LoginWidget::userLoginDone);
|
||||||
|
dataCenter->userLoginAsync(username, password);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//注册
|
||||||
|
connect(dataCenter, &DataCenter::userRegisterDone, this, &LoginWidget::userRegisterDone);
|
||||||
|
dataCenter->userRegisterAsync(username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginWidget::userLoginDone(bool ok, const QString& reason)
|
||||||
|
{
|
||||||
|
//此处区分登录是否成功
|
||||||
|
//不成功反馈失败原因
|
||||||
|
if (!ok) {
|
||||||
|
Toast::showMessage("登录失败:" + reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//登录成功,要跳转到主页面
|
||||||
|
MainWidget* mainWidget = MainWidget::getInstance();
|
||||||
|
mainWidget->show();
|
||||||
|
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoginWidget::userRegisterDone(bool ok, const QString& reason)
|
||||||
|
{
|
||||||
|
if (!ok) {
|
||||||
|
Toast::showMessage("注册失败:" + reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Toast::showMessage("注册成功!");
|
||||||
|
|
||||||
|
//切换到登录界面
|
||||||
|
this->switchMode();
|
||||||
|
|
||||||
|
//输入框清空一下
|
||||||
|
verifyCodeEdit->clear();
|
||||||
|
verifyCodeWidget->refreshVerifyCode();
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
#include "phoneloginwidget.h"
|
#include "phoneloginwidget.h"
|
||||||
|
#include "verifycodewidget.h"
|
||||||
#include "toast.h"
|
#include "toast.h"
|
||||||
|
|
||||||
class LoginWidget : public QWidget
|
class LoginWidget : public QWidget
|
||||||
@ -16,11 +17,11 @@ class LoginWidget : public QWidget
|
|||||||
public:
|
public:
|
||||||
explicit LoginWidget(QWidget *parent);
|
explicit LoginWidget(QWidget *parent);
|
||||||
|
|
||||||
/*void switchMode();
|
void switchMode();
|
||||||
|
|
||||||
void clickSubmitBtn();
|
void clickSubmitBtn();
|
||||||
void userLoginDone(bool ok, const QString& reason);
|
void userLoginDone(bool ok, const QString& reason);
|
||||||
void userRegisterDone(bool ok, const QString& reason);*/
|
void userRegisterDone(bool ok, const QString& reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isLoginMode = true;
|
bool isLoginMode = true;
|
||||||
@ -29,7 +30,7 @@ private:
|
|||||||
QLineEdit* usernameEdit;
|
QLineEdit* usernameEdit;
|
||||||
QLineEdit* passwordEdit;
|
QLineEdit* passwordEdit;
|
||||||
QLineEdit* verifyCodeEdit;
|
QLineEdit* verifyCodeEdit;
|
||||||
//VerifyCodeWidget* verifyCodeWidget;
|
VerifyCodeWidget* verifyCodeWidget;
|
||||||
|
|
||||||
QPushButton* submitBtn;
|
QPushButton* submitBtn;
|
||||||
QPushButton* phoneModeBtn;
|
QPushButton* phoneModeBtn;
|
||||||
|
|||||||
19
main.cpp
19
main.cpp
@ -6,10 +6,25 @@
|
|||||||
#include "loginwidget.h"
|
#include "loginwidget.h"
|
||||||
#include "model/datacenter.h"
|
#include "model/datacenter.h"
|
||||||
|
|
||||||
|
FILE* output = nullptr;
|
||||||
|
|
||||||
|
void msgHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg) {
|
||||||
|
(void)type;
|
||||||
|
(void)context;
|
||||||
|
const QByteArray& log = msg.toUtf8();
|
||||||
|
fprintf(output, "%s\n", log.constData());
|
||||||
|
fflush(output);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
#if DEPOLY
|
||||||
|
output = fopen("./log.txt", "a");
|
||||||
|
qInstallMessageHandler(msgHandler);
|
||||||
|
#endif
|
||||||
|
|
||||||
qputenv("QT_QPA_PLATFORM", "windows:darkmode=0");
|
qputenv("QT_QPA_PLATFORM", "windows:darkmode=0");
|
||||||
|
|
||||||
LOG() << "Hello";
|
LOG() << "Hello";
|
||||||
@ -39,6 +54,10 @@ int main(int argc, char *argv[])
|
|||||||
MainWidget* w = MainWidget::getInstance();
|
MainWidget* w = MainWidget::getInstance();
|
||||||
w->show();
|
w->show();
|
||||||
#else
|
#else
|
||||||
|
QPalette palette;
|
||||||
|
palette.setColor(QPalette::WindowText, Qt::black);// 窗口文字颜色
|
||||||
|
QApplication::setPalette(palette);
|
||||||
|
|
||||||
LoginWidget* loginWidget = new LoginWidget(nullptr);
|
LoginWidget* loginWidget = new LoginWidget(nullptr);
|
||||||
loginWidget->show();
|
loginWidget->show();
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
117
mainwidget.cpp
117
mainwidget.cpp
@ -39,7 +39,8 @@ MainWidget::MainWidget(QWidget *parent)
|
|||||||
initRightWindow();
|
initRightWindow();
|
||||||
//初始化信号槽
|
//初始化信号槽
|
||||||
initSignalSlot();
|
initSignalSlot();
|
||||||
|
//初始化websocket
|
||||||
|
initWebSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWidget::~MainWidget()
|
MainWidget::~MainWidget()
|
||||||
@ -246,14 +247,28 @@ void MainWidget::initSignalSlot()
|
|||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
connect(extraBtn, &QPushButton::clicked, this, [=]() {
|
connect(extraBtn, &QPushButton::clicked, this, [=]() {
|
||||||
//判定当前的会话是单聊还是群聊
|
//判定当前的会话是单聊还是群聊
|
||||||
#if TEST_GROUP_SESSION_DETAIL
|
//#if TEST_GROUP_SESSION_DETAIL
|
||||||
bool isSingleChat = false; //要根据当前选中的实际的会话来确定
|
// bool isSingleChat = false; //要根据当前选中的实际的会话来确定
|
||||||
#else
|
//#else
|
||||||
bool isSingleChat = true; //要根据当前选中的实际的会话来确定
|
// bool isSingleChat = true; //要根据当前选中的实际的会话来确定
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
|
//获取到当前会话的详细信息, 通过会话中的userId属性
|
||||||
|
ChatSessionInfo* chatSessionInfo = dataCenter->findChatSessionById(dataCenter->getCurrentSessionId());
|
||||||
|
if (chatSessionInfo == nullptr) {
|
||||||
|
LOG() << "当前会话不存在, 无法弹出会话详情对话框";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool isSingleChat = chatSessionInfo->userId != "";
|
||||||
|
|
||||||
if (isSingleChat) {
|
if (isSingleChat) {
|
||||||
//说明是单聊
|
//说明是单聊
|
||||||
SessionDetailWidget* sessionDetailWidget = new SessionDetailWidget(this);
|
UserInfo* userInfo = dataCenter->findFriendById(chatSessionInfo->userId);
|
||||||
|
if (userInfo == nullptr) {
|
||||||
|
LOG() << "单聊会话对应的用户不存在,无法弹出会话详情窗口";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SessionDetailWidget* sessionDetailWidget = new SessionDetailWidget(this, *userInfo);
|
||||||
sessionDetailWidget->exec();
|
sessionDetailWidget->exec();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -316,6 +331,94 @@ void MainWidget::initSignalSlot()
|
|||||||
UserInfo* myself = dataCenter->getMyselfsync();
|
UserInfo* myself = dataCenter->getMyselfsync();
|
||||||
userAvatar->setIcon(myself->avatar);
|
userAvatar->setIcon(myself->avatar);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理删除好友
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::deleteFriendDone, this, [=]() {
|
||||||
|
//更新会话列表和好友列表
|
||||||
|
this->updateFriendList();
|
||||||
|
this->updateChatSessionList();
|
||||||
|
|
||||||
|
LOG() << "删除好友完成";
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(dataCenter, &DataCenter::clearCurrentSession, this, [=]() {
|
||||||
|
sessionTitleLabel->setText("");
|
||||||
|
messageShowArea->clear();
|
||||||
|
dataCenter->setCurrentChatSessionId("");
|
||||||
|
|
||||||
|
LOG() << "清空当前会话完成";
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理添加好友申请
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::addFriendApplyDone, this, [=]() {
|
||||||
|
Toast::showMessage("好友申请已发送");
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理添加好友申请的推送数据
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::receiveFriendApplyDone, this, [=]() {
|
||||||
|
this->updateApplyList();
|
||||||
|
Toast::showMessage("收到新的好友申请");
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理同意好友申请
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::acceptFriendApplyDone, this, [=]() {
|
||||||
|
this->updateApplyList();
|
||||||
|
this->updateFriendList();
|
||||||
|
Toast::showMessage("好友已经添加完成");
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理好友申请结果的推送数据
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::receiveFriendProcessDone, this, [=](const QString& nickname, bool agree) {
|
||||||
|
if (agree) {
|
||||||
|
//同意
|
||||||
|
this->updateFriendList();
|
||||||
|
Toast::showMessage(nickname + " 已经同意了你的好友申请");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Toast::showMessage(nickname + " 拒绝了你的好友申请");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理拒绝好友申请
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::rejectFriendApplyDone, this, [=]() {
|
||||||
|
//需要更新好友申请列表,刚才拒绝的这一项是需要删除的
|
||||||
|
this->updateApplyList();
|
||||||
|
Toast::showMessage("好友申请已拒绝");
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理创建群聊的响应信号
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::createGroupChatSessionDone, this, [=]() {
|
||||||
|
Toast::showMessage("创建群聊会话请求已经发送成功");
|
||||||
|
});
|
||||||
|
|
||||||
|
/////////////////////////////////////
|
||||||
|
// 处理创建会话的推送数据
|
||||||
|
/////////////////////////////////////
|
||||||
|
connect(dataCenter, &DataCenter::receiveSessionCreateDone, this, [=]() {
|
||||||
|
this->updateChatSessionList();
|
||||||
|
//通知用户入群
|
||||||
|
Toast::showMessage("您已被拉入到新的群聊中");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWidget::initWebSocket()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->initWebsocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::switchTabToSession()
|
void MainWidget::switchTabToSession()
|
||||||
|
|||||||
@ -89,6 +89,7 @@ public:
|
|||||||
void initRightWindow();
|
void initRightWindow();
|
||||||
|
|
||||||
void initSignalSlot();
|
void initSignalSlot();
|
||||||
|
void initWebSocket();
|
||||||
|
|
||||||
void switchTabToSession();
|
void switchTabToSession();
|
||||||
void switchTabToFriend();
|
void switchTabToFriend();
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "messageeditarea.h"
|
#include "messageeditarea.h"
|
||||||
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
#include "soundrecorder.h"
|
||||||
#include "model/datacenter.h"
|
#include "model/datacenter.h"
|
||||||
#include "toast.h"
|
#include "toast.h"
|
||||||
using namespace model;
|
using namespace model;
|
||||||
@ -182,6 +182,15 @@ MessageEditArea::MessageEditArea(QWidget *parent)
|
|||||||
|
|
||||||
vlayout->addWidget(sendTextButton, 0, Qt::AlignRight | Qt::AlignVCenter);
|
vlayout->addWidget(sendTextButton, 0, Qt::AlignRight | Qt::AlignVCenter);
|
||||||
|
|
||||||
|
//添加录制中
|
||||||
|
tipLabel = new QLabel();
|
||||||
|
tipLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
tipLabel->setText("录音中...");
|
||||||
|
tipLabel->setAlignment(Qt::AlignCenter);
|
||||||
|
tipLabel->setFont(QFont("微软雅黑", 24, 600));
|
||||||
|
vlayout->addWidget(tipLabel);
|
||||||
|
tipLabel->hide();
|
||||||
|
|
||||||
//统一初始化信号槽
|
//统一初始化信号槽
|
||||||
initSignalSlot();
|
initSignalSlot();
|
||||||
}
|
}
|
||||||
@ -192,6 +201,9 @@ void MessageEditArea::initSignalSlot()
|
|||||||
|
|
||||||
//关联“显示历史消息窗口”信号槽
|
//关联“显示历史消息窗口”信号槽
|
||||||
connect(showHistoryBtn, &QPushButton::clicked, this, [=]() {
|
connect(showHistoryBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
HistoryMessageWidget* historyMessageWidget = new HistoryMessageWidget(this);
|
HistoryMessageWidget* historyMessageWidget = new HistoryMessageWidget(this);
|
||||||
historyMessageWidget->exec();
|
historyMessageWidget->exec();
|
||||||
});
|
});
|
||||||
@ -202,6 +214,18 @@ void MessageEditArea::initSignalSlot()
|
|||||||
|
|
||||||
//关联收到消息的信号槽
|
//关联收到消息的信号槽
|
||||||
connect(dataCenter, &DataCenter::receiveMessageDone, this, &MessageEditArea::addOtherMessage);
|
connect(dataCenter, &DataCenter::receiveMessageDone, this, &MessageEditArea::addOtherMessage);
|
||||||
|
|
||||||
|
//关联发送图片
|
||||||
|
connect(sendImageBtn, &QPushButton::clicked, this, &MessageEditArea::clickSendImageBtn);
|
||||||
|
|
||||||
|
//关联发送文件
|
||||||
|
connect(sendFileBtn, &QPushButton::clicked, this, &MessageEditArea::clickSendFileBtn);
|
||||||
|
|
||||||
|
//关联发送语音
|
||||||
|
connect(sendSpeechBtn, &QPushButton::pressed, this, &MessageEditArea::soundRecordPressed);
|
||||||
|
connect(sendSpeechBtn, &QPushButton::released, this, &MessageEditArea::soundRecordReleased);
|
||||||
|
SoundRecorder* soundRecorder = SoundRecorder::getInstance();
|
||||||
|
connect(soundRecorder, &SoundRecorder::soundRecordDone, this, &MessageEditArea::soundSpeech);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageEditArea::sendTextMessage()
|
void MessageEditArea::sendTextMessage()
|
||||||
@ -267,6 +291,112 @@ void MessageEditArea::addOtherMessage(const model::Message& message)
|
|||||||
Toast::showMessage("收到新消息!");
|
Toast::showMessage("收到新消息!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageEditArea::clickSendImageBtn()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//判定当前是否有选中的会话
|
||||||
|
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||||
|
//没有选中会话
|
||||||
|
LOG() << "当前尚未选中任何会话";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//弹出文件对话框
|
||||||
|
QString filter = "Image Files (*.png *.jpg *.jpeg *.mp4)";
|
||||||
|
QString imagePath = QFileDialog::getOpenFileName(this, "选择图片", QDir::homePath(), filter);
|
||||||
|
if (imagePath.isEmpty()) {
|
||||||
|
LOG() << "用户取消选择";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取图片内容
|
||||||
|
QByteArray imageContent = loadFileToByteArray(imagePath);
|
||||||
|
|
||||||
|
//发送请求
|
||||||
|
dataCenter->sendImageMessageAsync(dataCenter->getCurrentSessionId(), imageContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageEditArea::clickSendFileBtn()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//判定当前是否有选中的会话
|
||||||
|
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||||
|
//没有选中会话
|
||||||
|
LOG() << "当前尚未选中任何会话";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//弹出对话框,选择文件
|
||||||
|
QString filter = "*";
|
||||||
|
QString path = QFileDialog::getOpenFileName(this, "选择文件", QDir::homePath(), filter);
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
LOG() << "用户取消选择";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//读取文件内容(暂时没有考虑非常大的文件)
|
||||||
|
//如果针对大文件,编写专门的网络通信接口,实现分片传输效果
|
||||||
|
QByteArray content = loadFileToByteArray(path);
|
||||||
|
|
||||||
|
//传输文件,还需要获取到文件名
|
||||||
|
QFileInfo fileInfo(path);
|
||||||
|
const QString& filename = fileInfo.fileName();
|
||||||
|
|
||||||
|
//发送消息
|
||||||
|
dataCenter->sendFileMessageAsync(dataCenter->getCurrentSessionId(), filename, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageEditArea::soundRecordPressed()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//判定当前是否有选中的会话
|
||||||
|
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||||
|
//没有选中会话
|
||||||
|
LOG() << "当前尚未选中任何会话";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//切换语音按钮的图标
|
||||||
|
sendSpeechBtn->setIcon(QIcon(":/resource/image/sound_active.png"));
|
||||||
|
|
||||||
|
//开始录音
|
||||||
|
SoundRecorder* soundRecorder = SoundRecorder::getInstance();
|
||||||
|
soundRecorder->startRecord();
|
||||||
|
tipLabel->show();
|
||||||
|
textEdit->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageEditArea::soundRecordReleased()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//判定当前是否有选中的会话
|
||||||
|
if (dataCenter->getCurrentSessionId().isEmpty()) {
|
||||||
|
//没有选中会话
|
||||||
|
LOG() << "当前尚未选中任何会话";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//切换语音按钮的图标
|
||||||
|
sendSpeechBtn->setIcon(QIcon(":/resource/image/sound.png"));
|
||||||
|
|
||||||
|
//开始录音
|
||||||
|
SoundRecorder* soundRecorder = SoundRecorder::getInstance();
|
||||||
|
tipLabel->hide();
|
||||||
|
textEdit->show();
|
||||||
|
soundRecorder->stopRecord();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageEditArea::soundSpeech(const QString& path)
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
QByteArray content = loadFileToByteArray(path);
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
LOG() << "语音文件加载失败";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dataCenter->sendSpeechMessageAsync(dataCenter->getCurrentSessionId(), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//bool MessageEditArea::eventFilter(QObject* obj, QEvent* event)
|
//bool MessageEditArea::eventFilter(QObject* obj, QEvent* event)
|
||||||
//{
|
//{
|
||||||
|
|||||||
@ -30,7 +30,13 @@ public:
|
|||||||
//花式按钮事件
|
//花式按钮事件
|
||||||
//bool eventFilter(QObject* obj, QEvent* event) override;
|
//bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
|
|
||||||
|
void clickSendImageBtn();
|
||||||
|
void clickSendFileBtn();
|
||||||
|
|
||||||
|
void soundRecordPressed();
|
||||||
|
void soundRecordReleased();
|
||||||
|
|
||||||
|
void soundSpeech(const QString& path);
|
||||||
private:
|
private:
|
||||||
QPushButton* sendImageBtn;
|
QPushButton* sendImageBtn;
|
||||||
QPushButton* sendFileBtn;
|
QPushButton* sendFileBtn;
|
||||||
@ -38,6 +44,7 @@ private:
|
|||||||
QPushButton* showHistoryBtn;
|
QPushButton* showHistoryBtn;
|
||||||
QPlainTextEdit* textEdit;
|
QPlainTextEdit* textEdit;
|
||||||
QPushButton* sendTextButton;
|
QPushButton* sendTextButton;
|
||||||
|
QLabel* tipLabel;
|
||||||
|
|
||||||
//花式按钮
|
//花式按钮
|
||||||
//QGraphicsDropShadowEffect* shadowEffect;
|
//QGraphicsDropShadowEffect* shadowEffect;
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
#include "messageshowarea.h"
|
#include "messageshowarea.h"
|
||||||
|
|
||||||
#include "mainwidget.h"
|
#include <QMenu>
|
||||||
#include "userinfowidget.h"
|
|
||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
|
#include "mainwidget.h"
|
||||||
|
#include "QFileDialog"
|
||||||
|
#include "toast.h"
|
||||||
|
#include "userinfowidget.h"
|
||||||
#include "model/datacenter.h"
|
#include "model/datacenter.h"
|
||||||
|
#include "soundrecorder.h"
|
||||||
|
|
||||||
MessageShowArea::MessageShowArea() {
|
MessageShowArea::MessageShowArea() {
|
||||||
//初始化基本属性
|
//初始化基本属性
|
||||||
@ -151,13 +155,13 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
|
|||||||
contentWidget = makeTextMessageItem(isLeft, message.content);
|
contentWidget = makeTextMessageItem(isLeft, message.content);
|
||||||
break;
|
break;
|
||||||
case model::IMAGE_TYPE:
|
case model::IMAGE_TYPE:
|
||||||
contentWidget = makeImageMessageItem();
|
contentWidget = makeImageMessageItem(isLeft, message.fileId, message.content);
|
||||||
break;
|
break;
|
||||||
case model::FILE_TYPE:
|
case model::FILE_TYPE:
|
||||||
contentWidget = makeFileMessageItem();
|
contentWidget = makeFileMessageItem(isLeft, message);
|
||||||
break;
|
break;
|
||||||
case model::SPEECH_TYPE:
|
case model::SPEECH_TYPE:
|
||||||
contentWidget = makeSpeechMessageItem();
|
contentWidget = makeSpeechMessageItem(isLeft, message);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG() << "error messageType: " << message.messageType;
|
LOG() << "error messageType: " << message.messageType;
|
||||||
@ -193,32 +197,38 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
|
|||||||
|
|
||||||
QWidget *MessageItem::makeTextMessageItem(bool isLeft, const QString &text)
|
QWidget *MessageItem::makeTextMessageItem(bool isLeft, const QString &text)
|
||||||
{
|
{
|
||||||
MessageContentLabel* messageContentLabel = new MessageContentLabel(text, isLeft);
|
MessageContentLabel* messageContentLabel = new MessageContentLabel(text, isLeft, TEXT_TYPE, "", QByteArray());
|
||||||
return messageContentLabel;
|
return messageContentLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *MessageItem::makeImageMessageItem()
|
QWidget *MessageItem::makeImageMessageItem(bool isLeft, const QString& fileId, const QByteArray& content)
|
||||||
{
|
{
|
||||||
return nullptr;
|
MessageImageLabel* messageImageLabel = new MessageImageLabel(fileId, content, isLeft);
|
||||||
|
return messageImageLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *MessageItem::makeFileMessageItem()
|
QWidget *MessageItem::makeFileMessageItem(bool isLeft, const Message& message)
|
||||||
{
|
{
|
||||||
return nullptr;
|
MessageContentLabel* messageContentLabel = new MessageContentLabel("[文件] " + message.fileName, isLeft, message.messageType,
|
||||||
|
message.fileId, message.content);
|
||||||
|
return messageContentLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *MessageItem::makeSpeechMessageItem()
|
QWidget *MessageItem::makeSpeechMessageItem(bool isLeft, const Message& message)
|
||||||
{
|
{
|
||||||
return nullptr;
|
MessageContentLabel* messageContentLabel = new MessageContentLabel("[语音]", isLeft, message.messageType, message.fileId, message.content);
|
||||||
|
return messageContentLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
/// 创建类表示“文本消息”正文部分
|
/// 创建类表示“文本消息”正文部分
|
||||||
|
//这个类也表示文件消息
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
MessageContentLabel::MessageContentLabel(const QString &text, bool isLeft)
|
MessageContentLabel::MessageContentLabel(const QString& text, bool isLeft, model::MessageType messageType, const QString& fileId,
|
||||||
:isLeft(isLeft)
|
const QByteArray& content)
|
||||||
|
:isLeft(isLeft), messageType(messageType), fileId(fileId), content(content)
|
||||||
{
|
{
|
||||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
@ -232,6 +242,21 @@ MessageContentLabel::MessageContentLabel(const QString &text, bool isLeft)
|
|||||||
this->label->setAlignment(Qt::AlignCenter | Qt::AlignLeft);
|
this->label->setAlignment(Qt::AlignCenter | Qt::AlignLeft);
|
||||||
this->label->setWordWrap(true);
|
this->label->setWordWrap(true);
|
||||||
this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");
|
this->label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");
|
||||||
|
|
||||||
|
//针对文件消息,且content为空,通过网络加载数据
|
||||||
|
if (messageType == model::TEXT_TYPE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->content.isEmpty()) {
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getSingleFileDone, this, &MessageContentLabel::updateUI);
|
||||||
|
dataCenter->getSingleFileAsync(this->fileId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//content 不为空,说明这个数据已经是现成的,加载状态直接改为true即可
|
||||||
|
this->loadContentDone = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//这个函数会在该控件被显示时,自动的调用到
|
//这个函数会在该控件被显示时,自动的调用到
|
||||||
@ -307,3 +332,181 @@ void MessageContentLabel::paintEvent(QPaintEvent *event)
|
|||||||
//注意高度要涵盖之前的名字和时间的label的高度,以及留一点的冗余的空间
|
//注意高度要涵盖之前的名字和时间的label的高度,以及留一点的冗余的空间
|
||||||
parent->setFixedHeight(height + 50);
|
parent->setFixedHeight(height + 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
//鼠标点击之后,触发文件另存为
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
//左键按下
|
||||||
|
if (this->messageType == FILE_TYPE) {
|
||||||
|
//真正触发另存为
|
||||||
|
if (!this->loadContentDone) {
|
||||||
|
Toast::showMessage("数据尚未加载成功,请稍后重试");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveAsFile(this->content);
|
||||||
|
}
|
||||||
|
else if (this->messageType == SPEECH_TYPE) {
|
||||||
|
if (!this->loadContentDone) {
|
||||||
|
Toast::showMessage("数据尚未加载成功,请稍后重试");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SoundRecorder* soundRecorder = SoundRecorder::getInstance();
|
||||||
|
this->label->setText("播放中...");
|
||||||
|
connect(soundRecorder, &SoundRecorder::soundPlayDone, this, &MessageContentLabel::playDone, Qt::UniqueConnection);
|
||||||
|
soundRecorder->startPlay(this->content);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//啥也不做
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::updateUI(const QString& fileId, const QByteArray& fileContent)
|
||||||
|
{
|
||||||
|
if (fileId != this->fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->content = fileContent;
|
||||||
|
this->loadContentDone = true;
|
||||||
|
//从服务器拿到文件正文之前,界面内容就应该已经绘制好了,拿到正文之后,也不需要做出调整
|
||||||
|
//所以,👇没有也行
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::saveAsFile(const QByteArray& content)
|
||||||
|
{
|
||||||
|
//弹出对话框,让让用户选择路径
|
||||||
|
QString filePath = QFileDialog::getOpenFileName(this, "另存为", QDir::homePath(), "*");
|
||||||
|
if (filePath.isEmpty()) {
|
||||||
|
LOG() << "用户取消了文件另存为";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writeByteArrayToFile(filePath, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::playDone()
|
||||||
|
{
|
||||||
|
if (this->label->text() == "播放中...") {
|
||||||
|
this->label->setText("[语音]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::contextMenuEvent(QContextMenuEvent* event)
|
||||||
|
{
|
||||||
|
//LOG() << "触发上下文菜单";
|
||||||
|
(void)event;
|
||||||
|
if (messageType != SPEECH_TYPE) {
|
||||||
|
LOG() << "非语音消息暂不支持右键菜单";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMenu* menu = new QMenu(this);
|
||||||
|
menu->setStyleSheet("QMenu { color: rgb(0, 0, 0); }");
|
||||||
|
QAction* action = menu->addAction("语音转文字");
|
||||||
|
connect(action, &QAction::triggered, this, [=]() {
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::speechConvertTextDone, this, &MessageContentLabel::speechConverTextDone, Qt::UniqueConnection);
|
||||||
|
dataCenter->speechConvertTextAsync(this->fileId, this->content);
|
||||||
|
});
|
||||||
|
//类似于模态对话框
|
||||||
|
menu->exec(event->globalPos());
|
||||||
|
delete menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageContentLabel::speechConverTextDone(const QString& fileId, const QString& text)
|
||||||
|
{
|
||||||
|
if (this->fileId != fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//修改界面内容
|
||||||
|
this->label->setText("[语音转文字] " + text);
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////
|
||||||
|
/// 创建类表示“图片消息”部分
|
||||||
|
////////////////////////////////////////////
|
||||||
|
MessageImageLabel::MessageImageLabel(const QString& fileId, const QByteArray& content, bool isLeft)
|
||||||
|
:fileId(fileId), content(content), isLeft(isLeft)
|
||||||
|
{
|
||||||
|
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
imageBtn = new QPushButton(this);
|
||||||
|
imageBtn->setStyleSheet("QPushButton { border: none; border-radius: 10px; }");
|
||||||
|
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
//此处,从服务器拿到图片消息
|
||||||
|
//拿着fileId,去服务器获取图片内容
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getSingleFileDone, this, &MessageImageLabel::updateUI);
|
||||||
|
dataCenter->getSingleFileAsync(fileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageImageLabel::updateUI(const QString& fileId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
//由于是一呼百应,要判断fileId是否是当前的fileId
|
||||||
|
if (this->fileId != fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//对上了,就真正显示图片内容
|
||||||
|
this->content = content;
|
||||||
|
|
||||||
|
//进行绘制图片到界面上
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//真正进行绘制图片到界面上
|
||||||
|
void MessageImageLabel::paintEvent(QPaintEvent* event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
QObject* object = this->parent();
|
||||||
|
if (!object->isWidgetType()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QWidget* parent = dynamic_cast<QWidget*>(object);
|
||||||
|
int width = parent->width() * 0.4;
|
||||||
|
|
||||||
|
//加载二进制数据为图片对象
|
||||||
|
QImage image;
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
//说明此时响应的数据还没有回来,
|
||||||
|
//那么先拿默认图片临时代替
|
||||||
|
QByteArray tmpContent = loadFileToByteArray(":resource/image/image.png");
|
||||||
|
image.loadFromData(tmpContent);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
image.loadFromData(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
//针对图片进行缩放
|
||||||
|
int height = 0;
|
||||||
|
if (image.width() > width) {
|
||||||
|
//说明图片过宽,把图片放缩(等比)
|
||||||
|
height = ((double)image.height() / image.width()) * width;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//没有过阈值,不用管
|
||||||
|
width = image.width();
|
||||||
|
height = image.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
//QImage不能直接转换为QIcon,需要QPixmap中转一下
|
||||||
|
QPixmap pixmap = QPixmap::fromImage(image);
|
||||||
|
imageBtn->setFixedSize(width, height);
|
||||||
|
imageBtn->setIconSize(QSize(width, height));
|
||||||
|
imageBtn->setIcon(QIcon(pixmap));
|
||||||
|
|
||||||
|
//为了容纳下上方名字部分,同时留下一点冗余
|
||||||
|
parent->setFixedHeight(height + 50);
|
||||||
|
|
||||||
|
//确定是左侧还是右侧消息
|
||||||
|
if (isLeft) {
|
||||||
|
imageBtn->setGeometry(10, 0, width, height);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int leftPos = this->width() - width - 10;
|
||||||
|
imageBtn->setGeometry(leftPos, 0, width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -56,9 +56,9 @@ public:
|
|||||||
|
|
||||||
//添加工厂函数
|
//添加工厂函数
|
||||||
static QWidget* makeTextMessageItem(bool isLeft, const QString& message);
|
static QWidget* makeTextMessageItem(bool isLeft, const QString& message);
|
||||||
static QWidget* makeImageMessageItem();
|
static QWidget* makeImageMessageItem(bool isLeft, const QString& fileId, const QByteArray& content);
|
||||||
static QWidget* makeFileMessageItem();
|
static QWidget* makeFileMessageItem(bool isLeft, const Message& message);
|
||||||
static QWidget* makeSpeechMessageItem();
|
static QWidget* makeSpeechMessageItem(bool isLeft, const Message& message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isLeft;
|
bool isLeft;
|
||||||
@ -66,16 +66,55 @@ private:
|
|||||||
|
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
/// 创建类表示“文本消息”正文部分
|
/// 创建类表示“文本消息”正文部分
|
||||||
|
//也让这个类表示文件消息
|
||||||
////////////////////////////////////////////
|
////////////////////////////////////////////
|
||||||
class MessageContentLabel : public QWidget {
|
class MessageContentLabel : public QWidget {
|
||||||
public:
|
public:
|
||||||
MessageContentLabel(const QString& text, bool isLeft);
|
MessageContentLabel(const QString& text, bool isLeft, model::MessageType messageType, const QString& fileId,
|
||||||
|
const QByteArray& content);
|
||||||
|
|
||||||
void paintEvent(QPaintEvent* event) override;
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
void updateUI(const QString& fileId, const QByteArray& fileContent);
|
||||||
|
void saveAsFile(const QByteArray& content);
|
||||||
|
|
||||||
|
void playDone();
|
||||||
|
|
||||||
|
void contextMenuEvent(QContextMenuEvent* event) override;
|
||||||
|
void speechConverTextDone(const QString& fileId, const QString& text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel* label;
|
QLabel* label;
|
||||||
bool isLeft;
|
bool isLeft;
|
||||||
|
|
||||||
|
model::MessageType messageType;
|
||||||
|
QString fileId;
|
||||||
|
QByteArray content;
|
||||||
|
QString fileName;
|
||||||
|
|
||||||
|
bool loadContentDone = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////
|
||||||
|
/// 创建类表示“图片消息”部分
|
||||||
|
////////////////////////////////////////////
|
||||||
|
class MessageImageLabel : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MessageImageLabel(const QString& fileId, const QByteArray& content, bool isLeft);
|
||||||
|
|
||||||
|
void updateUI(const QString& fileId, const QByteArray& content);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPushButton* imageBtn;
|
||||||
|
|
||||||
|
QString fileId; //该图片在服务器对应的文件id
|
||||||
|
QByteArray content; //图片的二进制数据
|
||||||
|
bool isLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MESSAGESHOWAREA_H
|
#endif // MESSAGESHOWAREA_H
|
||||||
|
|||||||
@ -170,7 +170,9 @@ void load(const bite_im::MessageInfo& messageInfo) {
|
|||||||
}
|
}
|
||||||
if (messageInfo.message().imageMessage().hasFileId()) {
|
if (messageInfo.message().imageMessage().hasFileId()) {
|
||||||
this->fileId = messageInfo.message().imageMessage().fileId();
|
this->fileId = messageInfo.message().imageMessage().fileId();
|
||||||
}else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
|
}
|
||||||
|
}
|
||||||
|
else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
|
||||||
this->messageType = FILE_TYPE;
|
this->messageType = FILE_TYPE;
|
||||||
if (messageInfo.message().fileMessage().hasFileContents()) {
|
if (messageInfo.message().fileMessage().hasFileContents()) {
|
||||||
this->content = messageInfo.message().fileMessage().fileContents();
|
this->content = messageInfo.message().fileMessage().fileContents();
|
||||||
@ -193,8 +195,6 @@ void load(const bite_im::MessageInfo& messageInfo) {
|
|||||||
// 错误的类型, 啥都不做了, 只是打印一个日志
|
// 错误的类型, 啥都不做了, 只是打印一个日志
|
||||||
LOG() << "非法的消息类型! type=" << type;
|
LOG() << "非法的消息类型! type=" << type;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ public:
|
|||||||
QString userId = ""; //(单聊为对方的id,群聊为"")
|
QString userId = ""; //(单聊为对方的id,群聊为"")
|
||||||
|
|
||||||
|
|
||||||
void load(bite_im::ChatSessionInfo& chatSessionInfo) {
|
void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
|
||||||
this->chatSessionId = chatSessionInfo.chatSessionId();
|
this->chatSessionId = chatSessionInfo.chatSessionId();
|
||||||
this->chatSessionName = chatSessionInfo.chatSessionName();
|
this->chatSessionName = chatSessionInfo.chatSessionName();
|
||||||
if (chatSessionInfo.hasSingleChatFriendId()) {
|
if (chatSessionInfo.hasSingleChatFriendId()) {
|
||||||
|
|||||||
@ -163,6 +163,11 @@ namespace model
|
|||||||
return (*unreadMessageCount)[chatSessionId];
|
return (*unreadMessageCount)[chatSessionId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataCenter::initWebsocket()
|
||||||
|
{
|
||||||
|
netClient.initWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
void DataCenter::getMyselfAsync()
|
void DataCenter::getMyselfAsync()
|
||||||
{
|
{
|
||||||
//DataCenter 只是负责“处理数据”,
|
//DataCenter 只是负责“处理数据”,
|
||||||
@ -294,6 +299,21 @@ namespace model
|
|||||||
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(), "");
|
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::TEXT_TYPE, content.toUtf8(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataCenter::sendImageMessageAsync(const QString& chatSessionId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::IMAGE_TYPE, content, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::sendFileMessageAsync(const QString& chatSessionId, const QString& fileName, const QByteArray& content)
|
||||||
|
{
|
||||||
|
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::FILE_TYPE, content, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::sendSpeechMessageAsync(const QString& chatSessionId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
netClient.sendMessage(loginSessionId, chatSessionId, MessageType::SPEECH_TYPE, content, "");
|
||||||
|
}
|
||||||
|
|
||||||
void DataCenter::changeNicknameAsync(const QString& nickname)
|
void DataCenter::changeNicknameAsync(const QString& nickname)
|
||||||
{
|
{
|
||||||
netClient.changeNickname(loginSessionId, nickname);
|
netClient.changeNickname(loginSessionId, nickname);
|
||||||
@ -350,6 +370,195 @@ namespace model
|
|||||||
myself->phone = email;
|
myself->phone = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataCenter::deleteFriendAsync(const QString& userId)
|
||||||
|
{
|
||||||
|
netClient.deleteFriend(loginSessionId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::removeFriend(const QString& userId)
|
||||||
|
{
|
||||||
|
//遍历friendList 找到要删除的匹配的好友元素
|
||||||
|
if (friendList == nullptr || chatSessionList == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
friendList->removeIf([=](const UserInfo& userInfo) {
|
||||||
|
//说明就是这个
|
||||||
|
return userInfo.userId == userId;
|
||||||
|
});
|
||||||
|
|
||||||
|
//考虑到会话列表
|
||||||
|
//删除会话操作,客户端和服务器都会删除
|
||||||
|
chatSessionList->removeIf([=](const ChatSessionInfo& chatSessionInfo) {
|
||||||
|
if (chatSessionInfo.userId == "") {
|
||||||
|
//群聊,不受影响
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (chatSessionInfo.userId == userId) {
|
||||||
|
//此处如果删除的会话正是用户正在选中的会话,此时就需要把当前选中会话的内容都清空
|
||||||
|
if (chatSessionInfo.chatSessionId == this->currentChatSessionId) {
|
||||||
|
emit this->clearCurrentSession();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::addFriendApplyAsync(const QString& userId)
|
||||||
|
{
|
||||||
|
netClient.addFriendApply(loginSessionId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::acceptFriendApplyAsync(const QString& userId)
|
||||||
|
{
|
||||||
|
netClient.acceptFriendApply(loginSessionId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfo DataCenter::removeFromApplyList(const QString& userId)
|
||||||
|
{
|
||||||
|
if (applyList == nullptr) {
|
||||||
|
return UserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = applyList->begin(); it != applyList->end(); ++it) {
|
||||||
|
if (it->userId == userId) {
|
||||||
|
//复制要删除的对象,进行返回
|
||||||
|
UserInfo toDelete = *it;
|
||||||
|
applyList->erase(it);
|
||||||
|
return toDelete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UserInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::rejectFriendApplyAsync(const QString& userId)
|
||||||
|
{
|
||||||
|
netClient.rejectFriendApply(loginSessionId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::createGroupChatSessionAsync(const QList<QString>& userIdList)
|
||||||
|
{
|
||||||
|
netClient.createGroupChatSession(loginSessionId, userIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::getMemberListAsync(const QString& chatSessionId)
|
||||||
|
{
|
||||||
|
netClient.getMemberList(loginSessionId, chatSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<UserInfo>* DataCenter::getMemberList(const QString& chatSessionId)
|
||||||
|
{
|
||||||
|
if (!this->memberList->contains(chatSessionId)) return nullptr;
|
||||||
|
return &(*this->memberList)[chatSessionId];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::resetMemberList(const QString& chatSessionId, const QList<bite_im::UserInfo>& memberList)
|
||||||
|
{
|
||||||
|
//根据chatSessionId,这个key,得到对应的value(QList)
|
||||||
|
QList<UserInfo>& currentMemberList = (*this->memberList)[chatSessionId];
|
||||||
|
currentMemberList.clear();
|
||||||
|
|
||||||
|
for (const auto& m : memberList) {
|
||||||
|
UserInfo userInfo;
|
||||||
|
userInfo.load(m);
|
||||||
|
currentMemberList.push_back(userInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::searchUserAsync(const QString& searchKey)
|
||||||
|
{
|
||||||
|
netClient.searchUser(loginSessionId, searchKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<UserInfo>* DataCenter::getSearchUserResult()
|
||||||
|
{
|
||||||
|
return searchUserResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::resetSearchUserResult(const QList<bite_im::UserInfo>& userList)
|
||||||
|
{
|
||||||
|
if (searchUserResult == nullptr) {
|
||||||
|
searchUserResult = new QList<UserInfo>();
|
||||||
|
}
|
||||||
|
searchUserResult->clear();
|
||||||
|
|
||||||
|
for (const auto& u : userList) {
|
||||||
|
UserInfo userInfo;
|
||||||
|
userInfo.load(u);
|
||||||
|
searchUserResult->push_back(userInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::searchMessageAsync(const QString& searchKey)
|
||||||
|
{
|
||||||
|
//搜索历史消息,根据会话来组织
|
||||||
|
netClient.searchMessage(loginSessionId, this->currentChatSessionId, searchKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::searchMessageByTimeAsync(const QDateTime& begTime, const QDateTime& endTime)
|
||||||
|
{
|
||||||
|
netClient.searchMessageByTime(loginSessionId, currentChatSessionId, begTime, endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Message>* DataCenter::getSearchMessageReuslt()
|
||||||
|
{
|
||||||
|
return searchMessageResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::resetSearchMessageResult(const QList<bite_im::MessageInfo>& msgList)
|
||||||
|
{
|
||||||
|
if (this->searchMessageResult == nullptr) {
|
||||||
|
this->searchMessageResult = new QList<Message>();
|
||||||
|
}
|
||||||
|
this->searchMessageResult->clear();
|
||||||
|
|
||||||
|
for (const auto& m : msgList) {
|
||||||
|
Message message;
|
||||||
|
message.load(m);
|
||||||
|
searchMessageResult->push_back(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::userLoginAsync(const QString& username, const QString& password)
|
||||||
|
{
|
||||||
|
//登录操作,没有loginSessionId
|
||||||
|
//登录成功之后,服务器才会返回loginSessionId
|
||||||
|
netClient.userLogin(username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::resetLoginSessionId(const QString& loginSessionId)
|
||||||
|
{
|
||||||
|
this->loginSessionId = loginSessionId;
|
||||||
|
|
||||||
|
//一旦会话id更改,就保存到硬盘上
|
||||||
|
saveDataFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::userRegisterAsync(const QString& username, const QString& password)
|
||||||
|
{
|
||||||
|
netClient.userRegister(username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::phoneLoginAsync(const QString& phone, const QString& verifyCode)
|
||||||
|
{
|
||||||
|
netClient.phoneLogin(phone, this->currentVerifyCodeId, verifyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::phoneRegisterAsync(const QString& phone, const QString& verifyCode)
|
||||||
|
{
|
||||||
|
netClient.phoneRegister(phone, this->currentVerifyCodeId, verifyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::getSingleFileAsync(const QString& fileId)
|
||||||
|
{
|
||||||
|
netClient.getSingleFile(loginSessionId, fileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataCenter::speechConvertTextAsync(const QString& fileId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
netClient.speechConvertText(loginSessionId, fileId, content);
|
||||||
|
}
|
||||||
|
|
||||||
void DataCenter::changeAvatarAsync(const QByteArray& imageBytes)
|
void DataCenter::changeAvatarAsync(const QByteArray& imageBytes)
|
||||||
{
|
{
|
||||||
netClient.changeAvatar(loginSessionId, imageBytes);
|
netClient.changeAvatar(loginSessionId, imageBytes);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <qstandardpaths.h>
|
#include <qstandardpaths.h>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
//#include <QList>
|
//#include <QList>
|
||||||
|
|
||||||
#include "data.h"
|
#include "data.h"
|
||||||
@ -104,6 +105,9 @@ namespace model
|
|||||||
//验证网络的连通性
|
//验证网络的连通性
|
||||||
void ping() { netClient.ping(); }
|
void ping() { netClient.ping(); }
|
||||||
|
|
||||||
|
//针对netclient中的websocket进行初始化
|
||||||
|
void initWebsocket();
|
||||||
|
|
||||||
//通过网络获取到用户的个人信息
|
//通过网络获取到用户的个人信息
|
||||||
void getMyselfAsync();
|
void getMyselfAsync();
|
||||||
|
|
||||||
@ -133,6 +137,9 @@ namespace model
|
|||||||
|
|
||||||
//发送消息给服务器
|
//发送消息给服务器
|
||||||
void sendTextMessageAsync(const QString& chatSessionId, const QString& content);
|
void sendTextMessageAsync(const QString& chatSessionId, const QString& content);
|
||||||
|
void sendImageMessageAsync(const QString& chatSessionId, const QByteArray& content);
|
||||||
|
void sendFileMessageAsync(const QString& chatSessionId, const QString& fileName, const QByteArray& content);
|
||||||
|
void sendSpeechMessageAsync(const QString& chatSessionId, const QByteArray& content);
|
||||||
|
|
||||||
//修改用户昵称
|
//修改用户昵称
|
||||||
void changeNicknameAsync(const QString& nickname);
|
void changeNicknameAsync(const QString& nickname);
|
||||||
@ -157,6 +164,50 @@ namespace model
|
|||||||
void changeAvatarAsync(const QByteArray& imageBytes);
|
void changeAvatarAsync(const QByteArray& imageBytes);
|
||||||
void resetAvatar(const QByteArray& avatar);
|
void resetAvatar(const QByteArray& avatar);
|
||||||
|
|
||||||
|
//删除好友
|
||||||
|
void deleteFriendAsync(const QString& userId);
|
||||||
|
void removeFriend(const QString& userId);
|
||||||
|
void addFriendApplyAsync(const QString& userId);
|
||||||
|
|
||||||
|
//发送同意好友申请操作
|
||||||
|
void acceptFriendApplyAsync(const QString& userId);
|
||||||
|
UserInfo removeFromApplyList(const QString& userId);
|
||||||
|
|
||||||
|
//拒绝好友申请操作
|
||||||
|
void rejectFriendApplyAsync(const QString& userId);
|
||||||
|
|
||||||
|
//创建群聊
|
||||||
|
void createGroupChatSessionAsync(const QList<QString>& userIdList);
|
||||||
|
|
||||||
|
//获取会话成员列表
|
||||||
|
void getMemberListAsync(const QString& chatSessionId);
|
||||||
|
QList<UserInfo>* getMemberList(const QString& chatSessionId);
|
||||||
|
void resetMemberList(const QString& chatSessionId, const QList<bite_im::UserInfo>& memberList);
|
||||||
|
|
||||||
|
//搜索用户
|
||||||
|
void searchUserAsync(const QString& searchKey);
|
||||||
|
QList<UserInfo>* getSearchUserResult();
|
||||||
|
void resetSearchUserResult(const QList<bite_im::UserInfo>& userList);
|
||||||
|
|
||||||
|
//搜索历史消息
|
||||||
|
void searchMessageAsync(const QString& searchKey);
|
||||||
|
void searchMessageByTimeAsync(const QDateTime& begTime, const QDateTime& endTime);
|
||||||
|
QList<Message>* getSearchMessageReuslt();
|
||||||
|
void resetSearchMessageResult(const QList<bite_im::MessageInfo>& msgList);
|
||||||
|
|
||||||
|
//登录注册
|
||||||
|
void userLoginAsync(const QString& username, const QString& password);
|
||||||
|
void resetLoginSessionId(const QString& loginSessionId);
|
||||||
|
void userRegisterAsync(const QString& username, const QString& password);
|
||||||
|
void phoneLoginAsync(const QString& phone, const QString& verifyCode);
|
||||||
|
void phoneRegisterAsync(const QString& phone, const QString& verifyCode);
|
||||||
|
|
||||||
|
//获取单个文件
|
||||||
|
void getSingleFileAsync(const QString& fileId);
|
||||||
|
|
||||||
|
//语音转文字
|
||||||
|
void speechConvertTextAsync(const QString& fileId, const QByteArray& content);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
///辅助函数
|
///辅助函数
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -189,8 +240,26 @@ namespace model
|
|||||||
void receiveMessageDone(const Message& lastMessage);
|
void receiveMessageDone(const Message& lastMessage);
|
||||||
void changeNicknameDone();
|
void changeNicknameDone();
|
||||||
void changeDescriptionDone();
|
void changeDescriptionDone();
|
||||||
void getVerifyCodeDone();
|
void getVerifyCodeDone(bool ok);
|
||||||
void changePhoneDone();
|
void changePhoneDone();
|
||||||
void changeAvatarDone();
|
void changeAvatarDone();
|
||||||
|
void deleteFriendDone();
|
||||||
|
void clearCurrentSession();
|
||||||
|
void addFriendApplyDone();
|
||||||
|
void receiveFriendApplyDone();
|
||||||
|
void acceptFriendApplyDone();
|
||||||
|
void rejectFriendApplyDone();
|
||||||
|
void receiveFriendProcessDone(const QString& nickname, bool agree);
|
||||||
|
void createGroupChatSessionDone();
|
||||||
|
void receiveSessionCreateDone();
|
||||||
|
void getMemberListDone(const QString& chatSessionId);
|
||||||
|
void searchUserDone();
|
||||||
|
void searchMessageDone();
|
||||||
|
void userLoginDone(bool ok, const QString& reason);
|
||||||
|
void userRegisterDone(bool ok, const QString& reason);
|
||||||
|
void phoneLoginDone(bool ok, const QString& reason);
|
||||||
|
void phoneRegisterDone(bool ok, const QString& reason);
|
||||||
|
void getSingleFileDone(const QString& fileId, const QByteArray& fileContent);
|
||||||
|
void speechConvertTextDone(const QString& fileId, const QString& text);
|
||||||
};
|
};
|
||||||
} //end namespace model
|
} //end namespace model
|
||||||
|
|||||||
@ -6,7 +6,8 @@ namespace network {
|
|||||||
NetClient::NetClient(model::DataCenter* dataCenter)
|
NetClient::NetClient(model::DataCenter* dataCenter)
|
||||||
:dataCenter(dataCenter)
|
:dataCenter(dataCenter)
|
||||||
{
|
{
|
||||||
initWebSocket();
|
//不应该在此处初始化websocket
|
||||||
|
//initWebSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetClient::ping()
|
void NetClient::ping()
|
||||||
@ -70,16 +71,27 @@ namespace network {
|
|||||||
handleWsMessage(message);
|
handleWsMessage(message);
|
||||||
}
|
}
|
||||||
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY) {
|
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::CHAT_SESSION_CREATE_NOTIFY) {
|
||||||
|
//创建新的会话通知
|
||||||
|
ChatSessionInfo chatSessionInfo;
|
||||||
|
chatSessionInfo.load(notifyMessage.newChatSessionInfo().chatSessionInfo());
|
||||||
|
handleWsSessionCreate(chatSessionInfo);
|
||||||
}
|
}
|
||||||
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY) {
|
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_APPLY_NOTIFY) {
|
||||||
|
//添加好友申请通知
|
||||||
|
UserInfo userInfo;
|
||||||
|
userInfo.load(notifyMessage.friendAddApply().userInfo());
|
||||||
|
handleWsAddfriendApply(userInfo);
|
||||||
}
|
}
|
||||||
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY) {
|
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_ADD_PROCESS_NOTIFY) {
|
||||||
|
//添加好友申请的处理结果通知
|
||||||
|
UserInfo userInfo;
|
||||||
|
userInfo.load(notifyMessage.friendProcessResult().userInfo());
|
||||||
|
bool agree = notifyMessage.friendProcessResult().agree();
|
||||||
|
handleWsAddFriendProcess(userInfo, agree);
|
||||||
}
|
}
|
||||||
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY) {
|
else if (notifyMessage.notifyType() == bite_im::NotifyTypeGadget::NotifyType::FRIEND_REMOVE_NOTIFY) {
|
||||||
|
const QString& userId = notifyMessage.friendRemove().userId();
|
||||||
|
handleWsRemoveFriend(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,6 +111,63 @@ namespace network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetClient::handleWsRemoveFriend(const QString& userId)
|
||||||
|
{
|
||||||
|
//删除数据 DataCenter 好友列表的数据
|
||||||
|
dataCenter->removeFriend(userId);
|
||||||
|
//通知界面变化,更新好友列表/会话列表
|
||||||
|
emit dataCenter->deleteFriendDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::handleWsAddfriendApply(const model::UserInfo& userInfo)
|
||||||
|
{
|
||||||
|
//DataCenter中有一个好友申请列表,需要把这个数据添加到好友申请的列表中
|
||||||
|
QList<UserInfo>* applyList = dataCenter->getApplyList();
|
||||||
|
if (applyList == nullptr) {
|
||||||
|
LOG() << "客户端没有加载到好友申请的列表";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//把新的元素放到列表前面
|
||||||
|
applyList->push_front(userInfo);
|
||||||
|
|
||||||
|
//通知界面进行更新
|
||||||
|
emit dataCenter->receiveFriendApplyDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::handleWsAddFriendProcess(const model::UserInfo& userInfo, bool agree)
|
||||||
|
{
|
||||||
|
if (agree) {
|
||||||
|
//对方同意了你的好友申请
|
||||||
|
QList<UserInfo>* friendList = dataCenter->getFriendList();
|
||||||
|
if (friendList == nullptr) {
|
||||||
|
LOG() << "客户端没有加载好友列表";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
friendList->push_front(userInfo);
|
||||||
|
|
||||||
|
//通知更新一下界面
|
||||||
|
emit dataCenter->receiveFriendProcessDone(userInfo.nickname, agree);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//对方未同意你的好友申请
|
||||||
|
emit dataCenter->receiveFriendProcessDone(userInfo.nickname, agree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::handleWsSessionCreate(const model::ChatSessionInfo& chatSessionInfo)
|
||||||
|
{
|
||||||
|
//把这个ChatSessionInfo添加到会话列表中即可
|
||||||
|
QList<ChatSessionInfo>* chatSessionList = dataCenter->getChatSessionList();
|
||||||
|
if (chatSessionList == nullptr) {
|
||||||
|
LOG() << "客户端没有加载会话列表";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//新的元素添加到列表头部
|
||||||
|
chatSessionList->push_front(chatSessionInfo);
|
||||||
|
//发送一个信号,通知界面更新
|
||||||
|
emit dataCenter->receiveSessionCreateDone();
|
||||||
|
}
|
||||||
|
|
||||||
void NetClient::sendAuth()
|
void NetClient::sendAuth()
|
||||||
{
|
{
|
||||||
bite_im::ClientAuthenticationReq req;
|
bite_im::ClientAuthenticationReq req;
|
||||||
@ -107,7 +176,6 @@ namespace network {
|
|||||||
QByteArray body = req.serialize(&serializer);
|
QByteArray body = req.serialize(&serializer);
|
||||||
websocketClient.sendBinaryMessage(body);
|
websocketClient.sendBinaryMessage(body);
|
||||||
LOG() << "[WS身份认证] requestId= " << req.requestId() << ",loginSessionId= " << req.sessionId();
|
LOG() << "[WS身份认证] requestId= " << req.requestId() << ",loginSessionId= " << req.sessionId();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString NetClient::makeRequestId()
|
QString NetClient::makeRequestId()
|
||||||
@ -525,6 +593,8 @@ namespace network {
|
|||||||
bool ok = false;
|
bool ok = false;
|
||||||
QString reason;
|
QString reason;
|
||||||
auto pbResp = this->handleHttpResponse<bite_im::PhoneVerifyCodeRsp>(resp, &ok, &reason);
|
auto pbResp = this->handleHttpResponse<bite_im::PhoneVerifyCodeRsp>(resp, &ok, &reason);
|
||||||
|
//发送信号给调用者
|
||||||
|
emit dataCenter->getVerifyCodeDone(ok);
|
||||||
//判定响应是否正确
|
//判定响应是否正确
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOG() << "获取验证码->处理出错 reason= " << reason;
|
LOG() << "获取验证码->处理出错 reason= " << reason;
|
||||||
@ -534,9 +604,6 @@ namespace network {
|
|||||||
//把得到的结果写入到DataCenter中
|
//把得到的结果写入到DataCenter中
|
||||||
dataCenter->resetVerifyCodeId(pbResp->verifyCodeId());
|
dataCenter->resetVerifyCodeId(pbResp->verifyCodeId());
|
||||||
|
|
||||||
//发送信号给调用者
|
|
||||||
emit dataCenter->getVerifyCodeDone();
|
|
||||||
|
|
||||||
//打印日志
|
//打印日志
|
||||||
LOG() << "获取验证码->响应处理完毕 requestId= " << pbResp->requestId() << "Id= " << dataCenter->getVerifyCodeId();
|
LOG() << "获取验证码->响应处理完毕 requestId= " << pbResp->requestId() << "Id= " << dataCenter->getVerifyCodeId();
|
||||||
});
|
});
|
||||||
@ -619,4 +686,592 @@ namespace network {
|
|||||||
LOG() << "修改用户头像->响应处理完成 requestId= " << pbResp->requestId();
|
LOG() << "修改用户头像->响应处理完成 requestId= " << pbResp->requestId();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetClient::deleteFriend(const QString& loginSessionId, const QString& userId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::FriendRemoveReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setPeerId(userId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "删除好友->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << pbReq.sessionId()
|
||||||
|
<< ", userId= " << pbReq.peerId();
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/remove_friend", body);
|
||||||
|
|
||||||
|
//处理HTTP响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::FriendRemoveRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "删除好友->处理出错 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//把结果写入到DataCenter中,把该用户从好友列表中删除掉
|
||||||
|
dataCenter->removeFriend(userId);
|
||||||
|
|
||||||
|
//发送信号,通知调用者当前好友删除完毕
|
||||||
|
emit dataCenter->deleteFriendDone();
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "删除好友->响应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::addFriendApply(const QString& loginSessionId, const QString& userId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::FriendAddReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setRespondentId(userId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "添加好友申请->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << pbReq.sessionId()
|
||||||
|
<< ", userId= " << userId;
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/add_friend_apply", body);
|
||||||
|
|
||||||
|
//处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::FriendAddRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "添加好友申请->响应失败 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//记录结果到DataCenter,此处不需要记录任何数据
|
||||||
|
|
||||||
|
//发送信号,通知调用者
|
||||||
|
emit dataCenter->addFriendApplyDone();
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "添加好友申请->响应完毕 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::acceptFriendApply(const QString& loginSessionId, const QString& userId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::FriendAddProcessReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setAgree(true);
|
||||||
|
pbReq.setApplyUserId(userId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "同意好友申请->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << pbReq.sessionId()
|
||||||
|
<< ", userId= " << pbReq.applyUserId();
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/add_friend_process", body);
|
||||||
|
|
||||||
|
//处理HTTP响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::FriendAddRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "同意好友申请->处理出错 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//此处做一个好友列表的更新
|
||||||
|
//把好友从申请列表中删除掉
|
||||||
|
//并将该好友添加到好友列表中
|
||||||
|
UserInfo applyUser = dataCenter->removeFromApplyList(userId);
|
||||||
|
QList<UserInfo>* friendList = dataCenter->getFriendList();
|
||||||
|
friendList->push_front(applyUser);
|
||||||
|
|
||||||
|
//发送信号,通知界面进行更新
|
||||||
|
emit dataCenter->acceptFriendApplyDone();
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "同意好友申请->相应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::rejectFriendApply(const QString& loginSessionId, const QString& userId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::FriendAddProcessReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setAgree(false);
|
||||||
|
pbReq.setApplyUserId(userId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "拒绝好友申请->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << pbReq.sessionId()
|
||||||
|
<< ", userId= " << pbReq.applyUserId();
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/add_friend_process", body);
|
||||||
|
|
||||||
|
//处理HTTP响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::FriendAddRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "拒绝好友申请->处理出错 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//把好友从申请列表中删除掉
|
||||||
|
dataCenter->removeFromApplyList(userId);
|
||||||
|
|
||||||
|
//发送信号,通知界面进行更新
|
||||||
|
emit dataCenter->rejectFriendApplyDone();
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "拒绝好友申请->相应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::createGroupChatSession(const QString& loginSessionId, const QList<QString>& userIdList)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::ChatSessionCreateReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setChatSessionName("新的群聊");
|
||||||
|
pbReq.setMemberIdList(userIdList);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "创建群聊会话->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << loginSessionId
|
||||||
|
<< ", userIdList= " << userIdList;
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/create_chat_session", body);
|
||||||
|
|
||||||
|
//处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::ChatSessionCreateRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判断结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "创建群聊会话->响应失败 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//这里无需更新DataCenter, 后续通过websocket的逻辑来更新即可
|
||||||
|
|
||||||
|
//通知调用者
|
||||||
|
emit dataCenter->createGroupChatSessionDone();
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "创建群聊会话->响应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::getMemberList(const QString& loginSessionId, const QString& chatSessionId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::GetChatSessionMemberReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setChatSessionId(chatSessionId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "获取会话成员列表->发送请求 requestId= " << pbReq.requestId() << ", loginSessionId= " << pbReq.sessionId()
|
||||||
|
<< ", chatSessionId= " << pbReq.chatSessionId();
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/get_chat_session_member", body);
|
||||||
|
|
||||||
|
//处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::GetChatSessionMemberRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "获取会话成员列表->响应失败 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//把结果记录到DataCenter
|
||||||
|
dataCenter->resetMemberList(chatSessionId, pbResp->memberInfoList());
|
||||||
|
|
||||||
|
//发送信号
|
||||||
|
emit dataCenter->getMemberListDone(chatSessionId);
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "获取会话成员列表->响应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::searchUser(const QString& loginSessionId, const QString& searchKey)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::FriendSearchReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setSearchKey(searchKey);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "搜索用户->发送请求 requestId=" << pbReq.requestId() << ", loginSessionId=" << loginSessionId
|
||||||
|
<< ", searchKey=" << searchKey;
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/friend/search_friend", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::FriendSearchRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应成功
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "搜索用户->响应失败 reason=" << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把得到的结果, 记录到 DataCenter
|
||||||
|
dataCenter->resetSearchUserResult(pbResp->userInfo());
|
||||||
|
|
||||||
|
// d) 发送信号, 通知调用者
|
||||||
|
emit dataCenter->searchUserDone();
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "搜索用户->响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::searchMessage(const QString& loginSessionId, const QString& chatSessionId, const QString& searchKey)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::MsgSearchReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setChatSessionId(chatSessionId);
|
||||||
|
pbReq.setSearchKey(searchKey);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "按关键词搜索历史消息->发送请求 requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId()
|
||||||
|
<< ", chatSessionId=" << pbReq.chatSessionId() << ", searchKey=" << searchKey;
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/message_storage/search_history", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::MsgSearchRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "按关键词搜索历史消息->响应失败! reason=" << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把响应结果写入到 DataCenter
|
||||||
|
dataCenter->resetSearchMessageResult(pbResp->msgList());
|
||||||
|
|
||||||
|
// d) 发送信号
|
||||||
|
emit dataCenter->searchMessageDone();
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "按关键词搜索历史消息->响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::searchMessageByTime(const QString& loginSessionId, const QString& chatSessionId, const QDateTime& begTime, const QDateTime& endTime)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::GetHistoryMsgReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setChatSessionId(chatSessionId);
|
||||||
|
pbReq.setStartTime(begTime.toSecsSinceEpoch());
|
||||||
|
pbReq.setOverTime(endTime.toSecsSinceEpoch());
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "按时间搜索历史消息->发送请求 requestId=" << pbReq.requestId() << ", loginSessionId=" << pbReq.sessionId()
|
||||||
|
<< ", chatSessionId=" << pbReq.chatSessionId() << ", begTime= " << begTime << ", endTime= " << endTime;
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/message_storage/get_history", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::GetHistoryMsgRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "按时间搜索历史消息->响应失败! reason=" << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把响应结果写入到 DataCenter
|
||||||
|
dataCenter->resetSearchMessageResult(pbResp->msgList());
|
||||||
|
|
||||||
|
// d) 发送信号
|
||||||
|
emit dataCenter->searchMessageDone();
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "按时间搜索历史消息->响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::userLogin(const QString& username, const QString& password)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::UserLoginReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setNickname(username);
|
||||||
|
pbReq.setPassword(password);
|
||||||
|
pbReq.setVerifyCodeId("");
|
||||||
|
pbReq.setVerifyCode("");
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "用户名登录->发送请求 requestId=" << pbReq.requestId() << ", username=" << pbReq.nickname() << ", password=" << pbReq.password();
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/user/username_login", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应内容
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::UserLoginRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "用户名登录->处理失败 reason=" << reason;
|
||||||
|
emit dataCenter->userLoginDone(false, reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 记录一下当前返回的数据
|
||||||
|
dataCenter->resetLoginSessionId(pbResp->loginSessionId());
|
||||||
|
|
||||||
|
// d) 发送信号, 通知调用者, 处理完毕了.
|
||||||
|
emit dataCenter->userLoginDone(true, "");
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "用户名登录->处理响应 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::userRegister(const QString& username, const QString& password)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::UserRegisterReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setNickname(username);
|
||||||
|
pbReq.setPassword(password);
|
||||||
|
pbReq.setVerifyCodeId("");
|
||||||
|
pbReq.setVerifyCode("");
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "用户名注册->发送请求 requestId=" << pbReq.requestId() << ", username=" << pbReq.nickname() << ", password=" << pbReq.password();
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/user/username_register", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应 body
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::UserRegisterRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "用户名注册->响应失败! reason=" << reason;
|
||||||
|
emit dataCenter->userRegisterDone(false, reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把返回的数据保存到 DataCenter 中
|
||||||
|
// 对于注册来说, 不需要保存任何信息, 直接跳过这个环节.
|
||||||
|
|
||||||
|
// d) 通知调用者响应处理完成
|
||||||
|
emit dataCenter->userRegisterDone(true, "");
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "用户名注册->响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::phoneLogin(const QString& phone, const QString& verifyCodeId, const QString& verifyCode)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::PhoneLoginReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setPhoneNumber(phone);
|
||||||
|
pbReq.setVerifyCodeId(verifyCodeId);
|
||||||
|
pbReq.setVerifyCode(verifyCode);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "手机号登录->发送请求 requestId=" << pbReq.requestId() << ", phone=" << pbReq.phoneNumber()
|
||||||
|
<< ", verifyCodeId=" << pbReq.verifyCodeId() << ", verifyCode=" << pbReq.verifyCode();
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/user/phone_login", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::PhoneLoginRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应是否成功
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "手机号登录->响应出错! reason=" << reason;
|
||||||
|
emit dataCenter->phoneLoginDone(false, reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把响应结果记录到 DataCenter
|
||||||
|
dataCenter->resetLoginSessionId(pbResp->loginSessionId());
|
||||||
|
|
||||||
|
// d) 发送信号
|
||||||
|
emit dataCenter->phoneLoginDone(true, "");
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "手机号登录->响应完毕 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::phoneRegister(const QString& phone, const QString& verifyCodeId, const QString& verifyCode)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::PhoneRegisterReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setPhoneNumber(phone);
|
||||||
|
pbReq.setVerifyCodeId(verifyCodeId);
|
||||||
|
pbReq.setVerifyCode(verifyCode);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "手机号注册->发送请求 requestId=" << pbReq.requestId() << ", phone=" << pbReq.phoneNumber()
|
||||||
|
<< ", verifyCodeId=" << pbReq.verifyCodeId() << ", verifyCode=" << pbReq.verifyCode();
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/user/phone_register", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::PhoneRegisterRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应是否成功
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "手机号注册->响应失败! reason=" << reason;
|
||||||
|
emit dataCenter->phoneRegisterDone(false, reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 让 DataCenter 记录结果, 注册操作不需要记录
|
||||||
|
|
||||||
|
// d) 发送信号
|
||||||
|
emit dataCenter->phoneRegisterDone(true, "");
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "手机号注册->响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::getSingleFile(const QString& loginSessionId, const QString& fileId)
|
||||||
|
{
|
||||||
|
//构造请求body
|
||||||
|
bite_im::GetSingleFileReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setFileId(fileId);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "获取文件内容->发送请求 requestId= " << pbReq.requestId() << ", fileId= " << fileId;
|
||||||
|
|
||||||
|
//发送HTTP请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/file/get_single_file", body);
|
||||||
|
|
||||||
|
//处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
//解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::GetSingleFileRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
//判定响应结果是否正确
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "获取文件内容->响应失败 reason= " << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//这里涉及的文件可能会很多,不使用DataCenter保存
|
||||||
|
//直接通过信号把文件数据,投送到调用者位置
|
||||||
|
|
||||||
|
//发送信号
|
||||||
|
emit dataCenter->getSingleFileDone(fileId, pbResp->fileData().fileContent());
|
||||||
|
|
||||||
|
//打印日志
|
||||||
|
LOG() << "获取文件内容->响应完成 requestId= " << pbResp->requestId();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetClient::speechConvertText(const QString& loginSessionId, const QString& fileId, const QByteArray& content)
|
||||||
|
{
|
||||||
|
// 1. 构造请求 body
|
||||||
|
bite_im::SpeechRecognitionReq pbReq;
|
||||||
|
pbReq.setRequestId(makeRequestId());
|
||||||
|
pbReq.setSessionId(loginSessionId);
|
||||||
|
pbReq.setSpeechContent(content);
|
||||||
|
QByteArray body = pbReq.serialize(&serializer);
|
||||||
|
LOG() << "[语音转文字] 发送请求 requestId=" << pbReq.requestId() << ", loginSessonId=" << pbReq.sessionId();
|
||||||
|
|
||||||
|
// 2. 发送 HTTP 请求
|
||||||
|
QNetworkReply* resp = this->sendHttpRequest("/service/speech/recognition", body);
|
||||||
|
|
||||||
|
// 3. 处理响应
|
||||||
|
connect(resp, &QNetworkReply::finished, this, [=]() {
|
||||||
|
// a) 解析响应
|
||||||
|
bool ok = false;
|
||||||
|
QString reason;
|
||||||
|
auto pbResp = this->handleHttpResponse<bite_im::SpeechRecognitionRsp>(resp, &ok, &reason);
|
||||||
|
|
||||||
|
// b) 判定响应结果
|
||||||
|
if (!ok) {
|
||||||
|
LOG() << "[语音转文字] 响应错误! reason=" << reason;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// c) 把结果写入到 DataCenter 中. 此处不打算通过 DataCenter 表示这里的语音识别结果. 直接通过 信号 通知结果即可.
|
||||||
|
|
||||||
|
// d) 发送信号, 通知调用者
|
||||||
|
emit dataCenter->speechConvertTextDone(fileId, pbResp->recognitionResult());
|
||||||
|
|
||||||
|
// e) 打印日志
|
||||||
|
LOG() << "[语音转文字] 响应完成 requestId=" << pbResp->requestId();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
} //end namespace network
|
} //end namespace network
|
||||||
@ -36,8 +36,13 @@ namespace network {
|
|||||||
//初始化websocket
|
//初始化websocket
|
||||||
void initWebSocket();
|
void initWebSocket();
|
||||||
|
|
||||||
|
//针对websocket的处理
|
||||||
void handleWsResponse(const bite_im::NotifyMessage& notifyMessage);
|
void handleWsResponse(const bite_im::NotifyMessage& notifyMessage);
|
||||||
void handleWsMessage(const model::Message& message);
|
void handleWsMessage(const model::Message& message);
|
||||||
|
void handleWsRemoveFriend(const QString& userId);
|
||||||
|
void handleWsAddfriendApply(const model::UserInfo& userInfo);
|
||||||
|
void handleWsAddFriendProcess(const model::UserInfo& userInfo, bool agree);
|
||||||
|
void handleWsSessionCreate(const model::ChatSessionInfo& chatSessionInfo);
|
||||||
|
|
||||||
//发送身份认证请求
|
//发送身份认证请求
|
||||||
void sendAuth();
|
void sendAuth();
|
||||||
@ -95,6 +100,21 @@ namespace network {
|
|||||||
void getVerifyCode(const QString& email);
|
void getVerifyCode(const QString& email);
|
||||||
void changeEmail(const QString& loginSessionId, const QString& email, const QString& verifyCodeId, const QString& verifyCode);
|
void changeEmail(const QString& loginSessionId, const QString& email, const QString& verifyCodeId, const QString& verifyCode);
|
||||||
void changeAvatar(const QString& loginSessionId, const QByteArray& avatar);
|
void changeAvatar(const QString& loginSessionId, const QByteArray& avatar);
|
||||||
|
void deleteFriend(const QString& loginSessionId, const QString& userId);
|
||||||
|
void addFriendApply(const QString& loginSessionId, const QString& userId);
|
||||||
|
void acceptFriendApply(const QString& loginSessionId, const QString& userId);
|
||||||
|
void rejectFriendApply(const QString& loginSessionId, const QString& userId);
|
||||||
|
void createGroupChatSession(const QString& loginSessionId, const QList<QString>& userIdList);
|
||||||
|
void getMemberList(const QString& loginSessionId, const QString& chatSessionId);
|
||||||
|
void searchUser(const QString& loginSessionId, const QString& searchKey);
|
||||||
|
void searchMessage(const QString& loginSessionId, const QString& chatSessionId, const QString& searchKey);
|
||||||
|
void searchMessageByTime(const QString& loginSessionId, const QString& chatSessionId, const QDateTime& begTime, const QDateTime& endTime);
|
||||||
|
void userLogin(const QString& username, const QString& password);
|
||||||
|
void userRegister(const QString& username, const QString& password);
|
||||||
|
void phoneLogin(const QString& phone, const QString& verifyCodeId, const QString& verifyCode);
|
||||||
|
void phoneRegister(const QString& phone, const QString& verifyCodeId, const QString& verifyCode);
|
||||||
|
void getSingleFile(const QString& loginSessionId, const QString& fileId);
|
||||||
|
void speechConvertText(const QString& loginSessionId, const QString& fileId, const QByteArray& content);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
model::DataCenter* dataCenter;
|
model::DataCenter* dataCenter;
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
#include "phoneloginwidget.h"
|
#include "phoneloginwidget.h"
|
||||||
|
|
||||||
|
#include "mainwidget.h"
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
#include "toast.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
PhoneLoginWidget::PhoneLoginWidget(QWidget *parent)
|
PhoneLoginWidget::PhoneLoginWidget(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
@ -27,7 +33,7 @@ PhoneLoginWidget::PhoneLoginWidget(QWidget *parent)
|
|||||||
// 4. 创建手机号输入框
|
// 4. 创建手机号输入框
|
||||||
QString editStyle = "QLineEdit { border: none; background-color: rgb(240, 240, 240); font-size: 20px; border-radius: 10px; padding-left: 5px;}";
|
QString editStyle = "QLineEdit { border: none; background-color: rgb(240, 240, 240); font-size: 20px; border-radius: 10px; padding-left: 5px;}";
|
||||||
phoneEdit = new QLineEdit();
|
phoneEdit = new QLineEdit();
|
||||||
phoneEdit->setPlaceholderText("输入手机号");
|
phoneEdit->setPlaceholderText("输入邮箱号");
|
||||||
phoneEdit->setFixedHeight(40);
|
phoneEdit->setFixedHeight(40);
|
||||||
phoneEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
phoneEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
phoneEdit->setStyleSheet(editStyle);
|
phoneEdit->setStyleSheet(editStyle);
|
||||||
@ -81,8 +87,151 @@ PhoneLoginWidget::PhoneLoginWidget(QWidget *parent)
|
|||||||
layout->addWidget(switchModeBtn, 4, 4, 1, 1);
|
layout->addWidget(switchModeBtn, 4, 4, 1, 1);
|
||||||
|
|
||||||
// 11. 添加信号槽
|
// 11. 添加信号槽
|
||||||
//connect(switchModeBtn, &QPushButton::clicked, this, &PhoneLoginWidget::switchMode);
|
connect(switchModeBtn, &QPushButton::clicked, this, &PhoneLoginWidget::switchMode);
|
||||||
connect(switchModeBtn, &QPushButton::clicked, this, [=]() {
|
//connect(switchModeBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
// if (isLoginMode) {
|
||||||
|
// //切换到注册模式
|
||||||
|
// this->setWindowTitle("注册");
|
||||||
|
// titleLabel->setText("注册");
|
||||||
|
// submitBtn->setText("注册");
|
||||||
|
// switchModeBtn->setText("登录");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// //切换到登录模式
|
||||||
|
// this->setWindowTitle("登录");
|
||||||
|
// titleLabel->setText("登录");
|
||||||
|
// submitBtn->setText("登录");
|
||||||
|
// switchModeBtn->setText("注册");
|
||||||
|
// }
|
||||||
|
// isLoginMode = !isLoginMode;
|
||||||
|
// });
|
||||||
|
|
||||||
|
connect(userModeBtn, &QPushButton::clicked, this, [=]() {
|
||||||
|
LoginWidget* loginWidget = new LoginWidget(nullptr);
|
||||||
|
loginWidget->show();
|
||||||
|
this->close();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(sendVerifyCodeBtn, &QPushButton::clicked, this, &PhoneLoginWidget::sendVerifyCode);
|
||||||
|
|
||||||
|
timer = new QTimer(this);
|
||||||
|
connect(timer, &QTimer::timeout, this, &PhoneLoginWidget::countDown);
|
||||||
|
|
||||||
|
connect(submitBtn, &QPushButton::clicked, this, &PhoneLoginWidget::clickSubmitBtn);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::sendVerifyCode()
|
||||||
|
{
|
||||||
|
sendVerifyCodeBtn->setEnabled(false);
|
||||||
|
sendVerifyCodeBtn->setStyleSheet("QPushButton { color: rgb(200, 200, 200); }");
|
||||||
|
//获取到手机验证码
|
||||||
|
const QString& phone = this->phoneEdit->text();
|
||||||
|
if (phone.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->currentPhone = phone;
|
||||||
|
|
||||||
|
//发送网络请求,获取验证吗
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
connect(dataCenter, &DataCenter::getVerifyCodeDone, this, &PhoneLoginWidget::sendVerifyCodeDone, Qt::AutoConnection);
|
||||||
|
dataCenter->getVerifyCodeAsync(phone);
|
||||||
|
|
||||||
|
//开启定时器,开始倒计时
|
||||||
|
timer->start(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::sendVerifyCodeDone(bool ok)
|
||||||
|
{
|
||||||
|
if (!ok) {
|
||||||
|
Toast::showMessage("邮箱格式错误");
|
||||||
|
sendVerifyCodeBtn->setEnabled(true);
|
||||||
|
sendVerifyCodeBtn->setText("发送验证码");
|
||||||
|
timer->stop();
|
||||||
|
sendVerifyCodeBtn->setStyleSheet("QPushButton { color: rgb(0, 0, 0); }");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Toast::showMessage("验证码已发送");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::clickSubmitBtn()
|
||||||
|
{
|
||||||
|
//从输入框中拿到必要的内容
|
||||||
|
const QString& phone = phoneEdit->text();
|
||||||
|
const QString& verifyCode = verifyCodeEdit->text();
|
||||||
|
if (phone.isEmpty() || verifyCode.isEmpty()) {
|
||||||
|
Toast::showMessage("电话或验证码不应该为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送请求
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
if (isLoginMode) {
|
||||||
|
//登录
|
||||||
|
connect(dataCenter, &DataCenter::phoneLoginDone, this, &PhoneLoginWidget::phoneLoginDone, Qt::AutoConnection);
|
||||||
|
dataCenter->phoneLoginAsync(phone, verifyCode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//注册
|
||||||
|
connect(dataCenter, &DataCenter::phoneRegisterDone, this, &PhoneLoginWidget::phoneRegisterDone, Qt::UniqueConnection);
|
||||||
|
dataCenter->phoneRegisterAsync(phone, verifyCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::phoneLoginDone(bool ok, const QString& reason)
|
||||||
|
{
|
||||||
|
if (!ok) {
|
||||||
|
Toast::showMessage("登录失败:" + reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//跳转到主窗口
|
||||||
|
MainWidget* mainWidget = MainWidget::getInstance();
|
||||||
|
mainWidget->show();
|
||||||
|
|
||||||
|
//关闭自己
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::phoneRegisterDone(bool ok, const QString& reason)
|
||||||
|
{
|
||||||
|
if (!ok) {
|
||||||
|
Toast::showMessage("注册失败:" + reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Toast::showMessage("注册成功");
|
||||||
|
|
||||||
|
//跳转到登录页面
|
||||||
|
switchMode();
|
||||||
|
|
||||||
|
//清空一下输入框
|
||||||
|
verifyCodeEdit->clear();
|
||||||
|
|
||||||
|
//处理一下倒计时按钮
|
||||||
|
leftTime = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::countDown()
|
||||||
|
{
|
||||||
|
if (leftTime <= 1) {
|
||||||
|
//时间到了,发送按钮设为可用,并停止定时器
|
||||||
|
sendVerifyCodeBtn->setEnabled(true);
|
||||||
|
sendVerifyCodeBtn->setText("发送验证码");
|
||||||
|
timer->stop();
|
||||||
|
sendVerifyCodeBtn->setStyleSheet("QPushButton { color: rgb(0, 0, 0); }");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftTime -= 1;
|
||||||
|
sendVerifyCodeBtn->setText(QString::number(leftTime) + " s");
|
||||||
|
if (sendVerifyCodeBtn->isEnabled()) {
|
||||||
|
sendVerifyCodeBtn->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhoneLoginWidget::switchMode()
|
||||||
|
{
|
||||||
if (isLoginMode) {
|
if (isLoginMode) {
|
||||||
//切换到注册模式
|
//切换到注册模式
|
||||||
this->setWindowTitle("注册");
|
this->setWindowTitle("注册");
|
||||||
@ -98,19 +247,4 @@ PhoneLoginWidget::PhoneLoginWidget(QWidget *parent)
|
|||||||
switchModeBtn->setText("注册");
|
switchModeBtn->setText("注册");
|
||||||
}
|
}
|
||||||
isLoginMode = !isLoginMode;
|
isLoginMode = !isLoginMode;
|
||||||
});
|
|
||||||
|
|
||||||
connect(userModeBtn, &QPushButton::clicked, this, [=]() {
|
|
||||||
LoginWidget* loginWidget = new LoginWidget(nullptr);
|
|
||||||
loginWidget->show();
|
|
||||||
this->close();
|
|
||||||
});
|
|
||||||
|
|
||||||
//connect(sendVerifyCodeBtn, &QPushButton::clicked, this, &PhoneLoginWidget::sendVerifyCode);
|
|
||||||
|
|
||||||
//timer = new QTimer(this);
|
|
||||||
//connect(timer, &QTimer::timeout, this, &PhoneLoginWidget::countDown);
|
|
||||||
|
|
||||||
//connect(submitBtn, &QPushButton::clicked, this, &PhoneLoginWidget::clickSubmitBtn);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -15,15 +15,15 @@ class PhoneLoginWidget : public QWidget
|
|||||||
public:
|
public:
|
||||||
PhoneLoginWidget(QWidget *parent);
|
PhoneLoginWidget(QWidget *parent);
|
||||||
|
|
||||||
//void sendVerifyCode();
|
void sendVerifyCode();
|
||||||
//void sendVerifyCodeDone();
|
void sendVerifyCodeDone(bool ok);
|
||||||
|
|
||||||
//void clickSubmitBtn();
|
void clickSubmitBtn();
|
||||||
//void phoneLoginDone(bool ok, const QString& reason);
|
void phoneLoginDone(bool ok, const QString& reason);
|
||||||
//void phoneRegisterDone(bool ok, const QString& reason);
|
void phoneRegisterDone(bool ok, const QString& reason);
|
||||||
|
|
||||||
//void countDown();
|
void countDown();
|
||||||
//void switchMode();
|
void switchMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLineEdit* phoneEdit;
|
QLineEdit* phoneEdit;
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
#include "sessiondetailwidget.h"
|
#include "sessiondetailwidget.h"
|
||||||
|
|
||||||
|
#include "model/datacenter.h"
|
||||||
|
|
||||||
|
using namespace model;
|
||||||
|
|
||||||
//右上角详情的会话人员列表
|
//右上角详情的会话人员列表
|
||||||
AvatarItem::AvatarItem(const QIcon& avatar, const QString& name)
|
AvatarItem::AvatarItem(const QIcon& avatar, const QString& name)
|
||||||
@ -48,9 +51,9 @@ AvatarItem::AvatarItem(const QIcon& avatar, const QString& name)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionDetailWidget::SessionDetailWidget(QWidget *parent)
|
SessionDetailWidget::SessionDetailWidget(QWidget *parent, const UserInfo& userInfo)
|
||||||
//:userInfo(userInfo),
|
:userInfo(userInfo),
|
||||||
: QDialog(parent)
|
QDialog(parent)
|
||||||
{
|
{
|
||||||
// 1. 设置基本属性
|
// 1. 设置基本属性
|
||||||
this->setWindowTitle("会话详情");
|
this->setWindowTitle("会话详情");
|
||||||
@ -74,8 +77,8 @@ SessionDetailWidget::SessionDetailWidget(QWidget *parent)
|
|||||||
AvatarItem* currentUser = new AvatarItem(QIcon(":/resource/image/defaultAvatar.png"), "张三123456");
|
AvatarItem* currentUser = new AvatarItem(QIcon(":/resource/image/defaultAvatar.png"), "张三123456");
|
||||||
layout->addWidget(currentUser, 0, 1);
|
layout->addWidget(currentUser, 0, 1);
|
||||||
#endif
|
#endif
|
||||||
//AvatarItem* currentUser = new AvatarItem(userInfo.avatar, userInfo.nickname);
|
AvatarItem* currentUser = new AvatarItem(userInfo.avatar, userInfo.nickname);
|
||||||
//layout->addWidget(currentUser, 0, 1);
|
layout->addWidget(currentUser, 0, 1);
|
||||||
|
|
||||||
// 5. 添加 "删除好友" 按钮
|
// 5. 添加 "删除好友" 按钮
|
||||||
deleteFriendBtn = new QPushButton();
|
deleteFriendBtn = new QPushButton();
|
||||||
@ -88,10 +91,36 @@ SessionDetailWidget::SessionDetailWidget(QWidget *parent)
|
|||||||
|
|
||||||
// 6. 添加信号槽, 处理点击 "创建群聊" 按钮
|
// 6. 添加信号槽, 处理点击 "创建群聊" 按钮
|
||||||
connect(createGroupBtn->getAvatar(), &QPushButton::clicked, this, [=]() {
|
connect(createGroupBtn->getAvatar(), &QPushButton::clicked, this, [=]() {
|
||||||
ChooseFriendDialog* chooseFriendDialog = new ChooseFriendDialog(this);
|
ChooseFriendDialog* chooseFriendDialog = new ChooseFriendDialog(this, userInfo.userId);
|
||||||
chooseFriendDialog->exec();
|
chooseFriendDialog->exec();
|
||||||
});
|
});
|
||||||
|
|
||||||
//connect(deleteFriendBtn, &QPushButton::clicked, this, &SessionDetailWidget::clickDeleteFriendBtn);
|
connect(deleteFriendBtn, &QPushButton::clicked, this, &SessionDetailWidget::clickDeleteFriendBtn);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionDetailWidget::clickDeleteFriendBtn() {
|
||||||
|
//弹出一个对话框让用户确认是否真的删除
|
||||||
|
//auto result = QMessageBox::warning(this, "确认删除", "确认删除该好友?", QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle("确认删除");
|
||||||
|
msgBox.setText("确认删除该好友?");
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
//msgBox.setStyleSheet("QPushButton { color: black; background-color: rgb(255, 255, 255); }");
|
||||||
|
msgBox.setStyleSheet("QMessageBox { background-color: white; } "
|
||||||
|
"QLabel { color: black; } "
|
||||||
|
"QPushButton { color: black; background-color: #E0E0E0; }");
|
||||||
|
int result = msgBox.exec();
|
||||||
|
|
||||||
|
if (result != QMessageBox::Ok) {
|
||||||
|
LOG() << "用户取消了好友删除";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送好友删除请求
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->deleteFriendAsync(this->userInfo.userId);
|
||||||
|
|
||||||
|
//关闭当前窗口
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
@ -40,10 +40,12 @@ class SessionDetailWidget : public QDialog
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionDetailWidget(QWidget *parent);
|
SessionDetailWidget(QWidget *parent, const UserInfo& userInfo);
|
||||||
|
|
||||||
|
void clickDeleteFriendBtn();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*UserInfo userInfo;*/
|
UserInfo userInfo;
|
||||||
|
|
||||||
QPushButton* deleteFriendBtn;
|
QPushButton* deleteFriendBtn;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -126,7 +126,7 @@ SessionFriendItem::SessionFriendItem(QWidget* owner, const QIcon& avatar, const
|
|||||||
|
|
||||||
//添加到网格布局
|
//添加到网格布局
|
||||||
layout->addWidget(avatarBtn, 0, 0, 2, 2);
|
layout->addWidget(avatarBtn, 0, 0, 2, 2);
|
||||||
layout->addWidget(nameLabel, 0, 2, 1, 25);
|
layout->addWidget(nameLabel, 0, 2, 1, 20);
|
||||||
layout->addWidget(messageLabel, 1, 2, 1, 25);
|
layout->addWidget(messageLabel, 1, 2, 1, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,16 +390,35 @@ ApplyItem::ApplyItem(QWidget *owner, const QString &userId, const QIcon &avatar,
|
|||||||
|
|
||||||
//创建两个按钮
|
//创建两个按钮
|
||||||
QPushButton* acceptBtn = new QPushButton();
|
QPushButton* acceptBtn = new QPushButton();
|
||||||
acceptBtn->setStyleSheet("QPushButton {color: rgb(0, 0, 0); } ");
|
acceptBtn->setStyleSheet("QPushButton {color: rgb(255, 255, 255); background-color: rgb(7, 193, 96); border: none; border-radius: 5px; } ");
|
||||||
acceptBtn->setText("同意");
|
acceptBtn->setText("同意");
|
||||||
|
acceptBtn->setFixedSize(40, 20);
|
||||||
QPushButton* rejectBtn = new QPushButton();
|
QPushButton* rejectBtn = new QPushButton();
|
||||||
rejectBtn->setStyleSheet("QPushButton {color: rgb(0, 0, 0); } ");
|
rejectBtn->setStyleSheet("QPushButton {color: rgb(250, 81, 81); background-color: rgb(190, 190, 190); border: none; border-radius: 5px; } ");
|
||||||
rejectBtn->setText("拒绝");
|
rejectBtn->setText("拒绝");
|
||||||
|
rejectBtn->setFixedSize(40, 20);
|
||||||
|
|
||||||
//添加到布局管理器中
|
//添加到布局管理器中
|
||||||
layout->addWidget(acceptBtn, 1, 2, 1, 3);
|
layout->addWidget(acceptBtn, 1, 2, 1, 4);
|
||||||
layout->addWidget(rejectBtn, 1, 5, 1, 3);
|
layout->addWidget(rejectBtn, 1, 6, 1, 4);
|
||||||
|
|
||||||
|
//添加信号槽
|
||||||
|
connect(acceptBtn, &QPushButton::clicked, this, &ApplyItem::acceptFriendApply);
|
||||||
|
connect(rejectBtn, &QPushButton::clicked, this, &ApplyItem::rejectFriendApply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyItem::acceptFriendApply()
|
||||||
|
{
|
||||||
|
//发送网络请求,告知服务器,同意了好友的申请
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//看同意了谁的好友申请
|
||||||
|
dataCenter->acceptFriendApplyAsync(this->userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyItem::rejectFriendApply()
|
||||||
|
{
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->rejectFriendApplyAsync(this->userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyItem::active()
|
void ApplyItem::active()
|
||||||
|
|||||||
@ -129,6 +129,9 @@ class ApplyItem : public SessionFriendItem {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ApplyItem(QWidget* owner, const QString& userId, const QIcon& avatar, const QString& name);
|
ApplyItem(QWidget* owner, const QString& userId, const QIcon& avatar, const QString& name);
|
||||||
|
void acceptFriendApply();
|
||||||
|
void rejectFriendApply();
|
||||||
|
|
||||||
void active() override;
|
void active() override;
|
||||||
private:
|
private:
|
||||||
//好友申请Id
|
//好友申请Id
|
||||||
|
|||||||
131
soundrecorder.cpp
Normal file
131
soundrecorder.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#include "soundrecorder.h"
|
||||||
|
#include <QDir>
|
||||||
|
#include <QMediaDevices>
|
||||||
|
|
||||||
|
#include "model/data.h"
|
||||||
|
#include "toast.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
/// 单例模式
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
SoundRecorder* SoundRecorder::instance = nullptr;
|
||||||
|
|
||||||
|
SoundRecorder *SoundRecorder::getInstance()
|
||||||
|
{
|
||||||
|
if (instance == nullptr) {
|
||||||
|
instance = new SoundRecorder();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放参考 https://www.cnblogs.com/tony-yang-flutter/p/16477212.html
|
||||||
|
// 录制参考 https://doc.qt.io/qt-6/qaudiosource.html
|
||||||
|
SoundRecorder::SoundRecorder(QObject *parent)
|
||||||
|
: QObject{parent}
|
||||||
|
{
|
||||||
|
// 1. 创建目录
|
||||||
|
QDir soundRootPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||||
|
soundRootPath.mkdir("sound");
|
||||||
|
|
||||||
|
// 2. 初始化录制模块
|
||||||
|
soundFile.setFileName(RECORD_PATH);
|
||||||
|
|
||||||
|
QAudioFormat inputFormat;
|
||||||
|
inputFormat.setSampleRate(16000);
|
||||||
|
inputFormat.setChannelCount(1);
|
||||||
|
inputFormat.setSampleFormat(QAudioFormat::Int16);
|
||||||
|
|
||||||
|
QAudioDevice info = QMediaDevices::defaultAudioInput();
|
||||||
|
if (!info.isFormatSupported(inputFormat)) {
|
||||||
|
//LOG() << "录制设备, 格式不支持!";
|
||||||
|
LOG() << "指定格式不支持,尝试使用设备的最佳格式进行录音";
|
||||||
|
inputFormat = info.preferredFormat();
|
||||||
|
|
||||||
|
QAudioFormat preferredFormat = inputFormat;
|
||||||
|
// 打印查看详细的格式信息
|
||||||
|
//LOG() << "设备首选格式详情:";
|
||||||
|
//LOG() << " 采样率 (SampleRate):" << preferredFormat.sampleRate() << "Hz";48000hz
|
||||||
|
//LOG() << " 声道数 (ChannelCount):" << preferredFormat.channelCount(); 2
|
||||||
|
//LOG() << " 样本格式 (SampleFormat):" << preferredFormat.sampleFormat(); FLOAT
|
||||||
|
|
||||||
|
// 确保至少是单声道
|
||||||
|
/*if (inputFormat.channelCount() > 1) {
|
||||||
|
inputFormat.setChannelCount(1);
|
||||||
|
}*/
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioSource = new QAudioSource(inputFormat, this);
|
||||||
|
connect(audioSource, &QAudioSource::stateChanged, this, [=](QtAudio::State state) {
|
||||||
|
if (state == QtAudio::StoppedState) {
|
||||||
|
// 录制完毕
|
||||||
|
if (audioSource->error() != QAudio::NoError) {
|
||||||
|
LOG() << audioSource->error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. 初始化播放模块
|
||||||
|
outputDevices = new QMediaDevices(this);
|
||||||
|
outputDevice = outputDevices->defaultAudioOutput();
|
||||||
|
QAudioFormat outputFormat;
|
||||||
|
outputFormat.setSampleRate(16000);
|
||||||
|
outputFormat.setChannelCount(1);
|
||||||
|
outputFormat.setSampleFormat(QAudioFormat::Int16);
|
||||||
|
if (!outputDevice.isFormatSupported(outputFormat)) {
|
||||||
|
//LOG() << "播放设备, 格式不支持";
|
||||||
|
LOG() << "指定格式不支持,尝试使用设备的最佳格式进行播放";
|
||||||
|
outputFormat = outputDevice.preferredFormat();
|
||||||
|
// 确保至少是单声道
|
||||||
|
/*if (outputFormat.channelCount() > 1) {
|
||||||
|
outputFormat.setChannelCount(1);
|
||||||
|
}*/
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
audioSink = new QAudioSink(outputDevice, outputFormat);
|
||||||
|
|
||||||
|
connect(audioSink, &QAudioSink::stateChanged, this, [=](QtAudio::State state) {
|
||||||
|
if (state == QtAudio::IdleState) {
|
||||||
|
LOG() << "IdleState";
|
||||||
|
this->stopPlay();
|
||||||
|
emit this->soundPlayDone();
|
||||||
|
} else if (state == QAudio::ActiveState) {
|
||||||
|
LOG() << "ActiveState";
|
||||||
|
} else if (state == QAudio::StoppedState) {
|
||||||
|
LOG() << "StoppedState";
|
||||||
|
if (audioSink->error() != QtAudio::NoError) {
|
||||||
|
LOG() << audioSink->error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundRecorder::startRecord() {
|
||||||
|
soundFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
|
||||||
|
audioSource->start(&soundFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundRecorder::stopRecord() {
|
||||||
|
audioSource->stop();
|
||||||
|
soundFile.close();
|
||||||
|
emit this->soundRecordDone(RECORD_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundRecorder::startPlay(const QByteArray& content) {
|
||||||
|
if (content.isEmpty()) {
|
||||||
|
Toast::showMessage("数据加载中, 请稍后播放");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 1. 把数据写入到临时文件
|
||||||
|
model::writeByteArrayToFile(PLAY_PATH, content);
|
||||||
|
|
||||||
|
// 2. 播放语音
|
||||||
|
inputFile.setFileName(PLAY_PATH);
|
||||||
|
inputFile.open(QIODevice::ReadOnly);
|
||||||
|
audioSink->start(&inputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundRecorder::stopPlay() {
|
||||||
|
audioSink->stop();
|
||||||
|
inputFile.close();
|
||||||
|
}
|
||||||
59
soundrecorder.h
Normal file
59
soundrecorder.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef SOUNDRECORDER_H
|
||||||
|
#define SOUNDRECORDER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QAudioSource>
|
||||||
|
#include <QAudioSink>
|
||||||
|
#include <QMediaDevices>
|
||||||
|
|
||||||
|
class SoundRecorder : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
const QString RECORD_PATH = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sound/tmpRecord.pcm";
|
||||||
|
const QString PLAY_PATH = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/sound/tmpPlay.pcm";
|
||||||
|
|
||||||
|
public:
|
||||||
|
static SoundRecorder* getInstance();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
/// 录制语音语音
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// 开始录制
|
||||||
|
void startRecord();
|
||||||
|
// 停止录制
|
||||||
|
void stopRecord();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static SoundRecorder* instance;
|
||||||
|
explicit SoundRecorder(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
QFile soundFile;
|
||||||
|
QAudioSource* audioSource;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
/// 播放语音
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
public:
|
||||||
|
// 开始播放
|
||||||
|
void startPlay(const QByteArray& content);
|
||||||
|
// 停止播放
|
||||||
|
void stopPlay();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QAudioSink *audioSink;
|
||||||
|
QMediaDevices *outputDevices;
|
||||||
|
QAudioDevice outputDevice;
|
||||||
|
QFile inputFile;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// 录制完毕后发送这个信号
|
||||||
|
void soundRecordDone(const QString& path);
|
||||||
|
// 播放完毕发送这个信号
|
||||||
|
void soundPlayDone();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SOUNDRECORDER_H
|
||||||
@ -144,4 +144,36 @@ void UserInfoWidget::initSingleSlot()
|
|||||||
//把当前模态窗口关闭
|
//把当前模态窗口关闭
|
||||||
this->close();
|
this->close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(deleteFriendBtn, &QPushButton::clicked, this, &UserInfoWidget::clickDeleteFriendBtn);
|
||||||
|
connect(applyBtn, &QPushButton::clicked, this, &UserInfoWidget::clickApplyBtn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInfoWidget::clickDeleteFriendBtn()
|
||||||
|
{
|
||||||
|
//弹出对话框,让用户确认是否删除好友
|
||||||
|
auto result = QMessageBox::warning(this, "删除好友", "确认要删除好友吗?", QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
if (result != QMessageBox::Ok)
|
||||||
|
{
|
||||||
|
LOG() << "删除好友取消";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送网络请求,实现删除好友功能
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
//由于此处信号的处理,都是由主窗口这里进行的
|
||||||
|
dataCenter->deleteFriendAsync(userInfo.userId);
|
||||||
|
|
||||||
|
//关闭本窗口
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInfoWidget::clickApplyBtn()
|
||||||
|
{
|
||||||
|
//发送好友申请
|
||||||
|
DataCenter* dataCenter = DataCenter::getInstance();
|
||||||
|
dataCenter->addFriendApplyAsync(userInfo.userId);
|
||||||
|
|
||||||
|
//关闭窗口
|
||||||
|
this->close();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,9 @@ public:
|
|||||||
UserInfoWidget(const UserInfo& userInfo, QWidget *parent);
|
UserInfoWidget(const UserInfo& userInfo, QWidget *parent);
|
||||||
void initSingleSlot();
|
void initSingleSlot();
|
||||||
|
|
||||||
|
void clickDeleteFriendBtn();
|
||||||
|
void clickApplyBtn();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
////保存对应的Message对象,暂时先放在这里
|
////保存对应的Message对象,暂时先放在这里
|
||||||
//Message message;
|
//Message message;
|
||||||
|
|||||||
124
verifycodewidget.cpp
Normal file
124
verifycodewidget.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#include "verifycodewidget.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPen>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QChar>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "model/data.h"
|
||||||
|
|
||||||
|
VerifyCodeWidget::VerifyCodeWidget(QWidget *parent)
|
||||||
|
: QWidget(parent),
|
||||||
|
randomGenerator(model::getTime())
|
||||||
|
{
|
||||||
|
verifyCode = generateVerifyCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VerifyCodeWidget::generateVerifyCode()
|
||||||
|
{
|
||||||
|
QString code;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
//每次循环生成一个字符
|
||||||
|
int init = 'A';
|
||||||
|
init += randomGenerator.generate() % 26;
|
||||||
|
code += static_cast<QChar>(init);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyCodeWidget::refreshVerifyCode()
|
||||||
|
{
|
||||||
|
verifyCode = generateVerifyCode();
|
||||||
|
// 通过 update 就可以起到 "刷新界面" , 本身就是触发 paintEvent
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyCodeWidget::checkVerifyCode(const QString& verifyCode)
|
||||||
|
{
|
||||||
|
//此处比较验证码需要忽略大小写
|
||||||
|
return this->verifyCode.compare(verifyCode, Qt::CaseInsensitive) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyCodeWidget::paintEvent(QPaintEvent* event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
const int width = 180;
|
||||||
|
const int height = 80;
|
||||||
|
|
||||||
|
QPainter painter(this);
|
||||||
|
QPen pen;
|
||||||
|
QFont font("楷体", 25, QFont::Bold, true);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
// 画点: 添加随机噪点
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
pen = QPen(QColor(randomGenerator.generate() % 256, randomGenerator.generate() % 256, randomGenerator.generate() % 256));
|
||||||
|
painter.setPen(pen);
|
||||||
|
painter.drawPoint(randomGenerator.generate() % width, randomGenerator.generate() % height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 画线: 添加随机干扰线
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
pen = QPen(QColor(randomGenerator.generate() % 256, randomGenerator.generate() % 256, randomGenerator.generate() % 256));
|
||||||
|
painter.setPen(pen);
|
||||||
|
painter.drawLine(randomGenerator.generate() % width, randomGenerator.generate() % height,
|
||||||
|
randomGenerator.generate() % width, randomGenerator.generate() % height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制验证码
|
||||||
|
for (int i = 0; i < verifyCode.size(); i++)
|
||||||
|
{
|
||||||
|
// 随机字体大小
|
||||||
|
int fontSize = 13 + randomGenerator.generate() % 16; // 20~35
|
||||||
|
QFont font("楷体", fontSize, QFont::Bold, true);
|
||||||
|
painter.setFont(font);
|
||||||
|
|
||||||
|
// 随机旋转角度(-30~30度)
|
||||||
|
int angle = (randomGenerator.generate() % 61) - 30;
|
||||||
|
|
||||||
|
// 随机颜色
|
||||||
|
pen = QPen(QColor(randomGenerator.generate() % 255, randomGenerator.generate() % 255, randomGenerator.generate() % 255));
|
||||||
|
painter.setPen(pen);
|
||||||
|
|
||||||
|
// 保存当前状态
|
||||||
|
painter.save();
|
||||||
|
|
||||||
|
// 计算字符中心点
|
||||||
|
int x = 5 + 22 * i;
|
||||||
|
int y = 10;
|
||||||
|
int w = 30, h = 30;
|
||||||
|
QPoint center(x + w / 2, y + h / 2);
|
||||||
|
|
||||||
|
// 平移到中心,旋转,再平移回去
|
||||||
|
painter.translate(center);
|
||||||
|
painter.rotate(angle);
|
||||||
|
painter.translate(-center);
|
||||||
|
|
||||||
|
// 绘制字符
|
||||||
|
painter.drawText(x, y, w, h, Qt::AlignCenter, QString(verifyCode[i]));
|
||||||
|
|
||||||
|
// 恢复状态
|
||||||
|
painter.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制验证码
|
||||||
|
/*for (int i = 0; i < verifyCode.size(); i++)
|
||||||
|
{
|
||||||
|
pen = QPen(QColor(randomGenerator.generate() % 255, randomGenerator.generate() % 255, randomGenerator.generate() % 255));
|
||||||
|
painter.setPen(pen);
|
||||||
|
painter.drawText(5 + 22 * i, randomGenerator.generate() % 10, 30, 30, Qt::AlignCenter, QString(verifyCode[i]));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerifyCodeWidget::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
this->refreshVerifyCode();
|
||||||
|
}
|
||||||
32
verifycodewidget.h
Normal file
32
verifycodewidget.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
|
class VerifyCodeWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VerifyCodeWidget(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
//通过这个函数生成随机的验证码字符串
|
||||||
|
QString generateVerifyCode();
|
||||||
|
|
||||||
|
//刷新并把当前验证码显示到界面上
|
||||||
|
void refreshVerifyCode();
|
||||||
|
|
||||||
|
//检验验证码是否匹配
|
||||||
|
bool checkVerifyCode(const QString& verifyCode);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//随机数生成器
|
||||||
|
QRandomGenerator randomGenerator;
|
||||||
|
|
||||||
|
//保存验证码的值
|
||||||
|
QString verifyCode = "";
|
||||||
|
signals:
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user