mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support mixed custom / default recent emoji.
This commit is contained in:
parent
c0ec3a23bb
commit
44a7d11e4a
10 changed files with 401 additions and 117 deletions
|
@ -201,7 +201,7 @@ private:
|
||||||
uint64 _setId = 0;
|
uint64 _setId = 0;
|
||||||
uint64 _setAccessHash = 0;
|
uint64 _setAccessHash = 0;
|
||||||
uint64 _setHash = 0;
|
uint64 _setHash = 0;
|
||||||
uint64 _setThumbnailDocumentId = 0;
|
DocumentId _setThumbnailDocumentId = 0;
|
||||||
QString _setTitle, _setShortName;
|
QString _setTitle, _setShortName;
|
||||||
int _setCount = 0;
|
int _setCount = 0;
|
||||||
Data::StickersSetFlags _setFlags;
|
Data::StickersSetFlags _setFlags;
|
||||||
|
|
|
@ -34,6 +34,81 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
|
||||||
namespace ChatHelpers {
|
namespace ChatHelpers {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kFakeEmojiDocumentIdBase = 0x7777'FFFF'FFFF'0000ULL;
|
||||||
|
|
||||||
|
[[nodiscard]] DocumentId FakeEmojiDocumentId(EmojiPtr emoji) {
|
||||||
|
return kFakeEmojiDocumentIdBase + emoji->index();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultEmojiLoader final : public Ui::CustomEmoji::Loader {
|
||||||
|
public:
|
||||||
|
DefaultEmojiLoader(EmojiPtr emoji, int size);
|
||||||
|
|
||||||
|
QString entityData() override;
|
||||||
|
|
||||||
|
void load(Fn<void(LoadResult)> loaded) override;
|
||||||
|
bool loading() override;
|
||||||
|
void cancel() override;
|
||||||
|
Ui::CustomEmoji::Preview preview() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void validateImage();
|
||||||
|
|
||||||
|
EmojiPtr _emoji = nullptr;
|
||||||
|
QImage _image;
|
||||||
|
int _size = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultEmojiLoader::DefaultEmojiLoader(EmojiPtr emoji, int size)
|
||||||
|
: _emoji(emoji)
|
||||||
|
, _size(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultEmojiLoader::load(Fn<void(LoadResult)> loaded) {
|
||||||
|
validateImage();
|
||||||
|
const auto data = entityData();
|
||||||
|
const auto unloader = [emoji = _emoji, size = _size] {
|
||||||
|
return std::make_unique<DefaultEmojiLoader>(emoji, size);
|
||||||
|
};
|
||||||
|
auto cache = Ui::CustomEmoji::Cache(_size);
|
||||||
|
cache.add(0, _image);
|
||||||
|
cache.finish();
|
||||||
|
loaded(Ui::CustomEmoji::Cached(data, unloader, std::move(cache)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultEmojiLoader::validateImage() {
|
||||||
|
if (!_image.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_image = QImage(
|
||||||
|
{ _size, _size },
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
_image.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
_image.fill(Qt::transparent);
|
||||||
|
QPainter p(&_image);
|
||||||
|
Ui::Emoji::Draw(p, _emoji, _size, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DefaultEmojiLoader::entityData() {
|
||||||
|
return "default-emoji://" + _emoji->id();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultEmojiLoader::loading() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultEmojiLoader::cancel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::CustomEmoji::Preview DefaultEmojiLoader::preview() {
|
||||||
|
validateImage();
|
||||||
|
return { _image };
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
class EmojiColorPicker : public Ui::RpWidget {
|
class EmojiColorPicker : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -92,10 +167,12 @@ struct EmojiListWidget::CustomInstance {
|
||||||
Fn<void(
|
Fn<void(
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
not_null<Ui::CustomEmoji::Instance*>,
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
||||||
Fn<void()> repaint);
|
Fn<void()> repaint,
|
||||||
|
bool recentOnly = false);
|
||||||
|
|
||||||
Ui::CustomEmoji::Instance emoji;
|
Ui::CustomEmoji::Instance emoji;
|
||||||
Ui::CustomEmoji::Object object;
|
Ui::CustomEmoji::Object object;
|
||||||
|
bool recentOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
EmojiListWidget::CustomInstance::CustomInstance(
|
EmojiListWidget::CustomInstance::CustomInstance(
|
||||||
|
@ -103,11 +180,13 @@ EmojiListWidget::CustomInstance::CustomInstance(
|
||||||
Fn<void(
|
Fn<void(
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
not_null<Ui::CustomEmoji::Instance*>,
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
||||||
Fn<void()> repaint)
|
Fn<void()> repaint,
|
||||||
|
bool recentOnly)
|
||||||
: emoji(
|
: emoji(
|
||||||
Ui::CustomEmoji::Loading(std::move(loader), Ui::CustomEmoji::Preview()),
|
Ui::CustomEmoji::Loading(std::move(loader), Ui::CustomEmoji::Preview()),
|
||||||
std::move(repaintLater))
|
std::move(repaintLater))
|
||||||
, object(&emoji, std::move(repaint)) {
|
, object(&emoji, std::move(repaint))
|
||||||
|
, recentOnly(recentOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
||||||
|
@ -384,6 +463,7 @@ EmojiListWidget::~EmojiListWidget() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::repaintLater(
|
void EmojiListWidget::repaintLater(
|
||||||
|
DocumentId documentId,
|
||||||
uint64 setId,
|
uint64 setId,
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
Ui::CustomEmoji::RepaintRequest request) {
|
||||||
if (_instances.empty()) {
|
if (_instances.empty()) {
|
||||||
|
@ -393,7 +473,12 @@ void EmojiListWidget::repaintLater(
|
||||||
if (repaint.when < request.when) {
|
if (repaint.when < request.when) {
|
||||||
repaint.when = request.when;
|
repaint.when = request.when;
|
||||||
}
|
}
|
||||||
repaint.ids.emplace(setId);
|
if (setId) {
|
||||||
|
repaint.ids.emplace(setId);
|
||||||
|
}
|
||||||
|
if (_recentCustomIds.contains(documentId)) {
|
||||||
|
repaint.ids.emplace(RecentEmojiSectionSetId());
|
||||||
|
}
|
||||||
scheduleRepaintTimer();
|
scheduleRepaintTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,8 +535,12 @@ void EmojiListWidget::invokeRepaints() {
|
||||||
template <typename CheckId>
|
template <typename CheckId>
|
||||||
void EmojiListWidget::repaintCustom(CheckId checkId) {
|
void EmojiListWidget::repaintCustom(CheckId checkId) {
|
||||||
enumerateSections([&](const SectionInfo &info) {
|
enumerateSections([&](const SectionInfo &info) {
|
||||||
if (info.section >= kEmojiSectionCount
|
const auto repaint1 = (info.section == int(Section::Recent))
|
||||||
&& checkId(_custom[info.section - kEmojiSectionCount].id)) {
|
&& checkId(RecentEmojiSectionSetId());
|
||||||
|
const auto repaint2 = !repaint1
|
||||||
|
&& (info.section >= kEmojiSectionCount)
|
||||||
|
&& checkId(_custom[info.section - kEmojiSectionCount].id);
|
||||||
|
if (repaint1 || repaint2) {
|
||||||
update(
|
update(
|
||||||
0,
|
0,
|
||||||
info.rowsTop,
|
info.rowsTop,
|
||||||
|
@ -618,16 +707,17 @@ int EmojiListWidget::countDesiredHeight(int newWidth) {
|
||||||
void EmojiListWidget::ensureLoaded(int section) {
|
void EmojiListWidget::ensureLoaded(int section) {
|
||||||
Expects(section >= 0 && section < sectionsCount());
|
Expects(section >= 0 && section < sectionsCount());
|
||||||
|
|
||||||
if (section >= kEmojiSectionCount || !_emoji[section].empty()) {
|
if (section == int(Section::Recent)) {
|
||||||
|
if (_recent.empty()) {
|
||||||
|
fillRecent();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (section >= kEmojiSectionCount || !_emoji[section].empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_emoji[section] = (static_cast<Section>(section) == Section::Recent)
|
_emoji[section] = Ui::Emoji::GetSection(static_cast<Section>(section));
|
||||||
? Core::App().settings().recentEmojiSection()
|
|
||||||
: Ui::Emoji::GetSection(static_cast<Section>(section));
|
|
||||||
_counts[section] = _emoji[section].size();
|
_counts[section] = _emoji[section].size();
|
||||||
if (static_cast<Section>(section) == Section::Recent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto &variants = Core::App().settings().emojiVariants();
|
const auto &variants = Core::App().settings().emojiVariants();
|
||||||
for (auto &emoji : _emoji[section]) {
|
for (auto &emoji : _emoji[section]) {
|
||||||
if (emoji->hasVariants()) {
|
if (emoji->hasVariants()) {
|
||||||
|
@ -639,6 +729,24 @@ void EmojiListWidget::ensureLoaded(int section) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::fillRecent() {
|
||||||
|
_recent.clear();
|
||||||
|
_recentCustomIds.clear();
|
||||||
|
|
||||||
|
const auto &list = Core::App().settings().recentEmoji();
|
||||||
|
_recent.reserve(list.size());
|
||||||
|
for (const auto &one : list) {
|
||||||
|
_recent.push_back({
|
||||||
|
.instance = resolveCustomInstance(one.id.data),
|
||||||
|
.id = one.id.data,
|
||||||
|
});
|
||||||
|
if (const auto documentId = std::get_if<DocumentId>(&one.id.data)) {
|
||||||
|
_recentCustomIds.emplace(*documentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_counts[0] = _recent.size();
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
QRect r = e ? e->rect() : rect();
|
QRect r = e ? e->rect() : rect();
|
||||||
|
@ -720,7 +828,9 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
|
if (rtl()) tl.setX(width() - tl.x() - _singleSize.width());
|
||||||
Ui::FillRoundRect(p, QRect(tl, _singleSize), st::emojiPanHover, Ui::StickerHoverCorners);
|
Ui::FillRoundRect(p, QRect(tl, _singleSize), st::emojiPanHover, Ui::StickerHoverCorners);
|
||||||
}
|
}
|
||||||
if (info.section < kEmojiSectionCount) {
|
if (info.section == int(Section::Recent)) {
|
||||||
|
drawRecent(p, w, now, paused, index);
|
||||||
|
} else if (info.section < kEmojiSectionCount) {
|
||||||
drawEmoji(p, w, info.section, index);
|
drawEmoji(p, w, info.section, index);
|
||||||
} else {
|
} else {
|
||||||
const auto set = info.section - kEmojiSectionCount;
|
const auto set = info.section - kEmojiSectionCount;
|
||||||
|
@ -733,6 +843,23 @@ void EmojiListWidget::paintEvent(QPaintEvent *e) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::drawRecent(
|
||||||
|
QPainter &p,
|
||||||
|
QPoint position,
|
||||||
|
crl::time now,
|
||||||
|
bool paused,
|
||||||
|
int index) {
|
||||||
|
const auto size = (_esize / cIntRetinaFactor());
|
||||||
|
_recentPainted = true;
|
||||||
|
_recent[index].instance->object.paint(
|
||||||
|
p,
|
||||||
|
position.x() + (_singleSize.width() - size) / 2,
|
||||||
|
position.y() + (_singleSize.height() - size) / 2,
|
||||||
|
now,
|
||||||
|
st::windowBgRipple->c,
|
||||||
|
paused);
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiListWidget::drawEmoji(
|
void EmojiListWidget::drawEmoji(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
QPoint position,
|
QPoint position,
|
||||||
|
@ -775,6 +902,20 @@ bool EmojiListWidget::checkPickerHide() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmojiPtr EmojiListWidget::lookupOverEmoji(const OverEmoji *over) const {
|
||||||
|
const auto section = over ? over->section : -1;
|
||||||
|
const auto index = over ? over->index : -1;
|
||||||
|
return (section == int(Section::Recent)
|
||||||
|
&& index < _recent.size()
|
||||||
|
&& v::is<EmojiPtr>(_recent[index].id))
|
||||||
|
? v::get<EmojiPtr>(_recent[index].id)
|
||||||
|
: (section > int(Section::Recent)
|
||||||
|
&& section < kEmojiSectionCount
|
||||||
|
&& index < _emoji[section].size())
|
||||||
|
? _emoji[section][index]
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
_lastMousePos = e->globalPos();
|
_lastMousePos = e->globalPos();
|
||||||
updateSelected();
|
updateSelected();
|
||||||
|
@ -783,13 +924,12 @@ void EmojiListWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
}
|
}
|
||||||
setPressed(_selected);
|
setPressed(_selected);
|
||||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||||
if (over->section < kEmojiSectionCount
|
const auto emoji = lookupOverEmoji(over);
|
||||||
&& over->index < _emoji[over->section].size()
|
if (emoji && emoji->hasVariants()) {
|
||||||
&& _emoji[over->section][over->index]->hasVariants()) {
|
|
||||||
_pickerSelected = _selected;
|
_pickerSelected = _selected;
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
const auto &variants = Core::App().settings().emojiVariants();
|
const auto &variants = Core::App().settings().emojiVariants();
|
||||||
if (!variants.contains(_emoji[over->section][over->index]->nonColoredId())) {
|
if (!variants.contains(emoji->nonColoredId())) {
|
||||||
showPicker();
|
showPicker();
|
||||||
} else {
|
} else {
|
||||||
_showPickerTimer.callOnce(500);
|
_showPickerTimer.callOnce(500);
|
||||||
|
@ -806,13 +946,10 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
if (_picker->rect().contains(_picker->mapFromGlobal(_lastMousePos))) {
|
||||||
return _picker->handleMouseRelease(QCursor::pos());
|
return _picker->handleMouseRelease(QCursor::pos());
|
||||||
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
} else if (const auto over = std::get_if<OverEmoji>(&_pickerSelected)) {
|
||||||
const auto section = over->section;
|
const auto emoji = lookupOverEmoji(over);
|
||||||
const auto index = over->index;
|
if (emoji && emoji->hasVariants()) {
|
||||||
if (section < kEmojiSectionCount
|
|
||||||
&& index < _emoji[section].size()
|
|
||||||
&& _emoji[section][index]->hasVariants()) {
|
|
||||||
const auto &variants = Core::App().settings().emojiVariants();
|
const auto &variants = Core::App().settings().emojiVariants();
|
||||||
if (variants.contains(_emoji[section][index]->nonColoredId())) {
|
if (variants.contains(emoji->nonColoredId())) {
|
||||||
_picker->hideAnimated();
|
_picker->hideAnimated();
|
||||||
_pickerSelected = v::null;
|
_pickerSelected = v::null;
|
||||||
}
|
}
|
||||||
|
@ -834,12 +971,20 @@ void EmojiListWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
if (const auto over = std::get_if<OverEmoji>(&_selected)) {
|
||||||
const auto section = over->section;
|
const auto section = over->section;
|
||||||
const auto index = over->index;
|
const auto index = over->index;
|
||||||
if (section < kEmojiSectionCount && index < _emoji[section].size()) {
|
if (const auto emoji = lookupOverEmoji(over)) {
|
||||||
const auto emoji = _emoji[section][index];
|
|
||||||
if (emoji->hasVariants() && !_picker->isHidden()) {
|
if (emoji->hasVariants() && !_picker->isHidden()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
selectEmoji(emoji);
|
selectEmoji(emoji);
|
||||||
|
} else if (section == int(Section::Recent)
|
||||||
|
&& index < _recent.size()) {
|
||||||
|
const auto id = std::get_if<DocumentId>(&_recent[index].id);
|
||||||
|
const auto document = id
|
||||||
|
? session().data().document(*id).get()
|
||||||
|
: nullptr;
|
||||||
|
if (document && document->sticker()) {
|
||||||
|
selectCustom(document);
|
||||||
|
}
|
||||||
} else if (section >= kEmojiSectionCount
|
} else if (section >= kEmojiSectionCount
|
||||||
&& index < _custom[section - kEmojiSectionCount].list.size()) {
|
&& index < _custom[section - kEmojiSectionCount].list.size()) {
|
||||||
auto &set = _custom[section - kEmojiSectionCount];
|
auto &set = _custom[section - kEmojiSectionCount];
|
||||||
|
@ -875,11 +1020,12 @@ void EmojiListWidget::removeSet(uint64 setId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::selectEmoji(EmojiPtr emoji) {
|
void EmojiListWidget::selectEmoji(EmojiPtr emoji) {
|
||||||
Core::App().settings().incrementRecentEmoji(emoji);
|
Core::App().settings().incrementRecentEmoji({ emoji });
|
||||||
_chosen.fire_copy(emoji);
|
_chosen.fire_copy(emoji);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
void EmojiListWidget::selectCustom(not_null<DocumentData*> document) {
|
||||||
|
Core::App().settings().incrementRecentEmoji({ document->id });
|
||||||
_customChosen.fire({ .document = document });
|
_customChosen.fire({ .document = document });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,14 +1035,11 @@ void EmojiListWidget::showPicker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||||
const auto section = over ? over->section : -1;
|
const auto emoji = lookupOverEmoji(over);
|
||||||
if (section >= 0
|
if (emoji && emoji->hasVariants()) {
|
||||||
&& section < kEmojiSectionCount
|
_picker->showEmoji(emoji);
|
||||||
&& over->index < _emoji[section].size()
|
|
||||||
&& _emoji[section][over->index]->hasVariants()) {
|
|
||||||
_picker->showEmoji(_emoji[section][over->index]);
|
|
||||||
|
|
||||||
auto y = emojiRect(section, over->index).y();
|
auto y = emojiRect(over->section, over->index).y();
|
||||||
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
y -= _picker->height() - st::roundRadiusSmall + getVisibleTop();
|
||||||
if (y < st::emojiPanHeader) {
|
if (y < st::emojiPanHeader) {
|
||||||
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
y += _picker->height() - st::roundRadiusSmall + _singleSize.height() - st::roundRadiusSmall;
|
||||||
|
@ -960,7 +1103,10 @@ void EmojiListWidget::colorChosen(EmojiPtr emoji) {
|
||||||
Core::App().settings().saveEmojiVariant(emoji);
|
Core::App().settings().saveEmojiVariant(emoji);
|
||||||
}
|
}
|
||||||
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
const auto over = std::get_if<OverEmoji>(&_pickerSelected);
|
||||||
if (over && over->section >= 0 && over->section < kEmojiSectionCount) {
|
if (over
|
||||||
|
&& over->section > int(Section::Recent)
|
||||||
|
&& over->section < kEmojiSectionCount
|
||||||
|
&& over->index < _emoji[over->section].size()) {
|
||||||
_emoji[over->section][over->index] = emoji;
|
_emoji[over->section][over->index] = emoji;
|
||||||
rtlupdate(emojiRect(over->section, over->index));
|
rtlupdate(emojiRect(over->section, over->index));
|
||||||
}
|
}
|
||||||
|
@ -1006,13 +1152,8 @@ uint64 EmojiListWidget::currentSet(int yOffset) const {
|
||||||
QString EmojiListWidget::tooltipText() const {
|
QString EmojiListWidget::tooltipText() const {
|
||||||
const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
|
const auto &replacements = Ui::Emoji::internal::GetAllReplacements();
|
||||||
const auto over = std::get_if<OverEmoji>(&_selected);
|
const auto over = std::get_if<OverEmoji>(&_selected);
|
||||||
const auto section = over ? over->section : -1;
|
if (const auto emoji = lookupOverEmoji(over)) {
|
||||||
const auto index = over ? over->index : -1;
|
const auto text = emoji->original()->text();
|
||||||
if (section >= 0
|
|
||||||
&& section < kEmojiSectionCount
|
|
||||||
&& index < _emoji[section].size()) {
|
|
||||||
const auto emoji = _emoji[section][index]->original();
|
|
||||||
const auto text = emoji->text();
|
|
||||||
// find the replacement belonging to the emoji
|
// find the replacement belonging to the emoji
|
||||||
const auto it = ranges::find_if(replacements, [&](const auto &one) {
|
const auto it = ranges::find_if(replacements, [&](const auto &one) {
|
||||||
return text == Ui::Emoji::QStringFromUTF16(one.emoji);
|
return text == Ui::Emoji::QStringFromUTF16(one.emoji);
|
||||||
|
@ -1046,8 +1187,7 @@ void EmojiListWidget::processHideFinished() {
|
||||||
|
|
||||||
void EmojiListWidget::refreshRecent() {
|
void EmojiListWidget::refreshRecent() {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
_emoji[0] = Core::App().settings().recentEmojiSection();
|
fillRecent();
|
||||||
_counts[0] = _emoji[0].size();
|
|
||||||
resizeToWidth(width());
|
resizeToWidth(width());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,30 +1227,8 @@ void EmojiListWidget::refreshCustom() {
|
||||||
set.reserve(list.size());
|
set.reserve(list.size());
|
||||||
for (const auto document : list) {
|
for (const auto document : list) {
|
||||||
if (document->sticker()) {
|
if (document->sticker()) {
|
||||||
auto i = _instances.find(document->id);
|
|
||||||
if (i == end(_instances)) {
|
|
||||||
auto loader = owner->customEmojiManager().createLoader(
|
|
||||||
document,
|
|
||||||
Data::CustomEmojiManager::SizeTag::Large);
|
|
||||||
const auto repaintDelayed = [=](
|
|
||||||
not_null<Ui::CustomEmoji::Instance*> instance,
|
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
|
||||||
repaintLater(setId, request);
|
|
||||||
};
|
|
||||||
const auto repaintNow = [=] {
|
|
||||||
repaintCustom([&](uint64 id) {
|
|
||||||
return id == setId;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
i = _instances.emplace(
|
|
||||||
document->id,
|
|
||||||
std::make_unique<CustomInstance>(
|
|
||||||
std::move(loader),
|
|
||||||
std::move(repaintDelayed),
|
|
||||||
std::move(repaintNow))).first;
|
|
||||||
}
|
|
||||||
set.push_back({
|
set.push_back({
|
||||||
.instance = i->second.get(),
|
.instance = resolveCustomInstance(document, setId),
|
||||||
.document = document,
|
.document = document,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1129,6 +1247,117 @@ void EmojiListWidget::refreshCustom() {
|
||||||
ValidateIconAnimations::None);
|
ValidateIconAnimations::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto EmojiListWidget::customInstanceWithLoader(
|
||||||
|
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
||||||
|
DocumentId documentId,
|
||||||
|
uint64 setId)
|
||||||
|
-> std::unique_ptr<CustomInstance> {
|
||||||
|
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)) {
|
||||||
|
const auto recentSetId = RecentEmojiSectionSetId();
|
||||||
|
repaintCustom([&](uint64 id) {
|
||||||
|
return (id == setId) || (id == recentSetId);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
repaintCustom([&](uint64 id) {
|
||||||
|
return (id == setId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return std::make_unique<CustomInstance>(
|
||||||
|
std::move(loader),
|
||||||
|
std::move(repaintDelayed),
|
||||||
|
std::move(repaintNow),
|
||||||
|
recentOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EmojiListWidget::resolveCustomInstance(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
uint64 setId)
|
||||||
|
-> not_null<CustomInstance*> {
|
||||||
|
Expects(document->sticker() != nullptr);
|
||||||
|
|
||||||
|
const auto documentId = document->id;
|
||||||
|
const auto i = _instances.find(documentId);
|
||||||
|
const auto recentOnly = (i != end(_instances)) && i->second->recentOnly;
|
||||||
|
if (i != end(_instances) && !recentOnly) {
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
auto instance = customInstanceWithLoader(
|
||||||
|
document->owner().customEmojiManager().createLoader(
|
||||||
|
document,
|
||||||
|
Data::CustomEmojiManager::SizeTag::Large),
|
||||||
|
documentId,
|
||||||
|
setId);
|
||||||
|
if (recentOnly) {
|
||||||
|
for (auto &recent : _recent) {
|
||||||
|
if (recent.instance == i->second.get()) {
|
||||||
|
recent.instance = instance.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i->second = std::move(instance);
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
return _instances.emplace(
|
||||||
|
documentId,
|
||||||
|
std::move(instance)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EmojiListWidget::resolveCustomInstance(
|
||||||
|
std::variant<EmojiPtr, DocumentId> customId)
|
||||||
|
-> not_null<CustomInstance*> {
|
||||||
|
if (const auto documentId = std::get_if<DocumentId>(&customId)) {
|
||||||
|
return resolveCustomInstance(*documentId);
|
||||||
|
} else if (const auto emoji = std::get_if<EmojiPtr>(&customId)) {
|
||||||
|
return resolveCustomInstance(FakeEmojiDocumentId(*emoji), *emoji);
|
||||||
|
}
|
||||||
|
Unexpected("Custom recent emoji id.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EmojiListWidget::resolveCustomInstance(
|
||||||
|
DocumentId fakeId,
|
||||||
|
EmojiPtr emoji)
|
||||||
|
-> not_null<CustomInstance*> {
|
||||||
|
const auto i = _instances.find(fakeId);
|
||||||
|
if (i != end(_instances)) {
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
return _instances.emplace(
|
||||||
|
fakeId,
|
||||||
|
std::make_unique<CustomInstance>(
|
||||||
|
std::make_unique<DefaultEmojiLoader>(
|
||||||
|
emoji,
|
||||||
|
Ui::Emoji::GetSizeLarge()),
|
||||||
|
[](const auto&, const auto&) {},
|
||||||
|
[] {},
|
||||||
|
true)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EmojiListWidget::resolveCustomInstance(
|
||||||
|
DocumentId documentId)
|
||||||
|
-> not_null<CustomInstance*> {
|
||||||
|
const auto i = _instances.find(documentId);
|
||||||
|
if (i != end(_instances)) {
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
return _instances.emplace(
|
||||||
|
documentId,
|
||||||
|
customInstanceWithLoader(
|
||||||
|
session().data().customEmojiManager().createLoader(
|
||||||
|
documentId,
|
||||||
|
Data::CustomEmojiManager::SizeTag::Large),
|
||||||
|
documentId,
|
||||||
|
RecentEmojiSectionSetId())
|
||||||
|
).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
std::vector<StickerIcon> EmojiListWidget::fillIcons() {
|
||||||
auto result = std::vector<StickerIcon>();
|
auto result = std::vector<StickerIcon>();
|
||||||
result.reserve(2 + _custom.size());
|
result.reserve(2 + _custom.size());
|
||||||
|
|
|
@ -29,6 +29,7 @@ enum class Section;
|
||||||
} // namespace Ui::Emoji
|
} // namespace Ui::Emoji
|
||||||
|
|
||||||
namespace Ui::CustomEmoji {
|
namespace Ui::CustomEmoji {
|
||||||
|
class Loader;
|
||||||
class Instance;
|
class Instance;
|
||||||
struct RepaintRequest;
|
struct RepaintRequest;
|
||||||
} // namespace Ui::CustomEmoji
|
} // namespace Ui::CustomEmoji
|
||||||
|
@ -116,6 +117,10 @@ private:
|
||||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||||
bool painted = false;
|
bool painted = false;
|
||||||
};
|
};
|
||||||
|
struct RecentOne {
|
||||||
|
not_null<CustomInstance*> instance;
|
||||||
|
std::variant<EmojiPtr, DocumentId> id;
|
||||||
|
};
|
||||||
struct RepaintSet {
|
struct RepaintSet {
|
||||||
base::flat_set<uint64> ids;
|
base::flat_set<uint64> ids;
|
||||||
crl::time when = 0;
|
crl::time when = 0;
|
||||||
|
@ -176,8 +181,15 @@ private:
|
||||||
void setSelected(OverState newSelected);
|
void setSelected(OverState newSelected);
|
||||||
void setPressed(OverState newPressed);
|
void setPressed(OverState newPressed);
|
||||||
|
|
||||||
|
[[nodiscard]] EmojiPtr lookupOverEmoji(const OverEmoji *over) const;
|
||||||
void selectEmoji(EmojiPtr emoji);
|
void selectEmoji(EmojiPtr emoji);
|
||||||
void selectCustom(not_null<DocumentData*> document);
|
void selectCustom(not_null<DocumentData*> document);
|
||||||
|
void drawRecent(
|
||||||
|
QPainter &p,
|
||||||
|
QPoint position,
|
||||||
|
crl::time now,
|
||||||
|
bool paused,
|
||||||
|
int index);
|
||||||
void drawEmoji(
|
void drawEmoji(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
QPoint position,
|
QPoint position,
|
||||||
|
@ -206,6 +218,7 @@ private:
|
||||||
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
[[nodiscard]] QPoint buttonRippleTopLeft(int section) const;
|
||||||
|
|
||||||
void repaintLater(
|
void repaintLater(
|
||||||
|
DocumentId documentId,
|
||||||
uint64 setId,
|
uint64 setId,
|
||||||
Ui::CustomEmoji::RepaintRequest request);
|
Ui::CustomEmoji::RepaintRequest request);
|
||||||
template <typename CheckId>
|
template <typename CheckId>
|
||||||
|
@ -213,12 +226,31 @@ private:
|
||||||
void scheduleRepaintTimer();
|
void scheduleRepaintTimer();
|
||||||
void invokeRepaints();
|
void invokeRepaints();
|
||||||
|
|
||||||
|
void fillRecent();
|
||||||
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
|
not_null<DocumentData*> document,
|
||||||
|
uint64 setId);
|
||||||
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
|
std::variant<EmojiPtr, DocumentId> customId);
|
||||||
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
|
DocumentId fakeId,
|
||||||
|
EmojiPtr emoji);
|
||||||
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
|
DocumentId documentId);
|
||||||
|
[[nodiscard]] std::unique_ptr<CustomInstance> customInstanceWithLoader(
|
||||||
|
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
||||||
|
DocumentId documentId,
|
||||||
|
uint64 setId);
|
||||||
|
|
||||||
StickersListFooter *_footer = nullptr;
|
StickersListFooter *_footer = nullptr;
|
||||||
|
|
||||||
int _counts[kEmojiSectionCount];
|
int _counts[kEmojiSectionCount];
|
||||||
|
std::vector<RecentOne> _recent;
|
||||||
|
base::flat_set<DocumentId> _recentCustomIds;
|
||||||
|
bool _recentPainted = false;
|
||||||
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
QVector<EmojiPtr> _emoji[kEmojiSectionCount];
|
||||||
std::vector<CustomSet> _custom;
|
std::vector<CustomSet> _custom;
|
||||||
base::flat_map<uint64, std::unique_ptr<CustomInstance>> _instances;
|
base::flat_map<DocumentId, std::unique_ptr<CustomInstance>> _instances;
|
||||||
|
|
||||||
int _rowsLeft = 0;
|
int _rowsLeft = 0;
|
||||||
int _columnCount = 1;
|
int _columnCount = 1;
|
||||||
|
|
|
@ -118,10 +118,14 @@ auto SuggestionsWidget::getRowsByQuery() const -> std::vector<Row> {
|
||||||
auto lastRecent = begin(result);
|
auto lastRecent = begin(result);
|
||||||
const auto &recent = Core::App().settings().recentEmoji();
|
const auto &recent = Core::App().settings().recentEmoji();
|
||||||
for (const auto &item : recent) {
|
for (const auto &item : recent) {
|
||||||
const auto emoji = item.emoji->original()
|
const auto emoji = std::get_if<EmojiPtr>(&item.id.data);
|
||||||
? item.emoji->original()
|
if (!emoji) {
|
||||||
: item.emoji;
|
continue;
|
||||||
const auto it = ranges::find(result, emoji, [](const Row &row) {
|
}
|
||||||
|
const auto original = (*emoji)->original()
|
||||||
|
? (*emoji)->original()
|
||||||
|
: (*emoji);
|
||||||
|
const auto it = ranges::find(result, original, [](const Row &row) {
|
||||||
return row.emoji.get();
|
return row.emoji.get();
|
||||||
});
|
});
|
||||||
if (it > lastRecent && it != end(result)) {
|
if (it > lastRecent && it != end(result)) {
|
||||||
|
|
|
@ -81,11 +81,17 @@ QByteArray Settings::serialize() const {
|
||||||
const auto windowPosition = Serialize(_windowPosition);
|
const auto windowPosition = Serialize(_windowPosition);
|
||||||
const auto proxy = _proxy.serialize();
|
const auto proxy = _proxy.serialize();
|
||||||
|
|
||||||
auto recentEmojiPreloadGenerated = std::vector<RecentEmojiId>();
|
auto recentEmojiPreloadGenerated = std::vector<RecentEmojiPreload>();
|
||||||
if (_recentEmojiPreload.empty()) {
|
if (_recentEmojiPreload.empty()) {
|
||||||
recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
|
recentEmojiPreloadGenerated.reserve(_recentEmoji.size());
|
||||||
for (const auto &[emoji, rating] : _recentEmoji) {
|
for (const auto &[id, rating] : _recentEmoji) {
|
||||||
recentEmojiPreloadGenerated.push_back({ emoji->id(), rating });
|
auto string = QString();
|
||||||
|
if (const auto documentId = std::get_if<DocumentId>(&id.data)) {
|
||||||
|
string = QString::number(*documentId);
|
||||||
|
} else if (const auto emoji = std::get_if<EmojiPtr>(&id.data)) {
|
||||||
|
string = (*emoji)->id();
|
||||||
|
}
|
||||||
|
recentEmojiPreloadGenerated.push_back({ string, rating });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto &recentEmojiPreloadData = _recentEmojiPreload.empty()
|
const auto &recentEmojiPreloadData = _recentEmojiPreload.empty()
|
||||||
|
@ -316,7 +322,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
|
||||||
qint32 callAudioBackend = 0;
|
qint32 callAudioBackend = 0;
|
||||||
qint32 disableCallsLegacy = 0;
|
qint32 disableCallsLegacy = 0;
|
||||||
QByteArray windowPosition;
|
QByteArray windowPosition;
|
||||||
std::vector<RecentEmojiId> recentEmojiPreload;
|
std::vector<RecentEmojiPreload> recentEmojiPreload;
|
||||||
base::flat_map<QString, uint8> emojiVariants;
|
base::flat_map<QString, uint8> emojiVariants;
|
||||||
qint32 disableOpenGL = _disableOpenGL ? 1 : 0;
|
qint32 disableOpenGL = _disableOpenGL ? 1 : 0;
|
||||||
qint32 groupCallNoiseSuppression = _groupCallNoiseSuppression ? 1 : 0;
|
qint32 groupCallNoiseSuppression = _groupCallNoiseSuppression ? 1 : 0;
|
||||||
|
@ -790,18 +796,24 @@ const std::vector<Settings::RecentEmoji> &Settings::recentEmoji() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::resolveRecentEmoji() const {
|
void Settings::resolveRecentEmoji() const {
|
||||||
const auto haveAlready = [&](EmojiPtr emoji) {
|
const auto haveAlready = [&](RecentEmojiId id) {
|
||||||
return ranges::contains(
|
return ranges::contains(
|
||||||
_recentEmoji,
|
_recentEmoji,
|
||||||
emoji->id(),
|
id,
|
||||||
[](const RecentEmoji &data) { return data.emoji->id(); });
|
[](const RecentEmoji &data) { return data.id; });
|
||||||
};
|
};
|
||||||
if (!_recentEmojiPreload.empty()) {
|
if (!_recentEmojiPreload.empty()) {
|
||||||
_recentEmoji.reserve(_recentEmojiPreload.size());
|
_recentEmoji.reserve(_recentEmojiPreload.size());
|
||||||
for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
|
for (const auto &[id, rating] : base::take(_recentEmojiPreload)) {
|
||||||
if (const auto emoji = Ui::Emoji::Find(id)) {
|
auto length = int();
|
||||||
if (!haveAlready(emoji)) {
|
const auto emoji = Ui::Emoji::Find(id, &length);
|
||||||
_recentEmoji.push_back({ emoji, rating });
|
if (emoji && length == id.size()) {
|
||||||
|
if (!haveAlready({ emoji })) {
|
||||||
|
_recentEmoji.push_back({ { emoji }, rating });
|
||||||
|
}
|
||||||
|
} else if (const auto documentId = id.toULongLong()) {
|
||||||
|
if (!haveAlready({ documentId })) {
|
||||||
|
_recentEmoji.push_back({ { documentId }, rating });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -810,29 +822,18 @@ void Settings::resolveRecentEmoji() const {
|
||||||
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
|
for (const auto emoji : Ui::Emoji::GetDefaultRecent()) {
|
||||||
if (_recentEmoji.size() >= kRecentEmojiLimit) {
|
if (_recentEmoji.size() >= kRecentEmojiLimit) {
|
||||||
break;
|
break;
|
||||||
} else if (!haveAlready(emoji)) {
|
} else if (!haveAlready({ emoji })) {
|
||||||
_recentEmoji.push_back({ emoji, 1 });
|
_recentEmoji.push_back({ { emoji }, 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmojiPack Settings::recentEmojiSection() const {
|
void Settings::incrementRecentEmoji(RecentEmojiId id) {
|
||||||
const auto &recent = recentEmoji();
|
|
||||||
|
|
||||||
auto result = EmojiPack();
|
|
||||||
result.reserve(recent.size());
|
|
||||||
for (const auto &[emoji, rating] : recent) {
|
|
||||||
result.push_back(emoji);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Settings::incrementRecentEmoji(EmojiPtr emoji) {
|
|
||||||
resolveRecentEmoji();
|
resolveRecentEmoji();
|
||||||
|
|
||||||
auto i = _recentEmoji.begin(), e = _recentEmoji.end();
|
auto i = _recentEmoji.begin(), e = _recentEmoji.end();
|
||||||
for (; i != e; ++i) {
|
for (; i != e; ++i) {
|
||||||
if (i->emoji == emoji) {
|
if (i->id == id) {
|
||||||
++i->rating;
|
++i->rating;
|
||||||
if (i->rating > 0x8000) {
|
if (i->rating > 0x8000) {
|
||||||
for (auto j = _recentEmoji.begin(); j != e; ++j) {
|
for (auto j = _recentEmoji.begin(); j != e; ++j) {
|
||||||
|
@ -856,7 +857,7 @@ void Settings::incrementRecentEmoji(EmojiPtr emoji) {
|
||||||
while (_recentEmoji.size() >= kRecentEmojiLimit) {
|
while (_recentEmoji.size() >= kRecentEmojiLimit) {
|
||||||
_recentEmoji.pop_back();
|
_recentEmoji.pop_back();
|
||||||
}
|
}
|
||||||
_recentEmoji.push_back({ emoji, 1 });
|
_recentEmoji.push_back({ id, 1 });
|
||||||
for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
|
for (i = _recentEmoji.end() - 1; i != _recentEmoji.begin(); --i) {
|
||||||
if ((i - 1)->rating > i->rating) {
|
if ((i - 1)->rating > i->rating) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -573,13 +573,19 @@ public:
|
||||||
return _workMode.changes();
|
return _workMode.changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RecentEmojiId {
|
||||||
|
std::variant<EmojiPtr, DocumentId> data;
|
||||||
|
|
||||||
|
friend inline auto operator<=>(
|
||||||
|
RecentEmojiId,
|
||||||
|
RecentEmojiId) = default;
|
||||||
|
};
|
||||||
struct RecentEmoji {
|
struct RecentEmoji {
|
||||||
EmojiPtr emoji = nullptr;
|
RecentEmojiId id;
|
||||||
ushort rating = 0;
|
ushort rating = 0;
|
||||||
};
|
};
|
||||||
[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
|
[[nodiscard]] const std::vector<RecentEmoji> &recentEmoji() const;
|
||||||
[[nodiscard]] EmojiPack recentEmojiSection() const;
|
void incrementRecentEmoji(RecentEmojiId id);
|
||||||
void incrementRecentEmoji(EmojiPtr emoji);
|
|
||||||
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);
|
void setLegacyRecentEmojiPreload(QVector<QPair<QString, ushort>> data);
|
||||||
[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
|
[[nodiscard]] rpl::producer<> recentEmojiUpdated() const {
|
||||||
return _recentEmojiUpdated.events();
|
return _recentEmojiUpdated.events();
|
||||||
|
@ -708,7 +714,7 @@ private:
|
||||||
static constexpr auto kDefaultDialogsWidthRatio = 5. / 14;
|
static constexpr auto kDefaultDialogsWidthRatio = 5. / 14;
|
||||||
static constexpr auto kDefaultBigDialogsWidthRatio = 0.275;
|
static constexpr auto kDefaultBigDialogsWidthRatio = 0.275;
|
||||||
|
|
||||||
struct RecentEmojiId {
|
struct RecentEmojiPreload {
|
||||||
QString emoji;
|
QString emoji;
|
||||||
ushort rating = 0;
|
ushort rating = 0;
|
||||||
};
|
};
|
||||||
|
@ -764,7 +770,7 @@ private:
|
||||||
rpl::variable<std::vector<int>> _dictionariesEnabled;
|
rpl::variable<std::vector<int>> _dictionariesEnabled;
|
||||||
rpl::variable<bool> _autoDownloadDictionaries = true;
|
rpl::variable<bool> _autoDownloadDictionaries = true;
|
||||||
rpl::variable<bool> _mainMenuAccountsShown = true;
|
rpl::variable<bool> _mainMenuAccountsShown = true;
|
||||||
mutable std::vector<RecentEmojiId> _recentEmojiPreload;
|
mutable std::vector<RecentEmojiPreload> _recentEmojiPreload;
|
||||||
mutable std::vector<RecentEmoji> _recentEmoji;
|
mutable std::vector<RecentEmoji> _recentEmoji;
|
||||||
base::flat_map<QString, uint8> _emojiVariants;
|
base::flat_map<QString, uint8> _emojiVariants;
|
||||||
rpl::event_stream<> _recentEmojiUpdated;
|
rpl::event_stream<> _recentEmojiUpdated;
|
||||||
|
|
|
@ -269,7 +269,7 @@ const Ui::Emoji::One *UiIntegration::defaultEmojiVariant(
|
||||||
const auto result = (i != end(variants))
|
const auto result = (i != end(variants))
|
||||||
? emoji->variant(i->second)
|
? emoji->variant(i->second)
|
||||||
: emoji;
|
: emoji;
|
||||||
Core::App().settings().incrementRecentEmoji(result);
|
Core::App().settings().incrementRecentEmoji({ result });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -371,17 +371,7 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
|
||||||
auto i = _instances.find(parsed.id);
|
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 = std::make_unique<CustomEmojiLoader>(
|
auto loader = createLoader(parsed.id, SizeTag::Normal);
|
||||||
_owner,
|
|
||||||
parsed,
|
|
||||||
SizeTag::Normal);
|
|
||||||
if (loader->resolving()) {
|
|
||||||
_loaders[parsed.id].push_back(base::make_weak(loader.get()));
|
|
||||||
_pendingForRequest.emplace(parsed.id);
|
|
||||||
if (!_requestId && _pendingForRequest.size() == 1) {
|
|
||||||
crl::on_main(this, [=] { request(); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
||||||
|
@ -406,6 +396,25 @@ std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
return std::make_unique<CustomEmojiLoader>(document, tag);
|
return std::make_unique<CustomEmojiLoader>(document, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
|
||||||
|
DocumentId documentId,
|
||||||
|
SizeTag tag) {
|
||||||
|
const auto selfId = _owner->session().userId().bare;
|
||||||
|
auto result = std::make_unique<CustomEmojiLoader>(
|
||||||
|
_owner,
|
||||||
|
CustomEmojiId{ .selfId = selfId, .id = documentId },
|
||||||
|
tag);
|
||||||
|
if (result->resolving()) {
|
||||||
|
_loaders[documentId].push_back(base::make_weak(result.get()));
|
||||||
|
_pendingForRequest.emplace(documentId);
|
||||||
|
if (!_requestId && _pendingForRequest.size() == 1) {
|
||||||
|
crl::on_main(this, [=] { request(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CustomEmojiManager::request() {
|
void CustomEmojiManager::request() {
|
||||||
auto ids = QVector<MTPlong>();
|
auto ids = QVector<MTPlong>();
|
||||||
ids.reserve(std::min(kMaxPerRequest, int(_pendingForRequest.size())));
|
ids.reserve(std::min(kMaxPerRequest, int(_pendingForRequest.size())));
|
||||||
|
|
|
@ -45,6 +45,9 @@ public:
|
||||||
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
SizeTag tag);
|
SizeTag tag);
|
||||||
|
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
|
||||||
|
DocumentId documentId,
|
||||||
|
SizeTag tag);
|
||||||
|
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
[[nodiscard]] Session &owner() const;
|
[[nodiscard]] Session &owner() const;
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
uint64 id = 0;
|
uint64 id = 0;
|
||||||
uint64 accessHash = 0;
|
uint64 accessHash = 0;
|
||||||
uint64 hash = 0;
|
uint64 hash = 0;
|
||||||
uint64 thumbnailDocumentId = 0;
|
DocumentId thumbnailDocumentId = 0;
|
||||||
QString title, shortName;
|
QString title, shortName;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
StickersSetFlags flags;
|
StickersSetFlags flags;
|
||||||
|
|
Loading…
Add table
Reference in a new issue