From f76e094e98dd678158c6f97dcc690548919cbe16 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 30 Apr 2020 15:20:50 +0400
Subject: [PATCH] Use info toast to show proxy / psa about text.

---
 Telegram/SourceFiles/history/history.cpp      | 18 +++-
 Telegram/SourceFiles/history/history.h        |  4 +-
 Telegram/SourceFiles/history/history.style    |  7 --
 .../history/history_inner_widget.cpp          | 26 +----
 .../history/history_inner_widget.h            |  4 -
 .../SourceFiles/history/history_widget.cpp    | 99 +++++++++++--------
 Telegram/SourceFiles/history/history_widget.h | 14 ++-
 7 files changed, 88 insertions(+), 84 deletions(-)

diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index 2f1e6cdfd..cb92da4b7 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -2730,7 +2730,7 @@ void History::cacheTopPromotion(
 		const QString &message) {
 	const auto changed = (isTopPromoted() != promoted);
 	cacheTopPromoted(promoted);
-	if (_topPromotedType != type || _topPromotedMessage != message) {
+	if (topPromotionType() != type || _topPromotedMessage != message) {
 		_topPromotedType = type;
 		_topPromotedMessage = message;
 		cloudDraftTextCache.clear();
@@ -2739,8 +2739,20 @@ void History::cacheTopPromotion(
 	}
 }
 
-QString History::topPromotionType() const {
-	return _topPromotedType;
+QStringRef History::topPromotionType() const {
+	return topPromotionAboutShown()
+		? _topPromotedType.midRef(5)
+		: _topPromotedType.midRef(0);
+}
+
+bool History::topPromotionAboutShown() const {
+	return _topPromotedType.startsWith("seen^");
+}
+
+void History::markTopPromotionAboutShown() {
+	if (!topPromotionAboutShown()) {
+		_topPromotedType = "seen^" + _topPromotedType;
+	}
 }
 
 QString History::topPromotionMessage() const {
diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h
index 8e97d204a..adfa3d605 100644
--- a/Telegram/SourceFiles/history/history.h
+++ b/Telegram/SourceFiles/history/history.h
@@ -241,8 +241,10 @@ public:
 		bool promoted,
 		const QString &type,
 		const QString &message);
-	[[nodiscard]] QString topPromotionType() const;
+	[[nodiscard]] QStringRef topPromotionType() const;
 	[[nodiscard]] QString topPromotionMessage() const;
+	[[nodiscard]] bool topPromotionAboutShown() const;
+	void markTopPromotionAboutShown();
 
 	MsgId minMsgId() const;
 	MsgId maxMsgId() const;
diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style
index c557efb23..d9328ff7b 100644
--- a/Telegram/SourceFiles/history/history.style
+++ b/Telegram/SourceFiles/history/history.style
@@ -529,13 +529,6 @@ historyGroupSkip: 4px;
 historyGroupRadialSize: 44px;
 historyGroupRadialLine: 3px;
 
-historyAboutProxy: FlatLabel(defaultFlatLabel) {
-	align: align(top);
-	textFg: windowSubTextFg;
-	minWidth: 300px;
-}
-historyAboutProxyPadding: margins(20px, 10px, 20px, 10px);
-
 historyMapPoint: icon {{ "map_point", mapPointDrop }};
 historyMapPointInner: icon {{ "map_point_inner", mapPointDot }};
 
diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index 9d0440268..4ecd52e78 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -88,13 +88,6 @@ int BinarySearchBlocksOrItems(const T &list, int edge) {
 	return start;
 }
 
-[[nodiscard]] crl::time CountToastDuration(const TextWithEntities &text) {
-	return std::clamp(
-		crl::time(1000) * text.text.size() / 14,
-		crl::time(1000) * 5,
-		crl::time(1000) * 8);
-}
-
 } // namespace
 
 // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@@ -2491,24 +2484,7 @@ void HistoryInner::elementShowPollResults(
 void HistoryInner::elementShowTooltip(
 		const TextWithEntities &text,
 		Fn<void()> hiddenCallback) {
-	if (const auto strong = _topToast.get()) {
-		strong->hideAnimated();
-	}
-	_topToast = Ui::Toast::Show(_scroll, Ui::Toast::Config{
-		.text = text,
-		.st = &st::historyInfoToast,
-		.durationMs = CountToastDuration(text),
-		.multiline = true,
-		.dark = true,
-		.slideSide = RectPart::Top,
-	});
-	if (const auto strong = _topToast.get()) {
-		if (hiddenCallback) {
-			connect(strong->widget(), &QObject::destroyed, hiddenCallback);
-		}
-	} else if (hiddenCallback) {
-		hiddenCallback();
-	}
+	_widget->showInfoTooltip(text, std::move(hiddenCallback));
 }
 
 auto HistoryInner::getSelectionState() const
diff --git a/Telegram/SourceFiles/history/history_inner_widget.h b/Telegram/SourceFiles/history/history_inner_widget.h
index 25ffcd55d..f1dfcc312 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.h
+++ b/Telegram/SourceFiles/history/history_inner_widget.h
@@ -34,9 +34,6 @@ class SessionController;
 
 namespace Ui {
 class PopupMenu;
-namespace Toast {
-class Instance;
-} // namespace Toast
 } // namespace Ui
 
 class HistoryWidget;
@@ -384,7 +381,6 @@ private:
 	QTimer _touchScrollTimer;
 
 	base::unique_qptr<Ui::PopupMenu> _menu;
-	base::weak_ptr<Ui::Toast::Instance> _topToast;
 
 	bool _scrollDateShown = false;
 	Ui::Animations::Simple _scrollDateOpacity;
diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp
index c8399dde0..02a01bb32 100644
--- a/Telegram/SourceFiles/history/history_widget.cpp
+++ b/Telegram/SourceFiles/history/history_widget.cpp
@@ -243,6 +243,13 @@ void ShowErrorToast(const QString &text) {
 	});
 }
 
+[[nodiscard]] crl::time CountToastDuration(const TextWithEntities &text) {
+	return std::clamp(
+		crl::time(1000) * text.text.size() / 14,
+		crl::time(1000) * 5,
+		crl::time(1000) * 8);
+}
+
 } // namespace
 
 HistoryWidget::HistoryWidget(
@@ -565,7 +572,6 @@ HistoryWidget::HistoryWidget(
 				}
 			}
 			if (update.flags & UpdateFlag::TopPromotedChanged) {
-				refreshAboutTopPromotion();
 				updateHistoryGeometry();
 				updateControlsVisibility();
 				updateControlsGeometry();
@@ -1649,6 +1655,7 @@ void HistoryWidget::showHistory(
 	}
 
 	clearHighlightMessages();
+	hideInfoTooltip(anim::type::instant);
 	if (_history) {
 		if (_peer->id == peerId && !reload) {
 			updateForwarding();
@@ -1903,6 +1910,7 @@ void HistoryWidget::showHistory(
 			}
 		}
 		unreadCountUpdated(); // set _historyDown badge.
+		showAboutTopPromotion();
 	} else {
 		_topBar->setActiveChat(
 			Dialogs::Key(),
@@ -2069,7 +2077,6 @@ void HistoryWidget::updateControlsVisibility() {
 	if (_contactStatus) {
 		_contactStatus->show();
 	}
-	refreshAboutTopPromotion();
 	if (!editingMessage() && (isBlocked() || isJoinChannel() || isMuteUnmute() || isBotStart())) {
 		if (isBlocked()) {
 			_joinChannel->hide();
@@ -2262,33 +2269,25 @@ void HistoryWidget::updateControlsVisibility() {
 	updateMouseTracking();
 }
 
-void HistoryWidget::refreshAboutTopPromotion() {
-	if (_history->useTopPromotion()) {
-		const auto type = _history->topPromotionType();
-		const auto custom = type.isEmpty()
-			? QString()
-			: Lang::Current().getNonDefaultValue(
-				kPsaAboutPrefix + type.toUtf8());
-		const auto text = type.isEmpty()
-			? tr::lng_proxy_sponsor_about(tr::now, Ui::Text::RichLangValue)
-			: custom.isEmpty()
-			? tr::lng_about_psa_default(tr::now, Ui::Text::RichLangValue)
-			: Ui::Text::RichLangValue(custom);
-		if (!_aboutTopPromotion || _aboutTopPromotionText != text) {
-			_aboutTopPromotionText = text;
-			_aboutTopPromotion = object_ptr<Ui::PaddingWrap<Ui::FlatLabel>>(
-				this,
-				object_ptr<Ui::FlatLabel>(
-					this,
-					rpl::single(_aboutTopPromotionText),
-					st::historyAboutProxy),
-				st::historyAboutProxyPadding);
-		}
-		_aboutTopPromotion->show();
-	} else {
-		_aboutTopPromotionText = TextWithEntities();
-		_aboutTopPromotion.destroy();
+void HistoryWidget::showAboutTopPromotion() {
+	Expects(_history != nullptr);
+	Expects(_list != nullptr);
+
+	if (!_history->useTopPromotion() || _history->topPromotionAboutShown()) {
+		return;
 	}
+	_history->markTopPromotionAboutShown();
+	const auto type = _history->topPromotionType();
+	const auto custom = type.isEmpty()
+		? QString()
+		: Lang::Current().getNonDefaultValue(
+			kPsaAboutPrefix + type.toUtf8());
+	const auto text = type.isEmpty()
+		? tr::lng_proxy_sponsor_about(tr::now, Ui::Text::RichLangValue)
+		: custom.isEmpty()
+		? tr::lng_about_psa_default(tr::now, Ui::Text::RichLangValue)
+		: Ui::Text::RichLangValue(custom);
+	showInfoTooltip(text, nullptr);
 }
 
 void HistoryWidget::updateMouseTracking() {
@@ -4201,13 +4200,6 @@ void HistoryWidget::moveFieldControls() {
 	} else {
 		_muteUnmute->setGeometry(fullWidthButtonRect);
 	}
-
-	if (_aboutTopPromotion) {
-		_aboutTopPromotion->resizeToWidth(width());
-		_aboutTopPromotion->moveToLeft(
-			0,
-			fullWidthButtonRect.y() - _aboutTopPromotion->height());
-	}
 }
 
 void HistoryWidget::updateFieldSize() {
@@ -5225,9 +5217,6 @@ void HistoryWidget::updateHistoryGeometry(
 			newScrollHeight -= _kbScroll->height();
 		}
 	}
-	if (_aboutTopPromotion) {
-		newScrollHeight -= _aboutTopPromotion->height();
-	}
 	if (newScrollHeight <= 0) {
 		return;
 	}
@@ -5932,6 +5921,37 @@ bool HistoryWidget::sendExistingPhoto(not_null<PhotoData*> photo) {
 	return true;
 }
 
+void HistoryWidget::showInfoTooltip(
+		const TextWithEntities &text,
+		Fn<void()> hiddenCallback) {
+	hideInfoTooltip(anim::type::normal);
+	_topToast = Ui::Toast::Show(_scroll, Ui::Toast::Config{
+		.text = text,
+		.st = &st::historyInfoToast,
+		.durationMs = CountToastDuration(text),
+		.multiline = true,
+		.dark = true,
+		.slideSide = RectPart::Top,
+	});
+	if (const auto strong = _topToast.get()) {
+		if (hiddenCallback) {
+			connect(strong->widget(), &QObject::destroyed, hiddenCallback);
+		}
+	} else if (hiddenCallback) {
+		hiddenCallback();
+	}
+}
+
+void HistoryWidget::hideInfoTooltip(anim::type animated) {
+	if (const auto strong = _topToast.get()) {
+		if (animated == anim::type::normal) {
+			strong->hideAnimated();
+		} else {
+			strong->hide();
+		}
+	}
+}
+
 void HistoryWidget::setFieldText(
 		const TextWithTags &textWithTags,
 		TextUpdateEvents events,
@@ -6997,9 +7017,6 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
 		} else if (const auto error = writeRestriction()) {
 			drawRestrictedWrite(p, *error);
 		}
-		if (_aboutTopPromotion) {
-			p.fillRect(_aboutTopPromotion->geometry(), st::historyReplyBg);
-		}
 		if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {
 			drawPinnedBar(p);
 		}
diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h
index eaf8855c1..2ff422952 100644
--- a/Telegram/SourceFiles/history/history_widget.h
+++ b/Telegram/SourceFiles/history/history_widget.h
@@ -60,6 +60,9 @@ class SilentToggle;
 class FlatButton;
 class LinkButton;
 class RoundButton;
+namespace Toast {
+class Instance;
+} // namespace Toast
 } // namespace Ui
 
 namespace Window {
@@ -242,6 +245,11 @@ public:
 	bool sendExistingDocument(not_null<DocumentData*> document);
 	bool sendExistingPhoto(not_null<PhotoData*> photo);
 
+	void showInfoTooltip(
+		const TextWithEntities &text,
+		Fn<void()> hiddenCallback);
+	void hideInfoTooltip(anim::type animated);
+
 	// Tabbed selector management.
 	void pushTabbedSelectorToThirdSection(
 		const Window::SectionShow &params) override;
@@ -380,7 +388,7 @@ private:
 	void handlePeerUpdate();
 	void setMembersShowAreaActive(bool active);
 	void handleHistoryChange(not_null<const History*> history);
-	void refreshAboutTopPromotion();
+	void showAboutTopPromotion();
 	void unreadCountUpdated();
 
 	[[nodiscard]] int computeMaxFieldHeight() const;
@@ -734,8 +742,6 @@ private:
 	object_ptr<Ui::FlatButton> _joinChannel;
 	object_ptr<Ui::FlatButton> _muteUnmute;
 	object_ptr<Ui::FlatButton> _discuss;
-	object_ptr<Ui::RpWidget> _aboutTopPromotion = { nullptr };
-	TextWithEntities _aboutTopPromotionText;
 	object_ptr<Ui::IconButton> _attachToggle;
 	object_ptr<Ui::EmojiButton> _tabbedSelectorToggle;
 	object_ptr<Ui::IconButton> _botKeyboardShow;
@@ -802,6 +808,8 @@ private:
 	bool _saveDraftText = false;
 	QTimer _saveDraftTimer, _saveCloudDraftTimer;
 
+	base::weak_ptr<Ui::Toast::Instance> _topToast;
+
 	object_ptr<Ui::PlainShadow> _topShadow;
 	bool _inGrab = false;