From 6da62f902b5c718c968fb024eebf398db7146aef Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 9 Jun 2016 22:28:58 +0300
Subject: [PATCH] Animated show and hide of the new history-to-down button.
 Fixed render in outbox read event handler for channels / supergroups.

---
 Telegram/SourceFiles/app.cpp                  | 19 +++---
 Telegram/SourceFiles/historywidget.cpp        | 12 ++--
 Telegram/SourceFiles/mainwidget.cpp           | 19 +++---
 .../ui/buttons/history_down_button.cpp        | 64 +++++++++++++++++--
 .../ui/buttons/history_down_button.h          | 16 +++++
 5 files changed, 101 insertions(+), 29 deletions(-)

diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index c05e0624e..272c9b29b 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -1203,18 +1203,21 @@ namespace {
 	}
 
 	void feedInboxRead(const PeerId &peer, MsgId upTo) {
-		History *h = App::historyLoaded(peer);
-		if (h) {
-			h->inboxRead(upTo);
+		if (auto history = App::historyLoaded(peer)) {
+			history->inboxRead(upTo);
 		}
 	}
 
 	void feedOutboxRead(const PeerId &peer, MsgId upTo) {
-		History *h = App::historyLoaded(peer);
-		if (h) {
-			h->outboxRead(upTo);
-			if (h->peer->isUser()) {
-				h->peer->asUser()->madeAction();
+		if (auto history = App::historyLoaded(peer)) {
+			history->outboxRead(upTo);
+			if (history->lastMsg && history->lastMsg->out() && history->lastMsg->id <= upTo) {
+				if (App::main()) App::main()->dlgUpdated(history, history->lastMsg->id);
+			}
+			history->updateChatListEntry();
+
+			if (history->peer->isUser()) {
+				history->peer->asUser()->madeAction();
 			}
 		}
 	}
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 55bbfa12a..85fc58ff5 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -2906,7 +2906,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
 
 	updateScrollColors();
 
-	_historyToEnd->hide();
 	_historyToEnd->installEventFilter(this);
 
 	_fieldAutocomplete->hide();
@@ -5004,6 +5003,7 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
 	_cacheUnder = params.oldContentCache;
 	show();
 	_topShadow.setVisible(params.withTopBarShadow ? false : true);
+	_historyToEnd->finishAnimation();
 	_cacheOver = App::main()->grabForShowAnimation(params);
 	App::main()->topBar()->startAnim();
 	_topShadow.setVisible(params.withTopBarShadow ? true : false);
@@ -5056,6 +5056,7 @@ void HistoryWidget::step_show(float64 ms, bool timer) {
 	if (dt >= 1) {
 		_a_show.stop();
 		_topShadow.setVisible(_peer ? true : false);
+		_historyToEnd->finishAnimation();
 
 		a_coordUnder.finish();
 		a_coordOver.finish();
@@ -5100,6 +5101,7 @@ void HistoryWidget::animStop() {
 	if (!_a_show.animating()) return;
 	_a_show.stop();
 	_topShadow.setVisible(_peer ? true : false);
+	_historyToEnd->finishAnimation();
 }
 
 void HistoryWidget::step_record(float64 ms, bool timer) {
@@ -6846,10 +6848,10 @@ void HistoryWidget::updateToEndVisibility() {
 		return false;
 	};
 	bool toEndVisible = isToEndVisible();
-	if (toEndVisible && _historyToEnd->isHidden()) {
-		_historyToEnd->show();
-	} else if (!toEndVisible && !_historyToEnd->isHidden()) {
-		_historyToEnd->hide();
+	if (toEndVisible && _historyToEnd->hidden()) {
+		_historyToEnd->showAnimated();
+	} else if (!toEndVisible && !_historyToEnd->hidden()) {
+		_historyToEnd->hideAnimated();
 	}
 }
 
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index e59b115fd..4a1f6524d 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -4178,17 +4178,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		}
 
 		// update before applying skipped
-		PeerId id = peerFromMTP(d.vpeer);
-		App::feedOutboxRead(id, d.vmax_id.v);
-		if (_history->peer() && _history->peer()->id == id) {
+		auto peerId = peerFromMTP(d.vpeer);
+		App::feedOutboxRead(peerId, d.vmax_id.v);
+		if (_history->peer() && _history->peer()->id == peerId) {
 			_history->update();
 		}
-		if (History *h = App::historyLoaded(id)) {
-			if (h->lastMsg && h->lastMsg->out() && h->lastMsg->id <= d.vmax_id.v) {
-				dlgUpdated(h, h->lastMsg->id);
-			}
-			h->updateChatListEntry();
-		}
 
 		ptsApplySkippedUpdates();
 	} break;
@@ -4538,8 +4532,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 
 	case mtpc_updateReadChannelOutbox: {
 		auto &d(update.c_updateReadChannelOutbox());
-		auto channel = App::channelLoaded(d.vchannel_id.v);
-		App::feedOutboxRead(peerFromChannel(d.vchannel_id.v), d.vmax_id.v);
+		auto peerId = peerFromChannel(d.vchannel_id.v);
+		App::feedOutboxRead(peerId, d.vmax_id.v);
+		if (_history->peer() && _history->peer()->id == peerId) {
+			_history->update();
+		}
 	} break;
 
 	case mtpc_updateDeleteChannelMessages: {
diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
index 3ba35eec6..409091755 100644
--- a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
+++ b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
@@ -30,16 +30,44 @@ HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
 , a_arrowOpacity(st::btnAttachEmoji.opacity, st::btnAttachEmoji.opacity)
 , _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
 	setCursor(style::cur_pointer);
-	resize(st::historyToDown.width(), st::historyToDownPaddingTop + st::historyToDown.height());
+
+	int iconWidth = st::historyToDown.width();
+	int iconHeight = st::historyToDown.height();
+	int retina = cIntRetinaFactor();
+	resize(iconWidth, st::historyToDownPaddingTop + iconHeight);
+
+	QImage cache(iconWidth * retina, iconHeight * retina, QImage::Format_ARGB32_Premultiplied);
+	cache.setDevicePixelRatio(cRetinaFactor());
+	{
+		Painter p(&cache);
+		p.setCompositionMode(QPainter::CompositionMode_Source);
+		p.fillRect(0, 0, iconWidth, iconHeight, st::transparent);
+		st::historyToDown.paint(p, QPoint(0, 0), st::historyToDown.width());
+	}
+	_cache = App::pixmapFromImageInPlace(std_::move(cache));
+	_cache.setDevicePixelRatio(cRetinaFactor());
+
+	hide();
 }
 
 void HistoryDownButton::paintEvent(QPaintEvent *e) {
 	Painter p(this);
-	st::historyToDown.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
-	p.setOpacity(a_arrowOpacity.current());
+
+	float64 opacity = 1.;
+	if (_a_show.animating(getms())) {
+		opacity = _a_show.current();
+		p.setOpacity(opacity);
+		p.drawPixmap(0, st::historyToDownPaddingTop, _cache);
+	} else if (!_shown) {
+		hide();
+		return;
+	} else {
+		st::historyToDown.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
+	}
+	p.setOpacity(opacity * a_arrowOpacity.current());
 	st::historyToDownArrow.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
 	if (_unreadCount > 0) {
-		p.setOpacity(1);
+		p.setOpacity(opacity);
 		bool active = false, muted = false;
 		auto unreadString = QString::number(_unreadCount);
 		if (unreadString.size() > 4) {
@@ -66,6 +94,33 @@ void HistoryDownButton::setUnreadCount(int unreadCount) {
 	update();
 }
 
+bool HistoryDownButton::hidden() const {
+	return !_shown;
+}
+
+void HistoryDownButton::showAnimated() {
+	if (_shown) return;
+
+	if (isHidden()) show();
+	toggleAnimated();
+}
+
+void HistoryDownButton::hideAnimated() {
+	if (!_shown) return;
+	toggleAnimated();
+}
+
+void HistoryDownButton::toggleAnimated() {
+	_shown = !_shown;
+	float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.;
+	START_ANIMATION(_a_show, func(this, &HistoryDownButton::repaintCallback), from, to, st::btnAttachEmoji.duration, anim::linear);
+}
+
+void HistoryDownButton::finishAnimation() {
+	_a_show.finish();
+	setVisible(_shown);
+}
+
 void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
 	float64 dt = ms / st::btnAttachEmoji.duration;
 	if (dt >= 1) {
@@ -77,5 +132,4 @@ void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
 	if (timer) update();
 }
 
-
 } // namespace Ui
diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.h b/Telegram/SourceFiles/ui/buttons/history_down_button.h
index 4b81ca5d3..43dbd098c 100644
--- a/Telegram/SourceFiles/ui/buttons/history_down_button.h
+++ b/Telegram/SourceFiles/ui/buttons/history_down_button.h
@@ -33,17 +33,33 @@ public:
 		return _unreadCount;
 	}
 
+	bool hidden() const;
+
+	void showAnimated();
+	void hideAnimated();
+
+	void finishAnimation();
+
 protected:
 	void paintEvent(QPaintEvent *e) override;
 
 	void onStateChanged(int oldState, ButtonStateChangeSource source) override;
 
 private:
+	void toggleAnimated();
+	void repaintCallback() {
+		update();
+	}
 	void step_arrowOver(float64 ms, bool timer);
 
+	QPixmap _cache;
+	bool _shown = false;
+
 	anim::fvalue a_arrowOpacity;
 	Animation _a_arrowOver;
 
+	FloatAnimation _a_show;
+
 	int _unreadCount = 0;
 
 };