mirror of
https://gitee.com/Zhaoxin59/my-chat_-client.git
synced 2026-02-14 00:51:48 +08:00
has been completed.
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user