diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 8f2ddd0fa..d207ae021 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -922,6 +922,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 "lng_stickers_masks_pack" = "This is a pack of mask stickers. You can use them in the photo editor on our mobile apps.";
 "lng_stickers_group_set" = "Group sticker set";
 "lng_stickers_remove_group_set" = "Remove group sticker set?";
+"lng_stickers_group_from_your" = "Choose from your stickers";
 
 "lng_in_dlg_photo" = "Photo";
 "lng_in_dlg_video" = "Video";
diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp
index 293c505ed..fc56e37c7 100644
--- a/Telegram/SourceFiles/boxes/abstract_box.cpp
+++ b/Telegram/SourceFiles/boxes/abstract_box.cpp
@@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "boxes/abstract_box.h"
 
 #include "styles/style_boxes.h"
+#include "styles/style_profile.h"
 #include "storage/localstorage.h"
 #include "lang/lang_keys.h"
 #include "ui/effects/widget_fade_wrap.h"
@@ -30,9 +31,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "mainwidget.h"
 #include "mainwindow.h"
 
-BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxLayerTitleShadow) {
-}
-
 QPointer<Ui::RoundButton> BoxContent::addButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback) {
 	return addButton(std::move(textFactory), std::move(clickCallback), st::defaultBoxButton);
 }
@@ -421,3 +419,22 @@ void AbstractBox::keyPressEvent(QKeyEvent *e) {
 		LayerWidget::keyPressEvent(e);
 	}
 }
+
+BoxLayerTitleShadow::BoxLayerTitleShadow(QWidget *parent) : Ui::PlainShadow(parent, st::boxLayerTitleShadow) {
+}
+
+BoxContentDivider::BoxContentDivider(QWidget *parent) : TWidget(parent) {
+}
+
+int BoxContentDivider::resizeGetHeight(int newWidth) {
+	return st::rightsDividerHeight;
+}
+
+void BoxContentDivider::paintEvent(QPaintEvent *e) {
+	Painter p(this);
+	p.fillRect(e->rect(), st::contactsAboutBg);
+	auto dividerFillTop = myrtlrect(0, 0, width(), st::profileDividerTop.height());
+	st::profileDividerTop.fill(p, dividerFillTop);
+	auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height());
+	st::profileDividerBottom.fill(p, dividerFillBottom);
+}
diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h
index e70f89f14..5f1fa5632 100644
--- a/Telegram/SourceFiles/boxes/abstract_box.h
+++ b/Telegram/SourceFiles/boxes/abstract_box.h
@@ -36,11 +36,7 @@ namespace Window {
 class Controller;
 } // namespace Window
 
-class BoxLayerTitleShadow : public Ui::PlainShadow {
-public:
-	BoxLayerTitleShadow(QWidget *parent);
-
-};
+class BoxLayerTitleShadow;
 
 class BoxContentDelegate {
 public:
@@ -287,6 +283,22 @@ private:
 
 };
 
+class BoxLayerTitleShadow : public Ui::PlainShadow {
+public:
+	BoxLayerTitleShadow(QWidget *parent);
+
+};
+
+class BoxContentDivider : public TWidget {
+public:
+	BoxContentDivider(QWidget *parent);
+
+protected:
+	int resizeGetHeight(int newWidth) override;
+	void paintEvent(QPaintEvent *e) override;
+
+};
+
 enum CreatingGroupType {
 	CreatingGroupNone,
 	CreatingGroupGroup,
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index cec437894..81f5fabae 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -679,3 +679,16 @@ muteChatTitle: FlatLabel(boxLabel) {
 		font: font(boxFontSize semibold);
 	}
 }
+
+groupStickersRemove: contactsSearchCancel;
+groupStickersRemovePosition: point(6px, 6px);
+groupStickersFieldPadding: margins(8px, 6px, 8px, 6px);
+groupStickersField: InputField(contactsSearchField) {
+	placeholderFont: boxTextFont;
+	font: boxTextFont;
+	placeholderMargins: margins(0px, 0px, 0px, 0px);
+	textMargins: margins(0px, 7px, 0px, 0px);
+	textBg: boxBg;
+	heightMin: 32px;
+}
+groupStickersSubTitleHeight: 36px;
diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.cpp b/Telegram/SourceFiles/boxes/edit_participant_box.cpp
index d479e5511..334d7ac16 100644
--- a/Telegram/SourceFiles/boxes/edit_participant_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_participant_box.cpp
@@ -25,7 +25,6 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "ui/widgets/labels.h"
 #include "ui/widgets/buttons.h"
 #include "styles/style_boxes.h"
-#include "styles/style_profile.h"
 #include "ui/special_buttons.h"
 #include "boxes/calendar_box.h"
 
@@ -74,30 +73,6 @@ void ApplyDependencies(CheckboxesMap &checkboxes, DependenciesMap &dependencies,
 
 } // namespace
 
-class EditParticipantBox::Divider : public TWidget {
-public:
-	Divider(QWidget *parent) : TWidget(parent) {
-	}
-
-protected:
-	int resizeGetHeight(int newWidth) override;
-	void paintEvent(QPaintEvent *e) override;
-
-};
-
-int EditParticipantBox::Divider::resizeGetHeight(int newWidth) {
-	return st::rightsDividerHeight;
-}
-
-void EditParticipantBox::Divider::paintEvent(QPaintEvent *e) {
-	Painter p(this);
-	p.fillRect(e->rect(), st::contactsAboutBg);
-	auto dividerFillTop = myrtlrect(0, 0, width(), st::profileDividerTop.height());
-	st::profileDividerTop.fill(p, dividerFillTop);
-	auto dividerFillBottom = myrtlrect(0, height() - st::profileDividerBottom.height(), width(), st::profileDividerBottom.height());
-	st::profileDividerBottom.fill(p, dividerFillBottom);
-}
-
 class EditParticipantBox::Inner : public TWidget {
 public:
 	Inner(QWidget *parent, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, bool hasAdminRights);
@@ -236,7 +211,7 @@ void EditAdminBox::prepare() {
 	auto hadRights = _oldRights.c_channelAdminRights().vflags.v;
 	setTitle(langFactory(hadRights ? lng_rights_edit_admin : lng_channel_add_admin));
 
-	addControl(object_ptr<Divider>(this), QMargins());
+	addControl(object_ptr<BoxContentDivider>(this), QMargins());
 	addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_edit_admin_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
 
 	auto prepareRights = (hadRights ? _oldRights : DefaultRights(channel()));
@@ -355,7 +330,7 @@ void EditRestrictedBox::prepare() {
 
 	setTitle(langFactory(lng_rights_user_restrictions));
 
-	addControl(object_ptr<Divider>(this), QMargins());
+	addControl(object_ptr<BoxContentDivider>(this), QMargins());
 	addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_user_restrictions_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
 
 	auto prepareRights = (_oldRights.c_channelBannedRights().vflags.v ? _oldRights : DefaultRights(channel()));
@@ -378,7 +353,7 @@ void EditRestrictedBox::prepare() {
 	addCheckbox(Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_games | Flag::f_send_inline, lang(lng_rights_chat_send_stickers));
 	addCheckbox(Flag::f_embed_links, lang(lng_rights_chat_send_links));
 
-	addControl(object_ptr<Divider>(this), st::rightsUntilMargin);
+	addControl(object_ptr<BoxContentDivider>(this), st::rightsUntilMargin);
 	addControl(object_ptr<Ui::FlatLabel>(this, lang(lng_rights_chat_banned_until_header), Ui::FlatLabel::InitType::Simple, st::rightsHeaderLabel), st::rightsHeaderMargin);
 	setRestrictUntil(_until);
 
diff --git a/Telegram/SourceFiles/boxes/edit_participant_box.h b/Telegram/SourceFiles/boxes/edit_participant_box.h
index 6b6519fba..ca5edd020 100644
--- a/Telegram/SourceFiles/boxes/edit_participant_box.h
+++ b/Telegram/SourceFiles/boxes/edit_participant_box.h
@@ -57,8 +57,6 @@ protected:
 		return _hasAdminRights;
 	}
 
-	class Divider;
-
 private:
 	gsl::not_null<ChannelData*> _channel;
 	gsl::not_null<UserData*> _user;
diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp
index d95f54d63..03d276a8c 100644
--- a/Telegram/SourceFiles/boxes/stickers_box.cpp
+++ b/Telegram/SourceFiles/boxes/stickers_box.cpp
@@ -31,16 +31,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "styles/style_boxes.h"
 #include "styles/style_chat_helpers.h"
 #include "ui/widgets/buttons.h"
+#include "ui/widgets/labels.h"
 #include "ui/widgets/scroll_area.h"
 #include "ui/effects/ripple_animation.h"
 #include "ui/effects/slide_animation.h"
 #include "ui/widgets/discrete_sliders.h"
+#include "ui/widgets/input_fields.h"
 #include "auth_session.h"
+#include "messenger.h"
 
 namespace {
 
-constexpr int kArchivedLimitFirstRequest = 10;
-constexpr int kArchivedLimitPerPage = 30;
+constexpr auto kArchivedLimitFirstRequest = 10;
+constexpr auto kArchivedLimitPerPage = 30;
+constexpr auto kHandleMegagroupSetAddressChangeTimeout = TimeMs(1000);
 
 } // namespace
 
@@ -156,6 +160,7 @@ StickersBox::StickersBox(QWidget*, gsl::not_null<ChannelData*> megagroup)
 : _section(Section::Installed)
 , _installed(0, this, megagroup)
 , _megagroupSet(megagroup) {
+	subscribe(_installed.widget()->scrollToY, [this](int y) { onScrollToY(y); });
 }
 
 void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedStickers &result) {
@@ -264,7 +269,12 @@ void StickersBox::prepare() {
 		_archived.widget()->setLoadMoreCallback([this] { loadMoreArchived(); });
 	}
 
-	addButton(langFactory(lng_about_done), [this] { closeBox(); });
+	if (_megagroupSet) {
+		addButton(langFactory(lng_settings_save), [this] { _installed.widget()->saveGroupSet(); closeBox(); });
+		addButton(langFactory(lng_cancel), [this] { closeBox(); });
+	} else {
+		addButton(langFactory(lng_about_done), [this] { closeBox(); });
+	}
 
 	if (_section == Section::Installed) {
 		_tab = &_installed;
@@ -554,7 +564,7 @@ void StickersBox::rebuildList(Tab *tab) {
 }
 
 void StickersBox::closeHook() {
-	if (!_installed.widget()) {
+	if (!_installed.widget() || _megagroupSet) {
 		return;
 	}
 
@@ -569,8 +579,30 @@ void StickersBox::closeHook() {
 	}
 }
 
+void StickersBox::setInnerFocus() {
+	if (_megagroupSet) {
+		_installed.widget()->setInnerFocus();
+	}
+}
+
 StickersBox::~StickersBox() = default;
 
+StickersBox::Inner::Row::Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id)
+, sticker(sticker)
+, count(count)
+, title(title)
+, titleWidth(titleWidth)
+, installed(installed)
+, official(official)
+, unread(unread)
+, archived(archived)
+, removed(removed)
+, pixw(pixw)
+, pixh(pixh) {
+}
+
+StickersBox::Inner::Row::~Row() = default;
+
 StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent)
 , _section(section)
 , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
@@ -599,7 +631,17 @@ StickersBox::Inner::Inner(QWidget *parent, gsl::not_null<ChannelData*> megagroup
 , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
 , _a_shifting(animation(this, &Inner::step_shifting))
 , _itemsTop(st::membersMarginTop)
-, _megagroupSet(megagroup) {
+, _megagroupSet(megagroup)
+, _megagroupSetInput(_megagroupSet->mgInfo->stickerSet)
+, _megagroupSetField(this, st::groupStickersField, [] { return qsl("stickerset"); }, QString(), true)
+, _megagroupDivider(this)
+, _megagroupSubTitle(this, lang(lng_stickers_group_from_your), Ui::FlatLabel::InitType::Simple, st::boxTitle) {
+	_megagroupSetField->setLinkPlaceholder(Messenger::Instance().createInternalLink(qsl("addstickers/")));
+	_megagroupSetField->setPlaceholderHidden(false);
+	_megagroupSetAddressChangedTimer.setCallback([this] { handleMegagroupSetAddressChange(); });
+	connect(_megagroupSetField, &Ui::MaskedInputField::changed, this, [this] { _megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout); });
+	connect(_megagroupSetField, &Ui::MaskedInputField::submitted, this, [this] { _megagroupSetAddressChangedTimer.cancel(); handleMegagroupSetAddressChange(); });
+
 	setup();
 }
 
@@ -611,41 +653,76 @@ void StickersBox::Inner::setup() {
 	setMouseTracking(true);
 }
 
+void StickersBox::Inner::setInnerFocus() {
+	if (_megagroupSetField) {
+		_megagroupSetField->setFocusFast();
+	}
+}
+
 void StickersBox::Inner::paintEvent(QPaintEvent *e) {
-	QRect r(e->rect());
 	Painter p(this);
 
 	_a_shifting.step();
 
+	auto clip = e->rect();
 	auto ms = getms();
-	p.fillRect(r, st::boxBg);
-	p.setClipRect(r);
+	p.fillRect(clip, st::boxBg);
+	p.setClipRect(clip);
+
+	if (_megagroupSelectedSet) {
+		auto setTop = _megagroupDivider->y() - _rowHeight;
+		p.translate(0, setTop);
+		paintRow(p, _megagroupSelectedSet.get(), -1, ms);
+		p.translate(0, -setTop);
+	}
 
 	auto y = _itemsTop;
-	if (_rows.isEmpty()) {
+	if (_rows.empty()) {
 		p.setFont(st::noContactsFont);
 		p.setPen(st::noContactsColor);
 		p.drawText(QRect(0, y, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
 	} else {
 		p.translate(0, _itemsTop);
 
-		int32 yFrom = r.y() - _itemsTop, yTo = r.y() + r.height() - _itemsTop;
+		int32 yFrom = clip.y() - _itemsTop, yTo = clip.y() + clip.height() - _itemsTop;
 		int32 from = floorclamp(yFrom - _rowHeight, _rowHeight, 0, _rows.size());
 		int32 to = ceilclamp(yTo + _rowHeight, _rowHeight, 0, _rows.size());
 		p.translate(0, from * _rowHeight);
 		for (int32 i = from; i < to; ++i) {
 			if (i != _above) {
-				paintRow(p, i, ms);
+				paintRow(p, _rows[i].get(), i, ms);
 			}
 			p.translate(0, _rowHeight);
 		}
 		if (from <= _above && _above < to) {
 			p.translate(0, (_above - to) * _rowHeight);
-			paintRow(p, _above, ms);
+			paintRow(p, _rows[_above].get(), _above, ms);
 		}
 	}
 }
 
+void StickersBox::Inner::resizeEvent(QResizeEvent *e) {
+	updateControlsGeometry();
+}
+
+void StickersBox::Inner::updateControlsGeometry() {
+	if (_megagroupSet) {
+		auto top = st::groupStickersFieldPadding.top();
+		auto fieldLeft = st::boxLayerTitlePosition.x();
+		_megagroupSetField->setGeometryToLeft(fieldLeft, top, width() - fieldLeft - st::groupStickersFieldPadding.right(), _megagroupSetField->height());
+		top += _megagroupSetField->height() + st::groupStickersFieldPadding.bottom();
+		if (_megagroupSelectedRemove) {
+			_megagroupSelectedShadow->setGeometryToLeft(0, top, width(), st::lineWidth);
+			top += st::lineWidth;
+			_megagroupSelectedRemove->moveToRight(st::groupStickersRemovePosition.x(), top + st::groupStickersRemovePosition.y());
+			top += _rowHeight;
+		}
+		_megagroupDivider->setGeometryToLeft(0, top, width(), _megagroupDivider->height());
+		top += _megagroupDivider->height();
+		_megagroupSubTitle->moveToLeft(st::boxLayerTitlePosition.x(), top + st::boxLayerTitlePosition.y());
+	}
+}
+
 QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
 	auto buttonw = st::stickersRemove.width;
 	auto buttonh = st::stickersRemove.height;
@@ -662,14 +739,21 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
 	return QRect(buttonx, buttony, buttonw, buttonh);
 }
 
-void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
-	auto s = _rows.at(index);
-
-	auto xadd = 0, yadd = qRound(s->yadd.current());
+void StickersBox::Inner::paintRow(Painter &p, Row *set, int index, TimeMs ms) {
+	auto xadd = 0, yadd = qRound(set->yadd.current());
 	if (xadd || yadd) p.translate(xadd, yadd);
 
+	if (_megagroupSet) {
+		if (index >= 0 && index == _selected) {
+			p.fillRect(0, 0, width(), _rowHeight, st::contactsBgOver);
+			if (set->ripple) {
+				set->ripple->paint(p, 0, 0, width(), ms);
+			}
+		}
+	}
+
 	if (_section == Section::Installed) {
-		if (index == _above) {
+		if (index >= 0 && index == _above) {
 			auto current = _aboveShadowFadeOpacity.current();
 			if (_started >= 0) {
 				auto reachedOpacity = aboveShadowOpacity();
@@ -686,16 +770,16 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
 			App::roundRect(p, row, st::boxBg, BoxCorners);
 
 			p.setOpacity(1. - current);
-			paintFakeButton(p, index, ms);
+			paintFakeButton(p, set, index, ms);
 			p.setOpacity(1.);
 		} else if (!_megagroupSet) {
-			paintFakeButton(p, index, ms);
+			paintFakeButton(p, set, index, ms);
 		}
 	} else if (!_megagroupSet) {
-		paintFakeButton(p, index, ms);
+		paintFakeButton(p, set, index, ms);
 	}
 
-	if (s->removed && _section == Section::Installed) {
+	if (set->removed && _section == Section::Installed) {
 		p.setOpacity(st::stickersRowDisabledOpacity);
 	}
 
@@ -703,15 +787,15 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
 
 	if (!_megagroupSet && _section == Section::Installed) {
 		stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip;
-		if (!s->isRecentSet()) {
+		if (!set->isRecentSet()) {
 			st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width());
 		}
 	}
 
-	if (s->sticker) {
-		s->sticker->thumb->load();
-		QPixmap pix(s->sticker->thumb->pix(s->pixw, s->pixh));
-		p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - s->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - s->pixh) / 2, width(), pix);
+	if (set->sticker) {
+		set->sticker->thumb->load();
+		auto pix = set->sticker->thumb->pix(set->pixw, set->pixh);
+		p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix);
 	}
 
 	int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left();
@@ -722,19 +806,19 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
 
 	p.setFont(st::contactsNameStyle.font);
 	p.setPen(st::contactsNameFg);
-	p.drawTextLeft(namex, namey, width(), s->title, s->titleWidth);
+	p.drawTextLeft(namex, namey, width(), set->title, set->titleWidth);
 
-	if (s->unread) {
+	if (set->unread) {
 		p.setPen(Qt::NoPen);
 		p.setBrush(st::stickersFeaturedUnreadBg);
 
 		{
 			PainterHighQualityEnabler hq(p);
-			p.drawEllipse(rtlrect(namex + s->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
+			p.drawEllipse(rtlrect(namex + set->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
 		}
 	}
 
-	auto statusText = (s->count > 0) ? lng_stickers_count(lt_count, s->count) : lang(lng_contacts_loading);
+	auto statusText = (set->count > 0) ? lng_stickers_count(lt_count, set->count) : lang(lng_contacts_loading);
 
 	p.setFont(st::contactsStatusFont);
 	p.setPen(st::contactsStatusFg);
@@ -744,8 +828,7 @@ void StickersBox::Inner::paintRow(Painter &p, int index, TimeMs ms) {
 	if (xadd || yadd) p.translate(-xadd, -yadd);
 }
 
-void StickersBox::Inner::paintFakeButton(Painter &p, int index, TimeMs ms) {
-	auto set = _rows[index];
+void StickersBox::Inner::paintFakeButton(Painter &p, Row *set, int index, TimeMs ms) {
 	auto removeButton = (_section == Section::Installed && !set->removed);
 	auto rect = relativeButtonRect(removeButton);
 	if (_section != Section::Installed && set->installed && !set->archived && !set->removed) {
@@ -794,7 +877,7 @@ void StickersBox::Inner::mousePressEvent(QMouseEvent *e) {
 	_mouse = e->globalPos();
 	onUpdateSelected();
 
-	_pressed = _selected;
+	setPressed(_selected);
 	if (_actionSel >= 0) {
 		setActionDown(_actionSel);
 		update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
@@ -810,7 +893,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
 	}
 	if (_actionDown >= 0 && _actionDown < _rows.size()) {
 		update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
-		auto set = _rows[_actionDown];
+		auto &set = _rows[_actionDown];
 		if (set->ripple) {
 			set->ripple->lastStop();
 		}
@@ -818,7 +901,7 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
 	_actionDown = newActionDown;
 	if (_actionDown >= 0 && _actionDown < _rows.size()) {
 		update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
-		auto set = _rows[_actionDown];
+		auto &set = _rows[_actionDown];
 		auto removeButton = (_section == Section::Installed && !set->removed);
 		if (!set->ripple) {
 			if (_section == Section::Installed) {
@@ -844,8 +927,46 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
 	}
 }
 
+void StickersBox::Inner::setSelected(int selected) {
+	if (_selected == selected) {
+		return;
+	}
+	if (_megagroupSet && _selected >= 0 && _selected < _rows.size()) {
+		update(0, _itemsTop + _selected * _rowHeight, width(), _rowHeight);
+	}
+	_selected = selected;
+	if (_megagroupSet && _selected >= 0 && _selected < _rows.size()) {
+		update(0, _itemsTop + _selected * _rowHeight, width(), _rowHeight);
+	}
+}
+
+void StickersBox::Inner::setPressed(int pressed) {
+	if (_pressed == pressed) {
+		return;
+	}
+	if (_megagroupSet && _pressed >= 0 && _pressed < _rows.size()) {
+		update(0, _itemsTop + _pressed * _rowHeight, width(), _rowHeight);
+		auto &set = _rows[_pressed];
+		if (set->ripple) {
+			set->ripple->lastStop();
+		}
+	}
+	_pressed = pressed;
+	if (_megagroupSet && _pressed >= 0 && _pressed < _rows.size()) {
+		update(0, _itemsTop + _pressed * _rowHeight, width(), _rowHeight);
+		auto &set = _rows[_pressed];
+		auto rippleMask = Ui::RippleAnimation::rectMask(QSize(width(), _rowHeight));
+		if (!_rows[_pressed]->ripple) {
+			_rows[_pressed]->ripple = std::make_unique<Ui::RippleAnimation>(st::contactsRipple, std::move(rippleMask), [this, index = _pressed] {
+				update(0, _itemsTop + index * _rowHeight, width(), _rowHeight);
+			});
+		}
+		_rows[_pressed]->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(0, _itemsTop + _pressed * _rowHeight));
+	}
+}
+
 void StickersBox::Inner::ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton) {
-	_rows[_actionDown]->ripple = MakeShared<Ui::RippleAnimation>(st, std::move(mask), [this, index = _actionDown, removeButton] {
+	_rows[_actionDown]->ripple = std::make_unique<Ui::RippleAnimation>(st, std::move(mask), [this, index = _actionDown, removeButton] {
 		update(myrtlrect(relativeButtonRect(removeButton).translated(0, _itemsTop + index * _rowHeight)));
 	});
 }
@@ -906,10 +1027,10 @@ void StickersBox::Inner::onUpdateSelected() {
 		auto selected = -1;
 		auto actionSel = -1;
 		auto inDragArea = false;
-		if (in && !_rows.isEmpty()) {
+		if (in && !_rows.empty()) {
 			selected = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1);
 			local.setY(local.y() - _itemsTop - selected * _rowHeight);
-			auto set = _rows[selected];
+			auto &set = _rows[selected];
 			if (!_megagroupSet && (_section == Section::Installed || !set->installed || set->archived || set->removed)) {
 				auto removeButton = (_section == Section::Installed && !set->removed);
 				auto rect = myrtlrect(relativeButtonRect(removeButton));
@@ -931,7 +1052,7 @@ void StickersBox::Inner::onUpdateSelected() {
 					setCursor((selected >= 0 || _pressed >= 0) ? style::cur_pointer : style::cur_default);
 				}
 			}
-			_selected = selected;
+			setSelected(selected);
 		}
 		if (_inDragArea != inDragArea) {
 			_inDragArea = inDragArea;
@@ -978,16 +1099,14 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
 	} else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) {
 		if (_selected >= 0 && !_inDragArea) {
 			auto &sets = Global::RefStickerSets();
-			auto row = _rows[pressed];
+			auto &row = _rows[pressed];
 			if (!row->isRecentSet()) {
 				auto it = sets.find(row->id);
 				if (it != sets.cend()) {
-					_selected = -1;
 					if (_megagroupSet) {
-						Auth().api().setGroupStickerSet(_megagroupSet, Stickers::inputSetId(*it));
-						Ui::hideLayer();
-						App::main()->onStickersInstalled(Stickers::MegagroupSetId);
+						setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)));
 					} else {
+						setSelected(-1);
 						Ui::show(Box<StickerSetBox>(Stickers::inputSetId(*it)), KeepOtherLayers);
 					}
 				}
@@ -997,8 +1116,18 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
 	setActionDown(-1);
 }
 
+void StickersBox::Inner::saveGroupSet() {
+	Expects(_megagroupSet != nullptr);
+	auto oldId = (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) ? _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v : 0;
+	auto newId = (_megagroupSetInput.type() == mtpc_inputStickerSetID) ? _megagroupSetInput.c_inputStickerSetID().vid.v : 0;
+	if (newId != oldId) {
+		Auth().api().setGroupStickerSet(_megagroupSet, _megagroupSetInput);
+		App::main()->onStickersInstalled(Stickers::MegagroupSetId);
+	}
+}
+
 void StickersBox::Inner::setRowRemoved(int index, bool removed) {
-	auto row = _rows[index];
+	auto &row = _rows[index];
 	if (row->removed != removed) {
 		row->removed = removed;
 		row->ripple.reset();
@@ -1012,6 +1141,11 @@ void StickersBox::Inner::leaveEventHook(QEvent *e) {
 	onUpdateSelected();
 }
 
+void StickersBox::Inner::leaveToChildEvent(QEvent *e, QWidget *child) {
+	_mouse = QPoint(-1, -1);
+	onUpdateSelected();
+}
+
 void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) {
 	auto animating = false;
 	auto updateMin = -1;
@@ -1062,19 +1196,16 @@ void StickersBox::Inner::step_shifting(TimeMs ms, bool timer) {
 }
 
 void StickersBox::Inner::clear() {
-	for (int32 i = 0, l = _rows.size(); i < l; ++i) {
-		delete _rows.at(i);
-	}
 	_rows.clear();
 	_animStartTimes.clear();
 	_aboveShadowFadeStart = 0;
 	_aboveShadowFadeOpacity = anim::value();
 	_a_shifting.stop();
 	_above = _dragging = _started = -1;
-	_selected = -1;
-	_pressed = -1;
-	_actionDown = -1;
+	setSelected(-1);
+	setPressed(-1);
 	setActionSel(-1);
+	setActionDown(-1);
 	update();
 }
 
@@ -1089,10 +1220,86 @@ void StickersBox::Inner::setActionSel(int32 actionSel) {
 	}
 }
 
+void StickersBox::Inner::handleMegagroupSetAddressChange() {
+	auto text = _megagroupSetField->getLastText().trimmed();
+	if (text.isEmpty()) {
+		if (_megagroupSelectedSet) {
+			auto it = Global::StickerSets().constFind(_megagroupSelectedSet->id);
+			if (it != Global::StickerSets().end() && !it->shortName.isEmpty()) {
+				setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
+			}
+		}
+	} else if (!_megagroupSetRequestId) {
+		_megagroupSetRequestId = request(MTPmessages_GetStickerSet(MTP_inputStickerSetShortName(MTP_string(text)))).done([this](const MTPmessages_StickerSet &result) {
+			_megagroupSetRequestId = 0;
+			auto set = Stickers::FeedSetFull(result);
+			setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access)));
+		}).fail([this](const RPCError &error) {
+			_megagroupSetRequestId = 0;
+			setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
+		}).send();
+	} else {
+		_megagroupSetAddressChangedTimer.callOnce(kHandleMegagroupSetAddressChangeTimeout);
+	}
+}
+
+void StickersBox::Inner::rebuildMegagroupSet() {
+	Expects(_megagroupSet != nullptr);
+	if (_megagroupSetInput.type() != mtpc_inputStickerSetID) {
+		if (_megagroupSelectedSet) {
+			_megagroupSetField->setText(QString());
+			_megagroupSetField->finishAnimations();
+		}
+		_megagroupSelectedSet.reset();
+		_megagroupSelectedRemove.destroy();
+		_megagroupSelectedShadow.destroy();
+		return;
+	}
+	auto &set = _megagroupSetInput.c_inputStickerSetID();
+	auto setId = set.vid.v;
+	auto &sets = Global::StickerSets();
+	auto it = sets.find(setId);
+	if (it == sets.cend() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
+		Auth().api().scheduleStickerSetRequest(set.vid.v, set.vaccess_hash.v);
+		return;
+	}
+
+	auto maxNameWidth = countMaxNameWidth();
+	auto titleWidth = 0;
+	auto title = fillSetTitle(*it, maxNameWidth, &titleWidth);
+	auto count = fillSetCount(*it);
+	auto sticker = (DocumentData*)nullptr;
+	auto pixw = 0, pixh = 0;
+	fillSetCover(*it, &sticker, &pixw, &pixh);
+	auto installed = true, official = false, unread = false, archived = false, removed = false;
+	if (!_megagroupSelectedSet || _megagroupSelectedSet->id != it->id) {
+		_megagroupSetField->setText(it->shortName);
+		_megagroupSetField->finishAnimations();
+	}
+	_megagroupSelectedSet = std::make_unique<Row>(it->id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh);
+	_itemsTop += st::lineWidth + _rowHeight;
+
+	if (!_megagroupSelectedRemove) {
+		_megagroupSelectedRemove.create(this, st::groupStickersRemove);
+		_megagroupSelectedRemove->showFast();
+		_megagroupSelectedRemove->setClickedCallback([this] {
+			setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
+		});
+		_megagroupSelectedShadow.create(this);
+		updateControlsGeometry();
+	}
+}
+
 void StickersBox::Inner::rebuild() {
 	_itemsTop = st::membersMarginTop;
 
-	int maxNameWidth = countMaxNameWidth();
+	if (_megagroupSet) {
+		_itemsTop += st::groupStickersFieldPadding.top() + _megagroupSetField->height() + st::groupStickersFieldPadding.bottom();
+		_itemsTop += _megagroupDivider->height() + st::groupStickersSubTitleHeight;
+		rebuildMegagroupSet();
+	}
+
+	auto maxNameWidth = countMaxNameWidth();
 
 	clear();
 	auto &order = ([this]() -> const Stickers::Order & {
@@ -1131,21 +1338,34 @@ void StickersBox::Inner::rebuild() {
 	updateSize();
 }
 
-void StickersBox::Inner::updateSize() {
-	resize(width(), _itemsTop + _rows.size() * _rowHeight + st::membersMarginBottom);
+void StickersBox::Inner::setMegagroupSelectedSet(const MTPInputStickerSet &set) {
+	_megagroupSetInput = set;
+	rebuild();
+	scrollToY.notify(0, true);
+	onUpdateSelected();
+}
+
+void StickersBox::Inner::setMinHeight(int newWidth, int minHeight) {
+	_minHeight = minHeight;
+	updateSize(newWidth);
+}
+
+void StickersBox::Inner::updateSize(int newWidth) {
+	auto naturalHeight = _itemsTop + int(_rows.size()) * _rowHeight + st::membersMarginBottom;
+	resize(newWidth ? newWidth : width(), qMax(_minHeight, naturalHeight));
 	checkLoadMore();
 }
 
 void StickersBox::Inner::updateRows() {
 	int maxNameWidth = countMaxNameWidth();
 	auto &sets = Global::StickerSets();
-	for_const (auto row, _rows) {
+	for_const (auto &row, _rows) {
 		auto it = sets.constFind(row->id);
 		if (it != sets.cend()) {
 			auto &set = it.value();
 			if (!row->sticker) {
-				DocumentData *sticker = nullptr;
-				int pixw = 0, pixh = 0;
+				auto sticker = (DocumentData*)nullptr;
+				auto pixw = 0, pixh = 0;
 				fillSetCover(set, &sticker, &pixw, &pixh);
 				if (sticker) {
 					row->sticker = sticker;
@@ -1172,7 +1392,7 @@ void StickersBox::Inner::updateRows() {
 }
 
 bool StickersBox::Inner::appendSet(const Stickers::Set &set) {
-	for_const (auto row, _rows) {
+	for_const (auto &row, _rows) {
 		if (row->id == set.id) {
 			return false;
 		}
@@ -1212,7 +1432,7 @@ void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameW
 	QString title = fillSetTitle(set, maxNameWidth, &titleWidth);
 	int count = fillSetCount(set);
 
-	_rows.push_back(new Row(set.id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh));
+	_rows.push_back(std::make_unique<Row>(set.id, sticker, count, title, titleWidth, installed, official, unread, archived, removed, pixw, pixh));
 	_animStartTimes.push_back(0);
 }
 
@@ -1288,8 +1508,8 @@ template <typename Check>
 Stickers::Order StickersBox::Inner::collectSets(Check check) const {
 	Stickers::Order result;
 	result.reserve(_rows.size());
-	for_const (auto row, _rows) {
-		if (check(row)) {
+	for_const (auto &row, _rows) {
+		if (check(row.get())) {
 			result.push_back(row->id);
 		}
 	}
@@ -1315,8 +1535,8 @@ Stickers::Order StickersBox::Inner::getRemovedSets() const {
 }
 
 int StickersBox::Inner::getRowIndex(uint64 setId) const {
-	for (auto i = 0, count = _rows.size(); i != count; ++i) {
-		auto row = _rows[i];
+	for (auto i = 0, count = int(_rows.size()); i != count; ++i) {
+		auto &row = _rows[i];
 		if (row->id == setId) {
 			return i;
 		}
@@ -1328,18 +1548,18 @@ void StickersBox::Inner::setFullOrder(const Stickers::Order &order) {
 	for_const (auto setId, order) {
 		auto index = getRowIndex(setId);
 		if (index >= 0) {
-			auto row = _rows[index];
+			auto row = std::move(_rows[index]);
 			auto count = _rows.size();
 			for (auto i = index + 1; i != count; ++i) {
-				_rows[i - 1] = _rows[i];
+				_rows[i - 1] = std::move(_rows[i]);
 			}
-			_rows[count - 1] = row;
+			_rows[count - 1] = std::move(row);
 		}
 	}
 }
 
 void StickersBox::Inner::setRemovedSets(const Stickers::Order &removed) {
-	for (auto i = 0, count = _rows.size(); i != count; ++i) {
+	for (auto i = 0, count = int(_rows.size()); i != count; ++i) {
 		setRowRemoved(i, removed.contains(_rows[i]->id));
 	}
 }
diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h
index 3b0cc4ec9..7b8f9e8cc 100644
--- a/Telegram/SourceFiles/boxes/stickers_box.h
+++ b/Telegram/SourceFiles/boxes/stickers_box.h
@@ -21,6 +21,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #pragma once
 
 #include "boxes/abstract_box.h"
+#include "base/timer.h"
+#include "mtproto/sender.h"
 
 class ConfirmBox;
 
@@ -33,6 +35,8 @@ class PlainShadow;
 class RippleAnimation;
 class SettingsSlider;
 class SlideAnimation;
+class UsernameInput;
+class CrossButton;
 } // namespace Ui
 
 class StickersBox : public BoxContent, public RPCSender {
@@ -48,6 +52,7 @@ public:
 	StickersBox(QWidget*, gsl::not_null<ChannelData*> megagroup);
 
 	void closeHook() override;
+	void setInnerFocus() override;
 
 	~StickersBox();
 
@@ -142,7 +147,7 @@ private:
 int stickerPacksCount(bool includeArchivedOfficial = false);
 
 // This class is hold in header because it requires Qt preprocessing.
-class StickersBox::Inner : public TWidget, private base::Subscriber {
+class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP::Sender {
 	Q_OBJECT
 
 public:
@@ -151,8 +156,13 @@ public:
 	Inner(QWidget *parent, const Stickers::Order &archivedIds);
 	Inner(QWidget *parent, gsl::not_null<ChannelData*> megagroup);
 
+	base::Observable<int> scrollToY;
+	void setInnerFocus();
+
+	void saveGroupSet();
+
 	void rebuild();
-	void updateSize();
+	void updateSize(int newWidth = 0);
 	void updateRows(); // refresh only pack cover stickers
 	bool appendSet(const Stickers::Set &set);
 
@@ -171,6 +181,7 @@ public:
 	}
 
 	void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
+	void setMinHeight(int newWidth, int minHeight);
 
 	int getVisibleTop() const {
 		return _visibleTop;
@@ -180,10 +191,12 @@ public:
 
 protected:
 	void paintEvent(QPaintEvent *e) override;
+	void resizeEvent(QResizeEvent *e) override;
 	void mousePressEvent(QMouseEvent *e) override;
 	void mouseMoveEvent(QMouseEvent *e) override;
 	void mouseReleaseEvent(QMouseEvent *e) override;
 	void leaveEventHook(QEvent *e) override;
+	void leaveToChildEvent(QEvent *e, QWidget *child) override;
 
 signals:
 	void draggingScrollDelta(int delta);
@@ -192,6 +205,29 @@ public slots:
 	void onUpdateSelected();
 
 private:
+	struct Row {
+		Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh);
+		bool isRecentSet() const {
+			return (id == Stickers::CloudRecentSetId);
+		}
+		~Row();
+
+		uint64 id = 0;
+		DocumentData *sticker = nullptr;
+		int32 count = 0;
+		QString title;
+		int titleWidth = 0;
+		bool installed = false;
+		bool official = false;
+		bool unread = false;
+		bool archived = false;
+		bool removed = false;
+		int32 pixw = 0;
+		int32 pixh = 0;
+		anim::value yadd;
+		std::unique_ptr<Ui::RippleAnimation> ripple;
+	};
+
 	template <typename Check>
 	Stickers::Order collectSets(Check check) const;
 
@@ -200,63 +236,40 @@ private:
 	int getRowIndex(uint64 setId) const;
 	void setRowRemoved(int index, bool removed);
 
+	void setSelected(int selected);
 	void setActionDown(int newActionDown);
+	void setPressed(int pressed);
 	void setup();
 	QRect relativeButtonRect(bool removeButton) const;
 	void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
 
 	void step_shifting(TimeMs ms, bool timer);
-	void paintRow(Painter &p, int index, TimeMs ms);
-	void paintFakeButton(Painter &p, int index, TimeMs ms);
+	void paintRow(Painter &p, Row *set, int index, TimeMs ms);
+	void paintFakeButton(Painter &p, Row *set, int index, TimeMs ms);
 	void clear();
 	void setActionSel(int32 actionSel);
 	float64 aboveShadowOpacity() const;
 
 	void readVisibleSets();
 
-	Section _section;
-	Stickers::Order _archivedIds;
-
-	int32 _rowHeight;
-	struct Row {
-		Row(uint64 id, DocumentData *sticker, int32 count, const QString &title, int titleWidth, bool installed, bool official, bool unread, bool archived, bool removed, int32 pixw, int32 pixh) : id(id)
-			, sticker(sticker)
-			, count(count)
-			, title(title)
-			, titleWidth(titleWidth)
-			, installed(installed)
-			, official(official)
-			, unread(unread)
-			, archived(archived)
-			, removed(removed)
-			, pixw(pixw)
-			, pixh(pixh)
-			, yadd(0, 0) {
-		}
-		bool isRecentSet() const {
-			return (id == Stickers::CloudRecentSetId);
-		}
-		uint64 id;
-		DocumentData *sticker;
-		int32 count;
-		QString title;
-		int titleWidth;
-		bool installed, official, unread, archived, removed;
-		int32 pixw, pixh;
-		anim::value yadd;
-		QSharedPointer<Ui::RippleAnimation> ripple;
-	};
-	using Rows = QList<Row*>;
-
+	void updateControlsGeometry();
 	void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
 	void fillSetCover(const Stickers::Set &set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
 	int fillSetCount(const Stickers::Set &set) const;
 	QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
 	void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived);
+	void rebuildMegagroupSet();
+	void handleMegagroupSetAddressChange();
+	void setMegagroupSelectedSet(const MTPInputStickerSet &set);
 
 	int countMaxNameWidth() const;
 
-	Rows _rows;
+	Section _section;
+	Stickers::Order _archivedIds;
+
+	int32 _rowHeight;
+
+	std::vector<std::unique_ptr<Row>> _rows;
 	QList<TimeMs> _animStartTimes;
 	TimeMs _aboveShadowFadeStart = 0;
 	anim::value _aboveShadowFadeOpacity;
@@ -288,7 +301,18 @@ private:
 	int _dragging = -1;
 	int _above = -1;
 
+	int _minHeight = 0;
+
 	int _scrollbar = 0;
 	ChannelData *_megagroupSet = nullptr;
+	MTPInputStickerSet _megagroupSetInput = MTP_inputStickerSetEmpty();
+	std::unique_ptr<Row> _megagroupSelectedSet;
+	object_ptr<Ui::UsernameInput> _megagroupSetField = { nullptr };
+	object_ptr<BoxLayerTitleShadow> _megagroupSelectedShadow = { nullptr };
+	object_ptr<Ui::CrossButton> _megagroupSelectedRemove = { nullptr };
+	object_ptr<BoxContentDivider> _megagroupDivider = { nullptr };
+	object_ptr<Ui::FlatLabel> _megagroupSubTitle = { nullptr };
+	base::Timer _megagroupSetAddressChangedTimer;
+	mtpRequestId _megagroupSetRequestId = 0;
 
 };
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
index e94baaf41..ad81a0c15 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
@@ -436,10 +436,10 @@ void StickersListWidget::Footer::step_icons(TimeMs ms, bool timer) {
 
 StickersListWidget::StickersListWidget(QWidget *parent, gsl::not_null<Window::Controller*> controller) : Inner(parent, controller)
 , _section(Section::Stickers)
+, _megagroupSetAbout(st::emojiPanWidth - st::emojiScroll.width - st::emojiPanHeaderLeft)
 , _addText(lang(lng_stickers_featured_add).toUpper())
 , _addWidth(st::stickersTrendingAdd.font->width(_addText))
-, _settings(this, lang(lng_stickers_you_have))
-, _megagroupSetAbout(st::emojiPanWidth - st::emojiScroll.width - st::emojiPanHeaderLeft) {
+, _settings(this, lang(lng_stickers_you_have)) {
 	resize(st::emojiPanWidth - st::emojiScroll.width - st::buttonRadius, countHeight());
 
 	setMouseTracking(true);
@@ -877,7 +877,10 @@ bool StickersListWidget::hasRemoveButton(int index) const {
 	}
 	if (set.id == Stickers::MegagroupSetId) {
 		t_assert(_megagroupSet != nullptr);
-		return set.pack.empty() ? (index + 1 != _mySets.size()) : _megagroupSet->canEditStickers();
+		if (index + 1 != _mySets.size()) {
+			return true;
+		}
+		return !set.pack.empty() && _megagroupSet->canEditStickers();
 	}
 	return false;
 }
@@ -1015,7 +1018,9 @@ void StickersListWidget::mouseReleaseEvent(QMouseEvent *e) {
 			if (_section == Section::Featured) {
 				installSet(sets[button->section].id);
 			} else if (sets[button->section].id == Stickers::MegagroupSetId) {
-				removeMegagroupSet(sets[button->section].pack.empty());
+				auto removeLocally = sets[button->section].pack.empty()
+					|| !_megagroupSet->canEditStickers();
+				removeMegagroupSet(removeLocally);
 			} else {
 				removeSet(sets[button->section].id);
 			}
@@ -1293,36 +1298,53 @@ void StickersListWidget::refreshMegagroupStickers(GroupStickersPlace place) {
 	if (!_megagroupSet) {
 		return;
 	}
+	auto canEdit = _megagroupSet->canEditStickers();
+	auto isShownHere = [place](bool hidden) {
+		return (hidden == (place == GroupStickersPlace::Hidden));
+	};
 	if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetEmpty) {
-		if (_megagroupSet->canEditStickers()) {
+		if (canEdit) {
 			auto hidden = Auth().data().isGroupStickersSectionHidden(_megagroupSet->id);
-			if (hidden == (place == GroupStickersPlace::Hidden)) {
+			if (isShownHere(hidden)) {
 				_mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), 0));
 			}
 		}
 		return;
 	}
-	if (place != GroupStickersPlace::Visible) {
-		return;
-	}
-	if (Auth().data().isGroupStickersSectionHidden(_megagroupSet->id)) {
-		Auth().data().removeGroupStickersSectionHidden(_megagroupSet->id);
-		Local::writeUserSettings();
+	auto hidden = Auth().data().isGroupStickersSectionHidden(_megagroupSet->id);
+	auto removeHiddenForGroup = [this, &hidden] {
+		if (hidden) {
+			Auth().data().removeGroupStickersSectionHidden(_megagroupSet->id);
+			Local::writeUserSettings();
+			hidden = false;
+		}
+	};
+	if (canEdit && hidden) {
+		removeHiddenForGroup();
 	}
 	if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) {
 		auto &set = _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID();
 		auto &sets = Global::StickerSets();
 		auto it = sets.constFind(set.vid.v);
 		if (it != sets.cend()) {
-			_mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), it->stickers.size() + 1, it->stickers));
+			auto isInstalled = (it->flags & MTPDstickerSet::Flag::f_installed)
+				&& !(it->flags & MTPDstickerSet::Flag::f_archived);
+			if (isInstalled && !canEdit) {
+				removeHiddenForGroup();
+			} else if (isShownHere(hidden)) {
+				_mySets.push_back(Set(Stickers::MegagroupSetId, qFlags(MTPDstickerSet_ClientFlag::f_special), lang(lng_group_stickers), it->stickers.size() + 1, it->stickers));
+			}
 			return;
 		}
 	}
+	if (!isShownHere(hidden)) {
+		return;
+	}
 	request(MTPmessages_GetStickerSet(_megagroupSet->mgInfo->stickerSet)).done([this](const MTPmessages_StickerSet &result) {
 		if (auto set = Stickers::FeedSetFull(result)) {
 			refreshStickers();
 		}
-	});
+	}).send();
 }
 
 void StickersListWidget::fillIcons(QList<StickerIcon> &icons) {
@@ -1417,6 +1439,9 @@ void StickersListWidget::updateSelected() {
 				newSelected = OverButton { section };
 			} else if (!(sets[section].flags & MTPDstickerSet_ClientFlag::f_special)) {
 				newSelected = OverSet { section };
+			} else if (sets[section].id == Stickers::MegagroupSetId
+					&& (_megagroupSet->canEditStickers() || !sets[section].pack.empty())) {
+				newSelected = OverSet { section };
 			}
 		} else if (p.y() >= info.rowsTop && p.y() < info.rowsBottom && sx >= 0) {
 			auto yOffset = p.y() - info.rowsTop;
@@ -1578,6 +1603,21 @@ void StickersListWidget::showMegagroupSet(ChannelData *megagroup) {
 }
 
 void StickersListWidget::displaySet(uint64 setId) {
+	if (setId == Stickers::MegagroupSetId) {
+		if (_megagroupSet->canEditStickers()) {
+			_displayingSetId = setId;
+			auto box = Ui::show(Box<StickersBox>(_megagroupSet));
+			connect(box, &QObject::destroyed, this, [this] {
+				_displayingSetId = 0;
+				emit checkForHide();
+			});
+			return;
+		} else if (_megagroupSet->mgInfo->stickerSet.type() == mtpc_inputStickerSetID) {
+			setId = _megagroupSet->mgInfo->stickerSet.c_inputStickerSetID().vid.v;
+		} else {
+			return;
+		}
+	}
 	auto &sets = Global::StickerSets();
 	auto it = sets.constFind(setId);
 	if (it != sets.cend()) {
@@ -1608,8 +1648,8 @@ void StickersListWidget::installSet(uint64 setId) {
 	}
 }
 
-void StickersListWidget::removeMegagroupSet(bool empty) {
-	if (empty) {
+void StickersListWidget::removeMegagroupSet(bool locally) {
+	if (locally) {
 		Auth().data().setGroupStickersSectionHidden(_megagroupSet->id);
 		Local::writeUserSettings();
 		refreshStickers();
@@ -1675,4 +1715,6 @@ void StickersListWidget::removeSet(uint64 setId) {
 	}
 }
 
+StickersListWidget::~StickersListWidget() = default;
+
 } // namespace ChatHelpers
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
index e81740e44..b25a1829c 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
@@ -62,6 +62,8 @@ public:
 	void notInstalledLocally(uint64 setId);
 	void clearInstalledLocally();
 
+	~StickersListWidget();
+
 protected:
 	void mousePressEvent(QMouseEvent *e) override;
 	void mouseReleaseEvent(QMouseEvent *e) override;
@@ -148,7 +150,7 @@ private:
 
 	void displaySet(uint64 setId);
 	void installSet(uint64 setId);
-	void removeMegagroupSet(bool empty);
+	void removeMegagroupSet(bool locally);
 	void removeSet(uint64 setId);
 
 	bool setHasTitle(const Set &set) const;
diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.cpp b/Telegram/SourceFiles/ui/widgets/input_fields.cpp
index 13ad489d5..a1cd85ce2 100644
--- a/Telegram/SourceFiles/ui/widgets/input_fields.cpp
+++ b/Telegram/SourceFiles/ui/widgets/input_fields.cpp
@@ -3435,7 +3435,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
 
 		auto placeholderTop = anim::interpolate(0, _st.placeholderShift, placeholderShiftDegree);
 
-		QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
+		QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
 		r.moveTop(r.top() + placeholderTop);
 		if (rtl()) r.moveLeft(width() - r.left() - r.width());
 
@@ -3460,7 +3460,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
 
 			auto placeholderLeft = anim::interpolate(0, -_st.placeholderShift, placeholderHiddenDegree);
 
-			QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
+			QRect r(rect().marginsRemoved(_textMargins + _st.placeholderMargins));
 			r.moveLeft(r.left() + placeholderLeft);
 			if (rtl()) r.moveLeft(width() - r.left() - r.width());
 
@@ -3469,6 +3469,7 @@ void MaskedInputField::paintEvent(QPaintEvent *e) {
 			p.drawText(r, _placeholder, _st.placeholderAlign);
 
 			p.restore();
+			p.setOpacity(1.);
 		}
 	}
 
@@ -3525,7 +3526,7 @@ void MaskedInputField::resizeEvent(QResizeEvent *e) {
 
 void MaskedInputField::refreshPlaceholder() {
 	auto placeholderText = _placeholderFactory ? _placeholderFactory() : QString();
-	auto availableWidth = width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1;
+	auto availableWidth = width() - _textMargins.left() - _textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1;
 	if (_st.placeholderScale > 0.) {
 		auto placeholderFont = _st.placeholderFont->f;
 		placeholderFont.setStyleStrategy(QFont::PreferMatch);
@@ -3609,7 +3610,7 @@ void MaskedInputField::startPlaceholderAnimation() {
 }
 
 QRect MaskedInputField::placeholderRect() const {
-	return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins);
+	return rect().marginsRemoved(_textMargins + _st.placeholderMargins);
 }
 
 void MaskedInputField::placeholderAdditionalPrepare(Painter &p, TimeMs ms) {
@@ -3893,8 +3894,12 @@ void PortInput::correctValue(const QString &was, int32 wasCursor, QString &now,
 	setCorrectedText(now, nowCursor, newText, newPos);
 }
 
-UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, base::lambda<QString()> placeholderFactory, const QString &val, bool isLink) : MaskedInputField(parent, st, std::move(placeholderFactory), val)
-, _linkPlaceholder(isLink ? Messenger::Instance().createInternalLink(QString()) : QString()) {
+UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, base::lambda<QString()> placeholderFactory, const QString &val, bool isLink) : MaskedInputField(parent, st, std::move(placeholderFactory), val) {
+	setLinkPlaceholder(isLink ? Messenger::Instance().createInternalLink(QString()) : QString());
+}
+
+void UsernameInput::setLinkPlaceholder(const QString &placeholder) {
+	_linkPlaceholder = placeholder;
 	if (!_linkPlaceholder.isEmpty()) {
 		setTextMargins(style::margins(_st.textMargins.left() + _st.font->width(_linkPlaceholder), _st.textMargins.top(), _st.textMargins.right(), _st.textMargins.bottom()));
 		setPlaceholderHidden(true);
diff --git a/Telegram/SourceFiles/ui/widgets/input_fields.h b/Telegram/SourceFiles/ui/widgets/input_fields.h
index 49f0d40f0..b9eeb885d 100644
--- a/Telegram/SourceFiles/ui/widgets/input_fields.h
+++ b/Telegram/SourceFiles/ui/widgets/input_fields.h
@@ -878,6 +878,8 @@ class UsernameInput : public MaskedInputField {
 public:
 	UsernameInput(QWidget *parent, const style::InputField &st, base::lambda<QString()> placeholderFactory, const QString &val, bool isLink);
 
+	void setLinkPlaceholder(const QString &placeholder);
+
 protected:
 	void correctValue(const QString &was, int wasCursor, QString &now, int &nowCursor) override;
 	void paintAdditionalPlaceholder(Painter &p, TimeMs ms) override;