From e118972d5cf110a5c78e31c99d07d98ff946c0ad Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Sun, 19 Apr 2020 16:17:53 +0400
Subject: [PATCH] Support generic dice media display.

---
 .../chat_helpers/stickers_dice_pack.cpp       | 31 +++++++++++++++----
 .../chat_helpers/stickers_dice_pack.h         |  1 +
 .../history/view/media/history_view_dice.cpp  | 27 +++++++++++-----
 .../history/view/media/history_view_dice.h    |  6 ++--
 .../view/media/history_view_sticker.cpp       | 22 +++++++++----
 .../history/view/media/history_view_sticker.h | 10 ++++++
 6 files changed, 75 insertions(+), 22 deletions(-)

diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp
index 869fa4b40..d69b76742 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp
+++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp
@@ -35,11 +35,11 @@ DocumentData *DicePack::lookup(int value) {
 	if (!_requestId) {
 		load();
 	}
-	if (!value) {
-		ensureZeroGenerated();
-		return _zero;
-	}
 	const auto i = _map.find(value);
+	//if (!value) {
+	//	ensureZeroGenerated();
+	//	return _zero;
+	//}
 	return (i != end(_map)) ? i->second.get() : nullptr;
 }
 
@@ -59,14 +59,33 @@ void DicePack::load() {
 }
 
 void DicePack::applySet(const MTPDmessages_stickerSet &data) {
-	auto index = 0;
+	_map.clear();
+	auto documents = base::flat_map<DocumentId, not_null<DocumentData*>>();
 	for (const auto &sticker : data.vdocuments().v) {
 		const auto document = _session->data().processDocument(
 			sticker);
 		if (document->sticker()) {
-			_map.emplace(++index, document);
+			documents.emplace(document->id, document);
 		}
 	}
+	for (const auto pack : data.vpacks().v) {
+		pack.match([&](const MTPDstickerPack &data) {
+			const auto emoji = qs(data.vemoticon());
+			if (emoji.isEmpty()) {
+				return;
+			}
+			const auto ch = int(emoji[0].unicode());
+			const auto index = (ch == '#') ? 0 : (ch + 1 - '1');
+			if (index < 0 || index > 6) {
+				return;
+			}
+			for (const auto id : data.vdocuments().v) {
+				if (const auto document = documents.take(id.v)) {
+					_map.emplace(index, *document);
+				}
+			}
+		});
+	}
 }
 
 void DicePack::ensureZeroGenerated() {
diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h
index aa8d2db31..92035bfdc 100644
--- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h
+++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.h
@@ -1,4 +1,5 @@
 /*
+/*
 This file is part of Telegram Desktop,
 the official desktop application for the Telegram messaging service.
 
diff --git a/Telegram/SourceFiles/history/view/media/history_view_dice.cpp b/Telegram/SourceFiles/history/view/media/history_view_dice.cpp
index 30fb6468a..b3fd34bfb 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_dice.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_dice.cpp
@@ -44,11 +44,13 @@ Dice::Dice(not_null<Element*> parent, not_null<Data::MediaDice*> dice)
 : _parent(parent)
 , _dice(dice)
 , _link(_parent->data()->Has<HistoryMessageForwarded>()
-	? nullptr
-	: MakeDiceHandler(dice->emoji()))
-, _start(parent, Lookup(parent, dice->emoji(), 0)) {
+		? nullptr
+		: MakeDiceHandler(dice->emoji())) {
+	if (const auto document = Lookup(parent, dice->emoji(), 0)) {
+		_start.emplace(parent, document);
+		_start->setDiceIndex(_dice->emoji(), 0);
+	}
 	_showLastFrame = _parent->data()->Has<HistoryMessageForwarded>();
-	_start.setDiceIndex(_dice->emoji(), 0);
 	if (_showLastFrame) {
 		_drawingEnd = true;
 	}
@@ -57,7 +59,9 @@ Dice::Dice(not_null<Element*> parent, not_null<Data::MediaDice*> dice)
 Dice::~Dice() = default;
 
 QSize Dice::size() {
-	return _start.size();
+	return _start
+		? _start->size()
+		: Sticker::GetAnimatedEmojiSize(&_parent->history()->session());
 }
 
 ClickHandlerPtr Dice::link() {
@@ -65,6 +69,13 @@ ClickHandlerPtr Dice::link() {
 }
 
 void Dice::draw(Painter &p, const QRect &r, bool selected) {
+	if (!_start) {
+		if (const auto document = Lookup(_parent, _dice->emoji(), 0)) {
+			_start.emplace(_parent, document);
+			_start->setDiceIndex(_dice->emoji(), 0);
+			_start->initSize();
+		}
+	}
 	if (const auto value = _end ? 0 : _dice->value()) {
 		if (const auto document = Lookup(_parent, _dice->emoji(), value)) {
 			_end.emplace(_parent, document);
@@ -77,9 +88,9 @@ void Dice::draw(Painter &p, const QRect &r, bool selected) {
 	}
 	if (_drawingEnd) {
 		_end->draw(p, r, selected);
-	} else {
-		_start.draw(p, r, selected);
-		if (_end && _end->readyToDrawLottie() && _start.atTheEnd()) {
+	} else if (_start) {
+		_start->draw(p, r, selected);
+		if (_end && _end->readyToDrawLottie() && _start->atTheEnd()) {
 			_drawingEnd = true;
 		}
 	}
diff --git a/Telegram/SourceFiles/history/view/media/history_view_dice.h b/Telegram/SourceFiles/history/view/media/history_view_dice.h
index 0c614deca..2e784ed1a 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_dice.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_dice.h
@@ -29,7 +29,9 @@ public:
 	void clearStickerLoopPlayed() override {
 	}
 	void unloadHeavyPart() override {
-		_start.unloadHeavyPart();
+		if (_start) {
+			_start->unloadHeavyPart();
+		}
 		if (_end) {
 			_end->unloadHeavyPart();
 		}
@@ -42,8 +44,8 @@ private:
 	const not_null<Element*> _parent;
 	const not_null<Data::MediaDice*> _dice;
 	ClickHandlerPtr _link;
+	std::optional<Sticker> _start;
 	std::optional<Sticker> _end;
-	Sticker _start;
 	mutable bool _showLastFrame = false;
 	mutable bool _drawingEnd = false;
 
diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
index 037567221..56e913809 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp
@@ -74,12 +74,7 @@ bool Sticker::isEmojiSticker() const {
 void Sticker::initSize() {
 	_size = _document->dimensions;
 	if (isEmojiSticker() || _diceIndex >= 0) {
-		constexpr auto kIdealStickerSize = 512;
-		const auto zoom = GetEmojiStickerZoom(&_document->session());
-		const auto convert = [&](int size) {
-			return int(size * st::maxStickerSize * zoom / kIdealStickerSize);
-		};
-		_size = QSize(convert(_size.width()), convert(_size.height()));
+		_size = GetAnimatedEmojiSize(&_document->session(), _size);
 		[[maybe_unused]] bool result = readyToDrawLottie();
 	} else {
 		_size = DownscaledSize(
@@ -110,6 +105,21 @@ bool Sticker::readyToDrawLottie() {
 	return (_lottie && _lottie->ready());
 }
 
+QSize Sticker::GetAnimatedEmojiSize(not_null<Main::Session*> session) {
+	return GetAnimatedEmojiSize(session, { 512, 512 });
+}
+
+QSize Sticker::GetAnimatedEmojiSize(
+		not_null<Main::Session*> session,
+		QSize documentSize) {
+	constexpr auto kIdealStickerSize = 512;
+	const auto zoom = GetEmojiStickerZoom(session);
+	const auto convert = [&](int size) {
+		return int(size * st::maxStickerSize * zoom / kIdealStickerSize);
+	};
+	return { convert(documentSize.width()), convert(documentSize.height()) };
+}
+
 void Sticker::draw(Painter &p, const QRect &r, bool selected) {
 	if (readyToDrawLottie()) {
 		paintLottie(p, r, selected);
diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.h b/Telegram/SourceFiles/history/view/media/history_view_sticker.h
index 7ec89fb3e..e9e09c7c3 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_sticker.h
+++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.h
@@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 #include "history/view/media/history_view_media_unwrapped.h"
 #include "base/weak_ptr.h"
 
+namespace Main {
+class Session;
+} // namespace Main
+
 namespace Data {
 struct FileOrigin;
 } // namespace Data
@@ -55,6 +59,12 @@ public:
 	}
 	[[nodiscard]] bool readyToDrawLottie();
 
+	[[nodiscard]] static QSize GetAnimatedEmojiSize(
+		not_null<Main::Session*> session);
+	[[nodiscard]] static QSize GetAnimatedEmojiSize(
+		not_null<Main::Session*> session,
+		QSize documentSize);
+
 private:
 	[[nodiscard]] bool isEmojiSticker() const;
 	void paintLottie(Painter &p, const QRect &r, bool selected);