diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 7b9adcfee..041fd7827 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -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
 
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 751757c63..11f67b836 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -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);
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index be22abcf3..c157dddc8 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -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);
 		}
diff --git a/Telegram/SourceFiles/boxes/aboutbox.cpp b/Telegram/SourceFiles/boxes/aboutbox.cpp
index c5bc8cdf5..7e64bd52d 100644
--- a/Telegram/SourceFiles/boxes/aboutbox.cpp
+++ b/Telegram/SourceFiles/boxes/aboutbox.cpp
@@ -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]")));
 
diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp
index f1bea515d..abe636529 100644
--- a/Telegram/SourceFiles/boxes/addcontactbox.cpp
+++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp
@@ -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();
 }
diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h
index 90e55311c..e70b1ac93 100644
--- a/Telegram/SourceFiles/boxes/addcontactbox.h
+++ b/Telegram/SourceFiles/boxes/addcontactbox.h
@@ -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;
 };
 
diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp
index fcd6b5e1d..f4c044e53 100644
--- a/Telegram/SourceFiles/boxes/confirmbox.cpp
+++ b/Telegram/SourceFiles/boxes/confirmbox.cpp
@@ -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)
diff --git a/Telegram/SourceFiles/boxes/confirmbox.h b/Telegram/SourceFiles/boxes/confirmbox.h
index 4af3c49af..e7af61470 100644
--- a/Telegram/SourceFiles/boxes/confirmbox.h
+++ b/Telegram/SourceFiles/boxes/confirmbox.h
@@ -217,7 +217,7 @@ private:
 
 	BoxButton _pin, _cancel;
 
-	mtpRequestId _requestId;
+	mtpRequestId _requestId = 0;
 
 };
 
diff --git a/Telegram/SourceFiles/core/click_handler.h b/Telegram/SourceFiles/core/click_handler.h
index c0199fac9..8ceadfb81 100644
--- a/Telegram/SourceFiles/core/click_handler.h
+++ b/Telegram/SourceFiles/core/click_handler.h
@@ -27,6 +27,7 @@ enum ExpandLinksMode {
 	ExpandLinksNone,
 	ExpandLinksShortened,
 	ExpandLinksAll,
+	ExpandLinksUrlOnly, // For custom urls leaves only url instead of text.
 };
 
 class ClickHandlerHost {
diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp
index 05043abf2..23b34fb76 100644
--- a/Telegram/SourceFiles/core/click_handler_types.cpp
+++ b/Telegram/SourceFiles/core/click_handler_types.cpp
@@ -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) {
diff --git a/Telegram/SourceFiles/core/click_handler_types.h b/Telegram/SourceFiles/core/click_handler_types.h
index d25078278..84deafe77 100644
--- a/Telegram/SourceFiles/core/click_handler_types.h
+++ b/Telegram/SourceFiles/core/click_handler_types.h
@@ -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;
+
 };
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 4375ede39..3e41bac0a 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -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;
 
diff --git a/Telegram/SourceFiles/intro/introphone.cpp b/Telegram/SourceFiles/intro/introphone.cpp
index e5fcb4956..48cc83f8b 100644
--- a/Telegram/SourceFiles/intro/introphone.cpp
+++ b/Telegram/SourceFiles/intro/introphone.cpp
@@ -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);
diff --git a/Telegram/SourceFiles/intro/introstart.cpp b/Telegram/SourceFiles/intro/introstart.cpp
index 8753300fc..bc3c520ff 100644
--- a/Telegram/SourceFiles/intro/introstart.cpp
+++ b/Telegram/SourceFiles/intro/introstart.cpp
@@ -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();
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index a94231f4a..9127b6abb 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -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;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 3a60bfb44..b3c12ede1 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -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;
 
diff --git a/Telegram/SourceFiles/observer_peer.h b/Telegram/SourceFiles/observer_peer.h
index 06f07b73a..797dd562d 100644
--- a/Telegram/SourceFiles/observer_peer.h
+++ b/Telegram/SourceFiles/observer_peer.h
@@ -33,9 +33,11 @@ enum class PeerUpdateFlag {
 	NameChanged          = 0x00000001U,
 	UsernameChanged      = 0x00000002U,
 	PhotoChanged         = 0x00000004U,
+	AboutChanged         = 0x00000008U,
 
 	UserCanShareContact  = 0x00010000U,
 	UserIsContact        = 0x00020000U,
+	UserPhoneChanged     = 0x00040000U,
 
 	ChatCanEdit          = 0x00010000U,
 
diff --git a/Telegram/SourceFiles/profile/profile.style b/Telegram/SourceFiles/profile/profile.style
index 76fc87208..cd0577934 100644
--- a/Telegram/SourceFiles/profile/profile.style
+++ b/Telegram/SourceFiles/profile/profile.style
@@ -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);
\ No newline at end of file
+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;
diff --git a/Telegram/SourceFiles/profile/profile_actions_widget.cpp b/Telegram/SourceFiles/profile/profile_actions_widget.cpp
new file mode 100644
index 000000000..aec40e5c8
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_actions_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_actions_widget.h b/Telegram/SourceFiles/profile/profile_actions_widget.h
new file mode 100644
index 000000000..118c2d0d5
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_actions_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_block_widget.cpp b/Telegram/SourceFiles/profile/profile_block_widget.cpp
index abfe8453b..6548fbb61 100644
--- a/Telegram/SourceFiles/profile/profile_block_widget.cpp
+++ b/Telegram/SourceFiles/profile/profile_block_widget.cpp
@@ -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);
 }
diff --git a/Telegram/SourceFiles/profile/profile_block_widget.h b/Telegram/SourceFiles/profile/profile_block_widget.h
index 313e0d747..8607aa0b5 100644
--- a/Telegram/SourceFiles/profile/profile_block_widget.h
+++ b/Telegram/SourceFiles/profile/profile_block_widget.h
@@ -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;
 	}
diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp
index fd8937987..8ed491b80 100644
--- a/Telegram/SourceFiles/profile/profile_cover.cpp
+++ b/Telegram/SourceFiles/profile/profile_cover.cpp
@@ -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() {
diff --git a/Telegram/SourceFiles/profile/profile_cover.h b/Telegram/SourceFiles/profile/profile_cover.h
index 47975485b..2a53e31ec 100644
--- a/Telegram/SourceFiles/profile/profile_cover.h
+++ b/Telegram/SourceFiles/profile/profile_cover.h
@@ -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;
diff --git a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp
index 71980895f..e051bc8f3 100644
--- a/Telegram/SourceFiles/profile/profile_fixed_bar.cpp
+++ b/Telegram/SourceFiles/profile/profile_fixed_bar.cpp
@@ -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);
diff --git a/Telegram/SourceFiles/profile/profile_info_widget.cpp b/Telegram/SourceFiles/profile/profile_info_widget.cpp
new file mode 100644
index 000000000..04ec57bc0
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_info_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_info_widget.h b/Telegram/SourceFiles/profile/profile_info_widget.h
new file mode 100644
index 000000000..b94f5199d
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_info_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.cpp b/Telegram/SourceFiles/profile/profile_inner_widget.cpp
index 77e701ac9..0cd9d0e17 100644
--- a/Telegram/SourceFiles/profile/profile_inner_widget.cpp
+++ b/Telegram/SourceFiles/profile/profile_inner_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_inner_widget.h b/Telegram/SourceFiles/profile/profile_inner_widget.h
index e702b17cd..61467d55b 100644
--- a/Telegram/SourceFiles/profile/profile_inner_widget.h
+++ b/Telegram/SourceFiles/profile/profile_inner_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp
new file mode 100644
index 000000000..ea90d357c
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_invite_link_widget.h b/Telegram/SourceFiles/profile/profile_invite_link_widget.h
new file mode 100644
index 000000000..c9eada6a2
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_invite_link_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_members_widget.cpp b/Telegram/SourceFiles/profile/profile_members_widget.cpp
new file mode 100644
index 000000000..26ccc9308
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_members_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_members_widget.h b/Telegram/SourceFiles/profile/profile_members_widget.h
new file mode 100644
index 000000000..8278091c1
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_members_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_settings_widget.cpp b/Telegram/SourceFiles/profile/profile_settings_widget.cpp
new file mode 100644
index 000000000..0b987f26d
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_settings_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_settings_widget.h b/Telegram/SourceFiles/profile/profile_settings_widget.h
new file mode 100644
index 000000000..76badc91b
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_settings_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp
new file mode 100644
index 000000000..5215e86fc
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_shared_media_widget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/profile/profile_shared_media_widget.h b/Telegram/SourceFiles/profile/profile_shared_media_widget.h
new file mode 100644
index 000000000..49597f69e
--- /dev/null
+++ b/Telegram/SourceFiles/profile/profile_shared_media_widget.h
@@ -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
diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp
index 6768a2b36..a72d5c404 100644
--- a/Telegram/SourceFiles/profilewidget.cpp
+++ b/Telegram/SourceFiles/profilewidget.cpp
@@ -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() {
diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp
index c08a12ab6..963f8fb9b 100644
--- a/Telegram/SourceFiles/settingswidget.cpp
+++ b/Telegram/SourceFiles/settingswidget.cpp
@@ -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
diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp
index 2d0971297..d91ee4150 100644
--- a/Telegram/SourceFiles/structs.cpp
+++ b/Telegram/SourceFiles/structs.cpp
@@ -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) {
diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h
index e14eb290b..bcb4537ca 100644
--- a/Telegram/SourceFiles/structs.h
+++ b/Telegram/SourceFiles/structs.h
@@ -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;
 
 };
 
diff --git a/Telegram/SourceFiles/ui/flatinput.cpp b/Telegram/SourceFiles/ui/flatinput.cpp
index 1afe8650e..dbb8f3006 100644
--- a/Telegram/SourceFiles/ui/flatinput.cpp
+++ b/Telegram/SourceFiles/ui/flatinput.cpp
@@ -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);
diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp
index a4894247c..b30fbd94d 100644
--- a/Telegram/SourceFiles/ui/flatlabel.cpp
+++ b/Telegram/SourceFiles/ui/flatlabel.cpp
@@ -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);
diff --git a/Telegram/SourceFiles/ui/flatlabel.h b/Telegram/SourceFiles/ui/flatlabel.h
index 592065229..097213560 100644
--- a/Telegram/SourceFiles/ui/flatlabel.h
+++ b/Telegram/SourceFiles/ui/flatlabel.h
@@ -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;
diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h
index 7b6935568..680ad4c86 100644
--- a/Telegram/SourceFiles/ui/twidget.h
+++ b/Telegram/SourceFiles/ui/twidget.h
@@ -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;
 
diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp
index c175611f0..2fbb27e5b 100644
--- a/Telegram/SourceFiles/window/top_bar_widget.cpp
+++ b/Telegram/SourceFiles/window/top_bar_widget.cpp
@@ -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() {
diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj
index 17d801473..345141923 100644
--- a/Telegram/Telegram.vcxproj
+++ b/Telegram/Telegram.vcxproj
@@ -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" />
diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters
index 7412f0303..6d0474c9b 100644
--- a/Telegram/Telegram.vcxproj.filters
+++ b/Telegram/Telegram.vcxproj.filters
@@ -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">