Open a community chats chooser when forwarding.

This commit is contained in:
John Preston
2026-07-17 16:19:08 +04:00
parent afe806b222
commit bc9c413e82
2 changed files with 219 additions and 0 deletions
@@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_stories.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_community.h"
#include "data/data_user.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
@@ -61,6 +62,15 @@ namespace {
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
constexpr auto kSearchPerPage = 50;
[[nodiscard]] Data::CommunityInfo *JoinedCommunityChats(
not_null<PeerData*> peer) {
const auto channel = peer->asChannel();
const auto info = (channel && channel->isCommunity())
? channel->communityInfo()
: nullptr;
return (info && !info->histories().empty()) ? info : nullptr;
}
} // namespace
object_ptr<Ui::BoxContent> PrepareContactsBox(
@@ -957,6 +967,50 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
*weak = owned.data();
delegate()->peerListUiShow()->showBox(std::move(owned));
return;
} else if (const auto community = JoinedCommunityChats(peer)) {
const auto weak = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
auto callback = [=](not_null<Data::Thread*> thread) {
const auto exists = guard.get();
if (!exists) {
if (*weak) {
(*weak)->closeBox();
}
return;
}
auto onstack = std::move(_callback);
onstack(thread);
if (guard) {
_callback = std::move(onstack);
} else if (*weak) {
(*weak)->closeBox();
}
};
const auto filter = [=](not_null<Data::Thread*> thread) {
return guard && (!_filter || _filter(thread));
};
const auto channel = community->channel();
auto owned = Box<PeerListBox>(
std::make_unique<ChooseCommunityChatBoxController>(
community,
std::move(callback),
filter),
[=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
channel->flagsValue(
) | rpl::filter([=](const ChannelData::Flags::Change &update) {
using Flag = ChannelData::Flag;
return (update.diff & Flag::Community)
&& !(update.value & Flag::Community);
}) | rpl::on_next([=] {
box->closeBox();
}, box->lifetime());
});
*weak = owned.data();
delegate()->peerListUiShow()->showBox(std::move(owned));
return;
}
const auto history = peer->owner().history(peer);
auto callback = std::move(_callback);
@@ -1397,6 +1451,144 @@ auto ChooseSublistBoxController::createRow(
return result;
};
ChooseCommunityChatBoxController::ChooseCommunityChatBoxController(
not_null<Data::CommunityInfo*> community,
FnMut<void(not_null<Data::Thread*>)> callback,
Fn<bool(not_null<Data::Thread*>)> filter)
: _community(community)
, _callback(std::move(callback))
, _filter(std::move(filter)) {
setStyleOverrides(&st::chooseTopicList);
_community->linkedPeersValue(
) | rpl::skip(1) | rpl::on_next([=] {
refreshRows();
}, lifetime());
}
Main::Session &ChooseCommunityChatBoxController::session() const {
return _community->channel()->session();
}
void ChooseCommunityChatBoxController::rowClicked(not_null<PeerListRow*> row) {
auto guard = base::make_weak(this);
const auto peer = row->peer();
if (const auto forum = peer->forum()) {
const auto weak = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
auto callback = [=](not_null<Data::Thread*> thread) {
const auto exists = guard.get();
if (!exists) {
if (*weak) {
(*weak)->closeBox();
}
return;
}
auto onstack = std::move(_callback);
onstack(thread);
if (guard) {
_callback = std::move(onstack);
} else if (*weak) {
(*weak)->closeBox();
}
};
const auto filter = [=](not_null<Data::Thread*> thread) {
return guard && (!_filter || _filter(thread));
};
auto owned = Box<PeerListBox>(
std::make_unique<ChooseTopicBoxController>(
forum,
std::move(callback),
filter),
[=](not_null<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [=] {
box->closeBox();
});
forum->destroyed(
) | rpl::on_next([=] {
box->closeBox();
}, box->lifetime());
});
*weak = owned.data();
delegate()->peerListUiShow()->showBox(std::move(owned));
return;
}
auto onstack = base::take(_callback);
onstack(peer->owner().history(peer));
if (guard) {
_callback = std::move(onstack);
}
}
void ChooseCommunityChatBoxController::prepare() {
delegate()->peerListSetTitle(tr::lng_forward_choose());
setSearchNoResultsText(tr::lng_topics_not_found(tr::now));
delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled);
refreshRows(true);
}
void ChooseCommunityChatBoxController::refreshRows(bool initial) {
auto changed = false;
const auto &histories = _community->histories();
const auto owner = &session().data();
for (auto i = 0; i != delegate()->peerListFullRowsCount();) {
const auto row = delegate()->peerListRowAt(i);
const auto history = owner->history(row->peer());
if (histories.contains(history)) {
++i;
} else {
delegate()->peerListRemoveRow(row);
changed = true;
}
}
auto sorted = std::vector<not_null<History*>>(
begin(histories),
end(histories));
ranges::sort(sorted, [](not_null<History*> a, not_null<History*> b) {
const auto aDate = a->chatListTimeId();
const auto bDate = b->chatListTimeId();
return (aDate != bDate)
? (aDate > bDate)
: (a->peer->name() < b->peer->name());
});
for (const auto &history : sorted) {
const auto id = history->peer->id.value;
auto already = delegate()->peerListFindRow(id);
if (initial || !already) {
if (auto created = createRow(history)) {
delegate()->peerListAppendRow(std::move(created));
changed = true;
}
} else if (already->isSearchResult()) {
delegate()->peerListAppendFoundRow(already);
changed = true;
}
}
if (changed) {
delegate()->peerListRefreshRows();
}
}
std::unique_ptr<PeerListRow> ChooseCommunityChatBoxController::createSearchRow(
PeerListRowId id) {
const auto peer = session().data().peer(PeerId(id));
const auto history = peer->owner().historyLoaded(peer);
if (history && _community->histories().contains(history)) {
return createRow(history);
}
return nullptr;
}
auto ChooseCommunityChatBoxController::createRow(not_null<History*> history)
-> std::unique_ptr<PeerListRow> {
if (_filter && !_filter(history)) {
return nullptr;
}
auto result = std::make_unique<PeerListRow>(history->peer);
result->setCustomStatus(QString());
return result;
}
void PaintRestrictionBadge(
Painter &p,
not_null<const style::PeerListItem*> st,