From e5a390d58e37c284eecf7f27ffbef3515b3a4b39 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 8 Jul 2026 01:04:26 +0400 Subject: [PATCH] Hide community bot chats when community is collapsed --- .../SourceFiles/boxes/peers/community_box.cpp | 6 ++-- Telegram/SourceFiles/data/data_community.cpp | 33 ++++++++++++++----- Telegram/SourceFiles/data/data_community.h | 11 ++++--- Telegram/SourceFiles/data/data_user.cpp | 8 +++++ .../dialogs/dialogs_community_chats_list.cpp | 5 +-- .../dialogs_community_requestable_list.cpp | 6 ++-- .../dialogs/dialogs_inner_widget.cpp | 5 +-- Telegram/SourceFiles/history/history.cpp | 18 +++++----- 8 files changed, 59 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peers/community_box.cpp b/Telegram/SourceFiles/boxes/peers/community_box.cpp index 86c9ee6658..110080a4b9 100644 --- a/Telegram/SourceFiles/boxes/peers/community_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/community_box.cpp @@ -308,10 +308,10 @@ void SetupCommunityContent( ) | rpl::map([=] { auto result = std::vector>(); for (const auto &linked : info->linkedPeers()) { - const auto channel = linked.peer->asChannel(); - if (channel && channel->amIn()) { + if (Data::CommunityChatJoined(linked.peer)) { continue; - } else if (Data::IsCommunityChatViewable(linked)) { + } else if (!linked.peer->isUser() + && Data::IsCommunityChatViewable(linked)) { continue; } result.push_back(linked.peer); diff --git a/Telegram/SourceFiles/data/data_community.cpp b/Telegram/SourceFiles/data/data_community.cpp index e664daa31d..37bff64c0d 100644 --- a/Telegram/SourceFiles/data/data_community.cpp +++ b/Telegram/SourceFiles/data/data_community.cpp @@ -34,8 +34,7 @@ constexpr auto kShowChatNamesCount = 20; auto notInCount = 0; for (const auto &linked : info->linkedPeers()) { - const auto channel = linked.peer->asChannel(); - if (!channel || !channel->amIn()) { + if (!CommunityChatJoined(linked.peer)) { ++notInCount; } } @@ -105,6 +104,25 @@ ChannelId PeerLinkedCommunityId(not_null peer) { return ChannelId(); } +bool CommunityChatJoined(not_null peer) { + if (const auto channel = peer->asChannel()) { + return channel->amIn(); + } else if (peer->isUser()) { + const auto history = peer->owner().historyLoaded(peer); + return history && (history->chatListMessage() != nullptr); + } + return false; +} + +bool CommunityChatJoined(not_null history) { + if (const auto channel = history->peer->asChannel()) { + return channel->amIn(); + } else if (history->peer->isUser()) { + return history->chatListMessage() != nullptr; + } + return false; +} + CommunityInfo::CommunityInfo(not_null channel) : _channel(channel) , _chatsList( @@ -245,8 +263,7 @@ void CommunityInfo::ensureRowInChatList() { } void CommunityInfo::registerOne(not_null history) { - const auto channel = history->peer->asChannel(); - if (channel && channel->amIn()) { + if (CommunityChatJoined(history)) { if (!_histories.emplace(history).second) { return; } @@ -271,10 +288,7 @@ void CommunityInfo::unregisterOne(not_null history) { } void CommunityInfo::refreshOneMembership(not_null history) { - const auto channel = history->peer->asChannel(); - if (channel && channel->amIn()) { - // A non-member linked chat the user just joined moves into the - // member aggregate. + if (CommunityChatJoined(history)) { if (_histories.contains(history) || !_otherHistories.remove(history)) { return; @@ -282,8 +296,8 @@ void CommunityInfo::refreshOneMembership(not_null history) { _histories.emplace(history); memberAdded(history); updateRowSortPosition(); + _linkedPeersChanges.fire({}); } else { - // A member chat the user just left moves out of the aggregate. if (!_histories.remove(history)) { return; } @@ -293,6 +307,7 @@ void CommunityInfo::refreshOneMembership(not_null history) { } reorderLastHistories(); updateRowSortPosition(); + _linkedPeersChanges.fire({}); } } diff --git a/Telegram/SourceFiles/data/data_community.h b/Telegram/SourceFiles/data/data_community.h index 43a7d87c4c..8fdb622b51 100644 --- a/Telegram/SourceFiles/data/data_community.h +++ b/Telegram/SourceFiles/data/data_community.h @@ -28,6 +28,8 @@ struct CommunityLinkedPeer { [[nodiscard]] bool IsCommunityChatViewable(const CommunityLinkedPeer &linked); [[nodiscard]] ChannelId PeerLinkedCommunityId(not_null peer); +[[nodiscard]] bool CommunityChatJoined(not_null peer); +[[nodiscard]] bool CommunityChatJoined(not_null history); class CommunityInfo final { public: @@ -90,10 +92,11 @@ private: rpl::event_stream<> _linkedPeersChanges; rpl::event_stream<> _refreshed; - // Member chats (amIn()) the user is joined to; the source of the - // grouped row's aggregated badge / date / preview. Non-member linked - // chats whose History is loaded are tracked separately in - // _otherHistories so they never leak into those aggregates. + // Member chats (CommunityChatJoined()) — joined channels and bot + // chats with messages; the source of the grouped row's aggregated + // badge / date / preview. Non-member linked chats whose History is + // loaded are tracked separately in _otherHistories so they never + // leak into those aggregates. base::flat_set> _histories; base::flat_set> _otherHistories; std::vector> _lastHistories; diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 2f588630a1..f0def015c7 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -323,7 +323,15 @@ ChannelId UserData::linkedCommunityId() const { } void UserData::setLinkedCommunityId(ChannelId id) { + if (_linkedCommunityId == id) { + return; + } _linkedCommunityId = id; + if (const auto history = owner().historyLoaded(this)) { + history->updateCommunityRegistration(); + history->updateChatListSortPosition(); + history->updateChatListExistence(); + } } UserId UserData::botManagerId() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_community_chats_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_community_chats_list.cpp index 66a7b71bff..8c5d2cc756 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_community_chats_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_community_chats_list.cpp @@ -113,8 +113,9 @@ void CommunityChatsList::rebuild() { } } else { for (const auto &linked : _community->linkedPeers()) { - const auto channel = linked.peer->asChannel(); - if (channel && channel->amIn()) { + if (linked.peer->isUser()) { + continue; + } else if (Data::CommunityChatJoined(linked.peer)) { continue; } else if (!Data::IsCommunityChatViewable(linked)) { continue; diff --git a/Telegram/SourceFiles/dialogs/dialogs_community_requestable_list.cpp b/Telegram/SourceFiles/dialogs/dialogs_community_requestable_list.cpp index 9e0a52f29d..a87de964de 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_community_requestable_list.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_community_requestable_list.cpp @@ -107,10 +107,10 @@ CommunityRequestableList::CommunityRequestableList( ) | rpl::map([=] { auto result = std::vector>(); for (const auto &linked : community->linkedPeers()) { - const auto channel = linked.peer->asChannel(); - if (channel && channel->amIn()) { + if (Data::CommunityChatJoined(linked.peer)) { continue; - } else if (Data::IsCommunityChatViewable(linked)) { + } else if (!linked.peer->isUser() + && Data::IsCommunityChatViewable(linked)) { continue; } result.push_back(linked.peer); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index d43beb124b..1241246dd4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -895,8 +895,9 @@ void InnerWidget::rebuildCommunitySections() { } const auto owner = &session().data(); for (const auto &linked : _openedCommunity->linkedPeers()) { - const auto channel = linked.peer->asChannel(); - if (channel && channel->amIn()) { + if (linked.peer->isUser()) { + continue; + } else if (Data::CommunityChatJoined(linked.peer)) { continue; } const auto history = owner->history(linked.peer); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 73dc265df4..e4cc0cad4d 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2469,10 +2469,7 @@ void History::setFolderPointer(Data::Folder *folder) { } void History::updateCommunityRegistration() { - const auto channel = peer->asChannel(); - const auto communityId = channel - ? channel->linkedCommunityId() - : ChannelId(); + const auto communityId = Data::PeerLinkedCommunityId(peer); const auto info = communityId ? owner().channel(communityId)->ensuredCommunityInfo().get() : nullptr; @@ -2515,11 +2512,7 @@ void History::communityChatsListDateChanged(TimeId wasDate) { } bool History::isLinkedCommunityMember() const { - if (!_communityInfo) { - return false; - } - const auto channel = peer->asChannel(); - return channel && channel->amIn(); + return _communityInfo && Data::CommunityChatJoined(this); } int History::chatListNameVersion() const { @@ -3094,6 +3087,7 @@ void History::setChatListMessage(HistoryItem *item) { if (_chatListMessage && *_chatListMessage == item) { return; } + const auto wasKnown = _chatListMessage.has_value(); const auto was = _chatListMessage.value_or(nullptr); if (item) { if (item->isSponsored()) { @@ -3115,7 +3109,11 @@ void History::setChatListMessage(HistoryItem *item) { if (const auto folder = this->folder()) { folder->oneListMessageChanged(was, item); } - if (isLinkedCommunityMember()) { + if (_communityInfo + && peer->isUser() + && (!wasKnown || ((was != nullptr) != (item != nullptr)))) { + _communityInfo->refreshOneMembership(this); + } else if (isLinkedCommunityMember()) { _communityInfo->oneListMessageChanged(); } if (const auto to = peer->migrateTo()) {