diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 6e786a6cd..fa06b446a 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -837,14 +837,14 @@ PRIVATE
     history/view/history_view_send_action.h
     history/view/history_view_service_message.cpp
     history/view/history_view_service_message.h
-    history/view/history_view_spoiler_click_handler.cpp
-    history/view/history_view_spoiler_click_handler.h
     history/view/history_view_sponsored_click_handler.cpp
     history/view/history_view_sponsored_click_handler.h
     history/view/history_view_sticker_toast.cpp
     history/view/history_view_sticker_toast.h
     history/view/history_view_sublist_section.cpp
     history/view/history_view_sublist_section.h
+    history/view/history_view_text_helper.cpp
+    history/view/history_view_text_helper.h
     history/view/history_view_transcribe_button.cpp
     history/view/history_view_transcribe_button.h
     history/view/history_view_translate_bar.cpp
diff --git a/Telegram/SourceFiles/api/api_text_entities.cpp b/Telegram/SourceFiles/api/api_text_entities.cpp
index 3c5098911..93d5cc5f3 100644
--- a/Telegram/SourceFiles/api/api_text_entities.cpp
+++ b/Telegram/SourceFiles/api/api_text_entities.cpp
@@ -217,6 +217,7 @@ EntitiesInText EntitiesFromMTP(
 				EntityType::Blockquote,
 				d.voffset().v,
 				d.vlength().v,
+				d.is_collapsed() ? u"1"_q : QString(),
 			});
 		});
 	}
@@ -311,8 +312,13 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
 					MTP_string(entity.data())));
 		} break;
 		case EntityType::Blockquote: {
+			using Flag = MTPDmessageEntityBlockquote::Flag;
+			const auto collapsed = !entity.data().isEmpty();
 			v.push_back(
-				MTP_messageEntityBlockquote(MTP_flags(0), offset, length));
+				MTP_messageEntityBlockquote(
+					MTP_flags(collapsed ? Flag::f_collapsed : Flag()),
+					offset,
+					length));
 		} break;
 		case EntityType::Spoiler: {
 			v.push_back(MTP_messageEntitySpoiler(offset, length));
diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp
index 836459ad8..8b5f3c373 100644
--- a/Telegram/SourceFiles/chat_helpers/message_field.cpp
+++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp
@@ -748,7 +748,8 @@ void MessageLinksParser::parse() {
 			|| (tag == Ui::InputField::kTagUnderline)
 			|| (tag == Ui::InputField::kTagStrikeOut)
 			|| (tag == Ui::InputField::kTagSpoiler)
-			|| (tag == Ui::InputField::kTagBlockquote);
+			|| (tag == Ui::InputField::kTagBlockquote)
+			|| (tag == Ui::InputField::kTagBlockquoteCollapsed);
 	};
 
 	_ranges.clear();
diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp
index 529b933d4..dba1c3d69 100644
--- a/Telegram/SourceFiles/data/data_session.cpp
+++ b/Telegram/SourceFiles/data/data_session.cpp
@@ -1820,12 +1820,19 @@ rpl::producer<not_null<HistoryItem*>> Session::itemDataChanges() const {
 }
 
 void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
-	if (const auto i = _views.find(item); i != _views.end()) {
-		for (const auto &view : i->second) {
-			view->itemTextUpdated();
+	const auto call = [&](not_null<HistoryItem*> item) {
+		if (const auto i = _views.find(item); i != _views.end()) {
+			for (const auto &view : i->second) {
+				view->itemTextUpdated();
+			}
 		}
-		requestItemResize(item);
+	};
+	if (const auto group = groups().find(item)) {
+		call(group->items.front());
+	} else {
+		call(item);
 	}
+	requestItemResize(item);
 }
 
 void Session::registerHighlightProcess(
diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp
index c4b55f346..71750a575 100644
--- a/Telegram/SourceFiles/export/data/export_data_types.cpp
+++ b/Telegram/SourceFiles/export/data/export_data_types.cpp
@@ -307,6 +307,8 @@ std::vector<TextPart> ParseText(
 			return NumberToString(data.vuser_id().v);
 		}, [](const MTPDmessageEntityCustomEmoji &data) {
 			return NumberToString(data.vdocument_id().v);
+		}, [](const MTPDmessageEntityBlockquote &data) {
+			return data.is_collapsed() ? Utf8String("1") : Utf8String();
 		}, [](const auto &) { return Utf8String(); });
 
 		result.push_back(std::move(part));
diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp
index 67814e5b2..b485e615b 100644
--- a/Telegram/SourceFiles/export/output/export_output_json.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_json.cpp
@@ -195,6 +195,8 @@ QByteArray SerializeText(
 			? "language"
 			: (part.type == Type::TextUrl)
 			? "href"
+			: (part.type == Type::Blockquote)
+			? "collapsed"
 			: "none";
 		const auto additionalValue = (part.type == Type::MentionName)
 			? part.additional
@@ -202,6 +204,8 @@ QByteArray SerializeText(
 				|| part.type == Type::TextUrl
 				|| part.type == Type::CustomEmoji)
 			? SerializeString(part.additional)
+			: (part.type == Type::Blockquote)
+			? (part.additional.isEmpty() ? "false" : "true")
 			: QByteArray();
 		return SerializeObject(context, {
 			{ "type", SerializeString(typeString) },
diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp
index 3cdb44ed0..df32ee082 100644
--- a/Telegram/SourceFiles/history/view/history_view_element.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_element.cpp
@@ -18,7 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/reactions/history_view_reactions.h"
 #include "history/view/history_view_cursor_state.h"
 #include "history/view/history_view_reply.h"
-#include "history/view/history_view_spoiler_click_handler.h"
+#include "history/view/history_view_text_helper.h"
 #include "history/history.h"
 #include "history/history_item_components.h"
 #include "history/history_item_helpers.h"
@@ -1027,7 +1027,7 @@ void Element::setTextWithLinks(
 			refreshMedia(nullptr);
 		}
 	}
-	FillTextWithAnimatedSpoilers(this, _text);
+	InitElementTextPart(this, _text);
 	_textWidth = -1;
 	_textHeight = 0;
 }
@@ -1464,6 +1464,12 @@ void Element::itemTextUpdated() {
 	}
 }
 
+void Element::blockquoteExpandChanged() {
+	_textWidth = -1;
+	_textHeight = 0;
+	history()->owner().requestViewResize(this);
+}
+
 void Element::unloadHeavyPart() {
 	history()->owner().unregisterHeavyViewPart(this);
 	if (_media) {
diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h
index fdac9a583..0c01e9767 100644
--- a/Telegram/SourceFiles/history/view/history_view_element.h
+++ b/Telegram/SourceFiles/history/view/history_view_element.h
@@ -498,6 +498,7 @@ public:
 
 	virtual void itemDataChanged();
 	void itemTextUpdated();
+	void blockquoteExpandChanged();
 
 	[[nodiscard]] virtual bool hasHeavyPart() const;
 	virtual void unloadHeavyPart();
diff --git a/Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.cpp b/Telegram/SourceFiles/history/view/history_view_text_helper.cpp
similarity index 68%
rename from Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.cpp
rename to Telegram/SourceFiles/history/view/history_view_text_helper.cpp
index eb72db0f2..fbe97ed56 100644
--- a/Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_text_helper.cpp
@@ -5,7 +5,7 @@ the official desktop application for the Telegram messaging service.
 For license and copyright information please follow this link:
 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 */
-#include "history/view/history_view_spoiler_click_handler.h"
+#include "history/view/history_view_text_helper.h"
 
 #include "data/data_session.h"
 #include "history/view/history_view_element.h"
@@ -15,9 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 
 namespace HistoryView {
 
-void FillTextWithAnimatedSpoilers(
-		not_null<Element*> view,
-		Ui::Text::String &text) {
+void InitElementTextPart(not_null<Element*> view, Ui::Text::String &text) {
 	if (text.hasSpoilers()) {
 		text.setSpoilerLinkFilter([weak = base::make_weak(view)](
 				const ClickContext &context) {
@@ -30,6 +28,14 @@ void FillTextWithAnimatedSpoilers(
 			return true;
 		});
 	}
+	if (text.hasCollapsedBlockquots()) {
+		const auto weak = base::make_weak(view);
+		text.setBlockquoteExpandCallback([=](int quoteIndex, bool expanded) {
+			if (const auto view = weak.get()) {
+				view->blockquoteExpandChanged();
+			}
+		});
+	}
 }
 
 } // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.h b/Telegram/SourceFiles/history/view/history_view_text_helper.h
similarity index 78%
rename from Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.h
rename to Telegram/SourceFiles/history/view/history_view_text_helper.h
index 3bef398b6..d7a604b53 100644
--- a/Telegram/SourceFiles/history/view/history_view_spoiler_click_handler.h
+++ b/Telegram/SourceFiles/history/view/history_view_text_helper.h
@@ -11,8 +11,6 @@ namespace HistoryView {
 
 class Element;
 
-void FillTextWithAnimatedSpoilers(
-	not_null<Element*> view,
-	Ui::Text::String &text);
+void InitElementTextPart(not_null<Element*> view, Ui::Text::String &text);
 
 } // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp
index e415264b3..b1c972053 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp
@@ -1490,8 +1490,12 @@ QMargins Document::bubbleMargins() const {
 }
 
 void Document::refreshCaption(bool last) {
+	const auto now = Get<HistoryDocumentCaptioned>();
 	auto caption = createCaption();
 	if (!caption.isEmpty()) {
+		if (now) {
+			return;
+		}
 		AddComponents(HistoryDocumentCaptioned::Bit());
 		auto captioned = Get<HistoryDocumentCaptioned>();
 		captioned->caption = std::move(caption);
@@ -1503,7 +1507,7 @@ void Document::refreshCaption(bool last) {
 		} else {
 			captioned->caption.removeSkipBlock();
 		}
-	} else {
+	} else if (now) {
 		RemoveComponents(HistoryDocumentCaptioned::Bit());
 	}
 }
@@ -1637,7 +1641,7 @@ void Document::refreshParentId(not_null<HistoryItem*> realParent) {
 }
 
 void Document::parentTextUpdated() {
-	history()->owner().requestViewResize(_parent);
+	RemoveComponents(HistoryDocumentCaptioned::Bit());
 }
 
 void Document::hideSpoilers() {
diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp
index 65c209153..4f8c8096b 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp
@@ -11,7 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/history_item.h"
 #include "history/view/history_view_element.h"
 #include "history/view/history_view_cursor_state.h"
-#include "history/view/history_view_spoiler_click_handler.h"
+#include "history/view/history_view_text_helper.h"
 #include "history/view/media/history_view_sticker.h"
 #include "history/view/media/history_view_media_spoiler.h"
 #include "storage/storage_shared_media.h"
@@ -319,7 +319,7 @@ Ui::Text::String Media::createCaption(not_null<HistoryItem*> item) const {
 		item->translatedTextWithLocalEntities(),
 		Ui::ItemTextOptions(item),
 		context);
-	FillTextWithAnimatedSpoilers(_parent, result);
+	InitElementTextPart(_parent, result);
 	if (const auto width = _parent->skipBlockWidth()) {
 		result.updateSkipBlock(width, _parent->skipBlockHeight());
 	}
diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp
index c4e51f174..b1c8ba33d 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp
@@ -781,7 +781,13 @@ void GroupedMedia::unloadHeavyPart() {
 
 void GroupedMedia::parentTextUpdated() {
 	if (_parent->media() == this) {
-		_captionItem = std::nullopt;
+		if (_mode == Mode::Column) {
+			for (const auto &part : _parts) {
+				part.content->parentTextUpdated();
+			}
+		} else {
+			_captionItem = std::nullopt;
+		}
 	}
 }
 
diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp
index 0275ed2c2..44863dd41 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp
@@ -282,7 +282,9 @@ WebPage::WebPage(
 	not_null<WebPageData*> data,
 	MediaWebPageFlags flags)
 : Media(parent)
-, _st(st::historyPagePreview)
+, _st(data->type == WebPageType::Factcheck
+	? st::factcheckPage
+	: st::historyPagePreview)
 , _data(data)
 , _flags(flags)
 , _siteName(st::msgMinWidth - _st.padding.left() - _st.padding.right())
@@ -859,13 +861,14 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
 			FillBackgroundEmoji(p, outer, false, *backgroundEmojiCache);
 		}
 	} else if (factcheck && factcheck->expandable) {
-		const auto &icon = factcheck->expanded
-			? st::factcheckIconCollapse
-			: st::factcheckIconExpand;
+		const auto &icon = factcheck->expanded ? _st.collapse : _st.expand;
+		const auto &position = factcheck->expanded
+			? _st.collapsePosition
+			: _st.expandPosition;
 		icon.paint(
 			p,
-			outer.x() + outer.width() - icon.width() - _st.padding.right(),
-			outer.y() + _st.padding.top(),
+			outer.x() + outer.width() - icon.width() - position.x(),
+			outer.y() + outer.height() - icon.height() - position.y(),
 			width());
 	}
 
diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style
index 3069b6f90..622ba8357 100644
--- a/Telegram/SourceFiles/ui/chat/chat.style
+++ b/Telegram/SourceFiles/ui/chat/chat.style
@@ -66,6 +66,10 @@ messageTextStyle: TextStyle(defaultTextStyle) {
 		padding: margins(10px, 2px, 20px, 2px);
 		icon: icon{{ "chat/mini_quote", windowFg }};
 		iconPosition: point(4px, 4px);
+		expand: icon{{ "intro_country_dropdown", windowFg }};
+		expandPosition: point(6px, 4px);
+		collapse: icon{{ "intro_country_dropdown-flip_vertical", windowFg }};
+		collapsePosition: point(6px, 4px);
 	}
 	pre: QuoteStyle(messageQuoteStyle) {
 		header: 20px;
@@ -1137,8 +1141,13 @@ factcheckFooterSkip: 16px;
 factcheckFooterStyle: TextStyle(defaultTextStyle) {
 	font: font(11px);
 }
-factcheckIconExpand: icon {{ "fast_to_original-rotate_cw", historyPeer1NameFg }};
-factcheckIconCollapse: icon {{ "fast_to_original-rotate_ccw", historyPeer1NameFg }};
+factcheckPage: QuoteStyle(historyPagePreview) {
+	padding: margins(10px, 5px, 22px, 7px);
+	expand: icon {{ "intro_country_dropdown", historyPeer1NameFg }};
+	expandPosition: point(6px, 4px);
+	collapse: icon {{ "intro_country_dropdown-flip_vertical", historyPeer1NameFg }};
+	collapsePosition: point(6px, 4px);
+}
 factcheckField: InputField(defaultInputField) {
 	textBg: transparent;
 	textMargins: margins(0px, 0px, 0px, 4px);
diff --git a/Telegram/lib_ui b/Telegram/lib_ui
index 0835adcc2..495ea0af5 160000
--- a/Telegram/lib_ui
+++ b/Telegram/lib_ui
@@ -1 +1 @@
-Subproject commit 0835adcc2d3cb1f2cf0d3630f6d95485864621f9
+Subproject commit 495ea0af50da469fb30769ac2d78251e4279a746