Show admins in participants_hidden group info.

This commit is contained in:
John Preston 2022-12-23 17:13:32 +04:00
parent d6c188d642
commit ce40ecc7f9
17 changed files with 154 additions and 91 deletions

View File

@ -365,6 +365,7 @@ void ChatParticipants::requestForAdd(
void ChatParticipants::requestLast(not_null<ChannelData*> channel) {
if (!channel->isMegagroup()
|| !channel->canViewMembers()
|| _participantsRequests.contains(channel)) {
return;
}
@ -532,6 +533,7 @@ ChatParticipants::Parsed ChatParticipants::ParseRecent(
const TLMembers &data) {
const auto result = Parse(channel, data);
const auto applyLast = channel->isMegagroup()
&& channel->canViewMembers()
&& (channel->mgInfo->lastParticipants.size() <= result.list.size());
if (applyLast) {
ApplyLastList(channel, result.availableCount, result.list);

View File

@ -1513,7 +1513,8 @@ void Updates::feedUpdate(const MTPUpdate &update) {
// Request last active supergroup participants if the 'from' user was not loaded yet.
// This will optimize similar getDifference() calls for almost all next messages.
if (isDataLoaded == DataIsLoadedResult::FromNotLoaded && channel && channel->isMegagroup()) {
if (channel->mgInfo->lastParticipants.size() < _session->serverConfig().chatSizeMax
if (channel->canViewMembers()
&& channel->mgInfo->lastParticipants.size() < _session->serverConfig().chatSizeMax
&& (channel->mgInfo->lastParticipants.empty()
|| channel->mgInfo->lastParticipants.size() < channel->membersCount())) {
session().api().chatParticipants().requestLast(channel);

View File

@ -363,10 +363,6 @@ void PeerListController::peerListSearchRefreshRows() {
delegate()->peerListRefreshRows();
}
rpl::producer<int> PeerListController::onlineCountValue() const {
return rpl::single(0);
}
void PeerListController::setDescriptionText(const QString &text) {
if (text.isEmpty()) {
setDescription(nullptr);

View File

@ -529,8 +529,6 @@ public:
Unexpected("PeerListController::customRowRippleMaskGenerator.");
}
[[nodiscard]] virtual rpl::producer<int> onlineCountValue() const;
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}

View File

@ -46,7 +46,7 @@ base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
if (const auto chat = peer->asChat()) {
return chat->participants;
} else if (const auto channel = peer->asChannel()) {
if (channel->isMegagroup()) {
if (channel->isMegagroup() && channel->canViewMembers()) {
const auto &participants = channel->mgInfo->lastParticipants;
return { participants.cbegin(), participants.cend() };
}
@ -140,6 +140,7 @@ bool AddParticipantsBoxController::isAlreadyIn(
} else if (const auto channel = _peer->asChannel()) {
return _alreadyIn.contains(user)
|| (channel->isMegagroup()
&& channel->canViewMembers()
&& base::contains(channel->mgInfo->lastParticipants, user));
}
Unexpected("User in AddParticipantsBoxController::isAlreadyIn");

View File

@ -501,7 +501,7 @@ void ParticipantsAdditionalData::fillFromChat(not_null<ChatData*> chat) {
void ParticipantsAdditionalData::fillFromChannel(
not_null<ChannelData*> channel) {
const auto information = channel->mgInfo.get();
if (!information) {
if (!information || !channel->canViewMembers()) {
return;
}
if (information->creator) {
@ -901,7 +901,7 @@ void ParticipantsBoxController::setupListChangeViewers() {
});
} else if (auto row = createRow(user)) {
delegate()->peerListPrependRow(std::move(row));
delegate()->peerListRefreshRows();
refreshRows();
if (_onlineSorter) {
_onlineSorter->sort();
}
@ -914,7 +914,7 @@ void ParticipantsBoxController::setupListChangeViewers() {
if (const auto row = delegate()->peerListFindRow(user->id.value)) {
delegate()->peerListRemoveRow(row);
}
delegate()->peerListRefreshRows();
refreshRows();
}, lifetime());
}
@ -1170,9 +1170,11 @@ void ParticipantsBoxController::restoreState(
}
rpl::producer<int> ParticipantsBoxController::onlineCountValue() const {
return _onlineSorter
? _onlineSorter->onlineCountValue()
: rpl::single(0);
return _onlineCountValue.value();
}
rpl::producer<int> ParticipantsBoxController::fullCountValue() const {
return _fullCountValue.value();
}
void ParticipantsBoxController::prepare() {
@ -1205,17 +1207,48 @@ void ParticipantsBoxController::prepare() {
setDescriptionText(tr::lng_contacts_loading(tr::now));
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
if (_role == Role::Profile) {
auto visible = _peer->isMegagroup()
? Info::Profile::CanViewParticipantsValue(_peer->asMegagroup())
: rpl::single(true);
std::move(visible) | rpl::start_with_next([=](bool visible) {
if (!visible) {
_onlineCountValue = 0;
_onlineSorter = nullptr;
} else if (!_onlineSorter) {
_onlineSorter = std::make_unique<ParticipantsOnlineSorter>(
_peer,
delegate());
_onlineCountValue = _onlineSorter->onlineCountValue();
}
unload();
rebuild();
}, lifetime());
} else {
rebuild();
}
}
void ParticipantsBoxController::unload() {
while (delegate()->peerListFullRowsCount() > 0) {
delegate()->peerListRemoveRow(
delegate()->peerListRowAt(
delegate()->peerListFullRowsCount() - 1));
}
if (const auto requestId = base::take(_loadRequestId)) {
_api.request(requestId).cancel();
}
_allLoaded = false;
_offset = 0;
}
void ParticipantsBoxController::rebuild() {
if (const auto chat = _peer->asChat()) {
prepareChatRows(chat);
} else {
loadMoreRows();
}
if (_role == Role::Profile && !_onlineSorter) {
_onlineSorter = std::make_unique<ParticipantsOnlineSorter>(
_peer,
delegate());
}
delegate()->peerListRefreshRows();
refreshRows();
}
QPointer<Ui::BoxContent> ParticipantsBoxController::showBox(
@ -1291,7 +1324,7 @@ void ParticipantsBoxController::rebuildChatParticipants(
}
_onlineSorter->sort();
delegate()->peerListRefreshRows();
refreshRows();
chatListReady();
}
@ -1344,7 +1377,7 @@ void ParticipantsBoxController::rebuildChatAdmins(
}
}
delegate()->peerListRefreshRows();
refreshRows();
chatListReady();
}
@ -1366,7 +1399,7 @@ void ParticipantsBoxController::rebuildRowTypes() {
delegate()->peerListRowAt(i).get());
row->setType(computeType(row->user()));
}
delegate()->peerListRefreshRows();
refreshRows();
}
void ParticipantsBoxController::loadMoreRows() {
@ -1405,11 +1438,13 @@ void ParticipantsBoxController::loadMoreRows() {
MTP_int(perPage),
MTP_long(participantsHash)
)).done([=](const MTPchannels_ChannelParticipants &result) {
auto added = false;
const auto firstLoad = !_offset;
_loadRequestId = 0;
auto wasRecentRequest = firstLoad
&& (_role == Role::Members || _role == Role::Profile);
&& (_role == Role::Members || _role == Role::Profile)
&& channel->canViewMembers();
result.match([&](const MTPDchannels_channelParticipants &data) {
const auto &[availableCount, list] = wasRecentRequest
@ -1418,7 +1453,9 @@ void ParticipantsBoxController::loadMoreRows() {
for (const auto &data : list) {
if (const auto participant = _additional.applyParticipant(
data)) {
appendRow(participant);
if (appendRow(participant)) {
added = true;
}
}
}
if (const auto size = list.size()) {
@ -1431,7 +1468,9 @@ void ParticipantsBoxController::loadMoreRows() {
LOG(("API Error: "
"channels.channelParticipantsNotModified received!"));
});
if (!firstLoad && !added) {
_allLoaded = true;
}
if (_allLoaded
|| (firstLoad && delegate()->peerListFullRowsCount() > 0)) {
refreshDescription();
@ -1439,7 +1478,7 @@ void ParticipantsBoxController::loadMoreRows() {
if (_onlineSorter) {
_onlineSorter->sort();
}
delegate()->peerListRefreshRows();
refreshRows();
}).fail([this] {
_loadRequestId = 0;
}).send();
@ -1461,7 +1500,7 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
return false;
}
const auto megagroup = _peer->asMegagroup();
if (!megagroup) {
if (!megagroup || !megagroup->canViewMembers()) {
return false;
}
const auto info = megagroup->mgInfo.get();
@ -1663,7 +1702,7 @@ void ParticipantsBoxController::editAdminDone(
}
}
recomputeTypeFor(user);
delegate()->peerListRefreshRows();
refreshRows();
}
void ParticipantsBoxController::showRestricted(not_null<UserData*> user) {
@ -1727,7 +1766,7 @@ void ParticipantsBoxController::editRestrictedDone(
}
}
recomputeTypeFor(participant);
delegate()->peerListRefreshRows();
refreshRows();
}
void ParticipantsBoxController::kickParticipant(not_null<PeerData*> participant) {
@ -1752,7 +1791,7 @@ void ParticipantsBoxController::unkickParticipant(not_null<UserData*> user) {
_editBox = nullptr;
if (const auto row = delegate()->peerListFindRow(user->id.value)) {
delegate()->peerListRemoveRow(row);
delegate()->peerListRefreshRows();
refreshRows();
}
_peer->session().api().chatParticipants().add(_peer, { 1, user });
}
@ -1768,7 +1807,7 @@ void ParticipantsBoxController::kickParticipantSure(
if (const auto row = delegate()->peerListFindRow(participant->id.value)) {
delegate()->peerListRemoveRow(row);
delegate()->peerListRefreshRows();
refreshRows();
}
auto &session = _peer->session();
if (const auto chat = _peer->asChat()) {
@ -1842,7 +1881,7 @@ void ParticipantsBoxController::removeKicked(
&& !delegate()->peerListFullRowsCount()) {
setDescriptionText(tr::lng_blocked_list_not_found(tr::now));
}
delegate()->peerListRefreshRows();
refreshRows();
removeKicked(participant);
}
@ -2059,6 +2098,11 @@ void ParticipantsBoxController::fullListRefresh() {
delegate()->peerListRowAt(count - 1));
}
loadMoreRows();
refreshRows();
}
void ParticipantsBoxController::refreshRows() {
_fullCountValue = delegate()->peerListFullRowsCount();
delegate()->peerListRefreshRows();
}

View File

@ -184,7 +184,8 @@ public:
std::unique_ptr<PeerListState> saveState() const override;
void restoreState(std::unique_ptr<PeerListState> state) override;
rpl::producer<int> onlineCountValue() const override;
[[nodiscard]] rpl::producer<int> onlineCountValue() const;
[[nodiscard]] rpl::producer<int> fullCountValue() const;
protected:
// Allow child controllers not providing navigation.
@ -229,6 +230,8 @@ private:
void rebuildChatAdmins(not_null<ChatData*> chat);
void chatListReady();
void rebuildRowTypes();
void rebuild();
void unload();
void addNewItem();
void addNewParticipants();
@ -266,6 +269,7 @@ private:
void migrate(not_null<ChatData*> chat, not_null<ChannelData*> channel);
void subscribeToCreatorChange(not_null<ChannelData*> channel);
void fullListRefresh();
void refreshRows();
// It may be nullptr in subclasses of this controller.
Window::SessionNavigation *_navigation = nullptr;
@ -278,6 +282,8 @@ private:
bool _allLoaded = false;
ParticipantsAdditionalData _additional;
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
rpl::variable<int> _onlineCountValue;
rpl::variable<int> _fullCountValue;
Ui::BoxPointer _editBox;
Ui::BoxPointer _addBox;
QPointer<Ui::BoxContent> _editParticipantBox;

View File

@ -472,7 +472,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
--i;
mrows.push_back({ i->second });
}
} else if (_channel && _channel->isMegagroup()) {
} else if (_channel
&& _channel->isMegagroup()
&& _channel->canViewMembers()) {
if (_channel->lastParticipantsRequestNeeded()) {
_channel->session().api().chatParticipants().requestLast(
_channel);

View File

@ -263,8 +263,11 @@ bool ChannelData::linkedChatKnown() const {
void ChannelData::setMembersCount(int newMembersCount) {
if (_membersCount != newMembersCount) {
if (isMegagroup() && !mgInfo->lastParticipants.empty()) {
mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
if (isMegagroup()
&& canViewMembers()
&& !mgInfo->lastParticipants.empty()) {
mgInfo->lastParticipantsStatus
|= MegagroupInfo::LastParticipantsCountOutdated;
mgInfo->lastParticipantsCount = membersCount();
}
_membersCount = newMembersCount;
@ -485,7 +488,7 @@ bool ChannelData::isGroupAdmin(not_null<UserData*> user) const {
}
bool ChannelData::lastParticipantsRequestNeeded() const {
if (!mgInfo) {
if (!mgInfo || !canViewMembers()) {
return false;
} else if (mgInfo->lastParticipantsCount == membersCount()) {
mgInfo->lastParticipantsStatus

View File

@ -879,7 +879,9 @@ not_null<HistoryItem*> History::addNewToBack(
if (auto chat = peer->asChat()) {
return &chat->lastAuthors;
} else if (auto channel = peer->asMegagroup()) {
return &channel->mgInfo->lastParticipants;
return channel->canViewMembers()
? &channel->mgInfo->lastParticipants
: nullptr;
}
return nullptr;
};
@ -998,7 +1000,8 @@ void History::applyServiceChanges(
not_null<ChannelData*> megagroup,
not_null<MegagroupInfo*> mgInfo,
not_null<UserData*> user) {
if (!base::contains(mgInfo->lastParticipants, user)) {
if (!base::contains(mgInfo->lastParticipants, user)
&& megagroup->canViewMembers()) {
mgInfo->lastParticipants.push_front(user);
session().changes().peerUpdated(
peer,

View File

@ -1504,9 +1504,10 @@ bool TopBarWidget::trackOnlineOf(not_null<PeerData*> user) const {
} else if (const auto chat = peer->asChat()) {
return chat->participants.contains(user->asUser());
} else if (const auto channel = peer->asMegagroup()) {
return ranges::contains(
channel->mgInfo->lastParticipants,
not_null{ user->asUser() });
return channel->canViewMembers()
&& ranges::contains(
channel->mgInfo->lastParticipants,
not_null{ user->asUser() });
}
return false;
}
@ -1562,6 +1563,7 @@ void TopBarWidget::updateOnlineDisplay() {
}
} else if (const auto channel = peer->asChannel()) {
if (channel->isMegagroup()
&& channel->canViewMembers()
&& (channel->membersCount() > 0)
&& (channel->membersCount()
<= channel->session().serverConfig().chatSizeMax)) {

View File

@ -932,9 +932,7 @@ void ActionsFiller::addLeaveChannelAction(not_null<ChannelData*> channel) {
AddActionButton(
_wrap,
(channel->isMegagroup()
? tr::lng_profile_leave_group()
: tr::lng_profile_leave_channel()),
tr::lng_profile_leave_channel(),
AmInChannelValue(channel),
Window::DeleteAndLeaveHandler(
_controller->parentController(),
@ -950,9 +948,7 @@ void ActionsFiller::addJoinChannelAction(
| rpl::start_spawning(_wrap->lifetime());
AddActionButton(
_wrap,
(channel->isMegagroup()
? tr::lng_profile_join_group()
: tr::lng_profile_join_channel()),
tr::lng_profile_join_channel(),
rpl::duplicate(joinVisible),
[=] { channel->session().api().joinChannel(channel); },
&st::infoIconAddMember);
@ -1003,14 +999,7 @@ void ActionsFiller::fillChannelActions(
}
object_ptr<Ui::RpWidget> ActionsFiller::fill() {
const auto wrapToggled = [=](
object_ptr<Ui::RpWidget> content,
rpl::producer<bool> shown) {
auto result = object_ptr<Ui::SlideWrap<>>(_parent, std::move(content));
result->setDuration(0)->toggleOn(std::move(shown));
return result;
};
const auto wrapResult = [=](auto &&callback) {
auto wrapResult = [=](auto &&callback) {
_wrap = object_ptr<Ui::VerticalLayout>(_parent);
_wrap->add(CreateSkipWidget(_wrap));
callback();
@ -1022,11 +1011,8 @@ object_ptr<Ui::RpWidget> ActionsFiller::fill() {
fillUserActions(user);
});
} else if (auto channel = _peer->asChannel()) {
if (const auto megagroup = channel->asMegagroup()) {
using namespace rpl::mappers;
return wrapToggled(wrapResult([=] {
fillChannelActions(megagroup);
}), CanViewParticipantsValue(megagroup) | rpl::map(!_1));
if (channel->isMegagroup()) {
return { nullptr };
}
return wrapResult([=] {
fillChannelActions(channel);

View File

@ -113,32 +113,23 @@ object_ptr<Ui::RpWidget> InnerWidget::setupContent(
if (auto members = SetupChannelMembers(_controller, result.data(), _peer)) {
result->add(std::move(members));
}
result->add(object_ptr<Ui::BoxContentDivider>(result));
if (auto actions = SetupActions(_controller, result.data(), _peer)) {
result->add(object_ptr<Ui::BoxContentDivider>(result));
result->add(std::move(actions));
}
if (_peer->isChat()) {
if (_peer->isChat() || _peer->isMegagroup()) {
setupMembers(result.data());
} else if (const auto megagroup = _peer->asMegagroup()) {
CanViewParticipantsValue(
megagroup
) | rpl::start_with_next([=, raw = result.data()](bool can) {
if (can) {
setupMembers(raw);
} else {
_cover->setOnlineCount(rpl::single(0));
delete base::take(_members);
}
}, lifetime());
}
return result;
}
void InnerWidget::setupMembers(not_null<Ui::VerticalLayout*> container) {
_members = container->add(object_ptr<Members>(
auto wrap = container->add(object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
_controller));
object_ptr<Ui::VerticalLayout>(container)));
const auto inner = wrap->entity();
inner->add(object_ptr<Ui::BoxContentDivider>(inner));
_members = inner->add(object_ptr<Members>(inner, _controller));
_members->scrollToRequests(
) | rpl::start_with_next([this](Ui::ScrollToRequest request) {
auto min = (request.ymin < 0)
@ -152,6 +143,11 @@ void InnerWidget::setupMembers(not_null<Ui::VerticalLayout*> container) {
_scrollToRequests.fire({ min, max });
}, _members->lifetime());
_cover->setOnlineCount(_members->onlineCountValue());
using namespace rpl::mappers;
wrap->toggleOn(
_members->fullCountValue() | rpl::map(_1 > 0),
anim::type::instant);
}
object_ptr<Ui::RpWidget> InnerWidget::setupSharedMedia(

View File

@ -87,6 +87,10 @@ rpl::producer<int> Members::onlineCountValue() const {
return _listController->onlineCountValue();
}
rpl::producer<int> Members::fullCountValue() const {
return _listController->fullCountValue();
}
rpl::producer<Ui::ScrollToRequest> Members::scrollToRequests() const {
return _scrollToRequests.events();
}
@ -162,13 +166,18 @@ void Members::setupHeader() {
}
object_ptr<Ui::FlatLabel> Members::setupTitle() {
auto visible = _peer->isMegagroup()
? CanViewParticipantsValue(_peer->asMegagroup())
: rpl::single(true);
auto result = object_ptr<Ui::FlatLabel>(
_titleWrap,
tr::lng_chat_status_members(
lt_count_decimal,
MembersCountValue(_peer) | tr::to_count(),
Ui::Text::Upper
),
rpl::conditional(
std::move(visible),
tr::lng_chat_status_members(
lt_count_decimal,
MembersCountValue(_peer) | tr::to_count(),
Ui::Text::Upper),
tr::lng_channel_admins(Ui::Text::Upper)),
st::infoBlockHeaderLabel);
result->setAttribute(Qt::WA_TransparentForMouseEvents);
return result;
@ -184,8 +193,16 @@ void Members::setupButtons() {
//_searchField->hide();
//_cancelSearch->setVisible(false);
auto addMemberShown = CanAddMemberValue(_peer)
| rpl::start_spawning(lifetime());
auto visible = _peer->isMegagroup()
? CanViewParticipantsValue(_peer->asMegagroup())
: rpl::single(true);
rpl::duplicate(visible) | rpl::start_with_next([=](bool visible) {
_openMembers->setVisible(visible);
}, lifetime());
auto addMemberShown = CanAddMemberValue(
_peer
) | rpl::start_spawning(lifetime());
_addMember->showOn(rpl::duplicate(addMemberShown));
_addMember->addClickHandler([this] { // TODO throttle(ripple duration)
this->addMember();
@ -205,7 +222,8 @@ void Members::setupButtons() {
rpl::combine(
std::move(addMemberShown),
std::move(searchShown)
std::move(searchShown),
std::move(visible)
) | rpl::start_with_next([this] {
updateHeaderControlsGeometry(width());
}, lifetime());

View File

@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rp_widget.h"
#include "boxes/peer_list_box.h"
class ParticipantsBoxController;
namespace Ui {
class InputField;
class CrossButton;
@ -50,8 +52,9 @@ public:
std::unique_ptr<MembersState> saveState();
void restoreState(std::unique_ptr<MembersState> state);
int desiredHeight() const;
rpl::producer<int> onlineCountValue() const;
[[nodiscard]] int desiredHeight() const;
[[nodiscard]] rpl::producer<int> onlineCountValue() const;
[[nodiscard]] rpl::producer<int> fullCountValue() const;
protected:
void visibleTopBottomUpdated(
@ -116,7 +119,7 @@ private:
//Wrap _wrap;
not_null<Controller*> _controller;
not_null<PeerData*> _peer;
std::unique_ptr<PeerListController> _listController;
std::unique_ptr<ParticipantsBoxController> _listController;
object_ptr<Ui::RpWidget> _header = { nullptr };
object_ptr<ListWidget> _list = { nullptr };

View File

@ -68,7 +68,7 @@ void MemberListRow::refreshStatus() {
}
}
std::unique_ptr<PeerListController> CreateMembersController(
std::unique_ptr<ParticipantsBoxController> CreateMembersController(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
return std::make_unique<ParticipantsBoxController>(

View File

@ -10,6 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_list_controllers.h"
#include "ui/unread_badge.h"
class ParticipantsBoxController;
namespace Window {
class SessionNavigation;
} // namespace Window
@ -43,7 +45,7 @@ private:
};
std::unique_ptr<PeerListController> CreateMembersController(
std::unique_ptr<ParticipantsBoxController> CreateMembersController(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer);