mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Improve emoji set box design.
This commit is contained in:
parent
152bcb3570
commit
b31a3ba5a3
20 changed files with 407 additions and 219 deletions
|
@ -45,19 +45,24 @@ void AttachedStickers::request(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Single attached sticker pack.
|
// Single attached sticker pack.
|
||||||
const auto setData = result.v.front().match([&](const auto &data) {
|
const auto data = result.v.front().match([&](const auto &data) {
|
||||||
return data.vset().match([&](const MTPDstickerSet &data) {
|
return &data.vset().data();
|
||||||
return &data;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto setId = (setData->vid().v && setData->vaccess_hash().v)
|
const auto setId = (data->vid().v && data->vaccess_hash().v)
|
||||||
? StickerSetIdentifier{
|
? StickerSetIdentifier{
|
||||||
.id = setData->vid().v,
|
.id = data->vid().v,
|
||||||
.accessHash = setData->vaccess_hash().v }
|
.accessHash = data->vaccess_hash().v }
|
||||||
: StickerSetIdentifier{ .shortName = qs(setData->vshort_name()) };
|
: StickerSetIdentifier{ .shortName = qs(data->vshort_name()) };
|
||||||
strongController->show(
|
strongController->show(
|
||||||
Box<StickerSetBox>(strongController, setId),
|
Box<StickerSetBox>(
|
||||||
|
strongController,
|
||||||
|
setId,
|
||||||
|
(data->is_emojis()
|
||||||
|
? Data::StickersType::Emoji
|
||||||
|
: data->is_masks()
|
||||||
|
? Data::StickersType::Masks
|
||||||
|
: Data::StickersType::Stickers)),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
}).fail([=] {
|
}).fail([=] {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "menu/menu_send.h"
|
#include "menu/menu_send.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/boxes/confirm_box.h"
|
#include "ui/boxes/confirm_box.h"
|
||||||
|
@ -26,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/image/image_location_factory.h"
|
#include "ui/image/image_location_factory.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
|
#include "ui/text/custom_emoji_instance.h"
|
||||||
#include "ui/effects/path_shift_gradient.h"
|
#include "ui/effects/path_shift_gradient.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
|
@ -115,7 +117,8 @@ public:
|
||||||
Inner(
|
Inner(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const StickerSetIdentifier &set);
|
const StickerSetIdentifier &set,
|
||||||
|
Data::StickersType type);
|
||||||
|
|
||||||
[[nodiscard]] bool loaded() const;
|
[[nodiscard]] bool loaded() const;
|
||||||
[[nodiscard]] bool notInstalled() const;
|
[[nodiscard]] bool notInstalled() const;
|
||||||
|
@ -153,12 +156,15 @@ 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::Animations::Simple overAnimation;
|
Ui::Animations::Simple overAnimation;
|
||||||
|
|
||||||
mutable QImage premiumLock;
|
mutable QImage premiumLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -178,6 +184,10 @@ private:
|
||||||
Media::Clip::Notification notification,
|
Media::Clip::Notification notification,
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
int index);
|
int index);
|
||||||
|
void setupEmoji(int index);
|
||||||
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
|
not_null<DocumentData*> document);
|
||||||
|
void customEmojiRepaint();
|
||||||
|
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
void setSelected(int selected);
|
void setSelected(int selected);
|
||||||
|
@ -196,10 +206,17 @@ private:
|
||||||
void updateItems();
|
void updateItems();
|
||||||
void repaintItems(crl::time now = 0);
|
void repaintItems(crl::time now = 0);
|
||||||
|
|
||||||
not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
MTP::Sender _api;
|
MTP::Sender _api;
|
||||||
std::vector<Element> _elements;
|
std::vector<Element> _elements;
|
||||||
std::unique_ptr<Lottie::MultiPlayer> _lottiePlayer;
|
std::unique_ptr<Lottie::MultiPlayer> _lottiePlayer;
|
||||||
|
|
||||||
|
base::flat_map<
|
||||||
|
not_null<DocumentData*>,
|
||||||
|
std::unique_ptr<CustomInstance>> _instances;
|
||||||
|
std::unique_ptr<Ui::CustomEmoji::SimpleManager> _manager;
|
||||||
|
bool _repaintScheduled = false;
|
||||||
|
|
||||||
StickersPack _pack;
|
StickersPack _pack;
|
||||||
StickersByEmojiMap _emoji;
|
StickersByEmojiMap _emoji;
|
||||||
bool _loaded = false;
|
bool _loaded = false;
|
||||||
|
@ -226,6 +243,7 @@ private:
|
||||||
base::Timer _updateItemsTimer;
|
base::Timer _updateItemsTimer;
|
||||||
|
|
||||||
StickerSetIdentifier _input;
|
StickerSetIdentifier _input;
|
||||||
|
QMargins _padding;
|
||||||
|
|
||||||
mtpRequestId _installRequest = 0;
|
mtpRequestId _installRequest = 0;
|
||||||
|
|
||||||
|
@ -246,9 +264,18 @@ private:
|
||||||
StickerSetBox::StickerSetBox(
|
StickerSetBox::StickerSetBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const StickerSetIdentifier &set)
|
const StickerSetIdentifier &set,
|
||||||
|
Data::StickersType type)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _set(set) {
|
, _set(set)
|
||||||
|
, _type(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StickerSetBox::StickerSetBox(
|
||||||
|
QWidget *parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<Data::StickersSet*> set)
|
||||||
|
: StickerSetBox(parent, controller, set->identifier(), set->type()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPointer<Ui::BoxContent> StickerSetBox::Show(
|
QPointer<Ui::BoxContent> StickerSetBox::Show(
|
||||||
|
@ -257,7 +284,10 @@ QPointer<Ui::BoxContent> StickerSetBox::Show(
|
||||||
if (const auto sticker = document->sticker()) {
|
if (const auto sticker = document->sticker()) {
|
||||||
if (sticker->set) {
|
if (sticker->set) {
|
||||||
return controller->show(
|
return controller->show(
|
||||||
Box<StickerSetBox>(controller, sticker->set),
|
Box<StickerSetBox>(
|
||||||
|
controller,
|
||||||
|
sticker->set,
|
||||||
|
sticker->setType),
|
||||||
Ui::LayerOption::KeepOther).data();
|
Ui::LayerOption::KeepOther).data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,14 +298,18 @@ void StickerSetBox::prepare() {
|
||||||
setTitle(tr::lng_contacts_loading());
|
setTitle(tr::lng_contacts_loading());
|
||||||
|
|
||||||
_inner = setInnerWidget(
|
_inner = setInnerWidget(
|
||||||
object_ptr<Inner>(this, _controller, _set),
|
object_ptr<Inner>(this, _controller, _set, _type),
|
||||||
st::stickersScroll);
|
st::stickersScroll);
|
||||||
_controller->session().data().stickers().updated(
|
_controller->session().data().stickers().updated(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
updateButtons();
|
updateButtons();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
setDimensions(st::boxWideWidth, st::stickersMaxHeight);
|
setDimensions(
|
||||||
|
st::boxWideWidth,
|
||||||
|
(_type == Data::StickersType::Emoji
|
||||||
|
? st::emojiSetMaxHeight
|
||||||
|
: st::stickersMaxHeight));
|
||||||
|
|
||||||
updateTitleAndButtons();
|
updateTitleAndButtons();
|
||||||
|
|
||||||
|
@ -476,10 +510,12 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
|
||||||
StickerSetBox::Inner::Inner(
|
StickerSetBox::Inner::Inner(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const StickerSetIdentifier &set)
|
const StickerSetIdentifier &set,
|
||||||
|
Data::StickersType type)
|
||||||
: 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)
|
||||||
|
@ -489,6 +525,9 @@ StickerSetBox::Inner::Inner(
|
||||||
[=] { repaintItems(); }))
|
[=] { repaintItems(); }))
|
||||||
, _updateItemsTimer([=] { updateItems(); })
|
, _updateItemsTimer([=] { updateItems(); })
|
||||||
, _input(set)
|
, _input(set)
|
||||||
|
, _padding((type == Data::StickersType::Emoji)
|
||||||
|
? st::emojiSetPadding
|
||||||
|
: st::stickersPadding)
|
||||||
, _previewTimer([=] { showPreview(); }) {
|
, _previewTimer([=] { showPreview(); }) {
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
@ -613,16 +652,11 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
|
||||||
}
|
}
|
||||||
_perRow = isEmojiSet() ? kEmojiPerRow : kStickersPerRow;
|
_perRow = isEmojiSet() ? kEmojiPerRow : kStickersPerRow;
|
||||||
_rowsCount = (_pack.size() + _perRow - 1) / _perRow;
|
_rowsCount = (_pack.size() + _perRow - 1) / _perRow;
|
||||||
const auto fullWidth = st::boxWideWidth;
|
_singleSize = isEmojiSet() ? st::emojiSetSize : st::stickersSize;
|
||||||
const auto rowsLeft = st::stickersPadding.left();
|
|
||||||
const auto rowsRight = rowsLeft;
|
|
||||||
const auto singleWidth = (fullWidth - rowsLeft - rowsRight)
|
|
||||||
/ _perRow;
|
|
||||||
_singleSize = isEmojiSet()
|
|
||||||
? QSize(singleWidth, singleWidth)
|
|
||||||
: st::stickersSize;
|
|
||||||
|
|
||||||
resize(st::stickersPadding.left() + _perRow * _singleSize.width(), st::stickersPadding.top() + _rowsCount * _singleSize.height() + st::stickersPadding.bottom());
|
resize(
|
||||||
|
_padding.left() + _perRow * _singleSize.width(),
|
||||||
|
_padding.top() + _rowsCount * _singleSize.height() + _padding.bottom());
|
||||||
|
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
updateSelected();
|
updateSelected();
|
||||||
|
@ -862,8 +896,8 @@ void StickerSetBox::Inner::startOverAnimation(int index, float64 from, float64 t
|
||||||
_elements[index].overAnimation.start([=] {
|
_elements[index].overAnimation.start([=] {
|
||||||
const auto row = index / _perRow;
|
const auto row = index / _perRow;
|
||||||
const auto column = index % _perRow;
|
const auto column = index % _perRow;
|
||||||
const auto left = st::stickersPadding.left() + column * _singleSize.width();
|
const auto left = _padding.left() + column * _singleSize.width();
|
||||||
const auto top = st::stickersPadding.top() + row * _singleSize.height();
|
const auto top = _padding.top() + row * _singleSize.height();
|
||||||
rtlupdate(left, top, _singleSize.width(), _singleSize.height());
|
rtlupdate(left, top, _singleSize.width(), _singleSize.height());
|
||||||
}, from, to, st::emojiPanDuration);
|
}, from, to, st::emojiPanDuration);
|
||||||
}
|
}
|
||||||
|
@ -903,8 +937,8 @@ not_null<Lottie::MultiPlayer*> StickerSetBox::Inner::getLottiePlayer() {
|
||||||
int32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const {
|
int32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const {
|
||||||
QPoint l(mapFromGlobal(p));
|
QPoint l(mapFromGlobal(p));
|
||||||
if (rtl()) l.setX(width() - l.x());
|
if (rtl()) l.setX(width() - l.x());
|
||||||
int32 row = (l.y() >= st::stickersPadding.top()) ? qFloor((l.y() - st::stickersPadding.top()) / _singleSize.height()) : -1;
|
int32 row = (l.y() >= _padding.top()) ? qFloor((l.y() - _padding.top()) / _singleSize.height()) : -1;
|
||||||
int32 col = (l.x() >= st::stickersPadding.left()) ? qFloor((l.x() - st::stickersPadding.left()) / _singleSize.width()) : -1;
|
int32 col = (l.x() >= _padding.left()) ? qFloor((l.x() - _padding.left()) / _singleSize.width()) : -1;
|
||||||
if (row >= 0 && col >= 0 && col < _perRow) {
|
if (row >= 0 && col >= 0 && col < _perRow) {
|
||||||
int32 result = row * _perRow + col;
|
int32 result = row * _perRow + col;
|
||||||
return (result < _pack.size()) ? result : -1;
|
return (result < _pack.size()) ? result : -1;
|
||||||
|
@ -915,6 +949,8 @@ int32 StickerSetBox::Inner::stickerFromGlobalPos(const QPoint &p) const {
|
||||||
void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
_repaintScheduled = false;
|
||||||
|
|
||||||
p.fillRect(e->rect(), st::boxBg);
|
p.fillRect(e->rect(), st::boxBg);
|
||||||
if (_elements.empty()) {
|
if (_elements.empty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -933,7 +969,9 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
|
||||||
if (index >= _elements.size()) {
|
if (index >= _elements.size()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const auto pos = QPoint(st::stickersPadding.left() + j * _singleSize.width(), st::stickersPadding.top() + i * _singleSize.height());
|
const auto pos = QPoint(
|
||||||
|
_padding.left() + j * _singleSize.width(),
|
||||||
|
_padding.top() + i * _singleSize.height());
|
||||||
paintSticker(p, index, pos, paused, now);
|
paintSticker(p, index, pos, paused, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -984,7 +1022,7 @@ void StickerSetBox::Inner::visibleTopBottomUpdated(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto rowsTop = st::stickersPadding.top();
|
const auto rowsTop = _padding.top();
|
||||||
const auto singleHeight = _singleSize.height();
|
const auto singleHeight = _singleSize.height();
|
||||||
const auto rowsBottom = rowsTop + _rowsCount * singleHeight;
|
const auto rowsBottom = rowsTop + _rowsCount * singleHeight;
|
||||||
if (visibleTop >= rowsTop + singleHeight && visibleTop < rowsBottom) {
|
if (visibleTop >= rowsTop + singleHeight && visibleTop < rowsBottom) {
|
||||||
|
@ -1058,6 +1096,37 @@ void StickerSetBox::Inner::clipCallback(
|
||||||
updateItems();
|
updateItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StickerSetBox::Inner::setupEmoji(int index) {
|
||||||
|
auto &element = _elements[index];
|
||||||
|
element.emoji = resolveCustomInstance(element.document);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto StickerSetBox::Inner::resolveCustomInstance(
|
||||||
|
not_null<DocumentData*> document)
|
||||||
|
-> not_null<CustomInstance*> {
|
||||||
|
const auto i = _instances.find(document);
|
||||||
|
if (i != end(_instances)) {
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
auto instance = _manager->make(
|
||||||
|
_controller->session().data().customEmojiManager().createLoader(
|
||||||
|
document,
|
||||||
|
Data::CustomEmojiManager::SizeTag::Large),
|
||||||
|
[=] { customEmojiRepaint(); });
|
||||||
|
return _instances.emplace(
|
||||||
|
document,
|
||||||
|
std::move(instance)
|
||||||
|
).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickerSetBox::Inner::customEmojiRepaint() {
|
||||||
|
if (_repaintScheduled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_repaintScheduled = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void StickerSetBox::Inner::paintSticker(
|
void StickerSetBox::Inner::paintSticker(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
int index,
|
int index,
|
||||||
|
@ -1080,7 +1149,9 @@ void StickerSetBox::Inner::paintSticker(
|
||||||
&& !_controller->session().premium();
|
&& !_controller->session().premium();
|
||||||
media->checkStickerSmall();
|
media->checkStickerSmall();
|
||||||
|
|
||||||
if (media->loaded()) {
|
if (sticker->setType == Data::StickersType::Emoji) {
|
||||||
|
const_cast<Inner*>(this)->setupEmoji(index);
|
||||||
|
} else if (media->loaded()) {
|
||||||
if (sticker->isLottie() && !element.lottie) {
|
if (sticker->isLottie() && !element.lottie) {
|
||||||
const_cast<Inner*>(this)->setupLottie(index);
|
const_cast<Inner*>(this)->setupLottie(index);
|
||||||
} else if (sticker->isWebm() && !element.webm) {
|
} else if (sticker->isWebm() && !element.webm) {
|
||||||
|
@ -1095,7 +1166,15 @@ void StickerSetBox::Inner::paintSticker(
|
||||||
(_singleSize.width() - size.width()) / 2,
|
(_singleSize.width() - size.width()) / 2,
|
||||||
(_singleSize.height() - size.height()) / 2);
|
(_singleSize.height() - size.height()) / 2);
|
||||||
auto lottieFrame = QImage();
|
auto lottieFrame = QImage();
|
||||||
if (element.lottie && element.lottie->ready()) {
|
if (element.emoji) {
|
||||||
|
element.emoji->object.paint(
|
||||||
|
p,
|
||||||
|
ppos.x(),
|
||||||
|
ppos.y(),
|
||||||
|
now,
|
||||||
|
st::windowBgOver->c,
|
||||||
|
paused);
|
||||||
|
} else if (element.lottie && element.lottie->ready()) {
|
||||||
lottieFrame = element.lottie->frame();
|
lottieFrame = element.lottie->frame();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(ppos, lottieFrame.size() / cIntRetinaFactor()),
|
QRect(ppos, lottieFrame.size() / cIntRetinaFactor()),
|
||||||
|
|
|
@ -19,12 +19,21 @@ namespace Ui {
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class StickersSet;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
class StickerSetBox final : public Ui::BoxContent {
|
class StickerSetBox final : public Ui::BoxContent {
|
||||||
public:
|
public:
|
||||||
StickerSetBox(
|
StickerSetBox(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const StickerSetIdentifier &set);
|
const StickerSetIdentifier &set,
|
||||||
|
Data::StickersType type);
|
||||||
|
StickerSetBox(
|
||||||
|
QWidget*,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
not_null<Data::StickersSet*> set);
|
||||||
|
|
||||||
static QPointer<Ui::BoxContent> Show(
|
static QPointer<Ui::BoxContent> Show(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
|
@ -48,6 +57,7 @@ private:
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
const StickerSetIdentifier _set;
|
const StickerSetIdentifier _set;
|
||||||
|
const Data::StickersType _type;
|
||||||
|
|
||||||
class Inner;
|
class Inner;
|
||||||
QPointer<Inner> _inner;
|
QPointer<Inner> _inner;
|
||||||
|
|
|
@ -1806,7 +1806,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
const auto showSetByRow = [&](const Row &row) {
|
const auto showSetByRow = [&](const Row &row) {
|
||||||
setSelected(SelectedRow());
|
setSelected(SelectedRow());
|
||||||
_controller->show(
|
_controller->show(
|
||||||
Box<StickerSetBox>(_controller, row.set->identifier()),
|
Box<StickerSetBox>(_controller, row.set),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
};
|
};
|
||||||
if (selectedIndex >= 0 && !_inDragArea) {
|
if (selectedIndex >= 0 && !_inDragArea) {
|
||||||
|
|
|
@ -79,6 +79,9 @@ stickersFeaturedInstalled: icon {{ "chat/input_save", lightButtonFg }};
|
||||||
stickersMaxHeight: 320px;
|
stickersMaxHeight: 320px;
|
||||||
stickersPadding: margins(19px, 13px, 19px, 13px);
|
stickersPadding: margins(19px, 13px, 19px, 13px);
|
||||||
stickersSize: size(64px, 64px);
|
stickersSize: size(64px, 64px);
|
||||||
|
emojiSetPadding: margins(12px, 0px, 12px, 0px);
|
||||||
|
emojiSetMaxHeight: 197px;
|
||||||
|
emojiSetSize: size(42px, 39px);
|
||||||
stickersScroll: ScrollArea(boxScroll) {
|
stickersScroll: ScrollArea(boxScroll) {
|
||||||
deltat: 19px;
|
deltat: 19px;
|
||||||
deltab: 9px;
|
deltab: 9px;
|
||||||
|
@ -225,6 +228,9 @@ stickerIconMove: 400;
|
||||||
stickerPreviewDuration: 150;
|
stickerPreviewDuration: 150;
|
||||||
stickerPreviewMin: 0.1;
|
stickerPreviewMin: 0.1;
|
||||||
|
|
||||||
|
emojiIconWidth: 35px;
|
||||||
|
emojiIconArea: 32px;
|
||||||
|
|
||||||
stickerGroupCategorySize: 28px;
|
stickerGroupCategorySize: 28px;
|
||||||
stickerGroupCategoryAbout: defaultTextStyle;
|
stickerGroupCategoryAbout: defaultTextStyle;
|
||||||
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
stickerGroupCategoryAddMargin: margins(0px, 10px, 0px, 5px);
|
||||||
|
|
|
@ -96,17 +96,9 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmojiListWidget::CustomInstance {
|
struct EmojiListWidget::CustomInstance : Ui::CustomEmoji::SeparateInstance {
|
||||||
CustomInstance(
|
using SeparateInstance::SeparateInstance;
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
|
||||||
Fn<void(
|
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint,
|
|
||||||
bool recentOnly = false);
|
|
||||||
|
|
||||||
Ui::CustomEmoji::Instance emoji;
|
|
||||||
Ui::CustomEmoji::Object object;
|
|
||||||
bool recentOnly = false;
|
bool recentOnly = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,20 +107,6 @@ struct EmojiListWidget::RecentOne {
|
||||||
RecentEmojiId id;
|
RecentEmojiId id;
|
||||||
};
|
};
|
||||||
|
|
||||||
EmojiListWidget::CustomInstance::CustomInstance(
|
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
|
||||||
Fn<void(
|
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint,
|
|
||||||
bool recentOnly)
|
|
||||||
: emoji(
|
|
||||||
Ui::CustomEmoji::Loading(std::move(loader), Ui::CustomEmoji::Preview()),
|
|
||||||
std::move(repaintLater))
|
|
||||||
, object(&emoji, std::move(repaint))
|
|
||||||
, recentOnly(recentOnly) {
|
|
||||||
}
|
|
||||||
|
|
||||||
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
EmojiColorPicker::EmojiColorPicker(QWidget *parent)
|
||||||
: RpWidget(parent) {
|
: RpWidget(parent) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
@ -540,23 +518,42 @@ void EmojiListWidget::unloadNotSeenCustom(
|
||||||
int visibleTop,
|
int visibleTop,
|
||||||
int visibleBottom) {
|
int visibleBottom) {
|
||||||
enumerateSections([&](const SectionInfo &info) {
|
enumerateSections([&](const SectionInfo &info) {
|
||||||
if (info.section < kEmojiSectionCount
|
if (info.rowsBottom <= visibleTop || info.rowsTop >= visibleBottom) {
|
||||||
|| (info.rowsBottom > visibleTop
|
unloadCustomIn(info);
|
||||||
&& info.rowsTop < visibleBottom)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto &custom = _custom[info.section - kEmojiSectionCount];
|
|
||||||
if (!custom.painted) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
custom.painted = false;
|
|
||||||
for (const auto &single : custom.list) {
|
|
||||||
single.instance->object.unload();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::unloadAllCustom() {
|
||||||
|
enumerateSections([&](const SectionInfo &info) {
|
||||||
|
unloadCustomIn(info);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::unloadCustomIn(const SectionInfo &info) {
|
||||||
|
if (!info.section && _recentPainted) {
|
||||||
|
_recentPainted = false;
|
||||||
|
for (const auto &single : _recent) {
|
||||||
|
if (const auto instance = single.instance) {
|
||||||
|
instance->object.unload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (info.section < kEmojiSectionCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &custom = _custom[info.section - kEmojiSectionCount];
|
||||||
|
if (!custom.painted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
custom.painted = false;
|
||||||
|
for (const auto &single : custom.list) {
|
||||||
|
single.instance->object.unload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
|
object_ptr<TabbedSelector::InnerFooter> EmojiListWidget::createFooter() {
|
||||||
Expects(_footer == nullptr);
|
Expects(_footer == nullptr);
|
||||||
|
|
||||||
|
@ -1020,7 +1017,7 @@ void EmojiListWidget::displaySet(uint64 setId) {
|
||||||
auto it = sets.find(setId);
|
auto it = sets.find(setId);
|
||||||
if (it != sets.cend()) {
|
if (it != sets.cend()) {
|
||||||
checkHideWithBox(controller()->show(
|
checkHideWithBox(controller()->show(
|
||||||
Box<StickerSetBox>(controller(), it->second->identifier()),
|
Box<StickerSetBox>(controller(), it->second.get()),
|
||||||
Ui::LayerOption::KeepOther).data());
|
Ui::LayerOption::KeepOther).data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1206,9 +1203,14 @@ void EmojiListWidget::processHideFinished() {
|
||||||
_picker->hideFast();
|
_picker->hideFast();
|
||||||
_pickerSelected = v::null;
|
_pickerSelected = v::null;
|
||||||
}
|
}
|
||||||
|
unloadAllCustom();
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmojiListWidget::processPanelHideFinished() {
|
||||||
|
unloadAllCustom();
|
||||||
|
}
|
||||||
|
|
||||||
void EmojiListWidget::refreshRecent() {
|
void EmojiListWidget::refreshRecent() {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
fillRecent();
|
fillRecent();
|
||||||
|
@ -1302,11 +1304,12 @@ auto EmojiListWidget::customInstanceWithLoader(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return std::make_unique<CustomInstance>(
|
auto result = std::make_unique<CustomInstance>(
|
||||||
std::move(loader),
|
std::move(loader),
|
||||||
std::move(repaintDelayed),
|
std::move(repaintDelayed),
|
||||||
std::move(repaintNow),
|
std::move(repaintNow));
|
||||||
recentOnly);
|
result->recentOnly = recentOnly;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EmojiListWidget::resolveCustomInstance(
|
auto EmojiListWidget::resolveCustomInstance(
|
||||||
|
|
|
@ -96,6 +96,7 @@ protected:
|
||||||
|
|
||||||
TabbedSelector::InnerFooter *getFooter() const override;
|
TabbedSelector::InnerFooter *getFooter() const override;
|
||||||
void processHideFinished() override;
|
void processHideFinished() override;
|
||||||
|
void processPanelHideFinished() override;
|
||||||
int countDesiredHeight(int newWidth) override;
|
int countDesiredHeight(int newWidth) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -179,6 +180,8 @@ private:
|
||||||
bool checkPickerHide();
|
bool checkPickerHide();
|
||||||
void refreshCustom();
|
void refreshCustom();
|
||||||
void unloadNotSeenCustom(int visibleTop, int visibleBottom);
|
void unloadNotSeenCustom(int visibleTop, int visibleBottom);
|
||||||
|
void unloadAllCustom();
|
||||||
|
void unloadCustomIn(const SectionInfo &info);
|
||||||
|
|
||||||
void ensureLoaded(int section);
|
void ensureLoaded(int section);
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
|
|
|
@ -41,36 +41,12 @@ constexpr auto kAnimationDuration = crl::time(120);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct SuggestionsWidget::CustomInstance {
|
|
||||||
CustomInstance(
|
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
|
||||||
Fn<void(
|
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint);
|
|
||||||
|
|
||||||
Ui::CustomEmoji::Instance emoji;
|
|
||||||
Ui::CustomEmoji::Object object;
|
|
||||||
};
|
|
||||||
|
|
||||||
SuggestionsWidget::CustomInstance::CustomInstance(
|
|
||||||
std::unique_ptr<Ui::CustomEmoji::Loader> loader,
|
|
||||||
Fn<void(
|
|
||||||
not_null<Ui::CustomEmoji::Instance*>,
|
|
||||||
Ui::CustomEmoji::RepaintRequest)> repaintLater,
|
|
||||||
Fn<void()> repaint)
|
|
||||||
: emoji(
|
|
||||||
Ui::CustomEmoji::Loading(std::move(loader), Ui::CustomEmoji::Preview()),
|
|
||||||
std::move(repaintLater))
|
|
||||||
, object(&emoji, std::move(repaint)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
SuggestionsWidget::SuggestionsWidget(
|
SuggestionsWidget::SuggestionsWidget(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Main::Session*> session)
|
not_null<Main::Session*> session)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _session(session)
|
, _session(session)
|
||||||
, _repaintTimer([=] { invokeRepaints(); })
|
, _manager(std::make_unique<Ui::CustomEmoji::SimpleManager>())
|
||||||
, _oneWidth(st::emojiSuggestionSize)
|
, _oneWidth(st::emojiSuggestionSize)
|
||||||
, _padding(st::emojiSuggestionsPadding) {
|
, _padding(st::emojiSuggestionsPadding) {
|
||||||
resize(
|
resize(
|
||||||
|
@ -180,77 +156,23 @@ auto SuggestionsWidget::resolveCustomInstance(
|
||||||
if (i != end(_instances)) {
|
if (i != end(_instances)) {
|
||||||
return i->second.get();
|
return i->second.get();
|
||||||
}
|
}
|
||||||
const auto repaintDelayed = [=](
|
auto instance = _manager->make(
|
||||||
not_null<Ui::CustomEmoji::Instance*> instance,
|
|
||||||
Ui::CustomEmoji::RepaintRequest request) {
|
|
||||||
if (_instances.empty() || !request.when) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto &when = _repaints[request.duration];
|
|
||||||
if (when < request.when) {
|
|
||||||
when = request.when;
|
|
||||||
}
|
|
||||||
if (_repaintTimerScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
};
|
|
||||||
const auto repaintNow = [=] {
|
|
||||||
update();
|
|
||||||
};
|
|
||||||
auto instance = std::make_unique<CustomInstance>(
|
|
||||||
_session->data().customEmojiManager().createLoader(
|
_session->data().customEmojiManager().createLoader(
|
||||||
document,
|
document,
|
||||||
Data::CustomEmojiManager::SizeTag::Large),
|
Data::CustomEmojiManager::SizeTag::Large),
|
||||||
std::move(repaintDelayed),
|
[=] { customEmojiRepaint(); });
|
||||||
std::move(repaintNow));
|
|
||||||
return _instances.emplace(
|
return _instances.emplace(
|
||||||
document,
|
document,
|
||||||
std::move(instance)
|
std::move(instance)
|
||||||
).first->second.get();
|
).first->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SuggestionsWidget::scheduleRepaintTimer() {
|
void SuggestionsWidget::customEmojiRepaint() {
|
||||||
_repaintTimerScheduled = true;
|
if (_repaintScheduled) {
|
||||||
Ui::PostponeCall(this, [=] {
|
return;
|
||||||
_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 SuggestionsWidget::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) {
|
_repaintScheduled = true;
|
||||||
update();
|
update();
|
||||||
}
|
|
||||||
scheduleRepaintTimer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SuggestionsWidget::Row::Row(
|
SuggestionsWidget::Row::Row(
|
||||||
|
@ -378,6 +300,8 @@ void SuggestionsWidget::scrollByWheelEvent(not_null<QWheelEvent*> e) {
|
||||||
void SuggestionsWidget::paintEvent(QPaintEvent *e) {
|
void SuggestionsWidget::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
_repaintScheduled = false;
|
||||||
|
|
||||||
const auto clip = e->rect();
|
const auto clip = e->rect();
|
||||||
p.fillRect(clip, st::boxBg);
|
p.fillRect(clip, st::boxBg);
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,16 @@ class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
class InnerDropdown;
|
class InnerDropdown;
|
||||||
class InputField;
|
class InputField;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Emoji {
|
namespace Ui::CustomEmoji {
|
||||||
|
struct SeparateInstance;
|
||||||
|
class SimpleManager;
|
||||||
|
} // namespace Ui::CustomEmoji
|
||||||
|
|
||||||
|
namespace Ui::Emoji {
|
||||||
|
|
||||||
class SuggestionsWidget final : public Ui::RpWidget {
|
class SuggestionsWidget final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -43,7 +48,7 @@ public:
|
||||||
[[nodiscard]] rpl::producer<Chosen> triggered() const;
|
[[nodiscard]] rpl::producer<Chosen> triggered() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CustomInstance;
|
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);
|
||||||
|
|
||||||
|
@ -89,19 +94,17 @@ private:
|
||||||
|
|
||||||
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
[[nodiscard]] not_null<CustomInstance*> resolveCustomInstance(
|
||||||
not_null<DocumentData*> document);
|
not_null<DocumentData*> document);
|
||||||
void scheduleRepaintTimer();
|
void customEmojiRepaint();
|
||||||
void invokeRepaints();
|
|
||||||
|
|
||||||
const not_null<Main::Session*> _session;
|
const not_null<Main::Session*> _session;
|
||||||
QString _query;
|
QString _query;
|
||||||
std::vector<Row> _rows;
|
std::vector<Row> _rows;
|
||||||
|
|
||||||
base::flat_map<
|
base::flat_map<
|
||||||
not_null<DocumentData*>,
|
not_null<DocumentData*>,
|
||||||
std::unique_ptr<CustomInstance>> _instances;
|
std::unique_ptr<CustomInstance>> _instances;
|
||||||
base::flat_map<crl::time, crl::time> _repaints;
|
std::unique_ptr<Ui::CustomEmoji::SimpleManager> _manager;
|
||||||
bool _repaintTimerScheduled = false;
|
bool _repaintScheduled = false;
|
||||||
base::Timer _repaintTimer;
|
|
||||||
crl::time _repaintNext = 0;
|
|
||||||
|
|
||||||
std::optional<QPoint> _lastMousePosition;
|
std::optional<QPoint> _lastMousePosition;
|
||||||
bool _mouseSelection = false;
|
bool _mouseSelection = false;
|
||||||
|
@ -190,5 +193,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Emoji
|
} // namespace Ui::Emoji
|
||||||
} // namespace Ui
|
|
||||||
|
|
|
@ -139,8 +139,8 @@ bool StickersListFooter::ScrollState::animationCallback(crl::time now) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
x.update(dt, anim::linear);
|
x.update(dt, anim::linear);
|
||||||
selectionX.update(dt, anim::linear);
|
selectionX.update(dt, anim::easeOutCubic);
|
||||||
selectionWidth.update(dt, anim::linear);
|
selectionWidth.update(dt, anim::easeOutCubic);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,8 @@ StickersListFooter::StickersListFooter(Descriptor &&descriptor)
|
||||||
, _settingsButtonVisible(descriptor.settingsButtonVisible)
|
, _settingsButtonVisible(descriptor.settingsButtonVisible)
|
||||||
, _iconState([=] { update(); })
|
, _iconState([=] { update(); })
|
||||||
, _subiconState([=] { update(); })
|
, _subiconState([=] { update(); })
|
||||||
, _selectionBg(st::roundRadiusSmall, st::windowBgRipple)
|
, _selectionBg(st::roundRadiusLarge, st::windowBgRipple)
|
||||||
|
, _subselectionBg(st::emojiIconArea / 2, st::windowBgRipple)
|
||||||
, _barSelection(descriptor.barSelection) {
|
, _barSelection(descriptor.barSelection) {
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
@ -299,14 +300,13 @@ void StickersListFooter::enumerateIcons(
|
||||||
const auto shift = _iconsLeft - iconsX;
|
const auto shift = _iconsLeft - iconsX;
|
||||||
const auto emojiId = AllEmojiSectionSetId();
|
const auto emojiId = AllEmojiSectionSetId();
|
||||||
const auto right = width();
|
const auto right = width();
|
||||||
const auto single = st::stickerIconWidth;
|
|
||||||
for (auto i = 0, count = int(_icons.size()); i != count; ++i) {
|
for (auto i = 0, count = int(_icons.size()); i != count; ++i) {
|
||||||
auto &icon = _icons[i];
|
auto &icon = _icons[i];
|
||||||
const auto width = (icon.setId == emojiId)
|
const auto width = (icon.setId == emojiId)
|
||||||
? _subiconsWidthAnimation.value(_subiconsExpanded
|
? _subiconsWidthAnimation.value(_subiconsExpanded
|
||||||
? _subiconsWidth
|
? _subiconsWidth
|
||||||
: single)
|
: _singleWidth)
|
||||||
: single;
|
: _singleWidth;
|
||||||
const auto shifted = shift + left;
|
const auto shifted = shift + left;
|
||||||
const auto visible = (shifted + width > 0 && shifted < right);
|
const auto visible = (shifted + width > 0 && shifted < right);
|
||||||
const auto result = callback({
|
const auto result = callback({
|
||||||
|
@ -331,20 +331,19 @@ void StickersListFooter::enumerateSubicons(
|
||||||
const auto right = _subiconsWidth;
|
const auto right = _subiconsWidth;
|
||||||
using Section = Ui::Emoji::Section;
|
using Section = Ui::Emoji::Section;
|
||||||
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
|
for (auto i = int(Section::People); i <= int(Section::Symbols); ++i) {
|
||||||
const auto width = st::stickerIconWidth;
|
|
||||||
const auto shifted = shift + left;
|
const auto shifted = shift + left;
|
||||||
const auto visible = (shifted + width > 0 && shifted < right);
|
const auto visible = (shifted + _singleWidth > 0 && shifted < right);
|
||||||
const auto result = callback({
|
const auto result = callback({
|
||||||
.index = i - int(Section::People),
|
.index = i - int(Section::People),
|
||||||
.left = left,
|
.left = left,
|
||||||
.adjustedLeft = shifted,
|
.adjustedLeft = shifted,
|
||||||
.width = int(base::SafeRound(width)),
|
.width = _singleWidth,
|
||||||
.visible = visible,
|
.visible = visible,
|
||||||
});
|
});
|
||||||
if (!result) {
|
if (!result) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
left += width;
|
left += _singleWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,8 +431,8 @@ void StickersListFooter::updateEmojiSectionWidth() {
|
||||||
_subiconsExpanded = expanded;
|
_subiconsExpanded = expanded;
|
||||||
_subiconsWidthAnimation.start(
|
_subiconsWidthAnimation.start(
|
||||||
[=] { updateEmojiWidthCallback(); },
|
[=] { updateEmojiWidthCallback(); },
|
||||||
expanded ? st::stickerIconWidth : _subiconsWidth,
|
expanded ? _singleWidth : _subiconsWidth,
|
||||||
expanded ? _subiconsWidth : st::stickerIconWidth,
|
expanded ? _subiconsWidth : _singleWidth,
|
||||||
st::slideDuration);
|
st::slideDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,12 +579,27 @@ void StickersListFooter::paintSelectionBg(Painter &p) const {
|
||||||
selx = width() - selx - selw;
|
selx = width() - selx - selw;
|
||||||
}
|
}
|
||||||
const auto skip = st::emojiIconSelectSkip;
|
const auto skip = st::emojiIconSelectSkip;
|
||||||
const auto sely = _iconsTop
|
const auto sely = _iconsTop;
|
||||||
+ (st::emojiFooterHeight - st::stickerIconWidth) / 2;
|
const auto area = st::emojiIconArea;
|
||||||
const auto selh = st::stickerIconWidth;
|
const auto rect = QRect(
|
||||||
const auto rect = QRect(selx, sely, selw, selh);
|
QPoint(selx, sely) + _areaPosition,
|
||||||
const auto fill = rect.marginsRemoved({ skip, skip, skip, skip });
|
QSize(selw - 2 * _areaPosition.x(), area));
|
||||||
_selectionBg.paint(p, fill);
|
if (rect.width() == rect.height() || _subiconsWidth <= _singleWidth) {
|
||||||
|
_selectionBg.paint(p, rect);
|
||||||
|
} else if (selw == _subiconsWidth) {
|
||||||
|
_subselectionBg.paint(p, rect);
|
||||||
|
} else {
|
||||||
|
PainterHighQualityEnabler hq(p);
|
||||||
|
const auto progress = (selw - _singleWidth)
|
||||||
|
/ float64(_subiconsWidth - _singleWidth);
|
||||||
|
const auto radius = anim::interpolate(
|
||||||
|
st::roundRadiusLarge,
|
||||||
|
area / 2,
|
||||||
|
progress);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::windowBgRipple);
|
||||||
|
p.drawRoundedRect(rect, radius, radius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::paintSelectionBar(Painter &p) const {
|
void StickersListFooter::paintSelectionBar(Painter &p) const {
|
||||||
|
@ -864,17 +878,17 @@ void StickersListFooter::updateSelected() {
|
||||||
auto x = p.x(), y = p.y();
|
auto x = p.x(), y = p.y();
|
||||||
if (rtl()) x = width() - x;
|
if (rtl()) x = width() - x;
|
||||||
const auto settingsLeft = width() - _iconsRight;
|
const auto settingsLeft = width() - _iconsRight;
|
||||||
const auto searchLeft = _iconsLeft - st::stickerIconWidth;
|
const auto searchLeft = _iconsLeft - _singleWidth;
|
||||||
auto newOver = OverState(SpecialOver::None);
|
auto newOver = OverState(SpecialOver::None);
|
||||||
if (_searchButtonVisible
|
if (_searchButtonVisible
|
||||||
&& x >= searchLeft
|
&& x >= searchLeft
|
||||||
&& x < searchLeft + st::stickerIconWidth
|
&& x < searchLeft + _singleWidth
|
||||||
&& y >= _iconsTop
|
&& y >= _iconsTop
|
||||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
&& y < _iconsTop + st::emojiFooterHeight) {
|
||||||
newOver = SpecialOver::Search;
|
newOver = SpecialOver::Search;
|
||||||
} else if (_settingsButtonVisible
|
} else if (_settingsButtonVisible
|
||||||
&& x >= settingsLeft
|
&& x >= settingsLeft
|
||||||
&& x < settingsLeft + st::stickerIconWidth
|
&& x < settingsLeft + _singleWidth
|
||||||
&& y >= _iconsTop
|
&& y >= _iconsTop
|
||||||
&& y < _iconsTop + st::emojiFooterHeight) {
|
&& y < _iconsTop + st::emojiFooterHeight) {
|
||||||
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
|
if (!_icons.empty() && !hasOnlyFeaturedSets()) {
|
||||||
|
@ -975,6 +989,17 @@ void StickersListFooter::refreshIconsGeometry(
|
||||||
_iconState.selectionWidth.finish();
|
_iconState.selectionWidth.finish();
|
||||||
_iconState.animationStart = 0;
|
_iconState.animationStart = 0;
|
||||||
_iconState.animation.stop();
|
_iconState.animation.stop();
|
||||||
|
if (_barSelection) {
|
||||||
|
_singleWidth = st::stickerIconWidth;
|
||||||
|
} else if (_icons.size() > 1
|
||||||
|
&& _icons[1].setId == EmojiSectionSetId(EmojiSection::People)) {
|
||||||
|
_singleWidth = (width() - _iconsLeft - _iconsRight) / _icons.size();
|
||||||
|
} else {
|
||||||
|
_singleWidth = st::emojiIconWidth;
|
||||||
|
}
|
||||||
|
_areaPosition = QPoint(
|
||||||
|
(_singleWidth - st::emojiIconArea) / 2,
|
||||||
|
(st::emojiFooterHeight - st::emojiIconArea) / 2);
|
||||||
refreshScrollableDimensions();
|
refreshScrollableDimensions();
|
||||||
updateSelected();
|
updateSelected();
|
||||||
validateSelectedIcon(_activeByScrollId, animations);
|
validateSelectedIcon(_activeByScrollId, animations);
|
||||||
|
@ -988,18 +1013,18 @@ void StickersListFooter::refreshSubiconsGeometry() {
|
||||||
_subiconState.selectionWidth.finish();
|
_subiconState.selectionWidth.finish();
|
||||||
_subiconState.animationStart = 0;
|
_subiconState.animationStart = 0;
|
||||||
_subiconState.animation.stop();
|
_subiconState.animation.stop();
|
||||||
const auto single = st::stickerIconWidth;
|
const auto half = _singleWidth / 2;
|
||||||
const auto half = single / 2;
|
|
||||||
const auto count = int(Section::Symbols) - int(Section::Recent);
|
const auto count = int(Section::Symbols) - int(Section::Recent);
|
||||||
const auto widthMax = count * single;
|
const auto widthMax = count * _singleWidth;
|
||||||
const auto widthMin = 4 * single + half;
|
const auto widthMin = 4 * _singleWidth + half;
|
||||||
const auto collapsedWidth = int(_icons.size()) * single;
|
const auto collapsedWidth = int(_icons.size()) * _singleWidth;
|
||||||
_subiconsWidth = std::clamp(
|
_subiconsWidth = std::clamp(
|
||||||
width() + single - collapsedWidth,
|
width() + _singleWidth - collapsedWidth,
|
||||||
widthMin,
|
widthMin,
|
||||||
widthMax);
|
widthMax);
|
||||||
if (_subiconsWidth < widthMax) {
|
if (_subiconsWidth < widthMax) {
|
||||||
_subiconsWidth = ((_subiconsWidth - half) / single) * single + half;
|
_subiconsWidth = half
|
||||||
|
+ (((_subiconsWidth - half) / _singleWidth) * _singleWidth);
|
||||||
}
|
}
|
||||||
_subiconState.max = std::max(
|
_subiconState.max = std::max(
|
||||||
widthMax - _subiconsWidth,
|
widthMax - _subiconsWidth,
|
||||||
|
@ -1020,16 +1045,16 @@ void StickersListFooter::paintStickerSettingsIcon(Painter &p) const {
|
||||||
st::stickersSettings.paint(
|
st::stickersSettings.paint(
|
||||||
p,
|
p,
|
||||||
settingsLeft
|
settingsLeft
|
||||||
+ (st::stickerIconWidth - st::stickersSettings.width()) / 2,
|
+ (_singleWidth - st::stickersSettings.width()) / 2,
|
||||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
_iconsTop + st::emojiCategory.iconPosition.y(),
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::paintSearchIcon(Painter &p) const {
|
void StickersListFooter::paintSearchIcon(Painter &p) const {
|
||||||
const auto searchLeft = _iconsLeft - st::stickerIconWidth;
|
const auto searchLeft = _iconsLeft - _singleWidth;
|
||||||
st::stickersSearch.paint(
|
st::stickersSearch.paint(
|
||||||
p,
|
p,
|
||||||
searchLeft + (st::stickerIconWidth - st::stickersSearch.width()) / 2,
|
searchLeft + (_singleWidth - st::stickersSearch.width()) / 2,
|
||||||
_iconsTop + st::emojiCategory.iconPosition.y(),
|
_iconsTop + st::emojiCategory.iconPosition.y(),
|
||||||
width());
|
width());
|
||||||
}
|
}
|
||||||
|
@ -1100,7 +1125,7 @@ void StickersListFooter::updateSetIcon(uint64 setId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::updateSetIconAt(int left) {
|
void StickersListFooter::updateSetIconAt(int left) {
|
||||||
update(left, _iconsTop, st::stickerIconWidth, st::emojiFooterHeight);
|
update(left, _iconsTop, _singleWidth, st::emojiFooterHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersListFooter::paintSetIcon(
|
void StickersListFooter::paintSetIcon(
|
||||||
|
@ -1118,8 +1143,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
: icon.stickerMedia
|
: icon.stickerMedia
|
||||||
? icon.stickerMedia->thumbnail()
|
? icon.stickerMedia->thumbnail()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto x = info.adjustedLeft
|
const auto x = info.adjustedLeft + (_singleWidth - icon.pixw) / 2;
|
||||||
+ (st::stickerIconWidth - icon.pixw) / 2;
|
|
||||||
const auto y = _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2;
|
const auto y = _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2;
|
||||||
if (icon.lottie && icon.lottie->ready()) {
|
if (icon.lottie && icon.lottie->ready()) {
|
||||||
const auto frame = icon.lottie->frame();
|
const auto frame = icon.lottie->frame();
|
||||||
|
@ -1130,8 +1154,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
}
|
}
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(
|
QRect(
|
||||||
(info.adjustedLeft
|
(info.adjustedLeft + (_singleWidth - size.width()) / 2),
|
||||||
+ (st::stickerIconWidth - size.width()) / 2),
|
|
||||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
||||||
size.width(),
|
size.width(),
|
||||||
size.height()),
|
size.height()),
|
||||||
|
@ -1166,7 +1189,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
icon.megagroup->paintUserpicLeft(
|
icon.megagroup->paintUserpicLeft(
|
||||||
p,
|
p,
|
||||||
icon.megagroupUserpic,
|
icon.megagroupUserpic,
|
||||||
info.adjustedLeft + (st::stickerIconWidth - size) / 2,
|
info.adjustedLeft + (_singleWidth - size) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - size) / 2,
|
_iconsTop + (st::emojiFooterHeight - size) / 2,
|
||||||
width(),
|
width(),
|
||||||
st::stickerGroupCategorySize);
|
st::stickerGroupCategorySize);
|
||||||
|
@ -1174,7 +1197,7 @@ void StickersListFooter::paintSetIcon(
|
||||||
validatePremiumIcon();
|
validatePremiumIcon();
|
||||||
const auto size = st::stickersPremium.size();
|
const auto size = st::stickersPremium.size();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
info.adjustedLeft + (st::stickerIconWidth - size.width()) / 2,
|
info.adjustedLeft + (_singleWidth - size.width()) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
||||||
_premiumIcon);
|
_premiumIcon);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1207,12 +1230,12 @@ void StickersListFooter::paintSetIcon(
|
||||||
const auto paintOne = [&](int left, const style::icon *icon) {
|
const auto paintOne = [&](int left, const style::icon *icon) {
|
||||||
icon->paint(
|
icon->paint(
|
||||||
p,
|
p,
|
||||||
left + (st::stickerIconWidth - icon->width()) / 2,
|
left + (_singleWidth - icon->width()) / 2,
|
||||||
_iconsTop + (st::emojiFooterHeight - icon->height()) / 2,
|
_iconsTop + (st::emojiFooterHeight - icon->height()) / 2,
|
||||||
width());
|
width());
|
||||||
};
|
};
|
||||||
if (_icons[info.index].setId == AllEmojiSectionSetId()
|
if (_icons[info.index].setId == AllEmojiSectionSetId()
|
||||||
&& info.width > st::stickerIconWidth) {
|
&& info.width > _singleWidth) {
|
||||||
const auto skip = st::emojiIconSelectSkip;
|
const auto skip = st::emojiIconSelectSkip;
|
||||||
p.save();
|
p.save();
|
||||||
p.setClipRect(
|
p.setClipRect(
|
||||||
|
|
|
@ -226,11 +226,13 @@ private:
|
||||||
int _iconsLeft = 0;
|
int _iconsLeft = 0;
|
||||||
int _iconsRight = 0;
|
int _iconsRight = 0;
|
||||||
int _iconsTop = 0;
|
int _iconsTop = 0;
|
||||||
|
int _singleWidth = 0;
|
||||||
|
QPoint _areaPosition;
|
||||||
|
|
||||||
ScrollState _iconState;
|
ScrollState _iconState;
|
||||||
ScrollState _subiconState;
|
ScrollState _subiconState;
|
||||||
|
|
||||||
Ui::RoundRect _selectionBg;
|
Ui::RoundRect _selectionBg, _subselectionBg;
|
||||||
Ui::Animations::Simple _subiconsWidthAnimation;
|
Ui::Animations::Simple _subiconsWidthAnimation;
|
||||||
int _subiconsWidth = 0;
|
int _subiconsWidth = 0;
|
||||||
bool _subiconsExpanded = false;
|
bool _subiconsExpanded = false;
|
||||||
|
|
|
@ -2611,7 +2611,7 @@ void StickersListWidget::displaySet(uint64 setId) {
|
||||||
auto it = sets.find(setId);
|
auto it = sets.find(setId);
|
||||||
if (it != sets.cend()) {
|
if (it != sets.cend()) {
|
||||||
checkHideWithBox(controller()->show(
|
checkHideWithBox(controller()->show(
|
||||||
Box<StickerSetBox>(controller(), it->second->identifier()),
|
Box<StickerSetBox>(controller(), it->second.get()),
|
||||||
Ui::LayerOption::KeepOther).data());
|
Ui::LayerOption::KeepOther).data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,10 @@ bool ShowStickerSet(
|
||||||
Core::App().hideMediaView();
|
Core::App().hideMediaView();
|
||||||
controller->show(Box<StickerSetBox>(
|
controller->show(Box<StickerSetBox>(
|
||||||
controller,
|
controller,
|
||||||
StickerSetIdentifier{ .shortName = match->captured(2) }));
|
StickerSetIdentifier{ .shortName = match->captured(2) },
|
||||||
|
(match->captured(1) == "addemoji"
|
||||||
|
? Data::StickersType::Emoji
|
||||||
|
: Data::StickersType::Stickers)));
|
||||||
controller->window().activate();
|
controller->window().activate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "storage/file_download.h"
|
#include "storage/file_download.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
|
|
||||||
|
@ -97,6 +98,14 @@ StickerSetIdentifier StickersSet::identifier() const {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StickersType StickersSet::type() const {
|
||||||
|
return (flags & StickersSetFlag::Emoji)
|
||||||
|
? StickersType::Emoji
|
||||||
|
: (flags & StickersSetFlag::Masks)
|
||||||
|
? StickersType::Masks
|
||||||
|
: StickersType::Stickers;
|
||||||
|
}
|
||||||
|
|
||||||
void StickersSet::setThumbnail(const ImageWithLocation &data) {
|
void StickersSet::setThumbnail(const ImageWithLocation &data) {
|
||||||
Data::UpdateCloudFile(
|
Data::UpdateCloudFile(
|
||||||
_thumbnail,
|
_thumbnail,
|
||||||
|
|
|
@ -24,6 +24,8 @@ using SavedGifs = QVector<DocumentData*>;
|
||||||
using StickersPack = QVector<DocumentData*>;
|
using StickersPack = QVector<DocumentData*>;
|
||||||
using StickersByEmojiMap = QMap<EmojiPtr, StickersPack>;
|
using StickersByEmojiMap = QMap<EmojiPtr, StickersPack>;
|
||||||
|
|
||||||
|
enum class StickersType : uchar;
|
||||||
|
|
||||||
class StickersSet;
|
class StickersSet;
|
||||||
using StickersSets = base::flat_map<uint64, std::unique_ptr<StickersSet>>;
|
using StickersSets = base::flat_map<uint64, std::unique_ptr<StickersSet>>;
|
||||||
|
|
||||||
|
@ -81,6 +83,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] MTPInputStickerSet mtpInput() const;
|
[[nodiscard]] MTPInputStickerSet mtpInput() const;
|
||||||
[[nodiscard]] StickerSetIdentifier identifier() const;
|
[[nodiscard]] StickerSetIdentifier identifier() const;
|
||||||
|
[[nodiscard]] StickersType type() const;
|
||||||
|
|
||||||
void setThumbnail(const ImageWithLocation &data);
|
void setThumbnail(const ImageWithLocation &data);
|
||||||
|
|
||||||
|
|
|
@ -1043,7 +1043,8 @@ void GenerateItems(
|
||||||
controller->show(
|
controller->show(
|
||||||
Box<StickerSetBox>(
|
Box<StickerSetBox>(
|
||||||
controller,
|
controller,
|
||||||
Data::FromInputSet(set)),
|
Data::FromInputSet(set),
|
||||||
|
Data::StickersType::Stickers),
|
||||||
Ui::LayerOption::CloseOther);
|
Ui::LayerOption::CloseOther);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1324,7 +1324,10 @@ void AddEmojiPacksAction(
|
||||||
}
|
}
|
||||||
// Single used emoji pack.
|
// Single used emoji pack.
|
||||||
strong->show(
|
strong->show(
|
||||||
Box<StickerSetBox>(strong, packIds.front()),
|
Box<StickerSetBox>(
|
||||||
|
strong,
|
||||||
|
packIds.front(),
|
||||||
|
Data::StickersType::Emoji),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -195,7 +195,7 @@ void StickerToast::showWithTitle(const QString &title) {
|
||||||
}
|
}
|
||||||
button->setClickedCallback([=] {
|
button->setClickedCallback([=] {
|
||||||
_controller->show(
|
_controller->show(
|
||||||
Box<StickerSetBox>(_controller, _for->sticker()->set),
|
Box<StickerSetBox>(_controller, _for->sticker()->set, setType),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
hideToast();
|
hideToast();
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/text/custom_emoji_instance.h"
|
#include "ui/text/custom_emoji_instance.h"
|
||||||
|
|
||||||
#include "ui/effects/frame_generator.h"
|
#include "ui/effects/frame_generator.h"
|
||||||
|
#include "ui/ui_utility.h"
|
||||||
|
|
||||||
#include <crl/crl_async.h>
|
#include <crl/crl_async.h>
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
|
@ -647,4 +648,84 @@ 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
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/text/text_block.h"
|
#include "ui/text/text_block.h"
|
||||||
#include "base/weak_ptr.h"
|
#include "base/weak_ptr.h"
|
||||||
#include "base/bytes.h"
|
#include "base/bytes.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
class QColor;
|
class QColor;
|
||||||
class QPainter;
|
class QPainter;
|
||||||
|
@ -266,4 +267,34 @@ 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