Browse Source

Render locked group attachments and local decrypted media

stream-multiview
evgeny 6 days ago
parent
commit
2b7def369d
  1. 1
      tools/chatgui/src/messagedelegate.h
  2. 74
      tools/chatgui/src/messagelist.cpp
  3. 7
      tools/chatgui/src/messagelist.h

1
tools/chatgui/src/messagedelegate.h

@ -50,6 +50,7 @@ enum MessageDataRole {
MsgRawTimestampRole = Qt::UserRole + 39,
MsgReplyToRole = Qt::UserRole + 40,
MsgHighlightRole = Qt::UserRole + 41,
MsgEncryptedRole = Qt::UserRole + 42,
};
class MessageDelegate : public QStyledItemDelegate {

74
tools/chatgui/src/messagelist.cpp

@ -34,6 +34,11 @@
#include <QMenu>
#include <QFileDialog>
#include <QToolTip>
#include <QTreeWidget>
#include <QHeaderView>
#include <QDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <vector>
#include <algorithm>
#include <memory>
@ -44,6 +49,7 @@ static std::vector<std::unique_ptr<LottieIcon>> s_icons;
extern "C" {
#include "../transport/gui_bridge.h"
#include "chat/chat_core.h"
#include "chat/chat_attachment.h"
#include "chat/chat_poll.h"
#include "dm/dm_core.h"
#include "dm/dm_media.h"
@ -136,7 +142,8 @@ static QString contentTypeFromJson(const QByteArray& data) {
static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
const QString& contentType, const QString& mediaDirBase,
const QString& channelId, const QByteArray& localAttrs) {
const QString& channelId, const QByteArray& localAttrs,
DbManager* db, const QByteArray& messageId) {
QByteArray body = data;
if (body.startsWith('*')) {
int pipePos = body.indexOf('|');
@ -153,6 +160,56 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
item->setData(ct, MsgContentTypeRole);
item->setData(channelId, MsgChannelIdRole);
if (ct == QLatin1String(ENCRYPTED_ATTACHMENT_TYPE)) {
item->setData(true, MsgEncryptedRole);
item->setData(QStringLiteral("application/octet-stream"), MsgContentTypeRole);
item->setData(QCoreApplication::translate("ChatGui", "Encrypted attachment"), MsgFileDisplayNameRole);
item->setData(QString(), MsgVoiceFileRole);
item->setData(0, MsgFileDownloadStateRole);
const auto parts = QString::fromUtf8(body).split('|');
if (parts.size() > 3) { item->setData(parts[1].toLongLong(), MsgFileSizeRole); item->setData(parts[3].toInt(), MsgMediaNumBlocksRole); }
sqlite3_stmt* st = db ? db->prepareOrNull("SELECT a.ready,a.downloaded,a.decrypting,a.error,a.plain_path,a.info,a.content_type,"
"COALESCE(r.state,-1),length(a.key)=32 FROM attachment_keys a LEFT JOIN attachment_key_requests r"
" ON r.channel=a.channel AND r.message_id=a.message_id AND r.incoming=0 WHERE a.channel=? AND a.message_id=?") : nullptr;
if (!st) return;
const QByteArray channel = channelId.toUtf8();
sqlite3_bind_text(st, 1, channel.constData(), -1, SQLITE_STATIC); sqlite3_bind_blob(st, 2, messageId.constData(), messageId.size(), SQLITE_STATIC);
if (sqlite3_step(st) == SQLITE_ROW) {
const bool ready = sqlite3_column_int(st, 0), downloaded = sqlite3_column_int(st, 1), decrypting = sqlite3_column_int(st, 2);
const bool error = sqlite3_column_int(st, 3), key = sqlite3_column_int(st, 8);
const int state = sqlite3_column_int(st, 7);
const QString path = DbManager::colText(st, 4);
struct attachment_info info = {};
const bool available = ready && QFile::exists(path) &&
!attachment_decode((const uint8_t*)sqlite3_column_blob(st, 5), sqlite3_column_bytes(st, 5), &info);
if (available) {
item->setData(DbManager::colText(st, 6), MsgContentTypeRole);
item->setData(QString::fromUtf8(info.name), MsgFileDisplayNameRole);
item->setData(QFileInfo(path).size(), MsgFileSizeRole); item->setData(QFileInfo(path).size(), MsgVoiceFileSizeRole);
item->setData(path, MsgVoiceFileRole); item->setData(2, MsgFileDownloadStateRole);
item->setData(QCoreApplication::translate("ChatGui", "Encrypted"), MsgDeliveryStateRole);
item->setData(QString::number(info.duration_ms / 1000.0, 'f', 1) + "s", MsgVoiceDurationRole);
item->setData(QString::fromLatin1(info.waveform), MsgVoiceWaveformRole);
item->setData(info.duration_ms, MsgVideoDurationMsRole);
item->setData(info.width, MsgVideoWidthRole); item->setData(info.height, MsgVideoHeightRole);
item->setData(info.width, MsgImageWidthRole); item->setData(info.height, MsgImageHeightRole);
} else {
QString status;
if (error) status = QCoreApplication::translate("ChatGui", "Decryption failed; click to retry");
else if (state == 3) status = QCoreApplication::translate("ChatGui", "Access denied by author");
else if (decrypting || (downloaded && key)) status = QCoreApplication::translate("ChatGui", "Decrypting…");
else if (state == 1) status = QCoreApplication::translate("ChatGui", "Awaiting author's approval");
else if (state == 0) status = QCoreApplication::translate("ChatGui", "Sending key request…");
else if (downloaded) status = QCoreApplication::translate("ChatGui", "Requesting decryption…");
else status = QCoreApplication::translate("ChatGui", "Download encrypted attachment");
item->setData(status, MsgDeliveryStateRole);
item->setData(downloaded && !error ? 1 : 0, MsgFileDownloadStateRole);
}
}
sqlite3_finalize(st);
return;
}
if (ct == "audio/opus") {
QString raw = QString::fromUtf8(body);
if (raw.startsWith('{')) return;
@ -379,6 +436,11 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
m_channelTitle->setStyleSheet("font-weight: bold; font-size: 14px;");
m_channelTitle->setText(QCoreApplication::translate("ChatGui", "Channel"));
hl->addWidget(m_channelTitle, 1);
m_keyRequestsButton = new QPushButton(header);
m_keyRequestsButton->setObjectName("attachmentKeyRequestsButton");
m_keyRequestsButton->hide();
connect(m_keyRequestsButton, &QPushButton::clicked, this, &MessageList::showKeyRequests);
hl->addWidget(m_keyRequestsButton);
m_talkingLabel = new QLabel(header);
m_talkingLabel->setStyleSheet("color: #27ae60; font-size: 12px;");
m_talkingLabel->hide();
@ -780,6 +842,8 @@ void MessageList::loadChannel(const QString& channelId) {
m_avatarCache.clear();
if (m_currentChannelId != channelId) { m_feedback.clear(); m_pendingPoll.clear(); }
m_currentChannelId = channelId;
if (!sameChannel && m_keyRequestsDialog) m_keyRequestsDialog->close();
refreshKeyRequests();
clearStreams(); watchStreams();
m_groupMenuButton->setVisible(channelId.toULongLong() != 0);
clearDmCallRoute();
@ -855,7 +919,7 @@ void MessageList::loadChannel(const QString& channelId) {
item->setData(QVariant::fromValue(m.authorNodeId), MsgAuthorNodeIdRole);
item->setData(m.isOutgoing ? 1 : 0, MsgIsOutgoingRole);
setVoiceMessageRoles(item, m.data, m.contentType,
m_db ? m_db->dbPath() + "/media" : QString(), channelId, m.localAttrs);
m_db ? m_db->dbPath() + "/media" : QString(), channelId, m.localAttrs, m_db, m.messageId);
m_model->appendRow(item);
setupFeedback(item, m, channelId);
updateReply(item, m.replyTo);
@ -933,7 +997,7 @@ void MessageList::refresh() {
item->setData(QVariant::fromValue(m.authorNodeId), MsgAuthorNodeIdRole);
item->setData(m.isOutgoing ? 1 : 0, MsgIsOutgoingRole);
setVoiceMessageRoles(item, m.data, m.contentType,
m_db ? m_db->dbPath() + "/media" : QString(), m_currentChannelId, m.localAttrs);
m_db ? m_db->dbPath() + "/media" : QString(), m_currentChannelId, m.localAttrs, m_db, m.messageId);
m_model->appendRow(item);
setupFeedback(item, m, m_currentChannelId);
updateReply(item, m.replyTo);
@ -1127,7 +1191,7 @@ void MessageList::onAttachmentDownloaded(const QString& chId, int64_t msgId) {
QStandardItem* item = m_model->item(row);
setVoiceMessageRoles(item, m.data, m.contentType,
m_db->dbPath() + "/media", chId, m.localAttrs);
m_db->dbPath() + "/media", chId, m.localAttrs, m_db, m.messageId);
item->setData(0, MsgMediaBlocksDoneRole);
item->setData(false, MsgVoiceDownloadPendingRole);
@ -1239,7 +1303,7 @@ void MessageList::onMessageContextMenu(const QPoint& pos) {
QString ct = idx.data(MsgContentTypeRole).toString();
bool isVideo = (ct == "video/mp4");
bool isImage = ct.startsWith("image/");
bool isDmFile = isDmChannel(idx.data(MsgChannelIdRole).toString()) && ct == "application/octet-stream";
bool isDmFile = (isDmChannel(idx.data(MsgChannelIdRole).toString()) || idx.data(MsgEncryptedRole).toBool()) && ct == "application/octet-stream";
bool isDm = isDmChannel(idx.data(MsgChannelIdRole).toString());
QString filePath = idx.data(MsgVoiceFileRole).toString();

7
tools/chatgui/src/messagelist.h

@ -22,6 +22,7 @@ class QPushButton;
class RadioPanel;
class QDialog;
class QMenu;
class QTreeWidget;
struct MessageRow;
class MessageList : public QWidget {
@ -45,6 +46,7 @@ public:
void onFeedbackChanged(const uint8_t* data, int len);
void onFeedbackResult(const uint8_t* data, int len);
void onMessageSubmitted(const uint8_t* data, int len);
void onAttachmentKeysChanged(const uint8_t* data, int len);
void onRadioTalk(quint64 groupId, quint64 srcNodeId, bool on); /* индикация говорящего */
void onStreamSources(const uint8_t* data, int len);
void clearStreams();
@ -85,6 +87,11 @@ private:
QPushButton* m_callBtn = nullptr;
QPushButton* m_inviteBtn = nullptr;
QPushButton* m_groupMenuButton = nullptr;
QPushButton* m_keyRequestsButton = nullptr;
QPointer<QDialog> m_keyRequestsDialog;
QTreeWidget* m_keyRequestsList = nullptr;
void refreshKeyRequests();
void showKeyRequests();
quint64 m_callPeer = 0;
quint64 m_callGroup = 0;
QPushButton* m_radioBtn = nullptr; /* шапка: переключатель рации */

Loading…
Cancel
Save