channels members and admins management done

This commit is contained in:
John Preston 2015-09-23 20:43:08 +03:00
parent d54f299327
commit 9154edc217
31 changed files with 1362 additions and 226 deletions

View file

@ -28,19 +28,21 @@ if exist ..\Win32\Deploy\deploy\%AppVersionStrMajor%\%AppVersionStr%\ goto error
if exist ..\Win32\Deploy\deploy\%AppVersionStrMajor%\%AppVersionStr%.dev\ goto error_exist2
if exist ..\Win32\Deploy\tupdate%AppVersion% goto error_exist3
copy ./SourceFiles/telegram.qrc /B+ ,,/Y
cd SourceFiles\
copy telegram.qrc /B+,,/Y
cd ..\
if %errorlevel% neq 0 goto error
cd ..\
MSBuild Telegram.sln /property:Configuration=Deploy
if %errorlevel% neq 0 goto error
if %errorlevel% neq 0 goto error0
echo .
echo Version %AppVersionStr%%DevPostfix% build successfull! Preparing..
echo .
set "PATH=%PATH%;C:\Program Files\7-Zip;C:\Program Files (x86)\Inno Setup 5"
cd ..\Win32\Deploy
cd Win32\Deploy\
call ..\..\..\TelegramPrivate\Sign.bat Telegram.exe
if %errorlevel% neq 0 goto error1
@ -71,7 +73,7 @@ move tsetup.%AppVersionStr%%DevPostfix%.exe deploy\%AppVersionStrMajor%\%AppVers
move tupdate%AppVersion% deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
if %errorlevel% neq 0 goto error1
cd deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%
cd deploy\%AppVersionStrMajor%\%AppVersionStr%%DevPostfix%\
7z a -mx9 tportable.%AppVersionStr%%DevPostfix%.zip Telegram\
if %errorlevel% neq 0 goto error2
@ -97,13 +99,15 @@ xcopy Updater.pdb Z:\TBuild\tother\tsetup\%AppVersionStrMajor%\%AppVersionStr%%D
echo Version %AppVersionStr%%DevPostfix% deployed successfully!
cd ..\..\..\..\..\Telegram
cd ..\..\..\..\..\Telegram\
goto eof
:error2
cd ..\..\..
cd ..\..\..\
:error1
cd ..\..\Telegram
cd ..\..\
:error0
cd Telegram\
goto error
:error_exist1

View file

@ -95,6 +95,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_channel_status" = "channel";
"lng_channel_members_link" = "{count:_not_used_|# member|# members} »";
"lng_channel_admins_link" = "{count:_not_used_|# administrator|# administrators} »";
"lng_server_error" = "Internal server error.";
"lng_flood_error" = "Too many tries. Please try again later.";
"lng_deleted" = "Unknown";
@ -354,12 +357,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_chat_unaccessible" = "Group is unaccessible";
"lng_topbar_info" = "Info";
"lng_profile_about_section" = "About";
"lng_profile_description_section" = "Description";
"lng_profile_settings_section" = "Settings";
"lng_profile_actions_section" = "Actions";
"lng_profile_bot_settings" = "Settings";
"lng_profile_bot_help" = "Help";
"lng_profile_create_public_link" = "Create public link";
"lng_profile_edit_public_link" = "Edit link";
"lng_profile_edit_public_link" = "Edit public link";
"lng_profile_participants_section" = "Members";
"lng_profile_info" = "Contact info";
"lng_profile_group_info" = "Group info";
@ -384,8 +388,10 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_set_group_photo" = "Set Photo";
"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?";
"lng_profile_kick" = "Remove";
"lng_profile_sure_kick" = "Remove {user} from the group?";
"lng_profile_sure_kick_channel" = "Remove {user} from the channel?";
"lng_profile_sure_kick_admin" = "Remove {user} from administrators?";
"lng_profile_loading" = "Loading..";
"lng_profile_shared_media" = "Shared media";
"lng_profile_no_media" = "No media in this conversation.";
@ -402,13 +408,20 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_profile_audio_files_header" = "Playlist";
"lng_profile_copy_phone" = "Copy phone number";
"lng_channel_add_admins" = "Add";
"lng_channel_members" = "Members";
"lng_channel_admins" = "Administrators";
"lng_channel_add_admin" = "Add Administrator";
"lng_channel_admin_sure" = "Add {user} to administrators?";
"lng_participant_filter" = "Search";
"lng_participant_invite" = "Invite";
"lng_participant_invite_sorry" = "Sorry, you can only add the first\n{count} members to a channel personally.\n\nFrom now on, people will need\nto join via your invite link.";
"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_group_about" = "Groups have up to {count} 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";
@ -476,7 +489,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_group_invite_want_join_channel" = "Do you want to join channel «{title}»?";
"lng_group_invite_join" = "Join";
"lng_group_invite_link" = "Invite link";
"lng_group_invite_link" = "Invite link:";
"lng_group_invite_create" = "Create an invite link";
"lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link.";
"lng_channel_invite_about" = "Telegram users will be able to join\nyour channel by following this link.";
@ -731,6 +744,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_menu_insert_unicode" = "Insert Unicode control character";
"lng_full_name" = "{first_name} {last_name}";
// Wnd specific
"lng_wnd_choose_program_menu" = "Choose Default Program...";

View file

@ -1293,7 +1293,7 @@ profileNameFont: font(20px);
profileStatusLeft: 22px;
profileStatusTop: 31px;
profileStatusFont: font(fsize);
profilePhoneLeft: 20px;
profilePhoneLeft: 22px;
profilePhoneTop: 62px;
profilePhoneFont: font(16px);
profileButtonTop: 18px;
@ -1332,6 +1332,8 @@ btnShareContact: flatButton(btnDefNext, btnDefBig) {
}
profileMinBtnPadding: 10px;
membersPadding: margins(0px, 10px, 0px, 10px);
forwardWidth: 364px;
forwardMargins: margins(30px, 10px, 30px, 10px);
forwardFont: font(16px);
@ -1462,6 +1464,7 @@ newGroupPhoto: flatButton(btnDefNext, btnDefBig) {
newGroupPhotoSize: 96px;
newGroupPhotoSkip: 18px;
newGroupDescriptionSkip: 28px;
newGroupPublicLinkSkip: 27px;
newGroupDescription: flatTextarea(taDefFlat) {
font: font(15px);
bgColor: transparent;
@ -1832,7 +1835,7 @@ stickerPanSize: size(64px, 64px);
stickerPanPadding: 11px;
stickerPanDelete: sprite(128px, 132px, 12px, 12px);
stickerPanDeleteOpacity: 0.5;
stickerIconPadding: 3px;
stickerIconPadding: 5px;
stickerIconOpacity: 0.7;
stickerIconSel: 2px;
stickerIconSelColor: #58b2ed;
@ -1841,6 +1844,12 @@ stickerIconLeft: sprite(342px, 72px, 40px, 1px);
stickerIconRight: sprite(342px, 73px, 40px, 1px);
stickerIconMove: 400;
verifiedCheckProfile: sprite(285px, 240px, 22px, 22px);
verifiedCheckProfilePos: point(9px, 4px);
verifiedCheck: sprite(285px, 221px, 19px, 19px);
verifiedCheckInv: sprite(304px, 221px, 19px, 19px);
verifiedCheckPos: point(5px, 0px);
botKbDuration: 200;
botKbBg: #f7f7f7;
botKbOverBg: #e8ecef;

View file

@ -252,7 +252,7 @@ bool update() {
if (copyResult == FALSE) {
writeLog(L"Error: failed to copy, asking to retry..");
WCHAR errMsg[2048];
wsprintf(errMsg, L"Failed to update Telegram :(\n%s is not accessible.", tofname);
wsprintf(errMsg, L"Failed to update Telegram :(\n%s is not accessible.", tofname.c_str());
if (MessageBox(0, errMsg, L"Update error!", MB_ICONERROR | MB_RETRYCANCEL) != IDRETRY) {
delFolder();
return false;

View file

@ -276,10 +276,11 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result) {
}
channel->about = qs(f.vabout);
channel->count = f.has_participants_count() ? f.vparticipants_count.v : 0;
channel->adminsCount = f.has_admins_count() ? f.vadmins_count.v : 0;
channel->invitationUrl = (f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString();
if (History *h = App::historyLoaded(channel->id)) {
if (h->inboxReadBefore < f.vread_inbox_max_id.v + 1) {
h->unreadCount = f.vunread_important_count.v;
h->setUnreadCount(f.vunread_important_count.v);
h->inboxReadBefore = f.vread_inbox_max_id.v + 1;
h->asChannelHistory()->unreadCountAll = f.vunread_count.v;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 233 KiB

View file

@ -2291,11 +2291,11 @@ public:
trySet(_performer, dict, "artist");
trySet(_performer, dict, "performer");
trySet(_performer, dict, "album_artist");
for (AVDictionaryEntry *tag = av_dict_get(dict, "", 0, AV_DICT_IGNORE_SUFFIX); tag; tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX)) {
const char *key = tag->key;
const char *value = tag->value;
QString tmp = QString::fromUtf8(value);
}
//for (AVDictionaryEntry *tag = av_dict_get(dict, "", 0, AV_DICT_IGNORE_SUFFIX); tag; tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX)) {
// const char *key = tag->key;
// const char *value = tag->value;
// QString tmp = QString::fromUtf8(value);
//}
}
int64 duration() {

View file

@ -20,6 +20,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "application.h"
#include "addcontactbox.h"
#include "contactsbox.h"
#include "mainwidget.h"
#include "window.h"
@ -31,6 +32,7 @@ AddContactBox::AddContactBox(QString fname, QString lname, QString phone) :
_firstInput(this, st::inpAddContact, lang(lng_signup_firstname), fname),
_lastInput(this, st::inpAddContact, lang(lng_signup_lastname), lname),
_phoneInput(this, st::inpAddContact, lang(lng_contact_phone), phone.isEmpty() ? phone : App::formatPhone(phone)),
_invertOrder(langFirstNameGoesSecond()),
_contactId(0), _addRequest(0) {
if (!phone.isEmpty()) {
@ -48,12 +50,16 @@ AddContactBox::AddContactBox(PeerData *peer) :
_firstInput(this, st::inpAddContact, lang(peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), peer->isUser() ? peer->asUser()->firstName : peer->name),
_lastInput(this, st::inpAddContact, lang(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()),
_phoneInput(this, st::inpAddContact, lang(lng_contact_phone)),
_invertOrder((!peer || !peer->isChat()) && langFirstNameGoesSecond()),
_contactId(0), _addRequest(0) {
initBox();
}
void AddContactBox::initBox() {
if (_invertOrder) {
setTabOrder(&_lastInput, &_firstInput);
}
if (_peer) {
if (_peer->isUser()) {
_boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title);
@ -61,10 +67,6 @@ void AddContactBox::initBox() {
} else if (_peer->isChat()) {
_boxTitle = lang(lng_edit_group_title);
setMaxHeight(st::boxTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height());
} else if (_peer->isChannel()) {
// CHANNELS_UX
_boxTitle = lang(lng_edit_channel_title);
setMaxHeight(st::boxTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height());
}
} else {
bool readyToAdd = !_phoneInput.text().isEmpty() && (!_firstInput.text().isEmpty() || !_lastInput.text().isEmpty());
@ -107,7 +109,7 @@ void AddContactBox::showAll() {
void AddContactBox::showDone() {
if ((_firstInput.text().isEmpty() && _lastInput.text().isEmpty()) || _phoneInput.isHidden() || !_phoneInput.isEnabled()) {
_firstInput.setFocus();
(_invertOrder ? _lastInput : _firstInput).setFocus();
} else {
_phoneInput.setFocus();
}
@ -180,9 +182,15 @@ void AddContactBox::paintEvent(QPaintEvent *e) {
}
void AddContactBox::resizeEvent(QResizeEvent *e) {
_firstInput.setGeometry(st::addContactPadding.left(), st::boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height());
_lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _firstInput.width(), _firstInput.height());
_phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height());
if (_invertOrder) {
_lastInput.setGeometry(st::addContactPadding.left(), st::boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _lastInput.height());
_firstInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height());
_phoneInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height());
} else {
_firstInput.setGeometry(st::addContactPadding.left(), st::boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height());
_lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _firstInput.width(), _firstInput.height());
_phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height());
}
_cancelButton.move(0, height() - _cancelButton.height());
_addButton.move(width() - _addButton.width(), height() - _addButton.height());
@ -194,8 +202,13 @@ void AddContactBox::onSend() {
QString firstName = _firstInput.text().trimmed(), lastName = _lastInput.text().trimmed(), phone = _phoneInput.text().trimmed();
if (firstName.isEmpty() && lastName.isEmpty()) {
_firstInput.setFocus();
_firstInput.notaBene();
if (_invertOrder) {
_lastInput.setFocus();
_lastInput.notaBene();
} else {
_firstInput.setFocus();
_firstInput.notaBene();
}
return;
} else if (!_peer && !App::isValidPhone(phone)) {
_phoneInput.setFocus();
@ -212,8 +225,6 @@ void AddContactBox::onSend() {
} else if (_peer) {
if (_peer->isChat()) {
_addRequest = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(firstName)), rpcDone(&AddContactBox::onSaveChatDone), rpcFail(&AddContactBox::onSaveFail));
} else if (_peer->isChannel()) {
_addRequest = MTP::send(MTPchannels_EditTitle(_peer->asChannel()->inputChannel, MTP_string(firstName)), rpcDone(&AddContactBox::onSaveChatDone), rpcFail(&AddContactBox::onSaveFail));
} else {
_contactId = MTP::nonce<uint64>();
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_peer->asUser()->phone), MTP_string(firstName), MTP_string(lastName)));
@ -345,11 +356,14 @@ a_descriptionBg(st::newGroupName.bgColor->c, st::newGroupName.bgColor->c),
a_descriptionBorder(st::newGroupName.borderColor->c, st::newGroupName.borderColor->c),
a_description(animFunc(this, &EditChannelBox::descriptionAnimStep)),
_description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about),
_publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link)),
_saveTitleRequestId(0), _saveDescriptionRequestId(0) {
_boxTitle = lang(lng_edit_channel_title);
_description.installEventFilter(this);
connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*)));
setMouseTracking(true);
_description.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::newGroupDescriptionPadding.left() - st::newGroupDescriptionPadding.right(), _title.height() - st::newGroupDescriptionPadding.top() - st::newGroupDescriptionPadding.bottom());
@ -365,6 +379,8 @@ _saveTitleRequestId(0), _saveDescriptionRequestId(0) {
connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave()));
connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose()));
connect(&_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink()));
prepare();
}
@ -373,6 +389,7 @@ void EditChannelBox::hideAll() {
_description.hide();
_saveButton.hide();
_cancelButton.hide();
_publicLink.hide();
}
void EditChannelBox::showAll() {
@ -380,6 +397,7 @@ void EditChannelBox::showAll() {
_description.show();
_saveButton.show();
_cancelButton.show();
_publicLink.show();
}
void EditChannelBox::showDone() {
@ -439,6 +457,12 @@ bool EditChannelBox::descriptionAnimStep(float64 ms) {
return res;
}
void EditChannelBox::peerUpdated(PeerData *peer) {
if (peer == _channel) {
_publicLink.setText(lang(_channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link));
}
}
void EditChannelBox::onDescriptionResized() {
updateMaxHeight();
update();
@ -449,8 +473,10 @@ QRect EditChannelBox::descriptionRect() const {
}
void EditChannelBox::updateMaxHeight() {
int32 h = st::boxTitleHeight + st::newGroupPadding.top() + _title.height() + st::newGroupPadding.bottom() + _saveButton.height();
int32 h = st::boxTitleHeight + st::newGroupPadding.top() + _title.height();
h += st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom();
h += st::newGroupPublicLinkSkip + _publicLink.height();
h += st::newGroupPadding.bottom() + _saveButton.height();
setMaxHeight(h);
}
@ -475,8 +501,9 @@ void EditChannelBox::resizeEvent(QResizeEvent *e) {
_description.moveToLeft(st::newGroupPadding.left() + st::newGroupDescriptionPadding.left(), _title.y() + _title.height() + st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top(), width());
int32 buttonTop = _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom();
buttonTop += st::newGroupPadding.bottom();
_publicLink.moveToLeft(st::newGroupPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkSkip, width());
int32 buttonTop = _publicLink.y() + _publicLink.height() + st::newGroupPadding.bottom();
_cancelButton.move(0, buttonTop);
_saveButton.move(width() - _saveButton.width(), buttonTop);
}
@ -521,6 +548,10 @@ void EditChannelBox::onSave() {
_saveTitleRequestId = MTP::send(MTPchannels_EditTitle(_channel->inputChannel, MTP_string(_sentTitle)), rpcDone(&EditChannelBox::onSaveTitleDone), rpcFail(&EditChannelBox::onSaveFail));
}
void EditChannelBox::onPublicLink() {
App::wnd()->replaceLayer(new SetupChannelBox(_channel, true));
}
void EditChannelBox::saveDescription() {
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
}

View file

@ -64,6 +64,8 @@ private:
FlatButton _addButton, _retryButton, _cancelButton;
FlatInput _firstInput, _lastInput, _phoneInput;
bool _invertOrder;
uint64 _contactId;
mtpRequestId _addRequest;
@ -95,8 +97,11 @@ public:
public slots:
void peerUpdated(PeerData *peer);
void onSave();
void onDescriptionResized();
void onPublicLink();
protected:
@ -127,6 +132,8 @@ private:
Animation a_description;
FlatTextarea _description;
LinkButton _publicLink;
mtpRequestId _saveTitleRequestId, _saveDescriptionRequestId;
QString _sentTitle, _sentDescription;
};

View file

@ -22,6 +22,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "mainwidget.h"
#include "window.h"
#include "application.h"
TextParseOptions _confirmBoxTextOptions = {
TextParseLinks | TextParseMultiline | TextParseRichText, // flags
0, // maxw
@ -195,3 +197,97 @@ void ConfirmLinkBox::onOpenLink() {
}
App::wnd()->hideLayer();
}
MaxInviteBox::MaxInviteBox(const QString &link) :
_close(this, lang(lng_close), st::btnInfoClose),
_text(st::boxFont, lng_participant_invite_sorry(lt_count, QString::number(cMaxGroupCount())), _confirmBoxTextOptions),
_link(link), _linkOver(false),
a_goodOpacity(0, 0), a_good(animFunc(this, &MaxInviteBox::goodAnimStep)) {
setMouseTracking(true);
_textWidth = st::boxWidth + 10 - st::boxPadding.left() - st::boxPadding.right();
_textHeight = qMin(_text.countHeight(_textWidth), 16 * st::boxFont->height);
setMaxHeight(st::boxPadding.top() + _textHeight + st::newGroupLinkPadding.top() + st::newGroupLink.height + st::newGroupLinkPadding.bottom() + _close.height());
connect(&_close, SIGNAL(clicked()), this, SLOT(onClose()));
prepare();
}
void MaxInviteBox::mouseMoveEvent(QMouseEvent *e) {
updateSelected(e->globalPos());
}
void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
mouseMoveEvent(e);
if (_linkOver) {
App::app()->clipboard()->setText(_link);
_goodTextLink = lang(lng_create_channel_link_copied);
a_goodOpacity = anim::fvalue(1, 0);
a_good.start();
}
}
void MaxInviteBox::leaveEvent(QEvent *e) {
updateSelected(QCursor::pos());
}
void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
QPoint p(mapFromGlobal(cursorGlobalPosition));
bool linkOver = _invitationLink.contains(p);
if (linkOver != _linkOver) {
_linkOver = linkOver;
update();
setCursor(_linkOver ? style::cur_pointer : style::cur_default);
}
}
bool MaxInviteBox::goodAnimStep(float64 ms) {
float dt = ms / st::newGroupLinkFadeDuration;
bool res = true;
if (dt >= 1) {
res = false;
a_goodOpacity.finish();
} else {
a_goodOpacity.update(dt, anim::linear);
}
update();
return res;
}
void MaxInviteBox::hideAll() {
_close.hide();
}
void MaxInviteBox::showAll() {
_close.show();
}
void MaxInviteBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
// draw box title / text
p.setFont(st::boxFont->f);
p.setPen(st::black->p);
_text.drawElided(p, st::boxPadding.left(), st::boxPadding.top(), _textWidth, 16, (_text.maxWidth() < width()) ? style::al_center : style::al_left);
QTextOption option(style::al_left);
option.setWrapMode(QTextOption::WrapAnywhere);
p.setFont(_linkOver ? st::newGroupLink.font->underline() : st::newGroupLink.font);
p.setPen(st::btnDefLink.color);
p.drawText(_invitationLink, _link, option);
if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) {
p.setOpacity(a_goodOpacity.current());
p.setPen(st::setGoodColor->p);
p.setFont(st::setErrFont->f);
p.drawText(QRect(st::newGroupPadding.left(), st::boxPadding.top() + _textHeight + st::newGroupLinkTop + st::newGroupLinkFont->height - st::setErrFont->ascent, width() - st::newGroupPadding.left() - st::newGroupPadding.right(), st::setErrFont->height), _goodTextLink, style::al_top);
p.setOpacity(1);
}
}
void MaxInviteBox::resizeEvent(QResizeEvent *e) {
_close.move(0, height() - _close.height());
_invitationLink = QRect(st::newGroupPadding.left(), st::boxPadding.top() + _textHeight + st::newGroupLinkPadding.top() + (st::newGroupLink.height / 2) - st::newGroupLinkFont->height, width() - st::newGroupPadding.left() - st::newGroupPadding.right(), 2 * st::newGroupLinkFont->height);
}

View file

@ -19,7 +19,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "abstractbox.h"
class ConfirmBox : public AbstractBox, public RPCSender {
class ConfirmBox : public AbstractBox {
Q_OBJECT
public:
@ -84,3 +84,41 @@ private:
QString _url;
};
class MaxInviteBox : public AbstractBox {
Q_OBJECT
public:
MaxInviteBox(const QString &link);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void leaveEvent(QEvent *e);
void updateLink();
protected:
void hideAll();
void showAll();
private:
void updateSelected(const QPoint &cursorGlobalPosition);
bool goodAnimStep(float64 ms);
BottomButton _close;
Text _text;
int32 _textWidth, _textHeight;
QString _link;
QRect _invitationLink;
bool _linkOver;
QPoint _lastMousePos;
QString _goodTextLink;
anim::fvalue a_goodOpacity;
Animation a_good;
};

View file

@ -30,7 +30,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "confirmbox.h"
ContactsInner::ContactsInner(CreatingGroupType creating) : _chat(0), _channel(0), _bot(0), _creating(creating), _addToChat(0),
ContactsInner::ContactsInner(CreatingGroupType creating) :
_chat(0), _channel(0), _channelFilter(MembersFilterRecent), _bot(0), _creating(creating),
_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0),
_contacts(&App::main()->contactsList()),
_sel(0),
_filteredSel(-1),
@ -42,7 +44,9 @@ _addContactLnk(this, lang(lng_add_contact_button)) {
init();
}
ContactsInner::ContactsInner(ChannelData *channel) : _chat(0), _channel(channel), _bot(0), _creating(CreatingGroupChannel), _addToChat(0),
ContactsInner::ContactsInner(ChannelData *channel, MembersFilter channelFilter, const MembersAlreadyIn &already) :
_chat(0), _channel(channel), _channelFilter(channelFilter), _bot(0), _creating(CreatingGroupChannel), _already(already),
_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0),
_contacts(&App::main()->contactsList()),
_sel(0),
_filteredSel(-1),
@ -54,7 +58,9 @@ _addContactLnk(this, lang(lng_add_contact_button)) {
init();
}
ContactsInner::ContactsInner(ChatData *chat) : _chat(chat), _channel(0), _bot(0), _creating(CreatingGroupNone), _addToChat(0),
ContactsInner::ContactsInner(ChatData *chat) :
_chat(chat), _channel(0), _channelFilter(MembersFilterRecent), _bot(0), _creating(CreatingGroupNone),
_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0),
_contacts(&App::main()->contactsList()),
_sel(0),
_filteredSel(-1),
@ -66,7 +72,9 @@ _addContactLnk(this, lang(lng_add_contact_button)) {
init();
}
ContactsInner::ContactsInner(UserData *bot) : _chat(0), _channel(0), _bot(bot), _creating(CreatingGroupNone), _addToChat(0),
ContactsInner::ContactsInner(UserData *bot) :
_chat(0), _channel(0), _channelFilter(MembersFilterRecent), _bot(bot), _creating(CreatingGroupNone),
_addToChat(0), _addAdmin(0), _addAdminRequestId(0), _addAdminBox(0),
_contacts(new DialogsIndexed(DialogsSortByAdd)),
_sel(0),
_filteredSel(-1),
@ -117,6 +125,36 @@ void ContactsInner::onAddBot() {
App::main()->showPeerHistory(_addToChat->id, ShowAtUnreadMsgId);
}
void ContactsInner::onAddAdmin() {
if (_addAdminRequestId) return;
_addAdminRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _addAdmin->inputUser, MTP_channelRoleEditor()), rpcDone(&ContactsInner::addAdminDone), rpcFail(&ContactsInner::addAdminFail));
}
void ContactsInner::onNoAddAdminBox(QObject *obj) {
if (obj == _addAdminBox) {
_addAdminBox = 0;
}
}
void ContactsInner::addAdminDone(const MTPBool &result, mtpRequestId req) {
if (req != _addAdminRequestId) return;
_addAdminRequestId = 0;
if (_addAdminBox) _addAdminBox->onClose();
emit adminAdded();
}
bool ContactsInner::addAdminFail(const RPCError &error, mtpRequestId req) {
if (mtpIsFlood(error)) return false;
if (req != _addAdminRequestId) return true;
_addAdminRequestId = 0;
if (_addAdminBox) _addAdminBox->onClose();
emit adminAdded();
return true;
}
void ContactsInner::peerUpdated(PeerData *peer) {
if (_chat && (!peer || peer == _chat)) {
if (_chat->isForbidden || _chat->haveLeft) {
@ -197,8 +235,10 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
if (peer->isUser()) {
if (_chat) {
data->inchat = _chat->participants.contains(peer->asUser());
} else if (_creating == CreatingGroupGroup || _channel) {
} else if (_creating == CreatingGroupGroup) {
data->inchat = (peerToUser(peer->id) == MTP::authedId());
} else if (_channel) {
data->inchat = (peerToUser(peer->id) == MTP::authedId()) || _already.contains(peer->asUser());
} else {
data->inchat = false;
}
@ -227,7 +267,7 @@ ContactsInner::ContactData *ContactsInner::contactData(DialogRow *row) {
return data;
}
void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data, bool sel) {
void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel) {
int32 left = st::profileListPadding.width();
UserData *user = peer->asUser();
@ -248,9 +288,18 @@ void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data,
p.setPen(st::profileListNameColor->p);
}
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);
int32 namew = width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - iconw;
if (peer->isChannel() && peer->asChannel()->isVerified()) {
namew -= st::verifiedCheck.pxWidth() + st::verifiedCheckPos.x();
p.drawSprite(QPoint(left + st::profileListPhotoSize + st::participantDelta + qMin(data->name.maxWidth(), namew), st::profileListNameTop) + st::verifiedCheckPos, st::verifiedCheck);
}
data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, namew);
if (_chat || _creating !=CreatingGroupNone) {
if (_channel && _channelFilter == MembersFilterAdmins) {
if (sel) {
p.drawPixmap(QPoint(width() - st::contactsImg.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg);
}
} else 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));
}
@ -287,7 +336,7 @@ void ContactsInner::paintDialog(QPainter &p, PeerData *peer, ContactData *data,
void ContactsInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
QPainter p(this);
Painter p(this);
_time = unixtime();
p.fillRect(r, st::white->b);
@ -422,7 +471,8 @@ void ContactsInner::mousePressEvent(QMouseEvent *e) {
}
void ContactsInner::chooseParticipant() {
if (_chat || _creating != CreatingGroupNone) {
bool addingAdmin = (_channel && _channelFilter == MembersFilterAdmins);
if (!addingAdmin && (_chat || _creating != CreatingGroupNone)) {
_time = unixtime();
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
if (_filter.isEmpty()) {
@ -481,7 +531,18 @@ void ContactsInner::chooseParticipant() {
}
}
if (peer) {
if (bot() && peer->isChat()) {
if (addingAdmin) {
_addAdmin = peer->asUser();
if (_addAdminRequestId) {
MTP::cancel(_addAdminRequestId);
_addAdminRequestId = 0;
}
if (_addAdminBox) _addAdminBox->deleteLater();
_addAdminBox = new ConfirmBox(lng_channel_admin_sure(lt_user, _addAdmin->firstName));
connect(_addAdminBox, SIGNAL(confirmed()), this, SLOT(onAddAdmin()));
connect(_addAdminBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoAddAdminBox(QObject*)));
App::wnd()->replaceLayer(_addAdminBox);
} else if (bot() && peer->isChat()) {
_addToChat = peer->asChat();
ConfirmBox *box = new ConfirmBox(lng_bot_sure_invite(lt_group, peer->name));
connect(box, SIGNAL(confirmed()), this, SLOT(onAddBot()));
@ -519,7 +580,7 @@ int32 ContactsInner::selectedCount() const {
if (_chat) {
result += (_chat->count > 0) ? _chat->count : 1;
} else if (_channel) {
result += (_channel->count > 0) ? _channel->count : 1;
result += _already.size();
} else if (_creating == CreatingGroupGroup) {
result += 1;
}
@ -785,6 +846,10 @@ ChannelData *ContactsInner::channel() const {
return _channel;
}
MembersFilter ContactsInner::channelFilter() const {
return _channelFilter;
}
UserData *ContactsInner::bot() const {
return _bot;
}
@ -1017,6 +1082,15 @@ _creationRequestId(0) {
init();
}
ContactsBox::ContactsBox(ChannelData *channel, MembersFilter filter, const MembersAlreadyIn &already) : ItemListBox(st::boxNoTopScroll), _inner(channel, filter, already),
_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(filter == MembersFilterAdmins ? lng_contacts_done : lng_cancel), (filter == MembersFilterAdmins ? st::contactsClose : st::btnSelectCancel)),
_creationRequestId(0) {
init();
}
ContactsBox::ContactsBox(ChatData *chat) : ItemListBox(st::boxNoTopScroll), _inner(chat),
_addContact(this, lang(lng_add_contact_button), st::contactsAdd),
_filter(this, st::contactsFilter, lang(lng_participant_filter)),
@ -1060,6 +1134,7 @@ void ContactsBox::init() {
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()));
connect(&_inner, SIGNAL(adminAdded()), this, SIGNAL(adminAdded()));
_searchTimer.setSingleShot(true);
connect(&_searchTimer, SIGNAL(timeout()), this, SLOT(onSearchByUsername()));
@ -1146,7 +1221,10 @@ void ContactsBox::hideAll() {
void ContactsBox::showAll() {
ItemListBox::showAll();
_filter.show();
if (_inner.chat()) {
if (_inner.channel() && _inner.channelFilter() == MembersFilterAdmins) {
_next.hide();
_addContact.hide();
} else if (_inner.chat()) {
_next.show();
_addContact.hide();
} else if (_inner.creating() != CreatingGroupNone) {
@ -1195,15 +1273,18 @@ void ContactsBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
bool addingAdmin = _inner.channel() && _inner.channelFilter() == MembersFilterAdmins;
if (_inner.chat() || _inner.creating() != CreatingGroupNone) {
QString title(lang(lng_profile_add_participant));
QString title(lang(addingAdmin ? lng_channel_add_admin : 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()));
if (!addingAdmin) {
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);
// paint button sep
p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b);
}
} else if (_inner.bot()) {
paintTitle(p, lang(lng_bot_choose_group), true);
} else {
@ -1221,7 +1302,7 @@ void ContactsBox::resizeEvent(QResizeEvent *e) {
}
void ContactsBox::closePressed() {
if (_inner.channel()) {
if (_inner.channel() && !_inner.hasAlreadyMembersInChannel()) {
App::main()->showPeerHistory(_inner.channel()->id, ShowAtTheEndMsgId);
}
}
@ -1335,11 +1416,551 @@ bool ContactsBox::creationFail(const RPCError &error) {
return false;
}
MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : _channel(channel), _filter(filter),
_time(0),
_kickText(lang(lng_profile_kick)),
_kickWidth(st::normalFont->m.width(_kickText)),
_sel(-1),
_kickSel(-1),
_kickDown(-1),
_mouseSel(false),
_kickConfirm(0),
_kickRequestId(0),
_kickBox(0),
_loading(true),
_loadingRequestId(0) {
connect(App::main(), SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)));
connect(App::main(), SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(peerUpdated(PeerData*)));
refresh();
load();
}
void MembersInner::load() {
if (!_loadingRequestId) {
_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilterRecent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&MembersInner::membersReceived), rpcFail(&MembersInner::membersFailed));
}
}
void MembersInner::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
Painter p(this);
_time = unixtime();
p.fillRect(r, st::white->b);
int32 yFrom = r.top(), yTo = r.bottom();
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
p.translate(0, st::membersPadding.top());
if (_rows.isEmpty()) {
p.setFont(st::noContactsFont->f);
p.setPen(st::noContactsColor->p);
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
} else {
int32 from = (yFrom >= 0) ? (yFrom / rh) : 0;
if (from < _rows.size()) {
int32 to = (yTo / rh) + 1;
if (to > _rows.size()) to = _rows.size();
p.translate(0, from * rh);
for (; from < to; ++from) {
bool sel = (from == _sel);
bool kickSel = (from == _kickSel && (_kickDown < 0 || from == _kickDown));
bool kickDown = kickSel && (from == _kickDown);
paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
p.translate(0, rh);
}
}
}
}
void MembersInner::enterEvent(QEvent *e) {
setMouseTracking(true);
}
void MembersInner::leaveEvent(QEvent *e) {
setMouseTracking(false);
if (_sel >= 0) {
_sel = -1;
parentWidget()->update();
}
}
void MembersInner::mouseMoveEvent(QMouseEvent *e) {
_mouseSel = true;
_lastMousePos = e->globalPos();
updateSel();
}
void MembersInner::mousePressEvent(QMouseEvent *e) {
_mouseSel = true;
_lastMousePos = e->globalPos();
updateSel();
if (e->button() == Qt::LeftButton && _kickSel < 0) {
chooseParticipant();
}
_kickDown = _kickSel;
update();
}
void MembersInner::mouseReleaseEvent(QMouseEvent *e) {
_mouseSel = true;
_lastMousePos = e->globalPos();
updateSel();
if (_kickDown >= 0 && _kickDown == _kickSel && !_kickRequestId) {
_kickConfirm = _rows.at(_kickSel);
if (_kickBox) _kickBox->deleteLater();
_kickBox = new ConfirmBox((_filter == MembersFilterRecent ? lng_profile_sure_kick_channel : lng_profile_sure_kick_admin)(lt_user, _kickConfirm->firstName));
connect(_kickBox, SIGNAL(confirmed()), this, SLOT(onKickConfirm()));
connect(_kickBox, SIGNAL(destroyed(QObject*)), this, SLOT(onKickBoxDestroyed(QObject*)));
App::wnd()->replaceLayer(_kickBox);
}
_kickDown = -1;
}
void MembersInner::onKickBoxDestroyed(QObject *obj) {
if (_kickBox == obj) {
_kickBox = 0;
}
}
void MembersInner::onKickConfirm() {
if (_filter == MembersFilterRecent) {
_kickRequestId = MTP::send(MTPchannels_KickFromChannel(_channel->inputChannel, _kickConfirm->inputUser, MTP_bool(true)), rpcDone(&MembersInner::kickDone), rpcFail(&MembersInner::kickFail));
} else {
_kickRequestId = MTP::send(MTPchannels_EditAdmin(_channel->inputChannel, _kickConfirm->inputUser, MTP_channelRoleEmpty()), rpcDone(&MembersInner::kickAdminDone), rpcFail(&MembersInner::kickFail));
}
}
void MembersInner::paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown) {
int32 left = st::profileListPadding.width();
UserData *user = peer->asUser();
if (sel) {
p.fillRect(0, 0, width(), 2 * st::profileListPadding.height() + st::profileListPhotoSize, st::profileHoverBG->b);
}
p.drawPixmap(left, st::profileListPadding.height(), peer->photo->pix(st::profileListPhotoSize));
p.setPen(st::profileListNameColor->p);
data->name.drawElided(p, left + st::profileListPhotoSize + st::participantDelta, st::profileListNameTop, width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - (data->canKick ? _kickWidth : 0));
if (data->canKick) {
p.setFont((kickSel ? st::linkOverFont : st::linkFont)->f);
if (kickDown) {
p.setPen(st::btnDefLink.downColor->p);
} else {
p.setPen(st::btnDefLink.color->p);
}
p.drawText(width() - _kickWidth - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::normalFont->height) / 2 + st::normalFont->ascent, _kickText);
}
p.setFont(st::normalFont);
p.setPen(st::profileOfflineColor->p);
p.drawText(left + st::profileListPhotoSize + st::profileListPadding.width(), st::profileListPadding.height() + st::profileListPhotoSize - st::profileListStatusBottom, data->online);
}
void MembersInner::selectSkip(int32 dir) {
_time = unixtime();
_mouseSel = false;
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, origDir = dir;
int cur = (_sel >= 0) ? _sel : -1;
cur += dir;
if (cur <= 0) {
_sel = _rows.isEmpty() ? -1 : 0;
} else if (cur >= _rows.size()) {
_sel = -1;
} else {
_sel = cur;
}
if (dir > 0) {
if (_sel < 0 || _sel >= _rows.size()) {
_sel = -1;
}
} else {
if (!_rows.isEmpty()) {
if (_sel < 0) _sel = _rows.size() - 1;
}
}
if (_sel >= 0) {
emit mustScrollTo(_sel * rh, (_sel + 1) * rh);
}
parentWidget()->update();
}
void MembersInner::selectSkipPage(int32 h, int32 dir) {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
int32 points = h / rh;
if (!points) return;
selectSkip(points * dir);
}
void MembersInner::loadProfilePhotos(int32 yFrom) {
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
MTP::clearLoaderPriorities();
if (yTo < 0) return;
if (yFrom < 0) yFrom = 0;
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
if (!_rows.isEmpty()) {
int32 from = yFrom / rh;
if (from < 0) from = 0;
if (from < _rows.size()) {
int32 to = (yTo / rh) + 1;
if (to > _rows.size()) to = _rows.size();
for (; from < to; ++from) {
_rows[from]->photo->load();
}
}
}
}
void MembersInner::chooseParticipant() {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2, from;
if (_sel < 0 || _sel >= _rows.size()) return;
if (PeerData *peer = _rows[_sel]) {
App::wnd()->hideLayer();
App::main()->showPeerProfile(peer, ShowAtUnreadMsgId);
}
}
void MembersInner::refresh() {
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
if (_rows.isEmpty()) {
resize(width(), st::membersPadding.top() + st::noContactsHeight + st::membersPadding.bottom());
} else {
resize(width(), st::membersPadding.top() + _rows.size() * rh + st::membersPadding.bottom());
}
update();
}
ChannelData *MembersInner::channel() const {
return _channel;
}
MembersFilter MembersInner::filter() const {
return _filter;
}
QMap<UserData*, bool> MembersInner::already() const {
MembersAlreadyIn result;
for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i)->isUser()) {
result.insert(_rows.at(i)->asUser(), true);
}
}
return result;
}
void MembersInner::clearSel() {
_sel = _kickSel = _kickDown = -1;
_lastMousePos = QCursor::pos();
updateSel();
}
MembersInner::MemberData *MembersInner::data(int32 index) {
if (MemberData *result = _datas.at(index)) {
return result;
}
MemberData *result = _datas[index] = new MemberData();
result->name.setText(st::profileListNameFont, _rows[index]->name, _textNameOptions);
result->online = lng_mediaview_date_time(lt_date, _dates[index].date().toString(qsl("dd.MM.yy")), lt_time, _dates[index].time().toString(cTimeFormat()));
if (_filter == MembersFilterRecent) {
result->canKick = (_channel->amCreator() || _channel->amEditor() || _channel->amModerator()) ? (_roles[index] == MemberRoleNone) : false;
} else if (_filter == MembersFilterAdmins) {
result->canKick = _channel->amCreator() ? (_roles[index] == MemberRoleEditor || _roles[index] == MemberRoleModerator) : false;
} else {
result->canKick = false;
}
return result;
}
void MembersInner::clear() {
for (int32 i = 0, l = _datas.size(); i < l; ++i) {
delete _datas.at(i);
}
_datas.clear();
_rows.clear();
_dates.clear();
_roles.clear();
if (_kickBox) _kickBox->deleteLater();
clearSel();
}
MembersInner::~MembersInner() {
clear();
}
void MembersInner::updateSel() {
QPoint p(mapFromGlobal(_lastMousePos));
p.setY(p.y() - st::membersPadding.top());
bool in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(_lastMousePos));
int32 rh = st::profileListPhotoSize + st::profileListPadding.height() * 2;
int32 newSel = (in && p.y() >= 0 && p.y() < _rows.size() * rh) ? (p.y() / rh) : -1;
int32 newKickSel = newSel;
if (newSel >= 0 && (!data(newSel)->canKick || !QRect(width() - _kickWidth - st::profileCheckDeltaX, newSel * rh + st::profileListPadding.height() + (st::profileListPhotoSize - st::normalFont->height) / 2, _kickWidth, st::normalFont->height).contains(p))) {
newKickSel = -1;
}
if (newSel != _sel || newKickSel != _kickSel) {
_sel = newSel;
_kickSel = newKickSel;
parentWidget()->update();
setCursor(_kickSel >= 0 ? style::cur_pointer : style::cur_default);
}
}
void MembersInner::peerUpdated(PeerData *peer) {
parentWidget()->update();
}
void MembersInner::onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars) {
for (int32 i = 0, l = _rows.size(); i < l; ++i) {
if (_rows.at(i) == peer) {
if (_datas.at(i)) {
_datas.at(i)->name.setText(st::profileListNameFont, peer->name, _textNameOptions);
parentWidget()->update();
} else {
break;
}
}
}
}
void MembersInner::membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req) {
clear();
_loadingRequestId = 0;
if (result.type() == mtpc_channels_channelParticipants) {
const MTPDchannels_channelParticipants &d(result.c_channels_channelParticipants());
const QVector<MTPChannelParticipant> &v(d.vparticipants.c_vector().v);
_rows.reserve(v.size());
_datas.reserve(v.size());
_dates.reserve(v.size());
_roles.reserve(v.size());
if (_filter == MembersFilterRecent && _channel->count != d.vcount.v) {
_channel->count = d.vcount.v;
if (App::main()) emit App::main()->peerUpdated(_channel);
} else if (_filter == MembersFilterAdmins && _channel->adminsCount != d.vcount.v) {
_channel->adminsCount = d.vcount.v;
if (App::main()) emit App::main()->peerUpdated(_channel);
}
App::feedUsers(d.vusers);
for (QVector<MTPChannelParticipant>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
int32 userId = 0, addedTime = 0;
MemberRole role = MemberRoleNone;
switch (i->type()) {
case mtpc_channelParticipant:
userId = i->c_channelParticipant().vuser_id.v;
addedTime = i->c_channelParticipant().vdate.v;
break;
case mtpc_channelParticipantSelf:
role = MemberRoleSelf;
userId = i->c_channelParticipantSelf().vuser_id.v;
addedTime = i->c_channelParticipantSelf().vdate.v;
break;
case mtpc_channelParticipantModerator:
role = MemberRoleModerator;
userId = i->c_channelParticipantModerator().vuser_id.v;
addedTime = i->c_channelParticipantModerator().vdate.v;
break;
case mtpc_channelParticipantEditor:
role = MemberRoleEditor;
userId = i->c_channelParticipantEditor().vuser_id.v;
addedTime = i->c_channelParticipantEditor().vdate.v;
break;
case mtpc_channelParticipantKicked:
userId = i->c_channelParticipantKicked().vuser_id.v;
addedTime = i->c_channelParticipantKicked().vdate.v;
role = MemberRoleKicked;
break;
case mtpc_channelParticipantCreator:
userId = i->c_channelParticipantCreator().vuser_id.v;
addedTime = _channel->date;
role = MemberRoleCreator;
break;
}
if (UserData *user = App::userLoaded(userId)) {
_rows.push_back(user);
_dates.push_back(date(addedTime));
_roles.push_back(role);
_datas.push_back(0);
}
}
}
if (_rows.isEmpty()) {
_rows.push_back(App::self());
_dates.push_back(date(MTP_int(_channel->date)));
_roles.push_back(MemberRoleSelf);
_datas.push_back(0);
}
clearSel();
_loading = false;
refresh();
emit loaded();
}
bool MembersInner::membersFailed(const RPCError &error, mtpRequestId req) {
if (mtpIsFlood(error)) return false;
App::wnd()->hideLayer();
return true;
}
void MembersInner::kickDone(const MTPUpdates &result, mtpRequestId req) {
App::main()->sentUpdatesReceived(result);
if (_kickRequestId != req) return;
removeKicked();
if (_kickBox) _kickBox->onClose();
}
void MembersInner::kickAdminDone(const MTPBool &result, mtpRequestId req) {
if (_kickRequestId != req) return;
removeKicked();
if (_kickBox) _kickBox->onClose();
}
bool MembersInner::kickFail(const RPCError &error, mtpRequestId req) {
if (mtpIsFlood(error)) return false;
if (_kickBox) _kickBox->onClose();
load();
return true;
}
void MembersInner::removeKicked() {
_kickRequestId = 0;
int32 index = _rows.indexOf(_kickConfirm);
if (index >= 0) {
_rows.removeAt(index);
delete _datas.at(index);
_datas.removeAt(index);
_dates.removeAt(index);
_roles.removeAt(index);
clearSel();
if (_filter == MembersFilterRecent && _channel->count > 1) {
--_channel->count;
if (App::main()) emit App::main()->peerUpdated(_channel);
} else if (_filter == MembersFilterAdmins && _channel->adminsCount > 1) {
--_channel->adminsCount;
if (App::main()) emit App::main()->peerUpdated(_channel);
}
}
_kickConfirm = 0;
}
MembersBox::MembersBox(ChannelData *channel, MembersFilter filter) : ItemListBox(st::boxScroll), _inner(channel, filter),
_add(this, lang(filter == MembersFilterRecent ? lng_participant_invite : lng_channel_add_admins), st::contactsAdd),
_done(this, lang(lng_contacts_done), st::contactsClose),
_addBox(0) {
ItemListBox::init(&_inner, _done.height());
connect(&_add, SIGNAL(clicked()), this, SLOT(onAdd()));
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSel()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
connect(&_inner, SIGNAL(mustScrollTo(int, int)), &_scroll, SLOT(scrollToY(int, int)));
connect(&_inner, SIGNAL(loaded()), this, SLOT(onLoaded()));
prepare();
}
void MembersBox::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Down) {
_inner.selectSkip(1);
} else if (e->key() == Qt::Key_Up) {
_inner.selectSkip(-1);
} else if (e->key() == Qt::Key_PageDown) {
_inner.selectSkipPage(_scroll.height(), 1);
} else if (e->key() == Qt::Key_PageUp) {
_inner.selectSkipPage(_scroll.height(), -1);
} else {
ItemListBox::keyPressEvent(e);
}
}
void MembersBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (paint(p)) return;
QString title(lang(_inner.filter() == MembersFilterRecent ? lng_channel_members : lng_channel_admins));
paintTitle(p, title, false);
}
void MembersBox::resizeEvent(QResizeEvent *e) {
ItemListBox::resizeEvent(e);
_inner.resize(width(), _inner.height());
_done.move(0, height() - _done.height());
_add.move(width() - _add.width(), 0);
}
void MembersBox::onLoaded() {
if (!_done.isHidden() && _inner.channel()->amCreator() && (_inner.channel()->count < cMaxGroupCount() || !_inner.channel()->isPublic())) {
_add.show();
}
}
void MembersBox::onScroll() {
_inner.loadProfilePhotos(_scroll.scrollTop());
}
void MembersBox::onAdd() {
if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= cMaxGroupCount()) {
App::wnd()->replaceLayer(new MaxInviteBox(_inner.channel()->invitationUrl));
return;
}
ContactsBox *box = new ContactsBox(_inner.channel(), _inner.filter(), _inner.already());
if (_inner.filter() == MembersFilterRecent) {
App::wnd()->hideLayer(true);
App::wnd()->showLayer(box, true);
} else {
_addBox = box;
connect(_addBox, SIGNAL(adminAdded()), this, SLOT(onAdminAdded()));
App::wnd()->replaceLayer(_addBox);
}
}
void MembersBox::onAdminAdded() {
if (!_addBox) return;
_addBox->onClose();
_addBox = 0;
_inner.load();
}
void MembersBox::hideAll() {
ItemListBox::hideAll();
_add.hide();
_done.hide();
}
void MembersBox::showAll() {
ItemListBox::showAll();
if (_inner.channel()->amCreator() && _inner.isLoaded() && (_inner.channel()->count < cMaxGroupCount() || !_inner.channel()->isPublic())) {
_add.show();
} else {
_add.hide();
}
_done.show();
}
void MembersBox::showDone() {
setFocus();
}
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),
_aboutGroup(st::normalFont, lng_create_group_about(lt_count, QString::number(cMaxGroupCount())), _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) {
@ -1900,6 +2521,10 @@ void SetupChannelBox::mousePressEvent(QMouseEvent *e) {
}
}
void SetupChannelBox::leaveEvent(QEvent *e) {
updateSelected(QCursor::pos());
}
void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) {
QPoint p(mapFromGlobal(cursorGlobalPosition));

View file

@ -25,7 +25,14 @@ enum CreatingGroupType {
CreatingGroupChannel,
};
class ContactsInner : public QWidget, public RPCSender {
enum MembersFilter {
MembersFilterRecent,
MembersFilterAdmins,
};
typedef QMap<UserData*, bool> MembersAlreadyIn;
class ConfirmBox;
class ContactsInner : public TWidget, public RPCSender {
Q_OBJECT
private:
@ -35,7 +42,7 @@ private:
public:
ContactsInner(CreatingGroupType creating = CreatingGroupNone);
ContactsInner(ChannelData *channel);
ContactsInner(ChannelData *channel, MembersFilter channelFilter = MembersFilterRecent, const MembersAlreadyIn &already = MembersAlreadyIn());
ContactsInner(ChatData *chat);
ContactsInner(UserData *bot);
void init();
@ -47,7 +54,7 @@ public:
void mousePressEvent(QMouseEvent *e);
void resizeEvent(QResizeEvent *e);
void paintDialog(QPainter &p, PeerData *peer, ContactData *data, bool sel);
void paintDialog(Painter &p, PeerData *peer, ContactData *data, bool sel);
void updateFilter(QString filter = QString());
void selectSkip(int32 dir);
@ -68,10 +75,14 @@ public:
ChatData *chat() const;
ChannelData *channel() const;
MembersFilter channelFilter() const;
UserData *bot() const;
CreatingGroupType creating() const;
int32 selectedCount() const;
bool hasAlreadyMembersInChannel() const {
return !_already.isEmpty();
}
~ContactsInner();
@ -81,6 +92,7 @@ signals:
void selectAllQuery();
void searchByUsername();
void chosenChanged();
void adminAdded();
public slots:
@ -91,15 +103,25 @@ public slots:
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void onAddBot();
void onAddAdmin();
void onNoAddAdminBox(QObject *obj);
private:
void addAdminDone(const MTPBool &result, mtpRequestId req);
bool addAdminFail(const RPCError &error, mtpRequestId req);
ChatData *_chat;
ChannelData *_channel;
MembersFilter _channelFilter;
UserData *_bot;
CreatingGroupType _creating;
MembersAlreadyIn _already;
ChatData *_addToChat;
UserData *_addAdmin;
mtpRequestId _addAdminRequestId;
ConfirmBox *_addAdminBox;
int32 _time;
@ -148,6 +170,7 @@ public:
ContactsBox();
ContactsBox(const QString &name, const QImage &photo); // group creation
ContactsBox(ChannelData *channel); // channel setup
ContactsBox(ChannelData *channel, MembersFilter filter, const MembersAlreadyIn &already);
ContactsBox(ChatData *chat);
ContactsBox(UserData *bot);
void keyPressEvent(QKeyEvent *e);
@ -160,6 +183,10 @@ public:
_filter.setFocus();
}
signals:
void adminAdded();
public slots:
void onFilterUpdate();
@ -187,6 +214,7 @@ private:
FlatInput _filter;
FlatButton _next, _cancel;
MembersFilter _membersFilter;
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
bool peopleFailed(const RPCError &error, mtpRequestId req);
@ -211,6 +239,155 @@ private:
bool creationFail(const RPCError &e);
};
class MembersInner : public TWidget, public RPCSender {
Q_OBJECT
private:
struct MemberData;
public:
MembersInner(ChannelData *channel, MembersFilter filter);
void paintEvent(QPaintEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void paintDialog(Painter &p, PeerData *peer, MemberData *data, bool sel, bool kickSel, bool kickDown);
void selectSkip(int32 dir);
void selectSkipPage(int32 h, int32 dir);
void loadProfilePhotos(int32 yFrom);
void chooseParticipant();
void refresh();
ChannelData *channel() const;
MembersFilter filter() const;
void load();
bool isLoaded() const {
return !_loading;
}
QMap<UserData*, bool> already() const;
~MembersInner();
signals:
void mustScrollTo(int ymin, int ymax);
void loaded();
public slots:
void updateSel();
void peerUpdated(PeerData *peer);
void onPeerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
void onKickConfirm();
void onKickBoxDestroyed(QObject *obj);
private:
void clearSel();
MemberData *data(int32 index);
void membersReceived(const MTPchannels_ChannelParticipants &result, mtpRequestId req);
bool membersFailed(const RPCError &error, mtpRequestId req);
void kickDone(const MTPUpdates &result, mtpRequestId req);
void kickAdminDone(const MTPBool &result, mtpRequestId req);
bool kickFail(const RPCError &error, mtpRequestId req);
void removeKicked();
void clear();
ChannelData *_channel;
MembersFilter _filter;
QString _kickText;
int32 _time, _kickWidth;
int32 _sel, _kickSel, _kickDown;
bool _mouseSel;
UserData *_kickConfirm;
mtpRequestId _kickRequestId;
ConfirmBox *_kickBox;
enum MemberRole {
MemberRoleNone,
MemberRoleSelf,
MemberRoleCreator,
MemberRoleEditor,
MemberRoleModerator,
MemberRoleKicked
};
struct MemberData {
Text name;
QString online;
bool canKick;
};
bool _loading;
mtpRequestId _loadingRequestId;
typedef QVector<UserData*> MemberRows;
typedef QVector<QDateTime> MemberDates;
typedef QVector<MemberRole> MemberRoles;
typedef QVector<MemberData*> MemberDatas;
MemberRows _rows;
MemberDates _dates;
MemberRoles _roles;
MemberDatas _datas;
QPoint _lastMousePos;
};
class MembersBox : public ItemListBox {
Q_OBJECT
public:
MembersBox(ChannelData *channel, MembersFilter filter);
void keyPressEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void resizeEvent(QResizeEvent *e);
void setInnerFocus() {
setFocus();
}
public slots:
void onLoaded();
void onScroll();
void onAdd();
void onAdminAdded();
protected:
void hideAll();
void showAll();
void showDone();
private:
MembersInner _inner;
FlatButton _add, _done;
ContactsBox *_addBox;
};
class NewGroupBox : public AbstractBox {
Q_OBJECT
@ -319,6 +496,7 @@ public:
void resizeEvent(QResizeEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void leaveEvent(QEvent *e);
void closePressed();

View file

@ -105,7 +105,7 @@ _phone(phone), _fname(fname), _lname(lname), _replyTo(replyTo) {
_compressed.hide();
_name = _fname + QChar(' ') + _lname;
_name = lng_full_name(lt_first_name, _fname, lt_last_name, _lname);
_namew = st::mediaFont->m.width(_name);
_size = _phone;
_textw = qMax(_namew, st::mediaFont->m.width(_size));

View file

@ -228,25 +228,29 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
}
}
void DialogsListWidget::peopleResultPaint(PeerData *peer, QPainter &p, int32 w, bool act, bool sel) const {
void DialogsListWidget::peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool act, bool sel) const {
QRect fullRect(0, 0, w, st::dlgHeight);
p.fillRect(fullRect, (act ? st::dlgActiveBG : (sel ? st::dlgHoverBG : st::dlgBG))->b);
History *history = App::history(peer->id);
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, history->peer->photo->pix(st::dlgPhotoSize));
p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, peer->photo->pix(st::dlgPhotoSize));
int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
int32 namewidth = w - nameleft - st::dlgPaddingHor;
QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
// draw chat icon
if (history->peer->isChat()) {
if (peer->isChat()) {
p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgPos.x(), rectForName.top() + st::dlgChatImgPos.y()), App::sprite(), (act ? st::dlgActiveChatImg : st::dlgChatImg));
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
} else if (history->peer->isChannel()) {
} else if (peer->isChannel()) {
p.drawPixmap(QPoint(rectForName.left() + st::dlgChannelImgPos.x(), rectForName.top() + st::dlgChannelImgPos.y()), App::sprite(), (act ? st::dlgActiveChannelImg : st::dlgChannelImg));
rectForName.setLeft(rectForName.left() + st::dlgImgSkip);
if (peer->asChannel()->isVerified()) {
rectForName.setWidth(rectForName.width() - st::verifiedCheck.pxWidth() - st::verifiedCheckPos.x());
p.drawSprite(rectForName.topLeft() + QPoint(qMin(peer->dialogName().maxWidth(), rectForName.width()), 0) + st::verifiedCheckPos, (act ? st::verifiedCheckInv : st::verifiedCheck));
}
}
QRect tr(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth, st::dlgFont->height);
@ -273,7 +277,7 @@ void DialogsListWidget::peopleResultPaint(PeerData *peer, QPainter &p, int32 w,
peer->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
}
void DialogsListWidget::searchInPeerPaint(QPainter &p, int32 w) const {
void DialogsListWidget::searchInPeerPaint(Painter &p, int32 w) const {
QRect fullRect(0, 0, w, st::dlgHeight);
p.fillRect(fullRect, st::dlgBG->b);
@ -450,6 +454,8 @@ void DialogsListWidget::removePeer(PeerData *peer) {
History *history = App::history(peer->id);
dialogs.del(peer);
history->dialogs = History::DialogLinks();
history->clearNotifications();
if (App::wnd()) App::wnd()->notifyClear(history);
if (contacts.list.rowByPeer.constFind(peer->id) != contacts.list.rowByPeer.cend()) {
if (contactsNoDialogs.list.rowByPeer.constFind(peer->id) == contactsNoDialogs.list.rowByPeer.cend()) {
contactsNoDialogs.addByName(App::history(peer->id));
@ -1665,8 +1671,6 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque
} break;
}
unreadCountsReceived(*dlgList);
if (!_contactsRequest) {
_contactsRequest = MTP::send(MTPcontacts_GetContacts(MTP_string("")), rpcDone(&DialogsWidget::contactsReceived), rpcFail(&DialogsWidget::contactsFailed));
}
@ -1674,6 +1678,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque
if (_dialogsRequest == req) {
_dialogsCount = count;
if (dlgList) {
unreadCountsReceived(*dlgList);
list.dialogsReceived(*dlgList);
onListScroll();
@ -1693,6 +1698,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque
} else if (_channelDialogsRequest == req) {
//_channelDialogsCount = count;
if (dlgList) {
unreadCountsReceived(*dlgList);
list.dialogsReceived(*dlgList);
onListScroll();

View file

@ -49,8 +49,8 @@ public:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void peopleResultPaint(PeerData *peer, QPainter &p, int32 w, bool act, bool sel) const;
void searchInPeerPaint(QPainter &p, int32 w) const;
void peopleResultPaint(PeerData *peer, Painter &p, int32 w, bool act, bool sel) const;
void searchInPeerPaint(Painter &p, int32 w) const;
void selectSkip(int32 direction);
void selectSkipPage(int32 pixels, int32 direction);

View file

@ -647,11 +647,12 @@ void ChannelHistory::addNewGroup(const MTPMessageGroup &group) {
}
HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) {
if (_joinedMessage || peer->asChannel()->haveLeft() || peer->asChannel()->wasKicked()) return _joinedMessage;
if (_joinedMessage || !peer->asChannel()->amIn()) return _joinedMessage;
UserData *inviter = (peer->asChannel()->inviter > 0) ? App::userLoaded(peer->asChannel()->inviter) : 0;
if (!inviter) return 0;
if (peerToUser(inviter->id) == MTP::authedId()) unread = false;
int32 flags = (unread ? MTPDmessage_flag_unread : 0);
QDateTime inviteDate = peer->asChannel()->inviteDate;
if (unread) _maxReadMessageDate = inviteDate;
@ -1725,8 +1726,11 @@ void History::newItemAdded(HistoryItem *item) {
if (item->out()) {
if (unreadBar) unreadBar->destroy();
} else if (item->unread()) {
notifies.push_back(item);
App::main()->newUnreadMsg(this, item);
bool skip = false;
if (!isChannel() || peer->asChannel()->amIn()) {
notifies.push_back(item);
App::main()->newUnreadMsg(this, item);
}
}
}
@ -2310,7 +2314,7 @@ void History::setLastMessage(HistoryItem *msg) {
}
void History::setPosInDialogsDate(const QDateTime &date) {
bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amCreator() || (!peer->asChannel()->haveLeft() && !peer->asChannel()->wasKicked())));
bool updateDialog = (App::main() && (!peer->isChannel() || peer->asChannel()->amIn()));
if (!lastMsgDate.isNull() && lastMsgDate >= date) {
if (!updateDialog || !dialogs.isEmpty()) {
return;
@ -4493,7 +4497,24 @@ HistoryContact::HistoryContact(int32 userId, const QString &first, const QString
App::regSharedContactPhone(userId, phone);
_maxw = st::mediaMaxWidth;
name.setText(st::mediaFont, (first + ' ' + last).trimmed(), _textNameOptions);
name.setText(st::mediaFont, lng_full_name(lt_first_name, first, lt_last_name, last).trimmed(), _textNameOptions);
phonew = st::mediaFont->m.width(phone);
if (contact) {
contact->photo->load();
}
}
HistoryContact::HistoryContact(int32 userId, const QString &fullname, const QString &phone) : HistoryMedia(0)
, userId(userId)
, phone(App::formatPhone(phone))
, contact(App::userLoaded(userId))
{
App::regSharedContactPhone(userId, phone);
_maxw = st::mediaMaxWidth;
name.setText(st::mediaFont, fullname.trimmed(), _textNameOptions);
phonew = st::mediaFont->m.width(phone);
@ -4589,14 +4610,7 @@ void HistoryContact::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32
}
HistoryMedia *HistoryContact::clone() const {
QStringList names = name.original(0, 0xFFFF, false).split(QChar(' '), QString::SkipEmptyParts);
if (names.isEmpty()) {
names.push_back(QString());
}
QString fname = names.front();
names.pop_front();
HistoryContact *result = new HistoryContact(userId, fname, names.join(QChar(' ')), phone);
return result;
return new HistoryContact(userId, name.original(0, 0xFFFF, false), phone);
}
void HistoryContact::draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const {
@ -5966,7 +5980,7 @@ void HistoryImageLink::getState(TextLinkPtr &lnk, HistoryCursorState &state, int
skipx = st::mediaPadding.left();
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
} if (fwd) {
} else if (fwd) {
skipy = st::msgServiceNameFont->height + st::msgPadding.top();
}
if (parent->displayFromName()) {

View file

@ -827,7 +827,7 @@ public:
}
bool unread() const {
if ((out() && (id > 0 && id < _history->outboxReadBefore)) || (!out() && id > 0 && id < _history->inboxReadBefore)) return false;
return (id > 0) ? true : (_flags & MTPDmessage_flag_unread);
return (id > 0 && !out()) ? true : (_flags & MTPDmessage_flag_unread);
}
bool notifyByFrom() const {
return _flags & MTPDmessage_flag_notify_by_from;
@ -1332,6 +1332,7 @@ class HistoryContact : public HistoryMedia {
public:
HistoryContact(int32 userId, const QString &first, const QString &last, const QString &phone);
HistoryContact(int32 userId, const QString &fullname, const QString &phone);
void initDimensions(const HistoryItem *parent);
void draw(Painter &p, const HistoryItem *parent, bool selected, int32 width) const;

View file

@ -3867,6 +3867,10 @@ bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) {
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
if (_unblockRequest == req) _unblockRequest = 0;
if (error.type() == qstr("CHANNEL_PRIVATE")) {
App::wnd()->showLayer(new ConfirmBox(lang(lng_channel_not_accessible), true));
return true;
}
return false;
}
@ -4221,7 +4225,7 @@ void HistoryWidget::sendBotCommand(const QString &cmd, MsgId replyTo) { // reply
QString toSend = cmd;
PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? (App::hoveredLinkItem()->toHistoryForwarded() ? App::hoveredLinkItem()->toHistoryForwarded()->fromForwarded() : App::hoveredLinkItem()->from()) : 0);
if (!bot->isUser() || !bot->asUser()->botInfo) bot = 0;
if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) bot = 0;
QString username = bot ? bot->asUser()->username : QString();
int32 botStatus = _peer->isChat() ? _peer->asChat()->botStatus : (_peer->isChannel() ? _peer->asChannel()->botStatus : -1);
if (!replyTo && toSend.indexOf('@') < 2 && !username.isEmpty() && (botStatus == 0 || botStatus == 2)) {
@ -4352,7 +4356,7 @@ bool HistoryWidget::canSendMessages(PeerData *peer) const {
} else if (peer->isChat()) {
return !peer->asChat()->isForbidden && !peer->asChat()->haveLeft;
} else if (peer->isChannel()) {
return !peer->asChannel()->isForbidden && !peer->asChannel()->haveLeft() && !peer->asChannel()->wasKicked() && (peer->asChannel()->canPublish() || !peer->asChannel()->isBroadcast());
return peer->asChannel()->amIn() && (peer->asChannel()->canPublish() || !peer->asChannel()->isBroadcast());
}
}
return false;
@ -4376,7 +4380,7 @@ bool HistoryWidget::isBlocked() const {
}
bool HistoryWidget::isJoinChannel() const {
return _peer && _peer->isChannel() && !_peer->asChannel()->amParticipant();
return _peer && _peer->isChannel() && !_peer->asChannel()->amIn();
}
bool HistoryWidget::isMuteUnmute() const {

View file

@ -31,13 +31,18 @@ IntroSignup::IntroSignup(IntroWidget *parent) : IntroStage(parent),
errorAlpha(0), a_photo(0),
next(this, lang(lng_intro_finish), st::btnIntroNext),
first(this, st::inpIntroName, lang(lng_signup_firstname)),
last(this, st::inpIntroName, lang(lng_signup_lastname)) {
last(this, st::inpIntroName, lang(lng_signup_lastname)),
_invertOrder(langFirstNameGoesSecond()) {
setVisible(false);
setGeometry(parent->innerRect());
connect(&next, SIGNAL(clicked()), this, SLOT(onSubmitName()));
connect(&checkRequest, SIGNAL(timeout()), this, SLOT(onCheckRequest()));
if (_invertOrder) {
setTabOrder(&last, &first);
}
setMouseTracking(true);
}
@ -102,7 +107,12 @@ void IntroSignup::paintEvent(QPaintEvent *e) {
if (animating() || error.length()) {
p.setOpacity(errorAlpha.current());
QRect errRect((width() - st::introErrWidth) / 2, (last.y() + last.height() + next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight);
QRect errRect;
if (_invertOrder) {
errRect = QRect((width() - st::introErrWidth) / 2, (first.y() + first.height() + next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight);
} else {
errRect = QRect((width() - st::introErrWidth) / 2, (last.y() + last.height() + next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight);
}
p.setFont(st::introErrFont->f);
p.setPen(st::introErrColor->p);
p.drawText(errRect, error, QTextOption(style::al_center));
@ -135,8 +145,13 @@ void IntroSignup::resizeEvent(QResizeEvent *e) {
_phTop = st::introTextTop + st::introTextSize.height() + st::introCountry.top;
if (e->oldSize().width() != width()) {
next.move((width() - next.width()) / 2, st::introBtnTop);
first.move((width() - next.width()) / 2 + next.width() - first.width(), _phTop);
last.move((width() - next.width()) / 2 + next.width() - last.width(), first.y() + st::introCountry.height + st::introCountry.ptrSize.height() + st::introPhoneTop);
if (_invertOrder) {
last.move((width() - next.width()) / 2 + next.width() - last.width(), _phTop);
first.move((width() - next.width()) / 2 + next.width() - first.width(), last.y() + st::introCountry.height + st::introCountry.ptrSize.height() + st::introPhoneTop);
} else {
first.move((width() - next.width()) / 2 + next.width() - first.width(), _phTop);
last.move((width() - next.width()) / 2 + next.width() - last.width(), first.y() + st::introCountry.height + st::introCountry.ptrSize.height() + st::introPhoneTop);
}
}
textRect = QRect((width() - st::introTextSize.width()) / 2, st::introTextTop, st::introTextSize.width(), st::introTextSize.height());
}
@ -175,7 +190,11 @@ bool IntroSignup::animStep(float64 ms) {
void IntroSignup::activate() {
show();
first.setFocus();
if (_invertOrder) {
last.setFocus();
} else {
first.setFocus();
}
}
void IntroSignup::deactivate() {
@ -196,7 +215,11 @@ void IntroSignup::onCheckRequest() {
if (!first.isEnabled()) {
first.setDisabled(false);
last.setDisabled(false);
last.setFocus();
if (_invertOrder) {
first.setFocus();
} else {
last.setFocus();
}
}
}
}
@ -241,7 +264,11 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
return true;
} else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) {
showError(lang(lng_flood_error));
last.setFocus();
if (_invertOrder) {
first.setFocus();
} else {
last.setFocus();
}
return true;
}
if (cDebug()) { // internal server error
@ -249,7 +276,11 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) {
} else {
showError(lang(lng_server_error));
}
first.setFocus();
if (_invertOrder) {
last.setFocus();
} else {
first.setFocus();
}
return false;
}
@ -258,12 +289,22 @@ void IntroSignup::onInputChange() {
}
void IntroSignup::onSubmitName(bool force) {
if ((first.hasFocus() || first.text().trimmed().length()) && !last.text().trimmed().length()) {
last.setFocus();
return;
} else if (!first.text().trimmed().length()) {
first.setFocus();
return;
if (_invertOrder) {
if ((last.hasFocus() || last.text().trimmed().length()) && !first.text().trimmed().length()) {
first.setFocus();
return;
} else if (!last.text().trimmed().length()) {
last.setFocus();
return;
}
} else {
if ((first.hasFocus() || first.text().trimmed().length()) && !last.text().trimmed().length()) {
last.setFocus();
return;
} else if (!first.text().trimmed().length()) {
first.setFocus();
return;
}
}
if (!force && !first.isEnabled()) return;

View file

@ -72,5 +72,7 @@ private:
QString firstName, lastName;
mtpRequestId sentRequest;
bool _invertOrder;
QTimer checkRequest;
};

View file

@ -139,3 +139,19 @@ public:
QString translate(const char *context, const char *sourceText, const char *disambiguation = 0, int n = -1) const;
};
inline bool langFirstNameGoesSecond() {
QString fullname = lang(lng_full_name__tagged);
for (const QChar *s = fullname.constData(), *ch = s, *e = ch + fullname.size(); ch != e;) {
if (*ch == TextCommand) {
if (ch + 3 < e && (ch + 1)->unicode() == TextCommandLangTag && *(ch + 3) == TextCommand) {
if ((ch + 2)->unicode() == 0x0020 + lt_last_name) {
return true;
} else if ((ch + 2)->unicode() == 0x0020 + lt_first_name) {
break;
}
}
}
}
return false;
}

View file

@ -864,7 +864,7 @@ void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector<UserData
for (QVector<UserData*>::const_iterator i = users.cbegin(), e = users.cend(); i != e; ++i) {
inputUsers.push_back((*i)->inputUser);
}
MTP::send(MTPchannels_InviteToChannel(chatOrChannel->asChannel()->inputChannel, MTP_vector<MTPInputUser>(inputUsers)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantsFail), 0, 5);
MTP::send(MTPchannels_InviteToChannel(chatOrChannel->asChannel()->inputChannel, MTP_vector<MTPInputUser>(inputUsers)), rpcDone(&MainWidget::inviteToChannelDone, chatOrChannel->asChannel()), rpcFail(&MainWidget::addParticipantsFail), 0, 5);
}
}
@ -960,15 +960,13 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
showDialogs();
}
} else if (peer->isChannel()) {
if (peer->asChannel()->inviter > 0) {
if (!peer->asChannel()->isForbidden && !peer->asChannel()->haveLeft() && !peer->asChannel()->wasKicked()) {
if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) {
History *h = App::history(peer->id);
h->clear(true);
h->addNewerSlice(QVector<MTPMessage>(), 0);
h->asChannelHistory()->insertJoinedMessage(true);
history.peerMessagesUpdated(h->peer->id);
}
if (peer->asChannel()->inviter > 0 && peer->asChannel()->amIn()) {
if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) {
History *h = App::history(peer->id);
h->clear(true);
h->addNewerSlice(QVector<MTPMessage>(), 0);
h->asChannelHistory()->insertJoinedMessage(true);
history.peerMessagesUpdated(h->peer->id);
}
}
} else {
@ -990,12 +988,10 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
}
}
if (!h->lastMsgDate.isNull() && h->loadedAtBottom()) {
if (peer->isChannel() && peer->asChannel()->inviter > 0 && h->lastMsgDate <= peer->asChannel()->inviteDate) {
if (!peer->asChannel()->isForbidden && !peer->asChannel()->haveLeft() && !peer->asChannel()->wasKicked()) {
if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) {
h->asChannelHistory()->insertJoinedMessage(true);
history.peerMessagesUpdated(h->peer->id);
}
if (peer->isChannel() && peer->asChannel()->inviter > 0 && h->lastMsgDate <= peer->asChannel()->inviteDate && peer->asChannel()->amIn()) {
if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) {
h->asChannelHistory()->insertJoinedMessage(true);
history.peerMessagesUpdated(h->peer->id);
}
}
}
@ -1264,8 +1260,12 @@ void MainWidget::saveRecentHashtags(const QString &text) {
void MainWidget::readServerHistory(History *hist, bool force) {
if (!hist || (!force && !hist->unreadCount)) return;
ReadRequests::const_iterator i = _readRequests.constFind(hist->peer);
MsgId upTo = hist->inboxRead(0);
if (hist->isChannel() && !hist->peer->asChannel()->amIn()) {
return; // no read request for channels that I didn't koin
}
ReadRequests::const_iterator i = _readRequests.constFind(hist->peer);
if (i == _readRequests.cend()) {
sendReadRequest(hist->peer, upTo);
} else {
@ -1670,7 +1670,7 @@ void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMess
App::emitPeerUpdated();
}
}
if (History *h = App::historyLoaded(peer->id)) {
if (History *h = App::historyLoaded(peer ? peer->id : 0)) {
if (!h->lastMsg) {
checkPeerHistory(peer);
}
@ -2651,6 +2651,11 @@ void MainWidget::sentUpdatesReceived(uint64 randomId, const MTPUpdates &result)
App::emitPeerUpdated();
}
void MainWidget::inviteToChannelDone(ChannelData *channel, const MTPUpdates &updates) {
sentUpdatesReceived(updates);
channel->updateFull(true);
}
void MainWidget::msgUpdated(PeerId peer, const HistoryItem *msg) {
if (!msg) return;
history.msgUpdated(peer, msg);
@ -3504,6 +3509,8 @@ void MainWidget::openPeerByName(const QString &username, bool toProfile, const Q
if (peer->isUser() && peer->asUser()->botInfo && !peer->asUser()->botInfo->cantJoinGroups && !startToken.isEmpty()) {
peer->asUser()->botInfo->startGroupToken = startToken;
App::wnd()->showLayer(new ContactsBox(peer->asUser()));
} else if (peer->isChannel()) {
showPeerHistory(peer->id, ShowAtUnreadMsgId);
} else {
showPeerProfile(peer);
}
@ -3574,6 +3581,8 @@ void MainWidget::usernameResolveDone(QPair<bool, QString> toProfileStartToken, c
if (peer->isUser() && peer->asUser()->botInfo && !peer->asUser()->botInfo->cantJoinGroups && !toProfileStartToken.second.isEmpty()) {
peer->asUser()->botInfo->startGroupToken = toProfileStartToken.second;
App::wnd()->showLayer(new ContactsBox(peer->asUser()));
} else if (peer->isChannel()) {
showPeerHistory(peer->id, ShowAtUnreadMsgId);
} else {
showPeerProfile(peer);
}
@ -4504,7 +4513,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) {
App::markPeerUpdated(channel);
channel->inviter = 0;
if (channel->isForbidden || channel->wasKicked() || channel->haveLeft()) {
if (!channel->amIn()) {
dialogs.removePeer(channel);
if (History *h = App::historyLoaded(channel->id)) {
h->clear(true);

View file

@ -227,6 +227,7 @@ public:
void sentUpdatesReceived(const MTPUpdates &updates) {
return sentUpdatesReceived(0, updates);
}
void inviteToChannelDone(ChannelData *channel, const MTPUpdates &updates);
void msgUpdated(PeerId peer, const HistoryItem *msg);
void historyToDown(History *hist);
void dialogsToUp();

View file

@ -44,13 +44,18 @@ namespace {
MediaView *_view;
};
TextParseOptions _captionTextOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions _captionBotOptions = {
TextParseLinks | TextParseMentions | TextParseHashtags | TextParseMultiline | TextParseRichText | TextParseBotCommands, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
}
MediaView::MediaView() : TWidget(App::wnd()),
@ -763,7 +768,7 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
_caption = Text();
if (HistoryMessage *itemMsg = item ? item->toHistoryMessage() : 0) {
if (HistoryPhoto *photoMsg = dynamic_cast<HistoryPhoto*>(itemMsg->getMedia())) {
_caption.setText(st::mvCaptionFont, photoMsg->captionForClone().original(0, 0xFFFF), _captionTextOptions);
_caption.setText(st::mvCaptionFont, photoMsg->captionForClone().original(0, 0xFFFF), (item->from()->isUser() && item->from()->asUser()->botInfo) ? _captionBotOptions : _captionTextOptions);
}
}

View file

@ -47,8 +47,9 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
_invitationLink(this, qsl("telegram.me/joinchat/")),
_botSettings(this, lang(lng_profile_bot_settings)),
_botHelp(this, lang(lng_profile_bot_help)),
_username(this, qsl("https://telegram.me/") + (_peerChannel ? _peerChannel->username : QString())),
_editLink(this, lang((_peerChannel && _peerChannel->isPublic()) ? lng_profile_edit_public_link : lng_profile_create_public_link)),
_username(this, (_peerChannel && _peerChannel->isPublic()) ? (qsl("telegram.me/") + _peerChannel->username) : lang(lng_profile_create_public_link)),
_members(this, lng_channel_members_link(lt_count, (_peerChannel && _peerChannel->count > 0) ? _peerChannel->count : 1)),
_admins(this, lng_channel_admins_link(lt_count, (_peerChannel && _peerChannel->adminsCount > 0) ? _peerChannel->adminsCount : 1)),
// about
_about(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right()),
@ -121,6 +122,8 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
connect(&_createInvitationLink, SIGNAL(clicked()), this, SLOT(onCreateInvitationLink()));
connect(&_invitationLink, SIGNAL(clicked()), this, SLOT(onInvitationLink()));
connect(&_username, SIGNAL(clicked()), this, SLOT(onPublicLink()));
connect(&_members, SIGNAL(clicked()), this, SLOT(onMembers()));
connect(&_admins, SIGNAL(clicked()), this, SLOT(onAdmins()));
_invitationLink.setAcceptBoth(true);
_username.setAcceptBoth(true);
updateInvitationLink();
@ -128,7 +131,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
if (_peerChat) {
QString maxStr = lang(_uploadPhoto.textWidth() > _addParticipant.textWidth() ? lng_profile_set_group_photo : lng_profile_add_participant);
_uploadPhoto.setAutoFontSize(st::profileMinBtnPadding, maxStr);
_uploadPhoto.setAutoFontSize(st::profileMinBtnPadding, maxStr);
_addParticipant.setAutoFontSize(st::profileMinBtnPadding, maxStr);
} else if (_peerUser) {
QString maxStr;
if (_peerUser->botInfo && !_peerUser->botInfo->cantJoinGroups) {
@ -141,11 +144,12 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
_sendMessage.setAutoFontSize(st::profileMinBtnPadding, maxStr);
_shareContact.setAutoFontSize(st::profileMinBtnPadding, maxStr);
_inviteToGroup.setAutoFontSize(st::profileMinBtnPadding, maxStr);
} else if (_peerChannel && _amCreator) {
_uploadPhoto.setAutoFontSize(st::profileMinBtnPadding, lang(lng_profile_set_group_photo));
}
connect(&_botSettings, SIGNAL(clicked()), this, SLOT(onBotSettings()));
connect(&_botHelp, SIGNAL(clicked()), this, SLOT(onBotHelp()));
connect(&_editLink, SIGNAL(clicked()), this, SLOT(onEditPublicLink()));
connect(App::app(), SIGNAL(peerPhotoDone(PeerId)), this, SLOT(onPhotoUpdateDone(PeerId)));
connect(App::app(), SIGNAL(peerPhotoFail(PeerId)), this, SLOT(onPhotoUpdateFail(PeerId)));
@ -340,9 +344,9 @@ bool ProfileInner::blockFail(const RPCError &error) {
}
void ProfileInner::onAddParticipant() {
if (!_peerChat && !_peerChannel) return;
if (!_peerChat) return;
App::wnd()->showLayer(_peerChat ? (new ContactsBox(_peerChat)) : (new ContactsBox(_peerChannel)));
App::wnd()->showLayer(new ContactsBox(_peerChat));
}
void ProfileInner::onUpdatePhotoCancel() {
@ -398,10 +402,24 @@ void ProfileInner::onInvitationLink() {
}
void ProfileInner::onPublicLink() {
if (!_peerChannel || !_peerChannel->isPublic()) return;
if (!_peerChannel) return;
if (_peerChannel->isPublic()) {
QApplication::clipboard()->setText(qsl("https://telegram.me/") + _peerChannel->username);
App::wnd()->showLayer(new ConfirmBox(lang(lng_channel_public_link_copied), true));
} else {
App::wnd()->showLayer(new SetupChannelBox(_peerChannel, true));
}
}
QApplication::clipboard()->setText(qsl("https://telegram.me/") + _peerChannel->username);
App::wnd()->showLayer(new ConfirmBox(lang(lng_channel_public_link_copied), true));
void ProfileInner::onMembers() {
if (!_peerChannel) return;
App::wnd()->showLayer(new MembersBox(_peerChannel, MembersFilterRecent));
}
void ProfileInner::onAdmins() {
if (!_peerChannel) return;
App::wnd()->showLayer(new MembersBox(_peerChannel, MembersFilterAdmins));
}
void ProfileInner::onCreateInvitationLink() {
@ -459,6 +477,9 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
resizeEvent(0);
} else if (_peerChannel) {
updateInvitationLink();
_members.setText(lng_channel_members_link(lt_count, (_peerChannel->count > 0) ? _peerChannel->count : 1));
_admins.setText(lng_channel_admins_link(lt_count, (_peerChannel->adminsCount > 0) ? _peerChannel->adminsCount : 1));
_onlineText = lng_chat_status_members(lt_count, _peerChannel->count > 0 ? _peerChannel->count : 1);
if (_peerChannel->about.isEmpty()) {
_about = Text(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right());
} else {
@ -497,10 +518,6 @@ void ProfileInner::onBotHelp() {
updateBotLinksVisibility();
}
void ProfileInner::onEditPublicLink() {
App::wnd()->showLayer(new SetupChannelBox(_peerChannel, true), true);
}
void ProfileInner::peerUpdated(PeerData *data) {
if (data == _peer) {
PhotoData *photo = 0;
@ -518,6 +535,9 @@ void ProfileInner::peerUpdated(PeerData *data) {
if (_peerChannel->isPublic() != _invitationLink.isHidden()) {
peerUsernameChanged();
}
_members.setText(lng_channel_members_link(lt_count, (_peerChannel->count > 0) ? _peerChannel->count : 1));
_admins.setText(lng_channel_admins_link(lt_count, (_peerChannel->adminsCount > 0) ? _peerChannel->adminsCount : 1));
_onlineText = lng_chat_status_members(lt_count, _peerChannel->count > 0 ? _peerChannel->count : 1);
}
_photoLink = (photo && photo->date) ? TextLinkPtr(new PhotoLink(photo, _peer)) : TextLinkPtr();
if (_peer->name != _nameCache) {
@ -600,7 +620,7 @@ void ProfileInner::reorderParticipants() {
if (_peerUser) {
_onlineText = App::onlineText(_peerUser, t, true);
} else if (_peerChannel) {
_onlineText = _peerChannel->count ? lng_chat_status_members(lt_count, _peerChannel->count) : lang(lng_channel_status);
_onlineText = lng_chat_status_members(lt_count, _peerChannel->count > 0 ? _peerChannel->count : 1);
} else {
_onlineText = lang(lng_chat_status_unaccessible);
}
@ -615,12 +635,7 @@ void ProfileInner::start() {
void ProfileInner::peerUsernameChanged() {
if (_peerChannel) {
if (_peerChannel->isPublic()) {
_username.setText(qsl("https://telegram.me/") + _peerChannel->username);
_editLink.setText(lang(lng_profile_edit_public_link));
} else {
_editLink.setText(lang(lng_profile_create_public_link));
}
_username.setText(_peerChannel->isPublic() ? (qsl("telegram.me/") + _peerChannel->username) : lang(lng_profile_create_public_link));
resizeEvent(0);
showAll();
}
@ -636,7 +651,7 @@ bool ProfileInner::event(QEvent *e) {
}
void ProfileInner::paintEvent(QPaintEvent *e) {
QPainter p(this);
Painter p(this);
QRect r(e->rect());
p.setClipRect(r);
@ -657,8 +672,15 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.setOpacity(1);
}
}
int32 namew = _width - st::profilePhotoSize - st::profileNameLeft;
p.setPen(st::black->p);
_nameText.drawElided(p, _left + st::profilePhotoSize + st::profileNameLeft, top + st::profileNameTop, _width - st::profilePhotoSize - st::profileNameLeft);
if (_peerChannel && _peerChannel->isVerified()) {
namew -= st::verifiedCheckProfile.pxWidth() + st::verifiedCheckProfilePos.x();
int32 cx = _left + st::profilePhotoSize + st::profileNameLeft + qMin(_nameText.maxWidth(), namew);
p.drawSprite(QPoint(cx, top + st::profileNameTop) + st::verifiedCheckProfilePos, st::verifiedCheckProfile);
}
_nameText.drawElided(p, _left + st::profilePhotoSize + st::profileNameLeft, top + st::profileNameTop, namew);
p.setFont(st::profileStatusFont->f);
int32 addbyname = 0;
@ -666,24 +688,22 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent);
p.setPen(st::black->p);
p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop + st::linkFont->ascent, '@' + _peerUser->username);
} else if (_peerChannel && (_peerChannel->isPublic() || _amCreator)) {
addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent);
}
p.setPen((_peerUser && App::onlineColorUse(_peerUser, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop + st::linkFont->ascent, _onlineText);
if (_amCreator && ((_peerChat && !_peerChat->invitationUrl.isEmpty()) || (_peerChannel && !_peerChannel->invitationUrl.isEmpty()))) {
if (!_peerChannel || !_peerChannel->isPublic()) {
p.setPen(st::black->p);
p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _createInvitationLink.y() + st::linkFont->ascent, lang(lng_group_invite_link));
}
if (!_peerChannel || (!_amCreator && !_peerChannel->amEditor() && !_peerChannel->amModerator())) {
p.setPen((_peerUser && App::onlineColorUse(_peerUser, l_time) ? st::profileOnlineColor : st::profileOfflineColor)->p);
p.drawText(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop + st::linkFont->ascent, _onlineText);
}
if (!_cancelPhoto.isHidden()) {
p.setPen(st::profileOfflineColor->p);
p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + addbyname + st::linkFont->ascent, lang(lng_settings_uploading_photo));
p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::linkFont->ascent, lang(lng_settings_uploading_photo));
}
if (!_errorText.isEmpty()) {
p.setFont(st::setErrFont->f);
p.setPen(st::setErrColor->p);
p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + addbyname + st::profilePhoneFont->ascent, _errorText);
p.drawText(_left + st::profilePhotoSize + st::profilePhoneLeft, _cancelPhoto.y() + st::profilePhoneFont->ascent, _errorText);
}
if (!_phoneText.isEmpty()) {
p.setPen(st::black->p);
@ -702,20 +722,12 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
if (!_peerChannel || _amCreator) {
top += _shareContact.height();
}
if (_peerChannel && (_amCreator || _peerChannel->isPublic())) {
if (!_amCreator) {
top += st::setLittleSkip;
} else {
top += st::setSectionSkip;
}
top += _editLink.height();
}
// about
if (!_about.isEmpty()) {
p.setFont(st::profileHeaderFont->f);
p.setPen(st::profileHeaderColor->p);
p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(lng_profile_about_section));
p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(_peerChannel ? lng_profile_description_section : lng_profile_about_section));
top += st::profileHeaderSkip;
_about.draw(p, _left, top, _width);
@ -728,6 +740,17 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(lng_profile_settings_section));
top += st::profileHeaderSkip;
// invite link stuff
if (_amCreator && (!_peerChannel || !_peerChannel->isPublic())) {
if ((_peerChat && !_peerChat->invitationUrl.isEmpty()) || (_peerChannel && !_peerChannel->invitationUrl.isEmpty())) {
p.setPen(st::black);
p.setFont(st::linkFont);
p.drawText(_left, _invitationLink.y() + st::linkFont->ascent, lang(lng_group_invite_link));
top += _invitationLink.height() + st::setLittleSkip;
}
top += _createInvitationLink.height() + st::setSectionSkip;
}
top += _enableNotifications.height();
// shared media
@ -764,7 +787,7 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
if (_peerUser || _peerChat) {
top += st::setLittleSkip + _clearHistory.height();
}
if (_peerUser || _peerChat || !_amCreator) {
if (_peerUser || _peerChat || (_peerChannel->amIn() && !_amCreator)) {
top += st::setLittleSkip + _deleteConversation.height();
}
if (_peerUser && peerToUser(_peerUser->id) != MTP::authedId()) {
@ -874,7 +897,7 @@ void ProfileInner::updateSelected() {
if (_peerUser || _peerChat) {
partfrom = _clearHistory.y() + _clearHistory.height();
}
if (_peerUser || _peerChat || !_amCreator) {
if (_peerUser || _peerChat || (_peerChannel->amIn() && !_amCreator)) {
partfrom = _deleteConversation.y() + _deleteConversation.height();
}
partfrom += st::profileHeaderSkip;
@ -1075,16 +1098,15 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
// profile
top += st::profilePadding.top();
int32 addbyname = 0;
if (_peerChannel && (_amCreator || _peerChannel->isPublic())) {
_username.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + st::profileStatusTop);
addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent);
}
_members.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + addbyname + st::profileStatusTop);
addbyname = st::profileStatusTop + st::linkFont->ascent - (st::profileNameTop + st::profileNameFont->ascent);
_admins.move(_left + st::profilePhotoSize + st::profileStatusLeft, top + 2 * addbyname + st::profileStatusTop);
if (_amCreator) {
if ((_peerChat && _peerChat->invitationUrl.isEmpty()) || (_peerChannel && _peerChannel->invitationUrl.isEmpty())) {
_createInvitationLink.move(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profilePhoneTop);
} else {
_createInvitationLink.move(_left + _width - _createInvitationLink.width(), top + st::profilePhoneTop);
}
if (!_invitationText.isEmpty()) {
_invitationLink.setText(st::linkFont->m.elidedText(_invitationText, Qt::ElideRight, _width - st::profilePhotoSize - st::profilePhoneLeft));
}
_invitationLink.move(_left + st::profilePhotoSize + st::profilePhoneLeft, top + st::profilePhoneTop + st::linkFont->height * 1.2);
_cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhotoSize - st::linkFont->height);
} else {
_cancelPhoto.move(_left + _width - _cancelPhoto.width(), top + st::profilePhoneTop);
@ -1105,20 +1127,6 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
if (!_peerChannel || _amCreator) {
top += _shareContact.height();
}
if (_peerChannel && (_amCreator || _peerChannel->isPublic())) {
if (!_amCreator) {
top += st::setLittleSkip;
} else {
top += st::setSectionSkip;
}
if (_peerChannel->isPublic()) {
_username.move(_left, top);
_editLink.move(_left + _width - _editLink.width(), top);
} else {
_editLink.move(_left, top);
}
top += _editLink.height();
}
// about
if (!_about.isEmpty()) {
@ -1130,6 +1138,23 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
// settings
top += st::profileHeaderSkip;
// invite link stuff
int32 _inviteLinkTextWidth(st::linkFont->m.width(lang(lng_group_invite_link)) + st::linkFont->spacew);
if (_amCreator && (!_peerChannel || !_peerChannel->isPublic())) {
if (!_invitationText.isEmpty()) {
_invitationLink.setText(st::linkFont->m.elidedText(_invitationText, Qt::ElideRight, _width - _inviteLinkTextWidth));
}
if ((_peerChat && !_peerChat->invitationUrl.isEmpty()) || (_peerChannel && !_peerChannel->invitationUrl.isEmpty())) {
_invitationLink.move(_left + _inviteLinkTextWidth, top);
top += _invitationLink.height() + st::setLittleSkip;
_createInvitationLink.move(_left, top);
} else {
_createInvitationLink.move(_left, top);
}
top += _createInvitationLink.height() + st::setSectionSkip;
}
_enableNotifications.move(_left, top); top += _enableNotifications.height();
// shared media
@ -1157,7 +1182,7 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
if (_peerUser || _peerChat) {
_clearHistory.move(_left, top); top += _clearHistory.height() + st::setLittleSkip;
}
if (_peerUser || _peerChat || !_amCreator) {
if (_peerUser || _peerChat || (_peerChannel->amIn() && !_amCreator)) {
_deleteConversation.move(_left, top); top += _deleteConversation.height();
}
if (_peerUser && peerToUser(_peerUser->id) != MTP::authedId()) {
@ -1288,8 +1313,10 @@ int32 ProfileInner::countMinHeight() {
} else if (_peerChannel) {
if (_amCreator) {
h = _deleteChannel.y() + _deleteChannel.height() + st::profileHeaderSkip;
} else {
} else if (_peerChannel->amIn()) {
h = _deleteConversation.y() + _deleteConversation.height() + st::profileHeaderSkip;
} else {
h = _searchInPeer.y() + _searchInPeer.height() + st::profileHeaderSkip;
}
}
return h;
@ -1309,7 +1336,7 @@ void ProfileInner::showAll() {
} else {
_clearHistory.hide();
}
if (_peerUser || _peerChat || !_amCreator) {
if (_peerUser || _peerChat || (_peerChannel->amIn() && !_amCreator)) {
_deleteConversation.show();
} else {
_deleteConversation.hide();
@ -1339,8 +1366,9 @@ void ProfileInner::showAll() {
_blockUser.hide();
}
_deleteChannel.hide();
_editLink.hide();
_username.hide();
_members.hide();
_admins.hide();
} else if (_peerChat) {
_sendMessage.hide();
_shareContact.hide();
@ -1378,8 +1406,9 @@ void ProfileInner::showAll() {
}
_blockUser.hide();
_deleteChannel.hide();
_editLink.hide();
_username.hide();
_members.hide();
_admins.hide();
} else if (_peerChannel) {
_sendMessage.hide();
_shareContact.hide();
@ -1387,7 +1416,6 @@ void ProfileInner::showAll() {
if (_peerChannel->isForbidden) {
_uploadPhoto.hide();
_cancelPhoto.hide();
_addParticipant.hide();
_createInvitationLink.hide();
_invitationLink.hide();
} else {
@ -1413,25 +1441,26 @@ void ProfileInner::showAll() {
_createInvitationLink.hide();
_invitationLink.hide();
}
if (_amCreator) {
_addParticipant.show();
} else {
_addParticipant.hide();
}
}
_addParticipant.hide();
_blockUser.hide();
if (_amCreator) {
_deleteChannel.show();
_editLink.show();
} else {
_deleteChannel.hide();
_editLink.hide();
}
if (_peerChannel->isPublic()) {
if (_peerChannel->isPublic() || _amCreator) {
_username.show();
} else {
_username.hide();
}
if (_amCreator || _peerChannel->amEditor() || _peerChannel->amModerator()) {
_members.show();
_admins.show();
} else {
_members.hide();
_admins.hide();
}
}
_enableNotifications.show();
updateNotifySettings();

View file

@ -110,11 +110,13 @@ public slots:
void onCreateInvitationLinkSure();
void onPublicLink();
void onMembers();
void onAdmins();
void onFullPeerUpdated(PeerData *peer);
void onBotSettings();
void onBotHelp();
void onEditPublicLink();
private:
@ -146,7 +148,7 @@ private:
FlatButton _sendMessage, _shareContact, _inviteToGroup;
LinkButton _cancelPhoto, _createInvitationLink, _invitationLink;
QString _invitationText;
LinkButton _botSettings, _botHelp, _username, _editLink;
LinkButton _botSettings, _botHelp, _username, _members, _admins;
Text _about;
int32 _aboutTop, _aboutHeight;

View file

@ -2107,7 +2107,6 @@ bool psShowOpenWithMenu(int x, int y, const QString &file) {
if (sel > 0) {
if (sel <= handlers.size()) {
IDataObject *dataObj = 0;
IEnumAssocHandlers *assocHandlers = 0;
if (SUCCEEDED(pItem->BindToHandler(nullptr, BHID_DataObject, IID_PPV_ARGS(&dataObj))) && dataObj) {
handlers.at(sel - 1).handler->Invoke(dataObj);
dataObj->Release();

View file

@ -129,7 +129,17 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone,
asUser()->username = newUsername;
asUser()->setNameOrPhone(newNameOrPhone);
} else if (isChannel()) {
asChannel()->username = newUsername;
if (asChannel()->username != newUsername) {
asChannel()->username = newUsername;
if (newUsername.isEmpty()) {
asChannel()->flags &= ~MTPDchannel::flag_username;
} else {
asChannel()->flags |= MTPDchannel::flag_username;
}
if (App::main()) {
App::main()->peerUsernameChanged(this);
}
}
}
Names oldNames = names;
@ -207,7 +217,7 @@ void UserData::setName(const QString &first, const QString &last, const QString
firstName = first;
lastName = last;
}
updateName(lastName.isEmpty() ? firstName : (firstName + ' ' + lastName), phoneName, usern);
updateName(lastName.isEmpty() ? firstName : lng_full_name(lt_first_name, firstName, lt_last_name, lastName), phoneName, usern);
}
if (updUsername) {
if (App::main()) {
@ -383,20 +393,10 @@ void ChannelData::setName(const QString &newName, const QString &usern) {
bool updName = !newName.isEmpty(), updUsername = (username != usern);
updateName(newName.isEmpty() ? name : newName, QString(), usern);
if (updUsername) {
if (usern.isEmpty()) {
flags &= ~MTPDchannel::flag_username;
} else {
flags |= MTPDchannel::flag_username;
}
if (App::main()) {
App::main()->peerUsernameChanged(this);
}
}
}
void ChannelData::updateFull() {
if (!_lastFullUpdate || getms(true) > _lastFullUpdate + UpdateFullChannelTimeout) {
void ChannelData::updateFull(bool force) {
if (!_lastFullUpdate || force || getms(true) > _lastFullUpdate + UpdateFullChannelTimeout) {
App::api()->requestFullPeer(this);
if (!amCreator() && !inviter) App::api()->requestSelfParticipant(this);
}
@ -959,7 +959,7 @@ id(id), type(type), url(url), displayUrl(displayUrl), siteName(siteName), title(
void PeerLink::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton && App::main()) {
if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) {
if (!peer()->asChannel()->isPublic() && (peer()->asChannel()->isForbidden || peer()->asChannel()->haveLeft() || peer()->asChannel()->wasKicked())) {
if (!peer()->asChannel()->isPublic() && !peer()->asChannel()->amIn()) {
App::wnd()->showLayer(new ConfirmBox(lang(lng_channel_not_accessible), true));
} else {
App::main()->showPeerHistory(peer()->id, ShowAtUnreadMsgId);

View file

@ -451,13 +451,13 @@ private:
class ChannelData : public PeerData {
public:
ChannelData(const PeerId &id) : PeerData(id), access(0), inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))), count(0), date(0), version(0), isForbidden(true), botStatus(-1), inviter(0), _lastFullUpdate(0) {
ChannelData(const PeerId &id) : PeerData(id), access(0), inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))), count(1), adminsCount(1), date(0), version(0), isForbidden(true), botStatus(-1), inviter(0), _lastFullUpdate(0) {
setName(QString(), QString());
}
void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = UnknownPeerPhotoId);
void setName(const QString &name, const QString &username);
void updateFull();
void updateFull(bool force = false);
void fullUpdated();
uint64 access;
@ -466,7 +466,7 @@ public:
QString username, about;
int32 count;
int32 count, adminsCount;
int32 date;
int32 version;
int32 flags;
@ -491,13 +491,16 @@ public:
bool wasKicked() const {
return flags & MTPDchannel_flag_was_kicked;
}
bool amIn() const {
return !isForbidden && !haveLeft() && !wasKicked();
}
bool canPublish() const {
return amCreator() || amEditor();
}
bool amParticipant() const {
return canPublish() || (!haveLeft() && !wasKicked());
}
bool isForbidden;
bool isVerified() const {
return flags & MTPDchannel_flag_is_verified;
}
int32 botStatus; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other
// ImagePtr photoFull;