diff --git a/Telegram/Resources/icons/chat/input_forward.png b/Telegram/Resources/icons/chat/input_forward.png
index c04e20ceb..2d9c78335 100644
Binary files a/Telegram/Resources/icons/chat/input_forward.png and b/Telegram/Resources/icons/chat/input_forward.png differ
diff --git a/Telegram/Resources/icons/chat/input_forward@2x.png b/Telegram/Resources/icons/chat/input_forward@2x.png
index c500804d0..26e435458 100644
Binary files a/Telegram/Resources/icons/chat/input_forward@2x.png and b/Telegram/Resources/icons/chat/input_forward@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_forward@3x.png b/Telegram/Resources/icons/chat/input_forward@3x.png
index 9df3f2369..488f8e1e1 100644
Binary files a/Telegram/Resources/icons/chat/input_forward@3x.png and b/Telegram/Resources/icons/chat/input_forward@3x.png differ
diff --git a/Telegram/Resources/icons/chat/input_link_settings.png b/Telegram/Resources/icons/chat/input_link_settings.png
new file mode 100644
index 000000000..bd01d4ad1
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_link_settings.png differ
diff --git a/Telegram/Resources/icons/chat/input_link_settings@2x.png b/Telegram/Resources/icons/chat/input_link_settings@2x.png
new file mode 100644
index 000000000..0eb12d203
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_link_settings@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_link_settings@3x.png b/Telegram/Resources/icons/chat/input_link_settings@3x.png
new file mode 100644
index 000000000..851858faf
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_link_settings@3x.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply.png b/Telegram/Resources/icons/chat/input_reply.png
deleted file mode 100644
index f20b99773..000000000
Binary files a/Telegram/Resources/icons/chat/input_reply.png and /dev/null differ
diff --git a/Telegram/Resources/icons/chat/input_reply@2x.png b/Telegram/Resources/icons/chat/input_reply@2x.png
deleted file mode 100644
index e44f5f79e..000000000
Binary files a/Telegram/Resources/icons/chat/input_reply@2x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/chat/input_reply@3x.png b/Telegram/Resources/icons/chat/input_reply@3x.png
deleted file mode 100644
index 97688789f..000000000
Binary files a/Telegram/Resources/icons/chat/input_reply@3x.png and /dev/null differ
diff --git a/Telegram/Resources/icons/chat/input_reply_quote.png b/Telegram/Resources/icons/chat/input_reply_quote.png
new file mode 100644
index 000000000..0f0ade5dc
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_quote.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply_quote@2x.png b/Telegram/Resources/icons/chat/input_reply_quote@2x.png
new file mode 100644
index 000000000..c7bcb7d8e
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_quote@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply_quote@3x.png b/Telegram/Resources/icons/chat/input_reply_quote@3x.png
new file mode 100644
index 000000000..f1bc500a1
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_quote@3x.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply_settings.png b/Telegram/Resources/icons/chat/input_reply_settings.png
new file mode 100644
index 000000000..9b67e535c
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_settings.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply_settings@2x.png b/Telegram/Resources/icons/chat/input_reply_settings@2x.png
new file mode 100644
index 000000000..2a4aef116
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_settings@2x.png differ
diff --git a/Telegram/Resources/icons/chat/input_reply_settings@3x.png b/Telegram/Resources/icons/chat/input_reply_settings@3x.png
new file mode 100644
index 000000000..e2f131d6a
Binary files /dev/null and b/Telegram/Resources/icons/chat/input_reply_settings@3x.png differ
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 0c1422ba9..3f6b89211 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -2714,6 +2714,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 "lng_forwarding_from_two" = "{user} and {second_user}";
 "lng_inline_switch_choose" = "Choose conversation...";
 "lng_inline_switch_cant" = "Sorry, no way to write here :(";
+"lng_preview_reply_to" = "Reply to {name}";
+"lng_preview_reply_to_quote" = "Reply to quote by {name}";
 
 "lng_reply_in_another_title" = "Reply in...";
 "lng_reply_in_another_chat" = "Reply in Another Chat";
diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml
index 87d43e603..b206163a2 100644
--- a/Telegram/Resources/uwp/AppX/AppxManifest.xml
+++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml
@@ -10,7 +10,7 @@
   <Identity Name="TelegramMessengerLLP.TelegramDesktop"
     ProcessorArchitecture="ARCHITECTURE"
     Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
-    Version="4.11.6.0" />
+    Version="4.11.7.0" />
   <Properties>
     <DisplayName>Telegram Desktop</DisplayName>
     <PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc
index 53ffeebbe..0bbf19b2f 100644
--- a/Telegram/Resources/winrc/Telegram.rc
+++ b/Telegram/Resources/winrc/Telegram.rc
@@ -44,8 +44,8 @@ IDI_ICON1               ICON                    "..\\art\\icon256.ico"
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,11,6,0
- PRODUCTVERSION 4,11,6,0
+ FILEVERSION 4,11,7,0
+ PRODUCTVERSION 4,11,7,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Radolyn Labs"
             VALUE "FileDescription", "AyuGram Desktop"
-            VALUE "FileVersion", "4.11.6.0"
+            VALUE "FileVersion", "4.11.7.0"
             VALUE "LegalCopyright", "Copyright (C) 2014-2023"
             VALUE "ProductName", "AyuGram Desktop"
-            VALUE "ProductVersion", "4.11.6.0"
+            VALUE "ProductVersion", "4.11.7.0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc
index 22190fb9d..f9e4d3cfd 100644
--- a/Telegram/Resources/winrc/Updater.rc
+++ b/Telegram/Resources/winrc/Updater.rc
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,11,6,0
- PRODUCTVERSION 4,11,6,0
+ FILEVERSION 4,11,7,0
+ PRODUCTVERSION 4,11,7,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Radolyn Labs"
             VALUE "FileDescription", "AyuGram Desktop Updater"
-            VALUE "FileVersion", "4.11.6.0"
+            VALUE "FileVersion", "4.11.7.0"
             VALUE "LegalCopyright", "Copyright (C) 2014-2023"
             VALUE "ProductName", "AyuGram Desktop"
-            VALUE "ProductVersion", "4.11.6.0"
+            VALUE "ProductVersion", "4.11.7.0"
         END
     END
     BLOCK "VarFileInfo"
diff --git a/Telegram/SourceFiles/api/api_statistics.cpp b/Telegram/SourceFiles/api/api_statistics.cpp
index 383d0973c..1f5c093a6 100644
--- a/Telegram/SourceFiles/api/api_statistics.cpp
+++ b/Telegram/SourceFiles/api/api_statistics.cpp
@@ -18,6 +18,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 namespace Api {
 namespace {
 
+constexpr auto kCheckRequestsTimer = 10 * crl::time(1000);
+
 [[nodiscard]] Data::StatisticalGraph StatisticalGraphFromTL(
 		const MTPStatsGraph &tl) {
 	return tl.match([&](const MTPDstatsGraph &d) {
@@ -187,23 +189,73 @@ namespace {
 
 } // namespace
 
-Statistics::Statistics(not_null<ApiWrap*> api)
-: _api(&api->instance()) {
+Statistics::Statistics(not_null<ChannelData*> channel)
+: StatisticsRequestSender(channel) {
 }
 
-rpl::producer<rpl::no_value, QString> Statistics::request(
-		not_null<PeerData*> peer) {
+StatisticsRequestSender::StatisticsRequestSender(not_null<ChannelData *> channel)
+: _channel(channel)
+, _api(&_channel->session().api().instance())
+, _timer([=] { checkRequests(); }) {
+}
+
+StatisticsRequestSender::~StatisticsRequestSender() {
+	for (const auto &[dcId, ids] : _requests) {
+		for (const auto id : ids) {
+			_channel->session().api().unregisterStatsRequest(dcId, id);
+		}
+	}
+}
+
+void StatisticsRequestSender::checkRequests() {
+	for (auto i = begin(_requests); i != end(_requests);) {
+		for (auto j = begin(i->second); j != end(i->second);) {
+			if (_api.pending(*j)) {
+				++j;
+			} else {
+				_channel->session().api().unregisterStatsRequest(
+					i->first,
+					*j);
+				j = i->second.erase(j);
+			}
+		}
+		if (i->second.empty()) {
+			i = _requests.erase(i);
+		} else {
+			++i;
+		}
+	}
+	if (_requests.empty()) {
+		_timer.cancel();
+	}
+}
+
+template <typename Request, typename, typename>
+auto StatisticsRequestSender::makeRequest(Request &&request) {
+	const auto id = _api.allocateRequestId();
+	const auto dcId = _channel->owner().statsDcId(_channel);
+	if (dcId) {
+		_channel->session().api().registerStatsRequest(dcId, id);
+		_requests[dcId].emplace(id);
+		if (!_timer.isActive()) {
+			_timer.callEach(kCheckRequestsTimer);
+		}
+	}
+	return std::move(_api.request(
+		std::forward<Request>(request)
+	).toDC(
+		dcId ? MTP::ShiftDcId(dcId, MTP::kStatsDcShift) : 0
+	).overrideId(id));
+}
+
+rpl::producer<rpl::no_value, QString> Statistics::request() {
 	return [=](auto consumer) {
 		auto lifetime = rpl::lifetime();
-		const auto channel = peer->asChannel();
-		if (!channel) {
-			return lifetime;
-		}
 
-		if (!channel->isMegagroup()) {
-			_api.request(MTPstats_GetBroadcastStats(
+		if (!channel()->isMegagroup()) {
+			makeRequest(MTPstats_GetBroadcastStats(
 				MTP_flags(MTPstats_GetBroadcastStats::Flags(0)),
-				channel->inputChannel
+				channel()->inputChannel
 			)).done([=](const MTPstats_BroadcastStats &result) {
 				_channelStats = ChannelStatisticsFromTL(result.data());
 				consumer.put_done();
@@ -211,12 +263,13 @@ rpl::producer<rpl::no_value, QString> Statistics::request(
 				consumer.put_error_copy(error.type());
 			}).send();
 		} else {
-			_api.request(MTPstats_GetMegagroupStats(
+			makeRequest(MTPstats_GetMegagroupStats(
 				MTP_flags(MTPstats_GetMegagroupStats::Flags(0)),
-				channel->inputChannel
+				channel()->inputChannel
 			)).done([=](const MTPstats_MegagroupStats &result) {
-				_supergroupStats = SupergroupStatisticsFromTL(result.data());
-				peer->owner().processUsers(result.data().vusers());
+				const auto &data = result.data();
+				_supergroupStats = SupergroupStatisticsFromTL(data);
+				channel()->owner().processUsers(data.vusers());
 				consumer.put_done();
 			}).fail([=](const MTP::Error &error) {
 				consumer.put_error_copy(error.type());
@@ -228,18 +281,13 @@ rpl::producer<rpl::no_value, QString> Statistics::request(
 }
 
 Statistics::GraphResult Statistics::requestZoom(
-		not_null<PeerData*> peer,
 		const QString &token,
 		float64 x) {
 	return [=](auto consumer) {
 		auto lifetime = rpl::lifetime();
-		const auto channel = peer->asChannel();
-		if (!channel) {
-			return lifetime;
-		}
 		const auto wasEmpty = _zoomDeque.empty();
 		_zoomDeque.push_back([=] {
-			_api.request(MTPstats_LoadAsyncGraph(
+			makeRequest(MTPstats_LoadAsyncGraph(
 				MTP_flags(x
 					? MTPstats_LoadAsyncGraph::Flag::f_x
 					: MTPstats_LoadAsyncGraph::Flag(0)),
@@ -266,32 +314,6 @@ Statistics::GraphResult Statistics::requestZoom(
 	};
 }
 
-Statistics::GraphResult Statistics::requestMessage(
-		not_null<PeerData*> peer,
-		MsgId msgId) {
-	return [=](auto consumer) {
-		auto lifetime = rpl::lifetime();
-		const auto channel = peer->asChannel();
-		if (!channel) {
-			return lifetime;
-		}
-
-		_api.request(MTPstats_GetMessageStats(
-			MTP_flags(MTPstats_GetMessageStats::Flags(0)),
-			channel->inputChannel,
-			MTP_int(msgId.bare)
-		)).done([=](const MTPstats_MessageStats &result) {
-			consumer.put_next(
-				StatisticalGraphFromTL(result.data().vviews_graph()));
-			consumer.put_done();
-		}).fail([=](const MTP::Error &error) {
-			consumer.put_error_copy(error.type());
-		}).send();
-
-		return lifetime;
-	};
-}
-
 Data::ChannelStatistics Statistics::channelStats() const {
 	return _channelStats;
 }
@@ -303,9 +325,8 @@ Data::SupergroupStatistics Statistics::supergroupStats() const {
 PublicForwards::PublicForwards(
 	not_null<ChannelData*> channel,
 	FullMsgId fullId)
-: _channel(channel)
-, _fullId(fullId)
-, _api(&channel->session().api().instance()) {
+: StatisticsRequestSender(channel)
+, _fullId(fullId) {
 }
 
 void PublicForwards::request(
@@ -314,19 +335,19 @@ void PublicForwards::request(
 	if (_requestId) {
 		return;
 	}
-	const auto offsetPeer = _channel->owner().peer(token.fullId.peer);
+	const auto offsetPeer = channel()->owner().peer(token.fullId.peer);
 	const auto tlOffsetPeer = offsetPeer
 		? offsetPeer->input
 		: MTP_inputPeerEmpty();
 	constexpr auto kLimit = tl::make_int(100);
-	_requestId = _api.request(MTPstats_GetMessagePublicForwards(
-		_channel->inputChannel,
+	_requestId = makeRequest(MTPstats_GetMessagePublicForwards(
+		channel()->inputChannel,
 		MTP_int(_fullId.msg),
 		MTP_int(token.rate),
 		tlOffsetPeer,
 		MTP_int(token.fullId.msg),
 		kLimit
-	)).done([=, channel = _channel](const MTPmessages_Messages &result) {
+	)).done([=, channel = channel()](const MTPmessages_Messages &result) {
 		using Messages = QVector<FullMsgId>;
 		_requestId = 0;
 
@@ -402,10 +423,9 @@ void PublicForwards::request(
 MessageStatistics::MessageStatistics(
 	not_null<ChannelData*> channel,
 	FullMsgId fullId)
-: _publicForwards(channel, fullId)
-, _channel(channel)
-, _fullId(fullId)
-, _api(&channel->session().api().instance()) {
+: StatisticsRequestSender(channel)
+, _publicForwards(channel, fullId)
+, _fullId(fullId) {
 }
 
 Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
@@ -413,10 +433,9 @@ Data::PublicForwardsSlice MessageStatistics::firstSlice() const {
 }
 
 void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
-	if (_channel->isMegagroup()) {
+	if (channel()->isMegagroup()) {
 		return;
 	}
-
 	const auto requestFirstPublicForwards = [=](
 			const Data::StatisticalGraph &messageGraph,
 			const Data::StatisticsMessageInteractionInfo &info) {
@@ -434,8 +453,8 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
 
 	const auto requestPrivateForwards = [=](
 			const Data::StatisticalGraph &messageGraph) {
-		_api.request(MTPchannels_GetMessages(
-			_channel->inputChannel,
+		api().request(MTPchannels_GetMessages(
+			channel()->inputChannel,
 			MTP_vector<MTPInputMessage>(
 				1,
 				MTP_inputMessageID(MTP_int(_fullId.msg))))
@@ -475,9 +494,9 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
 		}).send();
 	};
 
-	_api.request(MTPstats_GetMessageStats(
+	makeRequest(MTPstats_GetMessageStats(
 		MTP_flags(MTPstats_GetMessageStats::Flags(0)),
-		_channel->inputChannel,
+		channel()->inputChannel,
 		MTP_int(_fullId.msg.bare)
 	)).done([=](const MTPstats_MessageStats &result) {
 		requestPrivateForwards(
@@ -485,7 +504,6 @@ void MessageStatistics::request(Fn<void(Data::MessageStatistics)> done) {
 	}).fail([=](const MTP::Error &error) {
 		requestPrivateForwards({});
 	}).send();
-
 }
 
 Boosts::Boosts(not_null<PeerData*> peer)
diff --git a/Telegram/SourceFiles/api/api_statistics.h b/Telegram/SourceFiles/api/api_statistics.h
index 460c9df9d..dddf3654c 100644
--- a/Telegram/SourceFiles/api/api_statistics.h
+++ b/Telegram/SourceFiles/api/api_statistics.h
@@ -7,30 +7,53 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "base/timer.h"
 #include "data/data_boosts.h"
 #include "data/data_statistics.h"
 #include "mtproto/sender.h"
 
-class ApiWrap;
 class ChannelData;
 class PeerData;
 
 namespace Api {
 
-class Statistics final {
-public:
-	explicit Statistics(not_null<ApiWrap*> api);
+class StatisticsRequestSender {
+protected:
+	explicit StatisticsRequestSender(not_null<ChannelData*> channel);
+	~StatisticsRequestSender();
 
-	[[nodiscard]] rpl::producer<rpl::no_value, QString> request(
-		not_null<PeerData*> peer);
+	template <
+		typename Request,
+		typename = std::enable_if_t<!std::is_reference_v<Request>>,
+		typename = typename Request::Unboxed>
+	[[nodiscard]] auto makeRequest(Request &&request);
+
+	[[nodiscard]] MTP::Sender &api() {
+		return _api;
+	}
+	[[nodiscard]] not_null<ChannelData*> channel() {
+		return _channel;
+	}
+
+private:
+	void checkRequests();
+
+	const not_null<ChannelData*> _channel;
+	MTP::Sender _api;
+	base::Timer _timer;
+	base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _requests;
+
+};
+
+class Statistics final : public StatisticsRequestSender {
+public:
+	explicit Statistics(not_null<ChannelData*> channel);
+
+	[[nodiscard]] rpl::producer<rpl::no_value, QString> request();
 	using GraphResult = rpl::producer<Data::StatisticalGraph, QString>;
 	[[nodiscard]] GraphResult requestZoom(
-		not_null<PeerData*> peer,
 		const QString &token,
 		float64 x);
-	[[nodiscard]] GraphResult requestMessage(
-		not_null<PeerData*> peer,
-		MsgId msgId);
 
 	[[nodiscard]] Data::ChannelStatistics channelStats() const;
 	[[nodiscard]] Data::SupergroupStatistics supergroupStats() const;
@@ -38,31 +61,27 @@ public:
 private:
 	Data::ChannelStatistics _channelStats;
 	Data::SupergroupStatistics _supergroupStats;
-	MTP::Sender _api;
 
 	std::deque<Fn<void()>> _zoomDeque;
 
 };
 
-class PublicForwards final {
+class PublicForwards final : public StatisticsRequestSender {
 public:
-	explicit PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
+	PublicForwards(not_null<ChannelData*> channel, FullMsgId fullId);
 
 	void request(
 		const Data::PublicForwardsSlice::OffsetToken &token,
 		Fn<void(Data::PublicForwardsSlice)> done);
 
 private:
-	const not_null<ChannelData*> _channel;
 	const FullMsgId _fullId;
 	mtpRequestId _requestId = 0;
 	int _lastTotal = 0;
 
-	MTP::Sender _api;
-
 };
 
-class MessageStatistics final {
+class MessageStatistics final : public StatisticsRequestSender {
 public:
 	explicit MessageStatistics(
 		not_null<ChannelData*> channel,
@@ -74,13 +93,11 @@ public:
 
 private:
 	PublicForwards _publicForwards;
-	const not_null<ChannelData*> _channel;
 	const FullMsgId _fullId;
 
 	Data::PublicForwardsSlice _firstSlice;
 
 	mtpRequestId _requestId = 0;
-	MTP::Sender _api;
 
 };
 
diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index c0d7a5bc2..2270743c2 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -118,6 +118,7 @@ constexpr auto kStickersByEmojiInvalidateTimeout = crl::time(6 * 1000);
 constexpr auto kNotifySettingSaveTimeout = crl::time(1000);
 constexpr auto kDialogsFirstLoad = 20;
 constexpr auto kDialogsPerPage = 500;
+constexpr auto kStatsSessionKillTimeout = 10 * crl::time(1000);
 
 using PhotoFileLocationId = Data::PhotoFileLocationId;
 using DocumentFileLocationId = Data::DocumentFileLocationId;
@@ -163,6 +164,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
 , _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
 , _topPromotionTimer([=] { refreshTopPromotion(); })
 , _updateNotifyTimer([=] { sendNotifySettingsUpdates(); })
+, _statsSessionKillTimer([=] { checkStatsSessions(); })
 , _authorizations(std::make_unique<Api::Authorizations>(this))
 , _attachedStickers(std::make_unique<Api::AttachedStickers>(this))
 , _blockedPeers(std::make_unique<Api::BlockedPeers>(this))
@@ -3614,11 +3616,12 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 	sendAction(action);
 
 	const auto clearCloudDraft = action.clearDraft;
+	const auto draftTopicRootId = action.replyTo.topicRootId;
 	const auto replyTo = action.replyTo.messageId
 		? peer->owner().message(action.replyTo.messageId)
 		: nullptr;
-	const auto topicRootId = action.replyTo.topicRootId
-		? action.replyTo.topicRootId
+	const auto topicRootId = draftTopicRootId
+		? draftTopicRootId
 		: replyTo
 		? replyTo->topicRootId()
 		: Data::ForumTopic::kGeneralId;
@@ -3658,7 +3661,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 		TextUtilities::Trim(sending);
 
 		_session->data().registerMessageRandomId(randomId, newId);
-		_session->data().registerMessageSentData(randomId, peer->id, sending.text);
+		_session->data().registerMessageSentData(
+			randomId,
+			peer->id,
+			sending.text);
 
 		MTPstring msgText(MTP_string(sending.text));
 		auto flags = NewMessageFlags(peer);
@@ -3720,8 +3726,8 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 		if (clearCloudDraft) {
 			sendFlags |= MTPmessages_SendMessage::Flag::f_clear_draft;
 			mediaFlags |= MTPmessages_SendMedia::Flag::f_clear_draft;
-			history->clearCloudDraft(topicRootId);
-			history->startSavingCloudDraft(topicRootId);
+			history->clearCloudDraft(draftTopicRootId);
+			history->startSavingCloudDraft(draftTopicRootId);
 		}
 		const auto sendAs = action.options.sendAs;
 		const auto messageFromId = sendAs
@@ -3758,7 +3764,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 				const MTP::Response &response) {
 			if (clearCloudDraft) {
 				history->finishSavingCloudDraft(
-					topicRootId,
+					draftTopicRootId,
 					UnixtimeFromMsgId(response.outerMsgId));
 			}
 		};
@@ -3772,7 +3778,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
 			}
 			if (clearCloudDraft) {
 				history->finishSavingCloudDraft(
-					topicRootId,
+					draftTopicRootId,
 					UnixtimeFromMsgId(response.outerMsgId));
 			}
 		};
@@ -4340,6 +4346,32 @@ void ApiWrap::saveSelfBio(const QString &text) {
 	}).send();
 }
 
+void ApiWrap::registerStatsRequest(MTP::DcId dcId, mtpRequestId id) {
+	_statsRequests[dcId].emplace(id);
+}
+
+void ApiWrap::unregisterStatsRequest(MTP::DcId dcId, mtpRequestId id) {
+	const auto i = _statsRequests.find(dcId);
+	Assert(i != end(_statsRequests));
+	const auto removed = i->second.remove(id);
+	Assert(removed);
+	if (i->second.empty()) {
+		_statsSessionKillTimer.callOnce(kStatsSessionKillTimeout);
+	}
+}
+
+void ApiWrap::checkStatsSessions() {
+	for (auto i = begin(_statsRequests); i != end(_statsRequests);) {
+		if (i->second.empty()) {
+			instance().killSession(
+				MTP::ShiftDcId(i->first, MTP::kStatsDcShift));
+			i = _statsRequests.erase(i);
+		} else {
+			++i;
+		}
+	}
+}
+
 Api::Authorizations &ApiWrap::authorizations() {
 	return *_authorizations;
 }
diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h
index f61eb0957..ecb0f968a 100644
--- a/Telegram/SourceFiles/apiwrap.h
+++ b/Telegram/SourceFiles/apiwrap.h
@@ -369,6 +369,9 @@ public:
 
 	void saveSelfBio(const QString &text);
 
+	void registerStatsRequest(MTP::DcId dcId, mtpRequestId id);
+	void unregisterStatsRequest(MTP::DcId dcId, mtpRequestId id);
+
 	[[nodiscard]] Api::Authorizations &authorizations();
 	[[nodiscard]] Api::AttachedStickers &attachedStickers();
 	[[nodiscard]] Api::BlockedPeers &blockedPeers();
@@ -547,6 +550,8 @@ private:
 		not_null<ChannelData*> channel);
 	void migrateFail(not_null<PeerData*> peer, const QString &error);
 
+	void checkStatsSessions();
+
 	const not_null<Main::Session*> _session;
 
 	base::flat_map<QString, int> _modifyRequests;
@@ -683,6 +688,9 @@ private:
 		QString requestedText;
 	} _bio;
 
+	base::flat_map<MTP::DcId, base::flat_set<mtpRequestId>> _statsRequests;
+	base::Timer _statsSessionKillTimer;
+
 	const std::unique_ptr<Api::Authorizations> _authorizations;
 	const std::unique_ptr<Api::AttachedStickers> _attachedStickers;
 	const std::unique_ptr<Api::BlockedPeers> _blockedPeers;
diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
index d100850ee..3739ef7e3 100644
--- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style
+++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style
@@ -827,11 +827,13 @@ historyEmojiStatusInfoLabel: FlatLabel(historyContactStatusLabel) {
 }
 historyContactStatusMinSkip: 16px;
 
-historyReplySkip: 51px;
+historyReplySkip: 53px;
 historyReplyNameFg: windowActiveTextFg;
 historyReplyHeight: 49px;
-historyReplyIconPosition: point(5px, 5px);
-historyReplyIcon: icon {{ "chat/input_reply", historyReplyIconFg }};
+historyReplyIconPosition: point(7px, 7px);
+historyReplyIcon: icon {{ "chat/input_reply_settings", historyReplyIconFg }};
+historyLinkIcon: icon {{ "chat/input_link_settings", historyReplyIconFg }};
+historyQuoteIcon: icon {{ "chat/input_reply_quote", historyReplyIconFg }};
 historyForwardIcon: icon {{ "chat/input_forward", historyReplyIconFg }};
 historyEditIcon: icon {{ "chat/input_edit", historyReplyIconFg }};
 historyReplyCancel: IconButton {
diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h
index b44f257ca..b32542428 100644
--- a/Telegram/SourceFiles/core/version.h
+++ b/Telegram/SourceFiles/core/version.h
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D666}"_cs;
 constexpr auto AppNameOld = "AyuGram for Windows"_cs;
 constexpr auto AppName = "AyuGram Desktop"_cs;
 constexpr auto AppFile = "AyuGram"_cs;
-constexpr auto AppVersion = 4011006;
-constexpr auto AppVersionStr = "4.11.6";
+constexpr auto AppVersion = 4011007;
+constexpr auto AppVersionStr = "4.11.7";
 constexpr auto AppBetaVersion = false;
 constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
diff --git a/Telegram/SourceFiles/data/data_channel.cpp b/Telegram/SourceFiles/data/data_channel.cpp
index 3b26c1eb9..5daff7e17 100644
--- a/Telegram/SourceFiles/data/data_channel.cpp
+++ b/Telegram/SourceFiles/data/data_channel.cpp
@@ -1120,6 +1120,10 @@ void ApplyChannelUpdate(
 		channel,
 		update.vnotify_settings());
 
+	if (update.vstats_dc()) {
+		channel->owner().applyStatsDcId(channel, update.vstats_dc()->v);
+	}
+
 	if (const auto sendAs = update.vdefault_send_as()) {
 		session->sendAsPeers().setChosen(channel, peerFromMTP(*sendAs));
 	} else {
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 8590e1fa6..85aa659f8 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -4567,6 +4567,19 @@ uint64 Session::wallpapersHash() const {
 	return _wallpapersHash;
 }
 
+MTP::DcId Session::statsDcId(not_null<ChannelData*> channel) {
+	const auto it = _channelStatsDcIds.find(channel);
+	return (it == end(_channelStatsDcIds)) ? MTP::DcId(0) : it->second;
+}
+
+void Session::applyStatsDcId(
+		not_null<ChannelData*> channel,
+		MTP::DcId dcId) {
+	if (dcId != channel->session().mainDcId()) {
+		_channelStatsDcIds[channel] = dcId;
+	}
+}
+
 void Session::webViewResultSent(WebViewResultSent &&sent) {
 	return _webViewResultSent.fire(std::move(sent));
 }
diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h
index c470e3a8b..df6dc5019 100644
--- a/Telegram/SourceFiles/data/data_session.h
+++ b/Telegram/SourceFiles/data/data_session.h
@@ -730,6 +730,9 @@ public:
 	[[nodiscard]] auto peerDecorationsUpdated() const
 		-> rpl::producer<not_null<PeerData*>>;
 
+	void applyStatsDcId(not_null<ChannelData*>, MTP::DcId);
+	[[nodiscard]] MTP::DcId statsDcId(not_null<ChannelData*>);
+
 	void clearLocalStorage();
 
 private:
@@ -1014,6 +1017,8 @@ private:
 	base::flat_map<not_null<UserData*>, TimeId> _watchingForOffline;
 	base::Timer _watchForOfflineTimer;
 
+	base::flat_map<not_null<ChannelData*>, MTP::DcId> _channelStatsDcIds;
+
 	rpl::event_stream<WebViewResultSent> _webViewResultSent;
 
 	rpl::event_stream<not_null<PeerData*>> _peerDecorationsUpdated;
diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp
index e71c3cefd..5299b648c 100644
--- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp
+++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp
@@ -879,7 +879,7 @@ void RowPainter::Paint(
 		}
 		return nullptr;
 	}();
-	const auto previewOptions = [&]() -> HistoryView::ToPreviewOptions {
+	auto previewOptions = [&]() -> HistoryView::ToPreviewOptions {
 		if (topic) {
 			return {};
 		} else if (const auto searchChat = row->searchInChat()) {
@@ -891,6 +891,7 @@ void RowPainter::Paint(
 		}
 		return {};
 	}();
+	previewOptions.ignoreGroup = true;
 
 	const auto badgesState = context.displayUnreadInfo
 		? entry->chatListBadgesState()
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index cdd0811dd..f8f5b9ba7 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -2956,11 +2956,22 @@ FullStoryId HistoryItem::replyToStory() const {
 }
 
 FullReplyTo HistoryItem::replyTo() const {
-	return {
-		.messageId = replyToFullId(),
-		.storyId = replyToStory(),
+	auto result = FullReplyTo{
 		.topicRootId = topicRootId(),
 	};
+	if (const auto reply = Get<HistoryMessageReply>()) {
+		const auto &fields = reply->fields();
+		const auto peer = fields.externalPeerId;
+		const auto replyToPeer = peer ? peer : _history->peer->id;
+		if (const auto id = fields.messageId) {
+			result.messageId = { replyToPeer, id };
+			result.quote = fields.quote;
+		}
+		if (const auto id = fields.storyId) {
+			result.storyId = { replyToPeer, id };
+		}
+	}
+	return result;
 }
 
 void HistoryItem::setText(const TextWithEntities &textWithEntities) {
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index 3c1ad01e6..7049d94d1 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -101,6 +101,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/history_view_pinned_bar.h"
 #include "history/view/history_view_group_call_bar.h"
 #include "history/view/history_view_item_preview.h"
+#include "history/view/history_view_reply.h"
 #include "history/view/history_view_requests_bar.h"
 #include "history/view/history_view_sticker_toast.h"
 #include "history/view/history_view_translate_bar.h"
@@ -4395,11 +4396,10 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
 
 void HistoryWidget::updateOverStates(QPoint pos) {
 	const auto isReadyToForward = readyToForward();
-	const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
 	const auto detailsRect = QRect(
-		skip,
+		0,
 		_field->y() - st::historySendPadding - st::historyReplyHeight,
-		width() - skip - _fieldBarCancel->width(),
+		width() - _fieldBarCancel->width(),
 		st::historyReplyHeight);
 	const auto hasWebPage = !!_previewDrawPreview;
 	const auto inDetails = detailsRect.contains(pos)
@@ -4439,10 +4439,6 @@ void HistoryWidget::leaveToChildEvent(QEvent *e, QWidget *child) { // e -- from
 }
 
 void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) {
-	if (_replyForwardPressed) {
-		_replyForwardPressed = false;
-		update(0, _field->y() - st::historySendPadding - st::historyReplyHeight, width(), st::historyReplyHeight);
-	}
 }
 
 void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
@@ -6264,20 +6260,7 @@ bool HistoryWidget::cornerButtonsHas(HistoryView::CornerButtonType type) {
 
 void HistoryWidget::mousePressEvent(QMouseEvent *e) {
 	const auto isReadyToForward = readyToForward();
-	const auto hasSecondLayer = (_editMsgId
-		|| _replyTo
-		|| isReadyToForward
-		|| _kbReplyTo);
-	_replyForwardPressed = hasSecondLayer && QRect(
-		0,
-		_field->y() - st::historySendPadding - st::historyReplyHeight,
-		st::historyReplySkip,
-		st::historyReplyHeight).contains(e->pos());
-	if (_replyForwardPressed
-			&& !_fieldBarCancel->isHidden()
-			&& !isReadyToForward) {
-		updateField();
-	} else if (_inPhotoEdit && _photoEditMedia) {
+	if (_inPhotoEdit && _photoEditMedia) {
 		EditCaptionBox::StartPhotoEdit(
 			controller(),
 			_photoEditMedia,
@@ -7507,7 +7490,6 @@ void HistoryWidget::cancelEdit() {
 
 void HistoryWidget::cancelFieldAreaState() {
 	controller()->hideLayer();
-	_replyForwardPressed = false;
 	if (_previewDrawPreview) {
 		_preview->apply({ .removed = true });
 	} else if (_editMsgId) {
@@ -7839,25 +7821,23 @@ void HistoryWidget::updateForwarding() {
 }
 
 void HistoryWidget::updateReplyToName() {
-	if (_editMsgId) {
+	if (!_history || _editMsgId) {
 		return;
 	} else if (!_replyEditMsg && (_replyTo || !_kbReplyTo)) {
 		return;
 	}
-	const auto from = [&] {
-		const auto item = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
-		if (const auto from = item->displayFrom()) {
-			return from;
-		}
-		return item->author().get();
-	}();
-	_replyToName.setText(
-		st::msgNameStyle,
-		from->name(),
-		Ui::NameTextOptions());
-	_replyToNameVersion = (_replyEditMsg
-		? _replyEditMsg
-		: _kbReplyTo)->author()->nameVersion();
+	const auto context = Core::MarkedTextContext{
+		.session = &_history->session(),
+		.customEmojiRepaint = [] {},
+		.customEmojiLoopLimit = 1,
+	};
+	const auto to = _replyEditMsg ? _replyEditMsg : _kbReplyTo;
+	const auto replyToQuote = _replyTo && !_replyTo.quote.empty();
+	_replyToName.setMarkedText(
+		st::fwdTextStyle,
+		HistoryView::Reply::ComposePreviewName(_history, to, replyToQuote),
+		Ui::NameTextOptions(),
+		context);
 }
 
 void HistoryWidget::updateField() {
@@ -7877,12 +7857,6 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
 	auto hasForward = readyToForward();
 	auto drawMsgText = (_editMsgId || _replyTo) ? _replyEditMsg : _kbReplyTo;
 	if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
-		if (!_editMsgId
-			&& drawMsgText
-			&& (_replyToNameVersion
-				< drawMsgText->author()->nameVersion())) {
-			updateReplyToName();
-		}
 		backy -= st::historyReplyHeight;
 		backh += st::historyReplyHeight;
 	} else if (hasForward) {
@@ -7892,12 +7866,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
 		backy -= st::historyReplyHeight;
 		backh += st::historyReplyHeight;
 	}
-	auto drawWebPagePreview = _previewDrawPreview && !_replyForwardPressed;
 	p.setInactive(
 		controller()->isGifPausedAtLeastFor(Window::GifPauseReason::Any));
 	p.fillRect(myrtlrect(0, backy, width(), backh), st::historyReplyBg);
 
-	const auto media = (!drawWebPagePreview && drawMsgText)
+	const auto media = (!_previewDrawPreview && drawMsgText)
 		? drawMsgText->media()
 		: nullptr;
 	const auto hasPreview = media && media->hasReplyPreview();
@@ -7911,86 +7884,11 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
 		});
 	}
 
-	if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
-		const auto now = crl::now();
-		const auto paused = p.inactive();
-		const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
-		auto replyLeft = st::historyReplySkip;
-		(_editMsgId ? st::historyEditIcon : st::historyReplyIcon).paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
-		if (!drawWebPagePreview) {
-			if (drawMsgText) {
-				if (hasPreview) {
-					if (preview) {
-						const auto overEdit = _photoEditMedia
-							? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
-							: 0.;
-						auto to = QRect(
-							replyLeft,
-							backy + (st::historyReplyHeight - st::historyReplyPreview) / 2,
-							st::historyReplyPreview,
-							st::historyReplyPreview);
-						p.drawPixmap(to.x(), to.y(), preview->pixSingle(
-							preview->size() / style::DevicePixelRatio(),
-							{
-								.options = Images::Option::RoundSmall,
-								.outer = to.size(),
-							}));
-						if (_replySpoiler) {
-							if (overEdit > 0.) {
-								p.setOpacity(1. - overEdit);
-							}
-							Ui::FillSpoilerRect(
-								p,
-								to,
-								Ui::DefaultImageSpoiler().frame(
-									_replySpoiler->index(now, pausedSpoiler)));
-						}
-						if (overEdit > 0.) {
-							p.setOpacity(overEdit);
-							p.fillRect(to, st::historyEditMediaBg);
-							st::historyEditMedia.paintInCenter(p, to);
-							p.setOpacity(1.);
-						}
-					}
-					replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
-				}
-				p.setPen(st::historyReplyNameFg);
-				if (_editMsgId) {
-					paintEditHeader(p, rect, replyLeft, backy);
-				} else {
-					_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
-				}
-				p.setPen(st::historyComposeAreaFg);
-				_replyEditMsgText.draw(p, {
-					.position = QPoint(
-						replyLeft,
-						backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
-					.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
-					.palette = &st::historyComposeAreaPalette,
-					.spoiler = Ui::Text::DefaultSpoilerCache(),
-					.now = now,
-					.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
-					.pausedSpoiler = pausedSpoiler,
-					.elisionLines = 1,
-				});
-			} else {
-				p.setFont(st::msgDateFont);
-				p.setPen(st::historyComposeAreaFgService);
-				p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
-			}
-		}
-	} else if (hasForward) {
-		st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
-		if (!drawWebPagePreview) {
-			const auto x = st::historyReplySkip;
-			const auto available = width()
-				- x
-				- _fieldBarCancel->width()
-				- st::msgReplyPadding.right();
-			_forwardPanel->paint(p, x, backy, available, width());
-		}
-	}
-	if (drawWebPagePreview) {
+	if (_previewDrawPreview) {
+		st::historyLinkIcon.paint(
+			p,
+			st::historyReplyIconPosition + QPoint(0, backy),
+			width());
 		const auto textTop = backy + st::msgReplyPadding.top();
 		auto previewLeft = st::historyReplySkip;
 
@@ -8019,6 +7917,87 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
 			previewLeft,
 			textTop + st::msgServiceNameFont->height,
 			elidedWidth);
+	} else if (_editMsgId || _replyTo || (!hasForward && _kbReplyTo)) {
+		const auto now = crl::now();
+		const auto paused = p.inactive();
+		const auto pausedSpoiler = paused || On(PowerSaving::kChatSpoiler);
+		auto replyLeft = st::historyReplySkip;
+		(_editMsgId
+			? st::historyEditIcon
+			: (_replyTo && !_replyTo.quote.empty())
+			? st::historyQuoteIcon
+			: st::historyReplyIcon).paint(
+				p,
+				st::historyReplyIconPosition + QPoint(0, backy),
+				width());
+		if (drawMsgText) {
+			if (hasPreview) {
+				if (preview) {
+					const auto overEdit = _photoEditMedia
+						? _inPhotoEditOver.value(_inPhotoEdit ? 1. : 0.)
+						: 0.;
+					auto to = QRect(
+						replyLeft,
+						backy + (st::historyReplyHeight - st::historyReplyPreview) / 2,
+						st::historyReplyPreview,
+						st::historyReplyPreview);
+					p.drawPixmap(to.x(), to.y(), preview->pixSingle(
+						preview->size() / style::DevicePixelRatio(),
+						{
+							.options = Images::Option::RoundSmall,
+							.outer = to.size(),
+						}));
+					if (_replySpoiler) {
+						if (overEdit > 0.) {
+							p.setOpacity(1. - overEdit);
+						}
+						Ui::FillSpoilerRect(
+							p,
+							to,
+							Ui::DefaultImageSpoiler().frame(
+								_replySpoiler->index(now, pausedSpoiler)));
+					}
+					if (overEdit > 0.) {
+						p.setOpacity(overEdit);
+						p.fillRect(to, st::historyEditMediaBg);
+						st::historyEditMedia.paintInCenter(p, to);
+						p.setOpacity(1.);
+					}
+				}
+				replyLeft += st::historyReplyPreview + st::msgReplyBarSkip;
+			}
+			p.setPen(st::historyReplyNameFg);
+			if (_editMsgId) {
+				paintEditHeader(p, rect, replyLeft, backy);
+			} else {
+				_replyToName.drawElided(p, replyLeft, backy + st::msgReplyPadding.top(), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right());
+			}
+			p.setPen(st::historyComposeAreaFg);
+			_replyEditMsgText.draw(p, {
+				.position = QPoint(
+					replyLeft,
+					backy + st::msgReplyPadding.top() + st::msgServiceNameFont->height),
+				.availableWidth = width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right(),
+				.palette = &st::historyComposeAreaPalette,
+				.spoiler = Ui::Text::DefaultSpoilerCache(),
+				.now = now,
+				.pausedEmoji = paused || On(PowerSaving::kEmojiChat),
+				.pausedSpoiler = pausedSpoiler,
+				.elisionLines = 1,
+			});
+		} else {
+			p.setFont(st::msgDateFont);
+			p.setPen(st::historyComposeAreaFgService);
+			p.drawText(replyLeft, backy + (st::historyReplyHeight - st::msgDateFont->height) / 2 + st::msgDateFont->ascent, st::msgDateFont->elided(tr::lng_profile_loading(tr::now), width() - replyLeft - _fieldBarCancel->width() - st::msgReplyPadding.right()));
+		}
+	} else if (hasForward) {
+		st::historyForwardIcon.paint(p, st::historyReplyIconPosition + QPoint(0, backy), width());
+		const auto x = st::historyReplySkip;
+		const auto available = width()
+			- x
+			- _fieldBarCancel->width()
+			- st::msgReplyPadding.right();
+		_forwardPanel->paint(p, x, backy, available, width());
 	}
 }
 
diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h
index 87b7edde9..10a54c858 100644
--- a/Telegram/SourceFiles/history/history_widget.h
+++ b/Telegram/SourceFiles/history/history_widget.h
@@ -647,7 +647,6 @@ private:
 	MTP::Sender _api;
 	FullReplyTo _replyTo;
 	Ui::Text::String _replyToName;
-	int _replyToNameVersion = 0;
 
 	FullReplyTo _processingReplyTo;
 	HistoryItem *_processingReplyItem = nullptr;
@@ -688,8 +687,6 @@ private:
 	Ui::Text::String _previewTitle;
 	Ui::Text::String _previewDescription;
 
-	bool _replyForwardPressed = false;
-
 	PeerData *_peer = nullptr;
 
 	bool _canSendMessages = false;
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 540d4ca5f..8b9ac3393 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp
@@ -51,6 +51,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/controls/history_view_voice_record_bar.h"
 #include "history/view/controls/history_view_ttl_button.h"
 #include "history/view/controls/history_view_webpage_processor.h"
+#include "history/view/history_view_reply.h"
 #include "history/view/history_view_webpage_preview.h"
 #include "inline_bots/bot_attach_web_view.h"
 #include "inline_bots/inline_results_widget.h"
@@ -192,7 +193,6 @@ private:
 	Ui::Text::String _shownMessageText;
 	std::unique_ptr<Ui::SpoilerAnimation> _shownPreviewSpoiler;
 	Ui::Animations::Simple _inPhotoEditOver;
-	int _shownMessageNameVersion = -1;
 	bool _shownMessageHasPreview : 1 = false;
 	bool _inPhotoEdit : 1 = false;
 	bool _photoEditAllowed : 1 = false;
@@ -245,7 +245,6 @@ void FieldHeader::init() {
 		updateVisible();
 	}, lifetime());
 
-	const auto leftIconPressed = lifetime().make_state<bool>(false);
 	paintRequest(
 	) | rpl::start_with_next([=] {
 		Painter p(this);
@@ -253,21 +252,29 @@ void FieldHeader::init() {
 		p.fillRect(rect(), st::historyComposeAreaBg);
 
 		const auto position = st::historyReplyIconPosition;
-		if (isEditingMessage()) {
+		if (_preview.parsed) {
+			st::historyLinkIcon.paint(p, position, width());
+		} else if (isEditingMessage()) {
 			st::historyEditIcon.paint(p, position, width());
 		} else if (readyToForward()) {
 			st::historyForwardIcon.paint(p, position, width());
-		} else if (replyingToMessage()) {
-			st::historyReplyIcon.paint(p, position, width());
+		} else if (const auto reply = replyingToMessage()) {
+			if (!reply.quote.empty()) {
+				st::historyQuoteIcon.paint(p, position, width());
+			} else {
+				st::historyReplyIcon.paint(p, position, width());
+			}
 		}
 
-		(_preview.parsed && !*leftIconPressed)
-			? paintWebPage(
+		if (_preview.parsed) {
+			paintWebPage(
 				p,
-				_history ? _history->peer : _data->session().user())
-			: (isEditingMessage() || !readyToForward())
-			? paintEditOrReplyToMessage(p)
-			: paintForwardInfo(p);
+				_history ? _history->peer : _data->session().user());
+		} else if (isEditingMessage() || !readyToForward()) {
+			paintEditOrReplyToMessage(p);
+		} else {
+			paintForwardInfo(p);
+		}
 	}, lifetime());
 
 	_editMsgId.value(
@@ -359,13 +366,9 @@ void FieldHeader::init() {
 			updateOver(inPreviewRect, inPhotoEdit);
 			return;
 		}
-		const auto isLeftIcon = (pos.x() < st::historyReplySkip);
 		const auto isLeftButton = (e->button() == Qt::LeftButton);
 		if (type == QEvent::MouseButtonPress) {
-			if (isLeftButton && isLeftIcon && !inPreviewRect) {
-				*leftIconPressed = true;
-				update();
-			} else if (isLeftButton && inPhotoEdit) {
+			if (isLeftButton && inPhotoEdit) {
 				_editPhotoRequests.fire({});
 			} else if (isLeftButton && inPreviewRect) {
 				const auto reply = replyingToMessage();
@@ -384,11 +387,6 @@ void FieldHeader::init() {
 					_editOptionsRequests.fire({});
 				}
 			}
-		} else if (type == QEvent::MouseButtonRelease) {
-			if (isLeftButton && *leftIconPressed) {
-				*leftIconPressed = false;
-				update();
-			}
 		}
 	}, lifetime());
 }
@@ -431,9 +429,21 @@ void FieldHeader::setShownMessage(HistoryItem *item) {
 			st::msgNameStyle,
 			tr::lng_edit_message(tr::now),
 			Ui::NameTextOptions());
+	} else if (item) {
+		const auto context = Core::MarkedTextContext{
+			.session = &_history->session(),
+			.customEmojiRepaint = [] {},
+			.customEmojiLoopLimit = 1,
+		};
+		const auto replyTo = _replyTo.current();
+		const auto quote = replyTo && !replyTo.quote.empty();
+		_shownMessageName.setMarkedText(
+			st::fwdTextStyle,
+			HistoryView::Reply::ComposePreviewName(_history, item, quote),
+			Ui::NameTextOptions(),
+			context);
 	} else {
 		_shownMessageName.clear();
-		_shownMessageNameVersion = -1;
 	}
 	updateVisible();
 	update();
@@ -545,19 +555,6 @@ void FieldHeader::paintEditOrReplyToMessage(Painter &p) {
 		return;
 	}
 
-	if (!isEditingMessage()) {
-		const auto user = _shownMessage->displayFrom()
-			? _shownMessage->displayFrom()
-			: _shownMessage->author().get();
-		if (_shownMessageNameVersion < user->nameVersion()) {
-			_shownMessageName.setText(
-				st::msgNameStyle,
-				user->name(),
-				Ui::NameTextOptions());
-			_shownMessageNameVersion = user->nameVersion();
-		}
-	}
-
 	const auto media = _shownMessage->media();
 	_shownMessageHasPreview = media && media->hasReplyPreview();
 	const auto preview = _shownMessageHasPreview
@@ -691,13 +688,11 @@ FullReplyTo FieldHeader::getDraftReply() const {
 }
 
 void FieldHeader::updateControlsGeometry(QSize size) {
-	const auto isReadyToForward = readyToForward();
-	const auto skip = isReadyToForward ? 0 : st::historyReplySkip;
 	_cancel->moveToRight(0, 0);
 	_clickableRect = QRect(
-		skip,
 		0,
-		width() - skip - _cancel->width(),
+		0,
+		width() - _cancel->width(),
 		height());
 	_shownMessagePreviewRect = QRect(
 		st::historyReplySkip,
diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp
index 850ecfe6b..6812cb273 100644
--- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp
+++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp
@@ -642,6 +642,8 @@ void DraftOptionsBox(
 		if (const auto current = state->quote.current()) {
 			result.messageId = current.item->fullId();
 			result.quote = current.text;
+		} else {
+			result.quote = {};
 		}
 		return result;
 	};
diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp
index 9b5334a5c..127049416 100644
--- a/Telegram/SourceFiles/history/view/history_view_element.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_element.cpp
@@ -1676,21 +1676,27 @@ TextSelection Element::FindSelectionFromQuote(
 		}
 		offset = i + 1;
 	}
-	//for (const auto &modification : text.modifications()) {
-	//	if (modification.position >= selection.to) {
-	//		break;
-	//	} else if (modification.position <= selection.from) {
-	//		modified.from += modification.skipped;
-	//		if (modification.added
-	//			&& modification.position < selection.from) {
-	//			--modified.from;
-	//		}
-	//	}
-	//	modified.to += modification.skipped;
-	//	if (modification.added && modified.to > modified.from) {
-	//		--modified.to;
-	//	}
-	//}
+	for (const auto &modification : text.modifications()) {
+		if (modification.position >= result.to) {
+			break;
+		}
+		if (modification.added) {
+			++result.to;
+		}
+		const auto shiftTo = std::min(
+			int(modification.skipped),
+			result.to - modification.position);
+		result.to -= shiftTo;
+		if (modification.position <= result.from) {
+			if (modification.added) {
+				++result.from;
+			}
+			const auto shiftFrom = std::min(
+				int(modification.skipped),
+				result.from - modification.position);
+			result.from -= shiftFrom;
+		}
+	}
 	return result;
 }
 
diff --git a/Telegram/SourceFiles/history/view/history_view_reply.cpp b/Telegram/SourceFiles/history/view/history_view_reply.cpp
index fad3d0e56..2abe667ea 100644
--- a/Telegram/SourceFiles/history/view/history_view_reply.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_reply.cpp
@@ -398,10 +398,11 @@ void Reply::updateName(
 			viaBotUsername = bot->username();
 		}
 	}
+	const auto history = view->history();
 	const auto &fields = data->fields();
 	const auto sender = resolvedSender.value_or(this->sender(view, data));
 	const auto externalPeer = fields.externalPeerId
-		? view->history()->owner().peer(fields.externalPeerId).get()
+		? history->owner().peer(fields.externalPeerId).get()
 		: nullptr;
 	const auto displayAsExternal = data->displayAsExternal(view->data());
 	const auto groupNameAdded = displayAsExternal
@@ -419,38 +420,20 @@ void Reply::updateName(
 			+ st::historyReplyPreviewMargin.right()
 			- st::historyReplyPadding.left())
 		: 0;
-	const auto peerIcon = [](PeerData *peer) {
-		using namespace std;
-		return !peer
-			? pair(&st::historyReplyUser, st::historyReplyUserPadding)
-			: peer->isBroadcast()
-			? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
-			: (peer->isChannel() || peer->isChat())
-			? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
-			: pair(&st::historyReplyUser, st::historyReplyUserPadding);
-	};
-	const auto peerEmoji = [&](PeerData *peer) {
-		const auto owner = &view->history()->owner();
-		const auto icon = peerIcon(peer);
-		return Ui::Text::SingleCustomEmoji(
-			owner->customEmojiManager().registerInternalEmoji(
-				*icon.first,
-				icon.second));
-	};
 	auto nameFull = TextWithEntities();
 	if (displayAsExternal && !groupNameAdded && !fields.storyId) {
-		nameFull.append(peerEmoji(sender));
+		nameFull.append(PeerEmoji(history, sender));
 	}
 	nameFull.append(name);
 	if (groupNameAdded) {
-		nameFull.append(' ').append(peerEmoji(externalPeer));
+		nameFull.append(' ').append(PeerEmoji(history, externalPeer));
 		nameFull.append(externalPeer->name());
 	}
 	if (!viaBotUsername.isEmpty()) {
 		nameFull.append(u" @"_q).append(viaBotUsername);
 	}
 	const auto context = Core::MarkedTextContext{
-		.session = &view->history()->session(),
+		.session = &history->session(),
 		.customEmojiRepaint = [] {},
 		.customEmojiLoopLimit = 1,
 	};
@@ -819,6 +802,61 @@ void Reply::stopLastRipple() {
 	}
 }
 
+TextWithEntities Reply::PeerEmoji(
+		not_null<History*> history,
+		PeerData *peer) {
+	using namespace std;
+	const auto icon = !peer
+		? pair(&st::historyReplyUser, st::historyReplyUserPadding)
+		: peer->isBroadcast()
+		? pair(&st::historyReplyChannel, st::historyReplyChannelPadding)
+		: (peer->isChannel() || peer->isChat())
+		? pair(&st::historyReplyGroup, st::historyReplyGroupPadding)
+		: pair(&st::historyReplyUser, st::historyReplyUserPadding);
+	const auto owner = &history->owner();
+	return Ui::Text::SingleCustomEmoji(
+		owner->customEmojiManager().registerInternalEmoji(
+			*icon.first,
+			icon.second));
+}
+
+TextWithEntities Reply::ComposePreviewName(
+		not_null<History*> history,
+		not_null<HistoryItem*> to,
+		bool quote) {
+	const auto sender = [&] {
+		if (const auto from = to->displayFrom()) {
+			return not_null(from);
+		}
+		return to->author();
+	}();
+	const auto toPeer = to->history()->peer;
+	const auto displayAsExternal = (to->history() != history);
+	const auto groupNameAdded = displayAsExternal
+		&& (toPeer != sender)
+		&& (toPeer->isChat() || toPeer->isMegagroup());
+	const auto shorten = groupNameAdded || quote;
+
+	auto nameFull = TextWithEntities();
+	using namespace HistoryView;
+	if (displayAsExternal && !groupNameAdded) {
+		nameFull.append(Reply::PeerEmoji(history, sender));
+	}
+	nameFull.append(shorten ? sender->shortName() : sender->name());
+	if (groupNameAdded) {
+		nameFull.append(' ').append(Reply::PeerEmoji(history, toPeer));
+		nameFull.append(toPeer->name());
+	}
+	return (quote
+		? tr::lng_preview_reply_to_quote
+		: tr::lng_preview_reply_to)(
+			tr::now,
+			lt_name,
+			nameFull,
+			Ui::Text::WithEntities);
+
+}
+
 void Reply::unloadPersistentAnimation() {
 	_text.unloadPersistentAnimation();
 }
diff --git a/Telegram/SourceFiles/history/view/history_view_reply.h b/Telegram/SourceFiles/history/view/history_view_reply.h
index 5322d5c09..4b30a842d 100644
--- a/Telegram/SourceFiles/history/view/history_view_reply.h
+++ b/Telegram/SourceFiles/history/view/history_view_reply.h
@@ -63,6 +63,14 @@ public:
 		return _link;
 	}
 
+	[[nodiscard]] static TextWithEntities PeerEmoji(
+		not_null<History*> history,
+		PeerData *peer);
+	[[nodiscard]] static TextWithEntities ComposePreviewName(
+		not_null<History*> history,
+		not_null<HistoryItem*> to,
+		bool quote);
+
 private:
 	[[nodiscard]] Ui::Text::GeometryDescriptor textGeometry(
 		int available,
diff --git a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
index 19704c779..694c67fb5 100644
--- a/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
+++ b/Telegram/SourceFiles/info/statistics/info_statistics_inner_widget.cpp
@@ -91,7 +91,6 @@ void ProcessZoom(
 	widget->zoomRequests(
 	) | rpl::start_with_next([=](float64 x) {
 		d.api->requestZoom(
-			d.peer,
 			zoomToken,
 			x
 		) | rpl::start_with_next_error_done([=](
@@ -144,7 +143,6 @@ void FillStatistic(
 				m);
 
 			descriptor.api->requestZoom(
-				descriptor.peer,
 				graphData.zoomToken,
 				0
 			) | rpl::start_with_next_error_done([=, graphPtr = &graphData](
@@ -524,7 +522,7 @@ void InnerWidget::load() {
 
 	const auto descriptor = Descriptor{
 		_peer,
-		lifetime().make_state<Api::Statistics>(&_peer->session().api()),
+		lifetime().make_state<Api::Statistics>(_peer->asChannel()),
 		_controller->uiShow()->toastParent(),
 	};
 
@@ -543,7 +541,6 @@ void InnerWidget::load() {
 	) | rpl::take(1) | rpl::start_with_next([=] {
 		if (!_contextId) {
 			descriptor.api->request(
-				descriptor.peer
 			) | rpl::start_with_done([=] {
 				_state.stats = Data::AnyStatistics{
 					descriptor.api->channelStats(),
@@ -575,7 +572,7 @@ void InnerWidget::fill() {
 	const auto inner = this;
 	const auto descriptor = Descriptor{
 		_peer,
-		lifetime().make_state<Api::Statistics>(&_peer->session().api()),
+		lifetime().make_state<Api::Statistics>(_peer->asChannel()),
 		_controller->uiShow()->toastParent(),
 	};
 	if (_state.stats.message) {
@@ -705,8 +702,9 @@ void InnerWidget::fillRecentPosts() {
 				container,
 				tr::lng_stories_show_more())));
 
-	constexpr auto kPerPage = int(10);
-	const auto max = stats.recentMessageInteractions.size();
+	constexpr auto kFirstPage = int(10);
+	constexpr auto kPerPage = int(30);
+	const auto max = int(stats.recentMessageInteractions.size());
 	if (_state.recentPostsExpanded) {
 		_state.recentPostsExpanded = std::max(
 			_state.recentPostsExpanded - kPerPage,
@@ -715,8 +713,10 @@ void InnerWidget::fillRecentPosts() {
 	const auto showMore = [=] {
 		const auto from = _state.recentPostsExpanded;
 		_state.recentPostsExpanded = std::min(
-			int(max),
-			_state.recentPostsExpanded + kPerPage);
+			max,
+			_state.recentPostsExpanded
+				? (_state.recentPostsExpanded + kPerPage)
+				: kFirstPage);
 		if (_state.recentPostsExpanded == max) {
 			buttonWrap->toggle(false, anim::type::instant);
 		}
diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h
index 0437644be..75287ceba 100644
--- a/Telegram/SourceFiles/mtproto/core_types.h
+++ b/Telegram/SourceFiles/mtproto/core_types.h
@@ -47,6 +47,7 @@ constexpr auto kUpdaterDcShift = 0x03;
 constexpr auto kExportDcShift = 0x04;
 constexpr auto kExportMediaDcShift = 0x05;
 constexpr auto kGroupCallStreamDcShift = 0x06;
+constexpr auto kStatsDcShift = 0x07;
 constexpr auto kMaxMediaDcCount = 0x10;
 constexpr auto kBaseDownloadDcShift = 0x10;
 constexpr auto kBaseUploadDcShift = 0x20;
diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.h b/Telegram/SourceFiles/mtproto/mtp_instance.h
index 2a3bc3d4e..7dc5be49b 100644
--- a/Telegram/SourceFiles/mtproto/mtp_instance.h
+++ b/Telegram/SourceFiles/mtproto/mtp_instance.h
@@ -150,8 +150,11 @@ public:
 			ResponseHandler &&callbacks = {},
 			ShiftedDcId shiftedDcId = 0,
 			crl::time msCanWait = 0,
-			mtpRequestId afterRequestId = 0) {
-		const auto requestId = details::GetNextRequestId();
+			mtpRequestId afterRequestId = 0,
+			mtpRequestId overrideRequestId = 0) {
+		const auto requestId = overrideRequestId
+			? overrideRequestId
+			: details::GetNextRequestId();
 		sendSerialized(
 			requestId,
 			details::SerializedRequest::Serialize(request),
@@ -169,13 +172,15 @@ public:
 			FailHandler &&onFail = nullptr,
 			ShiftedDcId shiftedDcId = 0,
 			crl::time msCanWait = 0,
-			mtpRequestId afterRequestId = 0) {
+			mtpRequestId afterRequestId = 0,
+			mtpRequestId overrideRequestId = 0) {
 		return send(
 			request,
 			ResponseHandler{ std::move(onDone), std::move(onFail) },
 			shiftedDcId,
 			msCanWait,
-			afterRequestId);
+			afterRequestId,
+			overrideRequestId);
 	}
 
 	template <typename Request>
diff --git a/Telegram/SourceFiles/mtproto/sender.h b/Telegram/SourceFiles/mtproto/sender.h
index 632f817f4..5330a0559 100644
--- a/Telegram/SourceFiles/mtproto/sender.h
+++ b/Telegram/SourceFiles/mtproto/sender.h
@@ -130,6 +130,9 @@ class Sender {
 		void setToDC(ShiftedDcId dcId) noexcept {
 			_dcId = dcId;
 		}
+		void setOverrideRequestId(mtpRequestId id) noexcept {
+			_overrideRequestId = id;
+		}
 		void setCanWait(crl::time ms) noexcept {
 			_canWait = ms;
 		}
@@ -147,16 +150,16 @@ class Sender {
 			_afterRequestId = requestId;
 		}
 
-		ShiftedDcId takeDcId() const noexcept {
+		[[nodiscard]] ShiftedDcId takeDcId() const noexcept {
 			return _dcId;
 		}
-		crl::time takeCanWait() const noexcept {
+		[[nodiscard]] crl::time takeCanWait() const noexcept {
 			return _canWait;
 		}
-		DoneHandler takeOnDone() noexcept {
+		[[nodiscard]] DoneHandler takeOnDone() noexcept {
 			return std::move(_done);
 		}
-		FailHandler takeOnFail() {
+		[[nodiscard]] FailHandler takeOnFail() {
 			return v::match(_fail, [&](auto &value) {
 				return MakeFailHandler(
 					_sender,
@@ -164,11 +167,14 @@ class Sender {
 					_failSkipPolicy);
 			});
 		}
-		mtpRequestId takeAfter() const noexcept {
+		[[nodiscard]] mtpRequestId takeAfter() const noexcept {
 			return _afterRequestId;
 		}
+		[[nodiscard]] mtpRequestId takeOverrideRequestId() const noexcept {
+			return _overrideRequestId;
+		}
 
-		not_null<Sender*> sender() const noexcept {
+		[[nodiscard]] not_null<Sender*> sender() const noexcept {
 			return _sender;
 		}
 		void registerRequest(mtpRequestId requestId) {
@@ -187,6 +193,7 @@ class Sender {
 			FailFullHandler> _fail;
 		FailSkipPolicy _failSkipPolicy = FailSkipPolicy::Simple;
 		mtpRequestId _afterRequestId = 0;
+		mtpRequestId _overrideRequestId = 0;
 
 	};
 
@@ -207,9 +214,10 @@ public:
 		: RequestBuilder(sender)
 		, _request(std::move(request)) {
 		}
-		SpecificRequestBuilder(SpecificRequestBuilder &&other) = default;
 
 	public:
+		SpecificRequestBuilder(SpecificRequestBuilder &&other) = default;
+
 		[[nodiscard]] SpecificRequestBuilder &toDC(ShiftedDcId dcId) noexcept {
 			setToDC(dcId);
 			return *this;
@@ -218,6 +226,10 @@ public:
 			setCanWait(ms);
 			return *this;
 		}
+		[[nodiscard]] SpecificRequestBuilder &overrideId(mtpRequestId id) noexcept {
+			setOverrideRequestId(id);
+			return *this;
+		}
 
 		using Result = typename Request::ResponseType;
 		[[nodiscard]] SpecificRequestBuilder &done(
@@ -295,7 +307,8 @@ public:
 				takeOnFail(),
 				takeDcId(),
 				takeCanWait(),
-				takeAfter());
+				takeAfter(),
+				takeOverrideRequestId());
 			registerRequest(id);
 			return id;
 		}
@@ -347,6 +360,13 @@ public:
 		}
 	}
 
+	[[nodiscard]] mtpRequestId allocateRequestId() noexcept {
+		return details::GetNextRequestId();
+	}
+	[[nodiscard]] bool pending(mtpRequestId requestId) noexcept {
+		return _requests.contains(requestId);
+	}
+
 private:
 	class RequestWrap {
 	public:
diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm
index dc9301a89..7914cd918 100644
--- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm
+++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm
@@ -40,7 +40,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include <QtWidgets/QLineEdit>
 #include <QtWidgets/QTextEdit>
 #include <QtGui/QClipboard>
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 #include <qpa/qwindowsysteminterface.h>
+#endif // Qt < 6.6.0
 
 #include <Cocoa/Cocoa.h>
 #include <CoreFoundation/CFURL.h>
@@ -52,7 +55,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 - (id) init:(MainWindow::Private*)window;
 - (void) activeSpaceDidChange:(NSNotification *)aNotification;
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 - (void) darkModeChanged:(NSNotification *)aNotification;
+#endif // Qt < 6.6.0
 - (void) screenIsLocked:(NSNotification *)aNotification;
 - (void) screenIsUnlocked:(NSNotification *)aNotification;
 
@@ -113,6 +118,7 @@ private:
 - (void) activeSpaceDidChange:(NSNotification *)aNotification {
 }
 
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 - (void) darkModeChanged:(NSNotification *)aNotification {
 	Core::Sandbox::Instance().customEnterFromEventLoop([&] {
 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
@@ -122,6 +128,7 @@ private:
 #endif // Qt < 6.5.0
 	});
 }
+#endif // Qt < 6.6.0
 
 - (void) screenIsLocked:(NSNotification *)aNotification {
 	Core::App().setScreenIsLocked(true);
@@ -156,10 +163,12 @@ void ForceDisabled(QAction *action, bool disabled) {
 	}
 }
 
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 QString strNotificationAboutThemeChange() {
 	const uint32 letters[] = { 0x75E86256, 0xD03E11B1, 0x4D92201D, 0xA2144987, 0x99D5B34F, 0x037589C3, 0x38ED2A7C, 0xD2371ABC, 0xDC98BB02, 0x27964E1B, 0x01748AED, 0xE06679F8, 0x761C9580, 0x4F2595BF, 0x6B5FCBF4, 0xE4D9C24E, 0xBA2F6AB5, 0xE6E3FA71, 0xF2CFC255, 0x56A50C19, 0x43AE1239, 0x77CA4254, 0x7D189A89, 0xEA7663EE, 0x84CEB554, 0xA0ADF236, 0x886512D4, 0x7D3FBDAF, 0x85C4BE4F, 0x12C8255E, 0x9AD8BD41, 0xAC154683, 0xB117598B, 0xDFD9F947, 0x63F06C7B, 0x6340DCD6, 0x3AAE6B3E, 0x26CB125A };
 	return Platform::MakeFromLetters(letters);
 }
+#endif // Qt < 6.6.0
 
 QString strNotificationAboutScreenLocked() {
 	const uint32 letters[] = { 0x34B47F28, 0x47E95179, 0x73D05C42, 0xB4E2A933, 0x924F22D1, 0x4265D8EA, 0x9E4D2CC2, 0x02E8157B, 0x35BF7525, 0x75901A41, 0xB0400FCC, 0xE801169D, 0x4E04B589, 0xC1CEF054, 0xAB2A7EB0, 0x5C67C4F6, 0xA4E2B954, 0xB35E12D2, 0xD598B22B, 0x4E3B8AAB, 0xBEA5E439, 0xFDA8AA3C, 0x1632DBA8, 0x88FE8965 };
@@ -181,7 +190,9 @@ MainWindow::Private::Private(not_null<MainWindow*> window)
 	@autoreleasepool {
 
 	[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:_observer selector:@selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 	[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(darkModeChanged:) name:Q2NSString(strNotificationAboutThemeChange()) object:nil];
+#endif // Qt < 6.6.0
 	[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsLocked:) name:Q2NSString(strNotificationAboutScreenLocked()) object:nil];
 	[[NSDistributedNotificationCenter defaultCenter] addObserver:_observer selector:@selector(screenIsUnlocked:) name:Q2NSString(strNotificationAboutScreenUnlocked()) object:nil];
 
diff --git a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm
index 984643871..de1f1d1ec 100644
--- a/Telegram/SourceFiles/platform/mac/specific_mac_p.mm
+++ b/Telegram/SourceFiles/platform/mac/specific_mac_p.mm
@@ -30,7 +30,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #if __has_include(<QtCore/QOperatingSystemVersion>)
 #include <QtCore/QOperatingSystemVersion>
 #endif // __has_include(<QtCore/QOperatingSystemVersion>)
+#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
 #include <qpa/qwindowsysteminterface.h>
+#endif // Qt < 6.6.0
 #include <Cocoa/Cocoa.h>
 #include <CoreFoundation/CFURL.h>
 #include <IOKit/IOKitLib.h>
@@ -201,11 +203,11 @@ ApplicationDelegate *_sharedDelegate = nil;
 			"-receiveWakeNote: received, scheduling detach from audio device"));
 		Media::Audio::ScheduleDetachFromDeviceSafe();
 
-#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
-		QWindowSystemInterface::handleThemeChange();
-#else // Qt >= 6.5.0
+#if QT_VERSION < QT_VERSION_CHECK(6, 5, 0)
 		Core::App().settings().setSystemDarkMode(Platform::IsDarkMode());
-#endif // Qt < 6.5.0
+#elif QT_VERSION < QT_VERSION_CHECK(6, 6, 0) // Qt < 6.5.0
+		QWindowSystemInterface::handleThemeChange();
+#endif // Qt < 6.6.0
 	});
 }
 
diff --git a/Telegram/SourceFiles/platform/win/integration_win.h b/Telegram/SourceFiles/platform/win/integration_win.h
index b51184e1d..5e559b69a 100644
--- a/Telegram/SourceFiles/platform/win/integration_win.h
+++ b/Telegram/SourceFiles/platform/win/integration_win.h
@@ -7,11 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
 #pragma once
 
+#include "base/platform/win/base_windows_winrt.h"
 #include "platform/platform_integration.h"
 
 #include <QAbstractNativeEventFilter>
 
-#include <winrt/base.h>
 #include <ShlObj.h>
 
 namespace Platform {
diff --git a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h
index 92d6c2b7d..4f69019eb 100644
--- a/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h
+++ b/Telegram/SourceFiles/platform/win/windows_app_user_model_id.h
@@ -9,6 +9,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "base/platform/win/base_windows_h.h"
 
+#include <wtypes.h>
+
 namespace Platform {
 namespace AppUserModelId {
 
diff --git a/Telegram/SourceFiles/platform/win/windows_dlls.h b/Telegram/SourceFiles/platform/win/windows_dlls.h
index eef6e9bc7..d97eeab92 100644
--- a/Telegram/SourceFiles/platform/win/windows_dlls.h
+++ b/Telegram/SourceFiles/platform/win/windows_dlls.h
@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 #include "base/platform/win/base_windows_h.h"
 
+#include <shellapi.h>
 #include <shlobj.h>
 #include <dwmapi.h>
 #include <RestartManager.h>
diff --git a/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp b/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp
index e89be9177..23fb14d3c 100644
--- a/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp
+++ b/Telegram/SourceFiles/statistics/view/linear_chart_view.cpp
@@ -163,7 +163,7 @@ void LinearChartView::paintSelectedXIndex(
 				+ c.rect.topLeft();
 		}
 
-		if (!linePainted) {
+		if (!linePainted && lineAlpha) {
 			[[maybe_unused]] const auto o = ScopedPainterOpacity(
 				p,
 				p.opacity() * progress * kRulerLineAlpha);
diff --git a/Telegram/SourceFiles/ui/boxes/boost_box.cpp b/Telegram/SourceFiles/ui/boxes/boost_box.cpp
index 83bd4fa37..0be48632c 100644
--- a/Telegram/SourceFiles/ui/boxes/boost_box.cpp
+++ b/Telegram/SourceFiles/ui/boxes/boost_box.cpp
@@ -98,11 +98,7 @@ namespace {
 		auto hq = PainterHighQualityEnabler(p);
 		const auto radius = std::min(badge->width(), badge->height()) / 2;
 		p.setPen(Qt::NoPen);
-		auto brush = QLinearGradient(
-			QPointF(badge->width(), badge->height()),
-			QPointF());
-		brush.setStops(Ui::Premium::ButtonGradientStops());
-		p.setBrush(brush);
+		p.setBrush(st::premiumButtonBg2);
 		p.drawRoundedRect(badge->rect(), radius, radius);
 	}, badge->lifetime());
 
diff --git a/Telegram/ThirdParty/libtgvoip b/Telegram/ThirdParty/libtgvoip
index c2e718049..e286ab661 160000
--- a/Telegram/ThirdParty/libtgvoip
+++ b/Telegram/ThirdParty/libtgvoip
@@ -1 +1 @@
-Subproject commit c2e718049cf11bbbe7b6d78b78b2d21f0e0affa0
+Subproject commit e286ab66141a2f986803177e4cbb7b14002664cb
diff --git a/Telegram/build/version b/Telegram/build/version
index 447ef2247..065ee5c80 100644
--- a/Telegram/build/version
+++ b/Telegram/build/version
@@ -1,7 +1,7 @@
-AppVersion         4011006
+AppVersion         4011007
 AppVersionStrMajor 4.11
-AppVersionStrSmall 4.11.6
-AppVersionStr      4.11.6
+AppVersionStrSmall 4.11.7
+AppVersionStr      4.11.7
 BetaChannel        0
 AlphaVersion       0
-AppVersionOriginal 4.11.6
+AppVersionOriginal 4.11.7
diff --git a/Telegram/lib_base b/Telegram/lib_base
index bb5e7fafd..fe4f0a72d 160000
--- a/Telegram/lib_base
+++ b/Telegram/lib_base
@@ -1 +1 @@
-Subproject commit bb5e7fafd7aca5808217baeeb9ee3af8c3be6b1b
+Subproject commit fe4f0a72d2041a860c67a81a70f2e4b6f845d9fb
diff --git a/Telegram/lib_webview b/Telegram/lib_webview
index f5fe3afcf..aab27269f 160000
--- a/Telegram/lib_webview
+++ b/Telegram/lib_webview
@@ -1 +1 @@
-Subproject commit f5fe3afcf5bc5edf07a78ad18b9e8d33c3fbfdb2
+Subproject commit aab27269ff8aad5dfaf7372db10bff700fdb5fe9
diff --git a/changelog.txt b/changelog.txt
index 245ef9c1e..c7e56597b 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,11 @@
+4.11.7 (13.11.23)
+
+- Fix sending media files with quote replies.
+- Fix quoted text highlighting in some cases.
+- Fix loading statistics for some channels.
+- Fix Ctrl+Shift+. shortcut on X11.
+- Fix a crash in statistics.
+
 4.11.6 (09.11.23)
 
 - Support multiple boosts and reassignment.
diff --git a/cmake b/cmake
index 78098ede7..c373a0a01 160000
--- a/cmake
+++ b/cmake
@@ -1 +1 @@
-Subproject commit 78098ede77a09e41da6233d765d02b43a60e7138
+Subproject commit c373a0a0141bbe146a9507f02b8515183748eb51