From 77d89b841a44e7afe5ff9330264f045fb7fc833e Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sun, 26 Jul 2026 07:18:27 +0300 Subject: [PATCH] chatgui: double-click member edit, fix delegate backgrounds; transport: invite_sync/member_sync robustness --- tools/chatgui/src/accountdelegate.cpp | 2 ++ tools/chatgui/src/accountlist.cpp | 10 ++++++++++ tools/chatgui/src/accountlist.h | 1 + tools/chatgui/src/channeldelegate.cpp | 2 ++ tools/chatgui/transport/chat_sync.c | 20 +++++++++++++------- tools/chatgui/transport/merkle_sync.c | 9 +++++++-- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/tools/chatgui/src/accountdelegate.cpp b/tools/chatgui/src/accountdelegate.cpp index 7cc03126..81394ecf 100644 --- a/tools/chatgui/src/accountdelegate.cpp +++ b/tools/chatgui/src/accountdelegate.cpp @@ -14,6 +14,8 @@ void AccountDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio painter->fillRect(option.rect, option.palette.highlight()); else if (option.state & QStyle::State_MouseOver) painter->fillRect(option.rect, QColor(240, 240, 240)); + else + painter->fillRect(option.rect, option.palette.base()); const int margin = 4; const int iconSz = 24; diff --git a/tools/chatgui/src/accountlist.cpp b/tools/chatgui/src/accountlist.cpp index f045f907..97584d1a 100644 --- a/tools/chatgui/src/accountlist.cpp +++ b/tools/chatgui/src/accountlist.cpp @@ -73,6 +73,7 @@ AccountList::AccountList(DbManager* db, QWidget *parent) layout->addWidget(m_detailText, 2); connect(m_listView, &QListView::clicked, this, &AccountList::onMemberClicked); + connect(m_listView, &QListView::doubleClicked, this, &AccountList::onMemberDoubleClicked); m_refreshTimer = new QTimer(this); m_refreshTimer->start(2000); @@ -165,6 +166,15 @@ void AccountList::showMemberDetail(quint64 nodeId) { m_detailText->setPlainText(text); } +void AccountList::onMemberDoubleClicked(const QModelIndex& index) { + if (!index.isValid()) return; + quint64 nodeId = m_model->nodeIdAt(index.row()); + if (!nodeId) return; + QString name = m_model->data(index, Qt::DisplayRole).toString(); + MemberPropsDialog dlg(m_db, m_channelId, nodeId, name, this); + dlg.exec(); +} + void AccountList::onMemberContextMenu(const QPoint& pos) { QModelIndex index = m_listView->indexAt(pos); if (!index.isValid()) return; diff --git a/tools/chatgui/src/accountlist.h b/tools/chatgui/src/accountlist.h index 678011fd..aa1bbec2 100644 --- a/tools/chatgui/src/accountlist.h +++ b/tools/chatgui/src/accountlist.h @@ -19,6 +19,7 @@ public: private slots: void onMemberClicked(const QModelIndex& index); + void onMemberDoubleClicked(const QModelIndex& index); void onMemberContextMenu(const QPoint& pos); private: diff --git a/tools/chatgui/src/channeldelegate.cpp b/tools/chatgui/src/channeldelegate.cpp index a4c1a260..b0be4612 100644 --- a/tools/chatgui/src/channeldelegate.cpp +++ b/tools/chatgui/src/channeldelegate.cpp @@ -28,6 +28,8 @@ void ChannelDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio painter->fillRect(option.rect, option.palette.highlight()); } else if (option.state & QStyle::State_MouseOver) { painter->fillRect(option.rect, option.palette.light()); + } else { + painter->fillRect(option.rect, option.palette.base()); } /* ── vertical status bar (left edge, over background) ── */ diff --git a/tools/chatgui/transport/chat_sync.c b/tools/chatgui/transport/chat_sync.c index a9f4241a..7ecb13cb 100644 --- a/tools/chatgui/transport/chat_sync.c +++ b/tools/chatgui/transport/chat_sync.c @@ -369,15 +369,20 @@ struct invite_sync_arg { static void _on_invite_sync_done(uint64_t peer, const char* ns, int result, void* arg) { struct invite_sync_arg* sa = (struct invite_sync_arg*)arg; - DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync %s ns=%s peer=%016llx node=0x%016llx", + DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync %s ns=%s peer=%016llx sa=%p node=0x%016llx ch=%s", CS_ID, result == MT_OK ? "OK" : "FAIL", ns, - (unsigned long long)peer, sa ? (unsigned long long)sa->node_id : 0); + (unsigned long long)peer, (void*)sa, sa ? (unsigned long long)sa->node_id : 0, sa ? sa->ch_id : "(null)"); if (result == MT_OK && sa && g_cs) { - cs_post_channel_online(g_cs, sa->ch_id); - uint8_t one = 1; - merkle_sync_push_update(g_cs->inst, sa->ch_id, sa->node_id, 0x01, &one, 1); - DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync push_update node=0x%016llx online=1 ch=%s", - CS_ID, (unsigned long long)sa->node_id, sa->ch_id); + if (sa->node_id == 0 || sa->ch_id[0] == '\0') { + DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync CORRUPTED sa=%p node_id=0x%016llx ch_id='%s' — skip, will free", + CS_ID, (void*)sa, (unsigned long long)sa->node_id, sa->ch_id); + } else { + cs_post_channel_online(g_cs, sa->ch_id); + uint8_t one = 1; + merkle_sync_push_update(g_cs->inst, sa->ch_id, sa->node_id, 0x01, &one, 1); + DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: invite_sync push_update node=0x%016llx online=1 ch=%s", + CS_ID, (unsigned long long)sa->node_id, sa->ch_id); + } } u_free(sa); } @@ -1126,6 +1131,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer, struct invite_sync_arg* sa = u_malloc(sizeof(struct invite_sync_arg)); if (sa) { sa->node_id = node_id; strncpy(sa->ch_id, ch_id, sizeof(sa->ch_id) - 1); sa->ch_id[sizeof(sa->ch_id) - 1] = '\0'; + DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN alloc sa=%p node=0x%016llx ch=%s", CS_ID, (void*)sa, (unsigned long long)sa->node_id, sa->ch_id); member_sync_start(cs->inst, node_id, ch_id, _on_invite_sync_done, sa); } else member_sync_start(cs->inst, node_id, ch_id, NULL, NULL); DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN starting member_sync with joiner node=0x%016llx ch=%s done_cb=%s", diff --git a/tools/chatgui/transport/merkle_sync.c b/tools/chatgui/transport/merkle_sync.c index dfa9de1b..58e4673d 100644 --- a/tools/chatgui/transport/merkle_sync.c +++ b/tools/chatgui/transport/merkle_sync.c @@ -332,10 +332,13 @@ static struct ms_session* _session_find(struct merkle_sync* ms, uint64_t peer, c } static void _session_done(struct ms_session* s, int result) { + if (!s->active && s->synced) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: session ALREADY DONE peer=%016llx ns=%s — SKIP second call", MS_ID, (unsigned long long)s->peer, s->ns); return; } s->active = 0; + merkle_sync_done_cb cb = s->done_cb; void* arg = s->cb_arg; + s->done_cb = NULL; s->cb_arg = NULL; if (result == MT_OK) { s->synced = 1; DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: session SYNCED peer=%016llx ns=%s", MS_ID, (unsigned long long)s->peer, s->ns); } else { s->synced = 0; DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: session FAILED peer=%016llx ns=%s result=%d", MS_ID, (unsigned long long)s->peer, s->ns, result); } - if (s->done_cb) s->done_cb(s->peer, s->ns, result, s->cb_arg); + if (cb) cb(s->peer, s->ns, result, arg); } /* ── Recv handlers ── */ @@ -698,8 +701,10 @@ int merkle_sync_start(struct UTUN_INSTANCE* inst, uint64_t peer, s->next = ms->sessions; ms->sessions = s; } else { - /* replace callback if session already exists */ s->synced = 0; + DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: start OVERWRITE peer=%016llx ns=%s old_cb=%p old_arg=%p → new_cb=%p new_arg=%p", + MS_ID, (unsigned long long)peer, ns, + (void*)s->done_cb, s->cb_arg, (void*)done_cb, arg); } s->active = 1; s->done_cb = done_cb; s->cb_arg = arg;