diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp new file mode 100644 index 000000000..65d3ad149 --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp @@ -0,0 +1,91 @@ +/* +This file is part of Telegram Desktop, +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 "chat_helpers/stickers_emoji_pack.h" + +#include "history/history_item.h" +#include "ui/emoji_config.h" +#include "main/main_session.h" +#include "data/data_session.h" +#include "data/data_document.h" +#include "apiwrap.h" + +namespace Stickers { +namespace { + +constexpr auto kRefreshTimeout = TimeId(7200); + +} // namespace + +EmojiPack::EmojiPack(not_null session) : _session(session) { + refresh(); +} + +DocumentData *EmojiPack::stickerForEmoji(not_null item) { + const auto text = item->originalText().text.trimmed(); + auto length = 0; + const auto emoji = Ui::Emoji::Find(text, &length); + if (!emoji || length != text.size()) { + return nullptr; + } + const auto i = _map.find(emoji); + if (i != end(_map)) { + return i->second; + } + return nullptr; +} + +void EmojiPack::refresh() { + if (_requestId) { + return; + } + _requestId = _session->api().request(MTPmessages_GetStickerSet( + MTP_inputStickerSetAnimatedEmoji() + )).done([=](const MTPmessages_StickerSet &result) { + refreshDelayed(); + result.match([&](const MTPDmessages_stickerSet &data) { + auto map = base::flat_map>(); + for (const auto &sticker : data.vdocuments().v) { + const auto document = _session->data().processDocument( + sticker); + if (document->sticker()) { + map.emplace(document->id, document); + } + } + for (const auto &pack : data.vpacks().v) { + pack.match([&](const MTPDstickerPack &data) { + const auto emoji = [&] { + return Ui::Emoji::Find(qs(data.vemoticon())); + }(); + const auto document = [&]() -> DocumentData* { + for (const auto &id : data.vdocuments().v) { + const auto i = map.find(id.v); + if (i != end(map)) { + return i->second.get(); + } + } + return nullptr; + }(); + if (emoji && document) { + _map.emplace_or_assign(emoji, document); + } + }); + } + }); + int a = 0; + }).fail([=](const RPCError &error) { + refreshDelayed(); + }).send(); +} + +void EmojiPack::refreshDelayed() { + App::CallDelayed(kRefreshTimeout, _session, [=] { + refresh(); + }); +} + +} // namespace Stickers diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h new file mode 100644 index 000000000..6c31ad3bc --- /dev/null +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h @@ -0,0 +1,38 @@ +/* +This file is part of Telegram Desktop, +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 +*/ +#pragma once + +namespace Main { +class Session; +} // namespace Main + +class HistoryItem; +class DocumentData; + +namespace Stickers { + +class EmojiPack final { +public: + explicit EmojiPack(not_null session); + + [[nodiscard]] DocumentData *stickerForEmoji(not_null item); + +private: + void refresh(); + void refreshDelayed(); + + not_null _session; + base::flat_set> _notLoaded; + base::flat_map> _map; + mtpRequestId _requestId = 0; + + rpl::lifetime _lifetime; + +}; + +} // namespace Stickers diff --git a/Telegram/SourceFiles/history/media/history_media_sticker.cpp b/Telegram/SourceFiles/history/media/history_media_sticker.cpp index 302e87b5d..c2a55c6af 100644 --- a/Telegram/SourceFiles/history/media/history_media_sticker.cpp +++ b/Telegram/SourceFiles/history/media/history_media_sticker.cpp @@ -46,13 +46,30 @@ HistorySticker::~HistorySticker() { unloadLottie(); } +bool HistorySticker::isEmojiSticker() const { + return (_parent->data()->media() == nullptr); +} + QSize HistorySticker::countOptimalSize() { auto sticker = _data->sticker(); - if (!_packLink && sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) { - _packLink = std::make_shared([document = _data] { - StickerSetBox::Show(App::wnd()->sessionController(), document); - }); + if (!_packLink) { + if (isEmojiSticker()) { + const auto weak = base::make_weak(this); + _packLink = std::make_shared([weak] { + const auto that = weak.get(); + if (!that) { + return; + } + that->_lottieOncePlayed = false; + that->_parent->data()->history()->owner().requestViewRepaint( + that->_parent); + }); + } else if (sticker && sticker->set.type() != mtpc_inputStickerSetEmpty) { + _packLink = std::make_shared([document = _data] { + StickerSetBox::Show(App::wnd()->sessionController(), document); + }); + } } _pixw = _data->dimensions.width(); _pixh = _data->dimensions.height(); @@ -213,7 +230,8 @@ void HistorySticker::draw( frame.image); const auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any); - const auto playOnce = !_data->session().settings().loopAnimatedStickers(); + const auto playOnce = isEmojiSticker() + || !_data->session().settings().loopAnimatedStickers(); if (!paused && (!playOnce || frame.index != 0 || !_lottieOncePlayed) && _lottie->markFrameShown() diff --git a/Telegram/SourceFiles/history/media/history_media_sticker.h b/Telegram/SourceFiles/history/media/history_media_sticker.h index eca113397..d5998ecb7 100644 --- a/Telegram/SourceFiles/history/media/history_media_sticker.h +++ b/Telegram/SourceFiles/history/media/history_media_sticker.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "history/media/history_media.h" +#include "base/weak_ptr.h" #include "base/timer.h" struct HistoryMessageVia; @@ -18,7 +19,7 @@ namespace Lottie { class SinglePlayer; } // namespace Lottie -class HistorySticker : public HistoryMedia { +class HistorySticker : public HistoryMedia, public base::has_weak_ptr { public: HistorySticker( not_null parent, @@ -63,6 +64,8 @@ public: } private: + [[nodiscard]] bool isEmojiSticker() const; + QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index fb5f1cf1b..e2cb084c1 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -13,7 +13,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "history/media/history_media.h" #include "history/media/history_media_grouped.h" +#include "history/media/history_media_sticker.h" #include "history/history.h" +#include "main/main_session.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "data/data_session.h" #include "data/data_groups.h" #include "data/data_media_types.h" @@ -338,8 +341,11 @@ void Element::refreshMedia() { return; } } + const auto emojiStickers = &history()->session().emojiStickersPack(); if (_data->media()) { _media = _data->media()->createView(this); + } else if (const auto document = emojiStickers->stickerForEmoji(_data)) { + _media = std::make_unique(this, document); } else { _media = nullptr; } diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 10f31336d..10567f1d1 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_instance.h" #include "window/section_widget.h" #include "chat_helpers/tabbed_selector.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "boxes/send_files_box.h" #include "ui/widgets/input_fields.h" #include "support/support_common.h" @@ -468,6 +469,7 @@ Session::Session( , _notifications(std::make_unique(this)) , _data(std::make_unique(this)) , _user(_data->processUser(user)) +, _emojiStickersPack(std::make_unique(this)) , _changelogs(Core::Changelogs::Create(this)) , _supportHelper(Support::Helper::Create(this)) { _saveDataTimer.setCallback([=] { diff --git a/Telegram/SourceFiles/main/main_session.h b/Telegram/SourceFiles/main/main_session.h index 6dafa969b..82e7e9ff5 100644 --- a/Telegram/SourceFiles/main/main_session.h +++ b/Telegram/SourceFiles/main/main_session.h @@ -51,6 +51,10 @@ namespace ChatHelpers { enum class SelectorTab; } // namespace ChatHelpers +namespace Stickers { +class EmojiPack; +} // namespace Stickers; + namespace Core { class Changelogs; } // namespace Core @@ -328,6 +332,9 @@ public: Storage::Facade &storage() { return *_storage; } + Stickers::EmojiPack &emojiStickersPack() { + return *_emojiStickersPack; + } base::Observable &downloaderTaskFinished(); @@ -391,6 +398,9 @@ private: const std::unique_ptr _data; const not_null _user; + // _emojiStickersPack depends on _data. + const std::unique_ptr _emojiStickersPack; + // _changelogs depends on _data, subscribes on chats loading event. const std::unique_ptr _changelogs; diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index a621d1bc6..bc0329479 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -121,6 +121,8 @@ <(src_loc)/chat_helpers/message_field.h <(src_loc)/chat_helpers/stickers.cpp <(src_loc)/chat_helpers/stickers.h +<(src_loc)/chat_helpers/stickers_emoji_pack.cpp +<(src_loc)/chat_helpers/stickers_emoji_pack.h <(src_loc)/chat_helpers/stickers_list_widget.cpp <(src_loc)/chat_helpers/stickers_list_widget.h <(src_loc)/chat_helpers/tabbed_panel.cpp