diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
index 1ab8dbf0e..82dc9dc39 100644
--- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp
+++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp
@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "apiwrap.h"
 #include "base/event_filter.h"
 #include "boxes/premium_limits_box.h"
+#include "boxes/premium_preview_box.h"
 #include "chat_helpers/emoji_suggestions_widget.h"
 #include "chat_helpers/message_field.h"
 #include "chat_helpers/tabbed_panel.h"
@@ -25,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_session.h"
 #include "data/data_user.h"
 #include "data/data_premium_limits.h"
+#include "data/stickers/data_stickers.h"
 #include "data/stickers/data_custom_emoji.h"
 #include "editor/photo_editor_layer_widget.h"
 #include "history/history_drag_area.h"
@@ -502,14 +504,22 @@ void EditCaptionBox::setupEmojiPanel() {
 	_emojiPanel->hide();
 	_emojiPanel->selector()->setCurrentPeer(_historyItem->history()->peer);
 	_emojiPanel->selector()->emojiChosen(
-	) | rpl::start_with_next([=](Selector::EmojiChosen data) {
+	) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
 		Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
 	}, lifetime());
 	_emojiPanel->selector()->customEmojiChosen(
-	) | rpl::start_with_next([=](Selector::FileChosen data) {
-		Data::InsertCustomEmoji(_field.get(), data.document);
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
+		const auto info = data.document->sticker();
+		if (info
+			&& info->setType == Data::StickersType::Emoji
+			&& !_controller->session().premium()) {
+			ShowPremiumPreviewBox(
+				_controller,
+				PremiumPreview::AnimatedEmoji);
+		} else {
+			Data::InsertCustomEmoji(_field.get(), data.document);
+		}
 	}, lifetime());
-	_emojiPanel->selector()->showPromoForPremiumEmoji();
 
 	const auto filterCallback = [=](not_null<QEvent*> event) {
 		emojiFilterForGeometry(event);
diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp
index 1cf3d45c6..25119bb08 100644
--- a/Telegram/SourceFiles/boxes/send_files_box.cpp
+++ b/Telegram/SourceFiles/boxes/send_files_box.cpp
@@ -26,6 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "core/mime_type.h"
 #include "base/event_filter.h"
 #include "boxes/premium_limits_box.h"
+#include "boxes/premium_preview_box.h"
 #include "ui/boxes/confirm_box.h"
 #include "ui/effects/animations.h"
 #include "ui/effects/scroll_content_shadow.h"
@@ -48,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "data/data_document.h"
 #include "data/data_user.h"
 #include "data/data_premium_limits.h"
+#include "data/stickers/data_stickers.h"
 #include "data/stickers/data_custom_emoji.h"
 #include "media/clip/media_clip_reader.h"
 #include "api/api_common.h"
@@ -744,14 +746,23 @@ void SendFilesBox::setupEmojiPanel() {
 	_emojiPanel->selector()->setAllowEmojiWithoutPremium(
 		_allowEmojiWithoutPremium);
 	_emojiPanel->selector()->emojiChosen(
-	) | rpl::start_with_next([=](Selector::EmojiChosen data) {
+	) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
 		Ui::InsertEmojiAtCursor(_caption->textCursor(), data.emoji);
 	}, lifetime());
 	_emojiPanel->selector()->customEmojiChosen(
-	) | rpl::start_with_next([=](Selector::FileChosen data) {
-		Data::InsertCustomEmoji(_caption.data(), data.document);
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
+		const auto info = data.document->sticker();
+		if (info
+			&& info->setType == Data::StickersType::Emoji
+			&& !_controller->session().premium()
+			&& !_allowEmojiWithoutPremium) {
+			ShowPremiumPreviewBox(
+				_controller,
+				PremiumPreview::AnimatedEmoji);
+		} else {
+			Data::InsertCustomEmoji(_caption.data(), data.document);
+		}
 	}, lifetime());
-	_emojiPanel->selector()->showPromoForPremiumEmoji();
 
 	const auto filterCallback = [=](not_null<QEvent*> event) {
 		emojiFilterForGeometry(event);
diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp
index 320bad243..ed7783548 100644
--- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp
+++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp
@@ -154,6 +154,25 @@ void ValidatePremiumStarFg(QImage &image) {
 	star.render(&p, outer);
 }
 
+[[nodiscard]] TextForMimeData PrepareTextFromEmoji(
+		not_null<DocumentData*> document) {
+	const auto info = document->sticker();
+	const auto text = info ? info->alt : QString();
+	return {
+		.expanded = text,
+		.rich = {
+			text,
+			{
+				EntityInText(
+					EntityType::CustomEmoji,
+					0,
+					text.size(),
+					Data::SerializeCustomEmojiId(document))
+			},
+		},
+	};
+}
+
 } // namespace
 
 StickerPremiumMark::StickerPremiumMark(not_null<Main::Session*> session) {
@@ -264,6 +283,9 @@ private:
 
 	void visibleTopBottomUpdated(int visibleTop, int visibleBottom) override;
 
+	[[nodiscard]] Ui::MessageSendingAnimationFrom messageSentAnimationInfo(
+		int index,
+		not_null<DocumentData*> document) const;
 	[[nodiscard]] QSize boundingBoxSize() const;
 
 	void paintSticker(
@@ -291,7 +313,10 @@ private:
 	void gotSet(const MTPmessages_StickerSet &set);
 	void installDone(const MTPmessages_StickerSetInstallResult &result);
 
-	void send(not_null<DocumentData*> sticker, Api::SendOptions options);
+	void chosen(
+		int index,
+		not_null<DocumentData*> sticker,
+		Api::SendOptions options);
 
 	not_null<Lottie::MultiPlayer*> getLottiePlayer();
 
@@ -920,74 +945,113 @@ void StickerSetBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
 	}
 	_previewTimer.cancel();
 	const auto index = stickerFromGlobalPos(e->globalPos());
-	if (index < 0
-		|| index >= _pack.size()
-		|| setType() != Data::StickersType::Stickers) {
+	if (index < 0 || index >= _pack.size()) {
 		return;
 	}
-	send(_pack[index], {});
+	chosen(index, _pack[index], {});
 }
 
-void StickerSetBox::Inner::send(
+void StickerSetBox::Inner::chosen(
+		int index,
 		not_null<DocumentData*> sticker,
 		Api::SendOptions options) {
 	const auto controller = _controller;
+	const auto animation = options.scheduled
+		? Ui::MessageSendingAnimationFrom()
+		: messageSentAnimationInfo(index, sticker);
 	Ui::PostponeCall(controller, [=] {
-		if (controller->content()->sendExistingDocument(sticker, options)) {
-			controller->window().hideSettingsAndLayer();
-		}
+		controller->stickerOrEmojiChosen({
+			.document = sticker,
+			.options = options,
+			.messageSendingFrom = animation,
+		});
 	});
 }
 
+auto StickerSetBox::Inner::messageSentAnimationInfo(
+	int index,
+	not_null<DocumentData*> document) const
+-> Ui::MessageSendingAnimationFrom {
+	if (index < 0 || index >= _pack.size() || _pack[index] != document) {
+		return {};
+	}
+	const auto row = index / _perRow;
+	const auto column = index % _perRow;
+	const auto left = _padding.left() + column * _singleSize.width();
+	const auto top = _padding.top() + row * _singleSize.height();
+	const auto rect = QRect(QPoint(left, top), _singleSize);
+	const auto size = ChatHelpers::ComputeStickerSize(
+		document,
+		boundingBoxSize());
+	const auto innerPos = QPoint(
+		(rect.width() - size.width()) / 2,
+		(rect.height() - size.height()) / 2);
+	return {
+		.type = Ui::MessageSendingAnimationFrom::Type::Sticker,
+		.localId = _controller->session().data().nextLocalMessageId(),
+		.globalStartGeometry = mapToGlobal(
+			QRect(rect.topLeft() + innerPos, size)),
+	};
+}
+
 void StickerSetBox::Inner::contextMenuEvent(QContextMenuEvent *e) {
 	const auto index = stickerFromGlobalPos(e->globalPos());
 	if (index < 0
 		|| index >= _pack.size()
-		|| setType() != Data::StickersType::Stickers) {
-		return;
-	}
-	const auto type = _controller->content()->sendMenuType();
-	if (type == SendMenu::Type::Disabled) {
+		|| setType() == Data::StickersType::Masks) {
 		return;
 	}
 	_previewTimer.cancel();
 	_menu = base::make_unique_q<Ui::PopupMenu>(
 		this,
 		st::popupMenuWithIcons);
+	const auto type = _controller->content()->sendMenuType();
+	if (setType() == Data::StickersType::Emoji) {
+		if (const auto t = PrepareTextFromEmoji(_pack[index]); !t.empty()) {
+			_menu->addAction(tr::lng_mediaview_copy(tr::now), [=] {
+				if (auto data = TextUtilities::MimeDataFromText(t)) {
+					QGuiApplication::clipboard()->setMimeData(data.release());
+				}
+			}, &st::menuIconCopy);
+		}
+	} else if (type != SendMenu::Type::Disabled) {
+		const auto document = _pack[index];
+		const auto sendSelected = [=](Api::SendOptions options) {
+			chosen(index, document, options);
+		};
+		SendMenu::FillSendMenu(
+			_menu.get(),
+			type,
+			SendMenu::DefaultSilentCallback(sendSelected),
+			SendMenu::DefaultScheduleCallback(this, type, sendSelected));
 
-	const auto document = _pack[index];
-	const auto sendSelected = [=](Api::SendOptions options) {
-		send(document, options);
-	};
-	SendMenu::FillSendMenu(
-		_menu.get(),
-		type,
-		SendMenu::DefaultSilentCallback(sendSelected),
-		SendMenu::DefaultScheduleCallback(this, type, sendSelected));
-
-	const auto controller = _controller;
-	const auto toggleFavedSticker = [=] {
-		Api::ToggleFavedSticker(
-			controller,
-			document,
-			Data::FileOriginStickerSet(Data::Stickers::FavedSetId, 0));
-	};
-	const auto isFaved = document->owner().stickers().isFaved(document);
-	_menu->addAction(
-		(isFaved
-			? tr::lng_faved_stickers_remove
-			: tr::lng_faved_stickers_add)(tr::now),
-		toggleFavedSticker,
-		(isFaved
-			? &st::menuIconUnfave
-			: &st::menuIconFave));
-
-	_menu->popup(QCursor::pos());
+		const auto controller = _controller;
+		const auto toggleFavedSticker = [=] {
+			Api::ToggleFavedSticker(
+				controller,
+				document,
+				Data::FileOriginStickerSet(Data::Stickers::FavedSetId, 0));
+		};
+		const auto isFaved = document->owner().stickers().isFaved(document);
+		_menu->addAction(
+			(isFaved
+				? tr::lng_faved_stickers_remove
+				: tr::lng_faved_stickers_add)(tr::now),
+			toggleFavedSticker,
+			(isFaved
+				? &st::menuIconUnfave
+				: &st::menuIconFave));
+	}
+	if (_menu->empty()) {
+		_menu = nullptr;
+	} else {
+		_menu->popup(QCursor::pos());
+	}
 }
 
 void StickerSetBox::Inner::updateSelected() {
 	auto selected = stickerFromGlobalPos(QCursor::pos());
-	setSelected(setType() != Data::StickersType::Stickers ? -1 : selected);
+	setSelected(setType() == Data::StickersType::Masks ? -1 : selected);
 }
 
 void StickerSetBox::Inner::setSelected(int selected) {
@@ -1092,9 +1156,10 @@ uint64 StickerSetBox::Inner::setId() const {
 
 QSize StickerSetBox::Inner::boundingBoxSize() const {
 	if (isEmojiSet()) {
-		const auto factor = style::DevicePixelRatio();
-		const auto large = Ui::Emoji::GetSizeLarge() / factor;
-		return QSize(large, large);
+		using namespace Data;
+		const auto size = FrameSizeFromTag(CustomEmojiSizeTag::Large)
+			/ style::DevicePixelRatio();
+		return { size, size };
 	}
 	return QSize(
 		_singleSize.width() - st::roundRadiusSmall * 2,
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
index bf0448281..cbbaf421a 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp
@@ -46,8 +46,6 @@ constexpr auto kAppearDuration = 0.3;
 
 using Core::RecentEmojiId;
 using Core::RecentEmojiDocument;
-using EmojiChosen = TabbedSelector::EmojiChosen;
-using FileChosen = TabbedSelector::FileChosen;
 
 } // namespace
 
@@ -504,10 +502,6 @@ rpl::producer<FileChosen> EmojiListWidget::customChosen() const {
 	return _customChosen.events();
 }
 
-rpl::producer<FileChosen> EmojiListWidget::premiumChosen() const {
-	return _premiumChosen.events();
-}
-
 rpl::producer<> EmojiListWidget::jumpedToPremium() const {
 	return _jumpedToPremium.events();
 }
@@ -1294,14 +1288,9 @@ void EmojiListWidget::selectEmoji(EmojiChosen data) {
 
 void EmojiListWidget::selectCustom(FileChosen data) {
 	const auto document = data.document;
-	if (document->isPremiumEmoji()
-		&& !document->session().premium()
-		&& !_allowWithoutPremium) {
-		_premiumChosen.fire(std::move(data));
-		return;
-	}
-	auto &settings = Core::App().settings();
-	if (_mode == Mode::Full) {
+	const auto skip = (document->isPremiumEmoji() && !session().premium());
+	if (!skip && _mode == Mode::Full) {
+		auto &settings = Core::App().settings();
 		settings.incrementRecentEmoji({ RecentEmojiDocument{
 			document->id,
 			document->session().isTestMode(),
diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
index f0d9389bb..b76a3cb96 100644
--- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.h
@@ -85,8 +85,6 @@ class EmojiListWidget
 	, public Ui::AbstractTooltipShower {
 public:
 	using Mode = EmojiListMode;
-	using EmojiChosen = TabbedSelector::EmojiChosen;
-	using FileChosen = TabbedSelector::FileChosen;
 
 	EmojiListWidget(
 		QWidget *parent,
@@ -115,7 +113,6 @@ public:
 
 	[[nodiscard]] rpl::producer<EmojiChosen> chosen() const;
 	[[nodiscard]] rpl::producer<FileChosen> customChosen() const;
-	[[nodiscard]] rpl::producer<FileChosen> premiumChosen() const;
 	[[nodiscard]] rpl::producer<> jumpedToPremium() const;
 
 	void provideRecent(const std::vector<DocumentId> &customRecentList);
@@ -382,7 +379,6 @@ private:
 
 	rpl::event_stream<EmojiChosen> _chosen;
 	rpl::event_stream<FileChosen> _customChosen;
-	rpl::event_stream<FileChosen> _premiumChosen;
 	rpl::event_stream<> _jumpedToPremium;
 
 };
diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
index 8930c8ca0..8044aabfc 100644
--- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
+++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "menu/menu_send.h" // SendMenu::FillSendMenu
 #include "chat_helpers/stickers_lottie.h"
 #include "chat_helpers/message_field.h" // PrepareMentionTag.
+#include "chat_helpers/tabbed_selector.h" // ChatHelpers::FileChosen.
 #include "mainwindow.h"
 #include "apiwrap.h"
 #include "api/api_chat_participants.h"
@@ -1127,7 +1128,7 @@ bool FieldAutocomplete::Inner::chooseAtIndex(
 				};
 			};
 
-			_stickerChosen.fire({ document, options, method, from() });
+			_stickerChosen.fire({ document, options, from() });
 			return true;
 		}
 	} else if (!_mrows->empty()) {
diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h
index aff798543..240547d98 100644
--- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.h
+++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.h
@@ -38,6 +38,9 @@ namespace SendMenu {
 enum class Type;
 } // namespace SendMenu
 
+namespace ChatHelpers {
+struct FileChosen;
+} // namespace ChatHelpers
 
 class FieldAutocomplete final : public Ui::RpWidget {
 public:
@@ -73,22 +76,17 @@ public:
 	};
 	struct MentionChosen {
 		not_null<UserData*> user;
-		ChooseMethod method;
+		ChooseMethod method = ChooseMethod::ByEnter;
 	};
 	struct HashtagChosen {
 		QString hashtag;
-		ChooseMethod method;
+		ChooseMethod method = ChooseMethod::ByEnter;
 	};
 	struct BotCommandChosen {
 		QString command;
-		ChooseMethod method;
-	};
-	struct StickerChosen {
-		not_null<DocumentData*> sticker;
-		Api::SendOptions options;
-		ChooseMethod method;
-		Ui::MessageSendingAnimationFrom messageSendingFrom;
+		ChooseMethod method = ChooseMethod::ByEnter;
 	};
+	using StickerChosen = ChatHelpers::FileChosen;
 	enum class Type {
 		Mentions,
 		Hashtags,
diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
index 5754fb5e0..0f49f2580 100644
--- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp
@@ -220,12 +220,11 @@ GifsListWidget::GifsListWidget(
 	_mosaic.setRightSkip(st::inlineResultsSkip);
 }
 
-rpl::producer<TabbedSelector::FileChosen> GifsListWidget::fileChosen() const {
+rpl::producer<FileChosen> GifsListWidget::fileChosen() const {
 	return _fileChosen.events();
 }
 
-auto GifsListWidget::photoChosen() const
--> rpl::producer<TabbedSelector::PhotoChosen> {
+rpl::producer<PhotoChosen> GifsListWidget::photoChosen() const {
 	return _photoChosen.events();
 }
 
diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h
index af0163cf4..4571a9e6b 100644
--- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.h
@@ -49,15 +49,13 @@ class GifsListWidget
 	: public TabbedSelector::Inner
 	, public InlineBots::Layout::Context {
 public:
-	using InlineChosen = TabbedSelector::InlineChosen;
-
 	GifsListWidget(
 		QWidget *parent,
 		not_null<Window::SessionController*> controller,
 		Window::GifPauseReason level);
 
-	rpl::producer<TabbedSelector::FileChosen> fileChosen() const;
-	rpl::producer<TabbedSelector::PhotoChosen> photoChosen() const;
+	rpl::producer<FileChosen> fileChosen() const;
+	rpl::producer<PhotoChosen> photoChosen() const;
 	rpl::producer<InlineChosen> inlineResultChosen() const;
 
 	void refreshRecent() override;
@@ -190,8 +188,8 @@ private:
 	QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
 	mtpRequestId _inlineRequestId = 0;
 
-	rpl::event_stream<TabbedSelector::FileChosen> _fileChosen;
-	rpl::event_stream<TabbedSelector::PhotoChosen> _photoChosen;
+	rpl::event_stream<FileChosen> _fileChosen;
+	rpl::event_stream<PhotoChosen> _photoChosen;
 	rpl::event_stream<InlineChosen> _inlineResultChosen;
 	rpl::event_stream<> _cancelled;
 
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
index 29b0686c1..19e9b15fb 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
+++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp
@@ -232,7 +232,7 @@ StickersListWidget::StickersListWidget(
 	}, lifetime());
 }
 
-rpl::producer<TabbedSelector::FileChosen> StickersListWidget::chosen() const {
+rpl::producer<FileChosen> StickersListWidget::chosen() const {
 	return _chosen.events();
 }
 
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
index 46dca8b8c..3ca5e4b6a 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
+++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.h
@@ -65,7 +65,7 @@ public:
 		Window::GifPauseReason level,
 		bool masks = false);
 
-	rpl::producer<TabbedSelector::FileChosen> chosen() const;
+	rpl::producer<FileChosen> chosen() const;
 	rpl::producer<> scrollUpdated() const;
 	rpl::producer<TabbedSelector::Action> choosingUpdated() const;
 
@@ -389,7 +389,7 @@ private:
 	QString _searchQuery, _searchNextQuery;
 	mtpRequestId _searchRequestId = 0;
 
-	rpl::event_stream<TabbedSelector::FileChosen> _chosen;
+	rpl::event_stream<FileChosen> _chosen;
 	rpl::event_stream<> _scrollUpdated;
 	rpl::event_stream<TabbedSelector::Action> _choosingUpdated;
 
diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
index 765b9abb2..25c2830db 100644
--- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
+++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp
@@ -492,21 +492,16 @@ bool TabbedSelector::hasMasksTab() const {
 	return _hasMasksTab;
 }
 
-auto TabbedSelector::emojiChosen() const -> rpl::producer<EmojiChosen> {
+rpl::producer<EmojiChosen> TabbedSelector::emojiChosen() const {
 	return emoji()->chosen();
 }
 
-auto TabbedSelector::customEmojiChosen() const -> rpl::producer<FileChosen> {
+rpl::producer<FileChosen> TabbedSelector::customEmojiChosen() const {
 	return emoji()->customChosen();
 }
 
-auto TabbedSelector::premiumEmojiChosen() const
--> rpl::producer<FileChosen> {
-	return emoji()->premiumChosen();
-}
-
-auto TabbedSelector::fileChosen() const -> rpl::producer<FileChosen> {
-	auto never = rpl::never<TabbedSelector::FileChosen>(
+rpl::producer<FileChosen> TabbedSelector::fileChosen() const {
+	auto never = rpl::never<FileChosen>(
 	) | rpl::type_erased();
 	return rpl::merge(
 		hasStickersTab() ? stickers()->chosen() : never,
@@ -514,8 +509,7 @@ auto TabbedSelector::fileChosen() const -> rpl::producer<FileChosen> {
 		hasMasksTab() ? masks()->chosen() : never);
 }
 
-auto TabbedSelector::photoChosen() const
--> rpl::producer<TabbedSelector::PhotoChosen>{
+rpl::producer<PhotoChosen> TabbedSelector::photoChosen() const {
 	return hasGifsTab() ? gifs()->photoChosen() : nullptr;
 }
 
@@ -865,13 +859,6 @@ void TabbedSelector::setCurrentPeer(PeerData *peer) {
 		peer && Data::AllowEmojiWithoutPremium(peer));
 }
 
-void TabbedSelector::showPromoForPremiumEmoji() {
-	premiumEmojiChosen(
-	) | rpl::start_with_next([=] {
-		ShowPremiumPreviewBox(_controller, PremiumPreview::AnimatedEmoji);
-	}, lifetime());
-}
-
 void TabbedSelector::provideRecentEmoji(
 		const std::vector<DocumentId> &customRecentList) {
 	for (const auto &tab : _tabs) {
diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h
index a01c546ca..a00e85edf 100644
--- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.h
+++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.h
@@ -47,6 +47,10 @@ struct EmojiPan;
 
 namespace ChatHelpers {
 
+class EmojiListWidget;
+class StickersListWidget;
+class GifsListWidget;
+
 enum class SelectorTab {
 	Emoji,
 	Stickers,
@@ -54,27 +58,27 @@ enum class SelectorTab {
 	Masks,
 };
 
-class EmojiListWidget;
-class StickersListWidget;
-class GifsListWidget;
+struct FileChosen {
+	not_null<DocumentData*> document;
+	Api::SendOptions options;
+	Ui::MessageSendingAnimationFrom messageSendingFrom;
+};
+
+struct PhotoChosen {
+	not_null<PhotoData*> photo;
+	Api::SendOptions options;
+};
+
+struct EmojiChosen {
+	EmojiPtr emoji;
+	Ui::MessageSendingAnimationFrom messageSendingFrom;
+};
+
+using InlineChosen = InlineBots::ResultSelected;
 
 class TabbedSelector : public Ui::RpWidget {
 public:
 	static constexpr auto kPickCustomTimeId = -1;
-	struct FileChosen {
-		not_null<DocumentData*> document;
-		Api::SendOptions options;
-		Ui::MessageSendingAnimationFrom messageSendingFrom;
-	};
-	struct PhotoChosen {
-		not_null<PhotoData*> photo;
-		Api::SendOptions options;
-	};
-	struct EmojiChosen {
-		EmojiPtr emoji;
-		Ui::MessageSendingAnimationFrom messageSendingFrom;
-	};
-	using InlineChosen = InlineBots::ResultSelected;
 	enum class Mode {
 		Full,
 		EmojiOnly,
@@ -98,7 +102,6 @@ public:
 
 	rpl::producer<EmojiChosen> emojiChosen() const;
 	rpl::producer<FileChosen> customEmojiChosen() const;
-	rpl::producer<FileChosen> premiumEmojiChosen() const;
 	rpl::producer<FileChosen> fileChosen() const;
 	rpl::producer<PhotoChosen> photoChosen() const;
 	rpl::producer<InlineChosen> inlineResultChosen() const;
@@ -113,7 +116,6 @@ public:
 	void setRoundRadius(int radius);
 	void refreshStickers();
 	void setCurrentPeer(PeerData *peer);
-	void showPromoForPremiumEmoji();
 	void provideRecentEmoji(const std::vector<DocumentId> &customRecentList);
 
 	void hideFinished();
diff --git a/Telegram/SourceFiles/editor/controllers/stickers_panel_controller.cpp b/Telegram/SourceFiles/editor/controllers/stickers_panel_controller.cpp
index 00991ee6a..91748f82d 100644
--- a/Telegram/SourceFiles/editor/controllers/stickers_panel_controller.cpp
+++ b/Telegram/SourceFiles/editor/controllers/stickers_panel_controller.cpp
@@ -37,7 +37,7 @@ StickersPanelController::StickersPanelController(
 auto StickersPanelController::stickerChosen() const
 -> rpl::producer<not_null<DocumentData*>> {
 	return _stickersPanel->selector()->fileChosen(
-	) | rpl::map([](const ChatHelpers::TabbedSelector::FileChosen &data) {
+	) | rpl::map([](const ChatHelpers::FileChosen &data) {
 		return data.document;
 	});
 }
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index e213b437a..f55f041cc 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -423,14 +423,6 @@ HistoryWidget::HistoryWidget(
 		insertHashtagOrBotCommand(data.command, data.method);
 	}, lifetime());
 
-	_fieldAutocomplete->stickerChosen(
-	) | rpl::start_with_next([=](FieldAutocomplete::StickerChosen data) {
-		controller->sendingAnimation().appendSending(
-			data.messageSendingFrom);
-		const auto localId = data.messageSendingFrom.localId;
-		sendExistingDocument(data.sticker, data.options, localId);
-	}, lifetime());
-
 	_fieldAutocomplete->setModerateKeyActivateCallback([=](int key) {
 		const auto context = [=](FullMsgId itemId) {
 			return _list->prepareClickContext(Qt::LeftButton, itemId);
@@ -1067,48 +1059,48 @@ void HistoryWidget::initTabbedSelector() {
 	selector->emojiChosen(
 	) | rpl::filter([=] {
 		return !isHidden() && !_field->isHidden();
-	}) | rpl::start_with_next([=](Selector::EmojiChosen data) {
+	}) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
 		Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
 	}, lifetime());
 
-	selector->customEmojiChosen(
-	) | rpl::filter([=] {
-		return !isHidden() && !_field->isHidden();
-	}) | rpl::start_with_next([=](Selector::FileChosen data) {
-		Data::InsertCustomEmoji(_field.data(), data.document);
-	}, lifetime());
-
-	selector->premiumEmojiChosen(
-	) | rpl::filter([=] {
-		return !isHidden() && !_field->isHidden();
-	}) | rpl::start_with_next([=](Selector::FileChosen data) {
-		showPremiumToast(data.document);
-	}, lifetime());
-
-	selector->fileChosen(
-	) | filter | rpl::start_with_next([=](Selector::FileChosen data) {
-		controller()->sendingAnimation().appendSending(
-			data.messageSendingFrom);
-		sendExistingDocument(
-			data.document,
-			data.options,
-			data.messageSendingFrom.localId);
+	rpl::merge(
+		selector->fileChosen() | filter,
+		_fieldAutocomplete->stickerChosen(),
+		selector->customEmojiChosen() | filter,
+		controller()->stickerOrEmojiChosen() | filter
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
+		controller()->hideLayer(anim::type::normal);
+		if (const auto info = data.document->sticker()
+			; info && info->setType == Data::StickersType::Emoji) {
+			if (data.document->isPremiumEmoji()
+				&& !session().premium()
+				&& (!_peer || !Data::AllowEmojiWithoutPremium(_peer))) {
+				showPremiumToast(data.document);
+			} else if (!_field->isHidden()) {
+				Data::InsertCustomEmoji(_field.data(), data.document);
+			}
+		} else {
+			controller()->sendingAnimation().appendSending(
+				data.messageSendingFrom);
+			const auto localId = data.messageSendingFrom.localId;
+			sendExistingDocument(data.document, data.options, localId);
+		}
 	}, lifetime());
 
 	selector->photoChosen(
-	) | filter | rpl::start_with_next([=](Selector::PhotoChosen data) {
+	) | filter | rpl::start_with_next([=](ChatHelpers::PhotoChosen data) {
 		sendExistingPhoto(data.photo, data.options);
 	}, lifetime());
 
 	selector->inlineResultChosen(
-	) | filter | rpl::filter([=](const Selector::InlineChosen &data) {
+	) | filter | rpl::filter([=](const ChatHelpers::InlineChosen &data) {
 		if (!data.recipientOverride) {
 			return true;
 		} else if (data.recipientOverride != _peer) {
 			showHistory(data.recipientOverride->id, ShowAtTheEndMsgId);
 		}
 		return (data.recipientOverride == _peer);
-	}) | rpl::start_with_next([=](Selector::InlineChosen data) {
+	}) | rpl::start_with_next([=](ChatHelpers::InlineChosen data) {
 		sendInlineResult(data);
 	}, lifetime());
 
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
index ef7632918..16d1e9396 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
@@ -1072,7 +1072,7 @@ rpl::producer<PhotoChosen> ComposeControls::photoChosen() const {
 }
 
 auto ComposeControls::inlineResultChosen() const
-->rpl::producer<ChatHelpers::TabbedSelector::InlineChosen> {
+-> rpl::producer<InlineChosen> {
 	return _inlineResultChosen.events();
 }
 
@@ -1525,11 +1525,7 @@ void ComposeControls::initAutocomplete() {
 		//_saveDraftStart = crl::now();
 		//saveDraft();
 		//saveCloudDraft(); // won't be needed if SendInlineBotResult will clear the cloud draft
-		_fileChosen.fire(FileChosen{
-			.document = data.sticker,
-			.options = data.options,
-			.messageSendingFrom = base::take(data.messageSendingFrom),
-		});
+		_fileChosen.fire(std::move(data));
 	}, _autocomplete->lifetime());
 
 	_autocomplete->choosingProcesses(
@@ -1857,28 +1853,33 @@ void ComposeControls::initTabbedSelector() {
 		return base::EventFilterResult::Continue;
 	});
 
-	using EmojiChosen = ChatHelpers::TabbedSelector::EmojiChosen;
 	selector->emojiChosen(
-	) | rpl::start_with_next([=](EmojiChosen data) {
+	) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
 		Ui::InsertEmojiAtCursor(_field->textCursor(), data.emoji);
 	}, wrap->lifetime());
 
-	using FileChosen = ChatHelpers::TabbedSelector::FileChosen;
-	selector->customEmojiChosen(
-	) | rpl::start_with_next([=](FileChosen data) {
-		Data::InsertCustomEmoji(_field, data.document);
-	}, wrap->lifetime());
-
-	selector->premiumEmojiChosen(
-	) | rpl::start_with_next([=](FileChosen data) {
-		if (_unavailableEmojiPasted) {
-			_unavailableEmojiPasted(data.document);
+	rpl::merge(
+		selector->fileChosen(),
+		selector->customEmojiChosen(),
+		_window->stickerOrEmojiChosen()
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen &&data) {
+		if (const auto info = data.document->sticker()
+			; info && info->setType == Data::StickersType::Emoji) {
+			if (data.document->isPremiumEmoji()
+				&& !session().premium()
+				&& (!_history
+					|| !Data::AllowEmojiWithoutPremium(_history->peer))) {
+				if (_unavailableEmojiPasted) {
+					_unavailableEmojiPasted(data.document);
+				}
+			} else {
+				Data::InsertCustomEmoji(_field, data.document);
+			}
+		} else {
+			_fileChosen.fire(std::move(data));
 		}
 	}, wrap->lifetime());
 
-	selector->fileChosen(
-	) | rpl::start_to_stream(_fileChosen, wrap->lifetime());
-
 	selector->photoChosen(
 	) | rpl::start_to_stream(_photoChosen, wrap->lifetime());
 
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
index ab5947546..1a08bf3c5 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.h
@@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/rp_widget.h"
 #include "ui/effects/animations.h"
 #include "ui/widgets/input_fields.h"
-#include "chat_helpers/tabbed_selector.h"
 
 class History;
 class FieldAutocomplete;
@@ -28,6 +27,8 @@ enum class Type;
 namespace ChatHelpers {
 class TabbedPanel;
 class TabbedSelector;
+struct FileChosen;
+struct PhotoChosen;
 } // namespace ChatHelpers
 
 namespace Data {
@@ -43,6 +44,7 @@ class ItemBase;
 class Widget;
 } // namespace Layout
 class Result;
+struct ResultSelected;
 } // namespace InlineBots
 
 namespace Ui {
@@ -78,9 +80,9 @@ class WebpageProcessor;
 
 class ComposeControls final {
 public:
-	using FileChosen = ChatHelpers::TabbedSelector::FileChosen;
-	using PhotoChosen = ChatHelpers::TabbedSelector::PhotoChosen;
-	using InlineChosen = ChatHelpers::TabbedSelector::InlineChosen;
+	using FileChosen = ChatHelpers::FileChosen;
+	using PhotoChosen = ChatHelpers::PhotoChosen;
+	using InlineChosen = InlineBots::ResultSelected;
 
 	using MessageToEdit = Controls::MessageToEdit;
 	using VoiceToSend = Controls::VoiceToSend;
diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
index 486e5076e..befb660ec 100644
--- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp
@@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_item_components.h"
 #include "history/history_item.h"
 #include "menu/menu_send.h" // SendMenu::Type.
+#include "ui/chat/attach/attach_prepare.h"
+#include "ui/chat/attach/attach_send_files_way.h"
 #include "ui/chat/pinned_bar.h"
 #include "ui/chat/chat_style.h"
 #include "ui/widgets/scroll_area.h"
@@ -28,8 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/toast/toast.h"
 #include "ui/text/format_values.h"
 #include "ui/text/text_utilities.h"
-#include "ui/chat/attach/attach_prepare.h"
-#include "ui/chat/attach/attach_send_files_way.h"
 #include "ui/effects/message_sending_animation_controller.h"
 #include "ui/special_buttons.h"
 #include "ui/ui_utility.h"
@@ -40,6 +40,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "api/api_sending.h"
 #include "apiwrap.h"
 #include "ui/boxes/confirm_box.h"
+#include "chat_helpers/tabbed_selector.h"
 #include "boxes/delete_messages_box.h"
 #include "boxes/edit_caption_box.h"
 #include "boxes/send_files_box.h"
@@ -573,22 +574,21 @@ void RepliesWidget::setupComposeControls() {
 	using Selector = ChatHelpers::TabbedSelector;
 
 	_composeControls->fileChosen(
-	) | rpl::start_with_next([=](Selector::FileChosen chosen) {
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
+		controller()->hideLayer(anim::type::normal);
 		controller()->sendingAnimation().appendSending(
-			chosen.messageSendingFrom);
-		sendExistingDocument(
-			chosen.document,
-			chosen.options,
-			chosen.messageSendingFrom.localId);
+			data.messageSendingFrom);
+		const auto localId = data.messageSendingFrom.localId;
+		sendExistingDocument(data.document, data.options, localId);
 	}, lifetime());
 
 	_composeControls->photoChosen(
-	) | rpl::start_with_next([=](Selector::PhotoChosen chosen) {
+	) | rpl::start_with_next([=](ChatHelpers::PhotoChosen chosen) {
 		sendExistingPhoto(chosen.photo, chosen.options);
 	}, lifetime());
 
 	_composeControls->inlineResultChosen(
-	) | rpl::start_with_next([=](Selector::InlineChosen chosen) {
+	) | rpl::start_with_next([=](ChatHelpers::InlineChosen chosen) {
 		controller()->sendingAnimation().appendSending(
 			chosen.messageSendingFrom);
 		const auto localId = chosen.messageSendingFrom.localId;
diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
index aff4ed513..42f3a3b8f 100644
--- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp
@@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "base/call_delayed.h"
 #include "base/qt/qt_key_modifiers.h"
 #include "core/file_utilities.h"
+#include "chat_helpers/tabbed_selector.h"
 #include "main/main_session.h"
 #include "data/data_chat_participant_status.h"
 #include "data/data_session.h"
@@ -263,17 +264,18 @@ void ScheduledWidget::setupComposeControls() {
 	using Selector = ChatHelpers::TabbedSelector;
 
 	_composeControls->fileChosen(
-	) | rpl::start_with_next([=](Selector::FileChosen chosen) {
-		sendExistingDocument(chosen.document);
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
+		controller()->hideLayer(anim::type::normal);
+		sendExistingDocument(data.document);
 	}, lifetime());
 
 	_composeControls->photoChosen(
-	) | rpl::start_with_next([=](Selector::PhotoChosen chosen) {
+	) | rpl::start_with_next([=](ChatHelpers::PhotoChosen chosen) {
 		sendExistingPhoto(chosen.photo);
 	}, lifetime());
 
 	_composeControls->inlineResultChosen(
-	) | rpl::start_with_next([=](Selector::InlineChosen chosen) {
+	) | rpl::start_with_next([=](ChatHelpers::InlineChosen chosen) {
 		sendInlineResult(chosen.result, chosen.bot);
 	}, lifetime());
 
diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
index 709151501..37c85b4ae 100644
--- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
+++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp
@@ -778,10 +778,8 @@ void Selector::createList(not_null<Window::SessionController*> controller) {
 		})
 	).data();
 
-	rpl::merge(
-		_list->customChosen(),
-		_list->premiumChosen()
-	) | rpl::start_with_next([=](TabbedSelector::FileChosen data) {
+	_list->customChosen(
+	) | rpl::start_with_next([=](ChatHelpers::FileChosen data) {
 		const auto id = DocumentId{ data.document->id };
 		const auto i = defaultReactionIds.find(id);
 		const auto reactionId = (i != end(defaultReactionIds))
diff --git a/Telegram/SourceFiles/info/profile/info_profile_emoji_status_panel.cpp b/Telegram/SourceFiles/info/profile/info_profile_emoji_status_panel.cpp
index 270972809..6a00a9f62 100644
--- a/Telegram/SourceFiles/info/profile/info_profile_emoji_status_panel.cpp
+++ b/Telegram/SourceFiles/info/profile/info_profile_emoji_status_panel.cpp
@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "ui/boxes/time_picker_box.h"
 #include "ui/text/format_values.h"
 #include "base/unixtime.h"
+#include "boxes/premium_preview_box.h"
 #include "window/window_session_controller.h"
 #include "window/window_controller.h"
 #include "main/main_session.h"
@@ -246,7 +247,6 @@ void EmojiStatusPanel::create(
 		st::emojiPanMinHeight / 2,
 		st::emojiPanMinHeight);
 	_panel->hide();
-	_panel->selector()->setAllowEmojiWithoutPremium(false);
 
 	struct Chosen {
 		DocumentId id = 0;
@@ -260,7 +260,7 @@ void EmojiStatusPanel::create(
 	}, _panel->lifetime());
 
 	auto statusChosen = _panel->selector()->customEmojiChosen(
-	) | rpl::map([=](Selector::FileChosen data) {
+	) | rpl::map([=](ChatHelpers::FileChosen data) {
 		return Chosen{
 			.id = data.document->id,
 			.until = data.options.scheduled,
@@ -269,7 +269,7 @@ void EmojiStatusPanel::create(
 	});
 
 	auto emojiChosen = _panel->selector()->emojiChosen(
-	) | rpl::map([=](Selector::EmojiChosen data) {
+	) | rpl::map([=](ChatHelpers::EmojiChosen data) {
 		return Chosen{ .animation = data.messageSendingFrom };
 	});
 
@@ -285,7 +285,9 @@ void EmojiStatusPanel::create(
 		std::move(statusChosen),
 		std::move(emojiChosen)
 	) | rpl::start_with_next([=](const Chosen chosen) {
-		if (chosen.until == Selector::kPickCustomTimeId) {
+		if (chosen.id && !controller->session().premium()) {
+			ShowPremiumPreviewBox(controller, PremiumPreview::EmojiStatus);
+		} else if (chosen.until == Selector::kPickCustomTimeId) {
 			_panel->hideAnimated();
 			controller->show(Box(PickUntilBox, [=](TimeId seconds) {
 				set({ chosen.id, base::unixtime::now() + seconds });
@@ -295,8 +297,6 @@ void EmojiStatusPanel::create(
 			_panel->hideAnimated();
 		}
 	}, _panel->lifetime());
-
-	_panel->selector()->showPromoForPremiumEmoji();
 }
 
 void EmojiStatusPanel::startAnimation(
diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp
index 7455f1a26..a42c67b34 100644
--- a/Telegram/SourceFiles/window/window_session_controller.cpp
+++ b/Telegram/SourceFiles/window/window_session_controller.cpp
@@ -1611,6 +1611,15 @@ rpl::producer<int> SessionController::connectingBottomSkipValue() const {
 	return _connectingBottomSkip.value();
 }
 
+void SessionController::stickerOrEmojiChosen(FileChosen chosen) {
+	_stickerOrEmojiChosen.fire(std::move(chosen));
+}
+
+auto SessionController::stickerOrEmojiChosen() const
+-> rpl::producer<FileChosen> {
+	return _stickerOrEmojiChosen.events();
+}
+
 QPointer<Ui::BoxContent> SessionController::show(
 		object_ptr<Ui::BoxContent> content,
 		Ui::LayerOptions options,
diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h
index 64fdfd232..dab6cf802 100644
--- a/Telegram/SourceFiles/window/window_session_controller.h
+++ b/Telegram/SourceFiles/window/window_session_controller.h
@@ -32,6 +32,7 @@ enum class WindowLayout;
 namespace ChatHelpers {
 class TabbedSelector;
 class EmojiInteractions;
+struct FileChosen;
 } // namespace ChatHelpers
 
 namespace Main {
@@ -317,6 +318,10 @@ public:
 	void setConnectingBottomSkip(int skip);
 	rpl::producer<int> connectingBottomSkipValue() const;
 
+	using FileChosen = ChatHelpers::FileChosen;
+	void stickerOrEmojiChosen(FileChosen chosen);
+	[[nodiscard]] rpl::producer<FileChosen> stickerOrEmojiChosen() const;
+
 	QPointer<Ui::BoxContent> show(
 		object_ptr<Ui::BoxContent> content,
 		Ui::LayerOptions options = Ui::LayerOption::KeepOther,
@@ -585,6 +590,8 @@ private:
 
 	rpl::variable<int> _connectingBottomSkip;
 
+	rpl::event_stream<ChatHelpers::FileChosen> _stickerOrEmojiChosen;
+
 	PeerData *_showEditPeer = nullptr;
 	rpl::variable<Data::Folder*> _openedFolder;