From 41e7ce11a080b7cc63d463a630baa17e2422e438 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 16 Sep 2015 16:04:08 +0300 Subject: [PATCH] channel creation almost done --- Telegram/Resources/lang.strings | 31 +- Telegram/Resources/style.txt | 58 +- Telegram/SourceFiles/boxes/addcontactbox.h | 4 + Telegram/SourceFiles/boxes/backgroundbox.cpp | 2 +- Telegram/SourceFiles/boxes/contactsbox.cpp | 973 +++++++++++++++---- Telegram/SourceFiles/boxes/contactsbox.h | 177 +++- Telegram/SourceFiles/boxes/photocropbox.cpp | 16 +- Telegram/SourceFiles/boxes/photocropbox.h | 3 +- Telegram/SourceFiles/boxes/usernamebox.cpp | 34 +- Telegram/SourceFiles/boxes/usernamebox.h | 11 - Telegram/SourceFiles/dialogswidget.cpp | 2 +- Telegram/SourceFiles/gui/flatinput.cpp | 32 + Telegram/SourceFiles/gui/flatinput.h | 15 + Telegram/SourceFiles/gui/flattextarea.cpp | 47 +- Telegram/SourceFiles/gui/flattextarea.h | 28 +- Telegram/SourceFiles/gui/twidget.h | 122 ++- Telegram/SourceFiles/history.cpp | 7 +- Telegram/SourceFiles/historywidget.cpp | 57 +- Telegram/SourceFiles/historywidget.h | 8 +- Telegram/SourceFiles/intro/introsignup.cpp | 4 +- Telegram/SourceFiles/layerwidget.cpp | 37 +- Telegram/SourceFiles/layerwidget.h | 11 +- Telegram/SourceFiles/localstorage.cpp | 1 + Telegram/SourceFiles/mainwidget.cpp | 24 +- Telegram/SourceFiles/mainwidget.h | 6 +- Telegram/SourceFiles/mediaview.cpp | 4 +- Telegram/SourceFiles/mtproto/mtpScheme.cpp | 110 ++- Telegram/SourceFiles/mtproto/mtpScheme.h | 488 +++++++++- Telegram/SourceFiles/mtproto/scheme.tl | 15 +- Telegram/SourceFiles/passcodewidget.cpp | 2 +- Telegram/SourceFiles/pspecific_linux.cpp | 2 +- Telegram/SourceFiles/pspecific_mac.cpp | 2 +- Telegram/SourceFiles/pspecific_wnd.cpp | 2 +- Telegram/SourceFiles/settingswidget.cpp | 2 + Telegram/SourceFiles/structs.cpp | 14 +- Telegram/SourceFiles/window.cpp | 35 +- 36 files changed, 1958 insertions(+), 428 deletions(-) diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 3c0d0b6e0f..f4255ae1b0 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -161,7 +161,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_dlg_filter" = "Search"; "lng_dlg_new_group_name" = "Group name"; "lng_dlg_new_channel_name" = "Channel name"; -"lng_dlg_create_group" = "Create"; "lng_no_contacts" = "You have no contacts"; "lng_no_chats" = "Your chats will be here"; "lng_contacts_loading" = "Loading.."; @@ -378,7 +377,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_profile_invite_to_group" = "Add to Group"; "lng_profile_delete_contact" = "Delete"; "lng_profile_set_group_photo" = "Set Photo"; -"lng_profile_add_participant" = "Add Member"; +"lng_profile_add_participant" = "Add Members"; "lng_profile_delete_and_exit" = "Leave"; "lng_profile_kick" = "Kick"; "lng_profile_sure_kick" = "Kick {user} from the group?"; @@ -402,9 +401,28 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_participant_invite" = "Invite"; "lng_create_new_group" = "New Group"; "lng_create_new_channel" = "New Channel"; +"lng_create_group_back" = "Back"; "lng_create_group_next" = "Next"; +"lng_create_group_create" = "Create"; "lng_create_group_title" = "New Group"; +"lng_create_group_about" = "Groups have up to 200 members and are good for smaller communities"; "lng_create_channel_title" = "New Channel"; +"lng_create_channel_about" = "Channels have unlimited number of members and are good for connecting with large audiences"; +"lng_create_public_channel_title" = "Public Channel"; +"lng_create_public_channel_about" = "Everyone will be able to join your channel"; +"lng_create_private_channel_title" = "Private Channel"; +"lng_create_private_channel_about" = "Only those who have the invitation link will be able to join your channel"; +"lng_create_group_save" = "Save"; +"lng_create_group_skip" = "Skip"; + +"lng_create_channel_link_invalid" = "This link is invalid"; +"lng_create_channel_link_occupied" = "This link is already occupied"; +"lng_create_channel_link_too_short" = "This link is too short"; +"lng_create_channel_link_bad_symbols" = "This link has bad symbols"; +"lng_create_channel_link_available" = "This link is available"; + +"lng_create_group_crop" = "Select square area for group photo"; +"lng_create_channel_crop" = "Select square area for channel photo"; "lng_failed_add_participant" = "Could not add user. Try again later."; "lng_failed_add_not_mutual" = "Sorry, if a person left a group, only a\nmutual contact can bring them back\n(they need to have your phone\nnumber, and you need theirs)."; @@ -435,6 +453,8 @@ Copyright (c) 2014 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_comments_disabled" = "Comments were disabled"; +"lng_action_comments_enabled" = "Comments were enabled"; "lng_group_invite_bad_link" = "This invite link is broken\nor has expired."; "lng_group_invite_want_join" = "Do you want to join the group «{title}»?"; @@ -509,6 +529,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_send_button" = "Send"; "lng_message_ph" = "Write a message.."; +"lng_comment_ph" = "Write a comment.."; +"lng_broadcast_ph" = "Broadcast a message.."; "lng_record_cancel" = "Release outside this field to cancel"; "lng_empty_history" = ""; "lng_willbe_history" = "Please select a chat to start messaging"; @@ -627,7 +649,10 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org "lng_contacts_header" = "Contacts"; "lng_contact_not_joined" = "Unfortunately {name} did not join Telegram yet, but you can send your friend an invitation.\n\nWe will notify you about any of your contacts who is joining Telegram."; "lng_try_other_contact" = "Try other"; -"lng_contacts_done" = "Cancel"; +"lng_contacts_done" = "Close"; +"lng_create_group_link" = "Link"; +"lng_create_group_photo" = "Set Photo"; +"lng_create_group_description" = "Description (optional)"; "lng_drag_images_here" = "Drop images here"; "lng_drag_photos_here" = "Drop photos here"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 51ed821c80..eaf0af65a0 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1380,15 +1380,57 @@ contactsFilter: flatInput(dlgFilter) { textMrg: margins(34px, 3px, 5px, 4px); imgPos: point(6px, 7px); } -newGroupName: flatInput(inpDefGray) { - width: 340px; - height: 44px; - font: font(15px); - textMrg: margins(12px, 5px, 12px, 5px); -} inpCountry: flatInput(contactsFilter) { } +newGroupName: flatInput(inpDefGray) { + width: 340px; + height: 42px; + font: font(15px); + textMrg: margins(12px, 4px, 12px, 4px); +} +newGroupLink: flatInput(inpDefFlat) { + width: 340px; + height: 42px; + font: font(15px); + textMrg: margins(12px, 4px, 12px, 4px); + bgColor: transparent; + bgActive: transparent; + borderWidth: 2px; + borderColor: #f2f2f2; + borderActive: #80cff9; + borderError: #ed8080; + phColor: #828282; + phFocusColor: #949494; +} +newGroupLimitFg: #a4a4a4; +newGroupAboutFg: #808080; newGroupNamePadding: margins(12px, 15px, 12px, 13px); +newGroupPadding: margins(26px, 28px, 26px, 24px); +newGroupSkip: 15px; +newGroupLinkPadding: margins(26px, 27px, 26px, 27px); +newGroupLinkTop: -3px; +newGroupLinkFont: font(16px); +newGroupPhoto: flatButton(btnDefNext, btnDefBig) { + width: 199px; + height: 42px; + + textTop: 9px; + overTextTop: 9px; + downTextTop: 10px; + + font: font(17px); + overFont: font(17px); +} +newGroupPhotoSize: 96px; +newGroupPhotoSkip: 18px; +newGroupDescriptionSkip: 28px; +newGroupDescription: flatTextarea(taDefFlat) { + font: font(15px); + bgColor: transparent; + phColor: #828282; + phFocusColor: #949494; +} +newGroupDescriptionPadding: margins(5px, 6px, 5px, 6px); connectionSkip: 20px; inpConnectionHost: flatInput(inpDefGray) { @@ -1546,10 +1588,6 @@ dragPadding: margins(20px, 10px, 20px, 10px); dragHeight: 72px; -selectedFont: font(fsize); -selectedColor: #777; -selectedTop: 14px; - downloadSkip: 20px; inpDownloadDir: flatInput(inpDefGray) { font: font(fsize); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h index 630a36cb89..ece1a89b4e 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.h +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -30,6 +30,10 @@ public: void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); + void setInnerFocus() { + _firstInput.setFocus(); + } + public slots: void onSend(); diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp index 35343e2a82..7341fad737 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.cpp +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -172,7 +172,7 @@ void BackgroundInner::resizeEvent(QResizeEvent *e) { } BackgroundBox::BackgroundBox() : ItemListBox(st::boxScroll), _inner(), -_close(this, lang(lng_contacts_done), st::contactsClose) { +_close(this, lang(lng_cancel), st::contactsClose) { init(&_inner, _close.height(), st::boxFont->height + st::newGroupNamePadding.top() + st::newGroupNamePadding.bottom()); diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index f6cb0da1ff..913a3da0b4 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -23,9 +23,38 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "window.h" +#include "application.h" + +#include "gui/filedialog.h" +#include "photocropbox.h" + #include "confirmbox.h" -ContactsInner::ContactsInner(bool creatingChat) : _chat(0), _bot(0), _creatingChat(creatingChat), _addToChat(0), +ContactsInner::ContactsInner(CreatingGroupType creating) : _chat(0), _channel(0), _bot(0), _creating(creating), _addToChat(0), +_contacts(&App::main()->contactsList()), +_sel(0), +_filteredSel(-1), +_mouseSel(false), +_selCount(1), +_searching(false), +_byUsernameSel(-1), +_addContactLnk(this, lang(lng_add_contact_button)) { + init(); +} + +ContactsInner::ContactsInner(ChannelData *channel) : _chat(0), _channel(channel), _bot(0), _creating(CreatingGroupChannel), _addToChat(0), +_contacts(&App::main()->contactsList()), +_sel(0), +_filteredSel(-1), +_mouseSel(false), +_selCount(1), +_searching(false), +_byUsernameSel(-1), +_addContactLnk(this, lang(lng_add_contact_button)) { + init(); +} + +ContactsInner::ContactsInner(ChatData *chat) : _chat(chat), _channel(0), _bot(0), _creating(CreatingGroupNone), _addToChat(0), _contacts(&App::main()->contactsList()), _sel(0), _filteredSel(-1), @@ -37,19 +66,7 @@ _addContactLnk(this, lang(lng_add_contact_button)) { init(); } -ContactsInner::ContactsInner(ChatData *chat) : _chat(chat), _bot(0), _creatingChat(false), _addToChat(0), -_contacts(&App::main()->contactsList()), -_sel(0), -_filteredSel(-1), -_mouseSel(false), -_selCount(0), -_searching(false), -_byUsernameSel(-1), -_addContactLnk(this, lang(lng_add_contact_button)) { - init(); -} - -ContactsInner::ContactsInner(UserData *bot) : _chat(0), _bot(bot), _creatingChat(false), _addToChat(0), +ContactsInner::ContactsInner(UserData *bot) : _chat(0), _channel(0), _bot(bot), _creating(CreatingGroupNone), _addToChat(0), _contacts(new DialogsIndexed(DialogsSortByAdd)), _sel(0), _filteredSel(-1), @@ -92,14 +109,12 @@ void ContactsInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &old void ContactsInner::onAddBot() { if (_bot->botInfo && !_bot->botInfo->startGroupToken.isEmpty()) { - uint64 randomId = MTP::nonce(); - MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToChat->inputChat, MTP_long(randomId), MTP_string(_bot->botInfo->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot)); - - App::wnd()->hideLayer(); - App::main()->showPeerHistory(_addToChat->id, ShowAtUnreadMsgId); + MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToChat->inputChat, MTP_long(MTP::nonce()), MTP_string(_bot->botInfo->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot)); } else { App::main()->addParticipants(_addToChat, QVector(1, _bot)); } + App::wnd()->hideLayer(); + App::main()->showPeerHistory(_addToChat->id, ShowAtUnreadMsgId); } void ContactsInner::peerUpdated(PeerData *peer) { @@ -179,7 +194,7 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) { ContactsData::const_iterator i = _contactsData.constFind(peer); if (i == _contactsData.cend()) { _contactsData.insert(peer, data = new ContactData()); - data->inchat = (_chat && peer->isUser()) ? _chat->participants.contains(peer->asUser()) : false; + data->inchat = (_chat && peer->isUser()) ? _chat->participants.contains(peer->asUser()) : ((_creating == CreatingGroupGroup || _channel) ? (peer == App::self()) : false); data->check = _checkedContacts.contains(peer); data->name.setText(st::profileListNameFont, peer->name, _textNameOptions); if (peer->isUser()) { @@ -207,7 +222,7 @@ void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data, UserData *user = peer->asUser(); - if (data->inchat || data->check || _selCount + (_chat ? _chat->count : 0) >= cMaxGroupCount()) { + if (data->inchat || data->check || selectedCount() >= cMaxGroupCount()) { sel = false; } @@ -222,10 +237,10 @@ void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data, } else { p.setPen(st::profileListNameColor->p); } - int32 iconw = (_chat || _creatingChat) ? st::profileCheckRect.pxWidth() : st::contactsImg.pxWidth(); + int32 iconw = (_chat || _creating != CreatingGroupNone) ? st::profileCheckRect.pxWidth() : st::contactsImg.pxWidth(); data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - iconw); - if (_chat || _creatingChat) { + if (_chat || _creating !=CreatingGroupNone) { if (sel || data->check) { p.drawPixmap(QPoint(width() - st::profileCheckRect.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect)); } @@ -397,7 +412,7 @@ void ContactsInner::mousePressEvent(QMouseEvent *e) { } void ContactsInner::chooseParticipant() { - if (_chat || _creatingChat) { + if (_chat || _creating != CreatingGroupNone) { _time = unixtime(); int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from; if (_filter.isEmpty()) { @@ -476,15 +491,21 @@ void ContactsInner::changeCheckState(DialogRow *row) { } void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) { + int32 cnt = _selCount; if (data->check) { data->check = false; _checkedContacts.remove(peer); --_selCount; - } else if (_selCount + (_chat ? _chat->count : 0) < cMaxGroupCount()) { + } else if (selectedCount() < cMaxGroupCount()) { data->check = true; _checkedContacts.insert(peer, true); ++_selCount; } + if (cnt != _selCount) emit chosenChanged(); +} + +int32 ContactsInner::selectedCount() const { + return _selCount + ((_chat && _chat->count >= 0) ? _chat->count : 0); } void ContactsInner::updateSel() { @@ -695,11 +716,12 @@ void ContactsInner::peopleReceived(const QString &query, const QVector PeerData *p = App::peer(peerId); if (!p) continue; - if ((!p->isUser() || p->asUser()->botInfo && p->asUser()->botInfo->cantJoinGroups) && (_chat || _creatingChat)) continue; // skip bot's that can't be invited to groups + if ((!p->isUser() || p->asUser()->botInfo && p->asUser()->botInfo->cantJoinGroups) && (_chat || _creating != CreatingGroupNone)) continue; // skip bot's that can't be invited to groups + if (p->isUser() && p->asUser()->botInfo && _creating == CreatingGroupChannel) continue; // skip bots in channels ContactData *d = new ContactData(); _byUsernameDatas.push_back(d); - d->inchat = _chat ? _chat->participants.contains(p->asUser()) : false; + d->inchat = _chat ? _chat->participants.contains(p->asUser()) : ((_creating == CreatingGroupGroup || _channel) ? (p == App::self()) : false); d->check = _checkedContacts.contains(p); d->name.setText(st::profileListNameFont, p->name, _textNameOptions); d->online = '@' + p->userName(); @@ -741,12 +763,16 @@ ChatData *ContactsInner::chat() const { return _chat; } +ChannelData *ContactsInner::channel() const { + return _channel; +} + UserData *ContactsInner::bot() const { return _bot; } -bool ContactsInner::creatingChat() const { - return _creatingChat; +CreatingGroupType ContactsInner::creating() const { + return _creating; } ContactsInner::~ContactsInner() { @@ -946,51 +972,66 @@ PeerData *ContactsInner::selectedUser() { return 0; } -ContactsBox::ContactsBox(bool creatingChat) : ItemListBox(st::boxNoTopScroll), _inner(creatingChat), +ContactsBox::ContactsBox() : ItemListBox(st::boxNoTopScroll), _inner(CreatingGroupNone), _addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_createChannel(this, lang(lng_create_channel_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_contacts_done), creatingChat ? st::btnSelectCancel : st::contactsClose), _creatingChannel(false) { +_cancel(this, lang(lng_contacts_done), st::contactsClose), +_creationRequestId(0) { + init(); +} + +ContactsBox::ContactsBox(const QString &name, const QImage &photo) : ItemListBox(st::boxNoTopScroll), _inner(CreatingGroupGroup), +_addContact(this, lang(lng_add_contact_button), st::contactsAdd), +_filter(this, st::contactsFilter, lang(lng_participant_filter)), +_next(this, lang(lng_create_group_create), st::btnSelectDone), +_cancel(this, lang(lng_create_group_back), st::btnSelectCancel), +_creationRequestId(0), _creationName(name), _creationPhoto(photo) { + init(); +} + +ContactsBox::ContactsBox(ChannelData *channel) : ItemListBox(st::boxNoTopScroll), _inner(channel), +_addContact(this, lang(lng_add_contact_button), st::contactsAdd), +_filter(this, st::contactsFilter, lang(lng_participant_filter)), +_next(this, lang(lng_participant_invite), st::btnSelectDone), +_cancel(this, lang(lng_create_group_skip), st::btnSelectCancel), +_creationRequestId(0) { init(); } ContactsBox::ContactsBox(ChatData *chat) : ItemListBox(st::boxNoTopScroll), _inner(chat), _addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_createChannel(this, lang(lng_create_channel_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::btnSelectCancel), _creatingChannel(false) { +_cancel(this, lang(lng_cancel), st::btnSelectCancel), +_creationRequestId(0) { init(); } ContactsBox::ContactsBox(UserData *bot) : ItemListBox(st::boxNoTopScroll), _inner(bot), _addContact(this, lang(lng_add_contact_button), st::contactsAdd), -_createChannel(this, lang(lng_create_channel_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::contactsClose), _creatingChannel(false) { +_cancel(this, lang(lng_cancel), st::contactsClose), +_creationRequestId(0) { init(); } void ContactsBox::init() { ItemListBox::init(&_inner, _cancel.height(), st::contactsAdd.height + st::newGroupNamePadding.top() + _filter.height() + st::newGroupNamePadding.bottom()); + connect(&_inner, SIGNAL(chosenChanged()), this, SLOT(update())); if (_inner.chat()) { _addContact.hide(); - _createChannel.hide(); - } else if (_inner.creatingChat()) { + } else if (_inner.creating() != CreatingGroupNone) { _addContact.hide(); - _createChannel.show(); - connect(&_createChannel, SIGNAL(clicked()), this, SLOT(onCreateChannel())); } else { connect(&_addContact, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); - _createChannel.hide(); } - if (_inner.chat()) { + if (_inner.chat() || _inner.channel()) { connect(&_next, SIGNAL(clicked()), this, SLOT(onInvite())); - } else if (_inner.creatingChat()) { - connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + } else if (_inner.creating() != CreatingGroupNone) { + connect(&_next, SIGNAL(clicked()), this, SLOT(onCreate())); } else { _next.hide(); } @@ -998,7 +1039,6 @@ void ContactsBox::init() { connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel())); connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll())); connect(&_filter, SIGNAL(changed()), this, SLOT(onFilterUpdate())); - connect(&_filter, SIGNAL(cancelled()), this, SLOT(onClose())); connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int))); connect(&_inner, SIGNAL(selectAllQuery()), &_filter, SLOT(selectAll())); connect(&_inner, SIGNAL(searchByUsername()), this, SLOT(onNeedSearchByUsername())); @@ -1079,7 +1119,6 @@ bool ContactsBox::peopleFailed(const RPCError &error, mtpRequestId req) { void ContactsBox::hideAll() { ItemListBox::hideAll(); _addContact.hide(); - _createChannel.hide(); _filter.hide(); _next.hide(); _cancel.hide(); @@ -1091,11 +1130,9 @@ void ContactsBox::showAll() { if (_inner.chat()) { _next.show(); _addContact.hide(); - _createChannel.hide(); - } else if (_inner.creatingChat()) { + } else if (_inner.creating() != CreatingGroupNone) { _next.show(); _addContact.hide(); - _createChannel.show(); } else { _next.hide(); if (_inner.bot()) { @@ -1103,7 +1140,6 @@ void ContactsBox::showAll() { } else { _addContact.show(); } - _createChannel.hide(); } _cancel.show(); } @@ -1140,8 +1176,12 @@ void ContactsBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - if (_inner.chat() || _inner.creatingChat()) { - paintTitle(p, lang(_inner.chat() ? lng_profile_add_participant : (_creatingChannel ? lng_create_new_channel : lng_create_new_group)), true); + if (_inner.chat() || _inner.creating() != CreatingGroupNone) { + QString title(lang(lng_profile_add_participant)); + paintTitle(p, title, true); + + p.setPen(st::newGroupLimitFg); + p.drawTextLeft(st::boxTitlePos.x() + st::boxTitleFont->m.width(title) + st::addContactDelta, st::boxTitlePos.y(), width(), QString("%1 / %2").arg(_inner.selectedCount()).arg(cMaxGroupCount())); // paint button sep p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); @@ -1155,13 +1195,18 @@ void ContactsBox::paintEvent(QPaintEvent *e) { void ContactsBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _addContact.move(width() - _addContact.width(), 0); - _createChannel.move(width() - _createChannel.width(), 0); _filter.move(st::newGroupNamePadding.left(), _addContact.height() + st::newGroupNamePadding.top()); _inner.resize(width(), _inner.height()); _next.move(width() - _next.width(), height() - _next.height()); _cancel.move(0, height() - _cancel.height()); } +void ContactsBox::closePressed() { + if (_inner.channel()) { + App::main()->showPeerHistory(_inner.channel()->id, ShowAtTheEndMsgId); + } +} + void ContactsBox::onFilterUpdate() { _scroll.scrollToY(0); _inner.updateFilter(_filter.text()); @@ -1171,130 +1216,52 @@ void ContactsBox::onAdd() { App::wnd()->replaceLayer(new AddContactBox()); } -void ContactsBox::onCreateChannel() { - _creatingChannel = !_creatingChannel; - _createChannel.setText(lang(_creatingChannel ? lng_create_group_button : lng_create_channel_button)); - _createChannel.move(width() - _createChannel.width(), 0); - update(); -} - void ContactsBox::onInvite() { QVector users(_inner.selected()); if (users.isEmpty()) { _filter.setFocus(); + _filter.notaBene(); return; } - App::main()->addParticipants(_inner.chat(), users); + App::main()->addParticipants(_inner.chat() ? (PeerData*)_inner.chat() : _inner.channel(), users); + if (_inner.chat()) { + App::wnd()->hideLayer(); + App::main()->showPeerHistory(_inner.chat()->id, ShowAtTheEndMsgId); + } else { + onClose(); + } } -void ContactsBox::onNext() { +void ContactsBox::onCreate() { + if (_creationRequestId) return; + + //if (_inner.creating() == CreatingGroupChannel) { // tmp + // ChannelData *channel = App::channelLoaded(10449997); + // if (channel) { + // App::wnd()->hideLayer(true); + // App::wnd()->showLayer(new SetupChannelBox(channel), true); + // } + // return; + //} + MTPVector users(MTP_vector(_inner.selectedInputs())); const QVector &v(users.c_vector().v); - if (v.isEmpty()) { + if (v.isEmpty() || (v.size() == 1 && v.at(0).type() == mtpc_inputUserSelf)) { _filter.setFocus(); _filter.notaBene(); - } else if (v.size() == 1) { - App::main()->showPeerHistory(_inner.selectedUser()->id, ShowAtUnreadMsgId); - } else { - App::wnd()->replaceLayer(new CreateGroupBox(users, _creatingChannel)); + return; } + _creationRequestId = MTP::send(MTPmessages_CreateChat(MTP_vector(v), MTP_string(_creationName)), rpcDone(&ContactsBox::creationDone), rpcFail(&ContactsBox::creationFail)); } void ContactsBox::onScroll() { _inner.loadProfilePhotos(_scroll.scrollTop()); } -CreateGroupBox::CreateGroupBox(const MTPVector &users, bool creatingChannel) : AbstractBox(), _users(users), -_creatingChannel(creatingChannel), -_createRequestId(0), -_name(this, st::newGroupName, lang(_creatingChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), -_create(this, lang(lng_dlg_create_group), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::btnSelectCancel) { - - setMaxHeight(st::boxTitleHeight + st::addContactPadding.top() + _name.height() + st::addContactPadding.bottom() + _create.height()); - - connect(&_create, SIGNAL(clicked()), this, SLOT(onCreate())); - connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); - - prepare(); -} - -void CreateGroupBox::hideAll() { - _name.hide(); - _cancel.hide(); - _create.hide(); -} - -void CreateGroupBox::showAll() { - _name.show(); - _cancel.show(); - _create.show(); -} - -void CreateGroupBox::showDone() { - _name.setFocus(); -} - -void CreateGroupBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - if (_name.hasFocus()) { - if (_name.text().trimmed().isEmpty()) { - _name.setFocus(); - _name.notaBene(); - } else { - onCreate(); - } - } - } else { - AbstractBox::keyPressEvent(e); - } -} - -void CreateGroupBox::paintEvent(QPaintEvent *e) { - Painter p(this); - if (paint(p)) return; - - paintTitle(p, lang(_creatingChannel ? lng_create_channel_title : lng_create_group_title), true); - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); -} - -void CreateGroupBox::resizeEvent(QResizeEvent *e) { - _name.setGeometry(st::addContactPadding.left(), st::boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _name.height()); - - int32 buttonTop = _name.y() + _name.height() + st::addContactPadding.bottom(); - _cancel.move(0, buttonTop); - _create.move(width() - _create.width(), buttonTop); -} - -void CreateGroupBox::onCreate() { - if (_createRequestId) return; - - QString name = _name.text(); - if (name.isEmpty()) { - _name.setFocus(); - _name.notaBene(); - return; - } - - _create.setDisabled(true); - _name.setDisabled(true); - if (_creatingChannel) { - _createRequestId = MTP::send(MTPmessages_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(_name.text()), MTP_string(""), _users), rpcDone(&CreateGroupBox::created), rpcFail(&CreateGroupBox::failed)); - } else { - _createRequestId = MTP::send(MTPmessages_CreateChat(_users, MTP_string(_name.text())), rpcDone(&CreateGroupBox::created), rpcFail(&CreateGroupBox::failed)); - } -} - -void CreateGroupBox::created(const MTPUpdates &updates) { +PeerData *chatOrChannelCreated(const MTPUpdates &updates, const QImage &photo) { App::main()->sentUpdatesReceived(updates); - App::wnd()->hideLayer(); const QVector *v = 0; switch (updates.type()) { case mtpc_updates: v = &updates.c_updates().vchats.c_vector().v; break; @@ -1311,26 +1278,706 @@ void CreateGroupBox::created(const MTPUpdates &updates) { } break; } if (v && !v->isEmpty() && v->front().type() == mtpc_chat) { - App::main()->showPeerHistory(peerFromChat(v->front().c_chat().vid.v), ShowAtUnreadMsgId); + ChatData *chat = App::chat(v->front().c_chat().vid.v); + if (chat) { + if (!photo.isNull()) { + App::app()->uploadProfilePhoto(photo, chat->id); + } + return chat; + } } else if (v && !v->isEmpty() && v->front().type() == mtpc_channel) { - App::main()->showPeerHistory(peerFromChannel(v->front().c_channel().vid.v), ShowAtUnreadMsgId); + ChannelData *channel = App::channel(v->front().c_channel().vid.v); + if (channel) { + if (!photo.isNull()) { + App::app()->uploadProfilePhoto(photo, channel->id); + } + return channel; + } + } + + return 0; +} + +void ContactsBox::creationDone(const MTPUpdates &updates) { + App::wnd()->hideLayer(); + + PeerData *peer = chatOrChannelCreated(updates, _creationPhoto); + if (peer) { + App::main()->showPeerHistory(peer->id, ShowAtUnreadMsgId); } } -bool CreateGroupBox::failed(const RPCError &error) { +bool ContactsBox::creationFail(const RPCError &error) { if (mtpIsFlood(error)) return false; - _createRequestId = 0; + _creationRequestId = 0; if (error.type() == "NO_CHAT_TITLE") { - _name.setFocus(); + emit closed(); return true; } else if (error.type() == "USERS_TOO_FEW") { - emit closed(); + _filter.setFocus(); + _filter.notaBene(); return true; } else if (error.type() == "PEER_FLOOD") { - emit closed(); - App::wnd()->showLayer(new ConfirmBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info)))), true); + App::wnd()->replaceLayer(new ConfirmBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); return true; } return false; } + +NewGroupBox::NewGroupBox() : AbstractBox(), +_group(this, qsl("group_type"), 0, lang(lng_create_group_title), true), +_channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)), +_aboutGroupWidth(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft), +_aboutGroup(st::normalFont, lang(lng_create_group_about), _defaultOptions, _aboutGroupWidth), +_aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth), +_next(this, lang(lng_create_group_next), st::btnSelectDone), +_cancel(this, lang(lng_cancel), st::btnSelectCancel) { + _aboutGroupHeight = _aboutGroup.countHeight(_aboutGroupWidth); + setMaxHeight(st::newGroupPadding.top() + _group.height() + _aboutGroupHeight + st::newGroupSkip + _channel.height() + _aboutChannel.countHeight(_aboutGroupWidth) + st::newGroupPadding.bottom() + _next.height()); + + connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + prepare(); +} + +void NewGroupBox::hideAll() { + _group.hide(); + _channel.hide(); + _cancel.hide(); + _next.hide(); +} + +void NewGroupBox::showAll() { + _group.show(); + _channel.show(); + _cancel.show(); + _next.show(); +} + +void NewGroupBox::showDone() { + setFocus(); +} + +void NewGroupBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + onNext(); + } else { + AbstractBox::keyPressEvent(e); + } +} + +void NewGroupBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + p.setPen(st::newGroupAboutFg->p); + + QRect aboutGroup(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _group.y() + _group.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutGroupHeight); + if (rtl()) aboutGroup.setX(width() - aboutGroup.x() - aboutGroup.width()); + _aboutGroup.draw(p, aboutGroup.x(), aboutGroup.y(), aboutGroup.width()); + + QRect aboutChannel(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _channel.y() + _channel.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutGroupHeight); + if (rtl()) aboutChannel.setX(width() - aboutChannel.x() - aboutChannel.width()); + _aboutChannel.draw(p, aboutChannel.x(), aboutChannel.y(), aboutChannel.width()); + + // paint shadow + p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); +} + +void NewGroupBox::resizeEvent(QResizeEvent *e) { + _group.moveToLeft(st::newGroupPadding.left(), st::newGroupPadding.top(), width()); + _channel.moveToLeft(st::newGroupPadding.left(), _group.y() + _group.height() + _aboutGroupHeight + st::newGroupSkip, width()); + + int32 buttonTop = height() - st::btnSelectCancel.height; + _cancel.moveToLeft(0, buttonTop, width()); + _next.moveToRight(0, buttonTop, width()); +} + +void NewGroupBox::onNext() { + App::wnd()->replaceLayer(new GroupInfoBox(_group.checked() ? CreatingGroupGroup : CreatingGroupChannel)); +} + +GroupInfoBox::GroupInfoBox(CreatingGroupType creating) : AbstractBox(), +_creating(creating), +a_photoOver(0, 0), +a_photo(animFunc(this, &GroupInfoBox::photoAnimStep)), +_photoOver(false), +_descriptionOver(false), +a_descriptionBg(st::newGroupName.bgColor->c, st::newGroupName.bgColor->c), +a_descriptionBorder(st::newGroupName.borderColor->c, st::newGroupName.borderColor->c), +a_description(animFunc(this, &GroupInfoBox::descriptionAnimStep)), +_name(this, st::newGroupName, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), +_photo(this, lang(lng_create_group_photo), st::newGroupPhoto), +_description(this, st::newGroupDescription, lang(lng_create_group_description)), +_next(this, lang(lng_create_group_next), st::btnSelectDone), +_cancel(this, lang(lng_create_group_back), st::btnSelectCancel), +_creationRequestId(0), _createdChannel(0) { + + setMouseTracking(true); + + _description.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::newGroupDescriptionPadding.left() - st::newGroupDescriptionPadding.right(), _name.height() - st::newGroupDescriptionPadding.top() - st::newGroupDescriptionPadding.bottom()); + _description.setMinHeight(_description.height()); + _description.setMaxHeight(3 * _description.height() + 2 * st::newGroupDescriptionPadding.top() + 2 * st::newGroupDescriptionPadding.bottom()); + + updateMaxHeight(); + connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); + connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onNext())); + connect(&_description, SIGNAL(cancelled()), this, SLOT(onClose())); + + connect(&_photo, SIGNAL(clicked()), this, SLOT(onPhoto())); + + connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + prepare(); +} + +void GroupInfoBox::hideAll() { + _name.hide(); + _photo.hide(); + _description.hide(); + _cancel.hide(); + _next.hide(); +} + +void GroupInfoBox::showAll() { + _name.show(); + _photo.show(); + if (_creating == CreatingGroupChannel) { + _description.show(); + } else { + _description.hide(); + } + _cancel.show(); + _next.show(); +} + +void GroupInfoBox::showDone() { + _name.setFocus(); +} + +void GroupInfoBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_name.hasFocus()) { + if (_name.text().trimmed().isEmpty()) { + _name.setFocus(); + _name.notaBene(); + } else if (_description.isHidden()) { + onNext(); + } else { + _description.setFocus(); + } + } + } else { + AbstractBox::keyPressEvent(e); + } +} + +void GroupInfoBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + QRect phRect(photoRect()); + if (phRect.intersects(e->rect())) { + if (_photoSmall.isNull()) { + int32 s = st::newGroupPhotoSize * cIntRetinaFactor(); + QRect ph(st::setPhotoImg), overph(st::setOverPhotoImg); + if (a_photoOver.current() < 1) { + p.drawPixmapLeft(phRect.topLeft(), width(), App::sprite(), QRect(ph.x() + (ph.width() - s) / 2, ph.y() + (ph.height() - s) / 2, s, s)); + } + if (a_photoOver.current() > 0) { + p.setOpacity(a_photoOver.current()); + p.drawPixmapLeft(phRect.topLeft(), width(), App::sprite(), QRect(overph.x() + (overph.width() - s) / 2, overph.y() + (overph.height() - s) / 2, s, s)); + p.setOpacity(1); + } + } else { + p.drawPixmap(st::newGroupPadding.left(), st::newGroupPadding.left(), _photoSmall); + } + if (phRect.contains(e->rect())) { + return; + } + } + QRect descRect(descriptionRect()); + if (_creating == CreatingGroupChannel && descRect.intersects(e->rect())) { + p.fillRect(descRect, a_descriptionBg.current()); + if (st::newGroupName.borderWidth) { + QBrush b(a_descriptionBorder.current()); + p.fillRect(descRect.x(), descRect.y(), descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); + p.fillRect(descRect.x() + descRect.width() - st::newGroupName.borderWidth, descRect.y(), st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); + p.fillRect(descRect.x() + st::newGroupName.borderWidth, descRect.y() + descRect.height() - st::newGroupName.borderWidth, descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); + p.fillRect(descRect.x(), descRect.y() + st::newGroupName.borderWidth, st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); + } + if (descRect.contains(e->rect())) { + return; + } + } + + // paint shadow + p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); +} + +void GroupInfoBox::resizeEvent(QResizeEvent *e) { + int32 nameLeft = st::newGroupPhotoSize + st::newGroupPhotoSkip; + _name.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - nameLeft, _name.height()); + _name.moveToLeft(st::newGroupPadding.left() + nameLeft, st::newGroupPadding.top(), width()); + _photo.moveToLeft(_name.x(), _name.y() + st::newGroupPhotoSize - _photo.height(), width()); + + _description.moveToLeft(st::newGroupPadding.left() + st::newGroupDescriptionPadding.left(), _photo.y() + _photo.height() + st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top(), width()); + _description.installEventFilter(this); + + int32 buttonTop = (_creating == CreatingGroupChannel) ? (_description.y() + _description.height() + st::newGroupDescriptionPadding.bottom()) : (_photo.y() + _photo.height()); + buttonTop += st::newGroupPadding.bottom(); + _cancel.move(0, buttonTop); + _next.move(width() - _next.width(), buttonTop); +} + +void GroupInfoBox::mouseMoveEvent(QMouseEvent *e) { + updateSelected(e->globalPos()); +} + +void GroupInfoBox::updateSelected(const QPoint &cursorGlobalPosition) { + QPoint p(mapFromGlobal(cursorGlobalPosition)); + + bool photoOver = photoRect().contains(p); + if (photoOver != _photoOver) { + _photoOver = photoOver; + if (_photoSmall.isNull()) { + a_photoOver.start(_photoOver ? 1 : 0); + a_photo.start(); + } + } + + bool descriptionOver = _photoOver ? false : descriptionRect().contains(p); + if (descriptionOver != _descriptionOver) { + _descriptionOver = descriptionOver; + } + + setCursor(_photoOver ? style::cur_pointer : (_descriptionOver ? style::cur_text : style::cur_default)); +} + +void GroupInfoBox::mousePressEvent(QMouseEvent *e) { + mouseMoveEvent(e); + if (_photoOver) { + onPhoto(); + } else if (_descriptionOver) { + _description.setFocus(); + } +} + +void GroupInfoBox::leaveEvent(QEvent *e) { + updateSelected(QCursor::pos()); +} + +bool GroupInfoBox::descriptionAnimStep(float64 ms) { + float dt = ms / st::newGroupName.phDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_descriptionBg.finish(); + a_descriptionBorder.finish(); + } else { + a_descriptionBg.update(dt, st::newGroupName.phColorFunc); + a_descriptionBorder.update(dt, st::newGroupName.phColorFunc); + } + update(descriptionRect()); + return res; +} + +bool GroupInfoBox::photoAnimStep(float64 ms) { + float64 dt = ms / st::setPhotoDuration; + bool res = true; + if (dt >= 1) { + res = false; + a_photoOver.finish(); + } else { + a_photoOver.update(dt, anim::linear); + } + update(photoRect()); + return res; +} + +bool GroupInfoBox::eventFilter(QObject *obj, QEvent *e) { + if (obj == &_description) { + if (e->type() == QEvent::FocusIn) { + a_descriptionBorder.start(st::newGroupName.borderActive->c); + a_descriptionBg.start(st::newGroupName.bgActive->c); + a_description.start(); + } else if (e->type() == QEvent::FocusOut) { + a_descriptionBorder.start(st::newGroupName.borderColor->c); + a_descriptionBg.start(st::newGroupName.bgColor->c); + a_description.start(); + } + } + return AbstractBox::eventFilter(obj, e); +} + +void GroupInfoBox::onNext() { + if (_creationRequestId) return; + + QString name = _name.text().trimmed(); + if (name.isEmpty()) { + _name.setFocus(); + _name.notaBene(); + return; + } + if (_creating == CreatingGroupGroup) { + App::wnd()->replaceLayer(new ContactsBox(name, _photoBig)); + } else { + _creationRequestId = MTP::send(MTPmessages_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); + } +} + +void GroupInfoBox::creationDone(const MTPUpdates &updates) { + PeerData *result = chatOrChannelCreated(updates, _photoBig); + if (!result || !result->isChannel()) { + onClose(); + } else { + _createdChannel = result->asChannel(); + _creationRequestId = MTP::send(MTPmessages_ExportChatInvite(_createdChannel->inputChat), rpcDone(&GroupInfoBox::exportDone)); + } +} + +bool GroupInfoBox::creationFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _creationRequestId = 0; + if (error.type() == "NO_CHAT_TITLE") { + _name.setFocus(); + _name.notaBene(); + return true; + } else if (error.type() == "PEER_FLOOD") { + App::wnd()->replaceLayer(new ConfirmBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); + return true; + } + return false; +} + +void GroupInfoBox::exportDone(const MTPExportedChatInvite &result) { + _creationRequestId = 0; + if (result.type() == mtpc_chatInviteExported) { + _createdChannel->invitationUrl = qs(result.c_chatInviteExported().vlink); + } + App::wnd()->hideLayer(true); + App::wnd()->showLayer(new SetupChannelBox(_createdChannel), true); +} + +void GroupInfoBox::onDescriptionResized() { + updateMaxHeight(); + update(); +} + +QRect GroupInfoBox::descriptionRect() const { + return rtlrect(_description.x() - st::newGroupDescriptionPadding.left(), _description.y() - st::newGroupDescriptionPadding.top(), _description.width() + st::newGroupDescriptionPadding.left() + st::newGroupDescriptionPadding.right(), _description.height() + st::newGroupDescriptionPadding.top() + st::newGroupDescriptionPadding.bottom(), width()); +} + +QRect GroupInfoBox::photoRect() const { + return rtlrect(st::newGroupPadding.left(), st::newGroupPadding.top(), st::newGroupPhotoSize, st::newGroupPhotoSize, width()); +} + +void GroupInfoBox::updateMaxHeight() { + int32 h = st::newGroupPadding.top() + st::newGroupPhotoSize + st::newGroupPadding.bottom() + _next.height(); + if (_creating == CreatingGroupChannel) { + h += st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); + } + setMaxHeight(h); +} + +void GroupInfoBox::onPhoto() { + QStringList imgExtensions(cImgExtensions()); + QString filter(qsl("Image files (*") + imgExtensions.join(qsl(" *")) + qsl(");;All files (*.*)")); + + QImage img; + QString file; + QByteArray remoteContent; + if (filedialogGetOpenFile(file, remoteContent, lang(lng_choose_images), filter)) { + if (!remoteContent.isEmpty()) { + img = App::readImage(remoteContent); + } else { + if (!file.isEmpty()) { + img = App::readImage(file); + } + } + } else { + return; + } + + if (img.isNull() || img.width() > 10 * img.height() || img.height() > 10 * img.width()) { + return; + } + PhotoCropBox *box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0), false); + connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&))); + App::wnd()->replaceLayer(box); +} + +void GroupInfoBox::onPhotoReady(const QImage &img) { + _photoBig = img; + _photoSmall = QPixmap::fromImage(img.scaled(st::newGroupPhotoSize * cIntRetinaFactor(), st::newGroupPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); + _photoSmall.setDevicePixelRatio(cRetinaFactor()); +} + +SetupChannelBox::SetupChannelBox(ChannelData *channel) : AbstractBox(), +_channel(channel), +_public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true), +_private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title)), +_aboutPublicWidth(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft), +_aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth), +_aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth), +_linkPlaceholder(qsl("telegram.me/")), +_link(this, st::newGroupLink, QString()), +_save(this, lang(lng_create_group_save), st::btnSelectDone), +_skip(this, lang(lng_create_group_skip), st::btnSelectCancel), +_saveRequestId(0), _checkRequestId(0) { + _link.setTextMargin(style::margins(st::newGroupLink.textMrg.left() + st::newGroupLink.font->m.width(_linkPlaceholder), st::newGroupLink.textMrg.top(), st::newGroupLink.textMrg.right(), st::newGroupLink.textMrg.bottom())); + + _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); + setMaxHeight(st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); + + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); + + connect(&_link, SIGNAL(changed()), this, SLOT(onChange())); + + _checkTimer.setSingleShot(true); + connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); + + connect(&_public, SIGNAL(changed()), this, SLOT(onPrivacyChange())); + connect(&_private, SIGNAL(changed()), this, SLOT(onPrivacyChange())); + + prepare(); +} + +void SetupChannelBox::hideAll() { + _link.hide(); + _save.hide(); + _skip.hide(); +} + +void SetupChannelBox::showAll() { + if (_public.checked()) { + _link.show(); + } else { + _link.hide(); + } + _save.show(); + _skip.show(); +} + +void SetupChannelBox::showDone() { + _link.setFocus(); +} + +void SetupChannelBox::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { + if (_link.hasFocus()) { + if (_link.text().trimmed().isEmpty()) { + _link.setFocus(); + _link.notaBene(); + } else { + onSave(); + } + } + } else { + AbstractBox::keyPressEvent(e); + } +} + +void SetupChannelBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + p.setPen(st::newGroupAboutFg); + + QRect aboutPublic(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _public.y() + _public.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight); + if (rtl()) aboutPublic.setX(width() - aboutPublic.x() - aboutPublic.width()); + _aboutPublic.draw(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width()); + + QRect aboutPrivate(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _private.y() + _private.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight); + if (rtl()) aboutPrivate.setX(width() - aboutPrivate.x() - aboutPrivate.width()); + _aboutPrivate.draw(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width()); + + p.setPen(st::black); + p.setFont(st::newGroupLinkFont); + p.drawTextLeft(st::newGroupPadding.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(lng_create_group_link)); + + if (!_link.isHidden()) { + p.setFont(st::newGroupLink.font); + p.setPen(st::newGroupLink.phColor); + p.drawText(QRect(_link.x() + st::newGroupLink.textMrg.left(), _link.y() + st::newGroupLink.textMrg.top(), _link.width(), _link.height() - st::newGroupLink.textMrg.top() - st::newGroupLink.textMrg.bottom()), _linkPlaceholder, style::al_left); + + if (!_errorText.isEmpty()) { + p.setPen(st::setErrColor->p); + p.setFont(st::setErrFont->f); + p.drawTextRight(st::newGroupPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::setErrFont->ascent, width(), _errorText); + } else if (!_goodText.isEmpty()) { + p.setPen(st::setGoodColor->p); + p.setFont(st::setErrFont->f); + p.drawTextRight(st::newGroupPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::setErrFont->ascent, width(), _goodText); + } + } + + // paint shadow + p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); + + // paint button sep + p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); +} + +void SetupChannelBox::resizeEvent(QResizeEvent *e) { + _public.moveToLeft(st::newGroupPadding.left(), st::newGroupPadding.top(), width()); + _private.moveToLeft(st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip, width()); + + _link.setGeometry(st::newGroupLinkPadding.left(), st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); + + int32 buttonTop = _link.y() + _link.height() + st::newGroupLinkPadding.bottom(); + _skip.moveToLeft(0, buttonTop, width()); + _save.moveToRight(0, buttonTop, width()); +} + +void SetupChannelBox::closePressed() { + App::wnd()->showLayer(new ContactsBox(_channel), true); +} + +void SetupChannelBox::onSave() { + if (!_public.checked()) { + onClose(); + } + + if (_saveRequestId) return; + + QString link = _link.text().trimmed(); + if (link.isEmpty()) { + _link.setFocus(); + _link.notaBene(); + return; + } + + _sentUsername = link; + _saveRequestId = MTP::send(MTPmessages_UpdateChannelUsername(_channel->inputChat, MTP_string(_sentUsername)), rpcDone(&SetupChannelBox::onUpdateDone), rpcFail(&SetupChannelBox::onUpdateFail)); +} + +void SetupChannelBox::onChange() { + QString name = _link.text().trimmed(); + if (name.isEmpty()) { + if (!_errorText.isEmpty() || !_goodText.isEmpty()) { + _errorText = _goodText = QString(); + update(); + } + _checkTimer.stop(); + } else { + int32 i, len = name.size(); + for (int32 i = 0; i < len; ++i) { + QChar ch = name.at(i); + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) { + if (_errorText != lang(lng_create_channel_link_bad_symbols)) { + _errorText = lang(lng_create_channel_link_bad_symbols); + update(); + } + _checkTimer.stop(); + return; + } + } + if (name.size() < MinUsernameLength) { + if (_errorText != lang(lng_create_channel_link_too_short)) { + _errorText = lang(lng_create_channel_link_too_short); + update(); + } + _checkTimer.stop(); + } else { + if (!_errorText.isEmpty() || !_goodText.isEmpty()) { + _errorText = _goodText = QString(); + update(); + } + _checkTimer.start(UsernameCheckTimeout); + } + } +} + +void SetupChannelBox::onCheck() { + if (_checkRequestId) { + MTP::cancel(_checkRequestId); + } + QString link = _link.text().trimmed(); + if (link.size() >= MinUsernameLength) { + _checkUsername = link; + _checkRequestId = MTP::send(MTPmessages_CheckChannelUsername(_channel->inputChat, MTP_string(link)), rpcDone(&SetupChannelBox::onCheckDone), rpcFail(&SetupChannelBox::onCheckFail)); + } +} + +void SetupChannelBox::onPrivacyChange() { + if (_public.checked()) { + _link.show(); + _link.setFocus(); + } else { + _link.hide(); + } + update(); +} + +void SetupChannelBox::onUpdateDone(const MTPBool &result) { + _channel->setName(textOneLine(_channel->name), _sentUsername); + onClose(); +} + +bool SetupChannelBox::onUpdateFail(const RPCError &error) { + if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + + _saveRequestId = 0; + QString err(error.type()); + if (err == "USERNAME_NOT_MODIFIED" || _sentUsername == _channel->username) { + _channel->setName(textOneLine(_channel->name), textOneLine(_sentUsername)); + onClose(); + return true; + } else if (err == "USERNAME_INVALID") { + _link.setFocus(); + _link.notaBene(); + _errorText = lang(lng_create_channel_link_invalid); + update(); + return true; + } else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") { + _link.setFocus(); + _link.notaBene(); + _errorText = lang(lng_create_channel_link_occupied); + update(); + return true; + } + _link.setFocus(); + return true; +} + +void SetupChannelBox::onCheckDone(const MTPBool &result) { + _checkRequestId = 0; + QString newError = (result.v || _checkUsername == _channel->username) ? QString() : lang(lng_create_channel_link_occupied); + QString newGood = newError.isEmpty() ? lang(lng_create_channel_link_available) : QString(); + if (_errorText != newError || _goodText != newGood) { + _errorText = newError; + _goodText = newGood; + update(); + } +} + +bool SetupChannelBox::onCheckFail(const RPCError &error) { + if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + + _checkRequestId = 0; + QString err(error.type()); + if (err == "USERNAME_INVALID") { + _errorText = lang(lng_create_channel_link_invalid); + update(); + return true; + } else if (err == "USERNAME_OCCUPIED" && _checkUsername != _channel->username) { + _errorText = lang(lng_create_channel_link_occupied); + update(); + return true; + } + _goodText = QString(); + _link.setFocus(); + return true; +} diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 276b7a5621..95ce9edcd1 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -19,6 +19,12 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "abstractbox.h" +enum CreatingGroupType { + CreatingGroupNone, + CreatingGroupGroup, + CreatingGroupChannel, +}; + class ContactsInner : public QWidget, public RPCSender { Q_OBJECT @@ -28,7 +34,8 @@ private: public: - ContactsInner(bool creatingChat); + ContactsInner(CreatingGroupType creating = CreatingGroupNone); + ContactsInner(ChannelData *channel); ContactsInner(ChatData *chat); ContactsInner(UserData *bot); void init(); @@ -60,8 +67,11 @@ public: void refresh(); ChatData *chat() const; + ChannelData *channel() const; UserData *bot() const; - bool creatingChat() const; + CreatingGroupType creating() const; + + int32 selectedCount() const; ~ContactsInner(); @@ -70,6 +80,7 @@ signals: void mustScrollTo(int ymin, int ymax); void selectAllQuery(); void searchByUsername(); + void chosenChanged(); public slots: @@ -84,8 +95,9 @@ public slots: private: ChatData *_chat; + ChannelData *_channel; UserData *_bot; - bool _creatingChat; + CreatingGroupType _creating; ChatData *_addToChat; @@ -133,22 +145,29 @@ class ContactsBox : public ItemListBox, public RPCSender { public: - ContactsBox(bool creatingChat = false); + ContactsBox(); + ContactsBox(const QString &name, const QImage &photo); // group creation + ContactsBox(ChannelData *channel); // channel setup ContactsBox(ChatData *chat); ContactsBox(UserData *bot); void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); + void closePressed(); + + void setInnerFocus() { + _filter.setFocus(); + } + public slots: void onFilterUpdate(); void onScroll(); void onAdd(); - void onCreateChannel(); void onInvite(); - void onNext(); + void onCreate(); bool onSearchByUsername(bool searchCache = false); void onNeedSearchByUsername(); @@ -164,7 +183,7 @@ private: void init(); ContactsInner _inner; - FlatButton _addContact, _createChannel; + FlatButton _addContact; FlatInput _filter; FlatButton _next, _cancel; @@ -172,8 +191,6 @@ private: void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req); bool peopleFailed(const RPCError &error, mtpRequestId req); - bool _creatingChannel; - QTimer _searchTimer; QString _peopleQuery; bool _peopleFull; @@ -184,21 +201,29 @@ private: typedef QMap PeopleQueries; PeopleQueries _peopleQueries; + + // group creation + int32 _creationRequestId; + QString _creationName; + QImage _creationPhoto; + + void creationDone(const MTPUpdates &updates); + bool creationFail(const RPCError &e); }; -class CreateGroupBox : public AbstractBox, public RPCSender { +class NewGroupBox : public AbstractBox { Q_OBJECT public: - CreateGroupBox(const MTPVector &users, bool creatingChannel); + NewGroupBox(); void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); public slots: - void onCreate(); + void onNext(); protected: @@ -208,14 +233,130 @@ protected: private: - void created(const MTPUpdates &updates); - bool failed(const RPCError &e); + FlatRadiobutton _group, _channel; + int32 _aboutGroupWidth, _aboutGroupHeight; + Text _aboutGroup, _aboutChannel; + FlatButton _next, _cancel; - MTPVector _users; - bool _creatingChannel; +}; - int32 _createRequestId; +class GroupInfoBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + + GroupInfoBox(CreatingGroupType creating); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void leaveEvent(QEvent *e); + + bool eventFilter(QObject *obj, QEvent *e); + + bool descriptionAnimStep(float64 ms); + bool photoAnimStep(float64 ms); + + void setInnerFocus() { + _name.setFocus(); + } + +public slots: + + void onPhoto(); + void onPhotoReady(const QImage &img); + + void onNext(); + void onDescriptionResized(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + QRect descriptionRect() const; + QRect photoRect() const; + + void updateMaxHeight(); + void updateSelected(const QPoint &cursorGlobalPosition); + CreatingGroupType _creating; + + anim::fvalue a_photoOver; + Animation a_photo; + bool _photoOver, _descriptionOver; + + anim::cvalue a_descriptionBg, a_descriptionBorder; + Animation a_description; FlatInput _name; - FlatButton _create, _cancel; + FlatButton _photo; + FlatTextarea _description; + QImage _photoBig; + QPixmap _photoSmall; + FlatButton _next, _cancel; + + // channel creation + int32 _creationRequestId; + ChannelData *_createdChannel; + + void creationDone(const MTPUpdates &updates); + bool creationFail(const RPCError &e); + void exportDone(const MTPExportedChatInvite &result); +}; + +class SetupChannelBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + + SetupChannelBox(ChannelData *channel); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + void closePressed(); + + void setInnerFocus() { + _link.setFocus(); + } + +public slots: + + void onSave(); + void onChange(); + void onCheck(); + + void onPrivacyChange(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + ChannelData *_channel; + + FlatRadiobutton _public, _private; + int32 _aboutPublicWidth, _aboutPublicHeight; + Text _aboutPublic, _aboutPrivate; + QString _linkPlaceholder; + UsernameInput _link; + FlatButton _save, _skip; + + void onUpdateDone(const MTPBool &result); + bool onUpdateFail(const RPCError &error); + + void onCheckDone(const MTPBool &result); + bool onCheckFail(const RPCError &error); + + mtpRequestId _saveRequestId, _checkRequestId; + QString _sentUsername, _checkUsername, _errorText, _goodText; + + QTimer _checkTimer; }; diff --git a/Telegram/SourceFiles/boxes/photocropbox.cpp b/Telegram/SourceFiles/boxes/photocropbox.cpp index ea0db6d564..c3f15771b1 100644 --- a/Telegram/SourceFiles/boxes/photocropbox.cpp +++ b/Telegram/SourceFiles/boxes/photocropbox.cpp @@ -24,14 +24,22 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "photocropbox.h" #include "fileuploader.h" -PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer) : _downState(0), +PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer, bool upload) : _downState(0), _sendButton(this, lang(lng_settings_save), st::btnSelectDone), _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), _img(img), _peerId(peer) { + if (peerIsChannel(_peerId)) { + _title = lang(lng_create_channel_crop); + } else if (peerIsChat(_peerId)) { + _title = lang(lng_create_group_crop); + } else { + _title = lang(lng_settings_crop_profile); + } + connect(&_sendButton, SIGNAL(clicked()), this, SLOT(onSend())); connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); - if (_peerId) { + if (_peerId && upload) { connect(this, SIGNAL(ready(const QImage &)), this, SLOT(onReady(const QImage &))); } @@ -209,7 +217,7 @@ void PhotoCropBox::paintEvent(QPaintEvent *e) { // paint button sep p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); - paintGrayTitle(p, lang(lng_settings_crop_profile)); + paintGrayTitle(p, _title); p.translate(_thumbx, _thumby); p.drawPixmap(0, 0, _thumb); @@ -269,11 +277,11 @@ void PhotoCropBox::onSend() { } emit ready(tosend); + onClose(); } void PhotoCropBox::onReady(const QImage &tosend) { App::app()->uploadProfilePhoto(tosend, _peerId); - emit closed(); } void PhotoCropBox::hideAll() { diff --git a/Telegram/SourceFiles/boxes/photocropbox.h b/Telegram/SourceFiles/boxes/photocropbox.h index 4afda343ca..ce0c0f45de 100644 --- a/Telegram/SourceFiles/boxes/photocropbox.h +++ b/Telegram/SourceFiles/boxes/photocropbox.h @@ -24,7 +24,7 @@ class PhotoCropBox : public AbstractBox { public: - PhotoCropBox(const QImage &img, const PeerId &peer); + PhotoCropBox(const QImage &img, const PeerId &peer, bool upload = true); void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); @@ -50,6 +50,7 @@ protected: private: + QString _title; int32 _downState; int32 _thumbx, _thumby, _thumbw, _thumbh; int32 _cropx, _cropy, _cropw; diff --git a/Telegram/SourceFiles/boxes/usernamebox.cpp b/Telegram/SourceFiles/boxes/usernamebox.cpp index 60b49eb50d..3e7815b391 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.cpp +++ b/Telegram/SourceFiles/boxes/usernamebox.cpp @@ -23,34 +23,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "window.h" -UsernameInput::UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) { -} - -void UsernameInput::correctValue(QKeyEvent *e, const QString &was) { - QString oldText(text()), newText; - int32 newPos = cursorPosition(), from, len = oldText.size(); - for (from = 0; from < len; ++from) { - if (!oldText.at(from).isSpace()) { - break; - } - if (newPos > 0) --newPos; - } - len -= from; - if (len > MaxUsernameLength) len = MaxUsernameLength + (oldText.at(from) == '@' ? 1 : 0); - for (int32 to = from + len; to > from;) { - --to; - if (!oldText.at(to).isSpace()) { - break; - } - --len; - } - newText = oldText.mid(from, len); - if (newText != oldText) { - setText(newText); - setCursorPosition(newPos); - } -} - UsernameBox::UsernameBox() : _saveButton(this, lang(lng_settings_save), st::usernameDone), _cancelButton(this, lang(lng_cancel), st::usernameCancel), @@ -146,7 +118,7 @@ void UsernameBox::onCheck() { } QString name = getName(); if (name.size() >= MinUsernameLength) { - _checkUsername = getName(); + _checkUsername = name; _checkRequest = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), rpcFail(&UsernameBox::onCheckFail)); } } @@ -197,9 +169,9 @@ bool UsernameBox::onUpdateFail(const RPCError &error) { if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; _saveRequest = 0; - QString err(error.type()), name = getName(); + QString err(error.type()); if (err == "USERNAME_NOT_MODIFIED" || _sentUsername == App::self()->username) { - App::self()->setName(textOneLine(App::self()->firstName), textOneLine(App::self()->lastName), textOneLine(App::self()->nameOrPhone), textOneLine(name)); + App::self()->setName(textOneLine(App::self()->firstName), textOneLine(App::self()->lastName), textOneLine(App::self()->nameOrPhone), textOneLine(_sentUsername)); emit closed(); return true; } else if (err == "USERNAME_INVALID") { diff --git a/Telegram/SourceFiles/boxes/usernamebox.h b/Telegram/SourceFiles/boxes/usernamebox.h index 73ea1a88ea..481ca17d84 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.h +++ b/Telegram/SourceFiles/boxes/usernamebox.h @@ -19,17 +19,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "abstractbox.h" -class UsernameInput : public FlatInput { -public: - - UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString()); - -protected: - - void correctValue(QKeyEvent *e, const QString &was); - -}; - class UsernameBox : public AbstractBox, public RPCSender { Q_OBJECT diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index b4fd697eb5..0b2709988d 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -2203,7 +2203,7 @@ void DialogsWidget::onAddContact() { } void DialogsWidget::onNewGroup() { - App::wnd()->showLayer(new ContactsBox(true)); + App::wnd()->showLayer(new NewGroupBox()); } bool DialogsWidget::onCancelSearch() { diff --git a/Telegram/SourceFiles/gui/flatinput.cpp b/Telegram/SourceFiles/gui/flatinput.cpp index 1d6f6e03fe..357765fba4 100644 --- a/Telegram/SourceFiles/gui/flatinput.cpp +++ b/Telegram/SourceFiles/gui/flatinput.cpp @@ -74,6 +74,10 @@ void FlatInput::customUpDown(bool custom) { _customUpDown = custom; } +void FlatInput::setTextMargin(const QMargins &mrg) { + _st.textMrg = mrg; +} + void FlatInput::onTouchTimer() { _touchRightButton = true; } @@ -383,6 +387,34 @@ void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) { } } +UsernameInput::UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) { +} + +void UsernameInput::correctValue(QKeyEvent *e, const QString &was) { + QString oldText(text()), newText; + int32 newPos = cursorPosition(), from, len = oldText.size(); + for (from = 0; from < len; ++from) { + if (!oldText.at(from).isSpace()) { + break; + } + if (newPos > 0) --newPos; + } + len -= from; + if (len > MaxUsernameLength) len = MaxUsernameLength + (oldText.at(from) == '@' ? 1 : 0); + for (int32 to = from + len; to > from;) { + --to; + if (!oldText.at(to).isSpace()) { + break; + } + --len; + } + newText = oldText.mid(from, len); + if (newText != oldText) { + setText(newText); + setCursorPosition(newPos); + } +} + InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : TWidget(parent), _inner(this, val), _oldtext(val), diff --git a/Telegram/SourceFiles/gui/flatinput.h b/Telegram/SourceFiles/gui/flatinput.h index 56ea566f07..94438b2302 100644 --- a/Telegram/SourceFiles/gui/flatinput.h +++ b/Telegram/SourceFiles/gui/flatinput.h @@ -23,6 +23,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org class FlatInput : public QLineEdit, public Animated { Q_OBJECT + T_WIDGET public: @@ -56,6 +57,8 @@ public: return text(); } + void setTextMargin(const QMargins &mrg); + public slots: void onTextChange(const QString &text); @@ -131,6 +134,18 @@ private: }; + +class UsernameInput : public FlatInput { +public: + + UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString()); + +protected: + + void correctValue(QKeyEvent *e, const QString &was); + +}; + class InputField : public TWidget { Q_OBJECT diff --git a/Telegram/SourceFiles/gui/flattextarea.cpp b/Telegram/SourceFiles/gui/flattextarea.cpp index 0e3a6a72df..59f3951751 100644 --- a/Telegram/SourceFiles/gui/flattextarea.cpp +++ b/Telegram/SourceFiles/gui/flattextarea.cpp @@ -22,10 +22,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "window.h" FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(v, parent), - _ph(pholder), _oldtext(v), _phVisible(!v.length()), - a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c), - _st(st), _undoAvailable(false), _redoAvailable(false), _inDrop(false), _fakeMargin(0), - _touchPress(false), _touchRightButton(false), _touchMove(false), _replacingEmojis(false) { +_minHeight(-1), _maxHeight(-1), _ctrlEnterSubmit(true), +_ph(pholder), _oldtext(v), _phVisible(!v.length()), +a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c), +_st(st), _undoAvailable(false), _redoAvailable(false), _inDrop(false), _fakeMargin(0), +_touchPress(false), _touchRightButton(false), _touchMove(false), _replacingEmojis(false) { setAcceptRichText(false); resize(_st.width, _st.font->height); @@ -64,6 +65,31 @@ FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu())); } +void FlatTextarea::setMinHeight(int32 minHeight) { + _minHeight = minHeight; + heightAutoupdated(); +} + +void FlatTextarea::setMaxHeight(int32 maxHeight) { + _maxHeight = maxHeight; + heightAutoupdated(); +} + +bool FlatTextarea::heightAutoupdated() { + if (_minHeight < 0 || _maxHeight < 0) return false; + int newh = ceil(document()->size().height()) + 2 * fakeMargin(); + if (newh > _maxHeight) { + newh = _maxHeight; + } else if (newh < _minHeight) { + newh = _minHeight; + } + if (height() != newh) { + resize(width(), newh); + return true; + } + return false; +} + void FlatTextarea::onTouchTimer() { _touchRightButton = true; } @@ -555,6 +581,12 @@ QVariant FlatTextarea::loadResource(int type, const QUrl &name) { return QVariant(); } +void FlatTextarea::checkContentHeight() { + if (heightAutoupdated()) { + emit resized(); + } +} + void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) { int32 emojiPosition = 0, emojiLen = 0; const EmojiData *emoji = 0; @@ -693,6 +725,7 @@ void FlatTextarea::onDocumentContentsChanged() { if (_oldtext != curText) { _oldtext = curText; emit changed(); + checkContentHeight(); } updatePlaceholder(); if (App::wnd()) App::wnd()->updateGlobalMenu(); @@ -753,10 +786,14 @@ QMimeData *FlatTextarea::createMimeDataFromSelection() const { return result; } +void FlatTextarea::setCtrlEnterSubmit(bool ctrlEnterSubmit) { + _ctrlEnterSubmit = ctrlEnterSubmit; +} + void FlatTextarea::keyPressEvent(QKeyEvent *e) { bool shift = e->modifiers().testFlag(Qt::ShiftModifier); bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier); - bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && cCtrlEnter()) || (!ctrl && !shift && !cCtrlEnter()) || (ctrl && shift); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && _ctrlEnterSubmit) || (!ctrl && !shift && !_ctrlEnterSubmit) || (ctrl && shift); bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return); if (macmeta && e->key() == Qt::Key_Backspace) { diff --git a/Telegram/SourceFiles/gui/flattextarea.h b/Telegram/SourceFiles/gui/flattextarea.h index 408f3ed169..a57fcbb666 100644 --- a/Telegram/SourceFiles/gui/flattextarea.h +++ b/Telegram/SourceFiles/gui/flattextarea.h @@ -23,6 +23,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org class FlatTextarea : public QTextEdit, public Animated { Q_OBJECT + T_WIDGET public: @@ -38,6 +39,9 @@ public: void mousePressEvent(QMouseEvent *e); void dropEvent(QDropEvent *e); + void setMinHeight(int32 minHeight); + void setMaxHeight(int32 maxHeight); + const QString &getLastText() const; void updatePlaceholder(); @@ -64,6 +68,7 @@ public: void insertFromMimeData(const QMimeData *source); QMimeData *createMimeDataFromSelection() const; + void setCtrlEnterSubmit(bool ctrlEnterSubmit); public slots: @@ -79,6 +84,7 @@ public slots: signals: + void resized(); void changed(); void submitted(bool ctrlShiftEnter); void cancelled(); @@ -89,29 +95,19 @@ signals: protected: void insertEmoji(EmojiPtr emoji, QTextCursor c); - TWidget *tparent() { - return qobject_cast(parentWidget()); - } - const TWidget *tparent() const { - return qobject_cast(parentWidget()); - } - void enterEvent(QEvent *e) { - TWidget *p(tparent()); - if (p) p->leaveToChildEvent(e); - return QTextEdit::enterEvent(e); - } - void leaveEvent(QEvent *e) { - TWidget *p(tparent()); - if (p) p->enterFromChildEvent(e); - return QTextEdit::leaveEvent(e); - } QVariant loadResource(int type, const QUrl &name); + void checkContentHeight(); + private: void getSingleEmojiFragment(QString &text, QTextFragment &fragment) const; void processDocumentContentsChange(int position, int charsAdded); + bool heightAutoupdated(); + + int32 _minHeight, _maxHeight; // < 0 - no autosize + bool _ctrlEnterSubmit; QString _ph, _phelided, _oldtext; bool _phVisible; diff --git a/Telegram/SourceFiles/gui/twidget.h b/Telegram/SourceFiles/gui/twidget.h index b79f824e41..15b1890feb 100644 --- a/Telegram/SourceFiles/gui/twidget.h +++ b/Telegram/SourceFiles/gui/twidget.h @@ -26,6 +26,37 @@ public: explicit Painter(QPaintDevice *device) : QPainter(device) { } + void setFont(const style::font &font) { + QPainter::setFont(font->f); + } + void setFont(const QFont &font) { + QPainter::setFont(font); + } + void setBrush(const style::color &color) { + QPainter::setBrush(color->b); + } + void setBrush(const QColor &color) { + QPainter::setBrush(color); + } + void setBrush(const QBrush &brush) { + QPainter::setBrush(brush); + } + void setBrush(Qt::BrushStyle style) { + QPainter::setBrush(style); + } + void setPen(const style::color &color) { + QPainter::setPen(color->p); + } + void setPen(const QPen &pen) { + QPainter::setPen(pen); + } + void setPen(const QColor &color) { + QPainter::setPen(color); + } + void setPen(Qt::PenStyle style) { + QPainter::setPen(style); + } + void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) { QFontMetrics m(fontMetrics()); if (rtl() && textWidth < 0) textWidth = m.width(text); @@ -113,63 +144,62 @@ public: } }; +#define T_WIDGET public: \ +TWidget *tparent() { \ +return qobject_cast(parentWidget()); \ +} \ +const TWidget *tparent() const { \ + return qobject_cast(parentWidget()); \ +} \ +virtual void leaveToChildEvent(QEvent *e) { /* e -- from enterEvent() of child TWidget */ \ +} \ +virtual void enterFromChildEvent(QEvent *e) { /* e -- from leaveEvent() of child TWidget */ \ +} \ +void moveToLeft(int x, int y, int outerw) { \ + move(rtl() ? (outerw - x - width()) : x, y); \ +} \ +void moveToRight(int x, int y, int outerw) { \ + move(rtl() ? x : (outerw - x - width()), y); \ +} \ +QPoint myrtlpoint(int x, int y) const { \ + return rtlpoint(x, y, width()); \ +} \ +QPoint myrtlpoint(const QPoint p) const { \ + return rtlpoint(p, width()); \ +} \ +QRect myrtlrect(int x, int y, int w, int h) const { \ + return rtlrect(x, y, w, h, width()); \ +} \ +QRect myrtlrect(const QRect &r) { \ + return rtlrect(r, width()); \ +} \ +void rtlupdate(const QRect &r) { \ + update(myrtlrect(r)); \ +} \ +protected: \ +void enterEvent(QEvent *e) { \ + TWidget *p(tparent()); \ + if (p) p->leaveToChildEvent(e); \ + return QWidget::enterEvent(e); \ +} \ +void leaveEvent(QEvent *e) { \ + TWidget *p(tparent()); \ + if (p) p->enterFromChildEvent(e); \ + return QWidget::leaveEvent(e); \ +} + class TWidget : public QWidget { Q_OBJECT + T_WIDGET public: TWidget(QWidget *parent = 0) : QWidget(parent) { } - TWidget *tparent() { - return qobject_cast(parentWidget()); - } - const TWidget *tparent() const { - return qobject_cast(parentWidget()); - } - - virtual void leaveToChildEvent(QEvent *e) { // e -- from enterEvent() of child TWidget - } - virtual void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget - } - - void moveToLeft(int x, int y, int outerw) { - move(rtl() ? (outerw - x - width()) : x, y); - } - void moveToRight(int x, int y, int outerw) { - move(rtl() ? x : (outerw - x - width()), y); - } - QPoint myrtlpoint(int x, int y) const { - return rtlpoint(x, y, width()); - } - QPoint myrtlpoint(const QPoint p) const { - return rtlpoint(p, width()); - } - QRect myrtlrect(int x, int y, int w, int h) const { - return rtlrect(x, y, w, h, width()); - } - QRect myrtlrect(const QRect &r) { - return rtlrect(r, width()); - } - void rtlupdate(const QRect &r) { - update(myrtlrect(r)); - } bool event(QEvent *e) { return QWidget::event(e); } -protected: - - void enterEvent(QEvent *e) { - TWidget *p(tparent()); - if (p) p->leaveToChildEvent(e); - return QWidget::enterEvent(e); - } - void leaveEvent(QEvent *e) { - TWidget *p(tparent()); - if (p) p->enterFromChildEvent(e); - return QWidget::leaveEvent(e); - } - private: }; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 5598f50581..d8b937726a 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1461,7 +1461,7 @@ bool History::isReadyFor(MsgId msgId, bool check) const { void History::getReadyFor(MsgId msgId) { if (!isReadyFor(msgId, true)) { clear(true); - newLoaded = (msgId == ShowAtTheEndMsgId) || (lastMsg && !lastMsg->detached()); + newLoaded = (msgId == ShowAtTheEndMsgId); oldLoaded = false; lastWidth = 0; lastShowAtMsgId = msgId; @@ -6386,6 +6386,11 @@ void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) { text = lng_action_created_channel(lt_title, textClean(qs(d.vtitle))); } break; + case mtpc_messageActionChannelToggleComments: { + const MTPDmessageActionChannelToggleComments &d(action.c_messageActionChannelToggleComments()); + text = lang(d.venabled.v ? lng_action_comments_enabled : lng_action_comments_disabled); + } break; + case mtpc_messageActionChatDeletePhoto: { text = fromChannel() ? lang(lng_action_removed_photo_channel) : lng_action_removed_photo(lt_from, from); } break; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 161e2324d0..80481f5ab9 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -695,7 +695,7 @@ void HistoryList::dragActionFinish(const QPoint &screenPos, Qt::MouseButton butt uint32 sel = _selected.cbegin().value(); if (sel != FullItemSel && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { _selected.clear(); - App::wnd()->setInnerFocus(); + if (App::wnd()) App::wnd()->setInnerFocus(); } } } @@ -1577,21 +1577,9 @@ void HistoryList::onParentGeometryChanged() { } } -MessageField::MessageField(HistoryWidget *history, const style::flatTextarea &st, const QString &ph, const QString &val) : FlatTextarea(history, st, ph, val), history(history), _maxHeight(st::maxFieldHeight) { - connect(this, SIGNAL(changed()), this, SLOT(onChange())); -} - -void MessageField::setMaxHeight(int32 maxHeight) { - _maxHeight = maxHeight; - int newh = ceil(document()->size().height()) + 2 * fakeMargin(), minh = st::btnSend.height - 2 * st::sendPadding; - if (newh > _maxHeight) { - newh = _maxHeight; - } else if (newh < minh) { - newh = minh; - } - if (height() != newh) { - resize(width(), newh); - } +MessageField::MessageField(HistoryWidget *history, const style::flatTextarea &st, const QString &ph, const QString &val) : FlatTextarea(history, st, ph, val), history(history) { + setMinHeight(st::btnSend.height - 2 * st::sendPadding); + setMaxHeight(st::maxFieldHeight); } bool MessageField::hasSendText() const { @@ -1605,20 +1593,6 @@ bool MessageField::hasSendText() const { return false; } -void MessageField::onChange() { - int newh = ceil(document()->size().height()) + 2 * fakeMargin(), minh = st::btnSend.height - 2 * st::sendPadding; - if (newh > _maxHeight) { - newh = _maxHeight; - } else if (newh < minh) { - newh = minh; - } - - if (height() != newh) { - resize(width(), newh); - emit resized(); - } -} - void MessageField::onEmojiInsert(EmojiPtr emoji) { insertEmoji(emoji, textCursor()); } @@ -1632,7 +1606,7 @@ void MessageField::dropEvent(QDropEvent *e) { void MessageField::resizeEvent(QResizeEvent *e) { FlatTextarea::resizeEvent(e); - onChange(); + checkContentHeight(); } bool MessageField::canInsertFromMimeData(const QMimeData *source) const { @@ -2396,6 +2370,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent) _attachMention.hide(); connect(&_attachMention, SIGNAL(chosen(QString)), this, SLOT(onMentionHashtagOrBotCommandInsert(QString))); _field.installEventFilter(&_attachMention); + _field.setCtrlEnterSubmit(cCtrlEnter()); _field.hide(); _field.resize(width() - _send.width() - _attachDocument.width() - _attachEmoji.width(), _send.height() - 2 * st::sendPadding); @@ -2580,7 +2555,7 @@ void HistoryWidget::sendActionDone(const MTPBool &result, mtpRequestId req) { void HistoryWidget::activate() { if (_history) updateListSize(0, true); - setInnerFocus(); + if (App::wnd()) App::wnd()->setInnerFocus(); } void HistoryWidget::setInnerFocus() { @@ -2935,7 +2910,7 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) { if (_history->draftToId > 0 || !_history->draft.isEmpty()) { setFieldText(_history->draft); - setInnerFocus(); + _field.setFocus(); _history->draftCursor.applyTo(_field, &_synthedTextUpdate); _replyToId = readyToForward() ? 0 : _history->draftToId; if (_history->draftPreviewCancelled) { @@ -2944,7 +2919,7 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) { } else { Local::MessageDraft draft = Local::readDraft(_peer->id); setFieldText(draft.text); - setInnerFocus(); + _field.setFocus(); if (!draft.text.isEmpty()) { MessageCursor cur = Local::readDraftPositions(_peer->id); cur.applyTo(_field, &_synthedTextUpdate); @@ -2969,6 +2944,8 @@ void HistoryWidget::showPeerHistory(const PeerId &peerId, MsgId showAtMsgId) { doneShow(); } + if (App::wnd()) App::wnd()->setInnerFocus(); + emit peerShown(_peer); App::main()->topBar()->update(); update(); @@ -3000,6 +2977,10 @@ void HistoryWidget::updateAfterDrag() { if (_list) _list->dragActionUpdate(QCursor::pos()); } +void HistoryWidget::ctrlEnterSubmitUpdated() { + _field.setCtrlEnterSubmit(cCtrlEnter()); +} + void HistoryWidget::updateReportSpamStatus() { if (!_peer || (_peer->isUser() && (peerToUser(_peer->id) == MTP::authedId() || isNotificationsUser(_peer->id) || isServiceUser(_peer->id) || _peer->asUser()->botInfo))) { _reportSpamStatus = dbiprsNoButton; @@ -3447,7 +3428,7 @@ void HistoryWidget::loadMessagesDown() { MsgId max = _history->maxMsgId(); if (!max) return; - int32 loadCount = MessagesPerPage, offset = -loadCount - 1; + int32 loadCount = MessagesPerPage, offset = -loadCount; if (_peer->isChannel()) { _preloadDownRequest = MTP::send(MTPmessages_GetImportantHistory(_peer->input, MTP_int(max + 1), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, _peer), rpcFail(&HistoryWidget::messagesFailed)); } else { @@ -3745,8 +3726,10 @@ void HistoryWidget::doneShow() { updateControlsVisibility(); updateListSize(0, true); onListScroll(); - if (App::wnd()) App::wnd()->checkHistoryActivation(); - App::wnd()->setInnerFocus(); + if (App::wnd()) { + App::wnd()->checkHistoryActivation(); + App::wnd()->setInnerFocus(); + } } void HistoryWidget::animStop() { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 0f8739bf2d..0ccc2bb0de 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -190,7 +190,6 @@ public: void insertFromMimeData(const QMimeData *source); void focusInEvent(QFocusEvent *e); - void setMaxHeight(int32 maxHeight); bool hasSendText() const; @@ -206,17 +205,14 @@ public: public slots: - void onChange(); void onEmojiInsert(EmojiPtr emoji); signals: - void resized(); void focused(); private: HistoryWidget *history; - int32 _maxHeight; }; @@ -520,6 +516,9 @@ public: void updateToEndVisibility(); void updateAfterDrag(); + void ctrlEnterSubmitUpdated(); + + void setInnerFocus(); ~HistoryWidget(); @@ -585,7 +584,6 @@ public slots: void onPhotoFailed(quint64 id); void activate(); - void setInnerFocus(); void onMentionHashtagOrBotCommandInsert(QString str); void onTextChange(); diff --git a/Telegram/SourceFiles/intro/introsignup.cpp b/Telegram/SourceFiles/intro/introsignup.cpp index d299773623..cc4bcdde13 100644 --- a/Telegram/SourceFiles/intro/introsignup.cpp +++ b/Telegram/SourceFiles/intro/introsignup.cpp @@ -207,8 +207,8 @@ void IntroSignup::onCheckRequest() { void IntroSignup::onPhotoReady(const QImage &img) { _photoBig = img; - _photoSmall = QPixmap::fromImage(img.scaled(st::introPhotoSize, st::introPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); - App::wnd()->hideLayer(); + _photoSmall = QPixmap::fromImage(img.scaled(st::introPhotoSize * cIntRetinaFactor(), st::introPhotoSize * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly); + _photoSmall.setDevicePixelRatio(cRetinaFactor()); } void IntroSignup::nameSubmitDone(const MTPauth_Authorization &result) { diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 1e0b92f882..69795b3add 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "gui/filedialog.h" -BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : QWidget(parent), w(w), _hidden(0), +BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : QWidget(parent), w(w), aBackground(0), aBackgroundFunc(anim::easeOutCirc), hiding(false), shadow(st::boxShadow) { w->setParent(this); setGeometry(0, 0, App::wnd()->width(), App::wnd()->height()); @@ -72,13 +72,13 @@ void BackgroundWidget::onClose() { } bool BackgroundWidget::onInnerClose() { - if (!_hidden) { + if (_hidden.isEmpty()) { onClose(); return true; } w->deleteLater(); - w = _hidden; - _hidden = 0; + w = _hidden.back(); + _hidden.pop_back(); w->show(); resizeEvent(0); w->animStep(1); @@ -87,13 +87,24 @@ bool BackgroundWidget::onInnerClose() { } void BackgroundWidget::startHide() { - if (App::main()) App::main()->setInnerFocus(); + if (hiding) return; hiding = true; + if (App::wnd()) App::wnd()->setInnerFocus(); aBackground.start(0); anim::start(this); w->startHide(); } +bool BackgroundWidget::canSetFocus() const { + return w && !hiding; +} + +void BackgroundWidget::setInnerFocus() { + if (w) { + w->setInnerFocus(); + } +} + void BackgroundWidget::resizeEvent(QResizeEvent *e) { w->parentResized(); } @@ -103,9 +114,8 @@ void BackgroundWidget::updateWideMode() { } void BackgroundWidget::replaceInner(LayeredWidget *n) { - if (_hidden) _hidden->deleteLater(); - _hidden = w; - _hidden->hide(); + _hidden.push_back(w); + w->hide(); w = n; w->setParent(this); connect(w, SIGNAL(closed()), this, SLOT(onInnerClose())); @@ -139,13 +149,18 @@ void BackgroundWidget::boxDestroyed(QObject *obj) { if (obj == w) { if (App::wnd()) App::wnd()->layerFinishedHide(this); w = 0; - } else if (_hidden == obj) { - _hidden = 0; + } else { + int32 index = _hidden.indexOf(static_cast(obj)); + if (index >= 0) { + _hidden.removeAt(index); + } } } BackgroundWidget::~BackgroundWidget() { if (App::wnd()) App::wnd()->noBox(this); w->deleteLater(); - if (_hidden) _hidden->deleteLater(); + for (HiddenLayers::const_iterator i = _hidden.cbegin(), e = _hidden.cend(); i != e; ++i) { + (*i)->deleteLater(); + } } diff --git a/Telegram/SourceFiles/layerwidget.h b/Telegram/SourceFiles/layerwidget.h index e5b6267cb1..0d4b57a71a 100644 --- a/Telegram/SourceFiles/layerwidget.h +++ b/Telegram/SourceFiles/layerwidget.h @@ -30,6 +30,10 @@ public: virtual void startHide() { } + virtual void setInnerFocus() { + setFocus(); + } + virtual void resizeEvent(QResizeEvent *e) { emit resized(); } @@ -71,6 +75,9 @@ public: bool animStep(float64 ms); + bool canSetFocus() const; + void setInnerFocus(); + ~BackgroundWidget(); public slots: @@ -83,7 +90,9 @@ private: void startHide(); - LayeredWidget *w, *_hidden; + LayeredWidget *w; + typedef QList HiddenLayers; + HiddenLayers _hidden; anim::fvalue aBackground; anim::transition aBackgroundFunc; bool hiding; diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index e977faa8e6..d40303dcf4 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -958,6 +958,7 @@ namespace { if (!_checkStreamStatus(stream)) return false; cSetCtrlEnter(v == dbiskCtrlEnter); + if (App::main()) App::main()->ctrlEnterSubmitUpdated(); } break; case dbiCatsAndDogs: { // deprecated diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 119d77bd6e..e4644ba7c3 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -831,12 +831,14 @@ void MainWidget::removeContact(UserData *user) { dialogs.removeContact(user); } -void MainWidget::addParticipants(ChatData *chat, const QVector &users) { +void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector &users) { for (QVector::const_iterator i = users.cbegin(), e = users.cend(); i != e; ++i) { - MTP::send(MTPmessages_AddChatUser(chat->inputChat, (*i)->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantFail, *i), 0, 5); + if (chatOrChannel->isChat()) { + MTP::send(MTPmessages_AddChatUser(chatOrChannel->asChat()->inputChat, (*i)->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantFail, *i), 0, 5); + } else if (chatOrChannel->isChannel()) { + MTP::send(MTPmessages_AddChatUser(chatOrChannel->asChannel()->inputChat, (*i)->inputUser, MTP_int(0)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantFail, *i), 0, 5); + } } - App::wnd()->hideLayer(); - showPeerHistory(chat->id, ShowAtTheEndMsgId); } bool MainWidget::addParticipantFail(UserData *user, const RPCError &error) { @@ -971,7 +973,7 @@ void MainWidget::onResendAsDocument() { item->destroy(); } } - App::wnd()->layerHidden(); + App::wnd()->hideLayer(true); } void MainWidget::onCancelResend() { @@ -2087,7 +2089,7 @@ void MainWidget::setInnerFocus() { } else if (profile) { profile->setFocus(); } else { - history.activate(); + history.setInnerFocus(); } } @@ -2121,6 +2123,10 @@ void MainWidget::updateAfterDrag() { } } +void MainWidget::ctrlEnterSubmitUpdated() { + history.ctrlEnterSubmitUpdated(); +} + void MainWidget::showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) { if (!back && (!peerId || (_stack.size() == 1 && _stack[0]->type() == HistoryStackItem && _stack[0]->peer->id == peerId))) { back = true; @@ -2197,8 +2203,8 @@ void MainWidget::showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) if (history.isHidden()) history.show(); if (!animCache.isNull()) { history.animShow(animCache, animTopBarCache, back); - } else { - QTimer::singleShot(0, this, SLOT(setInnerFocus())); + } else if (App::wnd()) { + QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus())); } } } @@ -2381,7 +2387,7 @@ void MainWidget::showBackFromStack() { if (selectingPeer()) return; if (_stack.isEmpty()) { showDialogs(); - QTimer::singleShot(0, this, SLOT(setInnerFocus())); + if (App::wnd()) QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus())); return; } StackItem *item = _stack.back(); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 07f2e40b96..dc38cd7745 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -291,7 +291,7 @@ public: void clearHistory(PeerData *peer); void removeContact(UserData *user); - void addParticipants(ChatData *chat, const QVector &users); + void addParticipants(PeerData *chatOrChannel, const QVector &users); bool addParticipantFail(UserData *user, const RPCError &e); void kickParticipant(ChatData *chat, UserData *user); @@ -385,6 +385,9 @@ public: void feedUpdate(const MTPUpdate &update); void updateAfterDrag(); + void ctrlEnterSubmitUpdated(); + void setInnerFocus(); + ~MainWidget(); signals: @@ -414,7 +417,6 @@ public slots: void documentPlayProgress(const SongMsgId &songId); void hidePlayer(); - void setInnerFocus(); void dialogsCancelled(); void onParentResize(const QSize &newSize); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 9b2cf778a9..55bc782250 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -412,7 +412,9 @@ void MediaView::showSaveMsgFile() { } void MediaView::close() { - if (App::wnd()) App::wnd()->layerHidden(); + if (App::wnd()) { + App::wnd()->hideLayer(true); + } } void MediaView::activateControls() { diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp index e6aa6ec563..d2b49fffee 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp +++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp @@ -1671,6 +1671,19 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } break; + case mtpc_messageActionChannelToggleComments: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messageActionChannelToggleComments"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" enabled: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + case mtpc_dialog: if (stage) { to.add(",\n").addSpaces(lev); @@ -4728,6 +4741,69 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } break; + case mtpc_channelParticipantModerator: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ channelParticipantModerator"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" inviter_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + + case mtpc_channelParticipantPublisher: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ channelParticipantPublisher"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" inviter_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + + case mtpc_channelParticipantCreator: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ channelParticipantCreator"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" user_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + + case mtpc_channelParticipantsRecent: + to.add("{ channelParticipantsRecent }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); + break; + + case mtpc_channelParticipantsAdmins: + to.add("{ channelParticipantsAdmins }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); + break; + + case mtpc_channelRoleEmpty: + to.add("{ channelRoleEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); + break; + + case mtpc_channelRoleModerator: + to.add("{ channelRoleModerator }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); + break; + + case mtpc_channelRolePublisher: + to.add("{ channelRolePublisher }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); + break; + case mtpc_messages_channelParticipants: if (stage) { to.add(",\n").addSpaces(lev); @@ -5257,6 +5333,21 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } break; + case mtpc_messages_editChatAdmin: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_editChatAdmin"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" chat_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" role: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + case mtpc_messages_checkChannelUsername: if (stage) { to.add(",\n").addSpaces(lev); @@ -6211,6 +6302,20 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } break; + case mtpc_messages_toggleChannelComments: + if (stage) { + to.add(",\n").addSpaces(lev); + } else { + to.add("{ messages_toggleChannelComments"); + to.add("\n").addSpaces(lev); + } + switch (stage) { + case 0: to.add(" chat_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" enabled: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; + } + break; + case mtpc_messages_getChats: if (stage) { to.add(",\n").addSpaces(lev); @@ -6441,8 +6546,9 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP } switch (stage) { case 0: to.add(" chat_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 1: to.add(" offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; - case 2: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 1: to.add(" filter: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 2: to.add(" offset: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; + case 3: to.add(" limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break; default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break; } break; diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h index 92b0133b07..ac89fcebd6 100644 --- a/Telegram/SourceFiles/mtproto/mtpScheme.h +++ b/Telegram/SourceFiles/mtproto/mtpScheme.h @@ -167,6 +167,7 @@ enum { mtpc_messageActionChatDeleteUser = 0xb2ae9b0c, mtpc_messageActionChatJoinedByLink = 0xf89cf5e8, mtpc_messageActionChannelCreate = 0x95d2ac92, + mtpc_messageActionChannelToggleComments = 0xf2863903, mtpc_dialog = 0xc1dd804a, mtpc_dialogChannel = 0x5b8496b2, mtpc_photoEmpty = 0x2331b22d, @@ -412,6 +413,14 @@ enum { mtpc_channelMessagesFilterCollapsed = 0xfa01232e, mtpc_contacts_resolvedPeer = 0x7f077ad9, mtpc_channelParticipant = 0x506116ea, + mtpc_channelParticipantModerator = 0x91057fef, + mtpc_channelParticipantPublisher = 0x375d616, + mtpc_channelParticipantCreator = 0xe3e2e1f9, + mtpc_channelParticipantsRecent = 0xde3f3c79, + mtpc_channelParticipantsAdmins = 0xb4608969, + mtpc_channelRoleEmpty = 0xb285a0c6, + mtpc_channelRoleModerator = 0x9618d975, + mtpc_channelRolePublisher = 0x515b5530, mtpc_messages_channelParticipants = 0xd6891de1, mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsgs = 0x3dc4b4f0, @@ -519,12 +528,14 @@ enum { mtpc_messages_getImportantHistory = 0x24af43a5, mtpc_messages_readChannelHistory = 0x36a1210e, mtpc_messages_createChannel = 0x7f44d2c3, + mtpc_messages_toggleChannelComments = 0xb405b8af, mtpc_messages_deleteChannelMessages = 0x9995a84f, mtpc_messages_getChannelMessages = 0x5f46b265, mtpc_messages_incrementMessagesViews = 0x91ffd479, mtpc_messages_getMessagesViews = 0x9abfbbe1, mtpc_messages_editChatAbout = 0x8a969b93, - mtpc_messages_getChannelParticipants = 0x4a771976, + mtpc_messages_getChannelParticipants = 0x38a1db31, + mtpc_messages_editChatAdmin = 0x62394070, mtpc_messages_checkChannelUsername = 0xe6d2d8f4, mtpc_messages_updateChannelUsername = 0xce2e9587, mtpc_updates_getState = 0xedd4882a, @@ -744,6 +755,7 @@ class MTPDmessageActionChatAddUser; class MTPDmessageActionChatDeleteUser; class MTPDmessageActionChatJoinedByLink; class MTPDmessageActionChannelCreate; +class MTPDmessageActionChannelToggleComments; class MTPdialog; class MTPDdialog; @@ -1131,6 +1143,13 @@ class MTPDcontacts_resolvedPeer; class MTPchannelParticipant; class MTPDchannelParticipant; +class MTPDchannelParticipantModerator; +class MTPDchannelParticipantPublisher; +class MTPDchannelParticipantCreator; + +class MTPchannelParticipantsFilter; + +class MTPchannelParticipantRole; class MTPmessages_channelParticipants; class MTPDmessages_channelParticipants; @@ -1286,6 +1305,8 @@ typedef MTPBoxed MTPupdates_ChannelDifference; typedef MTPBoxed MTPChannelMessagesFilter; typedef MTPBoxed MTPcontacts_ResolvedPeer; typedef MTPBoxed MTPChannelParticipant; +typedef MTPBoxed MTPChannelParticipantsFilter; +typedef MTPBoxed MTPChannelParticipantRole; typedef MTPBoxed MTPmessages_ChannelParticipants; // Type classes definitions @@ -3702,6 +3723,18 @@ public: return *(const MTPDmessageActionChannelCreate*)data; } + MTPDmessageActionChannelToggleComments &_messageActionChannelToggleComments() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChannelToggleComments) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChannelToggleComments); + split(); + return *(MTPDmessageActionChannelToggleComments*)data; + } + const MTPDmessageActionChannelToggleComments &c_messageActionChannelToggleComments() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_messageActionChannelToggleComments) throw mtpErrorWrongTypeId(_type, mtpc_messageActionChannelToggleComments); + return *(const MTPDmessageActionChannelToggleComments*)data; + } + uint32 innerLength() const; mtpTypeId type() const; void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); @@ -3718,6 +3751,7 @@ private: explicit MTPmessageAction(MTPDmessageActionChatDeleteUser *_data); explicit MTPmessageAction(MTPDmessageActionChatJoinedByLink *_data); explicit MTPmessageAction(MTPDmessageActionChannelCreate *_data); + explicit MTPmessageAction(MTPDmessageActionChannelToggleComments *_data); friend MTPmessageAction MTP_messageActionEmpty(); friend MTPmessageAction MTP_messageActionChatCreate(const MTPstring &_title, const MTPVector &_users); @@ -3728,6 +3762,7 @@ private: friend MTPmessageAction MTP_messageActionChatDeleteUser(MTPint _user_id); friend MTPmessageAction MTP_messageActionChatJoinedByLink(MTPint _inviter_id); friend MTPmessageAction MTP_messageActionChannelCreate(const MTPstring &_title); + friend MTPmessageAction MTP_messageActionChannelToggleComments(MTPBool _enabled); mtpTypeId _type; }; @@ -8392,35 +8427,134 @@ typedef MTPBoxed MTPcontacts_ResolvedPeer; class MTPchannelParticipant : private mtpDataOwner { public: - MTPchannelParticipant(); - MTPchannelParticipant(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channelParticipant) : mtpDataOwner(0) { + MTPchannelParticipant() : mtpDataOwner(0), _type(0) { + } + MTPchannelParticipant(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) { read(from, end, cons); } MTPDchannelParticipant &_channelParticipant() { if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipant) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipant); split(); return *(MTPDchannelParticipant*)data; } const MTPDchannelParticipant &c_channelParticipant() const { if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipant) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipant); return *(const MTPDchannelParticipant*)data; } + MTPDchannelParticipantModerator &_channelParticipantModerator() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantModerator) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantModerator); + split(); + return *(MTPDchannelParticipantModerator*)data; + } + const MTPDchannelParticipantModerator &c_channelParticipantModerator() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantModerator) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantModerator); + return *(const MTPDchannelParticipantModerator*)data; + } + + MTPDchannelParticipantPublisher &_channelParticipantPublisher() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantPublisher) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantPublisher); + split(); + return *(MTPDchannelParticipantPublisher*)data; + } + const MTPDchannelParticipantPublisher &c_channelParticipantPublisher() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantPublisher) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantPublisher); + return *(const MTPDchannelParticipantPublisher*)data; + } + + MTPDchannelParticipantCreator &_channelParticipantCreator() { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantCreator) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantCreator); + split(); + return *(MTPDchannelParticipantCreator*)data; + } + const MTPDchannelParticipantCreator &c_channelParticipantCreator() const { + if (!data) throw mtpErrorUninitialized(); + if (_type != mtpc_channelParticipantCreator) throw mtpErrorWrongTypeId(_type, mtpc_channelParticipantCreator); + return *(const MTPDchannelParticipantCreator*)data; + } + uint32 innerLength() const; mtpTypeId type() const; - void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channelParticipant); + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); void write(mtpBuffer &to) const; typedef void ResponseType; private: + explicit MTPchannelParticipant(mtpTypeId type); explicit MTPchannelParticipant(MTPDchannelParticipant *_data); + explicit MTPchannelParticipant(MTPDchannelParticipantModerator *_data); + explicit MTPchannelParticipant(MTPDchannelParticipantPublisher *_data); + explicit MTPchannelParticipant(MTPDchannelParticipantCreator *_data); friend MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date); + friend MTPchannelParticipant MTP_channelParticipantModerator(MTPint _user_id, MTPint _inviter_id, MTPint _date); + friend MTPchannelParticipant MTP_channelParticipantPublisher(MTPint _user_id, MTPint _inviter_id, MTPint _date); + friend MTPchannelParticipant MTP_channelParticipantCreator(MTPint _user_id); + + mtpTypeId _type; }; typedef MTPBoxed MTPChannelParticipant; +class MTPchannelParticipantsFilter { +public: + MTPchannelParticipantsFilter() : _type(0) { + } + MTPchannelParticipantsFilter(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchannelParticipantsFilter(mtpTypeId type); + + friend MTPchannelParticipantsFilter MTP_channelParticipantsRecent(); + friend MTPchannelParticipantsFilter MTP_channelParticipantsAdmins(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPChannelParticipantsFilter; + +class MTPchannelParticipantRole { +public: + MTPchannelParticipantRole() : _type(0) { + } + MTPchannelParticipantRole(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : _type(0) { + read(from, end, cons); + } + + uint32 innerLength() const; + mtpTypeId type() const; + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons); + void write(mtpBuffer &to) const; + + typedef void ResponseType; + +private: + explicit MTPchannelParticipantRole(mtpTypeId type); + + friend MTPchannelParticipantRole MTP_channelRoleEmpty(); + friend MTPchannelParticipantRole MTP_channelRoleModerator(); + friend MTPchannelParticipantRole MTP_channelRolePublisher(); + + mtpTypeId _type; +}; +typedef MTPBoxed MTPChannelParticipantRole; + class MTPmessages_channelParticipants : private mtpDataOwner { public: MTPmessages_channelParticipants(); @@ -9705,6 +9839,16 @@ public: MTPstring vtitle; }; +class MTPDmessageActionChannelToggleComments : public mtpDataImpl { +public: + MTPDmessageActionChannelToggleComments() { + } + MTPDmessageActionChannelToggleComments(MTPBool _enabled) : venabled(_enabled) { + } + + MTPBool venabled; +}; + class MTPDdialog : public mtpDataImpl { public: MTPDdialog() { @@ -12065,6 +12209,40 @@ public: MTPint vdate; }; +class MTPDchannelParticipantModerator : public mtpDataImpl { +public: + MTPDchannelParticipantModerator() { + } + MTPDchannelParticipantModerator(MTPint _user_id, MTPint _inviter_id, MTPint _date) : vuser_id(_user_id), vinviter_id(_inviter_id), vdate(_date) { + } + + MTPint vuser_id; + MTPint vinviter_id; + MTPint vdate; +}; + +class MTPDchannelParticipantPublisher : public mtpDataImpl { +public: + MTPDchannelParticipantPublisher() { + } + MTPDchannelParticipantPublisher(MTPint _user_id, MTPint _inviter_id, MTPint _date) : vuser_id(_user_id), vinviter_id(_inviter_id), vdate(_date) { + } + + MTPint vuser_id; + MTPint vinviter_id; + MTPint vdate; +}; + +class MTPDchannelParticipantCreator : public mtpDataImpl { +public: + MTPDchannelParticipantCreator() { + } + MTPDchannelParticipantCreator(MTPint _user_id) : vuser_id(_user_id) { + } + + MTPint vuser_id; +}; + class MTPDmessages_channelParticipants : public mtpDataImpl { public: MTPDmessages_channelParticipants() { @@ -16889,6 +17067,48 @@ public: } }; +class MTPmessages_toggleChannelComments { // RPC method 'messages.toggleChannelComments' +public: + MTPInputChat vchat_id; + MTPBool venabled; + + MTPmessages_toggleChannelComments() { + } + MTPmessages_toggleChannelComments(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_toggleChannelComments) { + read(from, end, cons); + } + MTPmessages_toggleChannelComments(const MTPInputChat &_chat_id, MTPBool _enabled) : vchat_id(_chat_id), venabled(_enabled) { + } + + uint32 innerLength() const { + return vchat_id.innerLength() + venabled.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_toggleChannelComments; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_toggleChannelComments) { + vchat_id.read(from, end); + venabled.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + venabled.write(to); + } + + typedef MTPUpdates ResponseType; +}; +class MTPmessages_ToggleChannelComments : public MTPBoxed { +public: + MTPmessages_ToggleChannelComments() { + } + MTPmessages_ToggleChannelComments(const MTPmessages_toggleChannelComments &v) : MTPBoxed(v) { + } + MTPmessages_ToggleChannelComments(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_ToggleChannelComments(const MTPInputChat &_chat_id, MTPBool _enabled) : MTPBoxed(MTPmessages_toggleChannelComments(_chat_id, _enabled)) { + } +}; + class MTPmessages_deleteChannelMessages { // RPC method 'messages.deleteChannelMessages' public: MTPInputPeer vpeer; @@ -17102,6 +17322,7 @@ public: class MTPmessages_getChannelParticipants { // RPC method 'messages.getChannelParticipants' public: MTPInputChat vchat_id; + MTPChannelParticipantsFilter vfilter; MTPint voffset; MTPint vlimit; @@ -17110,22 +17331,24 @@ public: MTPmessages_getChannelParticipants(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getChannelParticipants) { read(from, end, cons); } - MTPmessages_getChannelParticipants(const MTPInputChat &_chat_id, MTPint _offset, MTPint _limit) : vchat_id(_chat_id), voffset(_offset), vlimit(_limit) { + MTPmessages_getChannelParticipants(const MTPInputChat &_chat_id, const MTPChannelParticipantsFilter &_filter, MTPint _offset, MTPint _limit) : vchat_id(_chat_id), vfilter(_filter), voffset(_offset), vlimit(_limit) { } uint32 innerLength() const { - return vchat_id.innerLength() + voffset.innerLength() + vlimit.innerLength(); + return vchat_id.innerLength() + vfilter.innerLength() + voffset.innerLength() + vlimit.innerLength(); } mtpTypeId type() const { return mtpc_messages_getChannelParticipants; } void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getChannelParticipants) { vchat_id.read(from, end); + vfilter.read(from, end); voffset.read(from, end); vlimit.read(from, end); } void write(mtpBuffer &to) const { vchat_id.write(to); + vfilter.write(to); voffset.write(to); vlimit.write(to); } @@ -17140,7 +17363,52 @@ public: } MTPmessages_GetChannelParticipants(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { } - MTPmessages_GetChannelParticipants(const MTPInputChat &_chat_id, MTPint _offset, MTPint _limit) : MTPBoxed(MTPmessages_getChannelParticipants(_chat_id, _offset, _limit)) { + MTPmessages_GetChannelParticipants(const MTPInputChat &_chat_id, const MTPChannelParticipantsFilter &_filter, MTPint _offset, MTPint _limit) : MTPBoxed(MTPmessages_getChannelParticipants(_chat_id, _filter, _offset, _limit)) { + } +}; + +class MTPmessages_editChatAdmin { // RPC method 'messages.editChatAdmin' +public: + MTPInputChat vchat_id; + MTPInputUser vuser_id; + MTPChannelParticipantRole vrole; + + MTPmessages_editChatAdmin() { + } + MTPmessages_editChatAdmin(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatAdmin) { + read(from, end, cons); + } + MTPmessages_editChatAdmin(const MTPInputChat &_chat_id, const MTPInputUser &_user_id, const MTPChannelParticipantRole &_role) : vchat_id(_chat_id), vuser_id(_user_id), vrole(_role) { + } + + uint32 innerLength() const { + return vchat_id.innerLength() + vuser_id.innerLength() + vrole.innerLength(); + } + mtpTypeId type() const { + return mtpc_messages_editChatAdmin; + } + void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_editChatAdmin) { + vchat_id.read(from, end); + vuser_id.read(from, end); + vrole.read(from, end); + } + void write(mtpBuffer &to) const { + vchat_id.write(to); + vuser_id.write(to); + vrole.write(to); + } + + typedef MTPBool ResponseType; +}; +class MTPmessages_EditChatAdmin : public MTPBoxed { +public: + MTPmessages_EditChatAdmin() { + } + MTPmessages_EditChatAdmin(const MTPmessages_editChatAdmin &v) : MTPBoxed(v) { + } + MTPmessages_EditChatAdmin(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed(from, end, cons) { + } + MTPmessages_EditChatAdmin(const MTPInputChat &_chat_id, const MTPInputUser &_user_id, const MTPChannelParticipantRole &_role) : MTPBoxed(MTPmessages_editChatAdmin(_chat_id, _user_id, _role)) { } }; @@ -21118,6 +21386,10 @@ inline uint32 MTPmessageAction::innerLength() const { const MTPDmessageActionChannelCreate &v(c_messageActionChannelCreate()); return v.vtitle.innerLength(); } + case mtpc_messageActionChannelToggleComments: { + const MTPDmessageActionChannelToggleComments &v(c_messageActionChannelToggleComments()); + return v.venabled.innerLength(); + } } return 0; } @@ -21166,6 +21438,11 @@ inline void MTPmessageAction::read(const mtpPrime *&from, const mtpPrime *end, m MTPDmessageActionChannelCreate &v(_messageActionChannelCreate()); v.vtitle.read(from, end); } break; + case mtpc_messageActionChannelToggleComments: _type = cons; { + if (!data) setData(new MTPDmessageActionChannelToggleComments()); + MTPDmessageActionChannelToggleComments &v(_messageActionChannelToggleComments()); + v.venabled.read(from, end); + } break; default: throw mtpErrorUnexpected(cons, "MTPmessageAction"); } } @@ -21200,6 +21477,10 @@ inline void MTPmessageAction::write(mtpBuffer &to) const { const MTPDmessageActionChannelCreate &v(c_messageActionChannelCreate()); v.vtitle.write(to); } break; + case mtpc_messageActionChannelToggleComments: { + const MTPDmessageActionChannelToggleComments &v(c_messageActionChannelToggleComments()); + v.venabled.write(to); + } break; } } inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : mtpDataOwner(0), _type(type) { @@ -21213,6 +21494,7 @@ inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : mtpDataOwner(0), _ty case mtpc_messageActionChatDeleteUser: setData(new MTPDmessageActionChatDeleteUser()); break; case mtpc_messageActionChatJoinedByLink: setData(new MTPDmessageActionChatJoinedByLink()); break; case mtpc_messageActionChannelCreate: setData(new MTPDmessageActionChannelCreate()); break; + case mtpc_messageActionChannelToggleComments: setData(new MTPDmessageActionChannelToggleComments()); break; default: throw mtpErrorBadTypeId(type, "MTPmessageAction"); } } @@ -21230,6 +21512,8 @@ inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChatJoinedByLink *_da } inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChannelCreate *_data) : mtpDataOwner(_data), _type(mtpc_messageActionChannelCreate) { } +inline MTPmessageAction::MTPmessageAction(MTPDmessageActionChannelToggleComments *_data) : mtpDataOwner(_data), _type(mtpc_messageActionChannelToggleComments) { +} inline MTPmessageAction MTP_messageActionEmpty() { return MTPmessageAction(mtpc_messageActionEmpty); } @@ -21257,6 +21541,9 @@ inline MTPmessageAction MTP_messageActionChatJoinedByLink(MTPint _inviter_id) { inline MTPmessageAction MTP_messageActionChannelCreate(const MTPstring &_title) { return MTPmessageAction(new MTPDmessageActionChannelCreate(_title)); } +inline MTPmessageAction MTP_messageActionChannelToggleComments(MTPBool _enabled) { + return MTPmessageAction(new MTPDmessageActionChannelToggleComments(_enabled)); +} inline uint32 MTPdialog::innerLength() const { switch (_type) { @@ -27515,36 +27802,187 @@ inline MTPcontacts_resolvedPeer MTP_contacts_resolvedPeer(const MTPPeer &_peer, return MTPcontacts_resolvedPeer(new MTPDcontacts_resolvedPeer(_peer, _chats, _users)); } -inline MTPchannelParticipant::MTPchannelParticipant() : mtpDataOwner(new MTPDchannelParticipant()) { -} - inline uint32 MTPchannelParticipant::innerLength() const { - const MTPDchannelParticipant &v(c_channelParticipant()); - return v.vuser_id.innerLength() + v.vinviter_id.innerLength() + v.vdate.innerLength(); + switch (_type) { + case mtpc_channelParticipant: { + const MTPDchannelParticipant &v(c_channelParticipant()); + return v.vuser_id.innerLength() + v.vinviter_id.innerLength() + v.vdate.innerLength(); + } + case mtpc_channelParticipantModerator: { + const MTPDchannelParticipantModerator &v(c_channelParticipantModerator()); + return v.vuser_id.innerLength() + v.vinviter_id.innerLength() + v.vdate.innerLength(); + } + case mtpc_channelParticipantPublisher: { + const MTPDchannelParticipantPublisher &v(c_channelParticipantPublisher()); + return v.vuser_id.innerLength() + v.vinviter_id.innerLength() + v.vdate.innerLength(); + } + case mtpc_channelParticipantCreator: { + const MTPDchannelParticipantCreator &v(c_channelParticipantCreator()); + return v.vuser_id.innerLength(); + } + } + return 0; } inline mtpTypeId MTPchannelParticipant::type() const { - return mtpc_channelParticipant; + if (!_type) throw mtpErrorUninitialized(); + return _type; } inline void MTPchannelParticipant::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { - if (cons != mtpc_channelParticipant) throw mtpErrorUnexpected(cons, "MTPchannelParticipant"); - - if (!data) setData(new MTPDchannelParticipant()); - MTPDchannelParticipant &v(_channelParticipant()); - v.vuser_id.read(from, end); - v.vinviter_id.read(from, end); - v.vdate.read(from, end); + if (cons != _type) setData(0); + switch (cons) { + case mtpc_channelParticipant: _type = cons; { + if (!data) setData(new MTPDchannelParticipant()); + MTPDchannelParticipant &v(_channelParticipant()); + v.vuser_id.read(from, end); + v.vinviter_id.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_channelParticipantModerator: _type = cons; { + if (!data) setData(new MTPDchannelParticipantModerator()); + MTPDchannelParticipantModerator &v(_channelParticipantModerator()); + v.vuser_id.read(from, end); + v.vinviter_id.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_channelParticipantPublisher: _type = cons; { + if (!data) setData(new MTPDchannelParticipantPublisher()); + MTPDchannelParticipantPublisher &v(_channelParticipantPublisher()); + v.vuser_id.read(from, end); + v.vinviter_id.read(from, end); + v.vdate.read(from, end); + } break; + case mtpc_channelParticipantCreator: _type = cons; { + if (!data) setData(new MTPDchannelParticipantCreator()); + MTPDchannelParticipantCreator &v(_channelParticipantCreator()); + v.vuser_id.read(from, end); + } break; + default: throw mtpErrorUnexpected(cons, "MTPchannelParticipant"); + } } inline void MTPchannelParticipant::write(mtpBuffer &to) const { - const MTPDchannelParticipant &v(c_channelParticipant()); - v.vuser_id.write(to); - v.vinviter_id.write(to); - v.vdate.write(to); + switch (_type) { + case mtpc_channelParticipant: { + const MTPDchannelParticipant &v(c_channelParticipant()); + v.vuser_id.write(to); + v.vinviter_id.write(to); + v.vdate.write(to); + } break; + case mtpc_channelParticipantModerator: { + const MTPDchannelParticipantModerator &v(c_channelParticipantModerator()); + v.vuser_id.write(to); + v.vinviter_id.write(to); + v.vdate.write(to); + } break; + case mtpc_channelParticipantPublisher: { + const MTPDchannelParticipantPublisher &v(c_channelParticipantPublisher()); + v.vuser_id.write(to); + v.vinviter_id.write(to); + v.vdate.write(to); + } break; + case mtpc_channelParticipantCreator: { + const MTPDchannelParticipantCreator &v(c_channelParticipantCreator()); + v.vuser_id.write(to); + } break; + } } -inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipant *_data) : mtpDataOwner(_data) { +inline MTPchannelParticipant::MTPchannelParticipant(mtpTypeId type) : mtpDataOwner(0), _type(type) { + switch (type) { + case mtpc_channelParticipant: setData(new MTPDchannelParticipant()); break; + case mtpc_channelParticipantModerator: setData(new MTPDchannelParticipantModerator()); break; + case mtpc_channelParticipantPublisher: setData(new MTPDchannelParticipantPublisher()); break; + case mtpc_channelParticipantCreator: setData(new MTPDchannelParticipantCreator()); break; + default: throw mtpErrorBadTypeId(type, "MTPchannelParticipant"); + } +} +inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipant *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipant) { +} +inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantModerator *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantModerator) { +} +inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantPublisher *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantPublisher) { +} +inline MTPchannelParticipant::MTPchannelParticipant(MTPDchannelParticipantCreator *_data) : mtpDataOwner(_data), _type(mtpc_channelParticipantCreator) { } inline MTPchannelParticipant MTP_channelParticipant(MTPint _user_id, MTPint _inviter_id, MTPint _date) { return MTPchannelParticipant(new MTPDchannelParticipant(_user_id, _inviter_id, _date)); } +inline MTPchannelParticipant MTP_channelParticipantModerator(MTPint _user_id, MTPint _inviter_id, MTPint _date) { + return MTPchannelParticipant(new MTPDchannelParticipantModerator(_user_id, _inviter_id, _date)); +} +inline MTPchannelParticipant MTP_channelParticipantPublisher(MTPint _user_id, MTPint _inviter_id, MTPint _date) { + return MTPchannelParticipant(new MTPDchannelParticipantPublisher(_user_id, _inviter_id, _date)); +} +inline MTPchannelParticipant MTP_channelParticipantCreator(MTPint _user_id) { + return MTPchannelParticipant(new MTPDchannelParticipantCreator(_user_id)); +} + +inline uint32 MTPchannelParticipantsFilter::innerLength() const { + return 0; +} +inline mtpTypeId MTPchannelParticipantsFilter::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPchannelParticipantsFilter::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_channelParticipantsRecent: _type = cons; break; + case mtpc_channelParticipantsAdmins: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPchannelParticipantsFilter"); + } +} +inline void MTPchannelParticipantsFilter::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPchannelParticipantsFilter::MTPchannelParticipantsFilter(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_channelParticipantsRecent: break; + case mtpc_channelParticipantsAdmins: break; + default: throw mtpErrorBadTypeId(type, "MTPchannelParticipantsFilter"); + } +} +inline MTPchannelParticipantsFilter MTP_channelParticipantsRecent() { + return MTPchannelParticipantsFilter(mtpc_channelParticipantsRecent); +} +inline MTPchannelParticipantsFilter MTP_channelParticipantsAdmins() { + return MTPchannelParticipantsFilter(mtpc_channelParticipantsAdmins); +} + +inline uint32 MTPchannelParticipantRole::innerLength() const { + return 0; +} +inline mtpTypeId MTPchannelParticipantRole::type() const { + if (!_type) throw mtpErrorUninitialized(); + return _type; +} +inline void MTPchannelParticipantRole::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) { + switch (cons) { + case mtpc_channelRoleEmpty: _type = cons; break; + case mtpc_channelRoleModerator: _type = cons; break; + case mtpc_channelRolePublisher: _type = cons; break; + default: throw mtpErrorUnexpected(cons, "MTPchannelParticipantRole"); + } +} +inline void MTPchannelParticipantRole::write(mtpBuffer &to) const { + switch (_type) { + } +} +inline MTPchannelParticipantRole::MTPchannelParticipantRole(mtpTypeId type) : _type(type) { + switch (type) { + case mtpc_channelRoleEmpty: break; + case mtpc_channelRoleModerator: break; + case mtpc_channelRolePublisher: break; + default: throw mtpErrorBadTypeId(type, "MTPchannelParticipantRole"); + } +} +inline MTPchannelParticipantRole MTP_channelRoleEmpty() { + return MTPchannelParticipantRole(mtpc_channelRoleEmpty); +} +inline MTPchannelParticipantRole MTP_channelRoleModerator() { + return MTPchannelParticipantRole(mtpc_channelRoleModerator); +} +inline MTPchannelParticipantRole MTP_channelRolePublisher() { + return MTPchannelParticipantRole(mtpc_channelRolePublisher); +} inline MTPmessages_channelParticipants::MTPmessages_channelParticipants() : mtpDataOwner(new MTPDmessages_channelParticipants()) { } diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl index ff463de041..9236eb9c80 100644 --- a/Telegram/SourceFiles/mtproto/scheme.tl +++ b/Telegram/SourceFiles/mtproto/scheme.tl @@ -257,6 +257,7 @@ messageActionChatAddUser#5e3cfc4b user_id:int = MessageAction; messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction; messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction; messageActionChannelCreate#95d2ac92 title:string = MessageAction; +messageActionChannelToggleComments#f2863903 enabled:Bool = MessageAction; dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog; dialogChannel#5b8496b2 peer:Peer top_message:int top_important_message:int read_inbox_max_id:int unread_count:int unread_important_count:int notify_settings:PeerNotifySettings pts:int = Dialog; @@ -602,6 +603,16 @@ channelMessagesFilterCollapsed#fa01232e = ChannelMessagesFilter; contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; channelParticipant#506116ea user_id:int inviter_id:int date:int = ChannelParticipant; +channelParticipantModerator#91057fef user_id:int inviter_id:int date:int = ChannelParticipant; +channelParticipantPublisher#375d616 user_id:int inviter_id:int date:int = ChannelParticipant; +channelParticipantCreator#e3e2e1f9 user_id:int = ChannelParticipant; + +channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; +channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; + +channelRoleEmpty#b285a0c6 = ChannelParticipantRole; +channelRoleModerator#9618d975 = ChannelParticipantRole; +channelRolePublisher#515b5530 = ChannelParticipantRole; messages.channelParticipants#d6891de1 count:int participants:Vector users:Vector = messages.ChannelParticipants; @@ -718,12 +729,14 @@ messages.getChannelDialogs#92689583 offset:int limit:int = messages.Dialogs; messages.getImportantHistory#24af43a5 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; messages.readChannelHistory#36a1210e peer:InputPeer max_id:int = Bool; messages.createChannel#7f44d2c3 flags:# title:string about:string users:Vector = Updates; +messages.toggleChannelComments#b405b8af chat_id:InputChat enabled:Bool = Updates; messages.deleteChannelMessages#9995a84f peer:InputPeer id:Vector = messages.AffectedMessages; messages.getChannelMessages#5f46b265 peer:InputPeer id:Vector = messages.Messages; messages.incrementMessagesViews#91ffd479 peer:InputPeer id:Vector = Bool; messages.getMessagesViews#9abfbbe1 peer:InputPeer id:Vector = Vector; messages.editChatAbout#8a969b93 chat_id:InputChat about:string = Bool; -messages.getChannelParticipants#4a771976 chat_id:InputChat offset:int limit:int = messages.ChannelParticipants; +messages.getChannelParticipants#38a1db31 chat_id:InputChat filter:ChannelParticipantsFilter offset:int limit:int = messages.ChannelParticipants; +messages.editChatAdmin#62394070 chat_id:InputChat user_id:InputUser role:ChannelParticipantRole = Bool; messages.checkChannelUsername#e6d2d8f4 chat_id:InputChat username:string = Bool; messages.updateChannelUsername#ce2e9587 chat_id:InputChat username:string = Bool; diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index dbb2f19e2c..0c4bbd6294 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -139,7 +139,7 @@ bool PasscodeWidget::animStep(float64 ms) { _animCache = _bgAnimCache = QPixmap(); showAll(); - setInnerFocus(); + if (App::wnd()) App::wnd()->setInnerFocus(); } else { a_bgCoord.update(dt1, st::introHideFunc); a_bgAlpha.update(dt1, st::introAlphaHideFunc); diff --git a/Telegram/SourceFiles/pspecific_linux.cpp b/Telegram/SourceFiles/pspecific_linux.cpp index 2859c9067f..cf0ff373c5 100644 --- a/Telegram/SourceFiles/pspecific_linux.cpp +++ b/Telegram/SourceFiles/pspecific_linux.cpp @@ -1142,7 +1142,7 @@ void psOpenFile(const QString &name, bool openWith) { } void psShowInFolder(const QString &name) { - App::wnd()->layerHidden(); + App::wnd()->hideLayer(true); system((qsl("xdg-open ") + escapeShell(QFileInfo(name).absoluteDir().absolutePath())).toUtf8().constData()); } diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index 6863af5eaf..dedd5c33ff 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -65,7 +65,7 @@ void MacPrivate::notifyClicked(unsigned long long peer, int msgid) { App::wnd()->showFromTray(); if (App::passcoded()) { - App::wnd()->passcodeWidget()->setInnerFocus(); + App::wnd()->setInnerFocus(); App::wnd()->notifyClear(); } else { App::wnd()->hideSettings(); diff --git a/Telegram/SourceFiles/pspecific_wnd.cpp b/Telegram/SourceFiles/pspecific_wnd.cpp index a4039296d4..51feeda62c 100644 --- a/Telegram/SourceFiles/pspecific_wnd.cpp +++ b/Telegram/SourceFiles/pspecific_wnd.cpp @@ -2592,7 +2592,7 @@ public: App::wnd()->showFromTray(); if (App::passcoded()) { - App::wnd()->passcodeWidget()->setInnerFocus(); + App::wnd()->setInnerFocus(); App::wnd()->notifyClear(); } else { App::wnd()->hideSettings(); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index 41a1ed9a6f..e96490a3ae 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -1523,6 +1523,7 @@ void SettingsInner::onViewEmojis() { void SettingsInner::onEnterSend() { if (_enterSend.checked()) { cSetCtrlEnter(false); + if (App::main()) App::main()->ctrlEnterSubmitUpdated(); Local::writeUserSettings(); } } @@ -1530,6 +1531,7 @@ void SettingsInner::onEnterSend() { void SettingsInner::onCtrlEnterSend() { if (_ctrlEnterSend.checked()) { cSetCtrlEnter(true); + if (App::main()) App::main()->ctrlEnterSubmitUpdated(); Local::writeUserSettings(); } } diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index 4a4841b90c..c8a315278a 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -96,7 +96,19 @@ PeerData::PeerData(const PeerId &id) : id(id), lnk(new PeerLink(this)) } void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername) { - if (name == newName && (!isUser() || (asUser()->nameOrPhone == newNameOrPhone && asUser()->username == newUsername)) && nameVersion > 0) return; + if (name == newName && nameVersion > 0) { + if (isUser()) { + if (asUser()->nameOrPhone == newNameOrPhone && asUser()->username == newUsername) { + return; + } + } else if (isChannel()) { + if (asChannel()->username == newUsername) { + return; + } + } else if (isChat()) { + return; + } + } ++nameVersion; name = newName; diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 5c90d402f0..bfa319ccd6 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -286,7 +286,7 @@ void NotifyWindow::mousePressEvent(QMouseEvent *e) { } else if (history) { App::wnd()->showFromTray(); if (App::passcoded()) { - App::wnd()->passcodeWidget()->setInnerFocus(); + App::wnd()->setInnerFocus(); App::wnd()->notifyClear(); } else { App::wnd()->hideSettings(); @@ -461,7 +461,7 @@ QWidget *Window::filedialogParent() { } void Window::clearWidgets() { - layerHidden(); + hideLayer(true); if (_passcode) { _passcode->hide(); _passcode->deleteLater(); @@ -528,7 +528,7 @@ void Window::setupPasscode(bool anim) { if (anim) { _passcode->animShow(bg); } else { - _passcode->setInnerFocus(); + setInnerFocus(); } _shouldLockAt = 0; notifyUpdateAll(); @@ -746,34 +746,42 @@ void Window::showPhoto(const PhotoLink *lnk, HistoryItem *item) { } void Window::showPhoto(PhotoData *photo, HistoryItem *item) { - layerHidden(); + hideLayer(true); _mediaView->showPhoto(photo, item); _mediaView->activateWindow(); _mediaView->setFocus(); } void Window::showPhoto(PhotoData *photo, PeerData *peer) { - layerHidden(); + hideLayer(true); _mediaView->showPhoto(photo, peer); _mediaView->activateWindow(); _mediaView->setFocus(); } void Window::showDocument(DocumentData *doc, HistoryItem *item) { - layerHidden(); + hideLayer(true); _mediaView->showDocument(doc, item); _mediaView->activateWindow(); _mediaView->setFocus(); } void Window::showLayer(LayeredWidget *w, bool fast) { - layerHidden(); + hideLayer(true); layerBG = new BackgroundWidget(this, w); if (fast) { layerBG->showFast(); } } +void Window::replaceLayer(LayeredWidget *w) { + if (layerBG) { + layerBG->replaceInner(w); + } else { + layerBG = new BackgroundWidget(this, w); + } +} + void Window::showConnecting(const QString &text, const QString &reconnect) { if (_connecting) { _connecting->set(text, reconnect); @@ -798,19 +806,12 @@ void Window::hideConnecting() { if (settings) settings->update(); } -void Window::replaceLayer(LayeredWidget *w) { - if (layerBG) { - layerBG->replaceInner(w); - } else { - layerBG = new BackgroundWidget(this, w); - } -} - void Window::hideLayer(bool fast) { if (layerBG) { layerBG->onClose(); if (fast) { layerBG->hide(); + layerBG->deleteLater(); layerBG = 0; } } @@ -854,7 +855,9 @@ void Window::hideMediaview() { } void Window::setInnerFocus() { - if (_passcode) { + if (layerBG && layerBG->canSetFocus()) { + layerBG->setInnerFocus(); + } else if (_passcode) { _passcode->setInnerFocus(); } else if (settings) { settings->setInnerFocus();