Keep DM device selection and scroll stable during refresh

This commit is contained in:
evgeny committed 2026-11-03 14:17:24 +01:00
1 parent 9e7366d5fc
commit 888fe5f650
3 files changed
+11 -1

No files matched your search

+8 -1
View File
@@ -28,6 +28,7 @@
#include <QSortFilterProxyModel>
#include <QTreeWidget>
#include <QHeaderView>
#include <QScrollBar>
#include <algorithm>
#include <cstring>
#include "../../../lib/platform_compat.h"
@@ -243,7 +244,9 @@ void AccountList::setChannel(const QString& channelId, quint64 dmGeneration) {
if (!dmGeneration && channelId.startsWith("dm:") && m_db && m_db->isOpen())
for (const auto& conv : m_db->getDmConversations())
if (conv.convId == channelId.mid(3) && conv.mode == DM_MODE_GROUPS) { dmGeneration = conv.generation; break; }
if (m_channelId != channelId || m_dmGeneration != dmGeneration) { clearMemberDetail(); m_dmDevices->clear(); }
if (m_channelId != channelId || m_dmGeneration != dmGeneration) {
clearMemberDetail(); m_dmDevices->clear(); m_dmSnapshot.clear();
}
m_channelId = channelId;
m_dmGeneration = channelId.startsWith("dm:") ? dmGeneration : 0;
m_dmDevices->setVisible(m_dmGeneration != 0);
@@ -288,6 +291,8 @@ void AccountList::onDmMembers(const uint8_t* data, int len) {
if (count > DM_TARGET_MAX || len != 11 + cl + count * DM_MEMBER_WIRE_SIZE) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "DM members: invalid count=%d bytes=%d", count, len); return;
}
const QByteArray snapshot(reinterpret_cast<const char*>(data), len);
if (snapshot == m_dmSnapshot) return;
QVector<QPair<int, chat_member_display>> members; QSet<quint64> nodes;
for (int i = 0; i < count; i++) {
const auto* row = data + 11 + cl + i * DM_MEMBER_WIRE_SIZE; chat_member_display member{};
@@ -303,6 +308,7 @@ void AccountList::onDmMembers(const uint8_t* data, int len) {
return a.second.node_id < b.second.node_id;
});
const quint64 selected = m_dmDevices->currentItem() ? m_dmDevices->currentItem()->data(0, Qt::UserRole).toULongLong() : 0;
const int scroll = m_dmDevices->verticalScrollBar()->value();
m_dmDevices->clear(); QTreeWidgetItem* sections[2];
for (int side = 0; side < 2; side++) {
sections[side] = new QTreeWidgetItem(m_dmDevices, {QCoreApplication::translate("ChatGui", side ? "Peer devices" : "My devices")});
@@ -318,6 +324,7 @@ void AccountList::onDmMembers(const uint8_t* data, int len) {
if (member.is_self) { QFont font = row->font(0); font.setBold(true); row->setFont(0, font); }
if (member.node_id == selected) m_dmDevices->setCurrentItem(row);
}
m_dmDevices->verticalScrollBar()->setValue(scroll); m_dmSnapshot = snapshot;
DEBUG_DEBUG(DEBUG_CATEGORY_DM, "DM members: panel updated channel=%s count=%d", qPrintable(channel), count);
}
+1
View File
@@ -126,6 +126,7 @@ private:
QTreeWidget* m_dmDevices; // Два раздела текущего состава GROUPS; не снимок доставки сообщения.
QTimer* m_dmTimer; // Опрос текущего состава/online раз в 2 с только для видимой панели.
quint64 m_dmGeneration = 0; // 0 — обычная панель или DEVICE; ненулевое привязывает запросы к истории.
QByteArray m_dmSnapshot; // Повторный неизменившийся снимок не перестраивает видимые строки.
quint64 m_detailNodeId = 0;
qint64 m_detailLastSeen = 0, m_detailCreated = 0; // Unix seconds, 0=неизвестно
@@ -405,6 +405,8 @@ private slots:
QCOMPARE(tree->topLevelItem(0)->childCount(), 2); QCOMPARE(tree->topLevelItem(1)->childCount(), 1);
QCOMPARE(tree->topLevelItem(0)->child(0)->data(0, Qt::UserRole).toULongLong(), quint64(21));
QCOMPARE(tree->topLevelItem(0)->child(1)->text(1), QString("offline"));
const QString screenshot = qEnvironmentVariable("UTUN_TEST_DM_MEMBERS_SCREENSHOT");
if (!screenshot.isEmpty()) QVERIFY(panel.grab().save(screenshot));
apply(snapshot(6, {}, 0)); QCOMPARE(tree->topLevelItem(0)->childCount(), 2);
apply(snapshot(7, peer + peer, 2)); QCOMPARE(tree->topLevelItem(0)->childCount(), 2);
apply(snapshot(7, peer, 1)); QCOMPARE(tree->topLevelItem(0)->childCount(), 0);