Initial animated emoji implementation.

This commit is contained in:
John Preston 2019-08-01 15:13:02 +01:00
parent 4b7b1c35e1
commit f7f797dd78
8 changed files with 176 additions and 6 deletions

View File

@ -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<Main::Session*> session) : _session(session) {
refresh();
}
DocumentData *EmojiPack::stickerForEmoji(not_null<HistoryItem*> 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<uint64, not_null<DocumentData*>>();
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

View File

@ -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<Main::Session*> session);
[[nodiscard]] DocumentData *stickerForEmoji(not_null<HistoryItem*> item);
private:
void refresh();
void refreshDelayed();
not_null<Main::Session*> _session;
base::flat_set<not_null<HistoryItem*>> _notLoaded;
base::flat_map<EmojiPtr, not_null<DocumentData*>> _map;
mtpRequestId _requestId = 0;
rpl::lifetime _lifetime;
};
} // namespace Stickers

View File

@ -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<LambdaClickHandler>([document = _data] {
StickerSetBox::Show(App::wnd()->sessionController(), document);
});
if (!_packLink) {
if (isEmojiSticker()) {
const auto weak = base::make_weak(this);
_packLink = std::make_shared<LambdaClickHandler>([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<LambdaClickHandler>([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()

View File

@ -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<Element*> parent,
@ -63,6 +64,8 @@ public:
}
private:
[[nodiscard]] bool isEmojiSticker() const;
QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override;

View File

@ -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<HistorySticker>(this, document);
} else {
_media = nullptr;
}

View File

@ -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<Window::Notifications::System>(this))
, _data(std::make_unique<Data::Session>(this))
, _user(_data->processUser(user))
, _emojiStickersPack(std::make_unique<Stickers::EmojiPack>(this))
, _changelogs(Core::Changelogs::Create(this))
, _supportHelper(Support::Helper::Create(this)) {
_saveDataTimer.setCallback([=] {

View File

@ -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<void> &downloaderTaskFinished();
@ -391,6 +398,9 @@ private:
const std::unique_ptr<Data::Session> _data;
const not_null<UserData*> _user;
// _emojiStickersPack depends on _data.
const std::unique_ptr<Stickers::EmojiPack> _emojiStickersPack;
// _changelogs depends on _data, subscribes on chats loading event.
const std::unique_ptr<Core::Changelogs> _changelogs;

View File

@ -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