From 67d12fa6d29e6d23aab60b9977d4f75a061bdc13 Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 13 Jan 2019 12:03:34 +0400 Subject: [PATCH] Improve update handling for legacy chats. --- Telegram/SourceFiles/apiwrap.cpp | 115 +++---- Telegram/SourceFiles/apiwrap.h | 8 - Telegram/SourceFiles/app.cpp | 218 ------------- Telegram/SourceFiles/app.h | 4 - .../SourceFiles/boxes/add_contact_box.cpp | 39 +-- .../boxes/peers/add_participants_box.cpp | 11 +- .../boxes/peers/edit_participants_box.cpp | 91 +++--- Telegram/SourceFiles/boxes/share_box.cpp | 10 +- .../chat_helpers/field_autocomplete.cpp | 4 +- Telegram/SourceFiles/core/changelogs.cpp | 2 +- Telegram/SourceFiles/data/data_channel.cpp | 26 ++ Telegram/SourceFiles/data/data_channel.h | 23 +- Telegram/SourceFiles/data/data_chat.cpp | 248 ++++++++++++++- Telegram/SourceFiles/data/data_chat.h | 42 ++- Telegram/SourceFiles/data/data_peer.cpp | 5 +- Telegram/SourceFiles/data/data_session.cpp | 75 ++++- Telegram/SourceFiles/data/data_session.h | 10 +- Telegram/SourceFiles/data/data_user.h | 3 + .../dialogs_search_from_controllers.cpp | 2 +- Telegram/SourceFiles/history/history_item.cpp | 5 +- .../view/history_view_top_bar_widget.cpp | 4 +- .../info_common_groups_inner_widget.cpp | 24 +- .../info_profile_members_controllers.cpp | 297 +----------------- Telegram/SourceFiles/mainwidget.cpp | 42 +-- Telegram/SourceFiles/mtproto/core_types.h | 4 +- .../profile/profile_block_group_members.cpp | 99 +++--- .../profile/profile_block_group_members.h | 20 +- .../SourceFiles/storage/serialize_common.cpp | 16 +- 28 files changed, 650 insertions(+), 797 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ac3a653fd..6881a762b 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -395,7 +395,7 @@ void ApiWrap::importChatInvite(const QString &hash) { "(MainWidget::inviteImportDone)").arg(result.type())); }); }).fail([=](const RPCError &error) { - const auto type = error.type(); + const auto &type = error.type(); if (type == qstr("CHANNELS_TOO_MUCH")) { Ui::show(Box(lang(lng_join_channel_error))); } else if (error.code() == 400) { @@ -416,7 +416,7 @@ void ApiWrap::savePinnedOrder() { const auto &order = _session->data().pinnedDialogsOrder(); auto peers = QVector(); peers.reserve(order.size()); - for (const auto pinned : base::reversed(order)) { + for (const auto &pinned : base::reversed(order)) { if (const auto history = pinned.history()) { peers.push_back(MTP_inputDialogPeer(history->peer->input)); } else if (const auto feed = pinned.feed()) { @@ -510,7 +510,9 @@ ApiWrap::MessageDataRequests *ApiWrap::messageDataRequests(ChannelData *channel, if (channel) { auto i = _channelMessageDataRequests.find(channel); if (i == _channelMessageDataRequests.cend()) { - if (onlyExisting) return 0; + if (onlyExisting) { + return nullptr; + } i = _channelMessageDataRequests.insert(channel, MessageDataRequests()); } return &i.value(); @@ -694,7 +696,7 @@ void ApiWrap::requestDialogEntry( } const auto finalize = [=] { if (const auto callbacks = _dialogRequests.take(history)) { - for (const auto callback : *callbacks) { + for (const auto &callback : *callbacks) { callback(); } } @@ -731,7 +733,7 @@ void ApiWrap::requestDialogEntries( const auto finalize = [=](std::vector> histories) { for (const auto history : histories) { if (const auto callbacks = _dialogRequests.take(history)) { - for (const auto callback : *callbacks) { + for (const auto &callback : *callbacks) { callback(); } } @@ -846,7 +848,7 @@ void ApiWrap::applyFeedDialogs( if (peerIsChannel(peerId)) { const auto history = App::history(peerId); history->applyDialog(dialog.c_dialog()); - channels.push_back(history->peer->asChannel()); + channels.emplace_back(history->peer->asChannel()); } else { LOG(("API Error: " "Unexpected non-channel in feed dialogs list.")); @@ -932,18 +934,8 @@ void ApiWrap::gotChatFull( not_null peer, const MTPmessages_ChatFull &result, mtpRequestId req) { - auto &d = result.c_messages_chatFull(); - auto &vc = d.vchats.v; - auto badVersion = false; - if (const auto chat = peer->asChat()) { - badVersion = !vc.isEmpty() - && (vc[0].type() == mtpc_chat) - && (vc[0].c_chat().vversion.v < chat->version); - } else if (const auto channel = peer->asChannel()) { - badVersion = !vc.isEmpty() - && (vc[0].type() == mtpc_channel) - && (vc[0].c_channel().vversion.v < channel->version); - } + const auto &d = result.c_messages_chatFull(); + _session->data().applyMaximumChatVersions(d.vchats); App::feedUsers(d.vusers); App::feedChats(d.vchats); @@ -956,7 +948,7 @@ void ApiWrap::gotChatFull( return; } auto &f = d.vfull_chat.c_chatFull(); - App::feedParticipants(f.vparticipants, false); + Data::ApplyChatParticipants(chat, f.vparticipants); if (f.has_bot_info()) { for (const auto &item : f.vbot_info.v) { item.match([&](const MTPDbotInfo &data) { @@ -1087,14 +1079,6 @@ void ApiWrap::gotChatFull( _fullPeerRequests.erase(i); } } - if (badVersion) { - if (const auto chat = peer->asChat()) { - chat->version = vc[0].c_chat().vversion.v; - } else if (const auto channel = peer->asChannel()) { - channel->version = vc[0].c_channel().vversion.v; - } - requestPeer(peer); - } fullPeerUpdated().notify(peer); } @@ -1157,31 +1141,11 @@ void ApiWrap::requestPeer(not_null peer) { }; const auto chatHandler = [=](const MTPmessages_Chats &result) { _peerRequests.remove(peer); - - if (const auto chats = Api::getChatsFromMessagesChats(result)) { - auto &v = chats->v; - bool badVersion = false; - if (const auto chat = peer->asChat()) { - badVersion = !v.isEmpty() - && (v[0].type() == mtpc_chat) - && (v[0].c_chat().vversion.v < chat->version); - } else if (const auto channel = peer->asChannel()) { - badVersion = !v.isEmpty() - && (v[0].type() == mtpc_channel) - && (v[0].c_channel().vversion.v < channel->version); - } - const auto chat = App::feedChats(*chats); - if (chat == peer) { - if (badVersion) { - if (const auto chat = peer->asChat()) { - chat->version = v[0].c_chat().vversion.v; - } else if (const auto channel = peer->asChannel()) { - channel->version = v[0].c_channel().vversion.v; - } - requestPeer(peer); - } - } - } + const auto &chats = result.match([](const auto &data) { + return data.vchats; + }); + _session->data().applyMaximumChatVersions(chats); + App::feedChats(chats); }; if (const auto user = peer->asUser()) { return request(MTPusers_GetUsers( @@ -1272,36 +1236,47 @@ void ApiWrap::requestPeers(const QList &peers) { chats.reserve(peers.size()); channels.reserve(peers.size()); users.reserve(peers.size()); - for (QList::const_iterator i = peers.cbegin(), e = peers.cend(); i != e; ++i) { - if (!*i || _fullPeerRequests.contains(*i) || _peerRequests.contains(*i)) continue; - if ((*i)->isUser()) { - users.push_back((*i)->asUser()->inputUser); - } else if ((*i)->isChat()) { - chats.push_back((*i)->asChat()->inputChat); - } else if ((*i)->isChannel()) { - channels.push_back((*i)->asChannel()->inputChannel); + for (const auto peer : peers) { + if (!peer + || _fullPeerRequests.contains(peer) + || _peerRequests.contains(peer)) { + continue; + } + if (const auto user = peer->asUser()) { + users.push_back(user->inputUser); + } else if (const auto chat = peer->asChat()) { + chats.push_back(chat->inputChat); + } else if (const auto channel = peer->asChannel()) { + channels.push_back(channel->inputChannel); } } - auto handleChats = [=](const MTPmessages_Chats &result) { - if (auto chats = Api::getChatsFromMessagesChats(result)) { - App::feedChats(*chats); - } + const auto handleChats = [=](const MTPmessages_Chats &result) { + App::feedChats(result.match([](const auto &data) { + return data.vchats; + })); }; if (!chats.isEmpty()) { - request(MTPmessages_GetChats(MTP_vector(chats))).done(handleChats).send(); + request(MTPmessages_GetChats( + MTP_vector(chats) + )).done(handleChats).send(); } if (!channels.isEmpty()) { - request(MTPchannels_GetChannels(MTP_vector(channels))).done(handleChats).send(); + request(MTPchannels_GetChannels( + MTP_vector(channels) + )).done(handleChats).send(); } if (!users.isEmpty()) { - request(MTPusers_GetUsers(MTP_vector(users))).done([=](const MTPVector &result) { + request(MTPusers_GetUsers( + MTP_vector(users) + )).done([=](const MTPVector &result) { App::feedUsers(result); }).send(); } } void ApiWrap::requestLastParticipants(not_null channel) { - if (!channel->isMegagroup() || _participantsRequests.contains(channel)) { + if (!channel->isMegagroup() + || _participantsRequests.contains(channel)) { return; } @@ -1313,7 +1288,7 @@ void ApiWrap::requestLastParticipants(not_null channel) { MTP_int(offset), MTP_int(Global::ChatSizeMax()), MTP_int(participantsHash) - )).done([this, channel](const MTPchannels_ChannelParticipants &result) { + )).done([=](const MTPchannels_ChannelParticipants &result) { _participantsRequests.remove(channel); parseChannelParticipants(channel, result, [&]( int availableCount, @@ -4357,7 +4332,7 @@ void ApiWrap::sendFiles( _sendingAlbums.emplace(album->groupId, album); album->items.reserve(tasks.size()); for (const auto &task : tasks) { - album->items.push_back(SendingAlbum::Item(task->id())); + album->items.emplace_back(task->id()); } } _fileLoader->addTasks(std::move(tasks)); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 253918191..b429994be 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -47,14 +47,6 @@ struct CloudPasswordState; namespace Api { -inline const MTPVector *getChatsFromMessagesChats(const MTPmessages_Chats &chats) { - switch (chats.type()) { - case mtpc_messages_chats: return &chats.c_messages_chats().vchats; - case mtpc_messages_chatsSlice: return &chats.c_messages_chatsSlice().vchats; - } - return nullptr; -} - template inline int32 CountHash(IntRange &&range) { uint32 acc = 0; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index c9232bdf1..4e9f2d106 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -146,224 +146,6 @@ namespace App { return Auth().data().processChats(chats); } - void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos) { - ChatData *chat = 0; - switch (p.type()) { - case mtpc_chatParticipantsForbidden: { - const auto &d(p.c_chatParticipantsForbidden()); - chat = App::chat(d.vchat_id.v); - chat->count = -1; - chat->invalidateParticipants(); - } break; - - case mtpc_chatParticipants: { - const auto &d(p.c_chatParticipants()); - chat = App::chat(d.vchat_id.v); - if (!requestBotInfos || chat->version <= d.vversion.v) { // !requestBotInfos is true on getFullChat result - chat->version = d.vversion.v; - auto &v = d.vparticipants.v; - chat->count = v.size(); - int32 pversion = chat->participants.empty() - ? 1 - : (chat->participants.begin()->second + 1); - chat->invitedByMe.clear(); - chat->admins.clear(); - // #TODO groups - //chat->removeFlags(MTPDchat::Flag::f_admin); - for (auto i = v.cbegin(), e = v.cend(); i != e; ++i) { - int32 uid = 0, inviter = 0; - switch (i->type()) { - case mtpc_chatParticipantCreator: { - const auto &p(i->c_chatParticipantCreator()); - uid = p.vuser_id.v; - chat->creator = uid; - } break; - case mtpc_chatParticipantAdmin: { - const auto &p(i->c_chatParticipantAdmin()); - uid = p.vuser_id.v; - inviter = p.vinviter_id.v; - } break; - case mtpc_chatParticipant: { - const auto &p(i->c_chatParticipant()); - uid = p.vuser_id.v; - inviter = p.vinviter_id.v; - } break; - } - if (!uid) continue; - - UserData *user = App::userLoaded(uid); - if (user) { - chat->participants[user] = pversion; - if (inviter == Auth().userId()) { - chat->invitedByMe.insert(user); - } - if (i->type() == mtpc_chatParticipantAdmin) { - chat->admins.insert(user); - if (user->isSelf()) { - // #TODO groups -// chat->addFlags(MTPDchat::Flag::f_admin); - } - } - } else { - chat->invalidateParticipants(); - break; - } - } - if (!chat->participants.empty()) { - auto h = App::historyLoaded(chat->id); - bool found = !h || !h->lastKeyboardFrom; - auto botStatus = -1; - for (auto i = chat->participants.begin(); i != chat->participants.end();) { - const auto [user, version] = *i; - if (version < pversion) { - i = chat->participants.erase(i); - } else { - if (user->botInfo) { - botStatus = 2;// (botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1; - if (requestBotInfos && !user->botInfo->inited) { - Auth().api().requestFullPeer(user); - } - } - if (!found && user->id == h->lastKeyboardFrom) { - found = true; - } - ++i; - } - } - chat->botStatus = botStatus; - if (!found) { - h->clearLastKeyboard(); - } - } - } - } break; - } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged | Notify::PeerUpdate::Flag::AdminsChanged); - } - - void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count >= 0) { - chat->version = d.vversion.v; - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { - 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.empty() ? 1 : chat->participants.begin()->second); - if (d.vinviter_id.v == Auth().userId()) { - chat->invitedByMe.insert(user); - } else { - chat->invitedByMe.remove(user); - } - chat->count++; - if (user->botInfo) { - chat->botStatus = 2;// (chat->botStatus > 0/* || !user->botInfo->readsAllHistory*/) ? 2 : 1; - if (!user->botInfo->inited) { - Auth().api().requestFullPeer(user); - } - } - } - } else { - chat->invalidateParticipants(); - chat->count++; - } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); - } - } - - void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d) { - ChatData *chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count > 0) { - chat->version = d.vversion.v; - const auto user = App::userLoaded(d.vuser_id.v); - if (user) { - if (chat->participants.empty()) { - if (chat->count > 0) { - chat->count--; - } - } else { - auto i = chat->participants.find(user); - if (i != chat->participants.end()) { - chat->participants.erase(i); - chat->count--; - chat->invitedByMe.remove(user); - chat->admins.remove(user); - if (user->isSelf()) { - // #TODO groups -// chat->removeFlags(MTPDchat::Flag::f_admin); - } - - History *h = App::historyLoaded(chat->id); - if (h && h->lastKeyboardFrom == user->id) { - h->clearLastKeyboard(); - } - } - if (chat->botStatus > 0 && user->botInfo) { - int32 botStatus = -1; - for (const auto [participant, v] : chat->participants) { - if (participant->botInfo) { - if (true || botStatus > 0/* || !participant->botInfo->readsAllHistory*/) { - botStatus = 2; - break; - } - botStatus = 1; - } - } - chat->botStatus = botStatus; - } - } - } else { - chat->invalidateParticipants(); - chat->count--; - } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::MembersChanged); - } - } - - void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d) { - const auto chat = App::chat(d.vchat_id.v); - if (chat->version + 1 < d.vversion.v) { - chat->version = d.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } else if (chat->version <= d.vversion.v && chat->count > 0) { - chat->version = d.vversion.v; - const auto user = App::userLoaded(d.vuser_id.v); - if (user) { - if (mtpIsTrue(d.vis_admin)) { - if (user->isSelf()) { - // #TODO groups -// chat->addFlags(MTPDchat::Flag::f_admin); - } - if (chat->noParticipantInfo()) { - Auth().api().requestFullPeer(chat); - } else { - chat->admins.insert(user); - } - } else { - if (user->isSelf()) { - // #TODO groups - //chat->removeFlags(MTPDchat::Flag::f_admin); - } - chat->admins.remove(user); - } - } else { - chat->invalidateParticipants(); - } - Notify::peerUpdatedDelayed(chat, Notify::PeerUpdate::Flag::AdminsChanged); - } - } - bool checkEntitiesAndViewsUpdate(const MTPDmessage &m) { auto peerId = peerFromMTP(m.vto_id); if (m.has_from_id() && peerId == Auth().userPeerId()) { diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 5d729dd38..7d5f74277 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -70,10 +70,6 @@ namespace App { PeerData *feedChat(const MTPChat &chat); PeerData *feedChats(const MTPVector &chats); // returns last chat - void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos); - void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d); - void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d); - void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d); bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached void updateEditedMessage(const MTPMessage &m); void addSavedGif(DocumentData *doc); diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 1ee4fba40..774b650a7 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -1183,26 +1183,27 @@ RevokePublicLinkBox::Inner::Inner(QWidget *parent, Fn revokeCallback) : request(MTPchannels_GetAdminedPublicChannels( )).done([=](const MTPmessages_Chats &result) { - if (auto chats = Api::getChatsFromMessagesChats(result)) { - for_const (auto &chat, chats->v) { - if (auto peer = App::feedChat(chat)) { - if (!peer->isChannel() || peer->userName().isEmpty()) { - continue; - } - - auto row = ChatRow(peer); - row.peer = peer; - row.name.setText( - st::contactsNameStyle, - peer->name, - Ui::NameTextOptions()); - row.status.setText( - st::defaultTextStyle, - Messenger::Instance().createInternalLink( - textcmdLink(1, peer->userName())), - Ui::DialogTextOptions()); - _rows.push_back(std::move(row)); + const auto &chats = result.match([](const auto &data) { + return data.vchats.v; + }); + for (const auto &chat : chats) { + if (const auto peer = App::feedChat(chat)) { + if (!peer->isChannel() || peer->userName().isEmpty()) { + continue; } + + auto row = ChatRow(peer); + row.peer = peer; + row.name.setText( + st::contactsNameStyle, + peer->name, + Ui::NameTextOptions()); + row.status.setText( + st::defaultTextStyle, + Messenger::Instance().createInternalLink( + textcmdLink(1, peer->userName())), + Ui::DialogTextOptions()); + _rows.push_back(std::move(row)); } } resize(width(), _rows.size() * _rowHeight); diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index d19682b39..eaa3c4226 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -30,12 +30,7 @@ base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { return {}; } if (const auto chat = peer->asChat()) { - const auto participants = ( - chat->participants - ) | ranges::view::transform([](auto &&pair) -> not_null { - return pair.first; - }); - return { participants.begin(), participants.end() }; + return chat->participants; } else if (const auto channel = peer->asChannel()) { if (channel->isMegagroup()) { const auto &participants = channel->mgInfo->lastParticipants; @@ -306,7 +301,7 @@ void AddSpecialBoxController::rebuildChatRows(not_null chat) { --count; } } - for (const auto [user, v] : participants) { + for (const auto user : participants) { if (auto row = createRow(user)) { delegate()->peerListAppendRow(std::move(row)); } @@ -976,7 +971,7 @@ void AddSpecialBoxSearchController::addChatMembers( return true; }; - for (const auto [user, v] : chat->participants) { + for (const auto user : chat->participants) { if (allWordsAreFound(user->nameWords())) { delegate()->peerListSearchAddRow(user); } diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index ef8856a86..aa7014271 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -47,13 +47,9 @@ void RemoveAdmin( )).done([=](const MTPUpdates &result) { channel->session().api().applyUpdates(result); channel->applyEditAdmin(user, oldRights, newRights); - if (const auto done = onDone) { - done(); - } + onDone(); }).fail([=](const RPCError &error) { - if (const auto fail = onFail) { - fail(); - } + onFail(); }).send(); } @@ -69,13 +65,9 @@ void SaveChatAdmin( MTP_bool(isAdmin) )).done([=](const MTPBool &result) { chat->applyEditAdmin(user, isAdmin); - if (const auto done = onDone) { - done(); - } + onDone(); }).fail([=](const RPCError &error) { - if (const auto fail = onFail) { - fail(); - } + onFail(); }).send(); } @@ -93,9 +85,7 @@ void SaveChannelAdmin( )).done([=](const MTPUpdates &result) { channel->session().api().applyUpdates(result); channel->applyEditAdmin(user, oldRights, newRights); - if (const auto done = onDone) { - done(); - } + onDone(); }).fail([=](const RPCError &error) { if (error.type() == qstr("USER_NOT_MUTUAL_CONTACT")) { Ui::show( @@ -115,9 +105,7 @@ void SaveChannelAdmin( : lng_error_admin_limit_channel)), LayerOption::KeepOther); } - if (const auto fail = onFail) { - fail(); - } + onFail(); }).send(); } @@ -133,16 +121,11 @@ void SaveChannelRestriction( user->inputUser, newRights )).done([=](const MTPUpdates &result) { - const auto done = onDone; channel->session().api().applyUpdates(result); channel->applyEditBanned(user, oldRights, newRights); - if (const auto done = onDone) { - done(); - } + onDone(); }).fail([=](const RPCError &error) { - if (const auto fail = onFail) { - fail(); - } + onFail(); }).send(); } @@ -368,12 +351,7 @@ void ParticipantsAdditionalData::fillFromChat(not_null chat) { if (chat->participants.empty()) { return; } - const auto keys = ranges::view::all( - chat->participants - ) | ranges::view::transform([](auto &&pair) { - return pair.first; - }); - _members = { keys.begin(), keys.end() }; + _members = chat->participants; _admins = chat->admins; } @@ -794,7 +772,7 @@ void ParticipantsBoxController::addNewParticipants() { auto already = std::vector>(); already.reserve(count); for (auto i = 0; i != count; ++i) { - already.push_back( + already.emplace_back( delegate()->peerListRowAt(i)->peer()->asUser()); } AddParticipantsBoxController::Start( @@ -805,16 +783,18 @@ void ParticipantsBoxController::addNewParticipants() { } } -void ParticipantsBoxController::peerListSearchAddRow(not_null peer) { +void ParticipantsBoxController::peerListSearchAddRow( + not_null peer) { PeerListController::peerListSearchAddRow(peer); - if (_role == Role::Restricted && delegate()->peerListFullRowsCount() > 0) { + if (_role == Role::Restricted + && delegate()->peerListFullRowsCount() > 0) { setDescriptionText(QString()); } } std::unique_ptr ParticipantsBoxController::createSearchRow( not_null peer) { - if (auto user = peer->asUser()) { + if (const auto user = peer->asUser()) { return createRow(user); } return nullptr; @@ -822,13 +802,14 @@ std::unique_ptr ParticipantsBoxController::createSearchRow( std::unique_ptr ParticipantsBoxController::createRestoredRow( not_null peer) { - if (auto user = peer->asUser()) { + if (const auto user = peer->asUser()) { return createRow(user); } return nullptr; } -std::unique_ptr ParticipantsBoxController::saveState() const { +auto ParticipantsBoxController::saveState() const +-> std::unique_ptr { Expects(_role == Role::Profile); auto result = PeerListController::saveState(); @@ -837,14 +818,19 @@ std::unique_ptr ParticipantsBoxController::saveState() const { my->offset = _offset; my->allLoaded = _allLoaded; my->wasLoading = (_loadRequestId != 0); - if (auto search = searchController()) { + if (const auto search = searchController()) { my->searchState = search->saveState(); } - if (_peer->isMegagroup()) { - const auto channel = _peer->asChannel(); - - auto weak = result.get(); + const auto weak = result.get(); + if (const auto chat = _peer->asChat()) { + Notify::PeerUpdateViewer( + chat, + Notify::PeerUpdate::Flag::MembersChanged + ) | rpl::start_with_next([=](const Notify::PeerUpdate &) { + weak->controllerState = nullptr; + }, my->lifetime); + } else if (const auto channel = _peer->asMegagroup()) { channel->owner().megagroupParticipantAdded( channel ) | rpl::start_with_next([=](not_null user) { @@ -855,7 +841,7 @@ std::unique_ptr ParticipantsBoxController::saveState() const { } auto pos = ranges::find(weak->list, user); if (pos == weak->list.cend()) { - weak->list.push_back(user); + weak->list.emplace_back(user); } ranges::stable_partition( weak->list, @@ -884,15 +870,15 @@ void ParticipantsBoxController::restoreState( auto typeErasedState = state ? state->controllerState.get() : nullptr; - if (auto my = dynamic_cast(typeErasedState)) { - if (auto requestId = base::take(_loadRequestId)) { + if (const auto my = dynamic_cast(typeErasedState)) { + if (const auto requestId = base::take(_loadRequestId)) { request(requestId).cancel(); } _additional = std::move(my->additional); _offset = my->offset; _allLoaded = my->allLoaded; - if (auto search = searchController()) { + if (const auto search = searchController()) { search->restoreState(std::move(my->searchState)); } if (my->wasLoading) { @@ -989,13 +975,8 @@ void ParticipantsBoxController::rebuildChatRows(not_null chat) { void ParticipantsBoxController::rebuildChatParticipants( not_null chat) { - if (chat->participants.empty()) { - // We get such updates often - // (when participants list was invalidated). - //while (delegate()->peerListFullRowsCount() > 0) { - // delegate()->peerListRemoveRow( - // delegate()->peerListRowAt(0)); - //} + if (chat->noParticipantInfo()) { + chat->updateFullForced(); return; } @@ -1011,7 +992,7 @@ void ParticipantsBoxController::rebuildChatParticipants( --count; } } - for (const auto [user, v] : participants) { + for (const auto user : participants) { if (auto row = createRow(user)) { delegate()->peerListAppendRow(std::move(row)); } @@ -1036,7 +1017,7 @@ void ParticipantsBoxController::rebuildChatAdmins( auto list = ranges::view::all(chat->admins) | ranges::to_vector; if (const auto creator = chat->owner().userLoaded(chat->creator)) { - list.push_back(creator); + list.emplace_back(creator); } ranges::sort(list, [](not_null a, not_null b) { return (a->name.compare(b->name, Qt::CaseInsensitive) < 0); diff --git a/Telegram/SourceFiles/boxes/share_box.cpp b/Telegram/SourceFiles/boxes/share_box.cpp index 7c86dd227..3a81e7002 100644 --- a/Telegram/SourceFiles/boxes/share_box.cpp +++ b/Telegram/SourceFiles/boxes/share_box.cpp @@ -1175,11 +1175,11 @@ void ShareGameScoreByHash(const QString &hash) { } else { auto requestChannelIds = MTP_vector(1, MTP_inputChannel(MTP_int(channelId), MTP_long(channelAccessHash))); auto requestChannel = MTPchannels_GetChannels(requestChannelIds); - MTP::send(requestChannel, rpcDone([channelId, resolveMessageAndShareScore](const MTPmessages_Chats &result) { - if (auto chats = Api::getChatsFromMessagesChats(result)) { - App::feedChats(*chats); - } - if (auto channel = App::channelLoaded(channelId)) { + MTP::send(requestChannel, rpcDone([=](const MTPmessages_Chats &result) { + result.match([](const auto &data) { + App::feedChats(data.vchats); + }); + if (const auto channel = App::channelLoaded(channelId)) { resolveMessageAndShareScore(channel); } })); diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index da032df64..8c3fb451b 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -194,7 +194,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { if (_chat->noParticipantInfo()) { Auth().api().requestFullPeer(_chat); } else if (!_chat->participants.empty()) { - for (const auto [user, v] : _chat->participants) { + for (const auto user : _chat->participants) { if (user->isInaccessible()) continue; if (!listAllSuggestions && filterNotPassedByName(user)) continue; if (indexOfInFirstN(mrows, user, recentInlineBots) >= 0) continue; @@ -253,7 +253,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) { if (_chat->noParticipantInfo()) { Auth().api().requestFullPeer(_chat); } else if (!_chat->participants.empty()) { - for (const auto [user, version] : _chat->participants) { + for (const auto user : _chat->participants) { if (!user->botInfo) continue; if (!user->botInfo->inited) { Auth().api().requestFullPeer(user); diff --git a/Telegram/SourceFiles/core/changelogs.cpp b/Telegram/SourceFiles/core/changelogs.cpp index 85ddc0f47..95190cff3 100644 --- a/Telegram/SourceFiles/core/changelogs.cpp +++ b/Telegram/SourceFiles/core/changelogs.cpp @@ -157,7 +157,7 @@ void Changelogs::addLocalLog(const QString &text) { }; void Changelogs::addBetaLogs() { - for (const auto[version, changes] : BetaLogs()) { + for (const auto [version, changes] : BetaLogs()) { addBetaLog(version, changes); } } diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index d840a2bdf..9b9a09b25 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_feed.h" #include "observer_peer.h" #include "auth_session.h" +#include "apiwrap.h" namespace { @@ -482,3 +483,28 @@ void ChannelData::setDefaultRestrictions(const MTPChatBannedRights &rights) { _defaultRestrictions.set(rights.c_chatBannedRights().vflags.v); Notify::peerUpdatedDelayed(this, UpdateFlag::RightsChanged); } + +auto ChannelData::applyUpdateVersion(int version) -> UpdateStatus { + if (_version > version) { + return UpdateStatus::TooOld; + } else if (_version + 1 < version) { + session().api().requestPeer(this); + return UpdateStatus::Skipped; + } + setVersion(version); + return UpdateStatus::Good; +} + +namespace Data { + +void ApplyChannelUpdate( + not_null channel, + const MTPDupdateChatDefaultBannedRights &update) { + if (channel->applyUpdateVersion(update.vversion.v) + != ChannelData::UpdateStatus::Good) { + return; + } + channel->setDefaultRestrictions(update.vdefault_banned_rights); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 637e2d2a4..99df5874f 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -326,6 +326,19 @@ public: return _feed; } + enum class UpdateStatus { + Good, + TooOld, + Skipped, + }; + int version() const { + return _version; + } + void setVersion(int version) { + _version = version; + } + UpdateStatus applyUpdateVersion(int version); + // Still public data members. uint64 access = 0; @@ -334,7 +347,6 @@ public: QString username; int32 date = 0; - int version = 0; std::unique_ptr mgInfo; UserId inviter = 0; // > 0 - user who invited me to channel, < 0 - not in channel @@ -354,6 +366,7 @@ private: int _restrictedCount = 0; int _kickedCount = 0; MsgId _availableMinId = 0; + int _version = 0; RestrictionFlags _defaultRestrictions; AdminRightFlags _adminRights; @@ -368,3 +381,11 @@ private: rpl::lifetime _lifetime; }; + +namespace Data { + +void ApplyChannelUpdate( + not_null channel, + const MTPDupdateChatDefaultBannedRights &update); + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index 52649bd70..c8b37fde6 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -7,6 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "data/data_chat.h" +#include "data/data_user.h" +#include "data/data_session.h" +#include "history/history.h" +#include "auth_session.h" +#include "apiwrap.h" #include "observer_peer.h" namespace { @@ -113,10 +118,10 @@ void ChatData::applyEditAdmin(not_null user, bool isAdmin) { } void ChatData::invalidateParticipants() { - // #TODO groups participants.clear(); admins.clear(); - //removeFlags(MTPDchat::Flag::f_admin); + setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + //setDefaultRestrictions(MTP_chatBannedRights(MTP_flags(0), MTP_int(0))); invitedByMe.clear(); botStatus = 0; Notify::peerUpdatedDelayed( @@ -150,3 +155,242 @@ void ChatData::setDefaultRestrictions(const MTPChatBannedRights &rights) { _defaultRestrictions.set(rights.c_chatBannedRights().vflags.v); Notify::peerUpdatedDelayed(this, UpdateFlag::RightsChanged); } + +void ChatData::refreshBotStatus() { + if (participants.empty()) { + botStatus = 0; + } else { + const auto bot = ranges::find_if(participants, &UserData::isBot); + botStatus = (bot == end(participants)) ? -1 : 2; + } +} + +auto ChatData::applyUpdateVersion(int version) -> UpdateStatus { + if (_version > version) { + return UpdateStatus::TooOld; + } else if (_version + 1 < version) { + invalidateParticipants(); + session().api().requestPeer(this); + return UpdateStatus::Skipped; + } + setVersion(version); + return UpdateStatus::Good; +} + +namespace Data { + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipants &update) { + ApplyChatParticipants(chat, update.vparticipants); +} + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantAdd &update) { + if (chat->applyUpdateVersion(update.vversion.v) + != ChatData::UpdateStatus::Good) { + return; + } else if (chat->count < 0) { + return; + } + const auto user = chat->owner().userLoaded(update.vuser_id.v); + if (!user + || (!chat->participants.empty() + && chat->participants.contains(user))) { + chat->invalidateParticipants(); + ++chat->count; + return; + } + if (chat->participants.empty()) { + if (chat->count > 0) { // If the count is known. + ++chat->count; + } + chat->botStatus = 0; + } else { + chat->participants.emplace(user); + if (update.vinviter_id.v == chat->session().userId()) { + chat->invitedByMe.insert(user); + } else { + chat->invitedByMe.remove(user); + } + ++chat->count; + if (user->isBot()) { + chat->botStatus = 2; + if (!user->botInfo->inited) { + chat->session().api().requestFullPeer(user); + } + } + } + Notify::peerUpdatedDelayed( + chat, + Notify::PeerUpdate::Flag::MembersChanged); +} + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantDelete &update) { + if (chat->applyUpdateVersion(update.vversion.v) + != ChatData::UpdateStatus::Good) { + return; + } else if (chat->count <= 0) { + return; + } + const auto user = chat->owner().userLoaded(update.vuser_id.v); + if (!user + || (!chat->participants.empty() + && !chat->participants.contains(user))) { + chat->invalidateParticipants(); + --chat->count; + return; + } + if (chat->participants.empty()) { + if (chat->count > 0) { + chat->count--; + } + chat->botStatus = 0; + } else { + chat->participants.erase(user); + chat->count--; + chat->invitedByMe.remove(user); + chat->admins.remove(user); + if (user->isSelf()) { + chat->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + } + if (const auto history = chat->owner().historyLoaded(chat)) { + if (history->lastKeyboardFrom == user->id) { + history->clearLastKeyboard(); + } + } + if (chat->botStatus > 0 && user->botInfo) { + chat->refreshBotStatus(); + } + } + Notify::peerUpdatedDelayed( + chat, + Notify::PeerUpdate::Flag::MembersChanged); +} + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantAdmin &update) { + if (chat->applyUpdateVersion(update.vversion.v) + != ChatData::UpdateStatus::Good) { + return; + } + + const auto user = chat->owner().userLoaded(update.vuser_id.v); + if (!user) { + chat->invalidateParticipants(); + return; + } + if (user->isSelf()) { + chat->setAdminRights(MTP_chatAdminRights(mtpIsTrue(update.vis_admin) + ? MTP_flags(ChatData::DefaultAdminRights()) + : MTP_flags(0))); + } + if (mtpIsTrue(update.vis_admin)) { + if (chat->noParticipantInfo()) { + chat->session().api().requestFullPeer(chat); + } else { + chat->admins.emplace(user); + } + } else { + chat->admins.erase(user); + } + Notify::peerUpdatedDelayed( + chat, + Notify::PeerUpdate::Flag::AdminsChanged); +} + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatDefaultBannedRights &update) { + if (chat->applyUpdateVersion(update.vversion.v) + != ChatData::UpdateStatus::Good) { + return; + } + chat->setDefaultRestrictions(update.vdefault_banned_rights); +} + +void ApplyChatParticipants( + not_null chat, + const MTPChatParticipants &participants) { + participants.match([&](const MTPDchatParticipantsForbidden &data) { + if (data.has_self_participant()) { + // data.vself_participant. + } + chat->count = -1; + chat->invalidateParticipants(); + }, [&](const MTPDchatParticipants &data) { + const auto status = chat->applyUpdateVersion(data.vversion.v); + if (status == ChatData::UpdateStatus::TooOld) { + return; + } + // Even if we skipped some updates, we got current participants + // and we've requested peer from API to have current rights. + chat->setVersion(data.vversion.v); + + const auto &list = data.vparticipants.v; + chat->count = list.size(); + chat->participants.clear(); + chat->invitedByMe.clear(); + chat->admins.clear(); + chat->setAdminRights(MTP_chatAdminRights(MTP_flags(0))); + const auto selfUserId = chat->session().userId(); + for (const auto &participant : list) { + const auto userId = participant.match([&](const auto &data) { + return data.vuser_id.v; + }); + const auto user = chat->owner().userLoaded(userId); + if (!user) { + chat->invalidateParticipants(); + break; + } + + chat->participants.emplace(user); + + const auto inviterId = participant.match([&]( + const MTPDchatParticipantCreator &data) { + return 0; + }, [&](const auto &data) { + return data.vinviter_id.v; + }); + if (inviterId == selfUserId) { + chat->invitedByMe.insert(user); + } + + participant.match([&](const MTPDchatParticipantCreator &data) { + chat->creator = userId; + }, [&](const MTPDchatParticipantAdmin &data) { + chat->admins.emplace(user); + if (user->isSelf()) { + chat->setAdminRights(MTP_chatAdminRights( + MTP_flags(ChatData::DefaultAdminRights()))); + } + }, [](const MTPDchatParticipant &) { + }); + } + if (chat->participants.empty()) { + return; + } + if (const auto history = chat->owner().historyLoaded(chat)) { + if (history->lastKeyboardFrom) { + const auto i = ranges::find( + chat->participants, + history->lastKeyboardFrom, + &UserData::id); + if (i == end(chat->participants)) { + history->clearLastKeyboard(); + } + } + } + chat->refreshBotStatus(); + Notify::peerUpdatedDelayed( + chat, + Notify::PeerUpdate::Flag::MembersChanged + | Notify::PeerUpdate::Flag::AdminsChanged); + }); +} + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h index d6f248b3d..41ec72234 100644 --- a/Telegram/SourceFiles/data/data_chat.h +++ b/Telegram/SourceFiles/data/data_chat.h @@ -141,6 +141,20 @@ public: QString inviteLink() const { return _inviteLink; } + void refreshBotStatus(); + + enum class UpdateStatus { + Good, + TooOld, + Skipped, + }; + int version() const { + return _version; + } + void setVersion(int version) { + _version = version; + } + UpdateStatus applyUpdateVersion(int version); // Still public data members. MTPint inputChat; @@ -149,10 +163,9 @@ public: int count = 0; TimeId date = 0; - int version = 0; UserId creator = 0; - base::flat_map, int> participants; + base::flat_set> participants; base::flat_set> invitedByMe; base::flat_set> admins; std::deque> lastAuthors; @@ -169,5 +182,30 @@ private: RestrictionFlags _defaultRestrictions; AdminRightFlags _adminRights; + int _version = 0; }; + +namespace Data { + +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipants &update); +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantAdd &update); +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantDelete &update); +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatParticipantAdmin &update); +void ApplyChatUpdate( + not_null chat, + const MTPDupdateChatDefaultBannedRights &update); + +void ApplyChatParticipants( + not_null chat, + const MTPChatParticipants &participants); + +} // namespace Data diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index c53567464..6358a484f 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -350,10 +350,9 @@ bool PeerData::canPinMessages() const { if (const auto user = asUser()) { return user->fullFlags() & MTPDuserFull::Flag::f_can_pin_message; } else if (const auto chat = asChat()) { - // #TODO groups return !chat->isDeactivated() - /*&& ((chat->adminRights() & ChatAdminRight::f_pin_messages) - || chat->amCreator())*/; + && ((chat->adminRights() & ChatAdminRight::f_pin_messages) + || chat->amCreator()); } else if (const auto channel = asChannel()) { if (channel->isMegagroup()) { return (channel->adminRights() & ChatAdminRight::f_pin_messages) diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index b555d3616..531874a50 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -430,9 +430,8 @@ not_null Session::chat(const MTPChat &data) { const auto chat = result->asChat(); const auto canAddMembers = chat->canAddMembers(); - - if (chat->version < data.vversion.v) { - chat->version = data.vversion.v; + if (chat->version() < data.vversion.v) { + chat->setVersion(data.vversion.v); chat->invalidateParticipants(); } @@ -561,8 +560,8 @@ not_null Session::chat(const MTPChat &data) { channel->inputChannel = MTP_inputChannel(data.vid, data.vaccess_hash); channel->access = data.vaccess_hash.v; channel->date = data.vdate.v; - if (channel->version < data.vversion.v) { - channel->version = data.vversion.v; + if (channel->version() < data.vversion.v) { + channel->setVersion(data.vversion.v); } channel->setUnavailableReason(data.is_restricted() ? ExtractUnavailableReason(qs(data.vrestriction_reason)) @@ -657,6 +656,25 @@ PeerData *Session::processChats(const MTPVector &data) { return result; } +void Session::applyMaximumChatVersions(const MTPVector &data) { + for (const auto &chat : data.v) { + chat.match([&](const MTPDchat &data) { + if (const auto chat = chatLoaded(data.vid.v)) { + if (data.vversion.v < chat->version()) { + chat->setVersion(data.vversion.v); + } + } + }, [&](const MTPDchannel &data) { + if (const auto channel = channelLoaded(data.vid.v)) { + if (data.vversion.v < channel->version()) { + channel->setVersion(data.vversion.v); + } + } + }, [](const auto &) { + }); + } +} + PeerData *Session::peerByUsername(const QString &username) const { const auto uname = username.trimmed(); for (const auto &[peerId, peer] : _peers) { @@ -2372,7 +2390,7 @@ not_null Session::poll(const MTPDmessageMediaPoll &data) { return result; } -void Session::applyPollUpdate(const MTPDupdateMessagePoll &update) { +void Session::applyUpdate(const MTPDupdateMessagePoll &update) { const auto updated = [&] { const auto i = _polls.find(update.vpoll_id.v); return (i == end(_polls)) @@ -2386,6 +2404,51 @@ void Session::applyPollUpdate(const MTPDupdateMessagePoll &update) { } } +void Session::applyUpdate(const MTPDupdateChatParticipants &update) { + const auto chatId = update.vparticipants.match([](const auto &update) { + return update.vchat_id.v; + }); + if (const auto chat = chatLoaded(chatId)) { + ApplyChatUpdate(chat, update); + for (const auto user : chat->participants) { + if (user->botInfo && !user->botInfo->inited) { + _session->api().requestFullPeer(user); + } + } + } +} + +void Session::applyUpdate(const MTPDupdateChatParticipantAdd &update) { + if (const auto chat = chatLoaded(update.vchat_id.v)) { + ApplyChatUpdate(chat, update); + } +} + +void Session::applyUpdate(const MTPDupdateChatParticipantDelete &update) { + if (const auto chat = chatLoaded(update.vchat_id.v)) { + ApplyChatUpdate(chat, update); + } +} + +void Session::applyUpdate(const MTPDupdateChatParticipantAdmin &update) { + if (const auto chat = chatLoaded(update.vchat_id.v)) { + ApplyChatUpdate(chat, update); + } +} + +void Session::applyUpdate(const MTPDupdateChatDefaultBannedRights &update) { + if (const auto peer = peerLoaded(peerFromMTP(update.vpeer))) { + if (const auto chat = peer->asChat()) { + ApplyChatUpdate(chat, update); + } else if (const auto channel = peer->asChannel()) { + ApplyChannelUpdate(channel, update); + } else { + LOG(("API Error: " + "User received in updateChatDefaultBannedRights.")); + } + } +} + not_null Session::location(const LocationCoords &coords) { auto i = _locations.find(coords); if (i == _locations.cend()) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index b5fe9b616..beffba7a6 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -103,6 +103,8 @@ public: UserData *processUsers(const MTPVector &data); PeerData *processChats(const MTPVector &data); + void applyMaximumChatVersions(const MTPVector &data); + void enumerateUsers(Fn)> action) const; void enumerateGroups(Fn)> action) const; void enumerateChannels(Fn)> action) const; @@ -270,6 +272,13 @@ public: MessageIdsList itemsToIds(const HistoryItemsList &items) const; MessageIdsList itemOrItsGroup(not_null item) const; + void applyUpdate(const MTPDupdateMessagePoll &update); + void applyUpdate(const MTPDupdateChatParticipants &update); + void applyUpdate(const MTPDupdateChatParticipantAdd &update); + void applyUpdate(const MTPDupdateChatParticipantDelete &update); + void applyUpdate(const MTPDupdateChatParticipantAdmin &update); + void applyUpdate(const MTPDupdateChatDefaultBannedRights &update); + int pinnedDialogsCount() const; const std::deque &pinnedDialogsOrder() const; void setPinnedDialog(const Dialogs::Key &key, bool pinned); @@ -403,7 +412,6 @@ public: not_null poll(PollId id); not_null poll(const MTPPoll &data); not_null poll(const MTPDmessageMediaPoll &data); - void applyPollUpdate(const MTPDupdateMessagePoll &update); not_null location(const LocationCoords &coords); diff --git a/Telegram/SourceFiles/data/data_user.h b/Telegram/SourceFiles/data/data_user.h index 9cba58edb..3bcef79cd 100644 --- a/Telegram/SourceFiles/data/data_user.h +++ b/Telegram/SourceFiles/data/data_user.h @@ -122,6 +122,9 @@ public: bool isBotInlineGeo() const { return flags() & MTPDuser::Flag::f_bot_inline_geo; } + bool isBot() const { + return botInfo != nullptr; + } bool isInaccessible() const { constexpr auto inaccessible = 0 | MTPDuser::Flag::f_deleted; diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp index 78ae32bc3..286279476 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp @@ -96,7 +96,7 @@ void ChatSearchFromController::rebuildRows() { if (_chat->noParticipantInfo()) { Auth().api().requestFullPeer(_chat); } else if (!_chat->participants.empty()) { - for (const auto [user, version] : _chat->participants) { + for (const auto user : _chat->participants) { ordered.insertMulti(byOnline(user), user); } } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 2ee67ede7..6b17818a4 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -506,8 +506,9 @@ bool HistoryItem::canDeleteForEveryone(TimeId now) const { } if (!out()) { if (const auto chat = peer->asChat()) { - // #TODO groups - if (!chat->amCreator()/* && (!chat->amAdmin() || !chat->adminsEnabled())*/) { + if (!chat->amCreator() + && !(chat->adminRights() + & ChatAdminRight::f_delete_messages)) { return false; } } else if (peer->isUser()) { diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index 27a6369a3..0d63e9fc7 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -758,7 +758,7 @@ void TopBarWidget::updateOnlineDisplay() { const auto self = Auth().user(); auto online = 0; auto onlyMe = true; - for (const auto [user, v] : chat->participants) { + for (const auto user : chat->participants) { if (user->onlineTill > now) { ++online; if (onlyMe && user != self) onlyMe = false; @@ -826,7 +826,7 @@ void TopBarWidget::updateOnlineDisplayTimer() { if (const auto user = _activeChat.peer()->asUser()) { handleUser(user); } else if (auto chat = _activeChat.peer()->asChat()) { - for (const auto [user, v] : chat->participants) { + for (const auto user : chat->participants) { handleUser(user); } } else if (_activeChat.peer()->isChannel()) { diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp index 81af9b51d..16ef90930 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp @@ -97,21 +97,21 @@ void ListController::loadMoreRows() { _preloadRequestId = 0; _preloadGroupId = 0; _allLoaded = true; - if (auto chats = Api::getChatsFromMessagesChats(result)) { - auto &list = chats->v; - if (!list.empty()) { - for_const (auto &chatData, list) { - if (auto chat = App::feedChat(chatData)) { - if (!chat->migrateTo()) { - delegate()->peerListAppendRow( - createRow(chat)); - } - _preloadGroupId = chat->bareId(); - _allLoaded = false; + const auto &chats = result.match([](const auto &data) { + return data.vchats.v; + }); + if (!chats.empty()) { + for (const auto &chatData : chats) { + if (const auto chat = App::feedChat(chatData)) { + if (!chat->migrateTo()) { + delegate()->peerListAppendRow( + createRow(chat)); } + _preloadGroupId = chat->bareId(); + _allLoaded = false; } - delegate()->peerListRefreshRows(); } + delegate()->peerListRefreshRows(); } auto fullCount = delegate()->peerListFullRowsCount(); if (fullCount > kCommonGroupsSearchAfter) { diff --git a/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp b/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp index ea4fb04d7..77ebf3594 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp @@ -26,288 +26,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Info { namespace Profile { -namespace { - -constexpr auto kSortByOnlineDelay = TimeMs(1000); - -class ChatMembersController - : public PeerListController - , private base::Subscriber - , public base::has_weak_ptr { -public: - ChatMembersController( - not_null navigation, - not_null chat); - - void prepare() override; - void rowClicked(not_null row) override; - void rowActionClicked(not_null row) override; - base::unique_qptr rowContextMenu( - QWidget *parent, - not_null row) override; - - rpl::producer onlineCountValue() const override { - return _onlineCount.value(); - } - - std::unique_ptr createRestoredRow( - not_null peer) override; - - std::unique_ptr saveState() const override; - void restoreState(std::unique_ptr state) override; - -private: - using Rights = MemberListRow::Rights; - using Type = MemberListRow::Type; - struct SavedState : SavedStateBase { - rpl::lifetime lifetime; - }; - void rebuildRows(); - void rebuildRowTypes(); - void refreshOnlineCount(); - std::unique_ptr createRow( - not_null user); - void sortByOnline(); - void sortByOnlineDelayed(); - void removeMember(not_null user); - Type computeType(not_null user); - - not_null _navigation; - not_null _chat; - - base::Timer _sortByOnlineTimer; - rpl::variable _onlineCount = 0; - -}; - -ChatMembersController::ChatMembersController( - not_null navigation, - not_null chat) -: PeerListController() -, _navigation(navigation) -, _chat(chat) { - _sortByOnlineTimer.setCallback([this] { sortByOnline(); }); -} - -void ChatMembersController::prepare() { - setSearchNoResultsText(lang(lng_blocked_list_not_found)); - delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); - delegate()->peerListSetTitle(langFactory(lng_channel_admins)); - - rebuildRows(); - if (!delegate()->peerListFullRowsCount()) { - Auth().api().requestFullPeer(_chat); - } - using UpdateFlag = Notify::PeerUpdate::Flag; - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler( - UpdateFlag::MembersChanged - | UpdateFlag::UserOnlineChanged - | UpdateFlag::AdminsChanged, - [this](const Notify::PeerUpdate &update) { - if (update.peer == _chat) { - if (update.flags & UpdateFlag::MembersChanged) { - rebuildRows(); - } - if (update.flags & UpdateFlag::AdminsChanged) { - rebuildRowTypes(); - } - } - if (update.flags & UpdateFlag::UserOnlineChanged) { - if (auto row = delegate()->peerListFindRow( - update.peer->id)) { - row->refreshStatus(); - sortByOnlineDelayed(); - } - } - })); -} - -void ChatMembersController::sortByOnlineDelayed() { - if (!_sortByOnlineTimer.isActive()) { - _sortByOnlineTimer.callOnce(kSortByOnlineDelay); - } -} - -void ChatMembersController::sortByOnline() { - auto now = unixtime(); - delegate()->peerListSortRows([now]( - const PeerListRow &a, - const PeerListRow &b) { - return Data::SortByOnlineValue(a.peer()->asUser(), now) > - Data::SortByOnlineValue(b.peer()->asUser(), now); - }); - refreshOnlineCount(); -} - -std::unique_ptr ChatMembersController::saveState() const { - auto result = PeerListController::saveState(); - auto my = std::make_unique(); - using Flag = Notify::PeerUpdate::Flag; - Notify::PeerUpdateViewer( - _chat, - Flag::MembersChanged - ) | rpl::start_with_next([state = result.get()](auto update) { - state->controllerState = nullptr; - }, my->lifetime); - result->controllerState = std::move(my); - return result; -} - -void ChatMembersController::restoreState( - std::unique_ptr state) { - PeerListController::restoreState(std::move(state)); - sortByOnline(); -} - -void ChatMembersController::rebuildRows() { - if (_chat->participants.empty()) { - // We get such updates often - // (when participants list was invalidated). - //while (delegate()->peerListFullRowsCount() > 0) { - // delegate()->peerListRemoveRow( - // delegate()->peerListRowAt(0)); - //} - return; - } - - auto &participants = _chat->participants; - for (auto i = 0, count = delegate()->peerListFullRowsCount(); - i != count;) { - auto row = delegate()->peerListRowAt(i); - auto user = row->peer()->asUser(); - if (participants.contains(user)) { - ++i; - } else { - delegate()->peerListRemoveRow(row); - --count; - } - } - for (const auto [user, v] : participants) { - if (auto row = createRow(user)) { - delegate()->peerListAppendRow(std::move(row)); - } - } - sortByOnline(); - - delegate()->peerListRefreshRows(); -} - -void ChatMembersController::rebuildRowTypes() { - auto count = delegate()->peerListFullRowsCount(); - for (auto i = 0; i != count; ++i) { - auto row = static_cast( - delegate()->peerListRowAt(i).get()); - row->setType(computeType(row->user())); - } - delegate()->peerListRefreshRows(); -} - -void ChatMembersController::refreshOnlineCount() { - auto now = unixtime(); - auto left = 0, right = delegate()->peerListFullRowsCount(); - while (right > left) { - auto middle = (left + right) / 2; - auto row = delegate()->peerListRowAt(middle); - if (Data::OnlineTextActive(row->peer()->asUser(), now)) { - left = middle + 1; - } else { - right = middle; - } - } - _onlineCount = left; -} - -std::unique_ptr ChatMembersController::createRestoredRow( - not_null peer) { - if (auto user = peer->asUser()) { - return createRow(user); - } - return nullptr; -} - -std::unique_ptr ChatMembersController::createRow( - not_null user) { - return std::make_unique(user, computeType(user)); -} - -auto ChatMembersController::computeType( - not_null user) -> Type { - auto isCreator = (peerFromUser(_chat->creator) == user->id); - // #TODO groups - auto isAdmin = false;/* _chat->adminsEnabled() - && _chat->admins.contains(user);*/ - auto canRemove = false;/* [&] { - if (user->isSelf()) { - return false; - } else if (_chat->amCreator()) { - return true; - } else if (isAdmin || isCreator) { - return false; - } else if (_chat->amAdmin()) { - return true; - } else if (_chat->invitedByMe.contains(user)) { - return true; - } - return false; - }();*/ - - auto result = Type(); - result.rights = isCreator - ? Rights::Creator - : isAdmin - ? Rights::Admin - : Rights::Normal; - result.canRemove = canRemove; - return result; -} - -void ChatMembersController::rowClicked(not_null row) { - _navigation->showPeerInfo(row->peer()); -} - -void ChatMembersController::rowActionClicked( - not_null row) { - removeMember(row->peer()->asUser()); -} - -base::unique_qptr ChatMembersController::rowContextMenu( - QWidget *parent, - not_null row) { - auto my = static_cast(row.get()); - auto user = my->user(); - auto canRemoveMember = my->canRemove(); - - auto result = base::make_unique_q(parent); - result->addAction( - lang(lng_context_view_profile), - [weak = base::make_weak(this), user] { - if (weak) { - weak->_navigation->showPeerInfo(user); - } - }); - if (canRemoveMember) { - result->addAction( - lang(lng_context_remove_from_group), - [weak = base::make_weak(this), user] { - if (weak) { - weak->removeMember(user); - } - }); - } - - return result; -} - -void ChatMembersController::removeMember(not_null user) { - auto text = lng_profile_sure_kick(lt_user, user->firstName); - Ui::show(Box(text, lang(lng_box_remove), [user, chat = _chat] { - Ui::hideLayer(); - Auth().api().kickParticipant(chat, user); - Ui::showPeerHistory(chat->id, ShowAtTheEndMsgId); - })); -} - -} // namespace MemberListRow::MemberListRow( not_null user, @@ -379,17 +97,10 @@ void MemberListRow::paintNameIcon( std::unique_ptr CreateMembersController( not_null navigation, not_null peer) { - if (const auto chat = peer->asChat()) { - return std::make_unique( - navigation, - chat); - } else if (const auto channel = peer->asChannel()) { - return std::make_unique( - navigation, - channel, - ParticipantsBoxController::Role::Profile); - } - Unexpected("Peer type in CreateMembersController()"); + return std::make_unique( + navigation, + peer, + ParticipantsBoxController::Role::Profile); } } // namespace Profile diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 552567298..766f85be9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -4182,7 +4182,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateMessagePoll: { - Auth().data().applyPollUpdate(update.c_updateMessagePoll()); + Auth().data().applyUpdate(update.c_updateMessagePoll()); } break; case mtpc_updateUserTyping: { @@ -4216,47 +4216,23 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateChatParticipants: { - App::feedParticipants(update.c_updateChatParticipants().vparticipants, true); + Auth().data().applyUpdate(update.c_updateChatParticipants()); } break; case mtpc_updateChatParticipantAdd: { - App::feedParticipantAdd(update.c_updateChatParticipantAdd()); + Auth().data().applyUpdate(update.c_updateChatParticipantAdd()); } break; case mtpc_updateChatParticipantDelete: { - App::feedParticipantDelete(update.c_updateChatParticipantDelete()); - } break; - - case mtpc_updateChatDefaultBannedRights: { - const auto &data = update.c_updateChatDefaultBannedRights(); - const auto peerId = peerFromMTP(data.vpeer); - if (const auto peer = Auth().data().peerLoaded(peerId)) { - if (const auto chat = peer->asChat()) { - if (data.vversion.v == chat->version + 1) { - chat->setDefaultRestrictions( - data.vdefault_banned_rights); - } else { - chat->version = data.vversion.v; - chat->invalidateParticipants(); - Auth().api().requestPeer(chat); - } - } else if (const auto channel = peer->asChannel()) { - if (data.vversion.v == channel->version + 1) { - channel->setDefaultRestrictions( - data.vdefault_banned_rights); - } else { - channel->version = data.vversion.v; - Auth().api().requestPeer(channel); - } - } else { - LOG(("API Error: " - "User received in updateChatDefaultBannedRights.")); - } - } + Auth().data().applyUpdate(update.c_updateChatParticipantDelete()); } break; case mtpc_updateChatParticipantAdmin: { - App::feedParticipantAdmin(update.c_updateChatParticipantAdmin()); + Auth().data().applyUpdate(update.c_updateChatParticipantAdmin()); + } break; + + case mtpc_updateChatDefaultBannedRights: { + Auth().data().applyUpdate(update.c_updateChatDefaultBannedRights()); } break; case mtpc_updateUserStatus: { diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index 527b1d556..6b2942c49 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -411,7 +411,9 @@ template class MTPflags { public: Flags v = 0; - static_assert(sizeof(Flags) == sizeof(int32), "MTPflags are allowed only wrapping int32 flag types!"); + static_assert( + sizeof(Flags) == sizeof(int32), + "MTPflags are allowed only wrapping int32 flag types!"); MTPflags() = default; MTPflags(internal::ZeroFlagsHelper helper) { diff --git a/Telegram/SourceFiles/profile/profile_block_group_members.cpp b/Telegram/SourceFiles/profile/profile_block_group_members.cpp index 05bd7c5e2..3929530af 100644 --- a/Telegram/SourceFiles/profile/profile_block_group_members.cpp +++ b/Telegram/SourceFiles/profile/profile_block_group_members.cpp @@ -179,13 +179,13 @@ void GroupMembersWidget::updateItemStatusText(Item *item) { void GroupMembersWidget::refreshMembers() { _now = unixtime(); - if (auto chat = peer()->asChat()) { + if (const auto chat = peer()->asChat()) { checkSelfAdmin(chat); if (chat->noParticipantInfo()) { Auth().api().requestFullPeer(chat); } fillChatMembers(chat); - } else if (auto megagroup = peer()->asMegagroup()) { + } else if (const auto megagroup = peer()->asMegagroup()) { auto &megagroupInfo = megagroup->mgInfo; if (megagroupInfo->lastParticipants.empty() || megagroup->lastParticipantsCountOutdated()) { Auth().api().requestLastParticipants(megagroup); @@ -197,11 +197,12 @@ void GroupMembersWidget::refreshMembers() { refreshVisibility(); } -void GroupMembersWidget::checkSelfAdmin(ChatData *chat) { - if (chat->participants.empty()) return; +void GroupMembersWidget::checkSelfAdmin(not_null chat) { + if (chat->participants.empty()) { + return; + } - // #TODO groups - const auto self = Auth().user(); + const auto self = chat->session().user(); //if (chat->amAdmin() && !chat->admins.contains(self)) { // chat->admins.insert(self); //} else if (!chat->amAdmin() && chat->admins.contains(self)) { @@ -246,74 +247,95 @@ void GroupMembersWidget::updateOnlineCount() { } } -GroupMembersWidget::Member *GroupMembersWidget::addUser(ChatData *chat, UserData *user) { - auto member = computeMember(user); +auto GroupMembersWidget::addUser( + not_null chat, + not_null user) +-> not_null { + const auto member = computeMember(user); setItemFlags(member, chat); addItem(member); return member; } -void GroupMembersWidget::fillChatMembers(ChatData *chat) { - if (chat->participants.empty()) return; +void GroupMembersWidget::fillChatMembers(not_null chat) { + if (chat->participants.empty()) { + return; + } clearItems(); - if (!chat->amIn()) return; + if (!chat->amIn()) { + return; + } _sortByOnline = true; reserveItemsForSize(chat->participants.size()); - addUser(chat, Auth().user())->onlineForSort + addUser(chat, chat->session().user())->onlineForSort = std::numeric_limits::max(); - for (const auto &[user, v] : chat->participants) { + for (const auto user : chat->participants) { if (!user->isSelf()) { addUser(chat, user); } } } -void GroupMembersWidget::setItemFlags(Item *item, ChatData *chat) { +void GroupMembersWidget::setItemFlags( + not_null item, + not_null chat) { using AdminState = Item::AdminState; - auto user = getMember(item)->user(); - auto isCreator = (peerFromUser(chat->creator) == item->peer->id); - // #TODO groups - auto isAdmin = false;// chat->adminsEnabled() && chat->admins.contains(user); - auto adminState = isCreator ? AdminState::Creator : isAdmin ? AdminState::Admin : AdminState::None; + const auto user = getMember(item)->user(); + const auto isCreator = (peerFromUser(chat->creator) == item->peer->id); + const auto isAdmin = chat->hasAdminRights(); + const auto adminState = isCreator + ? AdminState::Creator + : isAdmin + ? AdminState::Admin + : AdminState::None; item->adminState = adminState; - if (item->peer->id == Auth().userPeerId()) { + if (item->peer->id == chat->session().userPeerId()) { item->hasRemoveLink = false; - } else if (chat->amCreator() /*|| (chat->amAdmin() && (adminState == AdminState::None))*/) { + } else if (chat->amCreator() + || ((chat->adminRights() & ChatAdminRight::f_ban_users) + && (adminState == AdminState::None))) { item->hasRemoveLink = true; - } else if (chat->invitedByMe.contains(user) && (adminState == AdminState::None)) { + } else if (chat->invitedByMe.contains(user) + && (adminState == AdminState::None)) { item->hasRemoveLink = true; } else { item->hasRemoveLink = false; } } -GroupMembersWidget::Member *GroupMembersWidget::addUser(ChannelData *megagroup, UserData *user) { - auto member = computeMember(user); +auto GroupMembersWidget::addUser( + not_null megagroup, + not_null user) +-> not_null { + const auto member = computeMember(user); setItemFlags(member, megagroup); addItem(member); return member; } -void GroupMembersWidget::fillMegagroupMembers(ChannelData *megagroup) { - Assert(megagroup->mgInfo != nullptr); - if (megagroup->mgInfo->lastParticipants.empty()) return; +void GroupMembersWidget::fillMegagroupMembers( + not_null megagroup) { + Expects(megagroup->mgInfo != nullptr); - if (!megagroup->canViewMembers()) { + if (megagroup->mgInfo->lastParticipants.empty()) { + return; + } else if (!megagroup->canViewMembers()) { clearItems(); return; } - _sortByOnline = (megagroup->membersCount() > 0 && megagroup->membersCount() <= Global::ChatSizeMax()); + _sortByOnline = (megagroup->membersCount() > 0) + && (megagroup->membersCount() <= Global::ChatSizeMax()); auto &membersList = megagroup->mgInfo->lastParticipants; if (_sortByOnline) { clearItems(); reserveItemsForSize(membersList.size()); if (megagroup->amIn()) { - addUser(megagroup, Auth().user())->onlineForSort + addUser(megagroup, megagroup->session().user())->onlineForSort = std::numeric_limits::max(); } } else if (membersList.size() >= itemsCount()) { @@ -325,14 +347,14 @@ void GroupMembersWidget::fillMegagroupMembers(ChannelData *megagroup) { clearItems(); reserveItemsForSize(membersList.size()); } - for_const (auto user, membersList) { + for (const auto user : membersList) { if (!_sortByOnline || !user->isSelf()) { addUser(megagroup, user); } } } -bool GroupMembersWidget::addUsersToEnd(ChannelData *megagroup) { +bool GroupMembersWidget::addUsersToEnd(not_null megagroup) { auto &membersList = megagroup->mgInfo->lastParticipants; auto &itemsList = items(); for (int i = 0, count = itemsList.size(); i < count; ++i) { @@ -347,7 +369,9 @@ bool GroupMembersWidget::addUsersToEnd(ChannelData *megagroup) { return true; } -void GroupMembersWidget::setItemFlags(Item *item, ChannelData *megagroup) { +void GroupMembersWidget::setItemFlags( + not_null item, + not_null megagroup) { using AdminState = Item::AdminState; auto amCreator = item->peer->isSelf() && megagroup->amCreator(); auto amAdmin = item->peer->isSelf() && megagroup->hasAdminRights(); @@ -355,7 +379,11 @@ void GroupMembersWidget::setItemFlags(Item *item, ChannelData *megagroup) { auto isAdmin = (adminIt != megagroup->mgInfo->lastAdmins.cend()); auto isCreator = megagroup->mgInfo->creator == item->peer; auto adminCanEdit = isAdmin && adminIt->second.canEdit; - auto adminState = (amCreator || isCreator) ? AdminState::Creator : (amAdmin || isAdmin) ? AdminState::Admin : AdminState::None; + auto adminState = (amCreator || isCreator) + ? AdminState::Creator + : (amAdmin || isAdmin) + ? AdminState::Admin + : AdminState::None; if (item->adminState != adminState) { item->adminState = adminState; auto user = item->peer->asUser(); @@ -375,7 +403,8 @@ void GroupMembersWidget::setItemFlags(Item *item, ChannelData *megagroup) { } } -GroupMembersWidget::Member *GroupMembersWidget::computeMember(UserData *user) { +auto GroupMembersWidget::computeMember(not_null user) +-> not_null { auto it = _membersByUser.constFind(user); if (it == _membersByUser.cend()) { auto member = new Member(user); diff --git a/Telegram/SourceFiles/profile/profile_block_group_members.h b/Telegram/SourceFiles/profile/profile_block_group_members.h index 297f15e54..9b7958ade 100644 --- a/Telegram/SourceFiles/profile/profile_block_group_members.h +++ b/Telegram/SourceFiles/profile/profile_block_group_members.h @@ -44,11 +44,11 @@ private: void removePeer(PeerData *selectedPeer); void refreshMembers(); - void fillChatMembers(ChatData *chat); - void fillMegagroupMembers(ChannelData *megagroup); + void fillChatMembers(not_null chat); + void fillMegagroupMembers(not_null megagroup); void sortMembers(); void updateOnlineCount(); - void checkSelfAdmin(ChatData *chat); + void checkSelfAdmin(not_null chat); void preloadMore(); void refreshUserOnline(UserData *user); @@ -66,12 +66,14 @@ private: } void updateItemStatusText(Item *item); - Member *computeMember(UserData *user); - Member *addUser(ChatData *chat, UserData *user); - Member *addUser(ChannelData *megagroup, UserData *user); - void setItemFlags(Item *item, ChatData *chat); - void setItemFlags(Item *item, ChannelData *megagroup); - bool addUsersToEnd(ChannelData *megagroup); + not_null computeMember(not_null user); + not_null addUser(not_null chat, not_null user); + not_null addUser(not_null megagroup, not_null user); + void setItemFlags(not_null item, not_null chat); + void setItemFlags( + not_null item, + not_null megagroup); + bool addUsersToEnd(not_null megagroup); QMap _membersByUser; bool _sortByOnline = false; diff --git a/Telegram/SourceFiles/storage/serialize_common.cpp b/Telegram/SourceFiles/storage/serialize_common.cpp index cae088d2b..510b1c1eb 100644 --- a/Telegram/SourceFiles/storage/serialize_common.cpp +++ b/Telegram/SourceFiles/storage/serialize_common.cpp @@ -126,7 +126,7 @@ void writePeer(QDataStream &stream, PeerData *peer) { << chat->name << qint32(chat->count) << qint32(chat->date) - << qint32(chat->version) + << qint32(chat->version()) << qint32(chat->creator) << qint32(0) << quint32(chat->flags()) @@ -136,7 +136,7 @@ void writePeer(QDataStream &stream, PeerData *peer) { << channel->name << quint64(channel->access) << qint32(channel->date) - << qint32(channel->version) + << qint32(channel->version()) << qint32(0) << quint32(channel->flags()) << channel->inviteLink(); @@ -226,7 +226,11 @@ PeerData *readPeer(int streamAppVersion, QDataStream &stream) { chat->setName(name); chat->count = count; chat->date = date; - chat->version = version; + + // We don't save participants, admin status and banned rights. + // So we don't restore the version field, info is still unknown. + chat->setVersion(0); + chat->creator = creator; chat->setFlags(MTPDchat::Flags::from_raw(flags)); chat->setInviteLink(inviteLink); @@ -247,7 +251,11 @@ PeerData *readPeer(int streamAppVersion, QDataStream &stream) { channel->setName(name, QString()); channel->access = access; channel->date = date; - channel->version = version; + + // We don't save participants, admin status and banned rights. + // So we don't restore the version field, info is still unknown. + channel->setVersion(0); + channel->setFlags(MTPDchannel::Flags::from_raw(flags)); channel->setInviteLink(inviteLink);