Wire desktop context-menu editing and update visible messages in place

This commit is contained in:
evgeny committed 2026-10-26 22:38:42 +01:00
1 parent 2a9b5748e9
commit 1afb1010cc
2 files changed
+50 -4

No files matched your search

+2 -4
View File
@@ -460,8 +460,7 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
QFont font = option.font; font.setPointSize(qMax(1, font.pointSize() - 1));
QFont timeFont = option.font; timeFont.setPointSize(qMax(1, timeFont.pointSize() - 2));
const int height = qMax(24, QFontMetrics(font).height() + 6), left = layout.bubbleRect.left() + kPadH;
layout.reactionTimeText = index.data(MsgEditedRole).toBool() ? QCoreApplication::translate("ChatGui", "edited ") : QString();
layout.reactionTimeText += index.data(MsgTimeRole).toString();
layout.reactionTimeText = index.data(MsgTimeRole).toString();
const int innerWidth = layout.bubbleRect.width() - 2 * kPadH;
const int timeWidth = qMin(QFontMetrics(timeFont).horizontalAdvance(layout.reactionTimeText) + 2, qMax(0, innerWidth - height - 6));
const int reactionsRight = layout.bubbleRect.right() - kPadH - timeWidth - 6;
@@ -1683,8 +1682,7 @@ void MessageDelegate::drawStatusBar(QPainter* p, const Layout& layout, const QMo
p->save();
QFont font = option.font; font.setPointSize(qMax(1, font.pointSize() - 2)); p->setFont(font);
p->setPen(QColor(128, 128, 128));
QString text = index.data(MsgEditedRole).toBool() ? QCoreApplication::translate("ChatGui", "edited ") : QString();
text += index.data(MsgTimeRole).toString();
QString text = index.data(MsgTimeRole).toString();
p->drawText(layout.statusRect, Qt::AlignRight | Qt::AlignVCenter, text);
p->restore();
}
+48
View File
@@ -683,6 +683,21 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
m_inputBar->focusProxy()->installEventFilter(m_view);
window()->installEventFilter(m_view);
connect(m_inputBar, &InputBar::saveEdit, this,
[this](const QString& channel, const QByteArray& id, quint64 version, const QString& text, quint64 request) {
const auto bytes = text.toUtf8();
if (!gui_bridge_get_inst() || !gui_bridge_is_uasync_ready() || channel != m_currentChannelId ||
isDmChannel(channel) || id.size() != 32) {
GUI_ERROR("edit: unavailable target=%s", qPrintable(channel)); m_inputBar->submissionResult(request, false); return;
}
auto* req = (struct chat_msg_submit*)u_calloc(1, sizeof(struct chat_msg_submit) + bytes.size());
if (!req) { GUI_ERROR("edit: allocation failed"); m_inputBar->submissionResult(request, false); return; }
req->inst = gui_bridge_get_inst(); req->request_id = request; req->expected_ver = version;
snprintf(req->channel_id, sizeof(req->channel_id), "%s", channel.toUtf8().constData());
memcpy(req->message_id, id.constData(), 32); req->data = (uint8_t*)(req + 1); req->data_len = bytes.size();
memcpy(req->data, bytes.constData(), bytes.size());
gui_bridge_post_uasync_fn(chat_core_submit_trampoline, req);
});
connect(m_inputBar, &InputBar::sendMessage, this, [this](const QString &text, const QByteArray& reply, quint64 request) {
if (!gui_bridge_get_inst() || !gui_bridge_is_uasync_ready()) {
GUI_ERROR("send: core unavailable"); m_inputBar->submissionResult(request, false); return;
@@ -1356,6 +1371,30 @@ void MessageList::onMessageSubmitted(const uint8_t* data, int len) {
m_inputBar->submissionResult(request, data[8] != 0);
}
/* Меняем существующий item даже в окне старой цитаты, сохраняя позицию прокрутки. */
void MessageList::onMessageUpdated(const uint8_t* data, int len) {
if (!data || len < 34 || len != 1 + data[0] + 32) { GUI_ERROR("edit: invalid event bytes=%d", len); return; }
const QString channel = QString::fromUtf8((const char*)data + 1, data[0]);
if (channel != m_currentChannelId || !m_db) return;
const QByteArray id((const char*)data + 1 + data[0], 32);
const auto message = m_db->getMessageByKey(channel, id);
if (message.messageId.isEmpty()) { GUI_WARN("edit: updated message disappeared ch=%s", qPrintable(channel)); return; }
auto* sb = m_view->verticalScrollBar(); const bool atBottom = sb->value() == sb->maximum();
const QPersistentModelIndex top(m_view->indexAt(QPoint(1, 1))); const int offset = m_view->visualRect(top).top();
for (int row = 0; row < m_model->rowCount(); ++row) {
auto* item = m_model->item(row);
if (item->data(MsgMessageKeyRole).toString() != QString::fromLatin1(id.toHex())) continue;
if (item->data(MsgVersionRole).toULongLong() >= message.version) break;
item->setData(QString::fromUtf8(message.data), MsgTextRole);
setupFeedback(item, message, channel); updateReply(item, message.replyTo); break;
}
refreshReplies(); m_view->doItemsLayout();
if (atBottom) m_view->scrollToBottom();
else if (top.isValid()) { m_view->scrollTo(top, QAbstractItemView::PositionAtTop); sb->setValue(sb->value() - offset); }
GUI_DEBUG("edit: row refreshed ch=%s id=%s ver=%llu", qPrintable(channel), id.toHex().constData(),
(unsigned long long)message.version);
}
void MessageList::onMessageContextMenu(const QPoint& pos) {
QModelIndex idx = m_view->indexAt(pos);
if (!idx.isValid()) return;
@@ -1374,6 +1413,15 @@ void MessageList::onMessageContextMenu(const QPoint& pos) {
QString messageId = idx.data(MsgMessageKeyRole).toString();
if (!isDm && messageId.size() == 64) {
const QString channel = idx.data(MsgChannelIdRole).toString();
if (idx.data(MsgIsOutgoingRole).toBool() && (ct == "text" || ct == "text/plain")) {
connect(menu.addAction(QCoreApplication::translate("ChatGui", "Edit message")), &QAction::triggered, this,
[this, channel, messageId] {
if (channel != m_currentChannelId || !m_db) return;
const auto message = m_db->getMessageByKey(channel, QByteArray::fromHex(messageId.toLatin1()));
if (message.isOutgoing && message.messageId.size() == 32)
m_inputBar->editMessage(message.messageId, message.version, QString::fromUtf8(message.data));
});
}
connect(menu.addAction(QCoreApplication::translate("ChatGui", "Reply")), &QAction::triggered, this, [this, channel, messageId]() {
if (channel != m_currentChannelId || !m_db) return;
const auto original = m_db->getMessageByKey(channel, QByteArray::fromHex(messageId.toLatin1()));