mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Reuse SizeTag::Large emoji instances.
This commit is contained in:
parent
076d5c756a
commit
c51837cfdf
9 changed files with 178 additions and 354 deletions
|
@ -156,13 +156,12 @@ protected:
|
||||||
void leaveEventHook(QEvent *e) override;
|
void leaveEventHook(QEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using CustomInstance = Ui::CustomEmoji::SeparateInstance;
|
|
||||||
struct Element {
|
struct Element {
|
||||||
not_null<DocumentData*> document;
|
not_null<DocumentData*> document;
|
||||||
std::shared_ptr<Data::DocumentMedia> documentMedia;
|
std::shared_ptr<Data::DocumentMedia> documentMedia;
|
||||||
Lottie::Animation *lottie = nullptr;
|
Lottie::Animation *lottie = nullptr;
|
||||||
Media::Clip::ReaderPointer webm;
|
Media::Clip::ReaderPointer webm;
|
||||||
CustomInstance *emoji = nullptr;
|
Ui::Text::CustomEmoji *emoji = nullptr;
|
||||||
Ui::Animations::Simple overAnimation;
|
Ui::Animations::Simple overAnimation;
|
||||||
|
|
||||||
mutable QImage premiumLock;
|
mutable QImage premiumLock;
|
||||||
|
@ -185,7 +184,7 @@ private:
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
int index);
|
int index);
|
||||||
void setupEmoji(int index);
|
void setupEmoji(int index);
|
||||||
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
void customEmojiRepaint();
|
void customEmojiRepaint();
|
||||||
|
|
||||||
|
@ -213,8 +212,7 @@ private:
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
not_null<DocumentData*>,
|
not_null<DocumentData*>,
|
||||||
std::unique_ptr<CustomInstance>> _instances;
|
std::unique_ptr<Ui::Text::CustomEmoji>> _customEmoji;
|
||||||
std::unique_ptr<Ui::CustomEmoji::SimpleManager> _manager;
|
|
||||||
bool _repaintScheduled = false;
|
bool _repaintScheduled = false;
|
||||||
|
|
||||||
StickersPack _pack;
|
StickersPack _pack;
|
||||||
|
@ -515,7 +513,6 @@ StickerSetBox::Inner::Inner(
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _api(&_controller->session().mtp())
|
, _api(&_controller->session().mtp())
|
||||||
, _manager(std::make_unique<Ui::CustomEmoji::SimpleManager>())
|
|
||||||
, _setId(set.id)
|
, _setId(set.id)
|
||||||
, _setAccessHash(set.accessHash)
|
, _setAccessHash(set.accessHash)
|
||||||
, _setShortName(set.shortName)
|
, _setShortName(set.shortName)
|
||||||
|
@ -1098,24 +1095,22 @@ void StickerSetBox::Inner::clipCallback(
|
||||||
|
|
||||||
void StickerSetBox::Inner::setupEmoji(int index) {
|
void StickerSetBox::Inner::setupEmoji(int index) {
|
||||||
auto &element = _elements[index];
|
auto &element = _elements[index];
|
||||||
element.emoji = resolveCustomInstance(element.document);
|
element.emoji = resolveCustomEmoji(element.document);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto StickerSetBox::Inner::resolveCustomInstance(
|
not_null<Ui::Text::CustomEmoji*> StickerSetBox::Inner::resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document)
|
not_null<DocumentData*> document) {
|
||||||
-> not_null<CustomInstance*> {
|
const auto i = _customEmoji.find(document);
|
||||||
const auto i = _instances.find(document);
|
if (i != end(_customEmoji)) {
|
||||||
if (i != end(_instances)) {
|
|
||||||
return i->second.get();
|
return i->second.get();
|
||||||
}
|
}
|
||||||
auto instance = _manager->make(
|
auto emoji = document->session().data().customEmojiManager().create(
|
||||||
_controller->session().data().customEmojiManager().createLoader(
|
|
||||||
document,
|
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
|
||||||
[=] { customEmojiRepaint(); });
|
|
||||||
return _instances.emplace(
|
|
||||||
document,
|
document,
|
||||||
std::move(instance)
|
[=] { customEmojiRepaint(); },
|
||||||
|
Data::CustomEmojiManager::SizeTag::Large);
|
||||||
|
return _customEmoji.emplace(
|
||||||
|
document,
|
||||||
|
std::move(emoji)
|
||||||
).first->second.get();
|
).first->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1167,7 +1162,7 @@ void StickerSetBox::Inner::paintSticker(
|
||||||
(_singleSize.height() - size.height()) / 2);
|
(_singleSize.height() - size.height()) / 2);
|
||||||
auto lottieFrame = QImage();
|
auto lottieFrame = QImage();
|
||||||
if (element.emoji) {
|
if (element.emoji) {
|
||||||
element.emoji->object.paint(
|
element.emoji->paint(
|
||||||
p,
|
p,
|
||||||
ppos.x(),
|
ppos.x(),
|
||||||
ppos.y(),
|
ppos.y(),
|
||||||
|
|
|
@ -100,14 +100,13 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmojiListWidget::CustomInstance : Ui::CustomEmoji::SeparateInstance {
|
struct EmojiListWidget::CustomEmojiInstance {
|
||||||
using SeparateInstance::SeparateInstance;
|
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
|
||||||
|
|
||||||
bool recentOnly = false;
|
bool recentOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmojiListWidget::RecentOne {
|
struct EmojiListWidget::RecentOne {
|
||||||
CustomInstance *instance = nullptr;
|
Ui::Text::CustomEmoji *custom = nullptr;
|
||||||
RecentEmojiId id;
|
RecentEmojiId id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -371,8 +370,7 @@ EmojiListWidget::EmojiListWidget(
|
||||||
std::make_unique<LocalStickersManager>(&controller->session()))
|
std::make_unique<LocalStickersManager>(&controller->session()))
|
||||||
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
|
, _collapsedBg(st::emojiPanExpand.height / 2, st::emojiPanHeaderFg)
|
||||||
, _picker(this)
|
, _picker(this)
|
||||||
, _showPickerTimer([=] { showPicker(); })
|
, _showPickerTimer([=] { showPicker(); }) {
|
||||||
, _repaintTimer([=] { invokeRepaints(); }) {
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
@ -419,88 +417,20 @@ EmojiListWidget::EmojiListWidget(
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiListWidget::~EmojiListWidget() {
|
EmojiListWidget::~EmojiListWidget() {
|
||||||
base::take(_instances);
|
base::take(_customEmoji);
|
||||||
base::take(_repaints);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::repaintLater(
|
void EmojiListWidget::repaintCustom(uint64 setId) {
|
||||||
DocumentId documentId,
|
if (!_repaintsScheduled.emplace(setId).second) {
|
||||||
uint64 setId,
|
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
|
||||||
if (_instances.empty() || !request.when) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &repaint = _repaints[request.duration];
|
const auto repaintRecent = (setId == RecentEmojiSectionSetId());
|
||||||
if (repaint.when < request.when) {
|
|
||||||
repaint.when = request.when;
|
|
||||||
}
|
|
||||||
if (setId) {
|
|
||||||
repaint.ids.emplace(setId);
|
|
||||||
}
|
|
||||||
if (_recentCustomIds.contains(documentId)) {
|
|
||||||
repaint.ids.emplace(RecentEmojiSectionSetId());
|
|
||||||
}
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiListWidget::scheduleRepaintTimer() {
|
|
||||||
if (_repaintTimerScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_repaintTimerScheduled = true;
|
|
||||||
Ui::PostponeCall(this, [=] {
|
|
||||||
_repaintTimerScheduled = false;
|
|
||||||
|
|
||||||
auto next = crl::time();
|
|
||||||
for (const auto &[duration, bunch] : _repaints) {
|
|
||||||
if (!next || next > bunch.when) {
|
|
||||||
next = bunch.when;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (next && (!_repaintNext || _repaintNext > next)) {
|
|
||||||
const auto now = crl::now();
|
|
||||||
if (now >= next) {
|
|
||||||
_repaintNext = 0;
|
|
||||||
_repaintTimer.cancel();
|
|
||||||
invokeRepaints();
|
|
||||||
} else {
|
|
||||||
_repaintNext = next;
|
|
||||||
_repaintTimer.callOnce(next - now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiListWidget::invokeRepaints() {
|
|
||||||
_repaintNext = 0;
|
|
||||||
auto ids = base::flat_set<uint64>();
|
|
||||||
const auto now = crl::now();
|
|
||||||
for (auto i = begin(_repaints); i != end(_repaints);) {
|
|
||||||
if (i->second.when > now) {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ids.empty()) {
|
|
||||||
ids = std::move(i->second.ids);
|
|
||||||
} else {
|
|
||||||
for (const auto id : i->second.ids) {
|
|
||||||
ids.emplace(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = _repaints.erase(i);
|
|
||||||
}
|
|
||||||
repaintCustom([&](uint64 id) { return ids.contains(id); });
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename CheckId>
|
|
||||||
void EmojiListWidget::repaintCustom(CheckId checkId) {
|
|
||||||
enumerateSections([&](const SectionInfo &info) {
|
enumerateSections([&](const SectionInfo &info) {
|
||||||
const auto repaint1 = (info.section == int(Section::Recent))
|
const auto repaint1 = repaintRecent
|
||||||
&& checkId(RecentEmojiSectionSetId());
|
&& (info.section == int(Section::Recent));
|
||||||
const auto repaint2 = !repaint1
|
const auto repaint2 = !repaint1
|
||||||
&& (info.section >= kEmojiSectionCount)
|
&& (info.section >= kEmojiSectionCount)
|
||||||
&& checkId(_custom[info.section - kEmojiSectionCount].id);
|
&& (setId == _custom[info.section - kEmojiSectionCount].id);
|
||||||
if (repaint1 || repaint2) {
|
if (repaint1 || repaint2) {
|
||||||
update(
|
update(
|
||||||
0,
|
0,
|
||||||
|
@ -555,8 +485,8 @@ void EmojiListWidget::unloadCustomIn(const SectionInfo &info) {
|
||||||
if (!info.section && _recentPainted) {
|
if (!info.section && _recentPainted) {
|
||||||
_recentPainted = false;
|
_recentPainted = false;
|
||||||
for (const auto &single : _recent) {
|
for (const auto &single : _recent) {
|
||||||
if (const auto instance = single.instance) {
|
if (const auto custom = single.custom) {
|
||||||
instance->object.unload();
|
custom->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -569,7 +499,7 @@ void EmojiListWidget::unloadCustomIn(const SectionInfo &info) {
|
||||||
}
|
}
|
||||||
custom.painted = false;
|
custom.painted = false;
|
||||||
for (const auto &single : custom.list) {
|
for (const auto &single : custom.list) {
|
||||||
single.instance->object.unload();
|
single.custom->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,7 +672,7 @@ void EmojiListWidget::fillRecent() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
_recent.push_back({
|
_recent.push_back({
|
||||||
.instance = resolveCustomInstance(one.id),
|
.custom = resolveCustomEmoji(one.id),
|
||||||
.id = one.id,
|
.id = one.id,
|
||||||
});
|
});
|
||||||
if (document) {
|
if (document) {
|
||||||
|
@ -756,7 +686,10 @@ void EmojiListWidget::fillRecent() {
|
||||||
|
|
||||||
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
QRect r = e ? e->rect() : rect();
|
|
||||||
|
_repaintsScheduled.clear();
|
||||||
|
|
||||||
|
const auto r = e ? e->rect() : rect();
|
||||||
if (r != rect()) {
|
if (r != rect()) {
|
||||||
p.setClipRect(r);
|
p.setClipRect(r);
|
||||||
}
|
}
|
||||||
|
@ -897,9 +830,9 @@ void EmojiListWidget::drawRecent(
|
||||||
if (const auto emoji = std::get_if<EmojiPtr>(&_recent[index].id.data)) {
|
if (const auto emoji = std::get_if<EmojiPtr>(&_recent[index].id.data)) {
|
||||||
drawEmoji(p, position, *emoji);
|
drawEmoji(p, position, *emoji);
|
||||||
} else {
|
} else {
|
||||||
Assert(_recent[index].instance != nullptr);
|
Assert(_recent[index].custom != nullptr);
|
||||||
position += _innerPosition;
|
position += _innerPosition;
|
||||||
_recent[index].instance->object.paint(
|
_recent[index].custom->paint(
|
||||||
p,
|
p,
|
||||||
position.x(),
|
position.x(),
|
||||||
position.y(),
|
position.y(),
|
||||||
|
@ -931,7 +864,7 @@ void EmojiListWidget::drawCustom(
|
||||||
int index) {
|
int index) {
|
||||||
position += _innerPosition;
|
position += _innerPosition;
|
||||||
_custom[set].painted = true;
|
_custom[set].painted = true;
|
||||||
_custom[set].list[index].instance->object.paint(
|
_custom[set].list[index].custom->paint(
|
||||||
p,
|
p,
|
||||||
position.x(),
|
position.x(),
|
||||||
position.y(),
|
position.y(),
|
||||||
|
@ -1408,7 +1341,7 @@ void EmojiListWidget::refreshCustom() {
|
||||||
for (const auto document : list) {
|
for (const auto document : list) {
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
set.push_back({
|
set.push_back({
|
||||||
.instance = resolveCustomInstance(document, setId),
|
.custom = resolveCustomEmoji(document, setId),
|
||||||
.document = document,
|
.document = document,
|
||||||
});
|
});
|
||||||
if (!premium && document->isPremiumEmoji()) {
|
if (!premium && document->isPremiumEmoji()) {
|
||||||
|
@ -1443,98 +1376,75 @@ void EmojiListWidget::refreshCustom() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiListWidget::customInstanceWithLoader(
|
Fn<void()> EmojiListWidget::repaintCallback(
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
DocumentId documentId,
|
||||||
DocumentId documentId,
|
uint64 setId) {
|
||||||
uint64 setId)
|
return [=] {
|
||||||
-> std::unique_ptr<CustomInstance> {
|
repaintCustom(setId);
|
||||||
const auto recentOnly = (setId == RecentEmojiSectionSetId());
|
|
||||||
const auto repaintDelayedSetId = !recentOnly ? setId : uint64(0);
|
|
||||||
const auto repaintDelayed = [=](
|
|
||||||
not_null<Ui::CustomEmoji::Instance*> instance,
|
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
|
||||||
repaintLater(documentId, repaintDelayedSetId, request);
|
|
||||||
};
|
|
||||||
const auto repaintNow = [=] {
|
|
||||||
if (_recentCustomIds.contains(documentId)) {
|
if (_recentCustomIds.contains(documentId)) {
|
||||||
const auto recentSetId = RecentEmojiSectionSetId();
|
repaintCustom(RecentEmojiSectionSetId());
|
||||||
repaintCustom([&](uint64 id) {
|
|
||||||
return (id == setId) || (id == recentSetId);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
repaintCustom([&](uint64 id) {
|
|
||||||
return (id == setId);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto result = std::make_unique<CustomInstance>(
|
|
||||||
std::move(loader),
|
|
||||||
std::move(repaintDelayed),
|
|
||||||
std::move(repaintNow));
|
|
||||||
result->recentOnly = recentOnly;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiListWidget::resolveCustomInstance(
|
not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
uint64 setId)
|
uint64 setId) {
|
||||||
-> not_null<CustomInstance*> {
|
|
||||||
Expects(document->sticker() != nullptr);
|
Expects(document->sticker() != nullptr);
|
||||||
|
|
||||||
const auto documentId = document->id;
|
const auto documentId = document->id;
|
||||||
const auto i = _instances.find(documentId);
|
const auto i = _customEmoji.find(documentId);
|
||||||
const auto recentOnly = (i != end(_instances)) && i->second->recentOnly;
|
const auto recentOnly = (i != end(_customEmoji)) && i->second.recentOnly;
|
||||||
if (i != end(_instances) && !recentOnly) {
|
if (i != end(_customEmoji) && !recentOnly) {
|
||||||
return i->second.get();
|
return i->second.emoji.get();
|
||||||
}
|
}
|
||||||
auto instance = customInstanceWithLoader(
|
auto instance = document->owner().customEmojiManager().create(
|
||||||
document->owner().customEmojiManager().createLoader(
|
document,
|
||||||
document,
|
repaintCallback(documentId, setId),
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
Data::CustomEmojiManager::SizeTag::Large);
|
||||||
documentId,
|
|
||||||
setId);
|
|
||||||
if (recentOnly) {
|
if (recentOnly) {
|
||||||
for (auto &recent : _recent) {
|
for (auto &recent : _recent) {
|
||||||
if (recent.instance && recent.instance == i->second.get()) {
|
if (recent.custom && recent.custom == i->second.emoji.get()) {
|
||||||
recent.instance = instance.get();
|
recent.custom = instance.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i->second = std::move(instance);
|
i->second.emoji = std::move(instance);
|
||||||
return i->second.get();
|
i->second.recentOnly = false;
|
||||||
|
return i->second.emoji.get();
|
||||||
}
|
}
|
||||||
return _instances.emplace(
|
return _customEmoji.emplace(
|
||||||
documentId,
|
documentId,
|
||||||
std::move(instance)).first->second.get();
|
CustomEmojiInstance{ .emoji = std::move(instance) }
|
||||||
|
).first->second.emoji.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiListWidget::resolveCustomInstance(
|
Ui::Text::CustomEmoji *EmojiListWidget::resolveCustomEmoji(
|
||||||
RecentEmojiId customId)
|
RecentEmojiId customId) {
|
||||||
-> CustomInstance* {
|
|
||||||
const auto &data = customId.data;
|
const auto &data = customId.data;
|
||||||
if (const auto document = std::get_if<RecentEmojiDocument>(&data)) {
|
if (const auto document = std::get_if<RecentEmojiDocument>(&data)) {
|
||||||
return resolveCustomInstance(document->id);
|
return resolveCustomEmoji(document->id);
|
||||||
} else if (const auto emoji = std::get_if<EmojiPtr>(&data)) {
|
} else if (const auto emoji = std::get_if<EmojiPtr>(&data)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Unexpected("Custom recent emoji id.");
|
Unexpected("Custom recent emoji id.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiListWidget::resolveCustomInstance(
|
not_null<Ui::Text::CustomEmoji*> EmojiListWidget::resolveCustomEmoji(
|
||||||
DocumentId documentId)
|
DocumentId documentId) {
|
||||||
-> not_null<CustomInstance*> {
|
const auto i = _customEmoji.find(documentId);
|
||||||
const auto i = _instances.find(documentId);
|
if (i != end(_customEmoji)) {
|
||||||
if (i != end(_instances)) {
|
return i->second.emoji.get();
|
||||||
return i->second.get();
|
|
||||||
}
|
}
|
||||||
return _instances.emplace(
|
return _customEmoji.emplace(
|
||||||
documentId,
|
documentId,
|
||||||
customInstanceWithLoader(
|
CustomEmojiInstance{
|
||||||
session().data().customEmojiManager().createLoader(
|
.emoji = session().data().customEmojiManager().create(
|
||||||
documentId,
|
documentId,
|
||||||
|
repaintCallback(documentId, RecentEmojiSectionSetId()),
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
Data::CustomEmojiManager::SizeTag::Large),
|
||||||
documentId,
|
.recentOnly = true,
|
||||||
RecentEmojiSectionSetId())
|
}
|
||||||
).first->second.get();
|
).first->second.emoji.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
||||||
|
|
|
@ -112,9 +112,8 @@ private:
|
||||||
bool premiumRequired = false;
|
bool premiumRequired = false;
|
||||||
bool collapsed = false;
|
bool collapsed = false;
|
||||||
};
|
};
|
||||||
struct CustomInstance;
|
|
||||||
struct CustomOne {
|
struct CustomOne {
|
||||||
not_null<CustomInstance*> instance;
|
not_null<Ui::Text::CustomEmoji*> custom;
|
||||||
not_null<DocumentData*> document;
|
not_null<DocumentData*> document;
|
||||||
};
|
};
|
||||||
struct CustomSet {
|
struct CustomSet {
|
||||||
|
@ -129,6 +128,7 @@ private:
|
||||||
bool canRemove = false;
|
bool canRemove = false;
|
||||||
bool premiumRequired = false;
|
bool premiumRequired = false;
|
||||||
};
|
};
|
||||||
|
struct CustomEmojiInstance;
|
||||||
struct RightButton {
|
struct RightButton {
|
||||||
QImage back;
|
QImage back;
|
||||||
QImage backOver;
|
QImage backOver;
|
||||||
|
@ -137,10 +137,6 @@ private:
|
||||||
int textWidth = 0;
|
int textWidth = 0;
|
||||||
};
|
};
|
||||||
struct RecentOne;
|
struct RecentOne;
|
||||||
struct RepaintSet {
|
|
||||||
base::flat_set<uint64> ids;
|
|
||||||
crl::time when = 0;
|
|
||||||
};
|
|
||||||
struct OverEmoji {
|
struct OverEmoji {
|
||||||
int section = 0;
|
int section = 0;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -253,25 +249,17 @@ private:
|
||||||
int section);
|
int section);
|
||||||
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
||||||
|
|
||||||
void repaintLater(
|
void repaintCustom(uint64 setId);
|
||||||
DocumentId documentId,
|
|
||||||
uint64 setId,
|
|
||||||
Ui::CustomEmoji::RepaintRequest request);
|
|
||||||
template <typename CheckId>
|
|
||||||
void repaintCustom(CheckId checkId);
|
|
||||||
void scheduleRepaintTimer();
|
|
||||||
void invokeRepaints();
|
|
||||||
|
|
||||||
void fillRecent();
|
void fillRecent();
|
||||||
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
uint64 setId);
|
uint64 setId);
|
||||||
[[nodiscard]] CustomInstance *resolveCustomInstance(
|
[[nodiscard]] Ui::Text::CustomEmoji *resolveCustomEmoji(
|
||||||
Core::RecentEmojiId customId);
|
Core::RecentEmojiId customId);
|
||||||
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||||
DocumentId documentId);
|
DocumentId documentId);
|
||||||
[[nodiscard]] std::unique_ptr<CustomInstance> customInstanceWithLoader(
|
[[nodiscard]] Fn<void()> repaintCallback(
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
|
||||||
DocumentId documentId,
|
DocumentId documentId,
|
||||||
uint64 setId);
|
uint64 setId);
|
||||||
|
|
||||||
|
@ -281,10 +269,11 @@ private:
|
||||||
int _counts[kEmojiSectionCount];
|
int _counts[kEmojiSectionCount];
|
||||||
std::vector<RecentOne> _recent;
|
std::vector<RecentOne> _recent;
|
||||||
base::flat_set<DocumentId> _recentCustomIds;
|
base::flat_set<DocumentId> _recentCustomIds;
|
||||||
|
base::flat_set<uint64> _repaintsScheduled;
|
||||||
bool _recentPainted = false;
|
bool _recentPainted = false;
|
||||||
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
||||||
std::vector<CustomSet> _custom;
|
std::vector<CustomSet> _custom;
|
||||||
base::flat_map<DocumentId, std::unique_ptr<CustomInstance>> _instances;
|
base::flat_map<DocumentId, CustomEmojiInstance> _customEmoji;
|
||||||
|
|
||||||
int _rowsLeft = 0;
|
int _rowsLeft = 0;
|
||||||
int _columnCount = 1;
|
int _columnCount = 1;
|
||||||
|
@ -305,11 +294,6 @@ private:
|
||||||
object_ptr<EmojiColorPicker> _picker;
|
object_ptr<EmojiColorPicker> _picker;
|
||||||
base::Timer _showPickerTimer;
|
base::Timer _showPickerTimer;
|
||||||
|
|
||||||
base::flat_map<crl::time, RepaintSet> _repaints;
|
|
||||||
bool _repaintTimerScheduled = false;
|
|
||||||
base::Timer _repaintTimer;
|
|
||||||
crl::time _repaintNext = 0;
|
|
||||||
|
|
||||||
rpl::event_stream<EmojiPtr> _chosen;
|
rpl::event_stream<EmojiPtr> _chosen;
|
||||||
rpl::event_stream<TabbedSelector::FileChosen> _customChosen;
|
rpl::event_stream<TabbedSelector::FileChosen> _customChosen;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,6 @@ SuggestionsWidget::SuggestionsWidget(
|
||||||
not_null<Main::Session*> session)
|
not_null<Main::Session*> session)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _session(session)
|
, _session(session)
|
||||||
, _manager(std::make_unique<Ui::CustomEmoji::SimpleManager>())
|
|
||||||
, _oneWidth(st::emojiSuggestionSize)
|
, _oneWidth(st::emojiSuggestionSize)
|
||||||
, _padding(st::emojiSuggestionsPadding) {
|
, _padding(st::emojiSuggestionsPadding) {
|
||||||
resize(
|
resize(
|
||||||
|
@ -141,7 +140,7 @@ auto SuggestionsWidget::prependCustom(std::vector<Row> rows)
|
||||||
for (const auto &[position, one] : custom) {
|
for (const auto &[position, one] : custom) {
|
||||||
result.push_back(Row(one.emoji, one.replacement));
|
result.push_back(Row(one.emoji, one.replacement));
|
||||||
result.back().document = one.document;
|
result.back().document = one.document;
|
||||||
result.back().instance = resolveCustomInstance(one.document);
|
result.back().custom = resolveCustomEmoji(one.document);
|
||||||
}
|
}
|
||||||
for (auto &row : rows) {
|
for (auto &row : rows) {
|
||||||
result.push_back(std::move(row));
|
result.push_back(std::move(row));
|
||||||
|
@ -149,21 +148,19 @@ auto SuggestionsWidget::prependCustom(std::vector<Row> rows)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuggestionsWidget::resolveCustomInstance(
|
not_null<Ui::Text::CustomEmoji*> SuggestionsWidget::resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document)
|
not_null<DocumentData*> document) {
|
||||||
-> not_null<CustomInstance*> {
|
const auto i = _customEmoji.find(document);
|
||||||
const auto i = _instances.find(document);
|
if (i != end(_customEmoji)) {
|
||||||
if (i != end(_instances)) {
|
|
||||||
return i->second.get();
|
return i->second.get();
|
||||||
}
|
}
|
||||||
auto instance = _manager->make(
|
auto emoji = document->session().data().customEmojiManager().create(
|
||||||
_session->data().customEmojiManager().createLoader(
|
|
||||||
document,
|
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
|
||||||
[=] { customEmojiRepaint(); });
|
|
||||||
return _instances.emplace(
|
|
||||||
document,
|
document,
|
||||||
std::move(instance)
|
[=] { customEmojiRepaint(); },
|
||||||
|
Data::CustomEmojiManager::SizeTag::Large);
|
||||||
|
return _customEmoji.emplace(
|
||||||
|
document,
|
||||||
|
std::move(emoji)
|
||||||
).first->second.get();
|
).first->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,8 +330,8 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto size = esize / style::DevicePixelRatio();
|
const auto size = esize / style::DevicePixelRatio();
|
||||||
const auto x = i * _oneWidth + (_oneWidth - size) / 2;
|
const auto x = i * _oneWidth + (_oneWidth - size) / 2;
|
||||||
const auto y = (_oneWidth - size) / 2;
|
const auto y = (_oneWidth - size) / 2;
|
||||||
if (row.instance) {
|
if (row.custom) {
|
||||||
row.instance->object.paint(p, x, y, now, preview, false);
|
row.custom->paint(p, x, y, now, preview, false);
|
||||||
} else {
|
} else {
|
||||||
Ui::Emoji::Draw(p, emoji, esize, x, y);
|
Ui::Emoji::Draw(p, emoji, esize, x, y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,9 @@ class InnerDropdown;
|
||||||
class InputField;
|
class InputField;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Ui::CustomEmoji {
|
namespace Ui::Text {
|
||||||
struct SeparateInstance;
|
class CustomEmoji;
|
||||||
class SimpleManager;
|
} // namespace Ui::Text
|
||||||
} // namespace Ui::CustomEmoji
|
|
||||||
|
|
||||||
namespace Ui::Emoji {
|
namespace Ui::Emoji {
|
||||||
|
|
||||||
|
@ -48,11 +47,10 @@ public:
|
||||||
[[nodiscard]] rpl::producer<Chosen> triggered() const;
|
[[nodiscard]] rpl::producer<Chosen> triggered() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using CustomInstance = Ui::CustomEmoji::SeparateInstance;
|
|
||||||
struct Row {
|
struct Row {
|
||||||
Row(not_null<EmojiPtr> emoji, const QString &replacement);
|
Row(not_null<EmojiPtr> emoji, const QString &replacement);
|
||||||
|
|
||||||
CustomInstance *instance = nullptr;
|
Ui::Text::CustomEmoji *custom = nullptr;
|
||||||
DocumentData *document = nullptr;
|
DocumentData *document = nullptr;
|
||||||
not_null<EmojiPtr> emoji;
|
not_null<EmojiPtr> emoji;
|
||||||
QString replacement;
|
QString replacement;
|
||||||
|
@ -92,7 +90,7 @@ private:
|
||||||
void scrollTo(int value, anim::type animated = anim::type::instant);
|
void scrollTo(int value, anim::type animated = anim::type::instant);
|
||||||
void stopAnimations();
|
void stopAnimations();
|
||||||
|
|
||||||
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
[[nodiscard]] not_null<Ui::Text::CustomEmoji*> resolveCustomEmoji(
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
void customEmojiRepaint();
|
void customEmojiRepaint();
|
||||||
|
|
||||||
|
@ -102,8 +100,7 @@ private:
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
not_null<DocumentData*>,
|
not_null<DocumentData*>,
|
||||||
std::unique_ptr<CustomInstance>> _instances;
|
std::unique_ptr<Ui::Text::CustomEmoji>> _customEmoji;
|
||||||
std::unique_ptr<Ui::CustomEmoji::SimpleManager> _manager;
|
|
||||||
bool _repaintScheduled = false;
|
bool _repaintScheduled = false;
|
||||||
|
|
||||||
std::optional<QPoint> _lastMousePosition;
|
std::optional<QPoint> _lastMousePosition;
|
||||||
|
|
|
@ -361,35 +361,59 @@ CustomEmojiManager::CustomEmojiManager(not_null<Session*> owner)
|
||||||
|
|
||||||
CustomEmojiManager::~CustomEmojiManager() = default;
|
CustomEmojiManager::~CustomEmojiManager() = default;
|
||||||
|
|
||||||
|
template <typename LoaderFactory>
|
||||||
std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
QStringView data,
|
DocumentId documentId,
|
||||||
Fn<void()> update) {
|
Fn<void()> update,
|
||||||
const auto parsed = ParseCustomEmojiData(data);
|
SizeTag tag,
|
||||||
if (!parsed.id) {
|
LoaderFactory factory) {
|
||||||
return nullptr;
|
auto &instances = _instances[SizeIndex(tag)];
|
||||||
}
|
auto i = instances.find(documentId);
|
||||||
auto i = _instances.find(parsed.id);
|
if (i == end(instances)) {
|
||||||
if (i == end(_instances)) {
|
|
||||||
using Loading = Ui::CustomEmoji::Loading;
|
using Loading = Ui::CustomEmoji::Loading;
|
||||||
auto loader = createLoader(parsed.id, SizeTag::Normal);
|
|
||||||
const auto repaint = [=](
|
const auto repaint = [=](
|
||||||
not_null<Ui::CustomEmoji::Instance*> instance,
|
not_null<Ui::CustomEmoji::Instance*> instance,
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
Ui::CustomEmoji::RepaintRequest request) {
|
||||||
repaintLater(instance, request);
|
repaintLater(instance, request);
|
||||||
};
|
};
|
||||||
i = _instances.emplace(
|
i = instances.emplace(
|
||||||
parsed.id,
|
documentId,
|
||||||
std::make_unique<Ui::CustomEmoji::Instance>(Loading{
|
std::make_unique<Ui::CustomEmoji::Instance>(Loading{
|
||||||
std::move(loader),
|
factory(),
|
||||||
Ui::CustomEmoji::Preview()
|
Ui::CustomEmoji::Preview()
|
||||||
}, std::move(repaint))).first;
|
}, std::move(repaint))).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_unique<Ui::CustomEmoji::Object>(
|
return std::make_unique<Ui::CustomEmoji::Object>(
|
||||||
i->second.get(),
|
i->second.get(),
|
||||||
std::move(update));
|
std::move(update));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
|
QStringView data,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag) {
|
||||||
|
const auto parsed = ParseCustomEmojiData(data);
|
||||||
|
return parsed.id ? create(parsed.id, std::move(update), tag) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
|
DocumentId documentId,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag) {
|
||||||
|
return create(documentId, std::move(update), tag, [&] {
|
||||||
|
return createLoader(documentId, tag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag) {
|
||||||
|
return create(document->id, std::move(update), tag, [&] {
|
||||||
|
return createLoader(document, tag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
SizeTag tag) {
|
SizeTag tag) {
|
||||||
|
@ -405,7 +429,8 @@ std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
CustomEmojiId{ .selfId = selfId, .id = documentId },
|
CustomEmojiId{ .selfId = selfId, .id = documentId },
|
||||||
tag);
|
tag);
|
||||||
if (result->resolving()) {
|
if (result->resolving()) {
|
||||||
_loaders[documentId].push_back(base::make_weak(result.get()));
|
const auto i = SizeIndex(tag);
|
||||||
|
_loaders[i][documentId].push_back(base::make_weak(result.get()));
|
||||||
_pendingForRequest.emplace(documentId);
|
_pendingForRequest.emplace(documentId);
|
||||||
if (!_requestId && _pendingForRequest.size() == 1) {
|
if (!_requestId && _pendingForRequest.size() == 1) {
|
||||||
crl::on_main(this, [=] { request(); });
|
crl::on_main(this, [=] { request(); });
|
||||||
|
@ -439,10 +464,12 @@ void CustomEmojiManager::request() {
|
||||||
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;
|
const auto id = document->id;
|
||||||
if (const auto loaders = _loaders.take(id)) {
|
for (auto &loaders : _loaders) {
|
||||||
for (const auto &weak : *loaders) {
|
if (const auto list = loaders.take(id)) {
|
||||||
if (const auto strong = weak.get()) {
|
for (const auto &weak : *list) {
|
||||||
strong->resolved(document);
|
if (const auto strong = weak.get()) {
|
||||||
|
strong->resolved(document);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,6 +506,13 @@ void CustomEmojiManager::requestSetFor(not_null<DocumentData*> document) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CustomEmojiManager::SizeIndex(SizeTag tag) {
|
||||||
|
const auto result = static_cast<int>(tag);
|
||||||
|
|
||||||
|
Ensures(result >= 0 && result < 2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CustomEmojiManager::requestFinished() {
|
void CustomEmojiManager::requestFinished() {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
if (!_pendingForRequest.empty()) {
|
if (!_pendingForRequest.empty()) {
|
||||||
|
|
|
@ -40,7 +40,16 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
|
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
|
||||||
QStringView data,
|
QStringView data,
|
||||||
Fn<void()> update);
|
Fn<void()> update,
|
||||||
|
SizeTag tag = SizeTag::Normal);
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
|
||||||
|
DocumentId documentId,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag = SizeTag::Normal);
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag = SizeTag::Normal);
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
|
@ -69,14 +78,22 @@ private:
|
||||||
void invokeRepaints();
|
void invokeRepaints();
|
||||||
void requestSetFor(not_null<DocumentData*> document);
|
void requestSetFor(not_null<DocumentData*> document);
|
||||||
|
|
||||||
|
template <typename LoaderFactory>
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::Text::CustomEmoji> create(
|
||||||
|
DocumentId documentId,
|
||||||
|
Fn<void()> update,
|
||||||
|
SizeTag tag,
|
||||||
|
LoaderFactory factory);
|
||||||
|
[[nodiscard]] static int SizeIndex(SizeTag tag);
|
||||||
|
|
||||||
const not_null<Session*> _owner;
|
const not_null<Session*> _owner;
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
uint64,
|
uint64,
|
||||||
std::unique_ptr<Ui::CustomEmoji::Instance>> _instances;
|
std::unique_ptr<Ui::CustomEmoji::Instance>> _instances[2];
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
uint64,
|
uint64,
|
||||||
std::vector<base::weak_ptr<CustomEmojiLoader>>> _loaders;
|
std::vector<base::weak_ptr<CustomEmojiLoader>>> _loaders[2];
|
||||||
base::flat_set<uint64> _pendingForRequest;
|
base::flat_set<uint64> _pendingForRequest;
|
||||||
mtpRequestId _requestId = 0;
|
mtpRequestId _requestId = 0;
|
||||||
|
|
||||||
|
|
|
@ -648,84 +648,4 @@ void Object::repaint() {
|
||||||
_repaint();
|
_repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
SeparateInstance::SeparateInstance(
|
|
||||||
std::unique_ptr<Loader> loader,
|
|
||||||
Fn<void(not_null<Instance*>, RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint)
|
|
||||||
: emoji(Loading(std::move(loader), Preview()), std::move(repaintLater))
|
|
||||||
, object(&emoji, std::move(repaint)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SimpleManager::SimpleManager()
|
|
||||||
: _repaintTimer([=] { invokeRepaints(); }) {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<SeparateInstance> SimpleManager::make(
|
|
||||||
std::unique_ptr<Loader> loader,
|
|
||||||
Fn<void()> repaint) {
|
|
||||||
auto repaintLater = [=](
|
|
||||||
not_null<Instance*> instance,
|
|
||||||
RepaintRequest request) {
|
|
||||||
if (!request.when) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &when = _repaints[request.duration];
|
|
||||||
if (when < request.when) {
|
|
||||||
when = request.when;
|
|
||||||
}
|
|
||||||
if (_repaintTimerScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
};
|
|
||||||
_simpleRepaint = repaint;
|
|
||||||
return std::make_unique<SeparateInstance>(
|
|
||||||
std::move(loader),
|
|
||||||
std::move(repaintLater),
|
|
||||||
std::move(repaint));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleManager::scheduleRepaintTimer() {
|
|
||||||
_repaintTimerScheduled = true;
|
|
||||||
Ui::PostponeCall(this, [=] {
|
|
||||||
_repaintTimerScheduled = false;
|
|
||||||
|
|
||||||
auto next = crl::time();
|
|
||||||
for (const auto &[duration, when] : _repaints) {
|
|
||||||
if (!next || next > when) {
|
|
||||||
next = when;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (next && (!_repaintNext || _repaintNext > next)) {
|
|
||||||
const auto now = crl::now();
|
|
||||||
if (now >= next) {
|
|
||||||
_repaintNext = 0;
|
|
||||||
_repaintTimer.cancel();
|
|
||||||
invokeRepaints();
|
|
||||||
} else {
|
|
||||||
_repaintNext = next;
|
|
||||||
_repaintTimer.callOnce(next - now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleManager::invokeRepaints() {
|
|
||||||
_repaintNext = 0;
|
|
||||||
auto invoke = false;
|
|
||||||
const auto now = crl::now();
|
|
||||||
for (auto i = begin(_repaints); i != end(_repaints);) {
|
|
||||||
if (i->second > now) {
|
|
||||||
++i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
invoke = true;
|
|
||||||
i = _repaints.erase(i);
|
|
||||||
}
|
|
||||||
if (invoke && _simpleRepaint) {
|
|
||||||
_simpleRepaint();
|
|
||||||
}
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Ui::CustomEmoji
|
} // namespace Ui::CustomEmoji
|
||||||
|
|
|
@ -267,34 +267,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SeparateInstance {
|
|
||||||
SeparateInstance(
|
|
||||||
std::unique_ptr<Loader> loader,
|
|
||||||
Fn<void(not_null<Instance*>, RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint);
|
|
||||||
|
|
||||||
Instance emoji;
|
|
||||||
Object object;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SimpleManager final : public base::has_weak_ptr {
|
|
||||||
public:
|
|
||||||
SimpleManager();
|
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<SeparateInstance> make(
|
|
||||||
std::unique_ptr<Loader> loader,
|
|
||||||
Fn<void()> repaint);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void scheduleRepaintTimer();
|
|
||||||
void invokeRepaints();
|
|
||||||
|
|
||||||
base::flat_map<crl::time, crl::time> _repaints;
|
|
||||||
bool _repaintTimerScheduled = false;
|
|
||||||
crl::time _repaintNext = 0;
|
|
||||||
base::Timer _repaintTimer;
|
|
||||||
Fn<void()> _simpleRepaint;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Ui::CustomEmoji
|
} // namespace Ui::CustomEmoji
|
||||||
|
|
Loading…
Add table
Reference in a new issue