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