mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Handle migration to supergroups in boxes.
This commit is contained in:
parent
3c44bdb6b7
commit
9728ddeaf9
29 changed files with 426 additions and 231 deletions
|
@ -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.";
|
||||
|
|
|
@ -886,6 +886,7 @@ void ApiWrap::requestFullPeer(not_null<PeerData*> 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<PeerData*> 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<PeerData*> peer,
|
||||
not_null<ChannelData*> channel) {
|
||||
Notify::peerUpdatedSendDelayed();
|
||||
if (auto handlers = _migrateCallbacks.take(peer)) {
|
||||
for (auto &handler : *handlers) {
|
||||
if (handler.done) {
|
||||
handler.done(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::migrateFail(not_null<PeerData*> peer, const RPCError &error) {
|
||||
const auto &type = error.type();
|
||||
if (type == qstr("CHANNELS_TOO_MUCH")) {
|
||||
Ui::show(Box<InformBox>(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<void(const MTPUser &)> callback) {
|
|||
}
|
||||
|
||||
void ApiWrap::uploadPeerPhoto(not_null<PeerData*> peer, QImage &&image) {
|
||||
peer = peer->migrateToOrMe();
|
||||
const auto ready = PreparePeerPhoto(peer->id, std::move(image));
|
||||
|
||||
const auto fakeId = FullMsgId(peerToChannel(peer->id), clientMsgId());
|
||||
|
|
|
@ -587,6 +587,11 @@ private:
|
|||
|
||||
void setSelfDestructDays(int days);
|
||||
|
||||
void migrateDone(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<ChannelData*> channel);
|
||||
void migrateFail(not_null<PeerData*> peer, const RPCError &error);
|
||||
|
||||
not_null<AuthSession*> _session;
|
||||
|
||||
MessageDataRequests _messageDataRequests;
|
||||
|
@ -737,7 +742,7 @@ private:
|
|||
FnMut<void(const RPCError&)> fail;
|
||||
};
|
||||
base::flat_map<
|
||||
not_null<ChatData*>,
|
||||
not_null<PeerData*>,
|
||||
std::vector<MigrateCallbacks>> _migrateCallbacks;
|
||||
|
||||
std::vector<FnMut<void(const MTPUser &)>> _supportContactCallbacks;
|
||||
|
|
|
@ -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<BoxContent> _value;
|
||||
|
||||
};
|
||||
|
|
|
@ -86,11 +86,8 @@ void AddParticipantsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
|||
}
|
||||
} else if (count >= Global::ChatSizeMax()
|
||||
&& count < Global::MegagroupSizeMax()) {
|
||||
// #TODO groups new error about "after creating"
|
||||
Ui::show(
|
||||
Box<InformBox>(lng_profile_add_more_after_upgrade(
|
||||
lt_count,
|
||||
Global::MegagroupSizeMax())),
|
||||
Box<InformBox>(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<UserData*> 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<UserData*> 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
|
||||
|
|
|
@ -115,7 +115,7 @@ private:
|
|||
bool _allLoaded = false;
|
||||
ParticipantsAdditionalData _additional;
|
||||
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
|
||||
QPointer<BoxContent> _editBox;
|
||||
BoxPointer _editBox;
|
||||
AdminDoneCallback _adminDoneCallback;
|
||||
BannedDoneCallback _bannedDoneCallback;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -802,6 +802,7 @@ void ParticipantsBoxController::addNewItem() {
|
|||
const auto initBox = [](not_null<PeerListBox*> box) {
|
||||
box->addButton(langFactory(lng_cancel), [=] { box->closeBox(); });
|
||||
};
|
||||
|
||||
_addBox = Ui::show(
|
||||
Box<PeerListBox>(
|
||||
std::make_unique<AddSpecialBoxController>(
|
||||
|
@ -1352,9 +1353,7 @@ void ParticipantsBoxController::showAdmin(not_null<UserData*> 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<UserData*> user) {
|
|||
void ParticipantsBoxController::editAdminDone(
|
||||
not_null<UserData*> 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<UserData*> 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<UserData*> user) {
|
|||
void ParticipantsBoxController::editRestrictedDone(
|
||||
not_null<UserData*> 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<UserData*> user) {
|
|||
}
|
||||
|
||||
void ParticipantsBoxController::kickMemberSure(not_null<UserData*> 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<UserData*> user) {
|
|||
}
|
||||
|
||||
void ParticipantsBoxController::removeAdminSure(not_null<UserData*> 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)));
|
||||
|
|
|
@ -234,8 +234,8 @@ private:
|
|||
bool _allLoaded = false;
|
||||
ParticipantsAdditionalData _additional;
|
||||
std::unique_ptr<ParticipantsOnlineSorter> _onlineSorter;
|
||||
QPointer<BoxContent> _editBox;
|
||||
QPointer<PeerListBox> _addBox;
|
||||
BoxPointer _editBox;
|
||||
BoxPointer _addBox;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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<Ui::RpWidget> 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<ChannelData*> channel);
|
||||
|
||||
not_null<BoxContent*> _box;
|
||||
not_null<PeerData*> _peer;
|
||||
bool _isGroup = false;
|
||||
|
@ -171,6 +176,8 @@ private:
|
|||
std::deque<FnMut<void()>> _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<ChannelData*> channel) { migrate(channel); });
|
||||
}
|
||||
|
||||
void Controller::migrate(not_null<ChannelData*> channel) {
|
||||
_peer = channel;
|
||||
observeInviteLink();
|
||||
_peer->updateFull();
|
||||
}
|
||||
|
||||
Fn<QString()> Controller::computeTitle() const {
|
||||
|
@ -222,10 +244,10 @@ void Controller::setFocus() {
|
|||
object_ptr<Ui::RpWidget> 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<QPointer<ConfirmBox>>();
|
||||
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<ConfirmBox>(
|
||||
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<Ui::RpWidget> Controller::createInviteLinkEdit() {
|
||||
Expects(_wrap != nullptr);
|
||||
|
||||
|
@ -721,14 +754,9 @@ object_ptr<Ui::RpWidget> 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<Ui::RpWidget> 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<Ui::RpWidget> 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<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
: _peer(peer->migrateToOrMe()) {
|
||||
}
|
||||
|
||||
void EditPeerInfoBox::prepare() {
|
||||
|
|
|
@ -215,10 +215,40 @@ ChatRestrictions DisabledByAdminRights(not_null<PeerData*> peer) {
|
|||
|
||||
} // namespace
|
||||
|
||||
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> 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<PeerData*> peer)
|
||||
: _peer(peer) {
|
||||
: _peer(peer->migrateToOrMe()) {
|
||||
}
|
||||
|
||||
auto EditPeerPermissionsBox::saveEvents() const
|
||||
|
@ -282,12 +312,18 @@ void EditPeerPermissionsBox::prepare() {
|
|||
|
||||
void EditPeerPermissionsBox::addBannedButtons(
|
||||
not_null<Ui::VerticalLayout*> container) {
|
||||
if (const auto chat = _peer->asChat()) {
|
||||
if (!chat->amCreator()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto channel = _peer->asChannel();
|
||||
|
||||
container->add(
|
||||
object_ptr<BoxContentDivider>(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),
|
||||
|
|
|
@ -55,3 +55,5 @@ EditFlagsControl<MTPDchatAdminRights::Flags> CreateEditAdminRights(
|
|||
MTPDchatAdminRights::Flags disabled,
|
||||
bool isGroup,
|
||||
bool anyoneCanAddMembers);
|
||||
|
||||
ChatAdminRights DisabledByDefaultRestrictions(not_null<PeerData*> peer);
|
||||
|
|
|
@ -107,8 +107,8 @@ void ShowEditPermissions(not_null<PeerData*> peer) {
|
|||
box->closeBox();
|
||||
}
|
||||
});
|
||||
Auth().api().saveDefaultRestrictions(
|
||||
peer,
|
||||
peer->session().api().saveDefaultRestrictions(
|
||||
peer->migrateToOrMe(),
|
||||
MTP_chatBannedRights(MTP_flags(restrictions), MTP_int(0)),
|
||||
callback);
|
||||
}, box->lifetime());
|
||||
|
|
|
@ -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<Data::Session*> 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<MegagroupInfo>();
|
||||
|
@ -37,6 +46,17 @@ ChannelData::ChannelData(not_null<Data::Session*> 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<ChatData*> chat,
|
||||
not_null<ChannelData*> channel) {
|
||||
Expects(channel->isMegagroup());
|
||||
|
||||
chat->setMigrateToChannel(channel);
|
||||
channel->setMigrateFromChat(chat);
|
||||
}
|
||||
|
||||
void ApplyChannelUpdate(
|
||||
not_null<ChannelData*> channel,
|
||||
const MTPDupdateChatDefaultBannedRights &update) {
|
||||
|
|
|
@ -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<not_null<UserData*>> lastParticipants;
|
||||
base::flat_map<not_null<UserData*>, Admin> lastAdmins;
|
||||
base::flat_map<not_null<UserData*>, 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<ChatData*> chat,
|
||||
not_null<ChannelData*> channel);
|
||||
|
||||
void ApplyChannelUpdate(
|
||||
not_null<ChannelData*> channel,
|
||||
const MTPDupdateChatDefaultBannedRights &update);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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*> PeerData::migrateToOrMe() {
|
||||
if (const auto channel = migrateTo()) {
|
||||
return channel;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
not_null<const PeerData*> 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();
|
||||
|
|
|
@ -117,6 +117,8 @@ public:
|
|||
|
||||
[[nodiscard]] ChatData *migrateFrom() const;
|
||||
[[nodiscard]] ChannelData *migrateTo() const;
|
||||
[[nodiscard]] not_null<PeerData*> migrateToOrMe();
|
||||
[[nodiscard]] not_null<const PeerData*> migrateToOrMe() const;
|
||||
[[nodiscard]] Data::Feed *feed() const;
|
||||
|
||||
void updateFull();
|
||||
|
|
|
@ -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<PeerData*> 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 &) {
|
||||
});
|
||||
|
||||
|
|
|
@ -139,8 +139,9 @@ DialogsInner::DialogsInner(QWidget *parent, not_null<Window::Controller*> 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<Window::Controller*> 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<Window::Controller*> contro
|
|||
setupShortcuts();
|
||||
}
|
||||
|
||||
void DialogsInner::handleChatMigration(not_null<ChatData*> 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;
|
||||
}
|
||||
|
|
|
@ -289,6 +289,7 @@ private:
|
|||
int countPinnedIndex(Dialogs::Row *ofRow);
|
||||
void savePinnedOrder();
|
||||
void step_pinnedShifting(TimeMs ms, bool timer);
|
||||
void handleChatMigration(not_null<ChatData*> chat);
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<DBIWorkMode>, WorkMode);
|
|||
|
||||
DeclareRefVar(base::Observable<void>, UnreadCounterUpdate);
|
||||
DeclareRefVar(base::Observable<void>, PeerChooseCancel);
|
||||
|
||||
|
||||
DeclareVar(QString, CallOutputDeviceID);
|
||||
DeclareVar(QString, CallInputDeviceID);
|
||||
DeclareVar(int, CallOutputVolume);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<MTPUpdate> &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<MTPUpdate> &updates) {
|
||||
for_const (auto &update, updates.v) {
|
||||
for (const auto &update : updates.v) {
|
||||
if (update.type() == mtpc_updateMessageID) {
|
||||
feedUpdate(update);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue