Display admin badges in supergroups.

Also prefer std containers to Qt and OrderedSet in data_peer.
This commit is contained in:
John Preston 2017-12-01 22:38:44 +04:00
parent 3bdce06e19
commit 85b3d3f64d
27 changed files with 347 additions and 220 deletions

View File

@ -859,6 +859,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_in_reply_to" = "In reply to";
"lng_edited" = "edited";
"lng_edited_date" = "Edited: {date}";
"lng_admin_badge" = "admin";
"lng_cancel_edit_post_sure" = "Cancel editing?";
"lng_cancel_edit_post_yes" = "Yes";
"lng_cancel_edit_post_no" = "No";

View File

@ -639,7 +639,7 @@ void ApiWrap::lastParticipantsDone(
if (!peer->mgInfo) return;
parseChannelParticipants(result, [&](
parseChannelParticipants(peer, result, [&](
int availableCount,
const QVector<MTPChannelParticipant> &list) {
applyLastParticipantsList(
@ -713,12 +713,12 @@ void ApiWrap::applyLastParticipantsList(
keyboardBotFound = true;
}
} else {
if (peer->mgInfo->lastParticipants.indexOf(u) < 0) {
if (!base::contains(peer->mgInfo->lastParticipants, u)) {
peer->mgInfo->lastParticipants.push_back(u);
if (adminRights.c_channelAdminRights().vflags.v) {
peer->mgInfo->lastAdmins.insert(u, MegagroupInfo::Admin { adminRights, adminCanEdit });
peer->mgInfo->lastAdmins.emplace(u, MegagroupInfo::Admin { adminRights, adminCanEdit });
} else if (restrictedRights.c_channelBannedRights().vflags.v != 0) {
peer->mgInfo->lastRestricted.insert(u, MegagroupInfo::Restricted { restrictedRights });
peer->mgInfo->lastRestricted.emplace(u, MegagroupInfo::Restricted { restrictedRights });
}
if (u->botInfo) {
peer->mgInfo->bots.insert(u);
@ -1765,6 +1765,7 @@ void ApiWrap::readFeaturedSets() {
}
void ApiWrap::parseChannelParticipants(
not_null<ChannelData*> channel,
const MTPchannels_ChannelParticipants &result,
base::lambda<void(
int availableCount,
@ -1773,6 +1774,9 @@ void ApiWrap::parseChannelParticipants(
TLHelp::VisitChannelParticipants(result, base::overload([&](
const MTPDchannels_channelParticipants &data) {
App::feedUsers(data.vusers);
if (channel->mgInfo) {
refreshChannelAdmins(channel, data.vparticipants.v);
}
if (callbackList) {
callbackList(data.vcount.v, data.vparticipants.v);
}
@ -1783,7 +1787,31 @@ void ApiWrap::parseChannelParticipants(
LOG(("API Error: channels.channelParticipantsNotModified received!"));
}
}));
};
}
void ApiWrap::refreshChannelAdmins(
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants) {
auto changes = base::flat_map<UserId, bool>();
auto &admins = channel->mgInfo->admins;
for (auto &participant : participants) {
auto userId = TLHelp::ReadChannelParticipantUserId(participant);
auto admin = (participant.type() == mtpc_channelParticipantAdmin)
|| (participant.type() == mtpc_channelParticipantCreator);
if (admin && !admins.contains(userId)) {
admins.insert(userId);
changes.emplace(userId, true);
} else if (!admin && admins.contains(userId)) {
admins.remove(userId);
changes.emplace(userId, false);
}
}
if (!changes.empty()) {
if (auto history = App::historyLoaded(channel)) {
history->applyGroupAdminChanges(changes);
}
}
}
void ApiWrap::parseRecentChannelParticipants(
not_null<ChannelData*> channel,
@ -1792,7 +1820,7 @@ void ApiWrap::parseRecentChannelParticipants(
int availableCount,
const QVector<MTPChannelParticipant> &list)> callbackList,
base::lambda<void()> callbackNotModified) {
parseChannelParticipants(result, [&](
parseChannelParticipants(channel, result, [&](
int availableCount,
const QVector<MTPChannelParticipant> &list) {
auto applyLast = channel->isMegagroup()

View File

@ -144,6 +144,7 @@ public:
void readFeaturedSetDelayed(uint64 setId);
void parseChannelParticipants(
not_null<ChannelData*> channel,
const MTPchannels_ChannelParticipants &result,
base::lambda<void(
int availableCount,
@ -215,6 +216,9 @@ private:
void cancelEditChatAdmins(not_null<ChatData*> chat);
void saveChatAdmins(not_null<ChatData*> chat);
void sendSaveChatAdminsRequests(not_null<ChatData*> chat);
void refreshChannelAdmins(
not_null<ChannelData*> channel,
const QVector<MTPChannelParticipant> &participants);
template <typename Callback>
void requestMessageAfterDate(

View File

@ -798,7 +798,9 @@ namespace {
chat->version = d.vversion.v;
auto &v = d.vparticipants.v;
chat->count = v.size();
int32 pversion = chat->participants.isEmpty() ? 1 : (chat->participants.begin().value() + 1);
int32 pversion = chat->participants.empty()
? 1
: (chat->participants.begin()->second + 1);
chat->invitedByMe.clear();
chat->admins.clear();
chat->removeFlags(MTPDchat::Flag::f_admin);
@ -840,21 +842,22 @@ namespace {
break;
}
}
if (!chat->participants.isEmpty()) {
History *h = App::historyLoaded(chat->id);
if (!chat->participants.empty()) {
auto h = App::historyLoaded(chat->id);
bool found = !h || !h->lastKeyboardFrom;
int32 botStatus = -1;
auto botStatus = -1;
for (auto i = chat->participants.begin(), e = chat->participants.end(); i != e;) {
if (i.value() < pversion) {
auto [user, version] = *i;
if (version < pversion) {
i = chat->participants.erase(i);
} else {
if (i.key()->botInfo) {
botStatus = 2;// (botStatus > 0/* || !i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
if (requestBotInfos && !i.key()->botInfo->inited) {
Auth().api().requestFullPeer(i.key());
if (user->botInfo) {
botStatus = 2;// (botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1;
if (requestBotInfos && !user->botInfo->inited) {
Auth().api().requestFullPeer(user);
}
}
if (!found && i.key()->id == h->lastKeyboardFrom) {
if (!found && user->id == h->lastKeyboardFrom) {
found = true;
}
++i;
@ -884,11 +887,11 @@ namespace {
chat->version = d.vversion.v;
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
if (chat->participants.isEmpty() && chat->count) {
if (chat->participants.empty() && chat->count) {
chat->count++;
chat->botStatus = 0;
} else if (chat->participants.find(user) == chat->participants.end()) {
chat->participants[user] = (chat->participants.isEmpty() ? 1 : chat->participants.begin().value());
chat->participants[user] = (chat->participants.empty() ? 1 : chat->participants.begin()->second);
if (d.vinviter_id.v == Auth().userId()) {
chat->invitedByMe.insert(user);
} else {
@ -921,7 +924,7 @@ namespace {
auto canEdit = chat->canEdit();
UserData *user = App::userLoaded(d.vuser_id.v);
if (user) {
if (chat->participants.isEmpty()) {
if (chat->participants.empty()) {
if (chat->count > 0) {
chat->count--;
}
@ -943,9 +946,9 @@ namespace {
}
if (chat->botStatus > 0 && user->botInfo) {
int32 botStatus = -1;
for (auto j = chat->participants.cbegin(), e = chat->participants.cend(); j != e; ++j) {
if (j.key()->botInfo) {
if (true || botStatus > 0/* || !j.key()->botInfo->readsAllHistory*/) {
for (auto [participant, v] : chat->participants) {
if (participant->botInfo) {
if (true || botStatus > 0/* || !participant->botInfo->readsAllHistory*/) {
botStatus = 2;
break;
}

View File

@ -47,29 +47,47 @@ template <
typename reference_impl>
class flat_multi_map_iterator_base_impl;
template <typename Key>
class flat_multi_map_key_const_wrap {
public:
constexpr flat_multi_map_key_const_wrap(const Key &value)
: _value(value) {
}
constexpr flat_multi_map_key_const_wrap(Key &&value)
: _value(std::move(value)) {
}
inline constexpr operator const Key&() const {
return _value;
template <typename Key, typename Value>
struct flat_multi_map_pair_type {
using first_type = const Key;
using second_type = Value;
constexpr flat_multi_map_pair_type()
: first()
, second() {
}
private:
Key _value;
template <typename OtherKey, typename OtherValue>
constexpr flat_multi_map_pair_type(OtherKey &&key, OtherValue &&value)
: first(std::forward<OtherKey>(key))
, second(std::forward<OtherValue>(value)) {
}
flat_multi_map_pair_type(const flat_multi_map_pair_type&) = default;
flat_multi_map_pair_type(flat_multi_map_pair_type&&) = default;
flat_multi_map_pair_type &operator=(const flat_multi_map_pair_type&) = delete;
flat_multi_map_pair_type &operator=(flat_multi_map_pair_type &&other) {
const_cast<Key&>(first) = other.first;
second = std::move(other.second);
return *this;
}
void swap(flat_multi_map_pair_type &other) {
using std::swap;
if (this != &other) {
std::swap(
const_cast<Key&>(first),
const_cast<Key&>(other.first));
std::swap(second, other.second);
}
}
const Key first;
Value second;
};
template <typename Key, typename Type>
using flat_multi_map_pair_type = std::pair<
flat_multi_map_key_const_wrap<Key>,
Type>;
template <
typename Me,
typename Key,
@ -230,7 +248,6 @@ public:
class const_reverse_iterator;
private:
using key_const_wrap = flat_multi_map_key_const_wrap<Key>;
using pair_type = flat_multi_map_pair_type<Key, Type>;
using impl_t = std::deque<pair_type>;
@ -477,9 +494,7 @@ private:
typename OtherType1,
typename OtherType2,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType1>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
!std::is_same_v<std::decay_t<OtherType2>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType2>, pair_type>>>
inline constexpr auto operator()(
OtherType1 &&a,
@ -488,42 +503,6 @@ private:
std::forward<OtherType1>(a),
std::forward<OtherType2>(b));
}
template <
typename OtherType1,
typename OtherType2>
inline constexpr auto operator()(
OtherType1 &&a,
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, key_const_wrap> &&
std::is_same_v<std::decay_t<OtherType2>, key_const_wrap>, bool> {
return initial()(
static_cast<const Key&>(a),
static_cast<const Key&>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
const key_const_wrap &a,
OtherType &&b) const {
return initial()(
static_cast<const Key&>(a),
std::forward<OtherType>(b));
}
template <
typename OtherType,
typename = std::enable_if_t<
!std::is_same_v<std::decay_t<OtherType>, key_const_wrap> &&
!std::is_same_v<std::decay_t<OtherType>, pair_type>>>
inline constexpr auto operator()(
OtherType &&a,
const key_const_wrap &b) const {
return initial()(
std::forward<OtherType>(a),
static_cast<const Key&>(b));
}
template <
typename OtherType1,
typename OtherType2>
@ -532,9 +511,7 @@ private:
OtherType2 &&b) const -> std::enable_if_t<
std::is_same_v<std::decay_t<OtherType1>, pair_type> &&
std::is_same_v<std::decay_t<OtherType2>, pair_type>, bool> {
return initial()(
static_cast<const Key&>(a.first),
static_cast<const Key&>(b.first));
return initial()(a.first, b.first);
}
template <
typename OtherType,
@ -543,9 +520,7 @@ private:
inline constexpr auto operator()(
const pair_type &a,
OtherType &&b) const {
return operator()(
static_cast<const Key&>(a.first),
std::forward<OtherType>(b));
return operator()(a.first, std::forward<OtherType>(b));
}
template <
typename OtherType,
@ -554,9 +529,7 @@ private:
inline constexpr auto operator()(
OtherType &&a,
const pair_type &b) const {
return operator()(
std::forward<OtherType>(a),
static_cast<const Key&>(b.first));
return operator()(std::forward<OtherType>(a), b.first);
}
};

View File

@ -38,8 +38,12 @@ base::flat_set<not_null<UserData*>> GetAlreadyInFromPeer(PeerData *peer) {
return {};
}
if (auto chat = peer->asChat()) {
auto participants = chat->participants.keys();
return { participants.cbegin(), participants.cend() };
auto participants = (
chat->participants
) | ranges::view::transform([](auto &&pair) -> not_null<UserData*> {
return pair.first;
});
return { participants.begin(), participants.end() };
} else if (auto channel = peer->asChannel()) {
if (channel->isMegagroup()) {
auto &participants = channel->mgInfo->lastParticipants;
@ -427,7 +431,7 @@ bool AddParticipantsBoxController::isAlreadyIn(not_null<UserData*> user) const {
return chat->participants.contains(user);
} else if (auto channel = _peer->asChannel()) {
return _alreadyIn.contains(user)
|| (channel->isMegagroup() && channel->mgInfo->lastParticipants.contains(user));
|| (channel->isMegagroup() && base::contains(channel->mgInfo->lastParticipants, user));
}
Unexpected("User in AddParticipantsBoxController::isAlreadyIn");
}
@ -632,12 +636,12 @@ void EditChatAdminsBoxController::rebuildRows() {
admins.reserve(allAdmins ? _chat->participants.size() : _chat->admins.size());
others.reserve(_chat->participants.size());
for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
if (i.key()->id == peerFromUser(_chat->creator)) continue;
if (_chat->admins.contains(i.key())) {
admins.push_back(i.key());
for (auto [user, version] : _chat->participants) {
if (user->id == peerFromUser(_chat->creator)) continue;
if (_chat->admins.contains(user)) {
admins.push_back(user);
} else {
others.push_back(i.key());
others.push_back(user);
}
}
if (!admins.empty()) {

View File

@ -153,9 +153,9 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
} else if (_type == Type::Mentions) {
int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0;
if (_chat) {
maxListSize += (_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size());
maxListSize += (_chat->participants.empty() ? _chat->lastAuthors.size() : _chat->participants.size());
} else if (_channel && _channel->isMegagroup()) {
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (_channel->mgInfo->lastParticipants.empty() || _channel->lastParticipantsCountOutdated()) {
} else {
maxListSize += _channel->mgInfo->lastParticipants.size();
}
@ -192,19 +192,18 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
}
if (_chat) {
QMultiMap<int32, UserData*> ordered;
mrows.reserve(mrows.size() + (_chat->participants.isEmpty() ? _chat->lastAuthors.size() : _chat->participants.size()));
mrows.reserve(mrows.size() + (_chat->participants.empty() ? _chat->lastAuthors.size() : _chat->participants.size()));
if (_chat->noParticipantInfo()) {
Auth().api().requestFullPeer(_chat);
} else if (!_chat->participants.isEmpty()) {
for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
auto user = i.key();
} else if (!_chat->participants.empty()) {
for (const auto [user, v] : _chat->participants) {
if (user->isInaccessible()) continue;
if (!listAllSuggestions && filterNotPassedByName(user)) continue;
if (indexOfInFirstN(mrows, user, recentInlineBots) >= 0) continue;
ordered.insertMulti(App::onlineForSort(user, now), user);
}
}
for_const (auto user, _chat->lastAuthors) {
for (const auto user : _chat->lastAuthors) {
if (user->isInaccessible()) continue;
if (!listAllSuggestions && filterNotPassedByName(user)) continue;
if (indexOfInFirstN(mrows, user, recentInlineBots) >= 0) continue;
@ -221,11 +220,11 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
}
} else if (_channel && _channel->isMegagroup()) {
QMultiMap<int32, UserData*> ordered;
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (_channel->mgInfo->lastParticipants.empty() || _channel->lastParticipantsCountOutdated()) {
Auth().api().requestLastParticipants(_channel);
} else {
mrows.reserve(mrows.size() + _channel->mgInfo->lastParticipants.size());
for_const (auto user, _channel->mgInfo->lastParticipants) {
for (const auto user : _channel->mgInfo->lastParticipants) {
if (user->isInaccessible()) continue;
if (!listAllSuggestions && filterNotPassedByName(user)) continue;
if (indexOfInFirstN(mrows, user, recentInlineBots) >= 0) continue;
@ -251,9 +250,8 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
if (_chat) {
if (_chat->noParticipantInfo()) {
Auth().api().requestFullPeer(_chat);
} else if (!_chat->participants.isEmpty()) {
for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
auto user = i.key();
} else if (!_chat->participants.empty()) {
for (const auto [user, version] : _chat->participants) {
if (!user->botInfo) continue;
if (!user->botInfo->inited) {
Auth().api().requestFullPeer(user);
@ -270,7 +268,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
cnt = _user->botInfo->commands.size();
bots.insert(_user, true);
} else if (_channel && _channel->isMegagroup()) {
if (_channel->mgInfo->bots.isEmpty()) {
if (_channel->mgInfo->bots.empty()) {
if (!_channel->mgInfo->botStatus) {
Auth().api().requestBots(_channel);
}

View File

@ -806,7 +806,7 @@ void ChannelData::setInviteLink(const QString &newInviteLink) {
void ChannelData::setMembersCount(int newMembersCount) {
if (_membersCount != newMembersCount) {
if (isMegagroup() && !mgInfo->lastParticipants.isEmpty()) {
if (isMegagroup() && !mgInfo->lastParticipants.empty()) {
mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
mgInfo->lastParticipantsCount = membersCount();
}
@ -845,7 +845,8 @@ MTPChannelBannedRights ChannelData::KickedRestrictedRights() {
void ChannelData::applyEditAdmin(not_null<UserData*> user, const MTPChannelAdminRights &oldRights, const MTPChannelAdminRights &newRights) {
auto flags = Notify::PeerUpdate::Flag::AdminsChanged | Notify::PeerUpdate::Flag::None;
if (mgInfo) {
if (!mgInfo->lastParticipants.contains(user)) { // If rights are empty - still add participant? TODO check
// If rights are empty - still add participant? TODO check
if (!base::contains(mgInfo->lastParticipants, user)) {
mgInfo->lastParticipants.push_front(user);
setMembersCount(membersCount() + 1);
if (user->botInfo && !mgInfo->bots.contains(user)) {
@ -855,7 +856,8 @@ void ChannelData::applyEditAdmin(not_null<UserData*> user, const MTPChannelAdmin
}
}
}
if (mgInfo->lastRestricted.contains(user)) { // If rights are empty - still remove restrictions? TODO check
// If rights are empty - still remove restrictions? TODO check
if (mgInfo->lastRestricted.contains(user)) {
mgInfo->lastRestricted.remove(user);
if (restrictedCount() > 0) {
setRestrictedCount(restrictedCount() - 1);
@ -866,10 +868,10 @@ void ChannelData::applyEditAdmin(not_null<UserData*> user, const MTPChannelAdmin
auto lastAdmin = MegagroupInfo::Admin { newRights };
lastAdmin.canEdit = true;
if (it == mgInfo->lastAdmins.cend()) {
mgInfo->lastAdmins.insert(user, lastAdmin);
mgInfo->lastAdmins.emplace(user, lastAdmin);
setAdminsCount(adminsCount() + 1);
} else {
it.value() = lastAdmin;
it->second = lastAdmin;
}
} else {
if (it != mgInfo->lastAdmins.cend()) {
@ -913,10 +915,10 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChannelBann
auto it = mgInfo->lastRestricted.find(user);
if (isRestricted) {
if (it == mgInfo->lastRestricted.cend()) {
mgInfo->lastRestricted.insert(user, MegagroupInfo::Restricted { newRights });
mgInfo->lastRestricted.emplace(user, MegagroupInfo::Restricted { newRights });
setRestrictedCount(restrictedCount() + 1);
} else {
it->rights = newRights;
it->second.rights = newRights;
}
} else {
if (it != mgInfo->lastRestricted.cend()) {
@ -926,9 +928,9 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChannelBann
}
}
if (isKicked) {
auto i = mgInfo->lastParticipants.indexOf(user);
if (i >= 0) {
mgInfo->lastParticipants.removeAt(i);
auto i = ranges::find(mgInfo->lastParticipants, user);
if (i != mgInfo->lastParticipants.end()) {
mgInfo->lastParticipants.erase(i);
}
if (membersCount() > 1) {
setMembersCount(membersCount() - 1);
@ -939,7 +941,7 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChannelBann
setKickedCount(kickedCount() + 1);
if (mgInfo->bots.contains(user)) {
mgInfo->bots.remove(user);
if (mgInfo->bots.isEmpty() && mgInfo->botStatus > 0) {
if (mgInfo->bots.empty() && mgInfo->botStatus > 0) {
mgInfo->botStatus = -1;
}
}
@ -956,6 +958,13 @@ void ChannelData::applyEditBanned(not_null<UserData*> user, const MTPChannelBann
Notify::peerUpdatedDelayed(this, flags);
}
bool ChannelData::isGroupAdmin(not_null<UserData*> user) const {
if (auto info = mgInfo.get()) {
return info->admins.contains(peerToUser(user->id));
}
return false;
}
void ChannelData::setRestrictionReason(const QString &text) {
if (_restrictionReason != text) {
_restrictionReason = text;
@ -1087,9 +1096,9 @@ bool ChannelData::canDelete() const {
bool ChannelData::canEditLastAdmin(not_null<UserData*> user) const {
// Duplicated in ParticipantsBoxController::canEditAdmin :(
if (mgInfo) {
auto i = mgInfo->lastAdmins.constFind(user);
auto i = mgInfo->lastAdmins.find(user);
if (i != mgInfo->lastAdmins.cend()) {
return i->canEdit;
return i->second.canEdit;
}
return (user != mgInfo->creator);
}
@ -1130,7 +1139,7 @@ void ChannelData::setAdminRights(const MTPChannelAdminRights &rights) {
if (!amCreator()) {
auto me = MegagroupInfo::Admin { rights };
me.canEdit = false;
mgInfo->lastAdmins.insert(App::self(), me);
mgInfo->lastAdmins.emplace(App::self(), me);
}
mgInfo->lastRestricted.remove(App::self());
} else {
@ -1151,7 +1160,7 @@ void ChannelData::setRestrictedRights(const MTPChannelBannedRights &rights) {
if (hasRestrictions()) {
if (!amCreator()) {
auto me = MegagroupInfo::Restricted { rights };
mgInfo->lastRestricted.insert(App::self(), me);
mgInfo->lastRestricted.emplace(App::self(), me);
}
mgInfo->lastAdmins.remove(App::self());
} else {

View File

@ -115,11 +115,6 @@ private:
static const PhotoId UnknownPeerPhotoId = 0xFFFFFFFFFFFFFFFFULL;
inline const QString &emptyUsername() {
static QString empty;
return empty;
}
class PeerData;
class PeerClickHandler : public ClickHandler {
@ -195,7 +190,7 @@ public:
const Text &dialogName() const;
const QString &shortName() const;
const QString &userName() const;
QString userName() const;
const PeerId id;
int32 bareId() const {
@ -559,7 +554,7 @@ public:
void invalidateParticipants();
bool noParticipantInfo() const {
return (count > 0 || amIn()) && participants.isEmpty();
return (count > 0 || amIn()) && participants.empty();
}
MTPint inputChat;
@ -623,11 +618,11 @@ public:
bool isMigrated() const {
return flags() & MTPDchat::Flag::f_migrated_to;
}
QMap<not_null<UserData*>, int> participants;
OrderedSet<not_null<UserData*>> invitedByMe;
OrderedSet<not_null<UserData*>> admins;
QList<not_null<UserData*>> lastAuthors;
OrderedSet<not_null<PeerData*>> markupSenders;
base::flat_map<not_null<UserData*>, int> participants;
base::flat_set<not_null<UserData*>> invitedByMe;
base::flat_set<not_null<UserData*>> admins;
std::deque<not_null<UserData*>> lastAuthors;
base::flat_set<not_null<PeerData*>> markupSenders;
int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
// ImagePtr photoFull;
@ -744,11 +739,14 @@ struct MegagroupInfo {
}
MTPChannelBannedRights rights;
};
QList<not_null<UserData*>> lastParticipants;
QMap<not_null<UserData*>, Admin> lastAdmins;
QMap<not_null<UserData*>, Restricted> lastRestricted;
OrderedSet<not_null<PeerData*>> markupSenders;
OrderedSet<not_null<UserData*>> bots;
std::deque<not_null<UserData*>> lastParticipants;
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
base::flat_map<not_null<UserData*>, Restricted> lastRestricted;
base::flat_set<not_null<PeerData*>> markupSenders;
base::flat_set<not_null<UserData*>> bots;
// For admin badges, full admins list.
base::flat_set<UserId> admins;
UserData *creator = nullptr; // nullptr means unknown
int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
@ -898,6 +896,8 @@ public:
const MTPChannelBannedRights &oldRights,
const MTPChannelBannedRights &newRights);
bool isGroupAdmin(not_null<UserData*> user) const;
int32 date = 0;
int version = 0;
std::unique_ptr<MegagroupInfo> mgInfo;
@ -1176,12 +1176,12 @@ inline const Text &PeerData::dialogName() const {
inline const QString &PeerData::shortName() const {
return isUser() ? asUser()->firstName : name;
}
inline const QString &PeerData::userName() const {
inline QString PeerData::userName() const {
return isUser()
? asUser()->username
: isChannel()
? asChannel()->username
: emptyUsername();
: QString();
}
inline bool PeerData::isVerified() const {
return isUser()

View File

@ -87,9 +87,8 @@ void ChatSearchFromController::rebuildRows() {
QMultiMap<int32, UserData*> ordered;
if (_chat->noParticipantInfo()) {
Auth().api().requestFullPeer(_chat);
} else if (!_chat->participants.isEmpty()) {
for (auto i = _chat->participants.cbegin(), e = _chat->participants.cend(); i != e; ++i) {
auto user = i.key();
} else if (!_chat->participants.empty()) {
for (const auto [user, version] : _chat->participants) {
ordered.insertMulti(App::onlineForSort(user, now), user);
}
}

View File

@ -945,7 +945,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
auto &v = d.vusers.v;
for (auto i = 0, l = v.size(); i != l; ++i) {
if (auto user = App::userLoaded(peerFromUser(v[i]))) {
if (mgInfo->lastParticipants.indexOf(user) < 0) {
if (!base::contains(mgInfo->lastParticipants, user)) {
mgInfo->lastParticipants.push_front(user);
mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
@ -968,7 +968,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
auto mgInfo = megagroup->mgInfo.get();
Assert(mgInfo != nullptr);
if (auto user = result->from()->asUser()) {
if (mgInfo->lastParticipants.indexOf(user) < 0) {
if (!base::contains(mgInfo->lastParticipants, user)) {
mgInfo->lastParticipants.push_front(user);
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
Auth().data().addNewMegagroupParticipant(megagroup, user);
@ -998,9 +998,12 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
if (auto user = App::userLoaded(uid)) {
auto mgInfo = megagroup->mgInfo.get();
Assert(mgInfo != nullptr);
auto index = mgInfo->lastParticipants.indexOf(user);
if (index >= 0) {
mgInfo->lastParticipants.removeAt(index);
auto i = ranges::find(
mgInfo->lastParticipants,
user,
[](not_null<UserData*> user) { return user.get(); });
if (i != mgInfo->lastParticipants.end()) {
mgInfo->lastParticipants.erase(i);
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::MembersChanged);
}
Auth().data().removeMegagroupParticipant(megagroup, user);
@ -1018,7 +1021,7 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
Notify::peerUpdatedDelayed(peer, Notify::PeerUpdate::Flag::AdminsChanged);
}
mgInfo->bots.remove(user);
if (mgInfo->bots.isEmpty() && mgInfo->botStatus > 0) {
if (mgInfo->bots.empty() && mgInfo->botStatus > 0) {
mgInfo->botStatus = -1;
}
}
@ -1305,7 +1308,7 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
}
if (adding->from()->id) {
if (auto user = adding->from()->asUser()) {
auto getLastAuthors = [this]() -> QList<not_null<UserData*>>* {
auto getLastAuthors = [this]() -> std::deque<not_null<UserData*>>* {
if (auto chat = peer->asChat()) {
return &chat->lastAuthors;
} else if (auto channel = peer->asMegagroup()) {
@ -1324,13 +1327,19 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
}
}
if (auto lastAuthors = getLastAuthors()) {
int prev = lastAuthors->indexOf(user);
if (prev > 0) {
lastAuthors->removeAt(prev);
} else if (prev < 0 && peer->isMegagroup()) { // nothing is outdated if just reordering
auto prev = ranges::find(
*lastAuthors,
user,
[](not_null<UserData*> user) { return user.get(); });
auto index = (prev != lastAuthors->end())
? (lastAuthors->end() - prev)
: -1;
if (index > 0) {
lastAuthors->erase(prev);
} else if (index < 0 && peer->isMegagroup()) { // nothing is outdated if just reordering
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
}
if (prev) {
if (index) {
lastAuthors->push_front(user);
}
if (auto megagroup = peer->asMegagroup()) {
@ -1342,7 +1351,7 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
if (adding->definesReplyKeyboard()) {
auto markupFlags = adding->replyKeyboardFlags();
if (!(markupFlags & MTPDreplyKeyboardMarkup::Flag::f_selective) || adding->mentionsMe()) {
auto getMarkupSenders = [this]() -> OrderedSet<not_null<PeerData*>>* {
auto getMarkupSenders = [this]() -> base::flat_set<not_null<PeerData*>>* {
if (auto chat = peer->asChat()) {
return &chat->markupSenders;
} else if (auto channel = peer->asMegagroup()) {
@ -1360,7 +1369,7 @@ HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
} else {
bool botNotInChat = false;
if (peer->isChat()) {
botNotInChat = adding->from()->isUser() && (!peer->canWrite() || !peer->asChat()->participants.isEmpty()) && !peer->asChat()->participants.contains(adding->from()->asUser());
botNotInChat = adding->from()->isUser() && (!peer->canWrite() || !peer->asChat()->participants.empty()) && !peer->asChat()->participants.contains(adding->from()->asUser());
} else if (peer->isMegagroup()) {
botNotInChat = adding->from()->isUser() && (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && !peer->asChannel()->mgInfo->bots.contains(adding->from()->asUser());
}
@ -1577,8 +1586,8 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors
bool channel = isChannel();
int32 mask = 0;
QList<not_null<UserData*>> *lastAuthors = nullptr;
OrderedSet<not_null<PeerData*>> *markupSenders = nullptr;
std::deque<not_null<UserData*>> *lastAuthors = nullptr;
base::flat_set<not_null<PeerData*>> *markupSenders = nullptr;
if (peer->isChat()) {
lastAuthors = &peer->asChat()->lastAuthors;
markupSenders = &peer->asChat()->markupSenders;
@ -1597,7 +1606,7 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
if (item->from()->id) {
if (lastAuthors) { // chats
if (auto user = item->from()->asUser()) {
if (!lastAuthors->contains(user)) {
if (!base::contains(*lastAuthors, user)) {
lastAuthors->push_back(user);
if (peer->isMegagroup()) {
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
@ -1620,7 +1629,7 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
if (!lastKeyboardInited) {
bool botNotInChat = false;
if (peer->isChat()) {
botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.isEmpty()) && item->author()->isUser() && !peer->asChat()->participants.contains(item->author()->asUser());
botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.empty()) && item->author()->isUser() && !peer->asChat()->participants.contains(item->author()->asUser());
} else if (peer->isMegagroup()) {
botNotInChat = (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && item->author()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->author()->asUser());
}
@ -2408,6 +2417,15 @@ void History::clearUpTill(MsgId availableMinId) {
}
}
void History::applyGroupAdminChanges(
const base::flat_map<UserId, bool> &changes) {
for (auto block : blocks) {
for (auto item : block->items) {
item->applyGroupAdminChanges(changes);
}
}
}
void History::clearBlocks(bool leaveItems) {
Blocks lst;
std::swap(lst, blocks);

View File

@ -223,6 +223,8 @@ public:
void clear(bool leaveItems = false);
void clearUpTill(MsgId availableMinId);
void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes);
virtual ~History();
HistoryItem *addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true);

View File

@ -357,7 +357,7 @@ void InnerWidget::requestAdmins() {
}, [](auto &&) {
return false;
});
Auth().api().parseChannelParticipants(result, [&](
Auth().api().parseChannelParticipants(_channel, result, [&](
int availableCount,
const QVector<MTPChannelParticipant> &list) {
auto filtered = (

View File

@ -1176,7 +1176,7 @@ void HistoryItem::audioTrackUpdated() {
void HistoryItem::recountDisplayDate() {
Expects(!isLogEntry());
setDisplayDate(([this]() {
setDisplayDate([&] {
if (isEmpty()) {
return false;
}
@ -1185,7 +1185,7 @@ void HistoryItem::recountDisplayDate() {
return previous->isEmpty() || (previous->date.date() != date.date());
}
return true;
})());
}());
}
void HistoryItem::setDisplayDate(bool displayDate) {

View File

@ -520,6 +520,9 @@ public:
virtual bool notificationReady() const {
return true;
}
virtual void applyGroupAdminChanges(
const base::flat_map<UserId, bool> &changes) {
}
UserData *viaBot() const {
if (auto via = Get<HistoryMessageVia>()) {
@ -822,9 +825,6 @@ public:
return 0;
}
bool hasFromName() const {
return (!out() || isPost()) && !history()->peer->isUser();
}
PeerData *author() const {
return isPost() ? history()->peer : from();
}

View File

@ -50,6 +50,10 @@ inline void initTextOptions() {
_textDlgOptions.maxw = st::columnMaximalWidthLeft * 2;
}
QString AdminBadgeText() {
return lang(lng_admin_badge);
}
style::color FromNameFg(not_null<PeerData*> peer, bool selected) {
if (selected) {
const style::color colors[] = {
@ -805,6 +809,35 @@ void HistoryMessage::updateMediaInBubbleState() {
_media->setInBubbleState(computeState());
}
void HistoryMessage::updateAdminBadgeState() {
auto hasAdminBadge = [&] {
if (auto channel = history()->peer->asChannel()) {
if (auto user = author()->asUser()) {
return channel->isGroupAdmin(user);
}
}
return false;
}();
if (hasAdminBadge) {
_flags |= MTPDmessage_ClientFlag::f_has_admin_badge;
} else {
_flags &= ~MTPDmessage_ClientFlag::f_has_admin_badge;
}
}
void HistoryMessage::applyGroupAdminChanges(
const base::flat_map<UserId, bool> &changes) {
auto i = changes.find(peerToUser(author()->id));
if (i != changes.end()) {
if (i->second) {
_flags |= MTPDmessage_ClientFlag::f_has_admin_badge;
} else {
_flags &= ~MTPDmessage_ClientFlag::f_has_admin_badge;
}
setPendingInitDimensions();
}
}
bool HistoryMessage::displayEditedBadge(bool hasViaBotOrInlineMarkup) const {
if (hasViaBotOrInlineMarkup) {
return false;
@ -1062,6 +1095,9 @@ void HistoryMessage::initDimensions() {
if (reply) {
reply->updateName();
}
if (displayFromName()) {
updateAdminBadgeState();
}
auto mediaDisplayed = false;
if (_media) {
@ -1111,6 +1147,11 @@ void HistoryMessage::initDimensions() {
if (via && !forwarded) {
namew += st::msgServiceFont->spacew + via->_maxWidth;
}
if (_flags & MTPDmessage_ClientFlag::f_has_admin_badge) {
auto badgeWidth = st::msgServiceFont->width(
AdminBadgeText());
namew += st::msgPadding.right() + badgeWidth;
}
accumulate_max(_maxw, namew);
} else if (via && !forwarded) {
accumulate_max(_maxw, st::msgPadding.left() + via->_maxWidth + st::msgPadding.right());
@ -1188,10 +1229,19 @@ QRect HistoryMessage::countGeometry() const {
}
void HistoryMessage::fromNameUpdated(int32 width) const {
if (_flags & MTPDmessage_ClientFlag::f_has_admin_badge) {
auto badgeWidth = st::msgServiceFont->width(
AdminBadgeText());
width -= st::msgPadding.right() + badgeWidth;
}
_authorNameVersion = author()->nameVersion;
if (!Has<HistoryMessageForwarded>()) {
if (auto via = Get<HistoryMessageVia>()) {
via->resize(width - st::msgPadding.left() - st::msgPadding.right() - author()->nameText.maxWidth() - st::msgServiceFont->spacew);
via->resize(width
- st::msgPadding.left()
- st::msgPadding.right()
- author()->nameText.maxWidth()
- st::msgServiceFont->spacew);
}
}
}
@ -1774,20 +1824,46 @@ void HistoryMessage::drawFastShare(Painter &p, int left, int top, int outerWidth
void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const {
if (displayFromName()) {
auto badgeWidth = [&] {
if (_flags & MTPDmessage_ClientFlag::f_has_admin_badge) {
return st::msgServiceFont->width(AdminBadgeText());
}
return 0;
}();
auto availableLeft = trect.left();
auto availableWidth = trect.width();
if (badgeWidth) {
availableWidth -= st::msgPadding.right() + badgeWidth;
}
p.setFont(st::msgNameFont);
if (isPost()) {
p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
} else {
p.setPen(FromNameFg(author(), selected));
}
author()->nameText.drawElided(p, trect.left(), trect.top(), trect.width());
author()->nameText.drawElided(p, availableLeft, trect.top(), availableWidth);
auto skipWidth = author()->nameText.maxWidth() + st::msgServiceFont->spacew;
availableLeft += skipWidth;
availableWidth -= skipWidth;
auto forwarded = Get<HistoryMessageForwarded>();
auto via = Get<HistoryMessageVia>();
if (via && !forwarded && trect.width() > author()->nameText.maxWidth() + st::msgServiceFont->spacew) {
bool outbg = out() && !isPost();
if (via && !forwarded && availableWidth > 0) {
auto outbg = out() && !isPost();
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
p.drawText(trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, trect.top() + st::msgServiceFont->ascent, via->_text);
p.drawText(availableLeft, trect.top() + st::msgServiceFont->ascent, via->_text);
auto skipWidth = via->_width + st::msgServiceFont->spacew;
availableLeft += skipWidth;
availableWidth -= skipWidth;
}
if (badgeWidth) {
p.setPen(selected ? st::msgInDateFgSelected : st::msgInDateFg);
p.setFont(st::msgFont);
p.drawText(
trect.left() + trect.width() - badgeWidth,
trect.top() + st::msgFont->ascent,
AdminBadgeText());
}
trect.setY(trect.y() + st::msgNameFont->height);
}

View File

@ -62,6 +62,9 @@ public:
bool hasBubble() const override {
return drawBubble();
}
bool hasFromName() const {
return (!out() || isPost()) && !history()->peer->isUser();
}
bool displayFromName() const {
if (!hasFromName()) return false;
if (isAttachedToPrevious()) return false;
@ -71,6 +74,9 @@ public:
bool uploading() const;
bool displayFastShare() const override;
void applyGroupAdminChanges(
const base::flat_map<UserId, bool> &changes) override;
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
void drawFastShare(Painter &p, int left, int top, int outerWidth) const override;
void setViewsCount(int32 count) override;
@ -229,5 +235,6 @@ private:
};
void updateMediaInBubbleState();
void updateAdminBadgeState();
};

View File

@ -639,7 +639,7 @@ void HistoryTopBarWidget::updateOnlineDisplay() {
} else if (auto chat = _historyPeer->asChat()) {
if (!chat->amIn()) {
text = lang(lng_chat_status_unaccessible);
} else if (chat->participants.isEmpty()) {
} else if (chat->participants.empty()) {
if (!_titlePeerText.isEmpty()) {
text = _titlePeerText;
} else if (chat->count <= 0) {
@ -650,10 +650,10 @@ void HistoryTopBarWidget::updateOnlineDisplay() {
} else {
auto online = 0;
auto onlyMe = true;
for (auto i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
if (i.key()->onlineTill > t) {
for (auto [user, v] : chat->participants) {
if (user->onlineTill > t) {
++online;
if (onlyMe && i.key() != App::self()) onlyMe = false;
if (onlyMe && user != App::self()) onlyMe = false;
}
}
if (online > 0 && !onlyMe) {
@ -668,7 +668,7 @@ void HistoryTopBarWidget::updateOnlineDisplay() {
}
} else if (auto channel = _historyPeer->asChannel()) {
if (channel->isMegagroup() && channel->membersCount() > 0 && channel->membersCount() <= Global::ChatSizeMax()) {
if (channel->mgInfo->lastParticipants.isEmpty() || channel->lastParticipantsCountOutdated()) {
if (channel->mgInfo->lastParticipants.empty() || channel->lastParticipantsCountOutdated()) {
Auth().api().requestLastParticipants(channel);
}
auto online = 0;
@ -713,10 +713,10 @@ void HistoryTopBarWidget::updateOnlineDisplayTimer() {
if (auto user = _historyPeer->asUser()) {
minIn = App::onlineWillChangeIn(user, t);
} else if (auto chat = _historyPeer->asChat()) {
if (chat->participants.isEmpty()) return;
if (chat->participants.empty()) return;
for (auto i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
int32 onlineWillChangeIn = App::onlineWillChangeIn(i.key(), t);
for (auto [user, v] : chat->participants) {
auto onlineWillChangeIn = App::onlineWillChangeIn(user, t);
if (onlineWillChangeIn < minIn) {
minIn = onlineWillChangeIn;
}

View File

@ -365,9 +365,9 @@ void Cover::refreshStatusText() {
if (!chat->amIn()) {
return lang(lng_chat_status_unaccessible);
}
auto fullCount = qMax(
auto fullCount = std::max(
chat->count,
chat->participants.size());
int(chat->participants.size()));
return ChatStatusText(fullCount, _onlineCount, true);
} else if (auto channel = _peer->asChannel()) {
auto fullCount = qMax(channel->membersCount(), 1);

View File

@ -188,10 +188,8 @@ void ChatMembersController::rebuildRows() {
--count;
}
}
for (auto i = participants.cbegin(), e = participants.cend();
i != e;
++i) {
if (auto row = createRow(i.key())) {
for (const auto [user, v] : participants) {
if (auto row = createRow(user)) {
delegate()->peerListAppendRow(std::move(row));
}
}

View File

@ -186,7 +186,7 @@ rpl::producer<int> MembersCountValue(
Notify::PeerUpdate::Flag::MembersChanged)
| rpl::map([chat] {
return chat->amIn()
? qMax(chat->count, chat->participants.size())
? std::max(chat->count, int(chat->participants.size()))
: 0;
});
} else if (auto channel = peer->asChannel()) {

View File

@ -5045,7 +5045,7 @@ void MainWidget::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() < Global::ChatSizeMax() && (channel->mgInfo->lastParticipants.isEmpty() || channel->mgInfo->lastParticipants.size() < channel->membersCount())) {
if (channel->mgInfo->lastParticipants.size() < Global::ChatSizeMax() && (channel->mgInfo->lastParticipants.empty() || channel->mgInfo->lastParticipants.size() < channel->membersCount())) {
Auth().api().requestLastParticipants(channel);
}
}

View File

@ -78,8 +78,11 @@ enum class MTPDmessage_ClientFlag : uint32 {
// message is generated on the client side and should be unread
f_clientside_unread = (1U << 21),
// message has an admin badge in supergroup
f_has_admin_badge = (1U << 20),
// update this when adding new client side flags
MIN_FIELD = (1U << 21),
MIN_FIELD = (1U << 20),
};
DEFINE_MTP_CLIENT_FLAGS(MTPDmessage)

View File

@ -78,7 +78,7 @@ void GroupMembersWidget::editAdmin(not_null<UserData*> user) {
}
auto currentRightsIt = megagroup->mgInfo->lastAdmins.find(user);
auto hasAdminRights = (currentRightsIt != megagroup->mgInfo->lastAdmins.cend());
auto currentRights = hasAdminRights ? currentRightsIt->rights : MTP_channelAdminRights(MTP_flags(0));
auto currentRights = hasAdminRights ? currentRightsIt->second.rights : MTP_channelAdminRights(MTP_flags(0));
auto weak = QPointer<GroupMembersWidget>(this);
auto box = Box<EditAdminBox>(megagroup, user, currentRights);
box->setSaveCallback([weak, megagroup, user](const MTPChannelAdminRights &oldRights, const MTPChannelAdminRights &newRights) {
@ -96,8 +96,10 @@ void GroupMembersWidget::restrictUser(not_null<UserData*> user) {
if (!megagroup) {
return; // not supported
}
auto defaultRestricted = MegagroupInfo::Restricted { MTP_channelBannedRights(MTP_flags(0), MTP_int(0)) };
auto currentRights = megagroup->mgInfo->lastRestricted.value(user, defaultRestricted).rights;
auto currentRightsIt = megagroup->mgInfo->lastRestricted.find(user);
auto currentRights = (currentRightsIt != megagroup->mgInfo->lastRestricted.end())
? currentRightsIt->second.rights
: MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
auto hasAdminRights = megagroup->mgInfo->lastAdmins.find(user) != megagroup->mgInfo->lastAdmins.cend();
auto box = Box<EditRestrictedBox>(megagroup, user, hasAdminRights, currentRights);
box->setSaveCallback([megagroup, user](const MTPChannelBannedRights &oldRights, const MTPChannelBannedRights &newRights) {
@ -114,13 +116,15 @@ void GroupMembersWidget::removePeer(PeerData *selectedPeer) {
auto user = selectedPeer->asUser();
Assert(user != nullptr);
auto text = lng_profile_sure_kick(lt_user, user->firstName);
auto currentRestrictedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
if (auto channel = peer()->asMegagroup()) {
auto it = channel->mgInfo->lastRestricted.find(user);
if (it != channel->mgInfo->lastRestricted.cend()) {
currentRestrictedRights = it->rights;
auto currentRestrictedRights = [&]() -> MTPChannelBannedRights {
if (auto channel = peer()->asMegagroup()) {
auto it = channel->mgInfo->lastRestricted.find(user);
if (it != channel->mgInfo->lastRestricted.cend()) {
return it->second.rights;
}
}
}
return MTP_channelBannedRights(MTP_flags(0), MTP_int(0));
}();
Ui::show(Box<ConfirmBox>(text, lang(lng_box_remove), [user, currentRestrictedRights, peer = peer()] {
Ui::hideLayer();
if (auto chat = peer->asChat()) {
@ -303,7 +307,7 @@ void GroupMembersWidget::refreshMembers() {
refreshLimitReached();
} else if (auto megagroup = peer()->asMegagroup()) {
auto &megagroupInfo = megagroup->mgInfo;
if (megagroupInfo->lastParticipants.isEmpty() || megagroup->lastParticipantsCountOutdated()) {
if (megagroupInfo->lastParticipants.empty() || megagroup->lastParticipantsCountOutdated()) {
Auth().api().requestLastParticipants(megagroup);
}
fillMegagroupMembers(megagroup);
@ -335,7 +339,7 @@ void GroupMembersWidget::refreshLimitReached() {
}
void GroupMembersWidget::checkSelfAdmin(ChatData *chat) {
if (chat->participants.isEmpty()) return;
if (chat->participants.empty()) return;
auto self = App::self();
if (chat->amAdmin() && !chat->admins.contains(self)) {
@ -390,7 +394,7 @@ GroupMembersWidget::Member *GroupMembersWidget::addUser(ChatData *chat, UserData
}
void GroupMembersWidget::fillChatMembers(ChatData *chat) {
if (chat->participants.isEmpty()) return;
if (chat->participants.empty()) return;
clearItems();
if (!chat->amIn()) return;
@ -399,8 +403,7 @@ void GroupMembersWidget::fillChatMembers(ChatData *chat) {
reserveItemsForSize(chat->participants.size());
addUser(chat, App::self())->onlineForSort = INT_MAX; // Put me on the first place.
for (auto i = chat->participants.cbegin(), e = chat->participants.cend(); i != e; ++i) {
auto user = i.key();
for (auto [user, v] : chat->participants) {
if (!user->isSelf()) {
addUser(chat, user);
}
@ -434,7 +437,7 @@ GroupMembersWidget::Member *GroupMembersWidget::addUser(ChannelData *megagroup,
void GroupMembersWidget::fillMegagroupMembers(ChannelData *megagroup) {
Assert(megagroup->mgInfo != nullptr);
if (megagroup->mgInfo->lastParticipants.isEmpty()) return;
if (megagroup->mgInfo->lastParticipants.empty()) return;
if (!megagroup->canViewMembers()) {
clearItems();
@ -485,10 +488,10 @@ void GroupMembersWidget::setItemFlags(Item *item, ChannelData *megagroup) {
using AdminState = Item::AdminState;
auto amCreator = item->peer->isSelf() && megagroup->amCreator();
auto amAdmin = item->peer->isSelf() && megagroup->hasAdminRights();
auto adminIt = megagroup->mgInfo->lastAdmins.constFind(getMember(item)->user());
auto adminIt = megagroup->mgInfo->lastAdmins.find(getMember(item)->user());
auto isAdmin = (adminIt != megagroup->mgInfo->lastAdmins.cend());
auto isCreator = megagroup->mgInfo->creator == item->peer;
auto adminCanEdit = isAdmin && adminIt->canEdit;
auto adminCanEdit = isAdmin && adminIt->second.canEdit;
auto adminState = (amCreator || isCreator) ? AdminState::Creator : (amAdmin || isAdmin) ? AdminState::Admin : AdminState::None;
if (item->adminState != adminState) {
item->adminState = adminState;

View File

@ -475,6 +475,7 @@ void ParticipantsBoxController::loadMoreRows() {
callback);
} else {
Auth().api().parseChannelParticipants(
_channel,
result,
callback);
}
@ -538,7 +539,7 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
// _channel->updateFull();
// return false;
//}
if (info->lastParticipants.isEmpty()) {
if (info->lastParticipants.empty()) {
return false;
}
@ -546,21 +547,21 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() {
_additional.creator = info->creator;
}
for_const (auto user, info->lastParticipants) {
auto admin = info->lastAdmins.constFind(user);
auto admin = info->lastAdmins.find(user);
if (admin != info->lastAdmins.cend()) {
_additional.restrictedRights.erase(user);
if (admin->canEdit) {
if (admin->second.canEdit) {
_additional.adminCanEdit.emplace(user);
} else {
_additional.adminCanEdit.erase(user);
}
_additional.adminRights.emplace(user, admin->rights);
_additional.adminRights.emplace(user, admin->second.rights);
} else {
_additional.adminCanEdit.erase(user);
_additional.adminRights.erase(user);
auto restricted = info->lastRestricted.constFind(user);
auto restricted = info->lastRestricted.find(user);
if (restricted != info->lastRestricted.cend()) {
_additional.restrictedRights.emplace(user, restricted->rights);
_additional.restrictedRights.emplace(user, restricted->second.rights);
} else {
_additional.restrictedRights.erase(user);
}
@ -1083,7 +1084,7 @@ void ParticipantsBoxSearchController::searchDone(
int requestedCount) {
auto query = _query;
if (requestId) {
Auth().api().parseChannelParticipants(result, [&](auto&&...) {
Auth().api().parseChannelParticipants(_channel, result, [&](auto&&...) {
auto it = _queries.find(requestId);
if (it != _queries.cend()) {
query = it->second.text;
@ -1184,7 +1185,7 @@ void AddParticipantBoxController::loadMoreRows() {
)).done([this](const MTPchannels_ChannelParticipants &result) {
_loadRequestId = 0;
Auth().api().parseChannelParticipants(result, [&](
Auth().api().parseChannelParticipants(_channel, result, [&](
int availableCount,
const QVector<MTPChannelParticipant> &list) {
for (auto &participant : list) {
@ -1720,7 +1721,7 @@ void AddParticipantBoxSearchController::requestParticipants() {
void AddParticipantBoxSearchController::searchParticipantsDone(mtpRequestId requestId, const MTPchannels_ChannelParticipants &result, int requestedCount) {
auto query = _query;
if (requestId) {
Auth().api().parseChannelParticipants(result, [&](auto&&...) {
Auth().api().parseChannelParticipants(_channel, result, [&](auto&&...) {
auto it = _participantsQueries.find(requestId);
if (it != _participantsQueries.cend()) {
query = it->second.text;

View File

@ -98,7 +98,7 @@ private:
QueuedNotification(HistoryItem *item, int forwardedCount)
: history(item->history())
, peer(history->peer)
, author((item->hasFromName() && !item->isPost()) ? item->author() : nullptr)
, author((!peer->isUser() && !item->isPost()) ? item->author() : nullptr)
, item((forwardedCount > 1) ? nullptr : item)
, forwardedCount(forwardedCount) {
}

View File

@ -510,7 +510,7 @@ void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {
return;
}
auto callback = [channel](const MTPchannels_ChannelParticipants &result) {
Auth().api().parseChannelParticipants(result, [&](
Auth().api().parseChannelParticipants(channel, result, [&](
int availableCount,
const QVector<MTPChannelParticipant> &list) {
auto already = (