diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 6881a762b..845ebde7f 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -1168,6 +1168,69 @@ void ApiWrap::requestPeer(not_null peer) { _peerRequests.insert(peer, requestId); } +void ApiWrap::migrateChat( + not_null chat, + FnMut)> done, + FnMut fail) { + const auto callback = [&] { + return MigrateCallbacks{ std::move(done), std::move(fail) }; + }; + const auto i = _migrateCallbacks.find(chat); + if (i != end(_migrateCallbacks)) { + i->second.push_back(callback()); + return; + } else if (const auto channel = chat->migrateTo()) { + Notify::peerUpdatedDelayed( + chat, + Notify::PeerUpdate::Flag::MigrationChanged); + crl::on_main([=, done = std::move(done)]() mutable { + Notify::peerUpdatedSendDelayed(); + done(channel); + }); + } else if (chat->isDeactivated()) { + crl::on_main([fail = std::move(fail)]() mutable { + fail(RPCError::Local( + "BAD_MIGRATION", + "Chat is already deactivated")); + }); + return; + } else if (!chat->amCreator()) { + crl::on_main([fail = std::move(fail)]() mutable { + fail(RPCError::Local( + "BAD_MIGRATION", + "Current user is not the creator of that chat")); + }); + return; + } + + _migrateCallbacks.emplace(chat).first->second.push_back(callback()); + request(MTPmessages_MigrateChat( + chat->inputChat + )).done([=](const MTPUpdates &result) { + applyUpdates(result); + Notify::peerUpdatedSendDelayed(); + + const auto channel = chat->migrateTo(); + if (auto handlers = _migrateCallbacks.take(chat)) { + for (auto &handler : *handlers) { + if (channel) { + handler.done(channel); + } else { + handler.fail(RPCError::Local( + "MIGRATION_FAIL", + "No channel")); + } + } + } + }).fail([=](const RPCError &error) { + if (auto handlers = _migrateCallbacks.take(chat)) { + for (auto &handler : *handlers) { + handler.fail(error); + } + } + }).send(); +} + void ApiWrap::markMediaRead( const base::flat_set> &items) { auto markedIds = QVector(); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index b429994be..9341691a1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -137,6 +137,11 @@ public: not_null user, const MTPUserFull &result); + void migrateChat( + not_null chat, + FnMut)> done, + FnMut fail = nullptr); + void markMediaRead(const base::flat_set> &items); void markMediaRead(not_null item); @@ -727,6 +732,14 @@ private: FnMut _checkInviteDone; FnMut _checkInviteFail; + struct MigrateCallbacks { + FnMut)> done; + FnMut fail; + }; + base::flat_map< + not_null, + std::vector> _migrateCallbacks; + std::vector> _supportContactCallbacks; base::flat_map> _peerPhotoUploads; diff --git a/Telegram/SourceFiles/boxes/add_contact_box.cpp b/Telegram/SourceFiles/boxes/add_contact_box.cpp index 774b650a7..ed4c71744 100644 --- a/Telegram/SourceFiles/boxes/add_contact_box.cpp +++ b/Telegram/SourceFiles/boxes/add_contact_box.cpp @@ -608,8 +608,7 @@ void GroupInfoBox::submit() { }; Ui::show( Box( - std::make_unique( - nullptr), + std::make_unique(), std::move(initBox)), LayerOption::KeepOther); } diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index dc62d189a..64d4934e8 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -318,12 +318,15 @@ int PeerListBox::peerListSelectedRowsCount() { return _select ? _select->entity()->getItemsCount() : 0; } -std::vector> PeerListBox::peerListCollectSelectedRows() { - auto result = std::vector> {}; - auto items = _select ? _select->entity()->getItems() : QVector {}; +auto PeerListBox::peerListCollectSelectedRows() +-> std::vector> { + auto result = std::vector>(); + auto items = _select + ? _select->entity()->getItems() + : QVector(); if (!items.empty()) { result.reserve(items.size()); - for_const (auto itemId, items) { + for (const auto itemId : items) { result.push_back(App::peer(itemId)); } } diff --git a/Telegram/SourceFiles/boxes/peer_list_box.h b/Telegram/SourceFiles/boxes/peer_list_box.h index 04fa47de0..3cd9867ec 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.h +++ b/Telegram/SourceFiles/boxes/peer_list_box.h @@ -303,6 +303,10 @@ public: std::unique_ptr state) { } + rpl::lifetime &lifetime() { + return _lifetime; + } + protected: not_null delegate() const { return _delegate; @@ -310,6 +314,7 @@ protected: private: PeerListSearchDelegate *_delegate = nullptr; + rpl::lifetime _lifetime; }; @@ -320,7 +325,8 @@ public: }; // Search works only with RowId == peer->id. - PeerListController(std::unique_ptr searchController = nullptr); + PeerListController( + std::unique_ptr searchController = {}); void setDelegate(not_null delegate) { _delegate = delegate; diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 76e08f1e6..2695a08c0 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -307,7 +307,9 @@ bool ChatsListBoxController::appendRow(not_null history) { return false; } -ContactsBoxController::ContactsBoxController(std::unique_ptr searchController) : PeerListController(std::move(searchController)) { +ContactsBoxController::ContactsBoxController( + std::unique_ptr searchController) +: PeerListController(std::move(searchController)) { } void ContactsBoxController::prepare() { diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h index c0f7fd699..8a932bb46 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.h +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h @@ -114,9 +114,13 @@ private: }; -class ContactsBoxController : public PeerListController, protected base::Subscriber { +class ContactsBoxController + : public PeerListController + , protected base::Subscriber { public: - ContactsBoxController(std::unique_ptr searchController = std::make_unique()); + ContactsBoxController( + std::unique_ptr searchController + = std::make_unique()); void prepare() override final; std::unique_ptr createSearchRow(not_null peer) override final; diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index eaa3c4226..1696e4e76 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -40,61 +40,63 @@ base::flat_set> GetAlreadyInFromPeer(PeerData *peer) { return {}; } -bool InviteSelectedUsers( - not_null box, - not_null chat) { - const auto rows = box->peerListCollectSelectedRows(); - const auto users = ranges::view::all( - rows - ) | ranges::view::transform([](not_null peer) { - Expects(peer->isUser()); - Expects(!peer->isSelf()); - - return not_null(peer->asUser()); - }) | ranges::to_vector; - if (users.empty()) { - return false; - } - chat->session().api().addChatParticipants(chat, users); - return true; -} - } // namespace -AddParticipantsBoxController::AddParticipantsBoxController(PeerData *peer) -: ContactsBoxController(std::make_unique()) -, _peer(peer) -, _alreadyIn(GetAlreadyInFromPeer(peer)) { +AddParticipantsBoxController::AddParticipantsBoxController() +: ContactsBoxController( + std::make_unique()) { } AddParticipantsBoxController::AddParticipantsBoxController( - not_null channel, + not_null peer) +: AddParticipantsBoxController(peer, GetAlreadyInFromPeer(peer)) { +} + +AddParticipantsBoxController::AddParticipantsBoxController( + not_null peer, base::flat_set> &&alreadyIn) : ContactsBoxController(std::make_unique()) -, _peer(channel) +, _peer(peer) , _alreadyIn(std::move(alreadyIn)) { + subscribeToMigration(); +} + +void AddParticipantsBoxController::subscribeToMigration() { + Expects(_peer != nullptr); + + SubscribeToMigration( + _peer, + lifetime(), + [=](not_null channel) { _peer = channel; }); } void AddParticipantsBoxController::rowClicked(not_null row) { auto count = fullCount(); - auto limit = (_peer && _peer->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax(); + auto limit = _peer && (_peer->isChat() || _peer->isMegagroup()) + ? Global::MegagroupSizeMax() + : Global::ChatSizeMax(); if (count < limit || row->checked()) { delegate()->peerListSetRowChecked(row, !row->checked()); updateTitle(); - } else if (auto channel = _peer ? _peer->asChannel() : nullptr) { + } else if (const auto channel = _peer ? _peer->asChannel() : nullptr) { if (!_peer->isMegagroup()) { Ui::show( Box(_peer->asChannel()), LayerOption::KeepOther); } - } else if (count >= Global::ChatSizeMax() && count < Global::MegagroupSizeMax()) { + } else if (count >= Global::ChatSizeMax() + && count < Global::MegagroupSizeMax()) { + // #TODO groups new error about "after creating" Ui::show( - Box(lng_profile_add_more_after_upgrade(lt_count, Global::MegagroupSizeMax())), + Box(lng_profile_add_more_after_upgrade( + lt_count, + Global::MegagroupSizeMax())), LayerOption::KeepOther); } } -void AddParticipantsBoxController::itemDeselectedHook(not_null peer) { +void AddParticipantsBoxController::itemDeselectedHook( + not_null peer) { updateTitle(); } @@ -106,23 +108,26 @@ int AddParticipantsBoxController::alreadyInCount() const { if (!_peer) { return 1; // self } - if (auto chat = _peer->asChat()) { + if (const auto chat = _peer->asChat()) { return qMax(chat->count, 1); - } else if (auto channel = _peer->asChannel()) { + } else if (const auto channel = _peer->asChannel()) { return qMax(channel->membersCount(), int(_alreadyIn.size())); } Unexpected("User in AddParticipantsBoxController::alreadyInCount"); } -bool AddParticipantsBoxController::isAlreadyIn(not_null user) const { +bool AddParticipantsBoxController::isAlreadyIn( + not_null user) const { if (!_peer) { return false; } - if (auto chat = _peer->asChat()) { - return chat->participants.contains(user); - } else if (auto channel = _peer->asChannel()) { + if (const auto chat = _peer->asChat()) { return _alreadyIn.contains(user) - || (channel->isMegagroup() && base::contains(channel->mgInfo->lastParticipants, user)); + || chat->participants.contains(user); + } else if (const auto channel = _peer->asChannel()) { + return _alreadyIn.contains(user) + || (channel->isMegagroup() + && base::contains(channel->mgInfo->lastParticipants, user)); } Unexpected("User in AddParticipantsBoxController::isAlreadyIn"); } @@ -144,25 +149,49 @@ std::unique_ptr AddParticipantsBoxController::createRow( } void AddParticipantsBoxController::updateTitle() { - auto additional = (_peer && _peer->isChannel() && !_peer->isMegagroup()) + const auto additional = (_peer + && _peer->isChannel() + && !_peer->isMegagroup()) ? QString() : QString("%1 / %2").arg(fullCount()).arg(Global::MegagroupSizeMax()); delegate()->peerListSetTitle(langFactory(lng_profile_add_participant)); - delegate()->peerListSetAdditionalTitle([additional] { return additional; }); + delegate()->peerListSetAdditionalTitle([=] { return additional; }); +} + +bool AddParticipantsBoxController::inviteSelectedUsers( + not_null box) const { + Expects(_peer != nullptr); + + const auto rows = box->peerListCollectSelectedRows(); + const auto users = ranges::view::all( + rows + ) | ranges::view::transform([](not_null peer) { + Expects(peer->isUser()); + Expects(!peer->isSelf()); + + return not_null(peer->asUser()); + }) | ranges::to_vector; + if (users.empty()) { + return false; + } + _peer->session().api().addChatParticipants(_peer, users); + return true; } void AddParticipantsBoxController::Start(not_null chat) { + auto controller = std::make_unique(chat); + const auto weak = controller.get(); auto initBox = [=](not_null box) { box->addButton(langFactory(lng_participant_invite), [=] { - if (InviteSelectedUsers(box, chat)) { + if (weak->inviteSelectedUsers(box)) { Ui::showPeerHistory(chat, ShowAtTheEndMsgId); } }); - box->addButton(langFactory(lng_cancel), [box] { box->closeBox(); }); + box->addButton(langFactory(lng_cancel), [=] { box->closeBox(); }); }; Ui::show( Box( - std::make_unique(chat), + std::move(controller), std::move(initBox)), LayerOption::KeepOther); } @@ -171,10 +200,13 @@ void AddParticipantsBoxController::Start( not_null channel, base::flat_set> &&alreadyIn, bool justCreated) { - auto initBox = [channel, justCreated](not_null box) { - auto subscription = std::make_shared(); - box->addButton(langFactory(lng_participant_invite), [=, copy = subscription] { - if (InviteSelectedUsers(box, channel)) { + auto controller = std::make_unique( + channel, + std::move(alreadyIn)); + const auto weak = controller.get(); + auto initBox = [=](not_null box) { + box->addButton(langFactory(lng_participant_invite), [=] { + if (weak->inviteSelectedUsers(box)) { if (channel->isMegagroup()) { Ui::showPeerHistory(channel, ShowAtTheEndMsgId); } else { @@ -182,18 +214,18 @@ void AddParticipantsBoxController::Start( } } }); - box->addButton(langFactory(justCreated ? lng_create_group_skip : lng_cancel), [box] { box->closeBox(); }); + box->addButton( + langFactory(justCreated ? lng_create_group_skip : lng_cancel), + [=] { box->closeBox(); }); if (justCreated) { box->boxClosing() | rpl::start_with_next([=] { Ui::showPeerHistory(channel, ShowAtTheEndMsgId); - }, *subscription); + }, box->lifetime()); } }; Ui::show( Box( - std::make_unique( - channel, - std::move(alreadyIn)), + std::move(controller), std::move(initBox)), LayerOption::KeepOther); } @@ -221,9 +253,23 @@ AddSpecialBoxController::AddSpecialBoxController( , _additional(peer, Role::Members) , _adminDoneCallback(std::move(adminDoneCallback)) , _bannedDoneCallback(std::move(bannedDoneCallback)) { + subscribeToMigration(); } -std::unique_ptr AddSpecialBoxController::createSearchRow(not_null peer) { +void AddSpecialBoxController::subscribeToMigration() { + SubscribeToMigration( + _peer, + lifetime(), + [=](not_null channel) { migrate(channel); }); +} + +void AddSpecialBoxController::migrate(not_null channel) { + _peer = channel; + _additional.migrate(channel); +} + +std::unique_ptr AddSpecialBoxController::createSearchRow( + not_null peer) { if (peer->isSelf()) { return nullptr; } @@ -237,9 +283,12 @@ void AddSpecialBoxController::prepare() { delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); const auto title = [&] { switch (_role) { - case Role::Admins: return langFactory(lng_channel_add_admin); - case Role::Restricted: return langFactory(lng_channel_add_restricted); - case Role::Kicked: return langFactory(lng_channel_add_banned); + case Role::Admins: + return langFactory(lng_channel_add_admin); + case Role::Restricted: + return langFactory(lng_channel_add_restricted); + case Role::Kicked: + return langFactory(lng_channel_add_banned); } Unexpected("Role in AddSpecialBoxController::prepare()"); }(); @@ -723,6 +772,14 @@ AddSpecialBoxSearchController::AddSpecialBoxSearchController( : _peer(peer) , _additional(additional) , _timer([=] { searchOnServer(); }) { + subscribeToMigration(); +} + +void AddSpecialBoxSearchController::subscribeToMigration() { + SubscribeToMigration( + _peer, + lifetime(), + [=](not_null channel) { _peer = channel; }); } void AddSpecialBoxSearchController::searchQuery(const QString &query) { @@ -752,10 +809,13 @@ bool AddSpecialBoxSearchController::isLoading() { } bool AddSpecialBoxSearchController::searchParticipantsInCache() { - auto it = _participantsCache.find(_query); - if (it != _participantsCache.cend()) { + const auto i = _participantsCache.find(_query); + if (i != _participantsCache.cend()) { _requestId = 0; - searchParticipantsDone(_requestId, it->second.result, it->second.requestedCount); + searchParticipantsDone( + _requestId, + i->second.result, + i->second.requestedCount); return true; } return false; @@ -837,8 +897,7 @@ void AddSpecialBoxSearchController::searchParticipantsDone( const auto channel = _peer->asChannel(); auto query = _query; if (requestId) { - auto &session = channel->session(); - session.api().parseChannelParticipants(channel, result, [&](auto&&...) { + const auto addToCache = [&](auto&&...) { auto it = _participantsQueries.find(requestId); if (it != _participantsQueries.cend()) { query = it->second.text; @@ -849,7 +908,11 @@ void AddSpecialBoxSearchController::searchParticipantsDone( } _participantsQueries.erase(it); } - }); + }; + channel->session().api().parseChannelParticipants( + channel, + result, + addToCache); } if (_requestId != requestId) { @@ -857,14 +920,14 @@ void AddSpecialBoxSearchController::searchParticipantsDone( } _requestId = 0; result.match([&](const MTPDchannels_channelParticipants &data) { - auto &list = data.vparticipants.v; + const auto &list = data.vparticipants.v; if (list.size() < requestedCount) { - // We want cache to have full information about a query with small - // results count (if we don't need the second request). So we don't - // wait for an empty results list unlike the non-search peer list. + // We want cache to have full information about a query with + // small results count (that we don't need the second request). + // So we don't wait for empty list unlike the non-search case. _participantsLoaded = true; if (list.empty() && _offset == 0) { - // No results, so we want to request global search immediately. + // No results, request global search immediately. loadMoreRows(); } } @@ -946,7 +1009,6 @@ void AddSpecialBoxSearchController::addChatMembers( if (chat->participants.empty()) { return; } - _participantsLoaded = true; const auto wordList = TextUtilities::PrepareSearchWords(_query); if (wordList.empty()) { @@ -1024,7 +1086,8 @@ void AddSpecialBoxSearchController::addChatsContacts() { return result; }; const auto dialogsIndex = getSmallestIndex(App::main()->dialogsList()); - const auto contactsIndex = getSmallestIndex(App::main()->contactsNoDialogsList()); + const auto contactsIndex = getSmallestIndex( + App::main()->contactsNoDialogsList()); const auto filterAndAppend = [&](const Dialogs::List *list) { if (!list) { diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.h b/Telegram/SourceFiles/boxes/peers/add_participants_box.h index ac4a95a5d..1eac6897b 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.h +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.h @@ -18,9 +18,10 @@ public: not_null channel, base::flat_set> &&alreadyIn); - AddParticipantsBoxController(PeerData *peer); + AddParticipantsBoxController(); + AddParticipantsBoxController(not_null peer); AddParticipantsBoxController( - not_null channel, + not_null peer, base::flat_set> &&alreadyIn); using ContactsBoxController::ContactsBoxController; @@ -39,11 +40,12 @@ private: base::flat_set> &&alreadyIn, bool justCreated); + bool inviteSelectedUsers(not_null box) const; + void subscribeToMigration(); int alreadyInCount() const; bool isAlreadyIn(not_null user) const; int fullCount() const; void updateTitle(); - bool inviteSelectedUsers(not_null chat) const; PeerData *_peer = nullptr; base::flat_set> _alreadyIn; @@ -103,6 +105,9 @@ private: bool prependRow(not_null user); std::unique_ptr createRow(not_null user) const; + void subscribeToMigration(); + void migrate(not_null channel); + not_null _peer; Role _role = Role::Admins; int _offset = 0; @@ -119,7 +124,8 @@ private: // Finds chat/channel members, then contacts, then global search results. class AddSpecialBoxSearchController : public PeerListSearchController - , private MTP::Sender { + , private MTP::Sender + , private base::Subscriber { public: using Role = ParticipantsBoxController::Role; @@ -156,6 +162,8 @@ private: void addChatsContacts(); void requestGlobal(); + void subscribeToMigration(); + not_null _peer; not_null _additional; diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index aa7014271..1382b5518 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -142,7 +142,16 @@ FnasChat()) { + const auto saveForChannel = [=](not_null channel) { + SaveChannelAdmin( + channel, + user, + oldRights, + newRights, + done, + onFail); + }; + if (const auto chat = peer->asChatNotMigrated()) { const auto saveChatAdmin = [&](bool isAdmin) { SaveChatAdmin(chat, user, isAdmin, done, onFail); }; @@ -155,16 +164,10 @@ Fnsession().api().migrateChat(chat, saveForChannel); } - } else if (const auto channel = peer->asChannel()) { - SaveChannelAdmin( - channel, - user, - oldRights, - newRights, - done, - onFail); + } else if (const auto channel = peer->asChannelOrMigrated()) { + saveForChannel(channel); } else { Unexpected("Peer in SaveAdminCallback."); } @@ -182,17 +185,7 @@ FnasChat()) { - const auto flags = newRights.match([]( - const MTPDchatBannedRights &data) { - return data.vflags.v; - }); - if (!flags) { - done(); - } else { - // #TODO groups autoconv - } - } else if (const auto channel = peer->asChannel()) { + const auto saveForChannel = [=](not_null channel) { SaveChannelRestriction( channel, user, @@ -200,12 +193,51 @@ FnasChatNotMigrated()) { + const auto flags = newRights.match([]( + const MTPDchatBannedRights &data) { + return data.vflags.v; + }); + if (!flags) { + done(); + } else { + peer->session().api().migrateChat(chat, saveForChannel); + } + } else if (const auto channel = peer->asChannelOrMigrated()) { + saveForChannel(channel); } else { Unexpected("Peer in SaveAdminCallback."); } }; } +void SubscribeToMigration( + not_null peer, + rpl::lifetime &lifetime, + Fn)> migrate) { + if (const auto chat = peer->asChat()) { + if (const auto channel = peer->migrateTo()) { + migrate(channel); + } else if (!chat->isDeactivated()) { + const auto alive = lifetime.make_state(); + const auto handler = [=](const Notify::PeerUpdate &update) { + if (update.peer == peer) { + if (const auto channel = peer->migrateTo()) { + const auto onstack = base::duplicate(migrate); + *alive = base::Subscription(); + onstack(channel); + } + } + }; + *alive = Notify::PeerUpdated().add_subscription( + Notify::PeerUpdatedHandler( + Notify::PeerUpdate::Flag::MigrationChanged, + handler)); + } + } +} + ParticipantsAdditionalData::ParticipantsAdditionalData( not_null peer, Role role) @@ -214,7 +246,8 @@ ParticipantsAdditionalData::ParticipantsAdditionalData( fillFromPeer(); } -bool ParticipantsAdditionalData::infoLoaded(not_null user) const { +bool ParticipantsAdditionalData::infoLoaded( + not_null user) const { return _peer->isChat() || (_infoNotLoaded.find(user) == end(_infoNotLoaded)); } @@ -286,7 +319,8 @@ bool ParticipantsAdditionalData::isCreator(not_null user) const { return (_creator == user); } -bool ParticipantsAdditionalData::isExternal(not_null user) const { +bool ParticipantsAdditionalData::isExternal( + not_null user) const { return _peer->isChat() ? !_members.contains(user) : _external.find(user) != end(_external); @@ -531,6 +565,23 @@ UserData *ParticipantsAdditionalData::applyBanned( return user; } +void ParticipantsAdditionalData::migrate(not_null channel) { + _peer = channel; + fillFromChannel(channel); + + for (const auto user : _admins) { + _adminRights.emplace( + user, + MTP_chatAdminRights(MTP_flags(ChatData::DefaultAdminRights()))); + if (channel->amCreator()) { + _adminCanEdit.emplace(user); + } + if (_creator) { + _adminPromotedBy.emplace(user, _creator); + } + } +} + ParticipantsOnlineSorter::ParticipantsOnlineSorter( not_null peer, not_null delegate) @@ -608,6 +659,7 @@ ParticipantsBoxController::ParticipantsBoxController( , _peer(peer) , _role(role) , _additional(peer, _role) { + subscribeToMigration(); if (_role == Role::Profile) { setupListChangeViewers(); } @@ -1183,13 +1235,14 @@ bool ParticipantsBoxController::feedMegagroupLastParticipants() { } const auto info = megagroup->mgInfo.get(); // - // channelFull and channels_channelParticipants members count is desynced + // channelFull and channels_channelParticipants members count desynced // so we almost always have LastParticipantsCountOutdated that is set // inside setMembersCount() and so we almost never use lastParticipants. // // => disable this check temporarily. // - //if (info->lastParticipantsStatus != MegagroupInfo::LastParticipantsUpToDate) { + //if (info->lastParticipantsStatus + // != MegagroupInfo::LastParticipantsUpToDate) { // _channel->updateFull(); // return false; //} @@ -1227,7 +1280,8 @@ void ParticipantsBoxController::rowClicked(not_null row) { } } -void ParticipantsBoxController::rowActionClicked(not_null row) { +void ParticipantsBoxController::rowActionClicked( + not_null row) { Expects(row->peer()->isUser()); const auto user = row->peer()->asUser(); @@ -1599,7 +1653,8 @@ void ParticipantsBoxController::recomputeTypeFor( } } -void ParticipantsBoxController::refreshCustomStatus(not_null row) const { +void ParticipantsBoxController::refreshCustomStatus( + not_null row) const { const auto user = row->peer()->asUser(); if (_role == Role::Admins) { if (const auto by = _additional.adminPromotedBy(user)) { @@ -1623,6 +1678,18 @@ void ParticipantsBoxController::refreshCustomStatus(not_null row) } } +void ParticipantsBoxController::subscribeToMigration() { + SubscribeToMigration( + _peer, + lifetime(), + [=](not_null channel) { migrate(channel); }); +} + +void ParticipantsBoxController::migrate(not_null channel) { + _peer = channel; + _additional.migrate(channel); +} + ParticipantsBoxSearchController::ParticipantsBoxSearchController( not_null channel, Role role, @@ -1686,10 +1753,13 @@ bool ParticipantsBoxSearchController::isLoading() { } bool ParticipantsBoxSearchController::searchInCache() { - auto it = _cache.find(_query); - if (it != _cache.cend()) { + const auto i = _cache.find(_query); + if (i != _cache.cend()) { _requestId = 0; - searchDone(_requestId, it->second.result, it->second.requestedCount); + searchDone( + _requestId, + i->second.result, + i->second.requestedCount); return true; } return false; @@ -1706,11 +1776,14 @@ bool ParticipantsBoxSearchController::loadMoreRows() { switch (_role) { case Role::Admins: // Search for members, appoint as admin on found. case Role::Profile: - case Role::Members: return MTP_channelParticipantsSearch(MTP_string(_query)); - case Role::Restricted: return MTP_channelParticipantsBanned(MTP_string(_query)); - case Role::Kicked: return MTP_channelParticipantsKicked(MTP_string(_query)); + case Role::Members: + return MTP_channelParticipantsSearch(MTP_string(_query)); + case Role::Restricted: + return MTP_channelParticipantsBanned(MTP_string(_query)); + case Role::Kicked: + return MTP_channelParticipantsKicked(MTP_string(_query)); } - Unexpected("Role in ParticipantsBoxSearchController::loadMoreRows()"); + Unexpected("Role in ParticipantsBoxSearchController."); }(); // For search we request a lot of rows from the first query. @@ -1725,9 +1798,11 @@ bool ParticipantsBoxSearchController::loadMoreRows() { MTP_int(_offset), MTP_int(perPage), MTP_int(participantsHash) - )).done([this, perPage](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + )).done([=]( + const MTPchannels_ChannelParticipants &result, + mtpRequestId requestId) { searchDone(requestId, result, perPage); - }).fail([this](const RPCError &error, mtpRequestId requestId) { + }).fail([=](const RPCError &error, mtpRequestId requestId) { if (_requestId == requestId) { _requestId = 0; _allLoaded = true; @@ -1748,7 +1823,7 @@ void ParticipantsBoxSearchController::searchDone( int requestedCount) { auto query = _query; if (requestId) { - _channel->session().api().parseChannelParticipants(_channel, result, [&](auto&&...) { + const auto addToCache = [&](auto&&...) { auto it = _queries.find(requestId); if (it != _queries.cend()) { query = it->second.text; @@ -1759,20 +1834,23 @@ void ParticipantsBoxSearchController::searchDone( } _queries.erase(it); } - }); + }; + _channel->session().api().parseChannelParticipants( + _channel, + result, + addToCache); } - if (_requestId != requestId) { return; } _requestId = 0; result.match([&](const MTPDchannels_channelParticipants &data) { - auto &list = data.vparticipants.v; + const auto &list = data.vparticipants.v; if (list.size() < requestedCount) { - // We want cache to have full information about a query with small - // results count (if we don't need the second request). So we don't - // wait for an empty results list unlike the non-search peer list. + // We want cache to have full information about a query with + // small results count (that we don't need the second request). + // So we don't wait for empty list unlike the non-search case. _allLoaded = true; } const auto overrideRole = (_role == Role::Admins) diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h index 38c3c69e9..58e16fa6c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h @@ -36,6 +36,11 @@ Fn onDone, Fn onFail); +void SubscribeToMigration( + not_null peer, + rpl::lifetime &lifetime, + Fn)> migrate); + enum class ParticipantsRole { Profile, Members, @@ -92,6 +97,8 @@ public: [[nodiscard]] UserData *adminPromotedBy(not_null user) const; [[nodiscard]] UserData *restrictedBy(not_null user) const; + void migrate(not_null channel); + private: UserData *applyCreator(const MTPDchannelParticipantCreator &data); UserData *applyAdmin(const MTPDchannelParticipantAdmin &data); @@ -216,6 +223,9 @@ private: Type computeType(not_null user) const; void recomputeTypeFor(not_null user); + void subscribeToMigration(); + void migrate(not_null channel); + not_null _navigation; not_null _peer; Role _role = Role::Admins; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index aab3cebee..33a6c70b9 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -1109,8 +1109,17 @@ void Controller::saveUsername() { if (!_savingData.username || *_savingData.username == username) { return continueSave(); } else if (!channel) { - // #TODO groups autoconv - return continueSave(); + const auto saveForChannel = [=](not_null channel) { + if (_peer->asChannel() == channel) { + saveUsername(); + } else { + cancelSave(); + } + }; + _peer->session().api().migrateChat( + _peer->asChat(), + crl::guard(this, saveForChannel)); + return; } request(MTPchannels_UpdateUsername( @@ -1122,7 +1131,7 @@ void Controller::saveUsername() { *_savingData.username); continueSave(); }).fail([=](const RPCError &error) { - const auto type = error.type(); + const auto &type = error.type(); if (type == qstr("USERNAME_NOT_MODIFIED")) { channel->setName( TextUtilities::SingleLine(channel->name), @@ -1156,7 +1165,7 @@ void Controller::saveTitle() { continueSave(); }; const auto onFail = [=](const RPCError &error) { - const auto type = error.type(); + const auto &type = error.type(); if (type == qstr("CHAT_NOT_MODIFIED") || type == qstr("CHAT_TITLE_NOT_MODIFIED")) { if (const auto channel = _peer->asChannel()) { @@ -1209,7 +1218,7 @@ void Controller::saveDescription() { )).done([=](const MTPBool &result) { successCallback(); }).fail([=](const RPCError &error) { - auto type = error.type(); + const auto &type = error.type(); if (type == qstr("CHAT_ABOUT_NOT_MODIFIED")) { successCallback(); return; @@ -1226,8 +1235,17 @@ void Controller::saveHistoryVisibility() { || *_savingData.hiddenPreHistory == hidden) { return continueSave(); } else if (!channel) { - // #TODO groups autoconv - return continueSave(); + const auto saveForChannel = [=](not_null channel) { + if (_peer->asChannel() == channel) { + saveHistoryVisibility(); + } else { + cancelSave(); + } + }; + _peer->session().api().migrateChat( + _peer->asChat(), + crl::guard(this, saveForChannel)); + return; } request(MTPchannels_TogglePreHistoryHidden( channel->inputChannel, diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 6358a484f..55e77b4df 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -489,6 +489,34 @@ const ChannelData *PeerData::asMegagroup() const { : nullptr; } +ChatData *PeerData::asChatNotMigrated() { + if (const auto chat = asChat()) { + return chat->migrateTo() ? nullptr : chat; + } + return nullptr; +} + +const ChatData *PeerData::asChatNotMigrated() const { + if (const auto chat = asChat()) { + return chat->migrateTo() ? nullptr : chat; + } + return nullptr; +} + +ChannelData *PeerData::asChannelOrMigrated() { + if (const auto channel = asChannel()) { + return channel; + } + return migrateTo(); +} + +const ChannelData *PeerData::asChannelOrMigrated() const { + if (const auto channel = asChannel()) { + return channel; + } + return migrateTo(); +} + ChatData *PeerData::migrateFrom() const { if (const auto megagroup = asMegagroup()) { return megagroup->amIn() diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index f45a10d8c..02dee74c2 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -110,6 +110,10 @@ public: [[nodiscard]] const ChannelData *asChannel() const; [[nodiscard]] ChannelData *asMegagroup(); [[nodiscard]] const ChannelData *asMegagroup() const; + [[nodiscard]] ChatData *asChatNotMigrated(); + [[nodiscard]] const ChatData *asChatNotMigrated() const; + [[nodiscard]] ChannelData *asChannelOrMigrated(); + [[nodiscard]] const ChannelData *asChannelOrMigrated() const; [[nodiscard]] ChatData *migrateFrom() const; [[nodiscard]] ChannelData *migrateTo() const; diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp index 286279476..61dc85a45 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.cpp @@ -28,25 +28,20 @@ void ShowSearchFromBox( peer, callback = std::move(callback) ]() -> std::unique_ptr { - if (peer) { - if (auto chat = peer->asChat()) { - return std::make_unique( - navigation, - chat, - std::move(callback)); - } else if (auto group = peer->asMegagroup()) { - return std::make_unique( - navigation, - group, - std::move(callback)); - } + if (peer && (peer->isChat() || peer->isMegagroup())) { + return std::make_unique( + navigation, + peer, + std::move(callback)); } return nullptr; }; if (auto controller = createController()) { auto subscription = std::make_shared(); auto box = Ui::show(Box(std::move(controller), [subscription](not_null box) { - box->addButton(langFactory(lng_cancel), [box, subscription] { box->closeBox(); }); + box->addButton(langFactory(lng_cancel), [box, subscription] { + box->closeBox(); + }); }), LayerOption::KeepOther); box->boxClosing() | rpl::start_with_next( std::move(closedCallback), @@ -54,106 +49,32 @@ void ShowSearchFromBox( } } -ChatSearchFromController::ChatSearchFromController( +SearchFromController::SearchFromController( not_null navigation, - not_null chat, - Fn)> callback) -: PeerListController() -, _chat(chat) -, _callback(std::move(callback)) { -} - -void ChatSearchFromController::prepare() { - setSearchNoResultsText(lang(lng_blocked_list_not_found)); - delegate()->peerListSetSearchMode(PeerListSearchMode::Enabled); - delegate()->peerListSetTitle(langFactory(lng_search_messages_from)); - - rebuildRows(); - - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::MembersChanged, [this](const Notify::PeerUpdate &update) { - if (update.peer == _chat) { - rebuildRows(); - } - })); -} - -void ChatSearchFromController::rowClicked(not_null row) { - Expects(row->peer()->isUser()); - - const auto onstack = _callback; - onstack(row->peer()->asUser()); -} - -void ChatSearchFromController::rebuildRows() { - auto ms = getms(); - auto wasEmpty = !delegate()->peerListFullRowsCount(); - - auto now = unixtime(); - const auto byOnline = [&](not_null user) { - return Data::SortByOnlineValue(user, now); - }; - auto ordered = QMultiMap>(); - if (_chat->noParticipantInfo()) { - Auth().api().requestFullPeer(_chat); - } else if (!_chat->participants.empty()) { - for (const auto user : _chat->participants) { - ordered.insertMulti(byOnline(user), user); - } - } - for_const (auto user, _chat->lastAuthors) { - if (user->isInaccessible()) continue; - appendRow(user); - if (!ordered.isEmpty()) { - ordered.remove(byOnline(user), user); - } - } - if (!ordered.isEmpty()) { - for (auto i = ordered.cend(), b = ordered.cbegin(); i != b;) { - appendRow(*(--i)); - } - } - checkForEmptyRows(); - delegate()->peerListRefreshRows(); -} - -void ChatSearchFromController::checkForEmptyRows() { - if (delegate()->peerListFullRowsCount()) { - setDescriptionText(QString()); - } else { - setDescriptionText(lang(lng_contacts_loading)); - } -} - -void ChatSearchFromController::appendRow(not_null user) { - if (!delegate()->peerListFindRow(user->id)) { - delegate()->peerListAppendRow(std::make_unique(user)); - } -} - -ChannelSearchFromController::ChannelSearchFromController( - not_null navigation, - not_null channel, + not_null peer, Fn)> callback) : ParticipantsBoxController( navigation, - channel, + peer, ParticipantsBoxController::Role::Members) , _callback(std::move(callback)) { } -void ChannelSearchFromController::prepare() { +void SearchFromController::prepare() { ParticipantsBoxController::prepare(); delegate()->peerListSetTitle(langFactory(lng_search_messages_from)); } -void ChannelSearchFromController::rowClicked(not_null row) { +void SearchFromController::rowClicked(not_null row) { Expects(row->peer()->isUser()); - const auto onstack = _callback; - onstack(row->peer()->asUser()); + if (const auto onstack = base::duplicate(_callback)) { + onstack(row->peer()->asUser()); + } } -std::unique_ptr ChannelSearchFromController::createRow(not_null user) const { +std::unique_ptr SearchFromController::createRow( + not_null user) const { return std::make_unique(user); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.h b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.h index 9a7a12c9d..8153c5f20 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.h +++ b/Telegram/SourceFiles/dialogs/dialogs_search_from_controllers.h @@ -18,31 +18,11 @@ void ShowSearchFromBox( Fn)> callback, Fn closedCallback); -class ChatSearchFromController : public PeerListController, protected base::Subscriber { +class SearchFromController : public ParticipantsBoxController { public: - ChatSearchFromController( + SearchFromController( not_null navigation, - not_null chat, - Fn)> callback); - - void prepare() override; - void rowClicked(not_null row) override; - -private: - void rebuildRows(); - void checkForEmptyRows(); - void appendRow(not_null user); - - not_null _chat; - Fn)> _callback; - -}; - -class ChannelSearchFromController : public ParticipantsBoxController { -public: - ChannelSearchFromController( - not_null navigation, - not_null channel, + not_null peer, Fn)> callback); void prepare() override; diff --git a/Telegram/SourceFiles/mtproto/concurrent_sender.cpp b/Telegram/SourceFiles/mtproto/concurrent_sender.cpp index a1f8b67ef..b4365a85b 100644 --- a/Telegram/SourceFiles/mtproto/concurrent_sender.cpp +++ b/Telegram/SourceFiles/mtproto/concurrent_sender.cpp @@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mtproto/mtp_instance.h" #include "mtproto/rpc_sender.h" -#include "mtproto/session.h" namespace MTP { @@ -180,11 +179,13 @@ void ConcurrentSender::senderRequestDone( bytes::const_span result) { if (auto handlers = _requests.take(requestId)) { try { - std::move(handlers->done)(requestId, result); + handlers->done(requestId, result); } catch (Exception &e) { - std::move(handlers->fail)(requestId, internal::rpcClientError( - "RESPONSE_PARSE_FAILED", - QString("exception text: ") + e.what())); + handlers->fail( + requestId, + RPCError::Local( + "RESPONSE_PARSE_FAILED", + QString("exception text: ") + e.what())); } } } @@ -193,7 +194,7 @@ void ConcurrentSender::senderRequestFail( mtpRequestId requestId, RPCError &&error) { if (auto handlers = _requests.take(requestId)) { - std::move(handlers->fail)(requestId, std::move(error)); + handlers->fail(requestId, std::move(error)); } } diff --git a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp index 752698250..e9746708d 100644 --- a/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp +++ b/Telegram/SourceFiles/mtproto/dedicated_file_loader.cpp @@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "mtproto/dedicated_file_loader.h" -#include "mtproto/session.h" #include "auth_session.h" #include "messenger.h" @@ -110,7 +109,9 @@ void WeakInstance::die() { if (instance) { instance->cancel(requestId); } - fail(MTP::internal::rpcClientError("UNAVAILABLE")); + fail(RPCError::Local( + "UNAVAILABLE", + "MTP instance is not available.")); } } @@ -125,7 +126,9 @@ bool WeakInstance::removeRequest(mtpRequestId requestId) { void WeakInstance::reportUnavailable( Fn callback) { InvokeQueued(this, [=] { - callback(MTP::internal::rpcClientError("UNAVAILABLE")); + callback(RPCError::Local( + "UNAVAILABLE", + "MTP instance is not available.")); }); } diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 675fe4ac2..590fe3cb2 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -956,7 +956,14 @@ void Instance::Private::clearCallbacks(mtpRequestId requestId, int32 errorCode) "Request: %1, error code: %2" ).arg(requestId ).arg(errorCode)); - rpcErrorOccured(requestId, h, internal::rpcClientError("CLEAR_CALLBACK", QString("did not handle request %1, error code %2").arg(requestId).arg(errorCode))); + rpcErrorOccured( + requestId, + h, + RPCError::Local( + "CLEAR_CALLBACK", + QString("did not handle request %1, error code %2" + ).arg(requestId + ).arg(errorCode))); } } @@ -1017,14 +1024,13 @@ void Instance::Private::execCallback( } } if (h.onDone || h.onFail) { - const auto handleError = [&](const MTPRpcError &error) { - const auto wrapped = RPCError(error); + const auto handleError = [&](const RPCError &error) { DEBUG_LOG(("RPC Info: " "error received, code %1, type %2, description: %3" - ).arg(wrapped.code() - ).arg(wrapped.type() - ).arg(wrapped.description())); - if (rpcErrorOccured(requestId, h, wrapped)) { + ).arg(error.code() + ).arg(error.type() + ).arg(error.description())); + if (rpcErrorOccured(requestId, h, error)) { unregisterRequest(requestId); } else { QMutexLocker locker(&_parserMapLock); @@ -1045,7 +1051,7 @@ void Instance::Private::execCallback( unregisterRequest(requestId); } } catch (Exception &e) { - handleError(internal::rpcClientError( + handleError(RPCError::Local( "RESPONSE_PARSE_FAILED", QString("exception text: ") + e.what())); } @@ -1103,7 +1109,10 @@ void Instance::Private::importDone(const MTPauth_Authorization &result, mtpReque // // Don't log out on export/import problems, perhaps this is a server side error. // - //RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find import request in requestsByDC, request %1").arg(requestId))); + //const auto error = RPCError::Local( + // "AUTH_IMPORT_FAIL", + // QString("did not find import request in requestsByDC, " + // "request %1").arg(requestId)); //if (_globalHandler.onFail && hasAuthorization()) { // (*_globalHandler.onFail)(requestId, error); // auth failed in main dc //} @@ -1156,7 +1165,10 @@ void Instance::Private::exportDone(const MTPauth_ExportedAuthorization &result, // // Don't log out on export/import problems, perhaps this is a server side error. // - //RPCError error(internal::rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dcWithShift, request %1").arg(requestId))); + //const auto error = RPCError::Local( + // "AUTH_IMPORT_FAIL", + // QString("did not find target dcWithShift, request %1" + // ).arg(requestId)); //if (_globalHandler.onFail && hasAuthorization()) { // (*_globalHandler.onFail)(requestId, error); // auth failed in main dc //} diff --git a/Telegram/SourceFiles/mtproto/rpc_sender.h b/Telegram/SourceFiles/mtproto/rpc_sender.h index f92a9a019..84c47449e 100644 --- a/Telegram/SourceFiles/mtproto/rpc_sender.h +++ b/Telegram/SourceFiles/mtproto/rpc_sender.h @@ -32,10 +32,21 @@ public: TimeoutError }; -private: + static RPCError Local(const QString &type, const QString &description) { + return MTP_rpc_error( + MTP_int(0), + MTP_bytes( + ("CLIENT_" + + type + + (description.length() + ? (": " + description) + : QString())).toUtf8())); + } +private: int32 _code; QString _type, _description; + }; namespace MTP { diff --git a/Telegram/SourceFiles/mtproto/session.cpp b/Telegram/SourceFiles/mtproto/session.cpp index be7573c10..6f5ef367f 100644 --- a/Telegram/SourceFiles/mtproto/session.cpp +++ b/Telegram/SourceFiles/mtproto/session.cpp @@ -156,8 +156,11 @@ void Session::createDcData() { connect(dc.get(), SIGNAL(connectionWasInited()), this, SLOT(connectionWasInitedForDC()), Qt::QueuedConnection); } -bool Session::rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data - return _instance->rpcErrorOccured(requestId, onFail, err); +bool Session::rpcErrorOccured( + mtpRequestId requestId, + const RPCFailHandlerPtr &onFail, + const RPCError &error) { // return true if need to clean request data + return _instance->rpcErrorOccured(requestId, onFail, error); } void Session::restart() { @@ -618,9 +621,5 @@ Session::~Session() { Assert(_connection == nullptr); } -MTPrpcError rpcClientError(const QString &type, const QString &description) { - return MTP_rpc_error(MTP_int(0), MTP_string(("CLIENT_" + type + (description.length() ? (": " + description) : "")).toUtf8().constData())); -} - } // namespace internal } // namespace MTP diff --git a/Telegram/SourceFiles/mtproto/session.h b/Telegram/SourceFiles/mtproto/session.h index da27be0d8..ebecb0389 100644 --- a/Telegram/SourceFiles/mtproto/session.h +++ b/Telegram/SourceFiles/mtproto/session.h @@ -402,7 +402,5 @@ inline not_null SessionData::keyMutex() const { return _owner->keyMutex(); } -MTPrpcError rpcClientError(const QString &type, const QString &description = QString()); - } // namespace internal } // namespace MTP diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 837b9760c..1e7d853c3 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -107,11 +107,7 @@ History *FindWastedPin() { } void AddChatMembers(not_null chat) { - if (chat->count >= Global::ChatSizeMax() && chat->amCreator()) { - // #TODO convert and add inside AddParticipantsBoxController? - } else { - AddParticipantsBoxController::Start(chat); - } + AddParticipantsBoxController::Start(chat); } bool PinnedLimitReached(Dialogs::Key key) {