mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show, send and receive interactions in single custom emoji.
This commit is contained in:
parent
9e63fc5acd
commit
e438cb57bc
18 changed files with 158 additions and 88 deletions
|
@ -69,60 +69,26 @@ EmojiInteractions::~EmojiInteractions() = default;
|
||||||
void EmojiInteractions::checkEdition(
|
void EmojiInteractions::checkEdition(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
base::flat_map<not_null<HistoryItem*>, std::vector<Animation>> &map) {
|
base::flat_map<not_null<HistoryItem*>, std::vector<Animation>> &map) {
|
||||||
|
const auto &pack = _session->emojiStickersPack();
|
||||||
const auto i = map.find(item);
|
const auto i = map.find(item);
|
||||||
if (i != end(map)
|
if (i != end(map)
|
||||||
&& (i->second.front().emoji != chooseInteractionEmoji(item))) {
|
&& (i->second.front().emoji != pack.chooseInteractionEmoji(item))) {
|
||||||
map.erase(i);
|
map.erase(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiPtr EmojiInteractions::chooseInteractionEmoji(
|
|
||||||
not_null<HistoryItem*> item) const {
|
|
||||||
return chooseInteractionEmoji(item->originalText().text);
|
|
||||||
}
|
|
||||||
|
|
||||||
EmojiPtr EmojiInteractions::chooseInteractionEmoji(
|
|
||||||
const QString &emoticon) const {
|
|
||||||
const auto emoji = Ui::Emoji::Find(emoticon);
|
|
||||||
if (!emoji) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
const auto &pack = _session->emojiStickersPack();
|
|
||||||
if (!pack.animationsForEmoji(emoji).empty()) {
|
|
||||||
return emoji;
|
|
||||||
}
|
|
||||||
if (const auto original = emoji->original(); original != emoji) {
|
|
||||||
if (!pack.animationsForEmoji(original).empty()) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static const auto kHearts = {
|
|
||||||
QString::fromUtf8("\xf0\x9f\x92\x9b"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\x92\x99"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\x92\x9a"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\x92\x9c"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\xa7\xa1"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\x96\xa4"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\xa4\x8e"),
|
|
||||||
QString::fromUtf8("\xf0\x9f\xa4\x8d"),
|
|
||||||
};
|
|
||||||
return ranges::contains(kHearts, emoji->id())
|
|
||||||
? Ui::Emoji::Find(QString::fromUtf8("\xe2\x9d\xa4"))
|
|
||||||
: emoji;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiInteractions::startOutgoing(
|
void EmojiInteractions::startOutgoing(
|
||||||
not_null<const HistoryView::Element*> view) {
|
not_null<const HistoryView::Element*> view) {
|
||||||
const auto item = view->data();
|
const auto item = view->data();
|
||||||
if (!item->isRegular() || !item->history()->peer->isUser()) {
|
if (!item->isRegular() || !item->history()->peer->isUser()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto &pack = _session->emojiStickersPack();
|
||||||
const auto emoticon = item->originalText().text;
|
const auto emoticon = item->originalText().text;
|
||||||
const auto emoji = chooseInteractionEmoji(emoticon);
|
const auto emoji = pack.chooseInteractionEmoji(emoticon);
|
||||||
if (!emoji) {
|
if (!emoji) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &pack = _session->emojiStickersPack();
|
|
||||||
const auto &list = pack.animationsForEmoji(emoji);
|
const auto &list = pack.animationsForEmoji(emoji);
|
||||||
if (list.empty()) {
|
if (list.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -168,11 +134,11 @@ void EmojiInteractions::startIncoming(
|
||||||
if (!item || !item->isRegular()) {
|
if (!item || !item->isRegular()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto emoji = chooseInteractionEmoji(item);
|
const auto &pack = _session->emojiStickersPack();
|
||||||
if (!emoji || emoji != chooseInteractionEmoji(emoticon)) {
|
const auto emoji = pack.chooseInteractionEmoji(item);
|
||||||
|
if (!emoji || emoji != pack.chooseInteractionEmoji(emoticon)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &pack = _session->emojiStickersPack();
|
|
||||||
const auto &list = pack.animationsForEmoji(emoji);
|
const auto &list = pack.animationsForEmoji(emoji);
|
||||||
if (list.empty()) {
|
if (list.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -215,8 +181,9 @@ void EmojiInteractions::startIncoming(
|
||||||
void EmojiInteractions::seenOutgoing(
|
void EmojiInteractions::seenOutgoing(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const QString &emoticon) {
|
const QString &emoticon) {
|
||||||
|
const auto &pack = _session->emojiStickersPack();
|
||||||
if (const auto i = _playsSent.find(peer); i != end(_playsSent)) {
|
if (const auto i = _playsSent.find(peer); i != end(_playsSent)) {
|
||||||
if (const auto emoji = chooseInteractionEmoji(emoticon)) {
|
if (const auto emoji = pack.chooseInteractionEmoji(emoticon)) {
|
||||||
if (const auto j = i->second.find(emoji); j != end(i->second)) {
|
if (const auto j = i->second.find(emoji); j != end(i->second)) {
|
||||||
const auto last = j->second.lastDoneReceivedAt;
|
const auto last = j->second.lastDoneReceivedAt;
|
||||||
if (!last || last + kAcceptSeenSinceRequest > crl::now()) {
|
if (!last || last + kAcceptSeenSinceRequest > crl::now()) {
|
||||||
|
|
|
@ -97,11 +97,6 @@ private:
|
||||||
};
|
};
|
||||||
[[nodiscard]] static CheckResult Combine(CheckResult a, CheckResult b);
|
[[nodiscard]] static CheckResult Combine(CheckResult a, CheckResult b);
|
||||||
|
|
||||||
[[nodiscard]] EmojiPtr chooseInteractionEmoji(
|
|
||||||
not_null<HistoryItem*> item) const;
|
|
||||||
[[nodiscard]] EmojiPtr chooseInteractionEmoji(
|
|
||||||
const QString &emoticon) const;
|
|
||||||
|
|
||||||
void check(crl::time now = 0);
|
void check(crl::time now = 0);
|
||||||
[[nodiscard]] CheckResult checkAnimations(crl::time now);
|
[[nodiscard]] CheckResult checkAnimations(crl::time now);
|
||||||
[[nodiscard]] CheckResult checkAnimations(
|
[[nodiscard]] CheckResult checkAnimations(
|
||||||
|
|
|
@ -214,13 +214,58 @@ std::shared_ptr<LargeEmojiImage> EmojiPack::image(EmojiPtr emoji) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmojiPtr EmojiPack::chooseInteractionEmoji(
|
||||||
|
not_null<HistoryItem*> item) const {
|
||||||
|
return chooseInteractionEmoji(item->originalText().text);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmojiPtr EmojiPack::chooseInteractionEmoji(
|
||||||
|
const QString &emoticon) const {
|
||||||
|
const auto emoji = Ui::Emoji::Find(emoticon);
|
||||||
|
if (!emoji) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!animationsForEmoji(emoji).empty()) {
|
||||||
|
return emoji;
|
||||||
|
}
|
||||||
|
if (const auto original = emoji->original(); original != emoji) {
|
||||||
|
if (!animationsForEmoji(original).empty()) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static const auto kHearts = {
|
||||||
|
QString::fromUtf8("\xf0\x9f\x92\x9b"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\x92\x99"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\x92\x9a"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\x92\x9c"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\xa7\xa1"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\x96\xa4"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\xa4\x8e"),
|
||||||
|
QString::fromUtf8("\xf0\x9f\xa4\x8d"),
|
||||||
|
};
|
||||||
|
return ranges::contains(kHearts, emoji->id())
|
||||||
|
? Ui::Emoji::Find(QString::fromUtf8("\xe2\x9d\xa4"))
|
||||||
|
: emoji;
|
||||||
|
}
|
||||||
|
|
||||||
auto EmojiPack::animationsForEmoji(EmojiPtr emoji) const
|
auto EmojiPack::animationsForEmoji(EmojiPtr emoji) const
|
||||||
-> const base::flat_map<int, not_null<DocumentData*>> & {
|
-> const base::flat_map<int, not_null<DocumentData*>> & {
|
||||||
static const auto empty = base::flat_map<int, not_null<DocumentData*>>();
|
static const auto empty = base::flat_map<int, not_null<DocumentData*>>();
|
||||||
|
if (!emoji) {
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
const auto i = _animations.find(emoji);
|
const auto i = _animations.find(emoji);
|
||||||
return (i != end(_animations)) ? i->second : empty;
|
return (i != end(_animations)) ? i->second : empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EmojiPack::hasAnimationsFor(not_null<HistoryItem*> item) const {
|
||||||
|
return !animationsForEmoji(chooseInteractionEmoji(item)).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EmojiPack::hasAnimationsFor(const QString &emoticon) const {
|
||||||
|
return !animationsForEmoji(chooseInteractionEmoji(emoticon)).empty();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Lottie::SinglePlayer> EmojiPack::effectPlayer(
|
std::unique_ptr<Lottie::SinglePlayer> EmojiPack::effectPlayer(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
QByteArray data,
|
QByteArray data,
|
||||||
|
@ -371,6 +416,7 @@ void EmojiPack::applyAnimationsSet(const MTPDmessages_stickerSet &data) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
++_animationsVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiPack::collectAnimationsIndices(
|
auto EmojiPack::collectAnimationsIndices(
|
||||||
|
|
|
@ -70,8 +70,17 @@ public:
|
||||||
[[nodiscard]] Sticker stickerForEmoji(const IsolatedEmoji &emoji);
|
[[nodiscard]] Sticker stickerForEmoji(const IsolatedEmoji &emoji);
|
||||||
[[nodiscard]] std::shared_ptr<LargeEmojiImage> image(EmojiPtr emoji);
|
[[nodiscard]] std::shared_ptr<LargeEmojiImage> image(EmojiPtr emoji);
|
||||||
|
|
||||||
|
[[nodiscard]] EmojiPtr chooseInteractionEmoji(
|
||||||
|
not_null<HistoryItem*> item) const;
|
||||||
|
[[nodiscard]] EmojiPtr chooseInteractionEmoji(
|
||||||
|
const QString &emoticon) const;
|
||||||
[[nodiscard]] auto animationsForEmoji(EmojiPtr emoji) const
|
[[nodiscard]] auto animationsForEmoji(EmojiPtr emoji) const
|
||||||
-> const base::flat_map<int, not_null<DocumentData*>> &;
|
-> const base::flat_map<int, not_null<DocumentData*>> &;
|
||||||
|
[[nodiscard]] bool hasAnimationsFor(not_null<HistoryItem*> item) const;
|
||||||
|
[[nodiscard]] bool hasAnimationsFor(const QString &emoticon) const;
|
||||||
|
[[nodiscard]] int animationsVersion() const {
|
||||||
|
return _animationsVersion;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> effectPlayer(
|
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> effectPlayer(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
|
@ -109,6 +118,7 @@ private:
|
||||||
|
|
||||||
base::flat_set<not_null<HistoryItem*>> _onlyCustomItems;
|
base::flat_set<not_null<HistoryItem*>> _onlyCustomItems;
|
||||||
|
|
||||||
|
int _animationsVersion = 0;
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
EmojiPtr,
|
EmojiPtr,
|
||||||
base::flat_map<int, not_null<DocumentData*>>> _animations;
|
base::flat_map<int, not_null<DocumentData*>>> _animations;
|
||||||
|
|
|
@ -3106,7 +3106,7 @@ auto HistoryInner::prevItem(Element *view) -> Element* {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (const auto result = view->previousDisplayedInBlocks()) {
|
} else if (const auto result = view->previousDisplayedInBlocks()) {
|
||||||
return result;
|
return result;
|
||||||
} else if (view->data()->history() == _history
|
} else if (view->history() == _history
|
||||||
&& _migrated
|
&& _migrated
|
||||||
&& _history->loadedAtTop()
|
&& _history->loadedAtTop()
|
||||||
&& !_migrated->isEmpty()
|
&& !_migrated->isEmpty()
|
||||||
|
@ -3121,7 +3121,7 @@ auto HistoryInner::nextItem(Element *view) -> Element* {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (const auto result = view->nextDisplayedInBlocks()) {
|
} else if (const auto result = view->nextDisplayedInBlocks()) {
|
||||||
return result;
|
return result;
|
||||||
} else if (view->data()->history() == _migrated
|
} else if (view->history() == _migrated
|
||||||
&& _migrated->loadedAtBottom()
|
&& _migrated->loadedAtBottom()
|
||||||
&& _history->loadedAtTop()
|
&& _history->loadedAtTop()
|
||||||
&& !_history->isEmpty()) {
|
&& !_history->isEmpty()) {
|
||||||
|
@ -3730,9 +3730,9 @@ int HistoryInner::itemTop(const Element *view) const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto top = (view->data()->history() == _history)
|
auto top = (view->history() == _history)
|
||||||
? historyTop()
|
? historyTop()
|
||||||
: (view->data()->history() == _migrated
|
: (view->history() == _migrated
|
||||||
? migratedTop()
|
? migratedTop()
|
||||||
: -2);
|
: -2);
|
||||||
return (top < 0) ? top : (top + view->y() + view->block()->y());
|
return (top < 0) ? top : (top + view->y() + view->block()->y());
|
||||||
|
@ -4020,8 +4020,8 @@ void HistoryInner::applyDragSelection(
|
||||||
auto toblock = _dragSelTo->block()->indexInHistory();
|
auto toblock = _dragSelTo->block()->indexInHistory();
|
||||||
auto toitem = _dragSelTo->indexInBlock();
|
auto toitem = _dragSelTo->indexInBlock();
|
||||||
if (_migrated) {
|
if (_migrated) {
|
||||||
if (_dragSelFrom->data()->history() == _migrated) {
|
if (_dragSelFrom->history() == _migrated) {
|
||||||
if (_dragSelTo->data()->history() == _migrated) {
|
if (_dragSelTo->history() == _migrated) {
|
||||||
addSelectionRange(toItems, _migrated, fromblock, fromitem, toblock, toitem);
|
addSelectionRange(toItems, _migrated, fromblock, fromitem, toblock, toitem);
|
||||||
toblock = -1;
|
toblock = -1;
|
||||||
toitem = -1;
|
toitem = -1;
|
||||||
|
@ -4030,7 +4030,7 @@ void HistoryInner::applyDragSelection(
|
||||||
}
|
}
|
||||||
fromblock = 0;
|
fromblock = 0;
|
||||||
fromitem = 0;
|
fromitem = 0;
|
||||||
} else if (_dragSelTo->data()->history() == _migrated) { // wtf
|
} else if (_dragSelTo->history() == _migrated) { // wtf
|
||||||
toblock = -1;
|
toblock = -1;
|
||||||
toitem = -1;
|
toitem = -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6319,7 +6319,7 @@ void HistoryWidget::updatePinnedViewer() {
|
||||||
auto [view, offset] = _list->findViewForPinnedTracking(visibleBottom);
|
auto [view, offset] = _list->findViewForPinnedTracking(visibleBottom);
|
||||||
const auto lessThanId = !view
|
const auto lessThanId = !view
|
||||||
? (ServerMaxMsgId - 1)
|
? (ServerMaxMsgId - 1)
|
||||||
: (view->data()->history() != _history)
|
: (view->history() != _history)
|
||||||
? (view->data()->id + (offset > 0 ? 1 : 0) - ServerMaxMsgId)
|
? (view->data()->id + (offset > 0 ? 1 : 0) - ServerMaxMsgId)
|
||||||
: (view->data()->id + (offset > 0 ? 1 : 0));
|
: (view->data()->id + (offset > 0 ? 1 : 0));
|
||||||
const auto lastClickedId = !_pinnedClickedId
|
const auto lastClickedId = !_pinnedClickedId
|
||||||
|
|
|
@ -976,7 +976,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
||||||
const auto context = list->elementContext();
|
const auto context = list->elementContext();
|
||||||
AddPollActions(result, poll, item, context, list->controller());
|
AddPollActions(result, poll, item, context, list->controller());
|
||||||
} else if (!request.overSelection && view && !hasSelection) {
|
} else if (!request.overSelection && view && !hasSelection) {
|
||||||
const auto owner = &view->data()->history()->owner();
|
const auto owner = &view->history()->owner();
|
||||||
const auto media = view->media();
|
const auto media = view->media();
|
||||||
const auto mediaHasTextForCopy = media && media->hasTextForCopy();
|
const auto mediaHasTextForCopy = media && media->hasTextForCopy();
|
||||||
if (const auto document = media ? media->getDocument() : nullptr) {
|
if (const auto document = media ? media->getDocument() : nullptr) {
|
||||||
|
|
|
@ -579,9 +579,7 @@ void Element::refreshMedia(Element *replacing) {
|
||||||
&& Core::App().settings().largeEmoji()) {
|
&& Core::App().settings().largeEmoji()) {
|
||||||
_media = std::make_unique<UnwrappedMedia>(
|
_media = std::make_unique<UnwrappedMedia>(
|
||||||
this,
|
this,
|
||||||
std::make_unique<CustomEmoji>(
|
std::make_unique<CustomEmoji>(this, _data->onlyCustomEmoji()));
|
||||||
this,
|
|
||||||
_data->onlyCustomEmoji()));
|
|
||||||
} else if (_data->isIsolatedEmoji()
|
} else if (_data->isIsolatedEmoji()
|
||||||
&& Core::App().settings().largeEmoji()) {
|
&& Core::App().settings().largeEmoji()) {
|
||||||
const auto emoji = _data->isolatedEmoji();
|
const auto emoji = _data->isolatedEmoji();
|
||||||
|
|
|
@ -57,7 +57,7 @@ Call::Call(
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Call::countOptimalSize() {
|
QSize Call::countOptimalSize() {
|
||||||
const auto user = _parent->data()->history()->peer->asUser();
|
const auto user = _parent->history()->peer->asUser();
|
||||||
const auto video = _video;
|
const auto video = _video;
|
||||||
_link = std::make_shared<LambdaClickHandler>([=] {
|
_link = std::make_shared<LambdaClickHandler>([=] {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
|
@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "chat_helpers/stickers_emoji_pack.h"
|
||||||
#include "chat_helpers/stickers_lottie.h"
|
#include "chat_helpers/stickers_lottie.h"
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
#include "ui/text/text_isolated_emoji.h"
|
#include "ui/text/text_isolated_emoji.h"
|
||||||
|
@ -33,7 +35,7 @@ struct CustomEmojiSizeInfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] const base::flat_map<int, CustomEmojiSizeInfo> &SizesInfo() {
|
[[nodiscard]] const base::flat_map<int, CustomEmojiSizeInfo> &SizesInfo() {
|
||||||
// size = i->second.scale * st::maxAnimatedEmojiSize.
|
// size = i->second.scale * Sticker::EmojiSize().width()
|
||||||
// CustomEmojiManager::SizeTag caching uses first ::EmojiInteraction-s.
|
// CustomEmojiManager::SizeTag caching uses first ::EmojiInteraction-s.
|
||||||
using Info = CustomEmojiSizeInfo;
|
using Info = CustomEmojiSizeInfo;
|
||||||
static auto result = base::flat_map<int, Info>{
|
static auto result = base::flat_map<int, Info>{
|
||||||
|
@ -64,7 +66,7 @@ CustomEmoji::CustomEmoji(
|
||||||
: _parent(parent) {
|
: _parent(parent) {
|
||||||
Expects(!emoji.lines.empty());
|
Expects(!emoji.lines.empty());
|
||||||
|
|
||||||
const auto owner = &parent->data()->history()->owner();
|
const auto owner = &parent->history()->owner();
|
||||||
const auto manager = &owner->customEmojiManager();
|
const auto manager = &owner->customEmojiManager();
|
||||||
const auto max = ranges::max_element(
|
const auto max = ranges::max_element(
|
||||||
emoji.lines,
|
emoji.lines,
|
||||||
|
@ -76,7 +78,8 @@ CustomEmoji::CustomEmoji(
|
||||||
const auto useCustomEmoji = (i == end(sizes));
|
const auto useCustomEmoji = (i == end(sizes));
|
||||||
const auto tag = EmojiSize(dimension);
|
const auto tag = EmojiSize(dimension);
|
||||||
_singleSize = !useCustomEmoji
|
_singleSize = !useCustomEmoji
|
||||||
? int(base::SafeRound(i->second.scale * st::maxAnimatedEmojiSize))
|
? int(base::SafeRound(
|
||||||
|
i->second.scale * Sticker::EmojiSize().width()))
|
||||||
: Data::FrameSizeFromTag(tag);
|
: Data::FrameSizeFromTag(tag);
|
||||||
if (!useCustomEmoji) {
|
if (!useCustomEmoji) {
|
||||||
_cachingTag = i->second.tag;
|
_cachingTag = i->second.tag;
|
||||||
|
@ -95,13 +98,7 @@ CustomEmoji::CustomEmoji(
|
||||||
const auto id = Data::ParseCustomEmojiData(data).id;
|
const auto id = Data::ParseCustomEmojiData(data).id;
|
||||||
const auto document = owner->document(id);
|
const auto document = owner->document(id);
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
const auto skipPremiumEffect = false;
|
_lines.back().push_back(createStickerPart(document));
|
||||||
auto sticker = std::make_unique<Sticker>(
|
|
||||||
parent,
|
|
||||||
document,
|
|
||||||
skipPremiumEffect);
|
|
||||||
sticker->setCustomEmojiPart(_singleSize, _cachingTag);
|
|
||||||
_lines.back().push_back(std::move(sticker));
|
|
||||||
} else {
|
} else {
|
||||||
_lines.back().push_back(id);
|
_lines.back().push_back(id);
|
||||||
manager->resolve(id, listener());
|
manager->resolve(id, listener());
|
||||||
|
@ -118,13 +115,7 @@ void CustomEmoji::customEmojiResolveDone(not_null<DocumentData*> document) {
|
||||||
for (auto &line : _lines) {
|
for (auto &line : _lines) {
|
||||||
for (auto &entry : line) {
|
for (auto &entry : line) {
|
||||||
if (entry == id) {
|
if (entry == id) {
|
||||||
const auto skipPremiumEffect = false;
|
entry = createStickerPart(document);
|
||||||
auto sticker = std::make_unique<Sticker>(
|
|
||||||
_parent,
|
|
||||||
document,
|
|
||||||
skipPremiumEffect);
|
|
||||||
sticker->setCustomEmojiPart(_singleSize, _cachingTag);
|
|
||||||
entry = std::move(sticker);
|
|
||||||
} else if (v::is<DocumentId>(entry)) {
|
} else if (v::is<DocumentId>(entry)) {
|
||||||
_resolving = true;
|
_resolving = true;
|
||||||
}
|
}
|
||||||
|
@ -132,13 +123,60 @@ void CustomEmoji::customEmojiResolveDone(not_null<DocumentData*> document) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Sticker> CustomEmoji::createStickerPart(
|
||||||
|
not_null<DocumentData*> document) const {
|
||||||
|
const auto skipPremiumEffect = false;
|
||||||
|
auto result = std::make_unique<Sticker>(
|
||||||
|
_parent,
|
||||||
|
document,
|
||||||
|
skipPremiumEffect);
|
||||||
|
result->setCustomEmojiPart(_singleSize, _cachingTag);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomEmoji::refreshInteractionLink() {
|
||||||
|
if (_lines.size() != 1 || _lines.front().size() != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto &pack = _parent->history()->session().emojiStickersPack();
|
||||||
|
const auto version = pack.animationsVersion();
|
||||||
|
if (_animationsCheckVersion == version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_animationsCheckVersion = version;
|
||||||
|
if (pack.hasAnimationsFor(_parent->data())) {
|
||||||
|
const auto weak = base::make_weak(this);
|
||||||
|
_interactionLink = std::make_shared<LambdaClickHandler>([weak] {
|
||||||
|
if (const auto that = weak.get()) {
|
||||||
|
that->interactionLinkClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_interactionLink = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr CustomEmoji::link() {
|
||||||
|
refreshInteractionLink();
|
||||||
|
return _interactionLink;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomEmoji::interactionLinkClicked() {
|
||||||
|
const auto &entry = _lines.front().front();
|
||||||
|
if (const auto sticker = std::get_if<StickerPtr>(&entry)) {
|
||||||
|
if ((*sticker)->ready()) {
|
||||||
|
_parent->delegate()->elementStartInteraction(_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CustomEmoji::~CustomEmoji() {
|
CustomEmoji::~CustomEmoji() {
|
||||||
if (_hasHeavyPart) {
|
if (_hasHeavyPart) {
|
||||||
unloadHeavyPart();
|
unloadHeavyPart();
|
||||||
_parent->checkHeavyPart();
|
_parent->checkHeavyPart();
|
||||||
}
|
}
|
||||||
if (_resolving) {
|
if (_resolving) {
|
||||||
const auto owner = &_parent->data()->history()->owner();
|
const auto owner = &_parent->history()->owner();
|
||||||
owner->customEmojiManager().unregisterListener(listener());
|
owner->customEmojiManager().unregisterListener(listener());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "history/view/media/history_view_media_unwrapped.h"
|
#include "history/view/media/history_view_media_unwrapped.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
#include "base/weak_ptr.h"
|
||||||
|
|
||||||
namespace Ui::Text {
|
namespace Ui::Text {
|
||||||
struct OnlyCustomEmoji;
|
struct OnlyCustomEmoji;
|
||||||
|
@ -33,6 +34,7 @@ using LargeCustomEmoji = std::variant<
|
||||||
|
|
||||||
class CustomEmoji final
|
class CustomEmoji final
|
||||||
: public UnwrappedMedia::Content
|
: public UnwrappedMedia::Content
|
||||||
|
, public base::has_weak_ptr
|
||||||
, private Data::CustomEmojiManager::Listener {
|
, private Data::CustomEmojiManager::Listener {
|
||||||
public:
|
public:
|
||||||
CustomEmoji(
|
CustomEmoji(
|
||||||
|
@ -46,6 +48,7 @@ public:
|
||||||
Painter &p,
|
Painter &p,
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
const QRect &r) override;
|
const QRect &r) override;
|
||||||
|
ClickHandlerPtr link() override;
|
||||||
|
|
||||||
bool alwaysShowOutTimestamp() override {
|
bool alwaysShowOutTimestamp() override {
|
||||||
return true;
|
return true;
|
||||||
|
@ -58,9 +61,6 @@ public:
|
||||||
void unloadHeavyPart() override;
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] not_null<Data::CustomEmojiManager::Listener*> listener() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
void paintElement(
|
void paintElement(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
int x,
|
int x,
|
||||||
|
@ -83,12 +83,23 @@ private:
|
||||||
const PaintContext &context,
|
const PaintContext &context,
|
||||||
bool paused);
|
bool paused);
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<Data::CustomEmojiManager::Listener*> listener() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
void customEmojiResolveDone(not_null<DocumentData*> document) override;
|
void customEmojiResolveDone(not_null<DocumentData*> document) override;
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<Sticker> createStickerPart(
|
||||||
|
not_null<DocumentData*> document) const;
|
||||||
|
|
||||||
|
void refreshInteractionLink();
|
||||||
|
void interactionLinkClicked();
|
||||||
|
|
||||||
const not_null<Element*> _parent;
|
const not_null<Element*> _parent;
|
||||||
std::vector<std::vector<LargeCustomEmoji>> _lines;
|
std::vector<std::vector<LargeCustomEmoji>> _lines;
|
||||||
|
ClickHandlerPtr _interactionLink;
|
||||||
QImage _selectedFrame;
|
QImage _selectedFrame;
|
||||||
int _singleSize = 0;
|
int _singleSize = 0;
|
||||||
|
int _animationsCheckVersion = -1;
|
||||||
ChatHelpers::StickerLottieSize _cachingTag = {};
|
ChatHelpers::StickerLottieSize _cachingTag = {};
|
||||||
bool _hasHeavyPart = false;
|
bool _hasHeavyPart = false;
|
||||||
bool _resolving = false;
|
bool _resolving = false;
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace {
|
||||||
not_null<Element*> view,
|
not_null<Element*> view,
|
||||||
const QString &emoji,
|
const QString &emoji,
|
||||||
int value) {
|
int value) {
|
||||||
const auto &session = view->data()->history()->session();
|
const auto &session = view->history()->session();
|
||||||
return session.diceStickersPacks().lookup(emoji, value);
|
return session.diceStickersPacks().lookup(emoji, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ LargeEmoji::LargeEmoji(
|
||||||
const Ui::Text::IsolatedEmoji &emoji)
|
const Ui::Text::IsolatedEmoji &emoji)
|
||||||
: _parent(parent)
|
: _parent(parent)
|
||||||
, _images(ResolveImages(
|
, _images(ResolveImages(
|
||||||
&parent->data()->history()->session(),
|
&parent->history()->session(),
|
||||||
[=] { parent->customEmojiRepaint(); },
|
[=] { parent->customEmojiRepaint(); },
|
||||||
emoji)) {
|
emoji)) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ MediaGift::MediaGift(
|
||||||
height);
|
height);
|
||||||
|
|
||||||
const auto from = _gift->from();
|
const auto from = _gift->from();
|
||||||
const auto to = _parent->data()->history()->peer;
|
const auto to = _parent->history()->peer;
|
||||||
const auto months = _gift->months();
|
const auto months = _gift->months();
|
||||||
result.link = std::make_shared<LambdaClickHandler>([=](
|
result.link = std::make_shared<LambdaClickHandler>([=](
|
||||||
ClickContext context) {
|
ClickContext context) {
|
||||||
|
@ -225,7 +225,7 @@ void MediaGift::ensureStickerCreated() const {
|
||||||
if (_sticker) {
|
if (_sticker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto &session = _parent->data()->history()->session();
|
const auto &session = _parent->history()->session();
|
||||||
auto &packs = session.giftBoxStickersPacks();
|
auto &packs = session.giftBoxStickersPacks();
|
||||||
if (const auto document = packs.lookup(_gift->months())) {
|
if (const auto document = packs.lookup(_gift->months())) {
|
||||||
if (const auto sticker = document->sticker()) {
|
if (const auto sticker = document->sticker()) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ const auto &kEmoji = ::Stickers::DicePacks::kSlotString;
|
||||||
[[nodiscard]] DocumentData *Lookup(
|
[[nodiscard]] DocumentData *Lookup(
|
||||||
not_null<Element*> view,
|
not_null<Element*> view,
|
||||||
int value) {
|
int value) {
|
||||||
const auto &session = view->data()->history()->session();
|
const auto &session = view->history()->session();
|
||||||
return session.diceStickersPacks().lookup(kEmoji, value);
|
return session.diceStickersPacks().lookup(kEmoji, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,7 +310,7 @@ bool Sticker::readyToDrawAnimationFrame() {
|
||||||
if (!_player && loaded && !waitingForPremium && sticker->isAnimated()) {
|
if (!_player && loaded && !waitingForPremium && sticker->isAnimated()) {
|
||||||
setupPlayer();
|
setupPlayer();
|
||||||
}
|
}
|
||||||
return (_player && _player->ready());
|
return ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Sticker::Size() {
|
QSize Sticker::Size() {
|
||||||
|
@ -362,6 +362,10 @@ ClickHandlerPtr Sticker::link() {
|
||||||
return _link;
|
return _link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sticker::ready() const {
|
||||||
|
return _player && _player->ready();
|
||||||
|
}
|
||||||
|
|
||||||
DocumentData *Sticker::document() {
|
DocumentData *Sticker::document() {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
const QRect &r) override;
|
const QRect &r) override;
|
||||||
ClickHandlerPtr link() override;
|
ClickHandlerPtr link() override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool ready() const;
|
||||||
DocumentData *document() override;
|
DocumentData *document() override;
|
||||||
void stickerClearLoopPlayed() override;
|
void stickerClearLoopPlayed() override;
|
||||||
std::unique_ptr<StickerPlayer> stickerTakePlayer(
|
std::unique_ptr<StickerPlayer> stickerTakePlayer(
|
||||||
|
|
|
@ -218,7 +218,7 @@ struct ForwardedTooltip {
|
||||||
const auto phrase = tr::lng_forwarded(
|
const auto phrase = tr::lng_forwarded(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_user,
|
lt_user,
|
||||||
view->data()->history()->session().user()->name);
|
view->history()->session().user()->name);
|
||||||
const auto kReplacementPosition = QChar(0x0001);
|
const auto kReplacementPosition = QChar(0x0001);
|
||||||
const auto possiblePosition = tr::lng_forwarded(
|
const auto possiblePosition = tr::lng_forwarded(
|
||||||
tr::now,
|
tr::now,
|
||||||
|
|
Loading…
Add table
Reference in a new issue