diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 922e4ad7e..37ddc7d5b 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -128,6 +128,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_gif_error" = "An error has occurred while reading GIF animation :("; "lng_edit_error" = "You cannot edit this message"; "lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining this one."; +"lng_migrate_error" = "This action will convert the group to a supergroup. Unfortunately, you are a member of too many supergroups and channels. Please leave some of the channels or groups you don't need before proceeding."; "lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again."; "lng_error_start_minimized_passcoded" = "You have set a local passcode, so Telegram Desktop can't be launched minimised; it will ask you to enter your passcode before it can start working."; "lng_error_pinned_max#one" = "Sorry, you can pin no more than {count} chat to the top."; @@ -797,6 +798,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_manage_history_visibility_shown_about" = "New members will see messages that were sent before they joined."; "lng_manage_history_visibility_hidden" = "Hidden"; "lng_manage_history_visibility_hidden_about" = "New members won't see earlier messages."; +"lng_manage_history_visibility_hidden_legacy" = "New members won't see more than 100 previous messages."; "lng_report_title" = "Report channel"; "lng_report_group_title" = "Report group"; @@ -957,8 +959,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_convert_feature4" = "— Creator can set a public link for the group"; "lng_profile_convert_warning" = "{bold_start}Note:{bold_end} This action can not be undone"; "lng_profile_convert_confirm" = "Convert"; -"lng_profile_add_more_after_upgrade#one" = "You will be able to add up to {count} member after you upgrade your group to a supergroup."; -"lng_profile_add_more_after_upgrade#other" = "You will be able to add up to {count} members after you upgrade your group to a supergroup."; +"lng_profile_add_more_after_create" = "You will be able to add more members after you create the group."; "lng_channel_not_accessible" = "Sorry, this channel is not accessible."; "lng_group_not_accessible" = "Sorry, this group is not accessible."; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 845ebde7f..c6e6c3bc3 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -886,6 +886,7 @@ void ApiWrap::requestFullPeer(not_null peer) { const auto requestId = [&] { const auto failHandler = [=](const RPCError &error) { _fullPeerRequests.remove(peer); + migrateFail(peer, error); }; if (const auto user = peer->asUser()) { if (_session->supportMode()) { @@ -911,6 +912,7 @@ void ApiWrap::requestFullPeer(not_null peer) { const MTPmessages_ChatFull &result, mtpRequestId requestId) { gotChatFull(peer, result, requestId); + migrateDone(channel, channel); }).fail(failHandler).send(); } Unexpected("Peer type in requestFullPeer."); @@ -993,40 +995,18 @@ void ApiWrap::gotChatFull( channel->setUserpicPhoto(f.vchat_photo); if (f.has_migrated_from_chat_id()) { channel->addFlags(MTPDchannel::Flag::f_megagroup); - auto cfrom = App::chat(peerFromChat(f.vmigrated_from_chat_id)); - bool updatedTo = (cfrom->migrateToPtr != channel), updatedFrom = (channel->mgInfo->migrateFromPtr != cfrom); - if (updatedTo) { - cfrom->migrateToPtr = channel; - } - if (updatedFrom) { - channel->mgInfo->migrateFromPtr = cfrom; - if (auto h = App::historyLoaded(cfrom->id)) { - if (auto hto = App::historyLoaded(channel->id)) { - if (!h->isEmpty()) { - h->unloadBlocks(); - } - if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { - App::main()->removeDialog(h); - } - } - } - Notify::migrateUpdated(channel); - } - if (updatedTo) { - Notify::migrateUpdated(cfrom); - } + const auto chat = channel->owner().chat( + peerFromChat(f.vmigrated_from_chat_id)); + Data::ApplyMigration(chat, channel); } - auto &v = f.vbot_info.v; - for_const (auto &item, v) { - switch (item.type()) { - case mtpc_botInfo: { - auto &b = item.c_botInfo(); - if (auto user = App::userLoaded(b.vuser_id.v)) { + for (const auto &item : f.vbot_info.v) { + auto &owner = channel->owner(); + item.match([&](const MTPDbotInfo &info) { + if (const auto user = owner.userLoaded(info.vuser_id.v)) { user->setBotInfo(item); fullPeerUpdated().notify(user); } - } break; - } + }); } channel->setAbout(qs(f.vabout)); channel->setMembersCount(f.has_participants_count() ? f.vparticipants_count.v : 0); @@ -1179,56 +1159,81 @@ void ApiWrap::migrateChat( if (i != end(_migrateCallbacks)) { i->second.push_back(callback()); return; - } else if (const auto channel = chat->migrateTo()) { + } + _migrateCallbacks.emplace(chat).first->second.push_back(callback()); + 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); + crl::on_main([=] { + migrateDone(chat, channel); }); } else if (chat->isDeactivated()) { - crl::on_main([fail = std::move(fail)]() mutable { - fail(RPCError::Local( - "BAD_MIGRATION", - "Chat is already deactivated")); + crl::on_main([=] { + migrateFail( + chat, + 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")); + crl::on_main([=] { + migrateFail( + chat, + 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")); - } + if (const auto channel = chat->migrateTo()) { + if (auto handlers = _migrateCallbacks.take(chat)) { + _migrateCallbacks.emplace(channel, std::move(*handlers)); } + requestFullPeer(channel); + } else { + migrateFail( + chat, + RPCError::Local("MIGRATION_FAIL", "No channel")); } }).fail([=](const RPCError &error) { - if (auto handlers = _migrateCallbacks.take(chat)) { - for (auto &handler : *handlers) { + migrateFail(chat, error); + }).send(); +} + +void ApiWrap::migrateDone( + not_null peer, + not_null channel) { + Notify::peerUpdatedSendDelayed(); + if (auto handlers = _migrateCallbacks.take(peer)) { + for (auto &handler : *handlers) { + if (handler.done) { + handler.done(channel); + } + } + } +} + +void ApiWrap::migrateFail(not_null peer, const RPCError &error) { + const auto &type = error.type(); + if (type == qstr("CHANNELS_TOO_MUCH")) { + Ui::show(Box(lang(lng_migrate_error))); + } + if (auto handlers = _migrateCallbacks.take(peer)) { + for (auto &handler : *handlers) { + if (handler.fail) { handler.fail(error); } } - }).send(); + } } void ApiWrap::markMediaRead( @@ -5059,6 +5064,7 @@ void ApiWrap::requestSupportContact(FnMut callback) { } void ApiWrap::uploadPeerPhoto(not_null peer, QImage &&image) { + peer = peer->migrateToOrMe(); const auto ready = PreparePeerPhoto(peer->id, std::move(image)); const auto fakeId = FullMsgId(peerToChannel(peer->id), clientMsgId()); diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 9341691a1..5117353f2 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -587,6 +587,11 @@ private: void setSelfDestructDays(int days); + void migrateDone( + not_null peer, + not_null channel); + void migrateFail(not_null peer, const RPCError &error); + not_null _session; MessageDataRequests _messageDataRequests; @@ -737,7 +742,7 @@ private: FnMut fail; }; base::flat_map< - not_null, + not_null, std::vector> _migrateCallbacks; std::vector> _supportContactCallbacks; diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 9bef60992..22f13015d 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -348,3 +348,45 @@ enum CreatingGroupType { CreatingGroupGroup, CreatingGroupChannel, }; + +class BoxPointer { +public: + BoxPointer() = default; + BoxPointer(const BoxPointer &other) = default; + BoxPointer(BoxPointer &&other) : _value(base::take(other._value)) { + } + BoxPointer &operator=(const BoxPointer &other) { + if (_value != other._value) { + destroy(); + _value = other._value; + } + return *this; + } + BoxPointer &operator=(BoxPointer &&other) { + if (_value != other._value) { + destroy(); + _value = base::take(other._value); + } + return *this; + } + BoxPointer &operator=(BoxContent *other) { + if (_value != other) { + destroy(); + _value = other; + } + return *this; + } + ~BoxPointer() { + destroy(); + } + +private: + void destroy() { + if (const auto value = base::take(_value)) { + value->closeBox(); + } + } + + QPointer _value; + +}; diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index 1696e4e76..dc00e279c 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -86,11 +86,8 @@ void AddParticipantsBoxController::rowClicked(not_null row) { } } 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(lang(lng_profile_add_more_after_create)), LayerOption::KeepOther); } } @@ -454,11 +451,7 @@ void AddSpecialBoxController::showAdmin( if (!checkInfoLoaded(user, [=] { showAdmin(user); })) { return; } - - if (sure && _editBox) { - // Close the confirmation box. - _editBox->closeBox(); - } + _editBox = nullptr; const auto chat = _peer->asChat(); const auto channel = _peer->asChannel(); @@ -555,9 +548,7 @@ void AddSpecialBoxController::showAdmin( editAdminDone(user, newRights); }); const auto fail = crl::guard(this, [=] { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; }); box->setSaveCallback(SaveAdminCallback(_peer, user, done, fail)); } @@ -567,7 +558,7 @@ void AddSpecialBoxController::showAdmin( void AddSpecialBoxController::editAdminDone( not_null user, const MTPChatAdminRights &rights) { - if (_editBox) _editBox->closeBox(); + _editBox = nullptr; const auto date = unixtime(); // Incorrect, but ignored. if (rights.c_chatAdminRights().vflags.v == 0) { @@ -597,11 +588,7 @@ void AddSpecialBoxController::showRestricted( if (!checkInfoLoaded(user, [=] { showRestricted(user); })) { return; } - - if (sure && _editBox) { - // Close the confirmation box. - _editBox->closeBox(); - } + _editBox = nullptr; const auto chat = _peer->asChat(); const auto channel = _peer->asChannel(); @@ -650,9 +637,7 @@ void AddSpecialBoxController::showRestricted( editRestrictedDone(user, newRights); }); const auto fail = crl::guard(this, [=] { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; }); box->setSaveCallback( SaveRestrictedCallback(_peer, user, done, fail)); @@ -663,7 +648,7 @@ void AddSpecialBoxController::showRestricted( void AddSpecialBoxController::editRestrictedDone( not_null user, const MTPChatBannedRights &rights) { - if (_editBox) _editBox->closeBox(); + _editBox = nullptr; const auto date = unixtime(); // Incorrect, but ignored. if (rights.c_chatBannedRights().vflags.v == 0) { @@ -731,6 +716,8 @@ void AddSpecialBoxController::kickUser( LayerOption::KeepOther); return; } + + _editBox = nullptr; const auto restrictedRights = _additional.restrictedRights(user); const auto currentRights = restrictedRights ? *restrictedRights diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.h b/Telegram/SourceFiles/boxes/peers/add_participants_box.h index 1eac6897b..3fa536cb0 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.h +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.h @@ -115,7 +115,7 @@ private: bool _allLoaded = false; ParticipantsAdditionalData _additional; std::unique_ptr _onlineSorter; - QPointer _editBox; + BoxPointer _editBox; AdminDoneCallback _adminDoneCallback; BannedDoneCallback _bannedDoneCallback; diff --git a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp index 782889cd8..a0f881361 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participant_box.cpp @@ -212,17 +212,20 @@ void EditAdminBox::prepare() { const auto chat = peer()->asChat(); const auto channel = peer()->asChannel(); const auto prepareRights = hadRights ? _oldRights : Defaults(peer()); + const auto disabledByDefaults = DisabledByDefaultRestrictions(peer()); const auto filterByMyRights = canSave() && !hadRights && channel && !channel->amCreator(); - const auto prepareFlags = prepareRights.c_chatAdminRights().vflags.v - & (filterByMyRights ? channel->adminRights() : ~Flag(0)); + const auto prepareFlags = disabledByDefaults + | (prepareRights.c_chatAdminRights().vflags.v + & (filterByMyRights ? channel->adminRights() : ~Flag(0))); const auto disabledFlags = canSave() - ? ((!channel || channel->amCreator()) - ? Flags(0) - : ~channel->adminRights()) + ? (disabledByDefaults + | ((!channel || channel->amCreator()) + ? Flags(0) + : ~channel->adminRights())) : ~Flags(0); const auto anyoneCanAddMembers = chat diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index 1382b5518..1fe0e71b6 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -802,6 +802,7 @@ void ParticipantsBoxController::addNewItem() { const auto initBox = [](not_null box) { box->addButton(langFactory(lng_cancel), [=] { box->closeBox(); }); }; + _addBox = Ui::show( Box( std::make_unique( @@ -1352,9 +1353,7 @@ void ParticipantsBoxController::showAdmin(not_null user) { editAdminDone(user, newRights); }); const auto fail = crl::guard(this, [=] { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; }); box->setSaveCallback(SaveAdminCallback(_peer, user, done, fail)); } @@ -1364,12 +1363,9 @@ void ParticipantsBoxController::showAdmin(not_null user) { void ParticipantsBoxController::editAdminDone( not_null user, const MTPChatAdminRights &rights) { - if (_editBox) { - _editBox->closeBox(); - } - if (_addBox) { - _addBox->closeBox(); - } + _addBox = nullptr; + _editBox = nullptr; + const auto date = unixtime(); // Incorrect, but ignored. if (rights.c_chatAdminRights().vflags.v == 0) { _additional.applyParticipant(MTP_channelParticipant( @@ -1420,9 +1416,7 @@ void ParticipantsBoxController::showRestricted(not_null user) { editRestrictedDone(user, newRights); }); const auto fail = crl::guard(this, [=] { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; }); box->setSaveCallback( SaveRestrictedCallback(_peer, user, done, fail)); @@ -1433,12 +1427,9 @@ void ParticipantsBoxController::showRestricted(not_null user) { void ParticipantsBoxController::editRestrictedDone( not_null user, const MTPChatBannedRights &rights) { - if (_editBox) { - _editBox->closeBox(); - } - if (_addBox) { - _addBox->closeBox(); - } + _addBox = nullptr; + _editBox = nullptr; + const auto date = unixtime(); // Incorrect, but ignored. if (rights.c_chatBannedRights().vflags.v == 0) { _additional.applyParticipant(MTP_channelParticipant( @@ -1495,9 +1486,8 @@ void ParticipantsBoxController::kickMember(not_null user) { } void ParticipantsBoxController::kickMemberSure(not_null user) { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; + const auto restrictedRights = _additional.restrictedRights(user); const auto currentRights = restrictedRights ? *restrictedRights @@ -1529,9 +1519,8 @@ void ParticipantsBoxController::removeAdmin(not_null user) { } void ParticipantsBoxController::removeAdminSure(not_null user) { - if (_editBox) { - _editBox->closeBox(); - } + _editBox = nullptr; + if (const auto chat = _peer->asChat()) { SaveChatAdmin(chat, user, false, crl::guard(this, [=] { editAdminDone(user, MTP_chatAdminRights(MTP_flags(0))); diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h index 58e16fa6c..1017ba70c 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h @@ -234,8 +234,8 @@ private: bool _allLoaded = false; ParticipantsAdditionalData _additional; std::unique_ptr _onlineSorter; - QPointer _editBox; - QPointer _addBox; + BoxPointer _editBox; + BoxPointer _addBox; }; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp index 33a6c70b9..d114fa9ca 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/add_contact_box.h" #include "boxes/stickers_box.h" #include "boxes/peer_list_controllers.h" +#include "boxes/peers/edit_participants_box.h" #include "data/data_peer.h" #include "data/data_chat.h" #include "data/data_channel.h" @@ -114,6 +115,7 @@ private: object_ptr createDeleteButton(); QString inviteLinkText() const; + void observeInviteLink(); void submitTitle(); void submitDescription(); @@ -157,6 +159,9 @@ private: void continueSave(); void cancelSave(); + void subscribeToMigration(); + void migrate(not_null channel); + not_null _box; not_null _peer; bool _isGroup = false; @@ -171,6 +176,8 @@ private: std::deque> _saveStagesQueue; Saving _savingData; + rpl::lifetime _lifetime; + }; Controller::Controller( @@ -179,7 +186,7 @@ Controller::Controller( : _box(box) , _peer(peer) , _isGroup(_peer->isChat() || _peer->isMegagroup()) -, _checkUsernameTimer([this] { checkUsernameAvailability(); }) { +, _checkUsernameTimer([=] { checkUsernameAvailability(); }) { _box->setTitle(computeTitle()); _box->addButton(langFactory(lng_settings_save), [this] { save(); @@ -187,6 +194,21 @@ Controller::Controller( _box->addButton(langFactory(lng_cancel), [this] { _box->closeBox(); }); + subscribeToMigration(); + _peer->updateFull(); +} + +void Controller::subscribeToMigration() { + SubscribeToMigration( + _peer, + _lifetime, + [=](not_null channel) { migrate(channel); }); +} + +void Controller::migrate(not_null channel) { + _peer = channel; + observeInviteLink(); + _peer->updateFull(); } Fn Controller::computeTitle() const { @@ -222,10 +244,10 @@ void Controller::setFocus() { object_ptr Controller::createPhotoAndTitleEdit() { Expects(_wrap != nullptr); - auto canEdit = [&] { - if (auto channel = _peer->asChannel()) { + const auto canEdit = [&] { + if (const auto channel = _peer->asChannel()) { return channel->canEditInformation(); - } else if (auto chat = _peer->asChat()) { + } else if (const auto chat = _peer->asChat()) { return chat->canEditInformation(); } return false; @@ -516,7 +538,7 @@ void Controller::checkUsernameAvailability() { if (_checkUsernameRequestId) { request(_checkUsernameRequestId).cancel(); } - const auto channel = _peer->asChannel(); + const auto channel = _peer->migrateToOrMe()->asChannel(); const auto username = channel ? channel->username : QString(); _checkUsernameRequestId = request(MTPchannels_CheckUsername( channel ? channel->inputChannel : MTP_inputChannelEmpty(), @@ -534,7 +556,7 @@ void Controller::checkUsernameAvailability() { } }).fail([=](const RPCError &error) { _checkUsernameRequestId = 0; - auto type = error.type(); + const auto &type = error.type(); _usernameState = UsernameState::Normal; if (type == qstr("CHANNEL_PUBLIC_GROUP_NA")) { _usernameState = UsernameState::NotAvailable; @@ -643,10 +665,10 @@ void Controller::revokeInviteLink() { void Controller::exportInviteLink(const QString &confirmation) { auto boxPointer = std::make_shared>(); auto callback = crl::guard(this, [=] { - if (auto strong = *boxPointer) { + if (const auto strong = *boxPointer) { strong->closeBox(); } - Auth().api().exportInviteLink(_peer); + Auth().api().exportInviteLink(_peer->migrateToOrMe()); }); auto box = Box( confirmation, @@ -656,12 +678,11 @@ void Controller::exportInviteLink(const QString &confirmation) { bool Controller::canEditInviteLink() const { if (const auto channel = _peer->asChannel()) { - if (channel->canEditUsername()) { - return true; - } - return (!channel->isPublic() && channel->canAddMembers()); + return channel->amCreator() + || (channel->adminRights() & ChatAdminRight::f_invite_users); } else if (const auto chat = _peer->asChat()) { - return chat->amCreator() || !chat->inviteLink().isEmpty(); + return chat->amCreator() + || (chat->adminRights() & ChatAdminRight::f_invite_users); } return false; } @@ -680,6 +701,18 @@ QString Controller::inviteLinkText() const { return QString(); } +void Controller::observeInviteLink() { + if (!_controls.editInviteLinkWrap) { + return; + } + Notify::PeerUpdateValue( + _peer, + Notify::PeerUpdate::Flag::InviteLinkChanged + ) | rpl::start_with_next([=] { + refreshEditInviteLink(); + }, _controls.editInviteLinkWrap->lifetime()); +} + object_ptr Controller::createInviteLinkEdit() { Expects(_wrap != nullptr); @@ -721,14 +754,9 @@ object_ptr Controller::createInviteLinkEdit() { container, lang(lng_group_invite_create_new), st::editPeerInviteLinkButton) - )->addClickHandler([this] { revokeInviteLink(); }); + )->addClickHandler([=] { revokeInviteLink(); }); - Notify::PeerUpdateValue( - _peer, - Notify::PeerUpdate::Flag::InviteLinkChanged - ) | rpl::start_with_next([this] { - refreshEditInviteLink(); - }, _controls.editInviteLinkWrap->lifetime()); + observeInviteLink(); return std::move(result); } @@ -788,12 +816,7 @@ object_ptr Controller::createInviteLinkCreate() { }); _controls.createInviteLinkWrap = result.data(); - Notify::PeerUpdateValue( - _peer, - Notify::PeerUpdate::Flag::InviteLinkChanged - ) | rpl::start_with_next([this] { - refreshCreateInviteLink(); - }, _controls.createInviteLinkWrap->lifetime()); + observeInviteLink(); return std::move(result); } @@ -865,7 +888,9 @@ object_ptr Controller::createHistoryVisibilityEdit() { addButton( HistoryVisibility::Hidden, lng_manage_history_visibility_hidden, - lng_manage_history_visibility_hidden_about); + (_peer->isChat() + ? lng_manage_history_visibility_hidden_legacy + : lng_manage_history_visibility_hidden_about)); refreshHistoryVisibility(); @@ -1258,7 +1283,7 @@ void Controller::saveHistoryVisibility() { Auth().api().applyUpdates(result); continueSave(); - }).fail([this](const RPCError &error) { + }).fail([=](const RPCError &error) { if (error.type() == qstr("CHAT_NOT_MODIFIED")) { continueSave(); } else { @@ -1340,7 +1365,7 @@ void Controller::deleteChannel() { EditPeerInfoBox::EditPeerInfoBox( QWidget*, not_null peer) -: _peer(peer) { +: _peer(peer->migrateToOrMe()) { } void EditPeerInfoBox::prepare() { diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp index 4b3b48135..c3c87ebf9 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.cpp @@ -215,10 +215,40 @@ ChatRestrictions DisabledByAdminRights(not_null peer) { } // namespace +ChatAdminRights DisabledByDefaultRestrictions(not_null peer) { + using Flag = ChatAdminRight; + using Restriction = ChatRestriction; + + const auto restrictions = [&] { + if (const auto chat = peer->asChat()) { + return chat->defaultRestrictions(); + } else if (const auto channel = peer->asChannel()) { + return channel->defaultRestrictions(); + } + Unexpected("User in DisabledByDefaultRestrictions."); + }(); + return Flag(0) + | ((restrictions & Restriction::f_pin_messages) + ? Flag(0) + : Flag::f_pin_messages) + // + // We allow to edit 'invite_users' admin right no matter what + // is chosen in default permissions for 'invite_users', because + // if everyone can 'invite_users' it handles invite link for admins. + // + //| ((restrictions & Restriction::f_invite_users) + // ? Flag(0) + // : Flag::f_invite_users) + // + | ((restrictions & Restriction::f_change_info) + ? Flag(0) + : Flag::f_change_info); +} + EditPeerPermissionsBox::EditPeerPermissionsBox( QWidget*, not_null peer) -: _peer(peer) { +: _peer(peer->migrateToOrMe()) { } auto EditPeerPermissionsBox::saveEvents() const @@ -282,12 +312,18 @@ void EditPeerPermissionsBox::prepare() { void EditPeerPermissionsBox::addBannedButtons( not_null container) { + if (const auto chat = _peer->asChat()) { + if (!chat->amCreator()) { + return; + } + } + const auto channel = _peer->asChannel(); + container->add( object_ptr(container), { 0, st::infoProfileSkip, 0, st::infoProfileSkip }); const auto navigation = App::wnd()->controller(); - const auto channel = _peer->asChannel(); ManagePeerBox::CreateButton( container, Lang::Viewer(lng_manage_peer_exceptions), diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h index 555991ced..f771bb38a 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_permissions_box.h @@ -55,3 +55,5 @@ EditFlagsControl CreateEditAdminRights( MTPDchatAdminRights::Flags disabled, bool isGroup, bool anyoneCanAddMembers); + +ChatAdminRights DisabledByDefaultRestrictions(not_null peer); diff --git a/Telegram/SourceFiles/boxes/peers/manage_peer_box.cpp b/Telegram/SourceFiles/boxes/peers/manage_peer_box.cpp index 38134cfe4..ee4daf6dc 100644 --- a/Telegram/SourceFiles/boxes/peers/manage_peer_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/manage_peer_box.cpp @@ -107,8 +107,8 @@ void ShowEditPermissions(not_null peer) { box->closeBox(); } }); - Auth().api().saveDefaultRestrictions( - peer, + peer->session().api().saveDefaultRestrictions( + peer->migrateToOrMe(), MTP_chatBannedRights(MTP_flags(restrictions), MTP_int(0)), callback); }, box->lifetime()); diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp index 9b9a09b25..40f5ed35c 100644 --- a/Telegram/SourceFiles/data/data_channel.cpp +++ b/Telegram/SourceFiles/data/data_channel.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer_values.h" #include "data/data_channel_admins.h" #include "data/data_user.h" +#include "data/data_chat.h" #include "data/data_session.h" #include "data/data_feed.h" #include "observer_peer.h" @@ -22,13 +23,21 @@ using UpdateFlag = Notify::PeerUpdate::Flag; } // namespace +ChatData *MegagroupInfo::getMigrateFromChat() const { + return _migratedFrom; +} + +void MegagroupInfo::setMigrateFromChat(ChatData *chat) { + _migratedFrom = chat; +} + ChannelData::ChannelData(not_null owner, PeerId id) : PeerData(owner, id) , inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))) { Data::PeerFlagValue( this, MTPDchannel::Flag::f_megagroup - ) | rpl::start_with_next([this](bool megagroup) { + ) | rpl::start_with_next([=](bool megagroup) { if (megagroup) { if (!mgInfo) { mgInfo = std::make_unique(); @@ -37,6 +46,17 @@ ChannelData::ChannelData(not_null owner, PeerId id) mgInfo = nullptr; } }, _lifetime); + + Data::PeerFlagsValue( + this, + MTPDchannel::Flag::f_left | MTPDchannel_ClientFlag::f_forbidden + ) | rpl::distinct_until_changed( + ) | rpl::start_with_next([=] { + if (const auto chat = getMigrateFromChat()) { + Notify::peerUpdatedDelayed(chat, UpdateFlag::MigrationChanged); + Notify::peerUpdatedDelayed(this, UpdateFlag::MigrationChanged); + } + }, _lifetime); } void ChannelData::setPhoto(const MTPChatPhoto &photo) { @@ -365,7 +385,8 @@ bool ChannelData::canEditInformation() const { } bool ChannelData::canEditPermissions() const { - return isMegagroup() && (hasAdminRights() || amCreator()); + return isMegagroup() + && ((adminRights() & AdminRight::f_ban_users) || amCreator()); } bool ChannelData::canEditSignatures() const { @@ -495,8 +516,36 @@ auto ChannelData::applyUpdateVersion(int version) -> UpdateStatus { return UpdateStatus::Good; } +ChatData *ChannelData::getMigrateFromChat() const { + if (const auto info = mgInfo.get()) { + return info->getMigrateFromChat(); + } + return nullptr; +} + +void ChannelData::setMigrateFromChat(ChatData *chat) { + Expects(mgInfo != nullptr); + + const auto info = mgInfo.get(); + if (chat != info->getMigrateFromChat()) { + info->setMigrateFromChat(chat); + if (amIn()) { + Notify::peerUpdatedDelayed(this, UpdateFlag::MigrationChanged); + } + } +} + namespace Data { +void ApplyMigration( + not_null chat, + not_null channel) { + Expects(channel->isMegagroup()); + + chat->setMigrateToChannel(channel); + channel->setMigrateFromChat(chat); +} + void ApplyChannelUpdate( not_null channel, const MTPDupdateChatDefaultBannedRights &update) { diff --git a/Telegram/SourceFiles/data/data_channel.h b/Telegram/SourceFiles/data/data_channel.h index 99df5874f..def708ad4 100644 --- a/Telegram/SourceFiles/data/data_channel.h +++ b/Telegram/SourceFiles/data/data_channel.h @@ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_peer.h" #include "data/data_pts_waiter.h" -struct MegagroupInfo { +class MegagroupInfo { +public: struct Admin { explicit Admin(MTPChatAdminRights rights) : rights(rights) { @@ -30,6 +31,9 @@ struct MegagroupInfo { MTPChatBannedRights rights; }; + ChatData *getMigrateFromChat() const; + void setMigrateFromChat(ChatData *chat); + std::deque> lastParticipants; base::flat_map, Admin> lastAdmins; base::flat_map, Restricted> lastRestricted; @@ -51,7 +55,8 @@ struct MegagroupInfo { mutable int lastParticipantsStatus = LastParticipantsUpToDate; int lastParticipantsCount = 0; - ChatData *migrateFromPtr = nullptr; +private: + ChatData *_migratedFrom = nullptr; }; @@ -60,6 +65,7 @@ public: static constexpr auto kEssentialFlags = 0 | MTPDchannel::Flag::f_creator | MTPDchannel::Flag::f_left + | MTPDchannel_ClientFlag::f_forbidden | MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup @@ -339,6 +345,9 @@ public: } UpdateStatus applyUpdateVersion(int version); + ChatData *getMigrateFromChat() const; + void setMigrateFromChat(ChatData *chat); + // Still public data members. uint64 access = 0; @@ -384,6 +393,10 @@ private: namespace Data { +void ApplyMigration( + not_null chat, + not_null channel); + void ApplyChannelUpdate( not_null channel, const MTPDupdateChatDefaultBannedRights &update); diff --git a/Telegram/SourceFiles/data/data_chat.cpp b/Telegram/SourceFiles/data/data_chat.cpp index c8b37fde6..c9f23265f 100644 --- a/Telegram/SourceFiles/data/data_chat.cpp +++ b/Telegram/SourceFiles/data/data_chat.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_chat.h" #include "data/data_user.h" +#include "data/data_channel.h" #include "data/data_session.h" #include "history/history.h" #include "auth_session.h" @@ -64,7 +65,7 @@ bool ChatData::canEditInformation() const { bool ChatData::canEditPermissions() const { return !actionsUnavailable() - && (amCreator() || hasAdminRights()); + && (amCreator() || (adminRights() & AdminRight::f_ban_users)); } bool ChatData::canEditUsername() const { @@ -177,6 +178,19 @@ auto ChatData::applyUpdateVersion(int version) -> UpdateStatus { return UpdateStatus::Good; } +ChannelData *ChatData::getMigrateToChannel() const { + return _migratedTo; +} + +void ChatData::setMigrateToChannel(ChannelData *channel) { + if (_migratedTo != channel) { + _migratedTo = channel; + if (channel->amIn()) { + Notify::peerUpdatedDelayed(this, UpdateFlag::MigrationChanged); + } + } +} + namespace Data { void ApplyChatUpdate( diff --git a/Telegram/SourceFiles/data/data_chat.h b/Telegram/SourceFiles/data/data_chat.h index 41ec72234..66d88a4ca 100644 --- a/Telegram/SourceFiles/data/data_chat.h +++ b/Telegram/SourceFiles/data/data_chat.h @@ -156,11 +156,12 @@ public: } UpdateStatus applyUpdateVersion(int version); + ChannelData *getMigrateToChannel() const; + void setMigrateToChannel(ChannelData *channel); + // Still public data members. MTPint inputChat; - ChannelData *migrateToPtr = nullptr; - int count = 0; TimeId date = 0; UserId creator = 0; @@ -184,6 +185,8 @@ private: AdminRightFlags _adminRights; int _version = 0; + ChannelData *_migratedTo = nullptr; + }; namespace Data { diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 55e77b4df..82b3cca3d 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -520,7 +520,7 @@ const ChannelData *PeerData::asChannelOrMigrated() const { ChatData *PeerData::migrateFrom() const { if (const auto megagroup = asMegagroup()) { return megagroup->amIn() - ? megagroup->mgInfo->migrateFromPtr + ? megagroup->getMigrateFromChat() : nullptr; } return nullptr; @@ -528,13 +528,27 @@ ChatData *PeerData::migrateFrom() const { ChannelData *PeerData::migrateTo() const { if (const auto chat = asChat()) { - if (const auto migrateTo = chat->migrateToPtr) { - return migrateTo->amIn() ? migrateTo : nullptr; + if (const auto result = chat->getMigrateToChannel()) { + return result->amIn() ? result : nullptr; } } return nullptr; } +not_null PeerData::migrateToOrMe() { + if (const auto channel = migrateTo()) { + return channel; + } + return this; +} + +not_null PeerData::migrateToOrMe() const { + if (const auto channel = migrateTo()) { + return channel; + } + return this; +} + Data::Feed *PeerData::feed() const { if (const auto channel = asChannel()) { return channel->feed(); diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 02dee74c2..33cab9608 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -117,6 +117,8 @@ public: [[nodiscard]] ChatData *migrateFrom() const; [[nodiscard]] ChannelData *migrateTo() const; + [[nodiscard]] not_null migrateToOrMe(); + [[nodiscard]] not_null migrateToOrMe() const; [[nodiscard]] Data::Feed *feed() const; void updateFull(); diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 531874a50..ef1938416 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "auth_session.h" #include "apiwrap.h" #include "messenger.h" -#include "mainwidget.h" // for main()->removeDialog #include "core/crash_reports.h" // for CrashReports::SetAnnotation #include "ui/image/image.h" #include "export/export_controller.h" @@ -455,35 +454,13 @@ not_null Session::chat(const MTPChat &data) { const auto channel = this->channel(input.vchannel_id.v); channel->addFlags(MTPDchannel::Flag::f_megagroup); if (!channel->access) { - channel->input = MTP_inputPeerChannel(input.vchannel_id, input.vaccess_hash); - channel->inputChannel = data.vmigrated_to; + channel->input = MTP_inputPeerChannel( + input.vchannel_id, + input.vaccess_hash); + channel->inputChannel = migratedTo; channel->access = input.vaccess_hash.v; } - const auto updatedTo = (chat->migrateToPtr != channel); - const auto updatedFrom = (channel->mgInfo->migrateFromPtr != chat); - if (updatedTo) { - chat->migrateToPtr = channel; - } - if (updatedFrom) { - channel->mgInfo->migrateFromPtr = chat; - if (const auto h = historyLoaded(chat->id)) { - if (const auto hto = historyLoaded(channel->id)) { - if (!h->isEmpty()) { - h->unloadBlocks(); - } - if (hto->inChatList(Dialogs::Mode::All) - && h->inChatList(Dialogs::Mode::All)) { - App::main()->removeDialog(h); - } - } - } - Notify::migrateUpdated(channel); - update.flags |= UpdateFlag::MigrationChanged; - } - if (updatedTo) { - Notify::migrateUpdated(chat); - update.flags |= UpdateFlag::MigrationChanged; - } + ApplyMigration(chat, channel); }, [](const MTPDinputChannelEmpty &) { }); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 24f896ebc..5dc2df70c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -139,8 +139,9 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro | UpdateFlag::NameChanged | UpdateFlag::PhotoChanged | UpdateFlag::UserIsContact - | UpdateFlag::UserOccupiedChanged; - subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [this](const Notify::PeerUpdate &update) { + | UpdateFlag::UserOccupiedChanged + | UpdateFlag::MigrationChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(changes, [=](const Notify::PeerUpdate &update) { if (update.flags & UpdateFlag::ChatPinnedChanged) { stopReorderPinned(); } @@ -156,6 +157,11 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro userIsContactUpdated(user); } } + if (update.flags & UpdateFlag::MigrationChanged) { + if (const auto chat = update.peer->asChat()) { + handleChatMigration(chat); + } + } })); Auth().data().feedUpdated( ) | rpl::start_with_next([=](const Data::FeedUpdate &update) { @@ -175,6 +181,22 @@ DialogsInner::DialogsInner(QWidget *parent, not_null contro setupShortcuts(); } +void DialogsInner::handleChatMigration(not_null chat) { + const auto channel = chat->migrateTo(); + if (!channel) { + return; + } + + if (const auto from = chat->owner().historyLoaded(chat)) { + if (const auto to = chat->owner().historyLoaded(channel)) { + if (to->inChatList(Dialogs::Mode::All) + && from->inChatList(Dialogs::Mode::All)) { + removeDialog(from); + } + } + } +} + int DialogsInner::dialogsOffset() const { return _dialogsImportant ? st::dialogsImportantBarHeight : 0; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 6d03e5597..f84740860 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -289,6 +289,7 @@ private: int countPinnedIndex(Dialogs::Row *ofRow); void savePinnedOrder(); void step_pinnedShifting(TimeMs ms, bool timer); + void handleChatMigration(not_null chat); not_null _controller; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index c4d990085..b39b16ec3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -310,7 +310,7 @@ void DialogsWidget::createDialog(Dialogs::Key key) { if (const auto migrated = App::historyLoaded( history->peer->migrateFrom())) { if (migrated->inChatList(Dialogs::Mode::All)) { - removeDialog(migrated); + _inner->removeDialog(migrated); } } } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 14a0ca443..39b27bcf3 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -321,10 +321,6 @@ bool switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, return false; } -void migrateUpdated(PeerData *peer) { - if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); -} - void historyMuteUpdated(History *history) { if (MainWidget *m = App::main()) m->notify_historyMuteUpdated(history); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 64a41ad72..7469866a3 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -149,8 +149,6 @@ void replyMarkupUpdated(const HistoryItem *item); void inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); bool switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot = nullptr, MsgId samePeerReplyTo = 0); -void migrateUpdated(PeerData *peer); - void historyMuteUpdated(History *history); void unreadCounterUpdated(); @@ -323,7 +321,7 @@ DeclareRefVar(base::Variable, WorkMode); DeclareRefVar(base::Observable, UnreadCounterUpdate); DeclareRefVar(base::Observable, PeerChooseCancel); - + DeclareVar(QString, CallOutputDeviceID); DeclareVar(QString, CallInputDeviceID); DeclareVar(int, CallOutputVolume); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index c3db626fc..8b9b3ed73 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -430,11 +430,7 @@ HistoryWidget::HistoryWidget( unreadCountUpdated(); } if (update.flags & UpdateFlag::MigrationChanged) { - if (auto channel = _peer->migrateTo()) { - Ui::showPeerHistory(channel, ShowAtUnreadMsgId); - Auth().api().requestParticipantsCountDelayed(channel); - return; - } + handlePeerMigration(); } if (update.flags & UpdateFlag::NotificationsEnabled) { updateNotifyControls(); @@ -1338,27 +1334,6 @@ void HistoryWidget::notify_userIsBotChanged(UserData *user) { } } -void HistoryWidget::notify_migrateUpdated(PeerData *peer) { - if (_peer) { - if (_peer == peer) { - if (peer->migrateTo()) { - showHistory(peer->migrateTo()->id, (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId, true); - } else if ((_migrated ? _migrated->peer.get() : nullptr) != peer->migrateFrom()) { - auto migrated = _history->migrateFrom(); - if (_migrated || (migrated && migrated->unreadCount() > 0)) { - showHistory(peer->id, peer->migrateFrom() ? _showAtMsgId : ((_showAtMsgId < 0 && -_showAtMsgId < ServerMaxMsgId) ? ShowAtUnreadMsgId : _showAtMsgId), true); - } else { - _migrated = migrated; - _list->notifyMigrateUpdated(); - updateHistoryGeometry(); - } - } - } else if (_migrated && _migrated->peer == peer && peer->migrateTo() != _peer) { - showHistory(_peer->id, _showAtMsgId, true); - } - } -} - void HistoryWidget::setupShortcuts() { Shortcuts::Requests( ) | rpl::filter([=] { @@ -1516,7 +1491,10 @@ void HistoryWidget::applyCloudDraft(History *history) { } } -void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool reload) { +void HistoryWidget::showHistory( + const PeerId &peerId, + MsgId showAtMsgId, + bool reload) { MsgId wasMsgId = _showAtMsgId; History *wasHistory = _history; @@ -1671,6 +1649,11 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re _history = App::history(_peer); _migrated = _history->migrateFrom(); + if (_migrated + && !_migrated->isEmpty() + && (!_history->loadedAtTop() || !_migrated->loadedAtBottom())) { + _migrated->unloadBlocks(); + } _topBar->setActiveChat(_history); updateTopBarSelection(); @@ -5173,6 +5156,35 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) { } } +void HistoryWidget::handlePeerMigration() { + const auto current = _peer->migrateToOrMe(); + const auto chat = current->migrateFrom(); + if (!chat) { + return; + } + const auto channel = current->asChannel(); + Assert(channel != nullptr); + + if (_peer != channel) { + showHistory( + channel->id, + (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId); + channel->session().api().requestParticipantsCountDelayed(channel); + } else { + _migrated = _history->migrateFrom(); + _list->notifyMigrateUpdated(); + updateHistoryGeometry(); + } + const auto from = chat->owner().historyLoaded(chat); + const auto to = channel->owner().historyLoaded(channel); + if (from + && to + && !from->isEmpty() + && (!from->loadedAtBottom() || !to->loadedAtTop())) { + from->unloadBlocks(); + } +} + void HistoryWidget::replyToPreviousMessage() { if (!_history || _editMsgId) { return; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index a2b9f2dc0..d4b46a571 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -288,7 +288,6 @@ public: void notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); void notify_userIsBotChanged(UserData *user); - void notify_migrateUpdated(PeerData *peer); ~HistoryWidget(); @@ -503,6 +502,8 @@ private: bool showNextChat(); bool showPreviousChat(); + void handlePeerMigration(); + MsgId _replyToId = 0; Text _replyToName; int _replyToNameVersion = 0; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 766f85be9..5718966f0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -621,10 +621,6 @@ void MainWidget::notify_userIsBotChanged(UserData *bot) { _history->notify_userIsBotChanged(bot); } -void MainWidget::notify_migrateUpdated(PeerData *peer) { - _history->notify_migrateUpdated(peer); -} - void MainWidget::notify_historyMuteUpdated(History *history) { _dialogs->notify_historyMuteUpdated(history); } @@ -874,7 +870,7 @@ void MainWidget::deleteConversation( removeDialog(history); if (const auto channel = peer->asMegagroup()) { channel->addFlags(MTPDchannel::Flag::f_left); - if (const auto from = channel->mgInfo->migrateFromPtr) { + if (const auto from = channel->getMigrateFromChat()) { if (const auto migrated = App::historyLoaded(from)) { migrated->updateChatListExistence(); } @@ -2832,15 +2828,17 @@ void MainWidget::searchInChat(Dialogs::Key chat) { void MainWidget::feedUpdateVector( const MTPVector &updates, bool skipMessageIds) { - for_const (auto &update, updates.v) { - if (skipMessageIds && update.type() == mtpc_updateMessageID) continue; + for (const auto &update : updates.v) { + if (skipMessageIds && update.type() == mtpc_updateMessageID) { + continue; + } feedUpdate(update); } Auth().data().sendHistoryChangeNotifications(); } void MainWidget::feedMessageIds(const MTPVector &updates) { - for_const (auto &update, updates.v) { + for (const auto &update : updates.v) { if (update.type() == mtpc_updateMessageID) { feedUpdate(update); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 4948ff00c..d2eab3b9c 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -290,7 +290,6 @@ public: void notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop); bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); void notify_userIsBotChanged(UserData *bot); - void notify_migrateUpdated(PeerData *peer); void notify_historyMuteUpdated(History *history); ~MainWidget();