From 445ead109c0e0617c0e2284ac2bea8a496000cd9 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 3 Nov 2026 13:13:09 +0100 Subject: [PATCH] Wire desktop subgroup messaging and the fallback mode choice --- tools/chatgui/src/accountlist.cpp | 48 +++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index 72a012a87..76a78f1bd 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -661,14 +661,31 @@ void AccountList::onMemberContextMenu(const QPoint& pos) { qPrintable(index.data(MemberListModel::DevgroupRole).toString())); if (index.data(GroupedMemberModel::GroupHeaderRole).toBool()) { const QString group = index.data(MemberListModel::DevgroupRole).toString(), channel = m_channelId; - if (!ownGroupNode(group)) return; + const bool own = ownGroupNode(group) != 0; + quint64 target = 0; QString name; + for (int row = 0; row < m_model->rowCount(); ++row) { + const auto item = m_model->index(row); + if (item.data(MemberListModel::DevgroupRole).toString() != group || + (item.data(Qt::UserRole + 3).toInt() & CHAT_MEMBER_FLAG_DELETED)) continue; + const auto member = m_model->member(m_model->nodeIdAt(row)); + if (member && !member->is_self) { target = member->node_id; name = QString::fromUtf8(member->devgroup_name); break; } + } QPointer alive(this); QMenu menu; connect(this, &QObject::destroyed, &menu, &QMenu::close); - auto* rename = menu.addAction(QCoreApplication::translate("ChatGui", "Rename")); - rename->setEnabled(gui_bridge_is_uasync_ready()); - auto* finish = hasPendingDevicePairing() ? menu.addAction(QCoreApplication::translate("ChatGui", "Finish pairing")) : nullptr; + auto* message = !own && target ? menu.addAction(QCoreApplication::translate("ChatGui", "Send message")) : nullptr; + auto* rename = own ? menu.addAction(QCoreApplication::translate("ChatGui", "Rename")) : nullptr; + if (rename) rename->setEnabled(gui_bridge_is_uasync_ready()); + auto* finish = own && hasPendingDevicePairing() ? menu.addAction(QCoreApplication::translate("ChatGui", "Finish pairing")) : nullptr; auto* chosen = menu.exec(view->viewport()->mapToGlobal(pos)); - if (!chosen || !alive || channel != m_channelId || !ownGroupNode(group)) return; + if (!chosen || !alive || channel != m_channelId) return; + if (message && chosen == message) { + const auto current = m_model->member(target); + if (current && !(current->flags & CHAT_MEMBER_FLAG_DELETED) && + QByteArray(reinterpret_cast(current->devgroup), 32).toHex() == group.toLatin1()) + emit pmRequested(channel, target, name, true); + return; + } + if (!ownGroupNode(group)) return; if (chosen == rename) renameGroup(group); else if (finish && chosen == finish) finishDevicePairing(this); return; @@ -723,7 +740,26 @@ void AccountList::onMemberContextMenu(const QPoint& pos) { if (chosen == inviteAction) { emit inviteRequested(channel, nodeId, name); return; } if (chosen == radioCallAction) { emit radioCallRequested(channel, nodeId); return; } if (chosen == filesAction) { emit filesRequested(channel, nodeId); return; } - if (chosen == pmAction) { emit pmRequested(channel, nodeId, name); return; } + if (chosen == pmAction) { + bool ownGroup = false, groups = false; const uint8_t noGroup[32] = {0}; + for (int row = 0; row < m_model->rowCount(); ++row) { + const auto item = m_model->index(row); + if (item.data(Qt::UserRole + 2).toBool() && !item.data(MemberListModel::DevgroupRole).toString().isEmpty() && + !(item.data(Qt::UserRole + 3).toInt() & CHAT_MEMBER_FLAG_DELETED)) ownGroup = true; + } + if (ownGroup && !memcmp(current->devgroup, noGroup, 32)) { + QMessageBox choice(QMessageBox::Question, QCoreApplication::translate("ChatGui", "Send message"), + QCoreApplication::translate("ChatGui", "Choose which devices participate in this conversation."), QMessageBox::Cancel, this); + auto* withGroups = choice.addButton(QCoreApplication::translate("ChatGui", "With device groups"), QMessageBox::AcceptRole); + auto* devices = choice.addButton(QCoreApplication::translate("ChatGui", "Only these devices"), QMessageBox::AcceptRole); + choice.exec(); if (!alive || channel != m_channelId) return; + if (choice.clickedButton() != withGroups && choice.clickedButton() != devices) return; + groups = choice.clickedButton() == withGroups; + const auto latest = m_model->member(nodeId); + if (!latest || latest->is_self || memcmp(latest->devgroup, current->devgroup, 32)) return; + } + emit pmRequested(channel, nodeId, name, groups); return; + } if (chosen == callAction) { emit callRequested(channel, nodeId, name); return; } if (chosen == connectAction) { auto* request = static_cast(u_calloc(1, sizeof(chat_connect_node_req)));