New profile blocks started. Info block fully ready.

All block widgets added (currently empty).
About text and phone number PeerUpdateFlag added for observers.
This commit is contained in:
John Preston 2016-05-31 22:27:11 +03:00
parent a06a989f97
commit 41c8df029a
48 changed files with 1342 additions and 165 deletions

View file

@ -405,12 +405,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
"lng_profile_actions_section" = "Actions";
"lng_profile_bot_settings" = "Settings";
"lng_profile_bot_help" = "Help";
"lng_profile_invite_link_section" = "Invite link";
"lng_profile_create_public_link" = "Create public 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";
"lng_profile_channel_info" = "Channel info";
"lng_profile_info_section" = "Info";
"lng_profile_mobile_number" = "Mobile:";
"lng_profile_username" = "Username:";
"lng_profile_link" = "Link:";
"lng_profile_add_contact" = "Add Contact";
"lng_profile_edit_contact" = "Edit";
"lng_profile_enable_notifications" = "Notifications";
@ -912,6 +914,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
// Not used
"lng_topbar_info" = "Info";
"lng_profile_group_info" = "Group info";
"lng_profile_channel_info" = "Channel info";
// Wnd specific

View file

@ -276,7 +276,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
} break;
}
}
channel->about = qs(f.vabout);
channel->setAbout(qs(f.vabout));
int32 newCount = f.has_participants_count() ? f.vparticipants_count.v : 0;
if (newCount != channel->count) {
if (channel->isMegagroup() && !channel->mgInfo->lastParticipants.isEmpty()) {
@ -343,7 +343,7 @@ void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestI
peer->asUser()->setBotInfoVersion(-1);
}
peer->asUser()->blocked = d.is_blocked() ? UserIsBlocked : UserIsNotBlocked;
peer->asUser()->about = d.has_about() ? qs(d.vabout) : QString();
peer->asUser()->setAbout(d.has_about() ? qs(d.vabout) : QString());
if (req) {
QMap<PeerData*, mtpRequestId>::iterator i = _fullPeerRequests.find(peer);

View file

@ -428,7 +428,10 @@ namespace {
}
}
if (d.is_deleted()) {
data->setPhone(QString());
if (!data->phone().isEmpty()) {
data->setPhone(QString());
update.flags |= UpdateFlag::UserPhoneChanged;
}
data->setNameDelayed(lang(lng_deleted), QString(), QString(), QString());
data->setPhoto(MTP_userProfilePhotoEmpty());
data->access = UserNoAccess;
@ -440,12 +443,14 @@ namespace {
QString fname = (!minimal || noLocalName) ? (d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString()) : data->firstName;
QString lname = (!minimal || noLocalName) ? (d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString()) : data->lastName;
QString phone = minimal ? data->phone : (d.has_phone() ? qs(d.vphone) : QString());
QString phone = minimal ? data->phone() : (d.has_phone() ? qs(d.vphone) : QString());
QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString());
bool phoneChanged = (data->phone != phone);
if (phoneChanged) data->setPhone(phone);
bool phoneChanged = (data->phone() != phone);
if (phoneChanged) {
data->setPhone(phone);
update.flags |= UpdateFlag::UserPhoneChanged;
}
bool nameChanged = (data->firstName != fname) || (data->lastName != lname);
bool showPhone = !isServiceUser(data->id) && !d.is_self() && !d.is_contact() && !d.is_mutual_contact();
@ -480,7 +485,7 @@ namespace {
} else {
data->setBotInfoVersion(-1);
}
data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone.isEmpty() ? -1 : 0);
data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone().isEmpty() ? -1 : 0);
if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsHidden) != dbiprsHidden) {
cRefReportSpamStatuses().insert(data->id, dbiprsHidden);
Local::writeReportSpamStatuses();
@ -522,7 +527,7 @@ namespace {
case mtpc_userStatusOnline: data->onlineTill = status->c_userStatusOnline().vexpires.v; break;
}
if (data->contact < 0 && !data->phone.isEmpty() && peerToUser(data->id) != MTP::authedId()) {
if (data->contact < 0 && !data->phone().isEmpty() && peerToUser(data->id) != MTP::authedId()) {
data->contact = 0;
}
if (App::main()) {
@ -1259,7 +1264,7 @@ namespace {
break;
}
if (user->contact < 1) {
if (user->contact < 0 && !user->phone.isEmpty() && peerToUser(user->id) != MTP::authedId()) {
if (user->contact < 0 && !user->phone().isEmpty() && peerToUser(user->id) != MTP::authedId()) {
user->contact = 0;
}
}
@ -1276,7 +1281,7 @@ namespace {
bool showPhone = !isServiceUser(user->id) && !user->isSelf() && !user->contact;
bool showPhoneChanged = !isServiceUser(user->id) && !user->isSelf() && ((showPhone && !wasShowPhone) || (!showPhone && wasShowPhone));
if (showPhoneChanged) {
user->setNameDelayed(textOneLine(user->firstName), textOneLine(user->lastName), showPhone ? App::formatPhone(user->phone) : QString(), textOneLine(user->username));
user->setNameDelayed(textOneLine(user->firstName), textOneLine(user->lastName), showPhone ? App::formatPhone(user->phone()) : QString(), textOneLine(user->username));
}
markPeerUpdated(user);
}

View file

@ -32,9 +32,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
AboutBox::AboutBox() : AbstractBox(st::aboutWidth)
, _version(this, lng_about_version(lt_version, QString::fromLatin1(AppVersionStr.c_str()) + (cAlphaVersion() ? " alpha" : "") + (cBetaVersion() ? qsl(" beta %1").arg(cBetaVersion()) : QString())), st::aboutVersionLink)
, _text1(this, lang(lng_about_text_1), st::aboutLabel, st::aboutTextStyle)
, _text2(this, lang(lng_about_text_2), st::aboutLabel, st::aboutTextStyle)
, _text3(this, QString(), st::aboutLabel, st::aboutTextStyle)
, _text1(this, lang(lng_about_text_1), FlatLabel::InitType::Rich, st::aboutLabel, st::aboutTextStyle)
, _text2(this, lang(lng_about_text_2), FlatLabel::InitType::Rich, st::aboutLabel, st::aboutTextStyle)
, _text3(this,st::aboutLabel, st::aboutTextStyle)
, _done(this, lang(lng_close), st::defaultBoxButton) {
_text3.setRichText(lng_about_text_3(lt_faq_open, qsl("[a href=\"%1\"]").arg(telegramFaqLink()), lt_faq_close, qsl("[/a]")));

View file

@ -33,16 +33,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "observer_peer.h"
AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth)
, _user(0)
, _save(this, lang(lng_add_contact), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _retry(this, lang(lng_try_other_contact), st::defaultBoxButton)
, _first(this, st::defaultInputField, lang(lng_signup_firstname), fname)
, _last(this, st::defaultInputField, lang(lng_signup_lastname), lname)
, _phone(this, st::defaultInputField, lang(lng_contact_phone), phone)
, _invertOrder(langFirstNameGoesSecond())
, _contactId(0)
, _addRequest(0) {
, _invertOrder(langFirstNameGoesSecond()) {
if (!phone.isEmpty()) {
_phone.setDisabled(true);
}
@ -57,10 +54,8 @@ AddContactBox::AddContactBox(UserData *user) : AbstractBox(st::boxWidth)
, _retry(this, lang(lng_try_other_contact), st::defaultBoxButton)
, _first(this, st::defaultInputField, lang(lng_signup_firstname), user->firstName)
, _last(this, st::defaultInputField, lang(lng_signup_lastname), user->lastName)
, _phone(this, st::defaultInputField, lang(lng_contact_phone), user->phone)
, _invertOrder(langFirstNameGoesSecond())
, _contactId(0)
, _addRequest(0) {
, _phone(this, st::defaultInputField, lang(lng_contact_phone), user->phone())
, _invertOrder(langFirstNameGoesSecond()) {
_phone.setDisabled(true);
initBox();
}
@ -191,7 +186,7 @@ void AddContactBox::onSave() {
_sentName = firstName;
if (_user) {
_contactId = rand_value<uint64>();
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone), MTP_string(firstName), MTP_string(lastName)));
QVector<MTPInputContact> v(1, MTP_inputPhoneContact(MTP_long(_contactId), MTP_string(_user->phone()), MTP_string(firstName), MTP_string(lastName)));
_addRequest = MTP::send(MTPcontacts_ImportContacts(MTP_vector<MTPInputContact>(v), MTP_bool(false)), rpcDone(&AddContactBox::onSaveUserDone), rpcFail(&AddContactBox::onSaveUserFail));
} else {
_contactId = rand_value<uint64>();
@ -1181,7 +1176,7 @@ EditChannelBox::EditChannelBox(ChannelData *channel) : AbstractBox()
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _title(this, st::defaultInputField, lang(lng_dlg_new_channel_name), _channel->name)
, _description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about)
, _description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about())
, _sign(this, lang(lng_edit_sign_messages), channel->addsSignature())
, _publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::defaultBoxLinkButton)
, _saveTitleRequestId(0)
@ -1322,7 +1317,7 @@ void EditChannelBox::onPublicLink() {
}
void EditChannelBox::saveDescription() {
if (_sentDescription == _channel->about) {
if (_sentDescription == _channel->about()) {
saveSign();
} else {
_saveDescriptionRequestId = MTP::send(MTPchannels_EditAbout(_channel->inputChannel, MTP_string(_sentDescription)), rpcDone(&EditChannelBox::onSaveDescriptionDone), rpcFail(&EditChannelBox::onSaveFail));
@ -1357,9 +1352,11 @@ bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) {
} else if (req == _saveDescriptionRequestId) {
_saveDescriptionRequestId = 0;
if (err == qstr("CHAT_ABOUT_NOT_MODIFIED")) {
_channel->about = _sentDescription;
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
if (_channel->setAbout(_sentDescription)) {
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
}
Notify::peerUpdatedSendDelayed();
}
saveSign();
return true;
@ -1386,9 +1383,11 @@ void EditChannelBox::onSaveTitleDone(const MTPUpdates &updates) {
void EditChannelBox::onSaveDescriptionDone(const MTPBool &result) {
_saveDescriptionRequestId = 0;
_channel->about = _sentDescription;
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
if (_channel->setAbout(_sentDescription)) {
if (App::api()) {
emit App::api()->fullPeerUpdated(_channel);
}
Notify::peerUpdatedSendDelayed();
}
saveSign();
}

View file

@ -57,7 +57,7 @@ private:
void initBox();
UserData *_user;
UserData *_user = nullptr;
QString _boxTitle;
BoxButton _save, _cancel, _retry;
@ -66,9 +66,9 @@ private:
bool _invertOrder;
uint64 _contactId;
uint64 _contactId = 0;
mtpRequestId _addRequest;
mtpRequestId _addRequest = 0;
QString _sentName;
};

View file

@ -381,11 +381,10 @@ void ConvertToSupergroupBox::resizeEvent(QResizeEvent *e) {
PinMessageBox::PinMessageBox(ChannelData *channel, MsgId msgId) : AbstractBox(st::boxWidth)
, _channel(channel)
, _msgId(msgId)
, _text(this, lang(lng_pinned_pin_sure), st::boxLabel)
, _text(this, lang(lng_pinned_pin_sure), FlatLabel::InitType::Simple, st::boxLabel)
, _notify(this, lang(lng_pinned_notify), true)
, _pin(this, lang(lng_pinned_pin), st::defaultBoxButton)
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
, _requestId(0) {
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
_text.resizeToWidth(st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right());
setMaxHeight(st::boxPadding.top() + _text.height() + st::boxMediumSkip + _notify.height() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _pin.height() + st::boxButtonPadding.bottom());
@ -441,7 +440,7 @@ RichDeleteMessageBox::RichDeleteMessageBox(ChannelData *channel, UserData *from,
, _channel(channel)
, _from(from)
, _msgId(msgId)
, _text(this, lang(lng_selected_delete_sure_this), st::boxLabel)
, _text(this, lang(lng_selected_delete_sure_this), FlatLabel::InitType::Simple, st::boxLabel)
, _banUser(this, lang(lng_ban_user), false)
, _reportSpam(this, lang(lng_report_spam), false)
, _deleteAll(this, lang(lng_delete_all_from), false)

View file

@ -217,7 +217,7 @@ private:
BoxButton _pin, _cancel;
mtpRequestId _requestId;
mtpRequestId _requestId = 0;
};

View file

@ -27,6 +27,7 @@ enum ExpandLinksMode {
ExpandLinksNone,
ExpandLinksShortened,
ExpandLinksAll,
ExpandLinksUrlOnly, // For custom urls leaves only url instead of text.
};
class ClickHandlerHost {

View file

@ -110,15 +110,22 @@ QString HiddenUrlClickHandler::getExpandedLinkText(ExpandLinksMode mode, const Q
QString result;
if (mode == ExpandLinksAll) {
result = textPart.toString() + qsl(" (") + url() + ')';
} else if (mode == ExpandLinksUrlOnly) {
result = url();
}
return result;
}
TextWithEntities HiddenUrlClickHandler::getExpandedLinkTextWithEntities(ExpandLinksMode mode, int entityOffset, const QStringRef &textPart) const {
TextWithEntities result;
result.entities.push_back({ EntityInTextCustomUrl, entityOffset, textPart.size(), url() });
if (mode == ExpandLinksAll) {
result.text = textPart.toString() + qsl(" (") + url() + ')';
if (mode == ExpandLinksUrlOnly) {
result.text = url();
result.entities.push_back({ EntityInTextUrl, entityOffset, result.text.size() });
} else {
result.entities.push_back({ EntityInTextCustomUrl, entityOffset, textPart.size(), url() });
if (mode == ExpandLinksAll) {
result.text = textPart.toString() + qsl(" (") + url() + ')';
}
}
return result;
}
@ -174,9 +181,19 @@ TextWithEntities HashtagClickHandler::getExpandedLinkTextWithEntities(ExpandLink
return simpleTextWithEntity({ EntityInTextHashtag, entityOffset, textPart.size() });
}
PeerData *BotCommandClickHandler::_peer = nullptr;
UserData *BotCommandClickHandler::_bot = nullptr;
void BotCommandClickHandler::onClick(Qt::MouseButton button) const {
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
if (PeerData *peer = Ui::getPeerForMouseAction()) {
if (auto peer = peerForCommand()) {
if (auto bot = peer->isUser() ? peer->asUser() : botForCommand()) {
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
App::sendBotCommand(peer, bot, _cmd);
return;
}
}
if (auto peer = Ui::getPeerForMouseAction()) { // old way
UserData *bot = peer->isUser() ? peer->asUser() : nullptr;
if (auto item = App::hoveredLinkItem()) {
if (!bot) {

View file

@ -193,6 +193,8 @@ private:
};
class PeerData;
class UserData;
class BotCommandClickHandler : public TextClickHandler {
public:
BotCommandClickHandler(const QString &cmd) : _cmd(cmd) {
@ -204,14 +206,30 @@ public:
return _cmd;
}
static void setPeerForCommand(PeerData *peer) {
_peer = peer;
}
static void setBotForCommand(UserData *bot) {
_bot = bot;
}
TextWithEntities getExpandedLinkTextWithEntities(ExpandLinksMode mode, int entityOffset, const QStringRef &textPart) const override;
protected:
QString url() const override {
return _cmd;
}
static PeerData *peerForCommand() {
return _peer;
}
static UserData *botForCommand() {
return _bot;
}
private:
QString _cmd;
static PeerData *_peer;
static UserData *_bot;
};

View file

@ -5034,7 +5034,7 @@ void HistoryWidget::onBroadcastSilentChange() {
}
void HistoryWidget::onShareContact(const PeerId &peer, UserData *contact) {
auto phone = contact->phone;
auto phone = contact->phone();
if (phone.isEmpty()) phone = App::phoneFromSharedContact(peerToUser(contact->id));
if (!contact || phone.isEmpty()) return;

View file

@ -50,7 +50,7 @@ IntroPhone::IntroPhone(IntroWidget *parent) : IntroStep(parent)
, country(this, st::introCountry)
, phone(this, st::inpIntroPhone)
, code(this, st::inpIntroCountryCode)
, _signup(this, lng_phone_notreg(lt_signup_start, textcmdStartLink(1), lt_signup_end, textcmdStopLink()), st::introErrLabel, st::introErrLabelTextStyle)
, _signup(this, lng_phone_notreg(lt_signup_start, textcmdStartLink(1), lt_signup_end, textcmdStopLink()), FlatLabel::InitType::Rich, st::introErrLabel, st::introErrLabelTextStyle)
, _showSignup(false)
, sentRequest(0) {
setVisible(false);

View file

@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "langloaderplain.h"
IntroStart::IntroStart(IntroWidget *parent) : IntroStep(parent)
, _intro(this, lang(lng_intro), st::introLabel, st::introLabelTextStyle)
, _intro(this, lang(lng_intro), FlatLabel::InitType::Rich, st::introLabel, st::introLabelTextStyle)
, _changeLang(this, QString())
, _next(this, lang(lng_start_msgs), st::btnIntroNext) {
_changeLang.hide();

View file

@ -3407,7 +3407,7 @@ namespace Local {
UserData *user = peer->asUser();
// first + last + phone + username + access
result += Serialize::stringSize(user->firstName) + Serialize::stringSize(user->lastName) + Serialize::stringSize(user->phone) + Serialize::stringSize(user->username) + sizeof(quint64);
result += Serialize::stringSize(user->firstName) + Serialize::stringSize(user->lastName) + Serialize::stringSize(user->phone()) + Serialize::stringSize(user->username) + sizeof(quint64);
// flags
if (AppVersion >= 9012) {
@ -3436,7 +3436,7 @@ namespace Local {
if (peer->isUser()) {
UserData *user = peer->asUser();
stream << user->firstName << user->lastName << user->phone << user->username << quint64(user->access);
stream << user->firstName << user->lastName << user->phone() << user->username << quint64(user->access);
if (AppVersion >= 9012) {
stream << qint32(user->flags);
}
@ -3490,6 +3490,7 @@ namespace Local {
QString pname = (showPhone && !phone.isEmpty()) ? App::formatPhone(phone) : QString();
if (!wasLoaded) {
user->setPhone(phone);
user->setNameDelayed(first, last, pname, username);
user->access = access;

View file

@ -4389,9 +4389,16 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateUserPhone: {
auto &d(update.c_updateUserPhone());
if (auto user = App::userLoaded(d.vuser_id.v)) {
user->setPhone(qs(d.vphone));
user->setNameDelayed(user->firstName, user->lastName, (user->contact || isServiceUser(user->id) || user->isSelf() || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), user->username);
App::markPeerUpdated(user);
auto newPhone = qs(d.vphone);
if (newPhone != user->phone()) {
user->setPhone(newPhone);
user->setNameDelayed(user->firstName, user->lastName, (user->contact || isServiceUser(user->id) || user->isSelf() || user->phone().isEmpty()) ? QString() : App::formatPhone(user->phone()), user->username);
App::markPeerUpdated(user);
Notify::PeerUpdate update(user);
update.flags |= Notify::PeerUpdateFlag::UserPhoneChanged;
Notify::peerUpdatedDelayed(update);
}
}
} break;

View file

@ -33,9 +33,11 @@ enum class PeerUpdateFlag {
NameChanged = 0x00000001U,
UsernameChanged = 0x00000002U,
PhotoChanged = 0x00000004U,
AboutChanged = 0x00000008U,
UserCanShareContact = 0x00010000U,
UserIsContact = 0x00020000U,
UserPhoneChanged = 0x00040000U,
ChatCanEdit = 0x00010000U,

View file

@ -37,7 +37,8 @@ profileFixedBarButton: flatButton(topBarButton) {
profileMarginTop: 13px;
profilePhotoSize: 112px;
profilePhotoLeft: 35px;
profilePhotoLeftMin: 18px;
profilePhotoLeftMax: 45px;
profilePhotoDuration: 500;
profileNameLeft: 26px;
profileNameTop: 9px;
@ -106,7 +107,28 @@ profileDividerFill: icon {
};
profileBlocksTop: 7px;
profileBlocksBottom: 20px;
profileBlockLeftMin: 8px;
profileBlockLeftMax: 25px;
profileBlockNarrowWidthMin: 220px;
profileBlockWideWidthMin: 300px;
profileBlockWideWidthMax: 340px;
profileBlockMarginTop: 21px;
profileBlockTitleFont: semiboldFont;
profileBlockMarginRight: 10px;
profileBlockMarginBottom: 4px;
profileBlockTitleHeight: 22px;
profileBlockTitleFont: font(14px semibold);
profileBlockTitleFg: black;
profileBlockTitlePosition: point(16px, profileBlockMarginTop);
profileBlockTitlePosition: point(24px, -7px);
profileBlockLabel: flatLabel(labelDefFlat) {
textFg: windowSubTextFg;
}
profileBlockTextPart: flatLabel(labelDefFlat) {
width: 180px;
margin: margins(5px, 5px, 5px, 5px);
}
profileBlockOneLineTextPart: flatLabel(profileBlockTextPart) {
width: 0px; // No need to set minWidth in one-line text.
maxHeight: 20px;
}
profileBlockOneLineSkip: 9px;

View file

@ -0,0 +1,40 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_actions_widget.h"
#include "styles/style_profile.h"
#include "lang.h"
namespace Profile {
ActionsWidget::ActionsWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_actions_section))
{
show();
}
int ActionsWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
} // namespace Profile

View file

@ -0,0 +1,37 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
namespace Profile {
class ActionsWidget : public BlockWidget {
public:
ActionsWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
} // namespace Profile

View file

@ -34,12 +34,18 @@ void BlockWidget::resizeToWidth(int newWidth) {
resize(newWidth, resizeGetHeight(newWidth));
}
int BlockWidget::contentTop() const {
return st::profileBlockMarginTop + st::profileBlockTitleHeight;
}
void BlockWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
p.setFont(st::profileBlockTitleFont);
p.setPen(st::profileBlockTitleFg);
p.drawText(st::profileBlockTitlePosition, _title);
int titleLeft = st::profileBlockTitlePosition.x();
int titleTop = st::profileBlockMarginTop + st::profileBlockTitlePosition.y();
p.drawTextLeft(titleLeft, titleTop, width(), _title);
paintContents(p);
}

View file

@ -35,14 +35,25 @@ public:
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
}
signals:
void heightUpdated();
protected:
void paintEvent(QPaintEvent *e) override;
virtual void paintContents(Painter &p) {
}
// Where does the block content start (after the title).
int contentTop() const;
// Resizes content and counts natural widget height for the desired width.
virtual int resizeGetHeight(int newWidth) = 0;
void contentSizeUpdated() {
resizeToWidth(width());
emit heightUpdated();
}
PeerData *peer() const {
return _peer;
}

View file

@ -80,7 +80,7 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
, _peerChannel(peer->asChannel())
, _peerMegagroup(peer->isMegagroup() ? _peerChannel : nullptr)
, _userpicButton(this, peer)
, _name(this, QString(), st::profileNameLabel) {
, _name(this, st::profileNameLabel) {
setAttribute(Qt::WA_OpaquePaintEvent);
setAcceptDrops(true);
@ -109,20 +109,23 @@ void CoverWidget::onPhotoShow() {
}
}
int CoverWidget::countPhotoLeft(int newWidth) const {
int result = st::profilePhotoLeftMin;
result += (newWidth - st::wndMinWidth) / 2;
return qMin(result, st::profilePhotoLeftMax);
}
void CoverWidget::resizeToWidth(int newWidth) {
int newHeight = 0;
newHeight += st::profileMarginTop;
_userpicButton->moveToLeft(st::profilePhotoLeft, newHeight);
_photoLeft = countPhotoLeft(newWidth);
_userpicButton->moveToLeft(_photoLeft, newHeight);
refreshNameGeometry(newWidth);
int infoLeft = _userpicButton->x() + _userpicButton->width();
int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left();
int nameTop = _userpicButton->y() + st::profileNameTop - st::profileNameLabel.margin.top();
_name.moveToLeft(nameLeft, nameTop);
int nameWidth = newWidth - infoLeft - st::profileNameLeft - st::profileButtonSkip;
nameWidth += st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right();
_name.resizeToWidth(nameWidth);
_statusPosition = QPoint(infoLeft + st::profileStatusLeft, _userpicButton->y() + st::profileStatusTop);
moveAndToggleButtons(newWidth);
@ -140,29 +143,43 @@ void CoverWidget::resizeToWidth(int newWidth) {
update();
}
void CoverWidget::refreshNameGeometry(int newWidth) {
int infoLeft = _userpicButton->x() + _userpicButton->width();
int nameLeft = infoLeft + st::profileNameLeft - st::profileNameLabel.margin.left();
int nameTop = _userpicButton->y() + st::profileNameTop - st::profileNameLabel.margin.top();
int nameWidth = newWidth - infoLeft - st::profileNameLeft - st::profileButtonSkip;
int marginsAdd = st::profileNameLabel.margin.left() + st::profileNameLabel.margin.right();
_name.resizeToWidth(qMin(nameWidth, _name.naturalWidth()) + marginsAdd);
_name.moveToLeft(nameLeft, nameTop);
}
// A more generic solution would be allowing an optional icon button
// for each text button. But currently we use only one, so it is done easily:
// There can be primary + secondary + icon buttons. If primary + secondary fit,
// then icon is hidden, otherwise secondary is hidden and icon is shown.
void CoverWidget::moveAndToggleButtons(int newWiddth) {
bool showNextButton = true;
int buttonLeft = st::profilePhotoLeft + _userpicButton->width() + st::profileButtonLeft;
int buttonLeft = _userpicButton->x() + _userpicButton->width() + st::profileButtonLeft;
int buttonsRight = newWiddth - st::profileButtonSkip;
for (int i = 0, count = _buttons.size(); i < count; ++i) {
auto button = _buttons.at(i);
button->moveToLeft(buttonLeft, st::profileButtonTop);
if (i == 1) {
// If second button is not fitting.
if (buttonLeft + button->width() > buttonsRight) {
button->hide();
auto &button = _buttons.at(i);
button.widget->moveToLeft(buttonLeft, st::profileButtonTop);
if (button.replacement) {
button.replacement->moveToLeft(buttonLeft, st::profileButtonTop);
if (buttonLeft + button.widget->width() > buttonsRight) {
button.widget->hide();
button.replacement->show();
buttonLeft += button.replacement->width() + st::profileButtonSkip;
} else {
button->show();
buttonLeft += button->width() + st::profileButtonSkip;
showNextButton = false;
button.widget->show();
button.replacement->hide();
buttonLeft += button.widget->width() + st::profileButtonSkip;
}
} else if (i == 1 && (buttonLeft + button.widget->width() > buttonsRight)) {
// If second button is not fitting.
button.widget->hide();
} else {
button->setVisible(showNextButton);
buttonLeft += button->width() + st::profileButtonSkip;
button.widget->show();
buttonLeft += button.widget->width() + st::profileButtonSkip;
}
}
}
@ -172,7 +189,7 @@ void CoverWidget::showFinished() {
}
bool CoverWidget::shareContactButtonShown() const {
return _peerUser && (_buttons.size() > 1) && !(_buttons.at(1)->isHidden());
return _peerUser && (_buttons.size() > 1) && !(_buttons.at(1).widget->isHidden());
}
void CoverWidget::paintEvent(QPaintEvent *e) {
@ -195,8 +212,7 @@ void CoverWidget::resizeDropArea() {
void CoverWidget::dropAreaHidden(CoverDropArea *dropArea) {
if (_dropArea == dropArea) {
_dropArea->deleteLater();
_dropArea = nullptr;
_dropArea.destroyDelayed();
}
}
@ -314,7 +330,7 @@ void CoverWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
void CoverWidget::refreshNameText() {
_name.setText(App::peerName(_peer));
update();
refreshNameGeometry(width());
}
void CoverWidget::refreshStatusText() {
@ -394,8 +410,7 @@ void CoverWidget::setUserButtons() {
void CoverWidget::setChatButtons() {
if (_peerChat->canEdit()) {
addButton(lang(lng_profile_set_group_photo), SLOT(onSetPhoto()));
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()));
addButton(st::profileAddMemberButton, SLOT(onAddMember()));
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()), &st::profileAddMemberButton);
}
}
@ -404,8 +419,7 @@ void CoverWidget::setMegagroupButtons() {
addButton(lang(lng_profile_set_group_photo), SLOT(onSetPhoto()));
}
if (_peerMegagroup->canAddParticipants()) {
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()));
addButton(st::profileAddMemberButton, SLOT(onAddMember()));
addButton(lang(lng_profile_add_participant), SLOT(onAddMember()), &st::profileAddMemberButton);
}
}
@ -422,21 +436,24 @@ void CoverWidget::setChannelButtons() {
void CoverWidget::clearButtons() {
auto buttons = createAndSwap(_buttons);
for_const (auto button, buttons) {
delete button;
delete button.widget;
delete button.replacement;
}
}
void CoverWidget::addButton(const QString &text, const char *slot) {
void CoverWidget::addButton(const QString &text, const char *slot, const style::BoxButton *replacementStyle) {
auto &buttonStyle = _buttons.isEmpty() ? st::profilePrimaryButton : st::profileSecondaryButton;
_buttons.push_back(new Ui::RoundButton(this, text, buttonStyle));
connect(_buttons.back(), SIGNAL(clicked()), this, slot);
_buttons.back()->show();
}
auto button = new Ui::RoundButton(this, text, buttonStyle);
connect(button, SIGNAL(clicked()), this, slot);
button->show();
void CoverWidget::addButton(const style::BoxButton &buttonStyle, const char *slot) {
_buttons.push_back(new Ui::RoundButton(this, QString(), buttonStyle));
connect(_buttons.back(), SIGNAL(clicked()), this, slot);
_buttons.back()->hide();
auto replacement = replacementStyle ? new Ui::RoundButton(this, QString(), *replacementStyle) : nullptr;
if (replacement) {
connect(replacement, SIGNAL(clicked()), this, slot);
replacement->hide();
}
_buttons.push_back({ button, replacement });
}
void CoverWidget::onSendMessage() {

View file

@ -75,6 +75,10 @@ private:
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void notifyFileQueryUpdated(const FileDialog::QueryUpdate &update);
// Counts userpic button left offset for a new widget width.
int countPhotoLeft(int newWidth) const;
void refreshNameGeometry(int newWidth);
void moveAndToggleButtons(int newWiddth);
void refreshNameText();
void refreshStatusText();
@ -87,8 +91,7 @@ private:
void setChannelButtons();
void clearButtons();
void addButton(const QString &text, const char *slot);
void addButton(const style::BoxButton &buttonStyle, const char *slot);
void addButton(const QString &text, const char *slot, const style::BoxButton *replacementStyle = nullptr);
void paintDivider(Painter &p);
@ -112,8 +115,13 @@ private:
QPoint _statusPosition;
QString _statusText;
QList<Ui::RoundButton*> _buttons;
struct Button {
Ui::RoundButton *widget;
Ui::RoundButton *replacement;
};
QList<Button> _buttons;
int _photoLeft = 0; // Caching countPhotoLeft() result.
int _dividerTop = 0;
FileDialog::QueryId _setPhotoFileQueryId = 0;

View file

@ -177,7 +177,7 @@ void FixedBar::onEditGroup() {
void FixedBar::onAddContact() {
auto firstName = _peerUser->firstName;
auto lastName = _peerUser->lastName;
auto phone = _peerUser->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(_peer->id)) : _peerUser->phone;
auto phone = _peerUser->phone().isEmpty() ? App::phoneFromSharedContact(peerToUser(_peer->id)) : _peerUser->phone();
Ui::showLayer(new AddContactBox(firstName, lastName, phone));
}
@ -223,8 +223,8 @@ void FixedBar::resizeToWidth(int newWidth) {
i->button->moveToLeft(buttonLeft, 0);
}
_backButton->moveToLeft(0, 0);
_backButton->resizeToWidth(newWidth);
_backButton->moveToLeft(0, 0);
newHeight += _backButton->height();
resize(newWidth, newHeight);

View file

@ -0,0 +1,217 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_info_widget.h"
#include "styles/style_profile.h"
#include "ui/flatlabel.h"
#include "core/click_handler_types.h"
#include "observer_peer.h"
#include "lang.h"
namespace Profile {
InfoWidget::InfoWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_info_section)) {
auto observeEvents = Notify::PeerUpdateFlag::AboutChanged
| Notify::PeerUpdateFlag::UsernameChanged
| Notify::PeerUpdateFlag::UserPhoneChanged
| Notify::PeerUpdateFlag::UserCanShareContact;
Notify::registerPeerObserver(observeEvents, this, &InfoWidget::notifyPeerUpdated);
refreshLabels();
}
void InfoWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) {
if (update.peer != peer()) {
return;
}
if (update.flags & Notify::PeerUpdateFlag::AboutChanged) {
refreshAbout();
}
if (update.flags & Notify::PeerUpdateFlag::UsernameChanged) {
refreshUsername();
refreshChannelLink();
}
if (update.flags & (Notify::PeerUpdateFlag::UserPhoneChanged | Notify::PeerUpdateFlag::UserCanShareContact)) {
refreshMobileNumber();
}
refreshVisibility();
contentSizeUpdated();
}
int InfoWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
int marginLeft = st::profileBlockTextPart.margin.left();
int marginRight = st::profileBlockTextPart.margin.right();
int left = st::profileBlockTitlePosition.x();
if (_about) {
int textWidth = _about->naturalWidth();
int availableWidth = newWidth - left - st::profileBlockMarginRight;
int maxWidth = st::msgMaxWidth;
accumulate_min(textWidth, availableWidth);
accumulate_min(textWidth, st::msgMaxWidth);
_about->resizeToWidth(textWidth + marginLeft + marginRight);
_about->moveToLeft(left - marginLeft, newHeight - st::profileBlockTextPart.margin.top());
newHeight += _about->height();
}
auto moveLabeledText = [&newHeight, left, newWidth, marginLeft, marginRight](FlatLabel *label, FlatLabel *text, FlatLabel *shortText) {
if (!label) return;
label->moveToLeft(left, newHeight);
int textLeft = left + label->width() + st::normalFont->spacew;
int textWidth = text->naturalWidth();
int availableWidth = newWidth - textLeft - st::profileBlockMarginRight;
bool doesNotFit = (textWidth > availableWidth);
accumulate_min(textWidth, availableWidth);
accumulate_min(textWidth, st::msgMaxWidth);
text->resizeToWidth(textWidth + marginLeft + marginRight);
text->moveToLeft(textLeft - marginLeft, newHeight - st::profileBlockOneLineTextPart.margin.top());
if (shortText) {
shortText->resizeToWidth(textWidth + marginLeft + marginRight);
shortText->moveToLeft(textLeft - marginLeft, newHeight - st::profileBlockOneLineTextPart.margin.top());
if (doesNotFit) {
shortText->show();
text->hide();
} else {
shortText->hide();
text->show();
}
}
newHeight += label->height() + st::profileBlockOneLineSkip;
};
moveLabeledText(_channelLinkLabel, _channelLink, _channelLinkShort);
moveLabeledText(_mobileNumberLabel, _mobileNumber, nullptr);
moveLabeledText(_usernameLabel, _username, nullptr);
newHeight += st::profileBlockMarginBottom;
return newHeight;
}
void InfoWidget::leaveEvent(QEvent *e) {
BotCommandClickHandler::setPeerForCommand(nullptr);
BotCommandClickHandler::setBotForCommand(nullptr);
}
void InfoWidget::refreshLabels() {
refreshAbout();
refreshMobileNumber();
refreshUsername();
refreshChannelLink();
refreshVisibility();
}
void InfoWidget::refreshVisibility() {
setVisible(_about || _mobileNumber || _username || _channelLink);
}
void InfoWidget::refreshAbout() {
auto getAboutText = [this]() -> QString {
if (auto user = peer()->asUser()) {
return user->about();
} else if (auto channel = peer()->asChannel()) {
return channel->about();
}
return QString();
};
_about.destroy();
auto aboutText = getAboutText();
if (!aboutText.isEmpty()) {
_about = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::profileBlockTextPart);
_about->show();
EntitiesInText aboutEntities;
textParseEntities(aboutText, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &aboutEntities);
_about->setMarkedText({ aboutText, aboutEntities });
_about->setSelectable(true);
_about->setClickHandlerHook(func(this, &InfoWidget::aboutClickHandlerHook));
}
}
bool InfoWidget::aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button) {
BotCommandClickHandler::setPeerForCommand(peer());
return true;
}
void InfoWidget::refreshMobileNumber() {
TextWithEntities phoneText;
if (auto user = peer()->asUser()) {
if (!user->phone().isEmpty()) {
phoneText.text = App::formatPhone(user->phone());
} else {
phoneText.text = App::phoneFromSharedContact(peerToUser(user->id));
}
}
setLabeledText(&_mobileNumberLabel, lang(lng_profile_mobile_number), &_mobileNumber, phoneText, lang(lng_profile_copy_phone));
}
void InfoWidget::refreshUsername() {
TextWithEntities usernameText;
if (auto user = peer()->asUser()) {
if (!user->username.isEmpty()) {
usernameText.text = '@' + user->username;
}
}
setLabeledText(&_usernameLabel, lang(lng_profile_username), &_username, usernameText, lang(lng_context_copy_mention));
}
void InfoWidget::refreshChannelLink() {
TextWithEntities channelLinkText;
TextWithEntities channelLinkTextShort;
if (auto channel = peer()->asChannel()) {
if (!channel->username.isEmpty()) {
channelLinkText.text = qsl("https://telegram.me/") + channel->username;
channelLinkText.entities.push_back(EntityInText(EntityInTextUrl, 0, channelLinkText.text.size()));
channelLinkTextShort.text = qsl("telegram.me/") + channel->username;
channelLinkTextShort.entities.push_back(EntityInText(EntityInTextCustomUrl, 0, channelLinkTextShort.text.size(), qsl("https://telegram.me/") + channel->username));
}
}
setLabeledText(nullptr, lang(lng_profile_link), &_channelLink, channelLinkText, QString());
setLabeledText(&_channelLinkLabel, lang(lng_profile_link), &_channelLinkShort, channelLinkTextShort, QString());
if (_channelLinkShort) {
_channelLinkShort->setExpandLinksMode(ExpandLinksUrlOnly);
}
}
void InfoWidget::setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText) {
if (labelWidget) labelWidget->destroy();
textWidget->destroy();
if (textWithEntities.text.isEmpty()) return;
if (labelWidget) {
*labelWidget = new FlatLabel(this, label, FlatLabel::InitType::Simple, st::profileBlockLabel);
(*labelWidget)->show();
}
*textWidget = new FlatLabel(this, QString(), FlatLabel::InitType::Simple, st::profileBlockOneLineTextPart);
(*textWidget)->show();
(*textWidget)->setMarkedText(textWithEntities);
(*textWidget)->setContextCopyText(copyText);
(*textWidget)->setSelectable(true);
(*textWidget)->setDoubleClickSelectsParagraph(true);
}
} // namespace Profile

View file

@ -0,0 +1,72 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
#include "core/observer.h"
class FlatLabel;
namespace Notify {
struct PeerUpdate;
} // namespace Notify
namespace Profile {
class InfoWidget : public BlockWidget, public Notify::Observer {
public:
InfoWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
void leaveEvent(QEvent *e) override;
private:
// Observed notifications.
void notifyPeerUpdated(const Notify::PeerUpdate &update);
void refreshLabels();
void refreshAbout();
void refreshMobileNumber();
void refreshUsername();
void refreshChannelLink();
void refreshVisibility();
bool aboutClickHandlerHook(const ClickHandlerPtr &handler, Qt::MouseButton button);
// labelWidget may be nullptr.
void setLabeledText(ChildWidget<FlatLabel> *labelWidget, const QString &label,
ChildWidget<FlatLabel> *textWidget, const TextWithEntities &textWithEntities, const QString &copyText);
ChildWidget<FlatLabel> _about = { nullptr };
ChildWidget<FlatLabel> _channelLinkLabel = { nullptr };
ChildWidget<FlatLabel> _channelLink = { nullptr };
ChildWidget<FlatLabel> _channelLinkShort = { nullptr };
ChildWidget<FlatLabel> _mobileNumberLabel = { nullptr };
ChildWidget<FlatLabel> _mobileNumber = { nullptr };
ChildWidget<FlatLabel> _usernameLabel = { nullptr };
ChildWidget<FlatLabel> _username = { nullptr };
};
} // namespace Profile

View file

@ -23,6 +23,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "styles/style_profile.h"
#include "profile/profile_cover.h"
#include "profile/profile_info_widget.h"
#include "profile/profile_settings_widget.h"
#include "profile/profile_invite_link_widget.h"
#include "profile/profile_shared_media_widget.h"
#include "profile/profile_actions_widget.h"
#include "profile/profile_members_widget.h"
#include "apiwrap.h"
namespace Profile {
@ -31,6 +37,33 @@ InnerWidget::InnerWidget(QWidget *parent, PeerData *peer) : TWidget(parent)
, _peer(peer)
, _cover(this, peer) {
setAttribute(Qt::WA_OpaquePaintEvent);
createBlocks();
}
void InnerWidget::createBlocks() {
auto user = _peer->asUser();
auto chat = _peer->asChat();
auto channel = _peer->asChannel();
auto megagroup = _peer->isMegagroup() ? channel : nullptr;
if (user || channel || megagroup) {
_blocks.push_back({ new InfoWidget(this, _peer), BlockSide::Right });
}
_blocks.push_back({ new SettingsWidget(this, _peer), BlockSide::Right });
if (chat || channel || megagroup) {
_blocks.push_back({ new InviteLinkWidget(this, _peer), BlockSide::Right });
}
_blocks.push_back({ new SharedMediaWidget(this, _peer), BlockSide::Right });
_blocks.push_back({ new ActionsWidget(this, _peer), BlockSide::Right });
if (channel && !megagroup) {
_blocks.push_back({ new ChannelMembersWidget(this, _peer), BlockSide::Right });
}
if (chat || megagroup) {
_blocks.push_back({ new MembersWidget(this, _peer), BlockSide::Left });
}
for_const (auto &blockData, _blocks) {
connect(blockData.block, SIGNAL(heightUpdated()), this, SLOT(onBlockHeightUpdated()));
}
}
void InnerWidget::resizeToWidth(int newWidth, int minHeight) {
@ -45,7 +78,7 @@ void InnerWidget::setVisibleTopBottom(int visibleTop, int visibleBottom) {
int notDisplayedAtBottom = height() - _visibleBottom;
if (notDisplayedAtBottom > 0) {
// decreaseAdditionalHeight(notDisplayedAtBottom); // testing
decreaseAdditionalHeight(notDisplayedAtBottom);
}
//loadProfilePhotos(_visibleTop);
@ -72,6 +105,16 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
p.fillRect(e->rect(), st::profileBg);
if (_mode == Mode::TwoColumn) {
int leftHeight = countBlocksHeight(BlockSide::Left);
int rightHeight = countBlocksHeight(BlockSide::Right);
int minHeight = qMin(leftHeight, rightHeight);
int shadowLeft = _blocksLeft + _leftColumnWidth + _columnDivider;
int shadowTop = _blocksTop + st::profileBlockMarginTop;
p.fillRect(rtlrect(shadowLeft, shadowTop, st::lineWidth, minHeight - st::profileBlockMarginTop, width()), st::shadowColor);
}
}
void InnerWidget::keyPressEvent(QKeyEvent *e) {
@ -80,11 +123,134 @@ void InnerWidget::keyPressEvent(QKeyEvent *e) {
}
}
int InnerWidget::countBlocksHeight(BlockSide countSide) const {
int result = 0;
for_const (auto &blockData, _blocks) {
if (blockData.side != countSide || blockData.block->isHidden()) {
continue;
}
result += blockData.block->height();
}
return result;
}
int InnerWidget::countBlocksLeft(int newWidth) const {
int result = st::profileBlockLeftMin;
result += (newWidth - st::wndMinWidth) / 2;
return qMin(result, st::profileBlockLeftMax);
}
InnerWidget::Mode InnerWidget::countBlocksMode(int newWidth) const {
bool hasLeftWidget = false, hasRightWidget = false;
for_const (auto &blockData, _blocks) {
if (!blockData.block->isHidden()) {
if (blockData.side == BlockSide::Left) {
hasLeftWidget = true;
} else {
hasRightWidget = true;
}
}
}
if (!hasLeftWidget || !hasRightWidget) {
return Mode::OneColumn;
}
int availWidth = newWidth - _blocksLeft;
if (availWidth >= st::profileBlockWideWidthMin + _columnDivider + st::profileBlockNarrowWidthMin) {
return Mode::TwoColumn;
}
return Mode::OneColumn;
}
int InnerWidget::countLeftColumnWidth(int newWidth) const {
int result = st::profileBlockWideWidthMin;
int availWidth = newWidth - _blocksLeft;
int additionalWidth = (availWidth - st::profileBlockWideWidthMin - _columnDivider - st::profileBlockNarrowWidthMin);
if (additionalWidth > 0) {
result += (additionalWidth / 2);
accumulate_min(result, st::profileBlockWideWidthMax);
}
return result;
}
void InnerWidget::refreshBlocksPositions() {
auto layoutBlocks = [this](BlockSide layoutSide, int left) {
int top = _blocksTop;
for_const (auto &blockData, _blocks) {
if (_mode == Mode::TwoColumn && blockData.side != layoutSide) {
continue;
}
if (blockData.block->isHidden()) {
continue;
}
blockData.block->moveToLeft(left, top);
top += blockData.block->height();
}
};
layoutBlocks(BlockSide::Left, _blocksLeft);
if (_mode == Mode::TwoColumn) {
layoutBlocks(BlockSide::Right, _blocksLeft + _leftColumnWidth + _columnDivider);
}
}
void InnerWidget::resizeBlocks(int newWidth) {
for_const (auto &blockData, _blocks) {
int blockWidth = newWidth - _blocksLeft;
if (_mode == Mode::OneColumn) {
blockWidth -= _blocksLeft;
} else {
if (blockData.side == BlockSide::Left) {
blockWidth = _leftColumnWidth;
} else {
blockWidth -= _leftColumnWidth + _columnDivider;
}
}
blockData.block->resizeToWidth(blockWidth);
}
}
int InnerWidget::resizeGetHeight(int newWidth) {
_cover->resizeToWidth(newWidth);
_blocksTop = _cover->y() + _cover->height() + st::profileBlocksTop;
_blocksLeft = countBlocksLeft(newWidth);
_columnDivider = _blocksLeft;
_mode = countBlocksMode(newWidth);
_leftColumnWidth = countLeftColumnWidth(newWidth);
resizeBlocks(newWidth);
refreshBlocksPositions();
update();
return countHeight();
}
int InnerWidget::countHeight() const {
int newHeight = _cover->height();
int leftHeight = countBlocksHeight(BlockSide::Left);
int rightHeight = countBlocksHeight(BlockSide::Right);
int blocksHeight = (_mode == Mode::OneColumn) ? (leftHeight + rightHeight) : qMax(leftHeight, rightHeight);
newHeight += st::profileBlocksTop + blocksHeight + st::profileBlocksBottom;
return newHeight;
}
void InnerWidget::onBlockHeightUpdated() {
refreshBlocksPositions();
int naturalHeight = countHeight();
int notDisplayedAtBottom = naturalHeight - _visibleBottom;
if (notDisplayedAtBottom < 0) {
_addedHeight = -notDisplayedAtBottom;
} else {
_addedHeight = 0;
}
if (naturalHeight + _addedHeight != height()) {
resize(width(), naturalHeight + _addedHeight);
}
}
} // namespace Profile

View file

@ -51,14 +51,37 @@ public:
signals:
void cancelled();
private slots:
void onBlockHeightUpdated();
protected:
void paintEvent(QPaintEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void createBlocks();
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth);
// Counts the natural widget height after resizing of child widgets.
int countHeight() const;
enum class Mode {
OneColumn,
TwoColumn,
};
enum class BlockSide {
Left,
Right,
};
int countBlocksLeft(int newWidth) const;
Mode countBlocksMode(int newWidth) const;
int countLeftColumnWidth(int newWidth) const;
int countBlocksHeight(BlockSide countSide) const;
void resizeBlocks(int newWidth);
void refreshBlocksPositions();
// Sometimes height of this widget is larger than it is required
// so that it is allowed to scroll down to the desired position.
// When resizing with scroll moving up the additional height may be decreased.
@ -73,8 +96,18 @@ private:
int _visibleBottom = 0;
ChildWidget<CoverWidget> _cover;
QList<BlockWidget*> _blocks;
int _blocksLeft = 0; // Caching countBlocksLeft() result.
int _blocksTop = 0;
int _columnDivider = 0;
int _leftColumnWidth = 0; // Caching countLeftColumnWidth() result.
struct Block {
BlockWidget *block;
BlockSide side;
};
QList<Block> _blocks;
Mode _mode = Mode::OneColumn;
};
} // namespace Profile

View file

@ -0,0 +1,40 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_invite_link_widget.h"
#include "styles/style_profile.h"
#include "lang.h"
namespace Profile {
InviteLinkWidget::InviteLinkWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_invite_link_section))
{
show();
}
int InviteLinkWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
} // namespace Profile

View file

@ -0,0 +1,37 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
namespace Profile {
class InviteLinkWidget : public BlockWidget {
public:
InviteLinkWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
} // namespace Profile

View file

@ -0,0 +1,51 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_members_widget.h"
#include "styles/style_profile.h"
#include "lang.h"
namespace Profile {
MembersWidget::MembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section))
{
show();
}
int MembersWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
ChannelMembersWidget::ChannelMembersWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_participants_section))
{
show();
}
int ChannelMembersWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
} // namespace Profile

View file

@ -0,0 +1,47 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
namespace Profile {
class MembersWidget : public BlockWidget {
public:
MembersWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
class ChannelMembersWidget : public BlockWidget {
public:
ChannelMembersWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
} // namespace Profile

View file

@ -0,0 +1,40 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_settings_widget.h"
#include "styles/style_profile.h"
#include "lang.h"
namespace Profile {
SettingsWidget::SettingsWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_settings_section))
{
show();
}
int SettingsWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
} // namespace Profile

View file

@ -0,0 +1,37 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
namespace Profile {
class SettingsWidget : public BlockWidget {
public:
SettingsWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
} // namespace Profile

View file

@ -0,0 +1,40 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#include "stdafx.h"
#include "profile/profile_shared_media_widget.h"
#include "styles/style_profile.h"
#include "lang.h"
namespace Profile {
SharedMediaWidget::SharedMediaWidget(QWidget *parent, PeerData *peer) : BlockWidget(parent, peer, lang(lng_profile_shared_media))
{
show();
}
int SharedMediaWidget::resizeGetHeight(int newWidth) {
int newHeight = contentTop();
return newHeight;
}
} // namespace Profile

View file

@ -0,0 +1,37 @@
/*
This file is part of Telegram Desktop,
the official desktop version of Telegram messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
In addition, as a special exception, the copyright holders give permission
to link the code of portions of this program with the OpenSSL library.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "profile/profile_block_widget.h"
namespace Profile {
class SharedMediaWidget : public BlockWidget {
public:
SharedMediaWidget(QWidget *parent, PeerData *peer);
protected:
// Resizes content and counts natural widget height for the desired width.
int resizeGetHeight(int newWidth) override;
};
} // namespace Profile

View file

@ -115,7 +115,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, PeerData *peer) : TWidget(0)
if (_peerUser->blocked == UserIsBlocked) {
_blockUser.setText(lang(_peerUser->botInfo ? lng_profile_unblock_bot : lng_profile_unblock_user));
}
_phoneText = App::formatPhone(_peerUser->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(_peerUser->id)) : _peerUser->phone);
_phoneText = App::formatPhone(_peerUser->phone().isEmpty() ? App::phoneFromSharedContact(peerToUser(_peerUser->id)) : _peerUser->phone());
PhotoData *userPhoto = (_peerUser->photoId && _peerUser->photoId != UnknownPeerPhotoId) ? App::photo(_peerUser->photoId) : 0;
if (userPhoto && userPhoto->date) {
_photoLink.reset(new PhotoOpenClickHandler(userPhoto, _peer));
@ -168,7 +168,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, PeerData *peer) : TWidget(0)
QString maxStr;
if (_peerUser->botInfo && !_peerUser->botInfo->cantJoinGroups) {
maxStr = lang(_sendMessage.textWidth() > _inviteToGroup.textWidth() ? lng_profile_send_message : lng_profile_invite_to_group);
} else if (!_peerUser->phone.isEmpty()) {
} else if (!_peerUser->phone().isEmpty()) {
maxStr = lang(_sendMessage.textWidth() > _shareContact.textWidth() ? lng_profile_send_message : lng_profile_share_contact);
} else {
maxStr = lang(lng_profile_send_message);
@ -193,13 +193,13 @@ ProfileInner::ProfileInner(ProfileWidget *profile, PeerData *peer) : TWidget(0)
// about
if (_peerUser) {
if (!_peerUser->about.isEmpty()) {
_about.setText(st::linkFont, _peerUser->about, _peerUser->botInfo ? _historyBotNoMonoOptions : _historyTextNoMonoOptions);
if (!_peerUser->about().isEmpty()) {
_about.setText(st::linkFont, _peerUser->about(), _peerUser->botInfo ? _historyBotNoMonoOptions : _historyTextNoMonoOptions);
}
updateBotLinksVisibility();
} else {
if (_peerChannel && !_peerChannel->about.isEmpty()) {
_about.setText(st::linkFont, _peerChannel->about, _historyTextNoMonoOptions);
if (_peerChannel && !_peerChannel->about().isEmpty()) {
_about.setText(st::linkFont, _peerChannel->about(), _historyTextNoMonoOptions);
}
_botSettings.hide();
_botHelp.hide();
@ -538,10 +538,10 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
_photoLink.clear();
}
if (_peerUser) {
if (_peerUser->about.isEmpty()) {
if (_peerUser->about().isEmpty()) {
_about = Text(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right());
} else {
_about.setText(st::linkFont, _peerUser->about, _peerUser->botInfo ? _historyBotNoMonoOptions : _historyTextNoMonoOptions);
_about.setText(st::linkFont, _peerUser->about(), _peerUser->botInfo ? _historyBotNoMonoOptions : _historyTextNoMonoOptions);
}
updateBotLinksVisibility();
resizeEvent(0);
@ -557,10 +557,10 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
_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 = (_peerChannel->count > 0) ? lng_chat_status_members(lt_count, _peerChannel->count) : lang(_peerChannel->isMegagroup() ? lng_group_status : lng_channel_status);
if (_peerChannel->about.isEmpty()) {
if (_peerChannel->about().isEmpty()) {
_about = Text(st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right());
} else {
_about.setText(st::linkFont, _peerChannel->about, _historyTextNoMonoOptions);
_about.setText(st::linkFont, _peerChannel->about(), _historyTextNoMonoOptions);
}
showAll();
resizeEvent(0);
@ -607,7 +607,7 @@ void ProfileInner::peerUpdated(PeerData *data) {
if (data == _peer) {
PhotoData *photo = 0;
if (_peerUser) {
_phoneText = App::formatPhone(_peerUser->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(_peerUser->id)) : _peerUser->phone);
_phoneText = App::formatPhone(_peerUser->phone().isEmpty() ? App::phoneFromSharedContact(peerToUser(_peerUser->id)) : _peerUser->phone());
if (_peerUser->photoId && _peerUser->photoId != UnknownPeerPhotoId) photo = App::photo(_peerUser->photoId);
if (_wasBlocked != _peerUser->blocked) {
_wasBlocked = _peerUser->blocked;
@ -1668,7 +1668,7 @@ void ProfileInner::showAll() {
_createInvitationLink.hide();
_invitationLink.hide();
_sendMessage.show();
if (_peerUser->phone.isEmpty()) {
if (_peerUser->phone().isEmpty()) {
_shareContact.hide();
if (_peerUser->botInfo && !_peerUser->botInfo->cantJoinGroups) {
_inviteToGroup.show();
@ -1950,7 +1950,7 @@ void ProfileWidget::paintTopBar(Painter &p, float64 over, int32 decreaseWidth) {
p.drawSprite(QPoint(st::topBarBackPadding.left(), (st::topBarHeight - st::topBarBackImg.pxHeight()) / 2), st::topBarBackImg);
p.setFont(st::topBarBackFont->f);
p.setPen(st::topBarBackColor->p);
p.drawText(st::topBarBackPadding.left() + st::topBarBackImg.pxWidth() + st::topBarBackPadding.right(), (st::topBarHeight - st::topBarBackFont->height) / 2 + st::topBarBackFont->ascent, lang(peer()->isUser() ? lng_profile_info : ((peer()->isChat() || peer()->isMegagroup()) ? lng_profile_group_info : lng_profile_channel_info)));
// p.drawText(st::topBarBackPadding.left() + st::topBarBackImg.pxWidth() + st::topBarBackPadding.right(), (st::topBarHeight - st::topBarBackFont->height) / 2 + st::topBarBackFont->ascent, lang(peer()->isUser() ? lng_profile_info : ((peer()->isChat() || peer()->isMegagroup()) ? lng_profile_group_info : lng_profile_channel_info)));
}
void ProfileWidget::topBarClick() {

View file

@ -123,7 +123,7 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent)
, _a_photo(animation(this, &SettingsInner::step_photo))
// contact info
, _phoneText(self() ? App::formatPhone(self()->phone) : QString())
, _phoneText(self() ? App::formatPhone(self()->phone()) : QString())
, _chooseUsername(this, (self() && !self()->username.isEmpty()) ? ('@' + self()->username) : lang(lng_settings_choose_username))
// notifications

View file

@ -262,6 +262,18 @@ void PeerData::fillNames() {
}
}
bool UserData::setAbout(const QString &newAbout) {
if (_about == newAbout) {
return false;
}
_about = newAbout;
Notify::PeerUpdate update(this);
update.flags |= Notify::PeerUpdateFlag::AboutChanged;
Notify::peerUpdatedDelayed(update);
return true;
}
void UserData::setName(const QString &newFirstName, const QString &newLastName, const QString &newPhoneName, const QString &newUsername) {
setNameDelayed(newFirstName, newLastName, newPhoneName, newUsername);
Notify::peerUpdatedSendDelayed();
@ -286,7 +298,7 @@ void UserData::setNameDelayed(const QString &newFirstName, const QString &newLas
}
void UserData::setPhone(const QString &newPhone) {
phone = newPhone;
_phone = newPhone;
}
void UserData::setBotInfoVersion(int version) {
@ -480,6 +492,18 @@ void ChannelData::fullUpdated() {
_lastFullUpdate = getms(true);
}
bool ChannelData::setAbout(const QString &newAbout) {
if (_about == newAbout) {
return false;
}
_about = newAbout;
Notify::PeerUpdate update(this);
update.flags |= Notify::PeerUpdateFlag::AboutChanged;
Notify::peerUpdatedDelayed(update);
return true;
}
void ChannelData::flagsUpdated() {
if (isMegagroup()) {
if (!mgInfo) {

View file

@ -442,7 +442,7 @@ public:
// When actually trying to share contact we perform
// a full check by canShareThisContact() call.
bool canShareThisContactFast() const {
return !phone.isEmpty();
return !_phone.isEmpty();
}
MTPInputUser inputUser;
@ -450,7 +450,9 @@ public:
QString firstName;
QString lastName;
QString username;
QString phone;
const QString &phone() const {
return _phone;
}
QString nameOrPhone;
Text phoneText;
TimeId onlineTill = 0;
@ -461,7 +463,10 @@ public:
Photos photos;
int photosCount = -1; // -1 not loaded, 0 all loaded
QString about;
bool setAbout(const QString &newAbout);
const QString &about() const {
return _about;
}
BotInfo *botInfo = nullptr;
@ -474,6 +479,8 @@ public:
private:
QString _restrictionReason;
QString _about;
QString _phone;
};
@ -669,7 +676,13 @@ public:
MTPinputChannel inputChannel;
QString username, about;
QString username;
// Returns true if about text was changed.
bool setAbout(const QString &newAbout);
const QString &about() const {
return _about;
}
int count = 1;
int adminsCount = 1;
@ -791,11 +804,11 @@ public:
~ChannelData();
private:
PtsWaiter _ptsWaiter;
uint64 _lastFullUpdate = 0;
QString _restrictionReason;
QString _about;
};

View file

@ -2472,9 +2472,9 @@ void PhoneInput::focusInEvent(QFocusEvent *e) {
void PhoneInput::clearText() {
QString phone;
if (App::self()) {
QVector<int> newPattern = phoneNumberParse(App::self()->phone);
QVector<int> newPattern = phoneNumberParse(App::self()->phone());
if (!newPattern.isEmpty()) {
phone = App::self()->phone.mid(0, newPattern.at(0));
phone = App::self()->phone().mid(0, newPattern.at(0));
}
}
setText(phone);

View file

@ -31,11 +31,36 @@ namespace {
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
TextParseOptions _labelMarkedOptions = {
TextParseMultiline | TextParseLinks | TextParseHashtags | TextParseMentions | TextParseBotCommands, // flags
0, // maxw
0, // maxh
Qt::LayoutDirectionAuto, // dir
};
}
FlatLabel::FlatLabel(QWidget *parent, const QString &text, const style::flatLabel &st, const style::textStyle &tst) : TWidget(parent),
_text(st.width ? st.width : QFIXED_MAX), _st(st), _tst(tst), _opacity(1) {
setRichText(text);
FlatLabel::FlatLabel(QWidget *parent, const style::flatLabel &st, const style::textStyle &tst) : TWidget(parent)
, _text(st.width ? st.width : QFIXED_MAX)
, _st(st)
, _tst(tst)
, _contextCopyText(lang(lng_context_copy_text)) {
init();
}
FlatLabel::FlatLabel(QWidget *parent, const QString &text, InitType initType, const style::flatLabel &st, const style::textStyle &tst) : TWidget(parent)
, _text(st.width ? st.width : QFIXED_MAX)
, _st(st)
, _tst(tst)
, _contextCopyText(lang(lng_context_copy_text)) {
if (initType == InitType::Rich) {
setRichText(text);
} else {
setText(text);
}
init();
}
void FlatLabel::init() {
_trippleClickTimer.setSingleShot(true);
_touchSelectTimer.setSingleShot(true);
@ -58,15 +83,31 @@ void FlatLabel::setRichText(const QString &text) {
setMouseTracking(_selectable || _text.hasLinks());
}
void FlatLabel::setMarkedText(const TextWithEntities &textWithEntities) {
textstyleSet(&_tst);
_text.setMarkedText(_st.font, textWithEntities, _labelMarkedOptions);
refreshSize();
textstyleRestore();
setMouseTracking(_selectable || _text.hasLinks());
}
void FlatLabel::setSelectable(bool selectable) {
_selectable = selectable;
setMouseTracking(_selectable || _text.hasLinks());
}
void FlatLabel::setDoubleClickSelectsParagraph(bool doubleClickSelectsParagraph) {
_doubleClickSelectsParagraph = doubleClickSelectsParagraph;
}
void FlatLabel::setContextCopyText(const QString &copyText) {
_contextCopyText = copyText;
}
void FlatLabel::setExpandLinksMode(ExpandLinksMode mode) {
_contextExpandLinksMode = mode;
}
void FlatLabel::resizeToWidth(int32 width) {
textstyleSet(&_tst);
_allowedWidth = width;
@ -74,6 +115,10 @@ void FlatLabel::resizeToWidth(int32 width) {
textstyleRestore();
}
int FlatLabel::naturalWidth() const {
return _text.maxWidth();
}
int FlatLabel::countTextWidth() const {
return _allowedWidth ? (_allowedWidth - _st.margin.left() - _st.margin.right()) : (_st.width ? _st.width : _text.maxWidth());
}
@ -95,6 +140,10 @@ void FlatLabel::setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk) {
_text.setLink(lnkIndex, lnk);
}
void FlatLabel::setClickHandlerHook(ClickHandlerHook &&hook) {
_clickHandlerHook = std_::move(hook);
}
void FlatLabel::mouseMoveEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos();
dragActionUpdate();
@ -177,7 +226,9 @@ Text::StateResult FlatLabel::dragActionFinish(const QPoint &p, Qt::MouseButton b
_selectionType = TextSelectType::Letters;
if (activated) {
App::activateClickHandler(activated, button);
if (_clickHandlerHook.isNull() || _clickHandlerHook.call(activated, button)) {
App::activateClickHandler(activated, button);
}
}
return state;
}
@ -194,7 +245,7 @@ void FlatLabel::mouseDoubleClickEvent(QMouseEvent *e) {
if (((_dragAction == Selecting) || (_dragAction == NoDrag)) && _selectionType == TextSelectType::Letters) {
if (state.uponSymbol) {
_dragSymbol = state.symbol;
_selectionType = TextSelectType::Words;
_selectionType = _doubleClickSelectsParagraph ? TextSelectType::Paragraphs : TextSelectType::Words;
if (_dragAction == NoDrag) {
_dragAction = Selecting;
_selection = { state.symbol, state.symbol };
@ -219,7 +270,9 @@ void FlatLabel::leaveEvent(QEvent *e) {
void FlatLabel::focusOutEvent(QFocusEvent *e) {
if (!_selection.empty()) {
_savedSelection = _selection;
if (_contextMenu) {
_savedSelection = _selection;
}
_selection = { 0, 0 };
update();
}
@ -338,12 +391,12 @@ void FlatLabel::showContextMenu(QContextMenuEvent *e, ContextMenuReason reason)
_contextMenuClickHandler = ClickHandler::getActive();
if (fullSelection) {
_contextMenu->addAction(contextCopyText(), this, SLOT(onCopyContextText()))->setEnabled(true);
} else if (uponSelection) {
if (fullSelection && !_contextCopyText.isEmpty()) {
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()))->setEnabled(true);
} else if (uponSelection && !fullSelection) {
_contextMenu->addAction(lang(lng_context_copy_selected), this, SLOT(onCopySelectedText()))->setEnabled(true);
} else if (!hasSelection) {
_contextMenu->addAction(contextCopyText(), this, SLOT(onCopyContextText()))->setEnabled(true);
} else if (!hasSelection && !_contextCopyText.isEmpty()) {
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()))->setEnabled(true);
}
QString linkCopyToClipboardText = _contextMenuClickHandler ? _contextMenuClickHandler->copyToClipboardContextItemText() : QString();
@ -361,19 +414,15 @@ void FlatLabel::showContextMenu(QContextMenuEvent *e, ContextMenuReason reason)
}
}
QString FlatLabel::contextCopyText() const {
return _contextCopyText.isEmpty() ? lang(lng_context_copy_text) : _contextCopyText;
}
void FlatLabel::onCopySelectedText() {
auto selection = _selection.empty() ? (_contextMenu ? _savedSelection : _selection) : _selection;
if (!selection.empty()) {
QApplication::clipboard()->setText(_text.originalText(selection, ExpandLinksAll));
QApplication::clipboard()->setText(_text.originalText(selection, _contextExpandLinksMode));
}
}
void FlatLabel::onCopyContextText() {
QApplication::clipboard()->setText(_text.originalText({ 0, 0xFFFF }, ExpandLinksAll));
QApplication::clipboard()->setText(_text.originalText({ 0, 0xFFFF }, _contextExpandLinksMode));
}
void FlatLabel::onCopyContextUrl() {
@ -514,7 +563,7 @@ Text::StateResult FlatLabel::getTextState(const QPoint &m) const {
textstyleSet(&_tst);
Text::StateResult state;
if (_st.maxHeight && _st.maxHeight < _fullTextHeight) {
if (_st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth())) {
auto lineHeight = qMax(_tst.lineHeight, _st.font->height);
request.lines = qMax(_st.maxHeight / lineHeight, 1);
state = _text.getStateElided(m.x() - _st.margin.left(), m.y() - _st.margin.top(), textWidth, request);
@ -538,7 +587,7 @@ void FlatLabel::paintEvent(QPaintEvent *e) {
textstyleSet(&_tst);
int textWidth = width() - _st.margin.left() - _st.margin.right();
auto selection = _selection.empty() ? (_contextMenu ? _savedSelection : _selection) : _selection;
if (_st.maxHeight && _st.maxHeight < _fullTextHeight) {
if (_st.maxHeight && (_st.maxHeight < _fullTextHeight || textWidth < _text.maxWidth())) {
auto lineHeight = qMax(_tst.lineHeight, _st.font->height);
auto lines = qMax(_st.maxHeight / lineHeight, 1);
_text.drawElided(p, _st.margin.left(), _st.margin.top(), textWidth, lines, _st.align, e->rect().y(), e->rect().bottom(), 0, false, selection);

View file

@ -24,19 +24,32 @@ class FlatLabel : public TWidget, public ClickHandlerHost {
Q_OBJECT
public:
FlatLabel(QWidget *parent, const QString &text, const style::flatLabel &st = st::labelDefFlat, const style::textStyle &tst = st::defaultTextStyle);
FlatLabel(QWidget *parent, const style::flatLabel &st = st::labelDefFlat, const style::textStyle &tst = st::defaultTextStyle);
enum class InitType {
Simple,
Rich,
};
FlatLabel(QWidget *parent, const QString &text, InitType initType, const style::flatLabel &st = st::labelDefFlat, const style::textStyle &tst = st::defaultTextStyle);
void setOpacity(float64 o);
void setText(const QString &text);
void setRichText(const QString &text);
void setMarkedText(const TextWithEntities &textWithEntities);
void setSelectable(bool selectable);
void setDoubleClickSelectsParagraph(bool doubleClickSelectsParagraph);
void setContextCopyText(const QString &copyText);
void setExpandLinksMode(ExpandLinksMode mode);
void resizeToWidth(int32 width);
int naturalWidth() const;
void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk);
using ClickHandlerHook = Function<bool, const ClickHandlerPtr &, Qt::MouseButton>;
void setClickHandlerHook(ClickHandlerHook &&hook);
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &action, bool active) override;
void clickHandlerPressedChanged(const ClickHandlerPtr &action, bool pressed) override;
@ -67,6 +80,8 @@ private slots:
void onExecuteDrag();
private:
void init();
Text::StateResult dragActionUpdate();
Text::StateResult dragActionStart(const QPoint &p, Qt::MouseButton button);
Text::StateResult dragActionFinish(const QPoint &p, Qt::MouseButton button);
@ -83,12 +98,11 @@ private:
FromTouch,
};
void showContextMenu(QContextMenuEvent *e, ContextMenuReason reason);
QString contextCopyText() const;
Text _text;
style::flatLabel _st;
style::textStyle _tst;
float64 _opacity;
float64 _opacity = 1.;
int _allowedWidth = 0;
int _fullTextHeight = 0;
@ -97,6 +111,7 @@ private:
bool _selectable = false;
TextSelection _selection, _savedSelection;
TextSelectType _selectionType = TextSelectType::Letters;
bool _doubleClickSelectsParagraph = false;
enum DragAction {
NoDrag = 0x00,
@ -117,6 +132,9 @@ private:
PopupMenu *_contextMenu = nullptr;
ClickHandlerPtr _contextMenuClickHandler;
QString _contextCopyText;
ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll;
ClickHandlerHook _clickHandlerHook;
// text selection and context menu by touch support (at least Windows Surface tablets)
bool _touchSelect = false;

View file

@ -312,6 +312,20 @@ public:
return _widget;
}
void destroy() {
if (_widget) {
delete _widget;
_widget = nullptr;
}
}
void destroyDelayed() {
if (_widget) {
_widget->hide();
_widget->deleteLater();
_widget = nullptr;
}
}
private:
T *_widget;

View file

@ -87,7 +87,7 @@ void TopBarWidget::onInfoClicked() {
void TopBarWidget::onAddContact() {
PeerData *p = nullptr;// App::main() ? App::main()->profilePeer() : 0;
UserData *u = p ? p->asUser() : 0;
if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone));
if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone().isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone()));
}
void TopBarWidget::onEdit() {

View file

@ -1213,12 +1213,18 @@
<ClCompile Include="SourceFiles\passcodewidget.cpp" />
<ClCompile Include="SourceFiles\playerwidget.cpp" />
<ClCompile Include="SourceFiles\profilewidget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_actions_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_block_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_cover.cpp" />
<ClCompile Include="SourceFiles\profile\profile_cover_drop_area.cpp" />
<ClCompile Include="SourceFiles\profile\profile_fixed_bar.cpp" />
<ClCompile Include="SourceFiles\profile\profile_info_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_inner_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_invite_link_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_members_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_section_memento.cpp" />
<ClCompile Include="SourceFiles\profile\profile_settings_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_shared_media_widget.cpp" />
<ClCompile Include="SourceFiles\profile\profile_userpic_button.cpp" />
<ClCompile Include="SourceFiles\profile\profile_widget.cpp" />
<ClCompile Include="SourceFiles\pspecific_linux.cpp">
@ -1549,21 +1555,27 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_fixed_bar.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
</CustomBuild>
<CustomBuild Include="SourceFiles\profile\profile_block_widget.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing profile_block_widget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_block_widget.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing profile_block_widget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_block_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl_debug\Debug\include"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing profile_block_widget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/profile/profile_block_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtCore\5.6.0\QtCore" "-I$(QTDIR)\include\QtGui\5.6.0\QtGui" "-I.\..\..\Libraries\breakpad\src" "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\ThirdParty\minizip" "-I.\..\..\Libraries\openssl\Release\include"</Command>
</CustomBuild>
<ClInclude Include="SourceFiles\profile\profile_actions_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_cover_drop_area.h" />
<ClInclude Include="SourceFiles\profile\profile_info_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_invite_link_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_members_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_section_memento.h" />
<ClInclude Include="SourceFiles\profile\profile_settings_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_shared_media_widget.h" />
<ClInclude Include="SourceFiles\profile\profile_userpic_button.h" />
<ClInclude Include="SourceFiles\serialize\serialize_common.h" />
<ClInclude Include="SourceFiles\serialize\serialize_document.h" />

View file

@ -1188,18 +1188,6 @@
<ClCompile Include="SourceFiles\profile\profile_section_memento.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_block_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\ui\buttons\round_button.cpp">
<Filter>SourceFiles\ui\buttons</Filter>
</ClCompile>
@ -1215,6 +1203,36 @@
<ClCompile Include="SourceFiles\profile\profile_userpic_button.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Deploy</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_profile_block_widget.cpp">
<Filter>GeneratedFiles\Release</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_block_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_info_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_actions_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_invite_link_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_members_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_settings_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\profile\profile_shared_media_widget.cpp">
<Filter>SourceFiles\profile</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -1418,6 +1436,24 @@
<ClInclude Include="SourceFiles\profile\profile_userpic_button.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_info_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_actions_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_invite_link_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_members_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_settings_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
<ClInclude Include="SourceFiles\profile\profile_shared_media_widget.h">
<Filter>SourceFiles\profile</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="SourceFiles\application.h">