participants handled good in supergroups: auto-load in profiles, outdate when something changes

This commit is contained in:
John Preston 2015-11-19 18:56:29 +03:00
parent 583c0e5904
commit 84a47d3be7
7 changed files with 178 additions and 95 deletions

View File

@ -316,10 +316,11 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
channel->about = qs(f.vabout);
int32 newCount = f.has_participants_count() ? f.vparticipants_count.v : 0;
if (newCount != channel->count) {
channel->count = newCount;
if (channel->isMegagroup() && !channel->mgInfo->lastParticipants.isEmpty()) {
requestLastParticipants(channel);
channel->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
channel->mgInfo->lastParticipantsCount = channel->count;
}
channel->count = newCount;
}
channel->adminsCount = f.has_admins_count() ? f.vadmins_count.v : 0;
channel->invitationUrl = (f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString();
@ -421,11 +422,24 @@ void ApiWrap::requestPeers(const QList<PeerData*> &peers) {
if (!users.isEmpty()) MTP::send(MTPusers_GetUsers(MTP_vector<MTPInputUser>(users)), rpcDone(&ApiWrap::gotUsers));
}
void ApiWrap::requestLastParticipants(ChannelData *peer) {
if (!peer || !peer->isMegagroup() || _participantsRequests.contains(peer)) return;
mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
_participantsRequests.insert(peer, req);
MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) {
if (!peer || !peer->isMegagroup()) return;
if ((peer->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || peer->lastParticipantsCountOutdated()) {
fromStart = true;
}
QMap<PeerData*, mtpRequestId>::iterator i = _participantsRequests.find(peer);
if (i != _participantsRequests.cend()) {
if (fromStart && i.value() < 0) { // was not loading from start
_participantsRequests.erase(i);
} else {
return;
}
}
mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : peer->mgInfo->lastParticipants.size()), MTP_int(1)), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
_participantsRequests.insert(peer, fromStart ? req : -req);
if (fromStart) {
_botsRequests.insert(peer, MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer)));
}
}
void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
@ -477,60 +491,80 @@ bool ApiWrap::gotPeerFailed(PeerData *peer, const RPCError &error) {
}
void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId req) {
bool bots = (_participantsRequests.value(peer) != req);
if (!bots) {
bool bots = (_botsRequests.value(peer) == req), fromStart = false;
if (bots) {
_botsRequests.remove(peer);
} else {
int32 was = _participantsRequests.value(peer);
if (was == req) {
fromStart = true;
} else if (was != -req) {
return;
}
_participantsRequests.remove(peer);
}
if (!peer->mgInfo) return;
if (result.type() == mtpc_channels_channelParticipants) {
const MTPDchannels_channelParticipants &d(result.c_channels_channelParticipants());
const QVector<MTPChannelParticipant> &v(d.vparticipants.c_vector().v);
App::feedUsers(d.vusers);
int32 botStatus = peer->mgInfo->botStatus;
if (bots) {
peer->mgInfo->bots.clear();
botStatus = -1;
} else {
peer->mgInfo->lastParticipants.clear();
peer->mgInfo->lastAdmins.clear();
if (!peer->mgInfo || result.type() != mtpc_channels_channelParticipants) return;
if (bots) {
peer->mgInfo->bots.clear();
peer->mgInfo->botStatus = -1;
} else if (fromStart) {
peer->mgInfo->lastAdmins.clear();
peer->mgInfo->lastParticipants.clear();
peer->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate;
}
const MTPDchannels_channelParticipants &d(result.c_channels_channelParticipants());
const QVector<MTPChannelParticipant> &v(d.vparticipants.c_vector().v);
App::feedUsers(d.vusers);
bool added = false;
int32 botStatus = peer->mgInfo->botStatus;
for (QVector<MTPChannelParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 userId = 0;
bool admin = false;
switch (i->type()) {
case mtpc_channelParticipant: userId = i->c_channelParticipant().vuser_id.v; break;
case mtpc_channelParticipantSelf: userId = i->c_channelParticipantSelf().vuser_id.v; break;
case mtpc_channelParticipantModerator: userId = i->c_channelParticipantModerator().vuser_id.v; break;
case mtpc_channelParticipantEditor: userId = i->c_channelParticipantEditor().vuser_id.v; admin = true; break;
case mtpc_channelParticipantKicked: userId = i->c_channelParticipantKicked().vuser_id.v; break;
case mtpc_channelParticipantCreator: userId = i->c_channelParticipantCreator().vuser_id.v; admin = true; break;
}
for (QVector<MTPChannelParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 userId = 0;
bool admin = false;
switch (i->type()) {
case mtpc_channelParticipant: userId = i->c_channelParticipant().vuser_id.v; break;
case mtpc_channelParticipantSelf: userId = i->c_channelParticipantSelf().vuser_id.v; break;
case mtpc_channelParticipantModerator: userId = i->c_channelParticipantModerator().vuser_id.v; break;
case mtpc_channelParticipantEditor: userId = i->c_channelParticipantEditor().vuser_id.v; admin = true; break;
case mtpc_channelParticipantKicked: userId = i->c_channelParticipantKicked().vuser_id.v; break;
case mtpc_channelParticipantCreator: userId = i->c_channelParticipantCreator().vuser_id.v; admin = true; break;
UserData *u = App::user(userId);
if (bots) {
if (u->botInfo) {
peer->mgInfo->bots.insert(u, true);
botStatus = (botStatus > 0/* || i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
}
UserData *u = App::user(userId);
if (bots) {
if (u->botInfo) {
peer->mgInfo->bots.insert(u, true);
botStatus = (botStatus > 0/* || i.key()->botInfo->readsAllHistory*/) ? 2 : 1;
}
} else {
} else {
if (peer->mgInfo->lastParticipants.indexOf(u) < 0) {
peer->mgInfo->lastParticipants.push_back(u);
if (admin) peer->mgInfo->lastAdmins.insert(u, true);
added = true;
}
}
if (d.vcount.v > peer->count) {
peer->count = d.vcount.v;
} else if (v.count() > peer->count) {
peer->count = v.count();
}
if (App::main()) emit fullPeerUpdated(peer);
}
if (d.vcount.v > peer->count) {
peer->count = d.vcount.v;
} else if (v.count() > peer->count) {
peer->count = v.count();
}
if (!bots && v.isEmpty()) {
peer->count = peer->mgInfo->lastParticipants.size();
}
peer->mgInfo->botStatus = botStatus;
if (App::main()) emit fullPeerUpdated(peer);
}
bool ApiWrap::lastParticipantsFail(ChannelData *peer, const RPCError &error) {
bool ApiWrap::lastParticipantsFail(ChannelData *peer, const RPCError &error, mtpRequestId req) {
if (mtpIsFlood(error)) return false;
_participantsRequests.remove(peer);
if (_participantsRequests.value(peer) == req || _participantsRequests.value(peer) == -req) {
_participantsRequests.remove(peer);
} else if (_botsRequests.value(peer) == req) {
_botsRequests.remove(peer);
}
return true;
}
@ -603,10 +637,13 @@ void ApiWrap::kickParticipantDone(KickRequest kick, const MTPUpdates &result, mt
if (i >= 0) {
kick.first->asChannel()->mgInfo->lastParticipants.removeAt(i);
kick.first->asChannel()->mgInfo->lastAdmins.remove(kick.second);
kick.first->asChannel()->mgInfo->bots.remove(kick.second);
}
kick.first->asChannel()->mgInfo->bots.remove(kick.second);
if (kick.first->asChannel()->count > 1) {
kick.first->asChannel()->count--;
} else {
kick.first->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated;
kick.first->asChannel()->mgInfo->lastParticipantsCount = 0;
}
}
emit fullPeerUpdated(kick.first);

View File

@ -36,7 +36,7 @@ public:
void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer);
void requestPeers(const QList<PeerData*> &peers);
void requestLastParticipants(ChannelData *peer);
void requestLastParticipants(ChannelData *peer, bool fromStart = true);
void processFullPeer(PeerData *peer, const MTPmessages_ChatFull &result);
void processFullPeer(PeerData *peer, const MTPUserFull &result);
@ -96,8 +96,8 @@ private:
PeerRequests _peerRequests;
void lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId req);
bool lastParticipantsFail(ChannelData *peer, const RPCError &error);
PeerRequests _participantsRequests;
bool lastParticipantsFail(ChannelData *peer, const RPCError &error, mtpRequestId req);
PeerRequests _participantsRequests, _botsRequests;
typedef QPair<PeerData*, UserData*> KickRequest;
typedef QMap<KickRequest, mtpRequestId> KickRequests;

View File

@ -1791,8 +1791,9 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque
peer = peerFromMTP(d.c_dialog().vpeer);
break;
case mtpc_dialogChannel:
msgId = d.c_dialogChannel().vtop_important_message.v;
if (!msgId) msgId = d.c_dialogChannel().vtop_message.v;
//msgId = d.c_dialogChannel().vtop_important_message.v;
//if (!msgId) msgId = d.c_dialogChannel().vtop_message.v;
msgId = d.c_dialogChannel().vtop_message.v;
peer = peerFromMTP(d.c_dialogChannel().vpeer);
break;
}
@ -1802,7 +1803,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque
if (!lastMsgId) lastMsgId = msgId;
for (int32 j = m->size(); j > 0;) {
const MTPMessage &d(m->at(--j));
if (idFromMessage(d) == msgId) {
if (idFromMessage(d) == msgId && peerFromMessage(d) == peer) {
int32 date = dateFromMessage(d);
if (date) lastDate = date;
break;

View File

@ -3006,7 +3006,7 @@ void MentionsDropdown::updateFiltered(bool toDown) {
}
} else if (_filter.at(0) == '@' && _channel && _channel->isMegagroup()) {
QMultiMap<int32, UserData*> ordered;
if (_channel->mgInfo->lastParticipants.isEmpty()) {
if (_channel->mgInfo->lastParticipants.isEmpty() || _channel->lastParticipantsCountOutdated()) {
if (App::api()) App::api()->requestLastParticipants(_channel);
} else {
rows.reserve(_channel->mgInfo->lastParticipants.size());

View File

@ -1482,12 +1482,26 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
switch (d.vaction.type()) {
case mtpc_messageActionChatAddUser: {
const MTPDmessageActionChatAddUser &d(action.c_messageActionChatAddUser());
// App::user(App::peerFromUser(d.vuser_id)); added
if (peer->isMegagroup()) {
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
const QVector<MTPint> &v(d.vusers.c_vector().v);
for (int32 i = 0, l = v.size(); i < l; ++i) {
if (UserData *user = App::userLoaded(peerFromUser(v.at(i)))) {
if (peer->asChannel()->mgInfo->lastParticipants.indexOf(user) < 0) {
peer->asChannel()->mgInfo->lastParticipants.push_front(user);
}
}
}
}
} break;
case mtpc_messageActionChatJoinedByLink: {
const MTPDmessageActionChatJoinedByLink &d(action.c_messageActionChatJoinedByLink());
// App::user(App::peerFromUser(d.vuser_id)); added
if (peer->isMegagroup()) {
if (result->from()->isUser() && peer->asChannel()->mgInfo->lastParticipants.indexOf(result->from()->asUser()) < 0) {
peer->asChannel()->mgInfo->lastParticipants.push_front(result->from()->asUser());
}
}
} break;
case mtpc_messageActionChatDeletePhoto: {
@ -1731,8 +1745,9 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a
QList<UserData*> *lastAuthors = 0;
if (peer->isChat()) {
lastAuthors = &peer->asChat()->lastAuthors;
} else if (peer->isMegagroup() && !peer->asChannel()->mgInfo->lastParticipants.isEmpty()) {
} else if (peer->isMegagroup()) {
lastAuthors = &peer->asChannel()->mgInfo->lastParticipants;
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
}
if (lastAuthors) {
int prev = lastAuthors->indexOf(adding->from()->asUser());
@ -1948,29 +1963,28 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
lastAuthors = &peer->asChat()->lastAuthors;
markupSenders = &peer->asChat()->markupSenders;
} else if (peer->isMegagroup()) {
if (!peer->asChannel()->mgInfo->lastParticipants.isEmpty()) {
lastAuthors = &peer->asChannel()->mgInfo->lastParticipants;
}
lastAuthors = &peer->asChannel()->mgInfo->lastParticipants;
markupSenders = &peer->asChannel()->mgInfo->markupSenders;
peer->asChannel()->mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsAdminsOutdated;
}
for (int32 i = block->items.size(); i > 0; --i) {
HistoryItem *item = block->items[i - 1];
if (!item->indexInOverview()) continue;
HistoryMedia *media = item->getMedia(true);
if (media) {
HistoryMediaType mt = media->type();
MediaOverviewType t = mediaToOverviewType(mt);
if (t != OverviewCount) {
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
if (addToOverviewFront(item, OverviewAudioDocuments)) mask |= (1 << OverviewAudioDocuments);
} else {
if (addToOverviewFront(item, t)) mask |= (1 << t);
if (item->indexInOverview()) {
HistoryMedia *media = item->getMedia(true);
if (media) {
HistoryMediaType mt = media->type();
MediaOverviewType t = mediaToOverviewType(mt);
if (t != OverviewCount) {
if (mt == MediaTypeDocument && static_cast<HistoryDocument*>(media)->document()->song()) {
if (addToOverviewFront(item, OverviewAudioDocuments)) mask |= (1 << OverviewAudioDocuments);
} else {
if (addToOverviewFront(item, t)) mask |= (1 << t);
}
}
}
}
if (item->hasTextLinks()) {
if (addToOverviewFront(item, OverviewLinks)) mask |= (1 << OverviewLinks);
if (item->hasTextLinks()) {
if (addToOverviewFront(item, OverviewLinks)) mask |= (1 << OverviewLinks);
}
}
if (item->from()->id) {
if (lastAuthors) { // chats

View File

@ -130,7 +130,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData
if (chatPhoto && chatPhoto->date) {
_photoLink = TextLinkPtr(new PhotoLink(chatPhoto, _peer));
}
if (_peerChannel->isMegagroup() && _peerChannel->mgInfo->lastParticipants.isEmpty()) {
if (_peerChannel->isMegagroup() && (_peerChannel->mgInfo->lastParticipants.isEmpty() || (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || _peerChannel->lastParticipantsCountOutdated())) {
if (App::api()) App::api()->requestLastParticipants(_peerChannel);
}
_peerChannel->updateFull();
@ -487,7 +487,7 @@ void ProfileInner::onAdmins() {
void ProfileInner::onCreateInvitationLink() {
if (!_peerChat && !_peerChannel) return;
ConfirmBox *box = new ConfirmBox(lang((_peerChat && _peerChat->invitationUrl.isEmpty()) ? lng_group_invite_about : lng_group_invite_about_new));
ConfirmBox *box = new ConfirmBox(lang(((_peerChat && _peerChat->invitationUrl.isEmpty()) || (_peerChannel && _peerChannel->invitationUrl.isEmpty())) ? lng_group_invite_about : lng_group_invite_about_new));
connect(box, SIGNAL(confirmed()), this, SLOT(onCreateInvitationLinkSure()));
App::wnd()->showLayer(box);
}
@ -686,24 +686,31 @@ void ProfileInner::reorderParticipants() {
}
loadProfilePhotos(_lastPreload);
} else if (_peerChannel && _peerChannel->isMegagroup() && _peerChannel->amIn() && !_peerChannel->mgInfo->lastParticipants.isEmpty()) {
if (!_peerChannel->mgInfo->lastParticipants.isEmpty()) {
_participants.clear();
for (ParticipantsData::iterator i = _participantsData.begin(), e = _participantsData.end(); i != e; ++i) {
if (*i) {
delete *i;
*i = 0;
if (_peerChannel->mgInfo->lastParticipants.isEmpty() || (_peerChannel->mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsAdminsOutdated) || _peerChannel->lastParticipantsCountOutdated()) {
if (App::api()) App::api()->requestLastParticipants(_peerChannel);
} else if (!_peerChannel->mgInfo->lastParticipants.isEmpty()) {
const MegagroupInfo::LastParticipants &list(_peerChannel->mgInfo->lastParticipants);
int32 s = list.size();
for (int32 i = 0, l = _participants.size(); i < l; ++i) {
if (i >= s || _participants.at(i) != list.at(i)) {
if (_participantsData.at(i)) {
delete _participantsData.at(i);
_participantsData[i] = 0;
}
if (i < s) {
_participants[i] = list.at(i);
}
}
}
_participants.reserve(_peerChannel->mgInfo->lastParticipants.size());
_participantsData.resize(_peerChannel->mgInfo->lastParticipants.size());
}
UserData *self = App::self();
bool onlyMe = true;
for (MegagroupInfo::LastParticipants::const_iterator i = _peerChannel->mgInfo->lastParticipants.cbegin(), e = _peerChannel->mgInfo->lastParticipants.cend(); i != e; ++i) {
_participants.push_back(*i);
}
if (_peerChannel->mgInfo->lastParticipants.isEmpty()) {
if (App::api()) App::api()->requestLastParticipants(_peerChannel);
if (_participants.size() > s) {
_participants.resize(s);
} else {
_participants.reserve(s);
for (int32 i = _participants.size(); i < s; ++i) {
_participants.push_back(list.at(i));
}
}
_participantsData.resize(s);
}
_onlineText = (_peerChannel->count > 0) ? lng_chat_status_members(lt_count, _peerChannel->count) : lang(_peerChannel->isMegagroup() ? lng_group_status : lng_channel_status);
loadProfilePhotos(_lastPreload);
@ -1720,6 +1727,11 @@ void ProfileWidget::onScroll() {
if (!_scroll.isHidden() && _scroll.scrollTop() < _scroll.scrollTopMax()) {
_inner.allowDecreaseHeight(_scroll.scrollTopMax() - _scroll.scrollTop());
}
if (peer()->isMegagroup() && !peer()->asChannel()->mgInfo->lastParticipants.isEmpty() && peer()->asChannel()->mgInfo->lastParticipants.size() < peer()->asChannel()->count) {
if (_scroll.scrollTop() + PreloadHeightsCount * _scroll.height() > _scroll.scrollTopMax()) {
App::api()->requestLastParticipants(peer()->asChannel(), false);
}
}
}
void ProfileWidget::resizeEvent(QResizeEvent *e) {

View File

@ -526,7 +526,7 @@ private:
};
struct MegagroupInfo {
MegagroupInfo() : botStatus(-1), migrateFromPtr(0) {
MegagroupInfo() : botStatus(-1), migrateFromPtr(0), lastParticipantsStatus(LastParticipantsUpToDate), lastParticipantsCount(0) {
}
typedef QList<UserData*> LastParticipants;
LastParticipants lastParticipants;
@ -537,6 +537,15 @@ struct MegagroupInfo {
typedef QMap<UserData*, bool> Bots;
Bots bots;
int32 botStatus; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
enum LastParticipantsStatus {
LastParticipantsUpToDate = 0x00,
LastParticipantsAdminsOutdated = 0x01,
LastParticipantsCountOutdated = 0x02,
};
mutable int32 lastParticipantsStatus;
int32 lastParticipantsCount;
ChatData *migrateFromPtr;
};
@ -563,6 +572,16 @@ public:
int32 version;
int32 flags, flagsFull;
MegagroupInfo *mgInfo;
bool lastParticipantsCountOutdated() const {
if (!mgInfo || !(mgInfo->lastParticipantsStatus & MegagroupInfo::LastParticipantsCountOutdated)) {
return false;
}
if (mgInfo->lastParticipantsCount == count) {
mgInfo->lastParticipantsStatus &= ~MegagroupInfo::LastParticipantsCountOutdated;
return false;
}
return true;
}
void flagsUpdated();
bool isMegagroup() const {
return flags & MTPDchannel::flag_megagroup;