mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 15:13:57 +02:00
Support colored emoji statuses.
This commit is contained in:
parent
923e725e18
commit
2d07539892
17 changed files with 224 additions and 56 deletions
|
@ -466,6 +466,8 @@ PRIVATE
|
||||||
data/data_download_manager.h
|
data/data_download_manager.h
|
||||||
data/data_drafts.cpp
|
data/data_drafts.cpp
|
||||||
data/data_drafts.h
|
data/data_drafts.h
|
||||||
|
data/data_emoji_statuses.cpp
|
||||||
|
data/data_emoji_statuses.h
|
||||||
data/data_folder.cpp
|
data/data_folder.cpp
|
||||||
data/data_folder.h
|
data/data_folder.h
|
||||||
data/data_file_click_handler.cpp
|
data/data_file_click_handler.cpp
|
||||||
|
|
|
@ -687,6 +687,9 @@ int PeerListRow::paintNameIconGetWidth(
|
||||||
? st::dialogsPremiumIconOver
|
? st::dialogsPremiumIconOver
|
||||||
: st::dialogsPremiumIcon),
|
: st::dialogsPremiumIcon),
|
||||||
.scam = &(selected ? st::dialogsScamFgOver : st::dialogsScamFg),
|
.scam = &(selected ? st::dialogsScamFgOver : st::dialogsScamFg),
|
||||||
|
.premiumFg = &(selected
|
||||||
|
? st::dialogsVerifiedIconBgOver
|
||||||
|
: st::dialogsVerifiedIconBg),
|
||||||
.preview = st::windowBgOver->c,
|
.preview = st::windowBgOver->c,
|
||||||
.customEmojiRepaint = repaint,
|
.customEmojiRepaint = repaint,
|
||||||
.now = now,
|
.now = now,
|
||||||
|
|
|
@ -435,6 +435,9 @@ EmojiListWidget::EmojiListWidget(
|
||||||
resizeToWidth(width());
|
resizeToWidth(width());
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
if (_mode == Mode::EmojiStatus) {
|
||||||
|
_emojiStatusColor = std::make_unique<Ui::Text::CustomEmojiColored>();
|
||||||
|
}
|
||||||
rpl::single(
|
rpl::single(
|
||||||
rpl::empty
|
rpl::empty
|
||||||
) | rpl::then(
|
) | rpl::then(
|
||||||
|
@ -443,6 +446,12 @@ EmojiListWidget::EmojiListWidget(
|
||||||
initButton(_add, tr::lng_stickers_featured_add(tr::now), false);
|
initButton(_add, tr::lng_stickers_featured_add(tr::now), false);
|
||||||
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
|
initButton(_unlock, tr::lng_emoji_featured_unlock(tr::now), true);
|
||||||
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
|
initButton(_restore, tr::lng_emoji_premium_restore(tr::now), true);
|
||||||
|
if (const auto status = _emojiStatusColor.get()) {
|
||||||
|
status->color = anim::color(
|
||||||
|
st::stickerPanPremium1,
|
||||||
|
st::stickerPanPremium2,
|
||||||
|
0.5);
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
if (!descriptor.customRecentList.empty()) {
|
if (!descriptor.customRecentList.empty()) {
|
||||||
|
@ -765,10 +774,11 @@ void EmojiListWidget::fillRecent() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
|
void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
|
||||||
Expects(_recent.empty());
|
|
||||||
|
|
||||||
const auto test = session().isTestMode();
|
const auto test = session().isTestMode();
|
||||||
|
const auto owner = &session().data();
|
||||||
|
const auto statuses = &owner->emojiStatuses();
|
||||||
|
const auto manager = &owner->customEmojiManager();
|
||||||
|
_recent.clear();
|
||||||
_recent.reserve(list.size());
|
_recent.reserve(list.size());
|
||||||
for (const auto &id : list) {
|
for (const auto &id : list) {
|
||||||
if (!id && _mode == Mode::EmojiStatus) {
|
if (!id && _mode == Mode::EmojiStatus) {
|
||||||
|
@ -777,7 +787,7 @@ void EmojiListWidget::fillRecentFrom(const std::vector<DocumentId> &list) {
|
||||||
} else {
|
} else {
|
||||||
_recent.push_back({
|
_recent.push_back({
|
||||||
.custom = resolveCustomRecent(id),
|
.custom = resolveCustomRecent(id),
|
||||||
.id = { RecentEmojiDocument{.id = id, .test = test } },
|
.id = { RecentEmojiDocument{ .id = id, .test = test } },
|
||||||
});
|
});
|
||||||
_recentCustomIds.emplace(id);
|
_recentCustomIds.emplace(id);
|
||||||
}
|
}
|
||||||
|
@ -963,7 +973,21 @@ void EmojiListWidget::drawRecent(
|
||||||
bool paused,
|
bool paused,
|
||||||
int index) {
|
int index) {
|
||||||
_recentPainted = true;
|
_recentPainted = true;
|
||||||
if (const auto emoji = std::get_if<EmojiPtr>(&_recent[index].id.data)) {
|
auto &recent = _recent[index];
|
||||||
|
if (const auto custom = recent.custom) {
|
||||||
|
position += _innerPosition + _customPosition;
|
||||||
|
const auto paintContext = Ui::Text::CustomEmoji::Context{
|
||||||
|
.preview = st::windowBgRipple->c,
|
||||||
|
.colored = _emojiStatusColor.get(),
|
||||||
|
.size = QSize(_customSingleSize, _customSingleSize),
|
||||||
|
.now = now,
|
||||||
|
.scale = context.progress,
|
||||||
|
.position = position,
|
||||||
|
.paused = paused,
|
||||||
|
.scaled = context.expanding,
|
||||||
|
};
|
||||||
|
custom->paint(p, paintContext);
|
||||||
|
} else if (const auto emoji = std::get_if<EmojiPtr>(&recent.id.data)) {
|
||||||
if (_mode == Mode::EmojiStatus) {
|
if (_mode == Mode::EmojiStatus) {
|
||||||
position += QPoint(
|
position += QPoint(
|
||||||
(_singleSize.width() - st::stickersPremium.width()) / 2,
|
(_singleSize.width() - st::stickersPremium.width()) / 2,
|
||||||
|
@ -973,18 +997,6 @@ void EmojiListWidget::drawRecent(
|
||||||
} else {
|
} else {
|
||||||
drawEmoji(p, context, position, *emoji);
|
drawEmoji(p, context, position, *emoji);
|
||||||
}
|
}
|
||||||
} else if (const auto custom = _recent[index].custom) {
|
|
||||||
position += _innerPosition + _customPosition;
|
|
||||||
const auto paintContext = Ui::Text::CustomEmoji::Context{
|
|
||||||
.preview = st::windowBgRipple->c,
|
|
||||||
.size = QSize(_customSingleSize, _customSingleSize),
|
|
||||||
.now = now,
|
|
||||||
.scale = context.progress,
|
|
||||||
.position = position,
|
|
||||||
.paused = paused,
|
|
||||||
.scaled = context.expanding,
|
|
||||||
};
|
|
||||||
custom->paint(p, paintContext);
|
|
||||||
} else {
|
} else {
|
||||||
Unexpected("Empty custom emoji in EmojiListWidget::drawRecent.");
|
Unexpected("Empty custom emoji in EmojiListWidget::drawRecent.");
|
||||||
}
|
}
|
||||||
|
@ -1013,9 +1025,12 @@ void EmojiListWidget::drawCustom(
|
||||||
int set,
|
int set,
|
||||||
int index) {
|
int index) {
|
||||||
position += _innerPosition + _customPosition;
|
position += _innerPosition + _customPosition;
|
||||||
_custom[set].painted = true;
|
auto &custom = _custom[set];
|
||||||
_custom[set].list[index].custom->paint(p, {
|
custom.painted = true;
|
||||||
|
auto &entry = custom.list[index];
|
||||||
|
entry.custom->paint(p, {
|
||||||
.preview = st::windowBgRipple->c,
|
.preview = st::windowBgRipple->c,
|
||||||
|
.colored = _emojiStatusColor.get(),
|
||||||
.size = QSize(_customSingleSize, _customSingleSize),
|
.size = QSize(_customSingleSize, _customSingleSize),
|
||||||
.now = now,
|
.now = now,
|
||||||
.scale = context.progress,
|
.scale = context.progress,
|
||||||
|
|
|
@ -37,6 +37,10 @@ namespace Ui::Emoji {
|
||||||
enum class Section;
|
enum class Section;
|
||||||
} // namespace Ui::Emoji
|
} // namespace Ui::Emoji
|
||||||
|
|
||||||
|
namespace Ui::Text {
|
||||||
|
struct CustomEmojiColored;
|
||||||
|
} // namespace Ui::Text
|
||||||
|
|
||||||
namespace Ui::CustomEmoji {
|
namespace Ui::CustomEmoji {
|
||||||
class Loader;
|
class Loader;
|
||||||
class Instance;
|
class Instance;
|
||||||
|
@ -294,6 +298,7 @@ private:
|
||||||
void displaySet(uint64 setId);
|
void displaySet(uint64 setId);
|
||||||
void removeSet(uint64 setId);
|
void removeSet(uint64 setId);
|
||||||
|
|
||||||
|
void refreshColoredStatuses();
|
||||||
void initButton(RightButton &button, const QString &text, bool gradient);
|
void initButton(RightButton &button, const QString &text, bool gradient);
|
||||||
[[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
|
[[nodiscard]] std::unique_ptr<Ui::RippleAnimation> createButtonRipple(
|
||||||
int section);
|
int section);
|
||||||
|
@ -328,6 +333,7 @@ private:
|
||||||
std::vector<RecentOne> _recent;
|
std::vector<RecentOne> _recent;
|
||||||
base::flat_set<DocumentId> _recentCustomIds;
|
base::flat_set<DocumentId> _recentCustomIds;
|
||||||
base::flat_set<uint64> _repaintsScheduled;
|
base::flat_set<uint64> _repaintsScheduled;
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmojiColored> _emojiStatusColor;
|
||||||
bool _recentPainted = false;
|
bool _recentPainted = false;
|
||||||
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
||||||
std::vector<CustomSet> _custom;
|
std::vector<CustomSet> _custom;
|
||||||
|
|
|
@ -6,10 +6,12 @@ For license and copyright information please follow this link:
|
||||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "data/data_emoji_statuses.h"
|
#include "data/data_emoji_statuses.h"
|
||||||
//
|
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "base/timer_rpl.h"
|
#include "base/timer_rpl.h"
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
|
|
||||||
#include "chat_helpers/stickers_emoji_pack.h"
|
#include "chat_helpers/stickers_emoji_pack.h"
|
||||||
|
#include "main/main_account.h"
|
||||||
|
#include "main/main_app_config.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
@ -78,7 +80,7 @@ public:
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride);
|
int sizeOverride);
|
||||||
|
|
||||||
[[nodiscard]] bool resolving() const;
|
[[nodiscard]] DocumentData *document() const;
|
||||||
void resolved(not_null<DocumentData*> document);
|
void resolved(not_null<DocumentData*> document);
|
||||||
|
|
||||||
QString entityData() override;
|
QString entityData() override;
|
||||||
|
@ -154,12 +156,16 @@ CustomEmojiLoader::CustomEmojiLoader(
|
||||||
&& sizeOverride <= std::numeric_limits<ushort>::max());
|
&& sizeOverride <= std::numeric_limits<ushort>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CustomEmojiLoader::resolving() const {
|
DocumentData *CustomEmojiLoader::document() const {
|
||||||
return v::is<Resolve>(_state);
|
return v::match(_state, [](const Resolve &) {
|
||||||
|
return (DocumentData*)nullptr;
|
||||||
|
}, [](const auto &data) {
|
||||||
|
return data.document.get();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CustomEmojiLoader::resolved(not_null<DocumentData*> document) {
|
void CustomEmojiLoader::resolved(not_null<DocumentData*> document) {
|
||||||
Expects(resolving());
|
Expects(v::is<Resolve>(_state));
|
||||||
|
|
||||||
auto requested = std::move(v::get<Resolve>(_state).requested);
|
auto requested = std::move(v::get<Resolve>(_state).requested);
|
||||||
_state = Lookup{ document };
|
_state = Lookup{ document };
|
||||||
|
@ -385,6 +391,22 @@ Ui::CustomEmoji::Preview CustomEmojiLoader::preview() {
|
||||||
CustomEmojiManager::CustomEmojiManager(not_null<Session*> owner)
|
CustomEmojiManager::CustomEmojiManager(not_null<Session*> owner)
|
||||||
: _owner(owner)
|
: _owner(owner)
|
||||||
, _repaintTimer([=] { invokeRepaints(); }) {
|
, _repaintTimer([=] { invokeRepaints(); }) {
|
||||||
|
const auto appConfig = &owner->session().account().appConfig();
|
||||||
|
appConfig->value(
|
||||||
|
) | rpl::take_while([=] {
|
||||||
|
return !_coloredSetId;
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
const auto setId = appConfig->get<QString>(
|
||||||
|
"default_emoji_statuses_stickerset_id",
|
||||||
|
QString()).toULongLong();
|
||||||
|
if (setId) {
|
||||||
|
_coloredSetId = setId;
|
||||||
|
auto pending = base::take(_coloredSetPending);
|
||||||
|
for (const auto &instance : pending[setId]) {
|
||||||
|
instance->setColored();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, _lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomEmojiManager::~CustomEmojiManager() = default;
|
CustomEmojiManager::~CustomEmojiManager() = default;
|
||||||
|
@ -405,12 +427,20 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
Ui::CustomEmoji::RepaintRequest request) {
|
||||||
repaintLater(instance, request);
|
repaintLater(instance, request);
|
||||||
};
|
};
|
||||||
|
auto [loader, setId] = factory();
|
||||||
i = instances.emplace(
|
i = instances.emplace(
|
||||||
documentId,
|
documentId,
|
||||||
std::make_unique<Ui::CustomEmoji::Instance>(Loading{
|
std::make_unique<Ui::CustomEmoji::Instance>(Loading{
|
||||||
factory(),
|
std::move(loader),
|
||||||
prepareNonExactPreview(documentId, tag, sizeOverride)
|
prepareNonExactPreview(documentId, tag, sizeOverride)
|
||||||
}, std::move(repaint))).first;
|
}, std::move(repaint))).first;
|
||||||
|
if (_coloredSetId) {
|
||||||
|
if (_coloredSetId == setId) {
|
||||||
|
i->second->setColored();
|
||||||
|
}
|
||||||
|
} else if (setId) {
|
||||||
|
_coloredSetPending[setId].emplace(i->second.get());
|
||||||
|
}
|
||||||
} else if (!i->second->hasImagePreview()) {
|
} else if (!i->second->hasImagePreview()) {
|
||||||
auto preview = prepareNonExactPreview(documentId, tag, sizeOverride);
|
auto preview = prepareNonExactPreview(documentId, tag, sizeOverride);
|
||||||
if (preview.isImage()) {
|
if (preview.isImage()) {
|
||||||
|
@ -466,7 +496,7 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride) {
|
int sizeOverride) {
|
||||||
return create(documentId, std::move(update), tag, sizeOverride, [&] {
|
return create(documentId, std::move(update), tag, sizeOverride, [&] {
|
||||||
return createLoader(documentId, tag, sizeOverride);
|
return createLoaderWithSetId(documentId, tag, sizeOverride);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,7 +506,7 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride) {
|
int sizeOverride) {
|
||||||
return create(document->id, std::move(update), tag, sizeOverride, [&] {
|
return create(document->id, std::move(update), tag, sizeOverride, [&] {
|
||||||
return createLoader(document, tag, sizeOverride);
|
return createLoaderWithSetId(document, tag, sizeOverride);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,19 +547,43 @@ std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride) {
|
int sizeOverride) {
|
||||||
return std::make_unique<CustomEmojiLoader>(document, tag, sizeOverride);
|
return createLoaderWithSetId(document, tag, sizeOverride).loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
DocumentId documentId,
|
DocumentId documentId,
|
||||||
SizeTag tag,
|
SizeTag tag,
|
||||||
int sizeOverride) {
|
int sizeOverride) {
|
||||||
|
return createLoaderWithSetId(documentId, tag, sizeOverride).loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CustomEmojiManager::createLoaderWithSetId(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
SizeTag tag,
|
||||||
|
int sizeOverride
|
||||||
|
) -> LoaderWithSetId {
|
||||||
|
const auto sticker = document->sticker();
|
||||||
|
return {
|
||||||
|
std::make_unique<CustomEmojiLoader>(document, tag, sizeOverride),
|
||||||
|
sticker ? sticker->set.id : uint64()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CustomEmojiManager::createLoaderWithSetId(
|
||||||
|
DocumentId documentId,
|
||||||
|
SizeTag tag,
|
||||||
|
int sizeOverride
|
||||||
|
) -> LoaderWithSetId {
|
||||||
auto result = std::make_unique<CustomEmojiLoader>(
|
auto result = std::make_unique<CustomEmojiLoader>(
|
||||||
_owner,
|
_owner,
|
||||||
CustomEmojiId{ .id = documentId },
|
CustomEmojiId{ .id = documentId },
|
||||||
tag,
|
tag,
|
||||||
sizeOverride);
|
sizeOverride);
|
||||||
if (result->resolving()) {
|
if (const auto document = result->document()) {
|
||||||
|
if (const auto sticker = document->sticker()) {
|
||||||
|
return { std::move(result), sticker->set.id };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const auto i = SizeIndex(tag);
|
const auto i = SizeIndex(tag);
|
||||||
_loaders[i][documentId].push_back(base::make_weak(result.get()));
|
_loaders[i][documentId].push_back(base::make_weak(result.get()));
|
||||||
_pendingForRequest.emplace(documentId);
|
_pendingForRequest.emplace(documentId);
|
||||||
|
@ -537,8 +591,7 @@ std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
crl::on_main(this, [=] { request(); });
|
crl::on_main(this, [=] { request(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return { std::move(result), uint64() };
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CustomEmojiManager::lookupSetName(uint64 setId) {
|
QString CustomEmojiManager::lookupSetName(uint64 setId) {
|
||||||
|
@ -564,27 +617,9 @@ void CustomEmojiManager::request() {
|
||||||
)).done([=](const MTPVector<MTPDocument> &result) {
|
)).done([=](const MTPVector<MTPDocument> &result) {
|
||||||
for (const auto &entry : result.v) {
|
for (const auto &entry : result.v) {
|
||||||
const auto document = _owner->processDocument(entry);
|
const auto document = _owner->processDocument(entry);
|
||||||
const auto id = document->id;
|
fillColoredFlags(document);
|
||||||
for (auto &loaders : _loaders) {
|
processLoaders(document);
|
||||||
if (const auto list = loaders.take(id)) {
|
processListeners(document);
|
||||||
for (const auto &weak : *list) {
|
|
||||||
if (const auto strong = weak.get()) {
|
|
||||||
strong->resolved(document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (const auto listeners = _resolvers.take(id)) {
|
|
||||||
for (const auto &listener : *listeners) {
|
|
||||||
const auto i = _listeners.find(listener);
|
|
||||||
if (i != end(_listeners) && i->second.remove(id)) {
|
|
||||||
if (i->second.empty()) {
|
|
||||||
_listeners.erase(i);
|
|
||||||
}
|
|
||||||
listener->customEmojiResolveDone(document);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requestSetFor(document);
|
requestSetFor(document);
|
||||||
}
|
}
|
||||||
requestFinished();
|
requestFinished();
|
||||||
|
@ -594,6 +629,53 @@ void CustomEmojiManager::request() {
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CustomEmojiManager::fillColoredFlags(not_null<DocumentData*> document) {
|
||||||
|
const auto id = document->id;
|
||||||
|
const auto sticker = document->sticker();
|
||||||
|
const auto setId = sticker ? sticker->set.id : uint64();
|
||||||
|
if (!setId || (_coloredSetId && setId != _coloredSetId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto &instances : _instances) {
|
||||||
|
const auto i = instances.find(id);
|
||||||
|
if (i != end(instances)) {
|
||||||
|
if (setId == _coloredSetId) {
|
||||||
|
i->second->setColored();
|
||||||
|
} else {
|
||||||
|
_coloredSetPending[setId].emplace(i->second.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomEmojiManager::processLoaders(not_null<DocumentData*> document) {
|
||||||
|
const auto id = document->id;
|
||||||
|
for (auto &loaders : _loaders) {
|
||||||
|
if (const auto list = loaders.take(id)) {
|
||||||
|
for (const auto &weak : *list) {
|
||||||
|
if (const auto strong = weak.get()) {
|
||||||
|
strong->resolved(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomEmojiManager::processListeners(not_null<DocumentData*> document) {
|
||||||
|
const auto id = document->id;
|
||||||
|
if (const auto listeners = _resolvers.take(id)) {
|
||||||
|
for (const auto &listener : *listeners) {
|
||||||
|
const auto i = _listeners.find(listener);
|
||||||
|
if (i != end(_listeners) && i->second.remove(id)) {
|
||||||
|
if (i->second.empty()) {
|
||||||
|
_listeners.erase(i);
|
||||||
|
}
|
||||||
|
listener->customEmojiResolveDone(document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CustomEmojiManager::requestSetFor(not_null<DocumentData*> document) {
|
void CustomEmojiManager::requestSetFor(not_null<DocumentData*> document) {
|
||||||
const auto sticker = document->sticker();
|
const auto sticker = document->sticker();
|
||||||
if (!sticker || !sticker->set.id) {
|
if (!sticker || !sticker->set.id) {
|
||||||
|
|
|
@ -84,6 +84,19 @@ private:
|
||||||
crl::time when = 0;
|
crl::time when = 0;
|
||||||
std::vector<base::weak_ptr<Ui::CustomEmoji::Instance>> instances;
|
std::vector<base::weak_ptr<Ui::CustomEmoji::Instance>> instances;
|
||||||
};
|
};
|
||||||
|
struct LoaderWithSetId {
|
||||||
|
std::unique_ptr<Ui::CustomEmoji::Loader> loader;
|
||||||
|
uint64 setId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] LoaderWithSetId createLoaderWithSetId(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
SizeTag tag,
|
||||||
|
int sizeOverride = 0);
|
||||||
|
[[nodiscard]] LoaderWithSetId createLoaderWithSetId(
|
||||||
|
DocumentId documentId,
|
||||||
|
SizeTag tag,
|
||||||
|
int sizeOverride = 0);
|
||||||
|
|
||||||
void request();
|
void request();
|
||||||
void requestFinished();
|
void requestFinished();
|
||||||
|
@ -92,6 +105,9 @@ private:
|
||||||
Ui::CustomEmoji::RepaintRequest request);
|
Ui::CustomEmoji::RepaintRequest request);
|
||||||
void scheduleRepaintTimer();
|
void scheduleRepaintTimer();
|
||||||
void invokeRepaints();
|
void invokeRepaints();
|
||||||
|
void fillColoredFlags(not_null<DocumentData*> document);
|
||||||
|
void processLoaders(not_null<DocumentData*> document);
|
||||||
|
void processListeners(not_null<DocumentData*> document);
|
||||||
void requestSetFor(not_null<DocumentData*> document);
|
void requestSetFor(not_null<DocumentData*> document);
|
||||||
|
|
||||||
[[nodiscard]] Ui::CustomEmoji::Preview prepareNonExactPreview(
|
[[nodiscard]] Ui::CustomEmoji::Preview prepareNonExactPreview(
|
||||||
|
@ -126,14 +142,23 @@ private:
|
||||||
not_null<Listener*>,
|
not_null<Listener*>,
|
||||||
base::flat_set<DocumentId>> _listeners;
|
base::flat_set<DocumentId>> _listeners;
|
||||||
base::flat_set<DocumentId> _pendingForRequest;
|
base::flat_set<DocumentId> _pendingForRequest;
|
||||||
|
base::flat_map<
|
||||||
|
uint64,
|
||||||
|
base::flat_set<
|
||||||
|
not_null<Ui::CustomEmoji::Instance*>>> _coloredSetPending;
|
||||||
|
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
|
|
||||||
|
uint64 _coloredSetId = 0;
|
||||||
|
|
||||||
base::flat_map<crl::time, RepaintBunch> _repaints;
|
base::flat_map<crl::time, RepaintBunch> _repaints;
|
||||||
crl::time _repaintNext = 0;
|
crl::time _repaintNext = 0;
|
||||||
base::Timer _repaintTimer;
|
base::Timer _repaintTimer;
|
||||||
bool _repaintTimerScheduled = false;
|
bool _repaintTimerScheduled = false;
|
||||||
bool _requestSetsScheduled = false;
|
bool _requestSetsScheduled = false;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] int FrameSizeFromTag(CustomEmojiManager::SizeTag tag);
|
[[nodiscard]] int FrameSizeFromTag(CustomEmojiManager::SizeTag tag);
|
||||||
|
|
|
@ -828,6 +828,11 @@ void InnerWidget::paintPeerSearchResult(
|
||||||
: selected
|
: selected
|
||||||
? &st::dialogsScamFgOver
|
? &st::dialogsScamFgOver
|
||||||
: &st::dialogsScamFg),
|
: &st::dialogsScamFg),
|
||||||
|
.premiumFg = (active
|
||||||
|
? &st::dialogsVerifiedIconBgActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsVerifiedIconBgOver
|
||||||
|
: &st::dialogsVerifiedIconBg),
|
||||||
.preview = (active
|
.preview = (active
|
||||||
? st::dialogsScamFgActive
|
? st::dialogsScamFgActive
|
||||||
: selected
|
: selected
|
||||||
|
|
|
@ -593,6 +593,11 @@ void paintRow(
|
||||||
: selected
|
: selected
|
||||||
? &st::dialogsScamFgOver
|
? &st::dialogsScamFgOver
|
||||||
: &st::dialogsScamFg),
|
: &st::dialogsScamFg),
|
||||||
|
.premiumFg = (active
|
||||||
|
? &st::dialogsVerifiedIconBgActive
|
||||||
|
: selected
|
||||||
|
? &st::dialogsVerifiedIconBgOver
|
||||||
|
: &st::dialogsVerifiedIconBg),
|
||||||
.preview = (active
|
.preview = (active
|
||||||
? st::dialogsScamFgActive
|
? st::dialogsScamFgActive
|
||||||
: selected
|
: selected
|
||||||
|
|
|
@ -545,6 +545,7 @@ void TopBarWidget::paintTopBar(Painter &p) {
|
||||||
.verified = &st::dialogsVerifiedIcon,
|
.verified = &st::dialogsVerifiedIcon,
|
||||||
.premium = &st::dialogsPremiumIcon,
|
.premium = &st::dialogsPremiumIcon,
|
||||||
.scam = &st::attentionButtonFg,
|
.scam = &st::attentionButtonFg,
|
||||||
|
.premiumFg = &st::dialogsVerifiedIconBg,
|
||||||
.preview = st::windowBgOver->c,
|
.preview = st::windowBgOver->c,
|
||||||
.customEmojiRepaint = [=] { update(); },
|
.customEmojiRepaint = [=] { update(); },
|
||||||
.now = now,
|
.now = now,
|
||||||
|
|
|
@ -23,6 +23,7 @@ InfoToggle {
|
||||||
InfoPeerBadge {
|
InfoPeerBadge {
|
||||||
verified: icon;
|
verified: icon;
|
||||||
premium: icon;
|
premium: icon;
|
||||||
|
premiumFg: color;
|
||||||
position: point;
|
position: point;
|
||||||
sizeTag: int;
|
sizeTag: int;
|
||||||
}
|
}
|
||||||
|
@ -316,6 +317,7 @@ infoPremiumStar: icon {{ "profile_premium", profileVerifiedCheckBg }};
|
||||||
infoPeerBadge: InfoPeerBadge {
|
infoPeerBadge: InfoPeerBadge {
|
||||||
verified: infoVerifiedCheck;
|
verified: infoVerifiedCheck;
|
||||||
premium: infoPremiumStar;
|
premium: infoPremiumStar;
|
||||||
|
premiumFg: profileVerifiedCheckBg;
|
||||||
position: infoVerifiedCheckPosition;
|
position: infoVerifiedCheckPosition;
|
||||||
sizeTag: 1; // Large
|
sizeTag: 1; // Large
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,7 @@ void BadgeView::setBadge(Badge badge, DocumentId emojiStatusId) {
|
||||||
_badge = badge;
|
_badge = badge;
|
||||||
_emojiStatusId = emojiStatusId;
|
_emojiStatusId = emojiStatusId;
|
||||||
_emojiStatus = nullptr;
|
_emojiStatus = nullptr;
|
||||||
|
_emojiStatusColored = nullptr;
|
||||||
_view.destroy();
|
_view.destroy();
|
||||||
if (_badge == Badge::None) {
|
if (_badge == Badge::None) {
|
||||||
_updated.fire({});
|
_updated.fire({});
|
||||||
|
@ -143,14 +144,19 @@ void BadgeView::setBadge(Badge badge, DocumentId emojiStatusId) {
|
||||||
_emojiStatusId,
|
_emojiStatusId,
|
||||||
[raw = _view.data()] { raw->update(); },
|
[raw = _view.data()] { raw->update(); },
|
||||||
tag);
|
tag);
|
||||||
|
_emojiStatusColored = std::make_unique<
|
||||||
|
Ui::Text::CustomEmojiColored
|
||||||
|
>();
|
||||||
const auto emoji = Data::FrameSizeFromTag(tag)
|
const auto emoji = Data::FrameSizeFromTag(tag)
|
||||||
/ style::DevicePixelRatio();
|
/ style::DevicePixelRatio();
|
||||||
_view->resize(emoji, emoji);
|
_view->resize(emoji, emoji);
|
||||||
_view->paintRequest(
|
_view->paintRequest(
|
||||||
) | rpl::start_with_next([=, check = _view.data()]{
|
) | rpl::start_with_next([=, check = _view.data()]{
|
||||||
Painter p(check);
|
Painter p(check);
|
||||||
|
_emojiStatusColored->color = _st.premiumFg->c;
|
||||||
_emojiStatus->paint(p, {
|
_emojiStatus->paint(p, {
|
||||||
.preview = st::windowBgOver->c,
|
.preview = st::windowBgOver->c,
|
||||||
|
.colored = _emojiStatusColored.get(),
|
||||||
.now = crl::now(),
|
.now = crl::now(),
|
||||||
.paused = _animationPaused && _animationPaused(),
|
.paused = _animationPaused && _animationPaused(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,6 +33,10 @@ template <typename Widget>
|
||||||
class SlideWrap;
|
class SlideWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Ui::Text {
|
||||||
|
struct CustomEmojiColored;
|
||||||
|
} // namespace Ui::Text
|
||||||
|
|
||||||
namespace Info {
|
namespace Info {
|
||||||
class Controller;
|
class Controller;
|
||||||
class Section;
|
class Section;
|
||||||
|
@ -73,6 +77,7 @@ private:
|
||||||
const not_null<PeerData*> _peer;
|
const not_null<PeerData*> _peer;
|
||||||
DocumentId _emojiStatusId = 0;
|
DocumentId _emojiStatusId = 0;
|
||||||
std::unique_ptr<Ui::Text::CustomEmoji> _emojiStatus;
|
std::unique_ptr<Ui::Text::CustomEmoji> _emojiStatus;
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmojiColored> _emojiStatusColored;
|
||||||
base::flags<Badge> _allowed;
|
base::flags<Badge> _allowed;
|
||||||
Badge _badge = Badge();
|
Badge _badge = Badge();
|
||||||
Fn<void()> _premiumClickCallback;
|
Fn<void()> _premiumClickCallback;
|
||||||
|
|
|
@ -186,6 +186,7 @@ settingsInfoNameSkip: -1px;
|
||||||
settingsInfoUploadLeft: 6px;
|
settingsInfoUploadLeft: 6px;
|
||||||
settingsInfoPeerBadge: InfoPeerBadge {
|
settingsInfoPeerBadge: InfoPeerBadge {
|
||||||
premium: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
|
premium: icon {{ "dialogs/dialogs_premium", dialogsVerifiedIconBg }};
|
||||||
|
premiumFg: dialogsVerifiedIconBg;
|
||||||
sizeTag: 0; // Normal
|
sizeTag: 0; // Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,9 +169,12 @@ int PeerBadge::drawGetWidth(
|
||||||
}
|
}
|
||||||
if (!_emojiStatus) {
|
if (!_emojiStatus) {
|
||||||
_emojiStatus = std::make_unique<EmojiStatus>();
|
_emojiStatus = std::make_unique<EmojiStatus>();
|
||||||
const auto size = st::emojiSize * 1.;
|
const auto size = st::emojiSize;
|
||||||
const auto emoji = Ui::Text::AdjustCustomEmojiSize(st::emojiSize);
|
const auto emoji = Ui::Text::AdjustCustomEmojiSize(size);
|
||||||
_emojiStatus->skip = (st::emojiSize - emoji) / 2;
|
_emojiStatus->skip = (size - emoji) / 2;
|
||||||
|
_emojiStatus->colored = std::make_unique<
|
||||||
|
Ui::Text::CustomEmojiColored
|
||||||
|
>();
|
||||||
}
|
}
|
||||||
if (_emojiStatus->id != id) {
|
if (_emojiStatus->id != id) {
|
||||||
auto &manager = peer->session().data().customEmojiManager();
|
auto &manager = peer->session().data().customEmojiManager();
|
||||||
|
@ -180,8 +183,10 @@ int PeerBadge::drawGetWidth(
|
||||||
id,
|
id,
|
||||||
descriptor.customEmojiRepaint);
|
descriptor.customEmojiRepaint);
|
||||||
}
|
}
|
||||||
|
_emojiStatus->colored->color = (*descriptor.premiumFg)->c;
|
||||||
_emojiStatus->emoji->paint(p, {
|
_emojiStatus->emoji->paint(p, {
|
||||||
.preview = descriptor.preview,
|
.preview = descriptor.preview,
|
||||||
|
.colored = _emojiStatus->colored.get(),
|
||||||
.now = descriptor.now,
|
.now = descriptor.now,
|
||||||
.position = QPoint(
|
.position = QPoint(
|
||||||
iconx - 2 * _emojiStatus->skip,
|
iconx - 2 * _emojiStatus->skip,
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Ui::Text {
|
namespace Ui::Text {
|
||||||
class CustomEmoji;
|
class CustomEmoji;
|
||||||
|
struct CustomEmojiColored;
|
||||||
} // namespace Ui::Text
|
} // namespace Ui::Text
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
@ -41,6 +42,7 @@ public:
|
||||||
const style::icon *verified = nullptr;
|
const style::icon *verified = nullptr;
|
||||||
const style::icon *premium = nullptr;
|
const style::icon *premium = nullptr;
|
||||||
const style::color *scam = nullptr;
|
const style::color *scam = nullptr;
|
||||||
|
const style::color *premiumFg = nullptr;
|
||||||
QColor preview;
|
QColor preview;
|
||||||
Fn<void()> customEmojiRepaint;
|
Fn<void()> customEmojiRepaint;
|
||||||
crl::time now = 0;
|
crl::time now = 0;
|
||||||
|
@ -58,6 +60,7 @@ private:
|
||||||
struct EmojiStatus {
|
struct EmojiStatus {
|
||||||
DocumentId id = 0;
|
DocumentId id = 0;
|
||||||
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
|
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmojiColored> colored;
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
};
|
};
|
||||||
std::unique_ptr<EmojiStatus> _emojiStatus;
|
std::unique_ptr<EmojiStatus> _emojiStatus;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 6dc6309269beb64a69e3184b671e030a2969f00e
|
Subproject commit 51657b3c8a643c9ca2721029fd48f63390417042
|
Loading…
Add table
Reference in a new issue