From 6382c794ea5e2d79463e8215ac8481dfe4f957ec Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 21:27:33 +0100 Subject: [PATCH] Complete desktop PM deletion after the core transaction result --- tools/chatgui/src/mainwindow.cpp | 75 ++++++++++++++++++++++++++++++-- tools/chatgui/src/mainwindow.h | 6 ++- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index 928ec519..7dc9107d 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -236,6 +236,10 @@ MainWindow::~MainWindow() { m_autoPlayTimer->stop(); gui_bridge_set_network_changed_cb(nullptr); gui_bridge_set_dm_call_route_cb(nullptr); + gui_bridge_set_dm_conv_updated_cb(nullptr); + gui_bridge_set_dm_msg_received_cb(nullptr); + gui_bridge_set_dm_messages_cb(nullptr); + gui_bridge_set_dm_delete_result_cb(nullptr); gui_bridge_set_msg_received_cb(nullptr); gui_bridge_set_channel_updated_cb(nullptr); gui_bridge_set_member_list_cb(nullptr); @@ -620,9 +624,15 @@ void MainWindow::setupBridgeCallbacks() { }); /* ── DM (p2p чат) ── */ - gui_bridge_set_dm_conv_updated_cb([](const char* conv_id, int conv_id_len) { + gui_bridge_set_dm_conv_updated_cb([](const char* conv_id, int conv_id_len, uint64_t generation) { if (s_mainWindow) - s_mainWindow->onDmConvUpdated(QString::fromUtf8(conv_id, conv_id_len)); + s_mainWindow->onDmConvUpdated(QString::fromUtf8(conv_id, conv_id_len), generation); + }); + gui_bridge_set_dm_delete_result_cb([](const uint8_t* data, int len) { + if (!s_mainWindow || len != 25) return; + quint64 request, conv, generation; + memcpy(&request, data, 8); memcpy(&conv, data + 8, 8); memcpy(&generation, data + 16, 8); + s_mainWindow->onDmDeleteResult(request, QString::number(conv), generation, data[24] != 0); }); gui_bridge_set_dm_msg_received_cb([](const char* conv_id, int conv_id_len, uint64_t author) { if (s_mainWindow) @@ -631,6 +641,9 @@ void MainWindow::setupBridgeCallbacks() { gui_bridge_set_network_changed_cb([](int type) { if (!s_mainWindow) return; if (type == 13) { + const auto pending = s_mainWindow->m_dmDeleteRequests; + for (auto it = pending.cbegin(); it != pending.cend(); ++it) + s_mainWindow->onDmDeleteResult(it.key(), it.value().first, it.value().second, false); s_mainWindow->m_cpuLoadPending = false; s_mainWindow->m_channelList->setCpuLoad(0); s_mainWindow->m_accountList->setChannel(QString()); @@ -756,6 +769,7 @@ void MainWindow::setupConnects() { connect(m_channelList, &ChannelList::createGroupRequested, this, &MainWindow::onCreateGroupRequested); connect(m_channelList, &ChannelList::settingsRequested, this, &MainWindow::showSettings); connect(m_channelList, &ChannelList::connMonitorRequested, this, &MainWindow::showConnMonitor); + connect(m_channelList, &ChannelList::dmDeleteRequested, this, &MainWindow::onDmDeleteRequested); connect(m_messageList, &MessageList::channelSettingsRequested, this, &MainWindow::showChannelSettings); connect(m_accountList, &AccountList::memberRenamed, m_messageList, &MessageList::reloadLocalNicks); @@ -1045,14 +1059,63 @@ void MainWindow::onPmRequested(const QString& chId, quint64 nodeId, const QStrin /* открытие беседы произойдёт по CHAT_EVT_DM_CONV_UPDATED (onDmConvUpdated) */ } -void MainWindow::onDmConvUpdated(const QString& convId) { - if (!m_channelList) return; +void MainWindow::onDmConvUpdated(const QString& convId, quint64 generation) { + if (!m_channelList || !m_db) return; + bool visible = false; + for (const auto& conv : m_db->getDmConversations()) if (conv.convId == convId && conv.generation == generation) visible = true; + if (!visible) { + GUI_INFO("PM update ignored: hidden/stale conv=%s generation=%llu", qPrintable(convId), (unsigned long long)generation); return; + } QString key = QStringLiteral("dm:") + convId; m_channelList->loadChannels(); + if (m_currentChannelId == key) { m_messageList->loadChannel(key); return; } if (qobject_cast(QApplication::activeModalWidget())) return; m_channelList->selectChannel(key); } +/* Диалог фиксирует поколение строки до вложенного Qt event loop; окончательную проверку выполняет ядро. */ +void MainWindow::onDmDeleteRequested(const QString& convId, quint64 generation, const QString& name) { + for (const auto& pending : m_dmDeleteRequests) if (pending.first == convId) return; + QMessageBox box(QMessageBox::Warning, QCoreApplication::translate("ChatGui", "Delete conversation"), + QCoreApplication::translate("ChatGui", "Delete the conversation with %1 and its local files? The other person keeps their history.") + .arg(name), QMessageBox::NoButton, this); + auto* remove = box.addButton(QCoreApplication::translate("ChatGui", "Delete"), QMessageBox::DestructiveRole); + auto* cancel = box.addButton(QCoreApplication::translate("ChatGui", "Cancel"), QMessageBox::RejectRole); + box.setDefaultButton(cancel); box.setEscapeButton(cancel); box.exec(); + if (box.clickedButton() != remove) return; + const quint64 request = ++m_dmDeleteSequence; + m_dmDeleteRequests.insert(request, {convId, generation}); + m_channelList->setDmDeleting(convId, generation, true); + m_messageList->setDmDeleting(convId, generation, true); + if (gui_bridge_delete_dm(qPrintable(convId), generation, request)) onDmDeleteResult(request, convId, generation, false); +} + +/* Только подтверждённый commit очищает беседу. Старый результат не закрывает PM нового поколения. */ +void MainWindow::onDmDeleteResult(quint64 request, const QString& convId, quint64 generation, bool success) { + auto expected = m_dmDeleteRequests.constFind(request); + if (expected == m_dmDeleteRequests.cend()) { + GUI_INFO("PM delete: ignored obsolete result request=%llu", (unsigned long long)request); return; + } + if (expected->first != convId || expected->second != generation) { + GUI_ERROR("PM delete: result target mismatch request=%llu conv=%s generation=%llu", (unsigned long long)request, + qPrintable(convId), (unsigned long long)generation); return; + } + m_dmDeleteRequests.remove(request); + GUI_INFO("PM delete completed: request=%llu conv=%s generation=%llu success=%d", (unsigned long long)request, + qPrintable(convId), (unsigned long long)generation, success); + if (success && m_messageList->forgetDmHistory(convId, generation)) { + m_currentChannelId.clear(); saveLastChannelId(QString()); m_accountList->setChannel(QString()); + } + m_channelList->setDmDeleting(convId, generation, false); + m_messageList->setDmDeleting(convId, generation, false); + m_channelList->loadChannels(); + if (!success) { + auto* error = new QMessageBox(QMessageBox::Warning, QCoreApplication::translate("ChatGui", "Delete conversation"), + QCoreApplication::translate("ChatGui", "Could not delete the conversation. Please try again."), QMessageBox::Ok, this); + error->setAttribute(Qt::WA_DeleteOnClose); error->open(); + } +} + void MainWindow::onInviteToPmRequested(const QString& source, quint64 peer, const QString& name) { if (!m_db || !m_db->isOpen() || !m_node || !m_node->isRunning()) { GUI_ERROR("invite PM: node unavailable"); @@ -1114,6 +1177,10 @@ void MainWindow::onMessageLinkActivated(const QString& link) { } void MainWindow::onDmMsgReceived(const QString& convId, quint64 author) { + if (!m_db) return; + bool visible = false; + for (const auto& conv : m_db->getDmConversations()) if (conv.convId == convId) visible = true; + if (!visible) { GUI_DEBUG("PM message event ignored: hidden conv=%s", qPrintable(convId)); return; } QString key = QStringLiteral("dm:") + convId; showIncomingMessageNotification(key, author); if (m_currentChannelId == key) { diff --git a/tools/chatgui/src/mainwindow.h b/tools/chatgui/src/mainwindow.h index 8ed4963f..61de3d19 100644 --- a/tools/chatgui/src/mainwindow.h +++ b/tools/chatgui/src/mainwindow.h @@ -93,8 +93,10 @@ public: void onPmRequested(const QString& chId, quint64 nodeId, const QString& name); void onInviteToPmRequested(const QString& source, quint64 peer, const QString& name); void onMessageLinkActivated(const QString& link); - void onDmConvUpdated(const QString& convId); + void onDmConvUpdated(const QString& convId, quint64 generation); void onDmMsgReceived(const QString& convId, quint64 author); + void onDmDeleteRequested(const QString& convId, quint64 generation, const QString& name); + void onDmDeleteResult(quint64 request, const QString& convId, quint64 generation, bool success); private: void setupUi(); @@ -129,6 +131,8 @@ private: QString m_cfgDebugCategories; QString m_pendingChannelSelect; QString m_currentChannelId; + quint64 m_dmDeleteSequence = 0; + QHash> m_dmDeleteRequests; /* request_id → conv_id и удаляемое поколение */ AudioRecorder *m_recorder = nullptr; ConnMonitorWindow *m_connMonitor = nullptr; VideoPlayerWindow *m_videoPlayer = nullptr;