has been completed.

This commit is contained in:
xyz
2025-09-09 15:37:57 +08:00
parent 83f3f4f74e
commit 89ff4fbac0
38 changed files with 2679 additions and 161 deletions

View File

@ -1,9 +1,13 @@
#include "messageshowarea.h"
#include "mainwidget.h"
#include "userinfowidget.h"
#include <QMenu>
#include <qtimer.h>
#include "mainwidget.h"
#include "QFileDialog"
#include "toast.h"
#include "userinfowidget.h"
#include "model/datacenter.h"
#include "soundrecorder.h"
MessageShowArea::MessageShowArea() {
//初始化基本属性
@ -151,13 +155,13 @@ MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
contentWidget = makeTextMessageItem(isLeft, message.content);
break;
case model::IMAGE_TYPE:
contentWidget = makeImageMessageItem();
contentWidget = makeImageMessageItem(isLeft, message.fileId, message.content);
break;
case model::FILE_TYPE:
contentWidget = makeFileMessageItem();
contentWidget = makeFileMessageItem(isLeft, message);
break;
case model::SPEECH_TYPE:
contentWidget = makeSpeechMessageItem();
contentWidget = makeSpeechMessageItem(isLeft, message);
break;
default:
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)
{
MessageContentLabel* messageContentLabel = new MessageContentLabel(text, isLeft);
MessageContentLabel* messageContentLabel = new MessageContentLabel(text, isLeft, TEXT_TYPE, "", QByteArray());
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)
:isLeft(isLeft)
MessageContentLabel::MessageContentLabel(const QString& text, bool isLeft, model::MessageType messageType, const QString& fileId,
const QByteArray& content)
:isLeft(isLeft), messageType(messageType), fileId(fileId), content(content)
{
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->setWordWrap(true);
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的高度以及留一点的冗余的空间
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);
}
}