From ff1b046c17c1abda5ec119d4aba9d6ad01908b01 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 6 Nov 2015 12:48:49 -0500 Subject: [PATCH] group > megagroup convert added --- Telegram/Resources/lang.strings | 12 ++ Telegram/Resources/style.txt | 3 + Telegram/SourceFiles/app.cpp | 6 + Telegram/SourceFiles/boxes/addcontactbox.cpp | 2 +- Telegram/SourceFiles/boxes/contactsbox.cpp | 6 +- Telegram/SourceFiles/history.cpp | 50 ++++- Telegram/SourceFiles/historywidget.cpp | 2 +- Telegram/SourceFiles/localstorage.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 4 +- Telegram/SourceFiles/mtproto/mtpScheme.cpp | 9 + Telegram/SourceFiles/mtproto/mtpScheme.h | 49 +++-- Telegram/SourceFiles/mtproto/scheme.tl | 5 +- Telegram/SourceFiles/profilewidget.cpp | 192 ++++++++++++++----- Telegram/SourceFiles/profilewidget.h | 11 ++ Telegram/SourceFiles/structs.cpp | 12 +- Telegram/SourceFiles/structs.h | 23 ++- 16 files changed, 310 insertions(+), 78 deletions(-) diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index c5cf3d2ad..d59f34801 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -501,6 +501,18 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_created_chat" = "{from} created group «{title}»"; "lng_action_created_channel" = "Channel «{title}» created"; +"lng_action_group_deactivate" = "The group was deactivated"; +"lng_action_group_activate" = "The group was activated"; +"lng_action_group_migrate" = "The group was converted to a supergroup"; + +"lng_profile_migrate_reached" = "{count:_not_used_|# member|# members} limit reached"; +"lng_profile_migrate_about" = "If you'd like to go over this limit, you can convert your group to a supergroup. In supergroups:"; +"lng_profile_migrate_feature1" = "— The members limit is {count:_not_used_|# user|# users}"; +"lng_profile_migrate_feature2" = "— New members see the entire chat history"; +"lng_profile_migrate_feature3" = "— Admins delete messages for everyone"; +"lng_profile_migrate_feature4" = "— Notifications are muted by default"; +"lng_profile_migrate_button" = "Upgrade to supergroup"; +"lng_profile_migrate_sure" = "Are you sure you want to convert this group to supergroup? This action cannot be undone."; "lng_channel_comments_count" = "{count:_not_used_|# comment|# comments}"; "lng_channel_hide_comments" = "Hide comments"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index cd51bf632..30ff2fc18 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1541,6 +1541,9 @@ btnShareContact: flatButton(btnDefNext, btnDefBig) { font: font(17px); overFont: font(17px); } +btnMigrateToMega: flatButton(btnShareContact) { + width: -40px; +} profileMinBtnPadding: 10px; membersPadding: margins(0px, 10px, 0px, 10px); diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 7f1d9a531..8c8a69d23 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -550,6 +550,9 @@ namespace App { cdata->flags = d.vflags.v; cdata->isForbidden = false; if (cdata->isMegagroup()) { + if (!cdata->mgInfo) { + cdata->mgInfo = new MegagroupInfo(); + } if (History *h = App::historyLoaded(cdata->id)) { if (h->asChannelHistory()->onlyImportant()) { MsgId fixInScrollMsgId = 0; @@ -557,6 +560,9 @@ namespace App { h->asChannelHistory()->getSwitchReadyFor(SwitchAtTopMsgId, fixInScrollMsgId, fixInScrollMsgTop); } } + } else if (cdata->mgInfo) { + delete cdata->mgInfo; + cdata->mgInfo = 0; } if (cdata->version < d.vversion.v) { cdata->version = d.vversion.v; diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 539b123ac..1337087df 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -500,7 +500,7 @@ void GroupInfoBox::onNext() { if (_creating == CreatingGroupGroup) { App::wnd()->replaceLayer(new ContactsBox(title, _photoBig)); } else { - bool mega = true; + bool mega = false; int32 flags = mega ? MTPchannels_CreateChannel::flag_megagroup : MTPchannels_CreateChannel::flag_broadcast; _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(flags), MTP_string(title), MTP_string(description)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); } diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index 679cddf3a..9819e58c3 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -150,7 +150,7 @@ ContactsInner::ContactsInner(UserData *bot) : TWidget() , _saving(false) { DialogsIndexed &v(App::main()->dialogsList()); for (DialogRow *r = v.list.begin; r != v.list.end; r = r->next) { - if (r->history->peer->isChat() && r->history->peer->asChat()->amIn()) { + if (r->history->peer->isChat() && r->history->peer->asChat()->canEdit()) { _contacts->addToEnd(r->history); } } @@ -285,7 +285,7 @@ void ContactsInner::peerUpdated(PeerData *peer) { initList(); inited = true; } - if (!_chat->amIn()) { + if (!_chat->canEdit()) { App::wnd()->hideLayer(); } else if (!_chat->participants.isEmpty()) { for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) { @@ -759,7 +759,7 @@ void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) { data->check = false; _checkedContacts.remove(peer); --_selCount; - } else if (selectedCount() < (_chat->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount())) { + } else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) { data->check = true; _checkedContacts.insert(peer, true); ++_selCount; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 98899b1ff..997dbb9ad 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1517,6 +1517,26 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo ChatData *chat = peer->asChat(); if (chat) chat->updateName(qs(d.vtitle), QString(), QString()); } break; + + case mtpc_messageActionChatDeactivate: { + peer->asChat()->flags |= MTPDchat::flag_deactivated; + } break; + + case mtpc_messageActionChatActivate: { + peer->asChat()->flags &= ~MTPDchat::flag_deactivated; + } break; + + case mtpc_messageActionChatMigrateTo: { + peer->asChat()->flags |= MTPDchat::flag_deactivated; + + //const MTPDmessageActionChatMigrateTo &d(action.c_messageActionChatMigrateTo()); + //PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id)); + } break; + + case mtpc_messageActionChannelMigrateFrom: { + //const MTPDmessageActionChannelMigrateFrom &d(action.c_messageActionChannelMigrateFrom()); + //PeerData *chat = App::peerLoaded(peerFromChat(d.vchat_id)); + } break; } } } break; @@ -1713,7 +1733,7 @@ HistoryItem *History::addNewItem(HistoryBlock *to, bool newBlock, HistoryItem *a if (lastKeyboardFrom == adding->from()->id || (!lastKeyboardInited && !peer->isChat() && !adding->out())) { clearLastKeyboard(); } - } else if (peer->isChat() && adding->from()->isUser() && (!peer->asChat()->amIn() || !peer->asChat()->participants.isEmpty()) && !peer->asChat()->participants.contains(adding->from()->asUser())) { + } else if (peer->isChat() && adding->from()->isUser() && (!peer->asChat()->canWrite() || !peer->asChat()->participants.isEmpty()) && !peer->asChat()->participants.contains(adding->from()->asUser())) { clearLastKeyboard(); } else { lastKeyboardInited = true; @@ -1921,7 +1941,7 @@ void History::addOlderSlice(const QVector &slice, const QVectorasChat()->amIn() || !peer->asChat()->participants.isEmpty()) && item->from()->isUser() && !peer->asChat()->participants.contains(item->from()->asUser()))) { + if (wasKeyboardHide || ((!peer->asChat()->canWrite() || !peer->asChat()->participants.isEmpty()) && item->from()->isUser() && !peer->asChat()->participants.contains(item->from()->asUser()))) { clearLastKeyboard(); } else { lastKeyboardInited = true; @@ -7409,6 +7429,32 @@ void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) { text = fromChannel() ? lng_action_changed_title_channel(lt_title, textClean(qs(d.vtitle))) : lng_action_changed_title(lt_from, from, lt_title, textClean(qs(d.vtitle))); } break; + case mtpc_messageActionChatDeactivate: { + text = lang(lng_action_group_deactivate); + } break; + + case mtpc_messageActionChatActivate: { + text = lang(lng_action_group_activate); + } break; + + case mtpc_messageActionChatMigrateTo: { + const MTPDmessageActionChatMigrateTo &d(action.c_messageActionChatMigrateTo()); + if (true/*PeerData *channel = App::peerLoaded(peerFromChannel(d.vchannel_id))*/) { + text = lang(lng_action_group_migrate); + } else { + text = lang(lng_contacts_loading); + } + } break; + + case mtpc_messageActionChannelMigrateFrom: { + const MTPDmessageActionChannelMigrateFrom &d(action.c_messageActionChannelMigrateFrom()); + if (true/*PeerData *chat = App::peerLoaded(peerFromChannel(d.vchat_id))*/) { + text = lang(lng_action_group_migrate); + } else { + text = lang(lng_contacts_loading); + } + } break; + default: from = QString(); break; } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 4d70baf85..128f5e454 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -4448,7 +4448,7 @@ bool HistoryWidget::canSendMessages(PeerData *peer) const { if (peer->isUser()) { return peer->asUser()->access != UserNoAccess; } else if (peer->isChat()) { - return peer->asChat()->amIn(); + return peer->asChat()->canWrite(); } else if (peer->isChannel()) { return peer->asChannel()->amIn() && (peer->asChannel()->canPublish() || !peer->asChannel()->isBroadcast()); } diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index c4864dd6e..7a49d043b 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -3080,7 +3080,7 @@ namespace Local { channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); - channel->photo = photoLoc.isNull() ? ImagePtr(channelDefPhoto(channel->colorIndex)) : ImagePtr(photoLoc); + channel->photo = photoLoc.isNull() ? ImagePtr((channel->isMegagroup() ? chatDefPhoto(channel->colorIndex) : channelDefPhoto(channel->colorIndex))) : ImagePtr(photoLoc); } App::markPeerUpdated(result); emit App::main()->peerPhotoChanged(result); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d2ad14b3a..9491d81f0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -477,7 +477,7 @@ MainWidget::MainWidget(Window *window) : TWidget(window) bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) { PeerData *p = App::peer(peer); - if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->amIn()) || (p->isUser() && p->asUser()->access == UserNoAccess)) { + if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->canWrite()) || (p->isUser() && p->asUser()->access == UserNoAccess)) { App::wnd()->showLayer(new InformBox(lang(lng_forward_cant))); return false; } @@ -511,7 +511,7 @@ bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) { bool MainWidget::onShareUrl(const PeerId &peer, const QString &url, const QString &text) { PeerData *p = App::peer(peer); - if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->amIn()) || (p->isUser() && p->asUser()->access == UserNoAccess)) { + if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->canWrite()) || (p->isUser() && p->asUser()->access == UserNoAccess)) { App::wnd()->showLayer(new InformBox(lang(lng_share_cant))); return false; } diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp index 729537438..686e334b2 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp +++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp @@ -1224,6 +1224,7 @@ void _serialize_chat(MTPStringLogger &to, int32 stage, int32 lev, Types &types, case 10: to.add(" participants_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 11: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 12: to.add(" version: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 13: to.add(" migrated_to: "); ++stages.back(); if (flag & MTPDchat::flag_migrated_to) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -1324,6 +1325,9 @@ void _serialize_channelFull(MTPStringLogger &to, int32 stage, int32 lev, Types & case 10: to.add(" chat_photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 11: to.add(" notify_settings: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; case 12: to.add(" exported_invite: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 13: to.add(" bot_info: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 14: to.add(" migrated_from_chat_id: "); ++stages.back(); if (flag & MTPDchannelFull::flag_migrated_from_chat_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; + case 15: to.add(" migrated_from_max_id: "); ++stages.back(); if (flag & MTPDchannelFull::flag_migrated_from_max_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } } @@ -4928,6 +4932,10 @@ void _serialize_channelParticipantsKicked(MTPStringLogger &to, int32 stage, int3 to.add("{ channelParticipantsKicked }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } +void _serialize_channelParticipantsBots(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) { + to.add("{ channelParticipantsBots }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); +} + void _serialize_channelRoleEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) { to.add("{ channelRoleEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); } @@ -7526,6 +7534,7 @@ namespace { _serializers.insert(mtpc_channelParticipantsRecent, _serialize_channelParticipantsRecent); _serializers.insert(mtpc_channelParticipantsAdmins, _serialize_channelParticipantsAdmins); _serializers.insert(mtpc_channelParticipantsKicked, _serialize_channelParticipantsKicked); + _serializers.insert(mtpc_channelParticipantsBots, _serialize_channelParticipantsBots); _serializers.insert(mtpc_channelRoleEmpty, _serialize_channelRoleEmpty); _serializers.insert(mtpc_channelRoleModerator, _serialize_channelRoleModerator); _serializers.insert(mtpc_channelRoleEditor, _serialize_channelRoleEditor); diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h index efe13d788..aa8878517 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.h +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -139,12 +139,12 @@ enum { mtpc_userStatusLastWeek = 0x7bf09fc, mtpc_userStatusLastMonth = 0x77ebc742, mtpc_chatEmpty = 0x9ba2d800, - mtpc_chat = 0x7312bc48, + mtpc_chat = 0xd91cdd54, mtpc_chatForbidden = 0x7328bdb, mtpc_channel = 0x678e9587, mtpc_channelForbidden = 0x2d85832c, mtpc_chatFull = 0x2e02a614, - mtpc_channelFull = 0xfab31aa3, + mtpc_channelFull = 0x9e341ddf, mtpc_chatParticipant = 0xc8d7493e, mtpc_chatParticipantCreator = 0xda13538a, mtpc_chatParticipantAdmin = 0xe2d6e436, @@ -432,6 +432,7 @@ enum { mtpc_channelParticipantsRecent = 0xde3f3c79, mtpc_channelParticipantsAdmins = 0xb4608969, mtpc_channelParticipantsKicked = 0x3c37bb7a, + mtpc_channelParticipantsBots = 0xb0d1865b, mtpc_channelRoleEmpty = 0xb285a0c6, mtpc_channelRoleModerator = 0x9618d975, mtpc_channelRoleEditor = 0x820bfe8c, @@ -3327,7 +3328,7 @@ private: explicit MTPchat(MTPDchannelForbidden *_data); friend MTPchat MTP_chatEmpty(MTPint _id); - friend MTPchat MTP_chat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version); + friend MTPchat MTP_chat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version, const MTPInputChannel &_migrated_to); friend MTPchat MTP_chatForbidden(MTPint _id, const MTPstring &_title); friend MTPchat MTP_channel(MTPint _flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_username, const MTPChatPhoto &_photo, MTPint _date, MTPint _version); friend MTPchat MTP_channelForbidden(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title); @@ -3381,7 +3382,7 @@ private: explicit MTPchatFull(MTPDchannelFull *_data); friend MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info); - friend MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite); + friend MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info, MTPint _migrated_from_chat_id, MTPint _migrated_from_max_id); mtpTypeId _type; }; @@ -8695,6 +8696,7 @@ private: friend MTPchannelParticipantsFilter MTP_channelParticipantsRecent(); friend MTPchannelParticipantsFilter MTP_channelParticipantsAdmins(); friend MTPchannelParticipantsFilter MTP_channelParticipantsKicked(); + friend MTPchannelParticipantsFilter MTP_channelParticipantsBots(); mtpTypeId _type; }; @@ -9661,7 +9663,7 @@ class MTPDchat : public mtpDataImpl { public: MTPDchat() { } - MTPDchat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version) : vflags(_flags), vid(_id), vtitle(_title), vphoto(_photo), vparticipants_count(_participants_count), vdate(_date), vversion(_version) { + MTPDchat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version, const MTPInputChannel &_migrated_to) : vflags(_flags), vid(_id), vtitle(_title), vphoto(_photo), vparticipants_count(_participants_count), vdate(_date), vversion(_version), vmigrated_to(_migrated_to) { } MTPint vflags; @@ -9671,6 +9673,7 @@ public: MTPint vparticipants_count; MTPint vdate; MTPint vversion; + MTPInputChannel vmigrated_to; enum { flag_creator = (1 << 0), @@ -9679,6 +9682,7 @@ public: flag_admins_enabled = (1 << 3), flag_admin = (1 << 4), flag_deactivated = (1 << 5), + flag_migrated_to = (1 << 6), }; bool is_creator() const { return vflags.v & flag_creator; } @@ -9687,6 +9691,7 @@ public: bool is_admins_enabled() const { return vflags.v & flag_admins_enabled; } bool is_admin() const { return vflags.v & flag_admin; } bool is_deactivated() const { return vflags.v & flag_deactivated; } + bool has_migrated_to() const { return vflags.v & flag_migrated_to; } }; class MTPDchatForbidden : public mtpDataImpl { @@ -9770,7 +9775,7 @@ class MTPDchannelFull : public mtpDataImpl { public: MTPDchannelFull() { } - MTPDchannelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) : vflags(_flags), vid(_id), vabout(_about), vparticipants_count(_participants_count), vadmins_count(_admins_count), vkicked_count(_kicked_count), vread_inbox_max_id(_read_inbox_max_id), vunread_count(_unread_count), vunread_important_count(_unread_important_count), vchat_photo(_chat_photo), vnotify_settings(_notify_settings), vexported_invite(_exported_invite) { + MTPDchannelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info, MTPint _migrated_from_chat_id, MTPint _migrated_from_max_id) : vflags(_flags), vid(_id), vabout(_about), vparticipants_count(_participants_count), vadmins_count(_admins_count), vkicked_count(_kicked_count), vread_inbox_max_id(_read_inbox_max_id), vunread_count(_unread_count), vunread_important_count(_unread_important_count), vchat_photo(_chat_photo), vnotify_settings(_notify_settings), vexported_invite(_exported_invite), vbot_info(_bot_info), vmigrated_from_chat_id(_migrated_from_chat_id), vmigrated_from_max_id(_migrated_from_max_id) { } MTPint vflags; @@ -9785,18 +9790,25 @@ public: MTPPhoto vchat_photo; MTPPeerNotifySettings vnotify_settings; MTPExportedChatInvite vexported_invite; + MTPVector vbot_info; + MTPint vmigrated_from_chat_id; + MTPint vmigrated_from_max_id; enum { flag_can_view_participants = (1 << 3), flag_participants_count = (1 << 0), flag_admins_count = (1 << 1), flag_kicked_count = (1 << 2), + flag_migrated_from_chat_id = (1 << 4), + flag_migrated_from_max_id = (1 << 4), }; bool is_can_view_participants() const { return vflags.v & flag_can_view_participants; } bool has_participants_count() const { return vflags.v & flag_participants_count; } bool has_admins_count() const { return vflags.v & flag_admins_count; } bool has_kicked_count() const { return vflags.v & flag_kicked_count; } + bool has_migrated_from_chat_id() const { return vflags.v & flag_migrated_from_chat_id; } + bool has_migrated_from_max_id() const { return vflags.v & flag_migrated_from_max_id; } }; class MTPDchatParticipant : public mtpDataImpl { @@ -21784,7 +21796,7 @@ inline uint32 MTPchat::innerLength() const { } case mtpc_chat: { const MTPDchat &v(c_chat()); - return v.vflags.innerLength() + v.vid.innerLength() + v.vtitle.innerLength() + v.vphoto.innerLength() + v.vparticipants_count.innerLength() + v.vdate.innerLength() + v.vversion.innerLength(); + return v.vflags.innerLength() + v.vid.innerLength() + v.vtitle.innerLength() + v.vphoto.innerLength() + v.vparticipants_count.innerLength() + v.vdate.innerLength() + v.vversion.innerLength() + (v.has_migrated_to() ? v.vmigrated_to.innerLength() : 0); } case mtpc_chatForbidden: { const MTPDchatForbidden &v(c_chatForbidden()); @@ -21823,6 +21835,7 @@ inline void MTPchat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId v.vparticipants_count.read(from, end); v.vdate.read(from, end); v.vversion.read(from, end); + if (v.has_migrated_to()) { v.vmigrated_to.read(from, end); } else { v.vmigrated_to = MTPInputChannel(); } } break; case mtpc_chatForbidden: _type = cons; { if (!data) setData(new MTPDchatForbidden()); @@ -21867,6 +21880,7 @@ inline void MTPchat::write(mtpBuffer &to) const { v.vparticipants_count.write(to); v.vdate.write(to); v.vversion.write(to); + if (v.has_migrated_to()) v.vmigrated_to.write(to); } break; case mtpc_chatForbidden: { const MTPDchatForbidden &v(c_chatForbidden()); @@ -21915,8 +21929,8 @@ inline MTPchat::MTPchat(MTPDchannelForbidden *_data) : mtpDataOwner(_data), _typ inline MTPchat MTP_chatEmpty(MTPint _id) { return MTPchat(new MTPDchatEmpty(_id)); } -inline MTPchat MTP_chat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version) { - return MTPchat(new MTPDchat(_flags, _id, _title, _photo, _participants_count, _date, _version)); +inline MTPchat MTP_chat(MTPint _flags, MTPint _id, const MTPstring &_title, const MTPChatPhoto &_photo, MTPint _participants_count, MTPint _date, MTPint _version, const MTPInputChannel &_migrated_to) { + return MTPchat(new MTPDchat(_flags, _id, _title, _photo, _participants_count, _date, _version, _migrated_to)); } inline MTPchat MTP_chatForbidden(MTPint _id, const MTPstring &_title) { return MTPchat(new MTPDchatForbidden(_id, _title)); @@ -21936,7 +21950,7 @@ inline uint32 MTPchatFull::innerLength() const { } case mtpc_channelFull: { const MTPDchannelFull &v(c_channelFull()); - return v.vflags.innerLength() + v.vid.innerLength() + v.vabout.innerLength() + (v.has_participants_count() ? v.vparticipants_count.innerLength() : 0) + (v.has_admins_count() ? v.vadmins_count.innerLength() : 0) + (v.has_kicked_count() ? v.vkicked_count.innerLength() : 0) + v.vread_inbox_max_id.innerLength() + v.vunread_count.innerLength() + v.vunread_important_count.innerLength() + v.vchat_photo.innerLength() + v.vnotify_settings.innerLength() + v.vexported_invite.innerLength(); + return v.vflags.innerLength() + v.vid.innerLength() + v.vabout.innerLength() + (v.has_participants_count() ? v.vparticipants_count.innerLength() : 0) + (v.has_admins_count() ? v.vadmins_count.innerLength() : 0) + (v.has_kicked_count() ? v.vkicked_count.innerLength() : 0) + v.vread_inbox_max_id.innerLength() + v.vunread_count.innerLength() + v.vunread_important_count.innerLength() + v.vchat_photo.innerLength() + v.vnotify_settings.innerLength() + v.vexported_invite.innerLength() + v.vbot_info.innerLength() + (v.has_migrated_from_chat_id() ? v.vmigrated_from_chat_id.innerLength() : 0) + (v.has_migrated_from_max_id() ? v.vmigrated_from_max_id.innerLength() : 0); } } return 0; @@ -21973,6 +21987,9 @@ inline void MTPchatFull::read(const mtpPrime *&from, const mtpPrime *end, mtpTyp v.vchat_photo.read(from, end); v.vnotify_settings.read(from, end); v.vexported_invite.read(from, end); + v.vbot_info.read(from, end); + if (v.has_migrated_from_chat_id()) { v.vmigrated_from_chat_id.read(from, end); } else { v.vmigrated_from_chat_id = MTPint(); } + if (v.has_migrated_from_max_id()) { v.vmigrated_from_max_id.read(from, end); } else { v.vmigrated_from_max_id = MTPint(); } } break; default: throw mtpErrorUnexpected(cons, "MTPchatFull"); } @@ -22002,6 +22019,9 @@ inline void MTPchatFull::write(mtpBuffer &to) const { v.vchat_photo.write(to); v.vnotify_settings.write(to); v.vexported_invite.write(to); + v.vbot_info.write(to); + if (v.has_migrated_from_chat_id()) v.vmigrated_from_chat_id.write(to); + if (v.has_migrated_from_max_id()) v.vmigrated_from_max_id.write(to); } break; } } @@ -22019,8 +22039,8 @@ inline MTPchatFull::MTPchatFull(MTPDchannelFull *_data) : mtpDataOwner(_data), _ inline MTPchatFull MTP_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info) { return MTPchatFull(new MTPDchatFull(_id, _participants, _chat_photo, _notify_settings, _exported_invite, _bot_info)); } -inline MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite) { - return MTPchatFull(new MTPDchannelFull(_flags, _id, _about, _participants_count, _admins_count, _kicked_count, _read_inbox_max_id, _unread_count, _unread_important_count, _chat_photo, _notify_settings, _exported_invite)); +inline MTPchatFull MTP_channelFull(MTPint _flags, MTPint _id, const MTPstring &_about, MTPint _participants_count, MTPint _admins_count, MTPint _kicked_count, MTPint _read_inbox_max_id, MTPint _unread_count, MTPint _unread_important_count, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector &_bot_info, MTPint _migrated_from_chat_id, MTPint _migrated_from_max_id) { + return MTPchatFull(new MTPDchannelFull(_flags, _id, _about, _participants_count, _admins_count, _kicked_count, _read_inbox_max_id, _unread_count, _unread_important_count, _chat_photo, _notify_settings, _exported_invite, _bot_info, _migrated_from_chat_id, _migrated_from_max_id)); } inline uint32 MTPchatParticipant::innerLength() const { @@ -29233,6 +29253,7 @@ inline void MTPchannelParticipantsFilter::read(const mtpPrime *&from, const mtpP case mtpc_channelParticipantsRecent: _type = cons; break; case mtpc_channelParticipantsAdmins: _type = cons; break; case mtpc_channelParticipantsKicked: _type = cons; break; + case mtpc_channelParticipantsBots: _type = cons; break; default: throw mtpErrorUnexpected(cons, "MTPchannelParticipantsFilter"); } } @@ -29245,6 +29266,7 @@ inline MTPchannelParticipantsFilter::MTPchannelParticipantsFilter(mtpTypeId type case mtpc_channelParticipantsRecent: break; case mtpc_channelParticipantsAdmins: break; case mtpc_channelParticipantsKicked: break; + case mtpc_channelParticipantsBots: break; default: throw mtpErrorBadTypeId(type, "MTPchannelParticipantsFilter"); } } @@ -29257,6 +29279,9 @@ inline MTPchannelParticipantsFilter MTP_channelParticipantsAdmins() { inline MTPchannelParticipantsFilter MTP_channelParticipantsKicked() { return MTPchannelParticipantsFilter(mtpc_channelParticipantsKicked); } +inline MTPchannelParticipantsFilter MTP_channelParticipantsBots() { + return MTPchannelParticipantsFilter(mtpc_channelParticipantsBots); +} inline uint32 MTPchannelParticipantRole::innerLength() const { return 0; diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index 8ec043b95..6373795b9 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -216,13 +216,13 @@ userStatusLastWeek#7bf09fc = UserStatus; userStatusLastMonth#77ebc742 = UserStatus; chatEmpty#9ba2d800 id:int = Chat; -chat#7312bc48 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int = Chat; +chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat; chatForbidden#7328bdb id:int title:string = Chat; channel#678e9587 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true id:int access_hash:long title:string username:flags.6?string photo:ChatPhoto date:int version:int = Chat; channelForbidden#2d85832c id:int access_hash:long title:string = Chat; chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector = ChatFull; -channelFull#fab31aa3 flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull; +channelFull#9e341ddf flags:# can_view_participants:flags.3?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int unread_count:int unread_important_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -617,6 +617,7 @@ channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; channelParticipantsKicked#3c37bb7a = ChannelParticipantsFilter; +channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; channelRoleEmpty#b285a0c6 = ChannelParticipantRole; channelRoleModerator#9618d975 = ChannelParticipantRole; diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 3feef1fff..f8ea8e98e 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -31,58 +31,75 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "boxes/contactsbox.h" #include "gui/filedialog.h" -ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const PeerData *peer) : TWidget(0), - _profile(profile), _scroll(scroll), _peer(App::peer(peer->id)), - _peerUser(_peer->asUser()), _peerChat(_peer->asChat()), _peerChannel(_peer->asChannel()), _hist(App::history(peer->id)), - _amCreator(_peerChat ? _peerChat->amCreator() : (_peerChannel ? _peerChannel->amCreator() : false)), +ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const PeerData *peer) : TWidget(0) +, _profile(profile) +, _scroll(scroll) +, _peer(App::peer(peer->id)) +, _peerUser(_peer->asUser()) +, _peerChat(_peer->asChat()) +, _peerChannel(_peer->asChannel()) +, _hist(App::history(peer->id)) +, _amCreator(_peerChat ? _peerChat->amCreator() : (_peerChannel ? _peerChannel->amCreator() : false)) - _width(0), _left(0), _addToHeight(0), +, _width(0) +, _left(0) +, _addToHeight(0) - // profile - _nameCache(peer->name), - _uploadPhoto(this, lang(lng_profile_set_group_photo), st::btnShareContact), - _addParticipant(this, lang(lng_profile_add_participant), st::btnShareContact), - _sendMessage(this, lang(lng_profile_send_message), st::btnShareContact), - _shareContact(this, lang(lng_profile_share_contact), st::btnShareContact), - _inviteToGroup(this, lang(lng_profile_invite_to_group), st::btnShareContact), - _cancelPhoto(this, lang(lng_cancel)), - _createInvitationLink(this, lang(lng_group_invite_create)), - _invitationLink(this, qsl("telegram.me/joinchat/")), - _botSettings(this, lang(lng_profile_bot_settings)), - _botHelp(this, lang(lng_profile_bot_help)), - _username(this, (_peerChannel && _peerChannel->isPublic()) ? (qsl("telegram.me/") + _peerChannel->username) : lang(lng_profile_create_public_link)), - _members(this, lng_channel_members_link(lt_count, (_peerChannel && _peerChannel->count > 0) ? _peerChannel->count : 1)), - _admins(this, lng_channel_admins_link(lt_count, (_peerChannel ? (_peerChannel->adminsCount > 0 ? _peerChannel->adminsCount : 1) : ((_peerChat && _peerChat->adminsEnabled()) ? (_peerChat->admins.size() + 1) : 0)))), +// profile +, _nameCache(peer->name) +, _uploadPhoto(this, lang(lng_profile_set_group_photo), st::btnShareContact) +, _addParticipant(this, lang(lng_profile_add_participant), st::btnShareContact) +, _sendMessage(this, lang(lng_profile_send_message), st::btnShareContact) +, _shareContact(this, lang(lng_profile_share_contact), st::btnShareContact) +, _inviteToGroup(this, lang(lng_profile_invite_to_group), st::btnShareContact) +, _cancelPhoto(this, lang(lng_cancel)) +, _createInvitationLink(this, lang(lng_group_invite_create)) +, _invitationLink(this, qsl("telegram.me/joinchat/")) +, _botSettings(this, lang(lng_profile_bot_settings)) +, _botHelp(this, lang(lng_profile_bot_help)) +, _username(this, (_peerChannel && _peerChannel->isPublic()) ? (qsl("telegram.me/") + _peerChannel->username) : lang(lng_profile_create_public_link)) +, _members(this, lng_channel_members_link(lt_count, (_peerChannel && _peerChannel->count > 0) ? _peerChannel->count : 1)) +, _admins(this, lng_channel_admins_link(lt_count, (_peerChannel ? (_peerChannel->adminsCount > 0 ? _peerChannel->adminsCount : 1) : ((_peerChat && _peerChat->adminsEnabled()) ? (_peerChat->admins.size() + 1) : 0)))) - // about - _about(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right()), - _aboutTop(0), _aboutHeight(0), +// about +, _about(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right()) +, _aboutTop(0) +, _aboutHeight(0) - a_photo(0), - _photoOver(false), +, a_photo(0) +, _photoOver(false) - // settings - _enableNotifications(this, lang(lng_profile_enable_notifications)), +// migrate to megagroup +, _showMigrate(_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= 3) +, _aboutMigrate(st::normalFont, lang(lng_profile_migrate_about), _defaultOptions, st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right()) +, _migrate(this, lang(lng_profile_migrate_button), st::btnMigrateToMega) - // shared media - _notAllMediaLoaded(false), +// settings +, _enableNotifications(this, lang(lng_profile_enable_notifications)) - // actions - _searchInPeer(this, lang(lng_profile_search_messages)), - _clearHistory(this, lang(lng_profile_clear_history)), - _deleteConversation(this, lang(_peer->isUser() ? lng_profile_delete_conversation : (_peer->isChat() ? lng_profile_clear_and_exit : (_peer->isMegagroup() ? lng_profile_leave_group : lng_profile_leave_channel)))), - _wasBlocked(_peerUser ? _peerUser->blocked : UserBlockUnknown), - _blockRequest(0), - _blockUser(this, lang((_peerUser && _peerUser->botInfo) ? lng_profile_block_bot : lng_profile_block_user), st::btnRedLink), - _deleteChannel(this, lang(_peer->isMegagroup() ? lng_profile_delete_group : lng_profile_delete_channel), st::btnRedLink), +// shared media +, _notAllMediaLoaded(false) - // participants - _pHeight(st::profileListPhotoSize + st::profileListPadding.height() * 2), - _kickWidth(st::linkFont->width(lang(lng_profile_kick))), - _selectedRow(-1), _lastPreload(0), _contactId(0), - _kickOver(0), _kickDown(0), _kickConfirm(0), +// actions +, _searchInPeer(this, lang(lng_profile_search_messages)) +, _clearHistory(this, lang(lng_profile_clear_history)) +, _deleteConversation(this, lang(_peer->isUser() ? lng_profile_delete_conversation : (_peer->isChat() ? lng_profile_clear_and_exit : (_peer->isMegagroup() ? lng_profile_leave_group : lng_profile_leave_channel)))) +, _wasBlocked(_peerUser ? _peerUser->blocked : UserBlockUnknown) +, _blockRequest(0) +, _blockUser(this, lang((_peerUser && _peerUser->botInfo) ? lng_profile_block_bot : lng_profile_block_user), st::btnRedLink) +, _deleteChannel(this, lang(_peer->isMegagroup() ? lng_profile_delete_group : lng_profile_delete_channel), st::btnRedLink) + +// participants +, _pHeight(st::profileListPhotoSize + st::profileListPadding.height() * 2) +, _kickWidth(st::linkFont->width(lang(lng_profile_kick))) +, _selectedRow(-1) +, _lastPreload(0) +, _contactId(0) +, _kickOver(0) +, _kickDown(0) +, _kickConfirm(0) - _menu(0) { +, _menu(0) { connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update())); connect(App::api(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); @@ -176,6 +193,9 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee _botHelp.hide(); } + // migrate to megagroup + connect(&_migrate, SIGNAL(clicked()), this, SLOT(onMigrate())); + // settings connect(&_enableNotifications, SIGNAL(clicked()), this, SLOT(onEnableNotifications())); @@ -354,6 +374,20 @@ void ProfileInner::onAddParticipant() { App::wnd()->showLayer(new ContactsBox(_peerChat, MembersFilterRecent)); } +void ProfileInner::onMigrate() { + if (!_peerChat) return; + + ConfirmBox *box = new ConfirmBox(lang(lng_profile_migrate_sure)); + connect(box, SIGNAL(confirmed()), this, SLOT(onMigrateSure())); + App::wnd()->showLayer(box); +} + +void ProfileInner::onMigrateSure() { + if (!_peerChat) return; + + MTP::send(MTPmessages_MigrateChat(_peerChat->inputChat), rpcDone(&ProfileInner::migrateDone), rpcFail(&ProfileInner::migrateFail)); +} + void ProfileInner::onUpdatePhotoCancel() { App::app()->cancelPhotoUpdate(_peer->id); showAll(); @@ -485,6 +519,7 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) { } } else if (_peerChat) { updateInvitationLink(); + _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= 3); showAll(); resizeEvent(0); _admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0)); @@ -544,6 +579,7 @@ void ProfileInner::peerUpdated(PeerData *data) { } else if (_peerChat) { if (_peerChat->photoId && _peerChat->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChat->photoId); _admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0)); + _showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= 3); if (App::main()) App::main()->topBar()->showAll(); } else if (_peerChannel) { if (_peerChannel->photoId && _peerChannel->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChannel->photoId); @@ -754,6 +790,24 @@ void ProfileInner::paintEvent(QPaintEvent *e) { top += _aboutHeight; } + // migrate to megagroup + if (_showMigrate) { + p.setFont(st::profileHeaderFont->f); + p.setPen(st::profileHeaderColor->p); + p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lng_profile_migrate_reached(lt_count, cMaxGroupCount())); + top += st::profileHeaderSkip; + + _aboutMigrate.draw(p, _left, top, _width); top += _aboutMigrate.countHeight(_width) + st::setLittleSkip; + p.setFont(st::normalFont); + p.setPen(st::black); + p.drawText(_left, top + st::normalFont->ascent, lng_profile_migrate_feature1(lt_count, cMaxMegaGroupCount())); top += st::normalFont->height + st::setLittleSkip; + p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature2)); top += st::normalFont->height + st::setLittleSkip; + p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature3)); top += st::normalFont->height + st::setLittleSkip; + p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature4)); top += st::normalFont->height + st::setSectionSkip; + + top += _migrate.height(); + } + // settings p.setFont(st::profileHeaderFont->f); p.setPen(st::profileHeaderColor->p); @@ -761,7 +815,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) { top += st::profileHeaderSkip; // invite link stuff - if (_amCreator && (!_peerChannel || !_peerChannel->isPublic())) { + if (_amCreator && ((_peerChat && _peerChat->canEdit()) || (_peerChannel && !_peerChannel->isPublic()))) { if ((_peerChat && !_peerChat->invitationUrl.isEmpty()) || (_peerChannel && !_peerChannel->invitationUrl.isEmpty())) { p.setPen(st::black); p.setFont(st::linkFont); @@ -961,7 +1015,7 @@ void ProfileInner::mousePressEvent(QMouseEvent *e) { } else if (QRect(_left, st::profilePadding.top(), st::setPhotoSize, st::setPhotoSize).contains(e->pos())) { if (_photoLink) { _photoLink->onClick(e->button()); - } else if ((_peerChat && _peerChat->amIn()) || (_peerChannel && _amCreator)) { + } else if ((_peerChat && _peerChat->canEdit()) || (_peerChannel && _amCreator)) { onUpdatePhoto(); } } @@ -1108,7 +1162,36 @@ bool ProfileInner::updateMediaLinks(int32 *addToScroll) { } } return changed; +} +void ProfileInner::migrateDone(const MTPUpdates &updates) { + App::wnd()->hideLayer(); + App::main()->sentUpdatesReceived(updates); + const QVector *v = 0; + switch (updates.type()) { + case mtpc_updates: v = &updates.c_updates().vchats.c_vector().v; break; + case mtpc_updatesCombined: v = &updates.c_updatesCombined().vchats.c_vector().v; break; + default: LOG(("API Error: unexpected update cons %1 (ProfileInner::migrateDone)").arg(updates.type())); break; + } + + PeerData *peer = 0; + if (v && !v->isEmpty()) { + for (int32 i = 0, l = v->size(); i < l; ++i) { + if (v->at(i).type() == mtpc_channel) { + peer = App::channel(v->at(i).c_channel().vid.v); + App::main()->showPeerHistory(peer->id, ShowAtUnreadMsgId); + } + } + } + if (!peer) { + LOG(("API Error: channel not found in updates (ProfileInner::migrateDone)")); + } +} + +bool ProfileInner::migrateFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + App::wnd()->hideLayer(); + return true; } void ProfileInner::resizeEvent(QResizeEvent *e) { @@ -1157,12 +1240,20 @@ void ProfileInner::resizeEvent(QResizeEvent *e) { _aboutTop = _aboutHeight = 0; } + // migrate to megagroup + if (_showMigrate) { + top += st::profileHeaderSkip; + top += _aboutMigrate.countHeight(_width) + st::setLittleSkip; + top += st::normalFont->height * 4 + st::setLittleSkip * 3 + st::setSectionSkip; + _migrate.move(_left, top); top += _migrate.height(); + } + // settings top += st::profileHeaderSkip; // invite link stuff int32 _inviteLinkTextWidth(st::linkFont->width(lang(lng_group_invite_link)) + st::linkFont->spacew); - if (_amCreator && (!_peerChannel || !_peerChannel->isPublic())) { + if (_amCreator && ((_peerChat && _peerChat->canEdit()) || (_peerChannel && !_peerChannel->isPublic()))) { if (!_invitationText.isEmpty()) { _invitationLink.setText(st::linkFont->elided(_invitationText, _width - _inviteLinkTextWidth)); } @@ -1416,7 +1507,7 @@ void ProfileInner::showAll() { _createInvitationLink.hide(); _invitationLink.hide(); } - if (_peerChat->count < cMaxGroupCount()) { + if (_peerChat->count < cMaxGroupCount() && !_showMigrate) { _addParticipant.show(); } else { _addParticipant.hide(); @@ -1426,7 +1517,7 @@ void ProfileInner::showAll() { _deleteChannel.hide(); _username.hide(); _members.hide(); - if (_amCreator) { + if (_amCreator && _peerChat->canEdit()) { _admins.show(); } else { _admins.hide(); @@ -1487,6 +1578,11 @@ void ProfileInner::showAll() { _members.hide(); } } + if (_showMigrate) { + _migrate.show(); + } else { + _migrate.hide(); + } _enableNotifications.show(); updateNotifySettings(); diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h index 3235b69cb..8e61161ad 100644 --- a/Telegram/SourceFiles/profilewidget.h +++ b/Telegram/SourceFiles/profilewidget.h @@ -88,6 +88,8 @@ public slots: void onDeleteChannelSure(); void onBlockUser(); void onAddParticipant(); + void onMigrate(); + void onMigrateSure(); void onUpdatePhoto(); void onUpdatePhotoCancel(); @@ -131,6 +133,9 @@ private: void chatInviteDone(const MTPExportedChatInvite &result); bool updateMediaLinks(int32 *addToScroll = 0); // returns if anything changed + void migrateDone(const MTPUpdates &updates); + bool migrateFail(const RPCError &error); + ProfileWidget *_profile; ScrollArea *_scroll; @@ -162,6 +167,12 @@ private: QString _errorText; + // migrate to megagroup + bool _showMigrate; + Text _aboutMigrate; + FlatButton _migrate; + + // settings FlatCheckbox _enableNotifications; diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 570db76b5..fbb2390ea 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -102,7 +102,7 @@ PeerData::PeerData(const PeerId &id) : id(id), lnk(new PeerLink(this)) , loaded(false) , colorIndex(peerColorIndex(id)) , color(peerColor(colorIndex)) -, photo(isChat() ? chatDefPhoto(colorIndex) : (isChannel() ? channelDefPhoto(colorIndex) : userDefPhoto(colorIndex))) +, photo((isChat() || isMegagroup()) ? chatDefPhoto(colorIndex) : (isChannel() ? channelDefPhoto(colorIndex) : userDefPhoto(colorIndex))) , photoId(UnknownPeerPhotoId) , nameVersion(0) , notify(UnknownNotifySettings) @@ -374,13 +374,13 @@ void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see newPhotoId = phId; } newPhotoLoc = App::imageLocation(160, 160, d.vphoto_small); - newPhoto = newPhotoLoc.isNull() ? channelDefPhoto(colorIndex) : ImagePtr(newPhotoLoc); -// photoFull = ImagePtr(640, 640, d.vphoto_big, channelDefPhoto(colorIndex)); + newPhoto = newPhotoLoc.isNull() ? (isMegagroup() ? chatDefPhoto(colorIndex) : channelDefPhoto(colorIndex)) : ImagePtr(newPhotoLoc); +// photoFull = ImagePtr(640, 640, d.vphoto_big, (isMegagroup() ? chatDefPhoto(colorIndex) : channelDefPhoto(colorIndex))); } break; default: { newPhotoId = 0; newPhotoLoc = StorageImageLocation(); - newPhoto = channelDefPhoto(colorIndex); + newPhoto = (isMegagroup() ? chatDefPhoto(colorIndex) : channelDefPhoto(colorIndex)); // photoFull = ImagePtr(); } break; } @@ -411,6 +411,10 @@ void ChannelData::fullUpdated() { _lastFullUpdate = getms(true); } +ChannelData::~ChannelData() { + delete mgInfo; +} + uint64 PtsWaiter::ptsKey(PtsSkippedQueue queue) { return _queue.insert(uint64(uint32(_last)) << 32 | uint64(uint32(_count)), queue).key(); } diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index e1ac814e0..6ef82fade 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -401,7 +401,10 @@ public: return !isForbidden && !haveLeft() && !wasKicked(); } bool canEdit() const { - return amCreator() || (adminsEnabled() ? amAdmin() : amIn()); + return !isDeactivated() && (amCreator() || (adminsEnabled() ? amAdmin() : amIn())); + } + bool canWrite() const { + return !isDeactivated() && amIn(); } bool haveLeft() const { return flags & MTPDchat::flag_left; @@ -421,6 +424,9 @@ public: bool isDeactivated() const { return flags & MTPDchat::flag_deactivated; } + bool isMigrated() const { + return flags & MTPDchat::flag_migrated_to; + } typedef QMap Participants; Participants participants; typedef QMap InvitedByMe; @@ -497,10 +503,20 @@ private: bool _requesting, _waitingForSkipped, _waitingForShortPoll; }; +struct MegagroupInfo { + MegagroupInfo() : botStatus(-1) { + } + typedef QList LastParticipants; + LastParticipants lastParticipants; + typedef QMap MarkupSenders; + MarkupSenders markupSenders; + int32 botStatus; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other +}; + class ChannelData : public PeerData { public: - ChannelData(const PeerId &id) : PeerData(id), access(0), inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))), count(1), adminsCount(1), date(0), version(0), flags(0), flagsFull(0), isForbidden(true), botStatus(-1), inviter(0), _lastFullUpdate(0) { + ChannelData(const PeerId &id) : PeerData(id), access(0), inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))), count(1), adminsCount(1), date(0), version(0), flags(0), flagsFull(0), mgInfo(0), isForbidden(true), botStatus(-1), inviter(0), _lastFullUpdate(0) { setName(QString(), QString()); } void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = UnknownPeerPhotoId); @@ -519,6 +535,7 @@ public: int32 date; int32 version; int32 flags, flagsFull; + MegagroupInfo *mgInfo; bool isMegagroup() const { return flags & MTPDchannel::flag_megagroup; } @@ -597,6 +614,8 @@ public: return _ptsWaiter.setWaitingForShortPoll(this, ms); } + ~ChannelData(); + private: PtsWaiter _ptsWaiter;