mirror of https://github.com/procxx/kepka.git
Support animated stickers in suggestions.
This commit is contained in:
parent
848ea16eef
commit
0dd1b4eae6
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
@ -23,11 +24,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
|
||||||
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
FieldAutocomplete::FieldAutocomplete(QWidget *parent)
|
||||||
|
: RpWidget(parent)
|
||||||
, _scroll(this, st::mentionScroll) {
|
, _scroll(this, st::mentionScroll) {
|
||||||
_scroll->setGeometry(rect());
|
_scroll->setGeometry(rect());
|
||||||
|
|
||||||
_inner = _scroll->setOwnedWidget(object_ptr<internal::FieldAutocompleteInner>(this, &_mrows, &_hrows, &_brows, &_srows));
|
_inner = _scroll->setOwnedWidget(
|
||||||
|
object_ptr<internal::FieldAutocompleteInner>(
|
||||||
|
this,
|
||||||
|
&_mrows,
|
||||||
|
&_hrows,
|
||||||
|
&_brows,
|
||||||
|
&_srows));
|
||||||
_inner->setGeometry(rect());
|
_inner->setGeometry(rect());
|
||||||
|
|
||||||
connect(_inner, SIGNAL(mentionChosen(UserData*, FieldAutocomplete::ChooseMethod)), this, SIGNAL(mentionChosen(UserData*, FieldAutocomplete::ChooseMethod)));
|
connect(_inner, SIGNAL(mentionChosen(UserData*, FieldAutocomplete::ChooseMethod)), this, SIGNAL(mentionChosen(UserData*, FieldAutocomplete::ChooseMethod)));
|
||||||
|
@ -44,6 +52,8 @@ FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
||||||
connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged()));
|
connect(_scroll, SIGNAL(geometryChanged()), _inner, SLOT(onParentGeometryChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FieldAutocomplete::~FieldAutocomplete() = default;
|
||||||
|
|
||||||
void FieldAutocomplete::paintEvent(QPaintEvent *e) {
|
void FieldAutocomplete::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
@ -70,7 +80,12 @@ void FieldAutocomplete::showFiltered(
|
||||||
_channel = peer->asChannel();
|
_channel = peer->asChannel();
|
||||||
if (query.isEmpty()) {
|
if (query.isEmpty()) {
|
||||||
_type = Type::Mentions;
|
_type = Type::Mentions;
|
||||||
rowsUpdated(internal::MentionRows(), internal::HashtagRows(), internal::BotCommandRows(), _srows, false);
|
rowsUpdated(
|
||||||
|
internal::MentionRows(),
|
||||||
|
internal::HashtagRows(),
|
||||||
|
internal::BotCommandRows(),
|
||||||
|
base::take(_srows),
|
||||||
|
false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +123,12 @@ void FieldAutocomplete::showStickers(EmojiPtr emoji) {
|
||||||
_emoji = emoji;
|
_emoji = emoji;
|
||||||
_type = Type::Stickers;
|
_type = Type::Stickers;
|
||||||
if (!emoji) {
|
if (!emoji) {
|
||||||
rowsUpdated(_mrows, _hrows, _brows, internal::StickerRows(), false);
|
rowsUpdated(
|
||||||
|
base::take(_mrows),
|
||||||
|
base::take(_hrows),
|
||||||
|
base::take(_brows),
|
||||||
|
internal::StickerRows(),
|
||||||
|
false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +157,31 @@ inline int indexOfInFirstN(const T &v, const U &elem, int last) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal::StickerRows FieldAutocomplete::getStickerSuggestions() {
|
||||||
|
const auto list = Stickers::GetListByEmoji(
|
||||||
|
_emoji,
|
||||||
|
_stickersSeed
|
||||||
|
);
|
||||||
|
auto result = ranges::view::all(
|
||||||
|
list
|
||||||
|
) | ranges::view::transform([](not_null<DocumentData*> sticker) {
|
||||||
|
return internal::StickerSuggestion{ sticker };
|
||||||
|
}) | ranges::to_vector;
|
||||||
|
for (auto &suggestion : _srows) {
|
||||||
|
if (!suggestion.animated) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto i = ranges::find(
|
||||||
|
result,
|
||||||
|
suggestion.document,
|
||||||
|
&internal::StickerSuggestion::document);
|
||||||
|
if (i != end(result)) {
|
||||||
|
i->animated = std::move(suggestion.animated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||||
int32 now = unixtime(), recentInlineBots = 0;
|
int32 now = unixtime(), recentInlineBots = 0;
|
||||||
internal::MentionRows mrows;
|
internal::MentionRows mrows;
|
||||||
|
@ -144,7 +189,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||||
internal::BotCommandRows brows;
|
internal::BotCommandRows brows;
|
||||||
internal::StickerRows srows;
|
internal::StickerRows srows;
|
||||||
if (_emoji) {
|
if (_emoji) {
|
||||||
srows = Stickers::GetListByEmoji(_emoji, _stickersSeed);
|
srows = getStickerSuggestions();
|
||||||
} else if (_type == Type::Mentions) {
|
} else if (_type == Type::Mentions) {
|
||||||
int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0;
|
int maxListSize = _addInlineBots ? cRecentInlineBots().size() : 0;
|
||||||
if (_chat) {
|
if (_chat) {
|
||||||
|
@ -326,11 +371,21 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rowsUpdated(mrows, hrows, brows, srows, resetScroll);
|
rowsUpdated(
|
||||||
|
std::move(mrows),
|
||||||
|
std::move(hrows),
|
||||||
|
std::move(brows),
|
||||||
|
std::move(srows),
|
||||||
|
resetScroll);
|
||||||
_inner->setRecentInlineBotsInRows(recentInlineBots);
|
_inner->setRecentInlineBotsInRows(recentInlineBots);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const internal::StickerRows &srows, bool resetScroll) {
|
void FieldAutocomplete::rowsUpdated(
|
||||||
|
internal::MentionRows &&mrows,
|
||||||
|
internal::HashtagRows &&hrows,
|
||||||
|
internal::BotCommandRows &&brows,
|
||||||
|
internal::StickerRows &&srows,
|
||||||
|
bool resetScroll) {
|
||||||
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.empty()) {
|
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.empty()) {
|
||||||
if (!isHidden()) {
|
if (!isHidden()) {
|
||||||
hideAnimated();
|
hideAnimated();
|
||||||
|
@ -341,10 +396,10 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in
|
||||||
_brows.clear();
|
_brows.clear();
|
||||||
_srows.clear();
|
_srows.clear();
|
||||||
} else {
|
} else {
|
||||||
_mrows = mrows;
|
_mrows = std::move(mrows);
|
||||||
_hrows = hrows;
|
_hrows = std::move(hrows);
|
||||||
_brows = brows;
|
_brows = std::move(brows);
|
||||||
_srows = srows;
|
_srows = std::move(srows);
|
||||||
|
|
||||||
bool hidden = _hiding || isHidden();
|
bool hidden = _hiding || isHidden();
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
|
@ -358,6 +413,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in
|
||||||
showAnimated();
|
showAnimated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_inner->rowsUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::setBoundings(QRect boundings) {
|
void FieldAutocomplete::setBoundings(QRect boundings) {
|
||||||
|
@ -505,12 +561,14 @@ bool FieldAutocomplete::eventFilter(QObject *obj, QEvent *e) {
|
||||||
return QWidget::eventFilter(obj, e);
|
return QWidget::eventFilter(obj, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldAutocomplete::~FieldAutocomplete() {
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
FieldAutocompleteInner::FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerRows *srows)
|
FieldAutocompleteInner::FieldAutocompleteInner(
|
||||||
|
not_null<FieldAutocomplete*> parent,
|
||||||
|
not_null<MentionRows*> mrows,
|
||||||
|
not_null<HashtagRows*> hrows,
|
||||||
|
not_null<BotCommandRows*> brows,
|
||||||
|
not_null<StickerRows*> srows)
|
||||||
: _parent(parent)
|
: _parent(parent)
|
||||||
, _mrows(mrows)
|
, _mrows(mrows)
|
||||||
, _hrows(hrows)
|
, _hrows(hrows)
|
||||||
|
@ -551,9 +609,16 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||||
int32 index = row * _stickersPerRow + col;
|
int32 index = row * _stickersPerRow + col;
|
||||||
if (index >= _srows->size()) break;
|
if (index >= _srows->size()) break;
|
||||||
|
|
||||||
const auto document = _srows->at(index);
|
auto &sticker = (*_srows)[index];
|
||||||
|
const auto document = sticker.document;
|
||||||
if (!document->sticker()) continue;
|
if (!document->sticker()) continue;
|
||||||
|
|
||||||
|
if (document->sticker()->animated
|
||||||
|
&& !sticker.animated
|
||||||
|
&& document->loaded()) {
|
||||||
|
setupLottie(sticker);
|
||||||
|
}
|
||||||
|
|
||||||
QPoint pos(st::stickerPanPadding + col * st::stickerPanSize.width(), st::stickerPanPadding + row * st::stickerPanSize.height());
|
QPoint pos(st::stickerPanPadding + col * st::stickerPanSize.width(), st::stickerPanPadding + row * st::stickerPanSize.height());
|
||||||
if (_sel == index) {
|
if (_sel == index) {
|
||||||
QPoint tl(pos);
|
QPoint tl(pos);
|
||||||
|
@ -562,14 +627,23 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
document->checkStickerSmall();
|
document->checkStickerSmall();
|
||||||
|
if (sticker.animated && sticker.animated->ready()) {
|
||||||
float64 coef = qMin((st::stickerPanSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (st::stickerPanSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height()));
|
const auto frame = sticker.animated->frame();
|
||||||
if (coef > 1) coef = 1;
|
sticker.animated->markFrameShown();
|
||||||
int32 w = qRound(coef * document->dimensions.width()), h = qRound(coef * document->dimensions.height());
|
const auto size = frame.size() / cIntRetinaFactor();
|
||||||
if (w < 1) w = 1;
|
const auto ppos = pos + QPoint(
|
||||||
if (h < 1) h = 1;
|
(st::stickerPanSize.width() - size.width()) / 2,
|
||||||
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
(st::stickerPanSize.height() - size.height()) / 2);
|
||||||
if (const auto image = document->getStickerSmall()) {
|
p.drawImage(
|
||||||
|
QRect(ppos, size),
|
||||||
|
frame);
|
||||||
|
} else if (const auto image = document->getStickerSmall()) {
|
||||||
|
float64 coef = qMin((st::stickerPanSize.width() - st::buttonRadius * 2) / float64(document->dimensions.width()), (st::stickerPanSize.height() - st::buttonRadius * 2) / float64(document->dimensions.height()));
|
||||||
|
if (coef > 1) coef = 1;
|
||||||
|
int32 w = qRound(coef * document->dimensions.width()), h = qRound(coef * document->dimensions.height());
|
||||||
|
if (w < 1) w = 1;
|
||||||
|
if (h < 1) h = 1;
|
||||||
|
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||||
p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h));
|
p.drawPixmapLeft(ppos, width(), image->pix(document->stickerSetOrigin(), w, h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -742,7 +816,7 @@ bool FieldAutocompleteInner::moveSel(int key) {
|
||||||
bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const {
|
bool FieldAutocompleteInner::chooseSelected(FieldAutocomplete::ChooseMethod method) const {
|
||||||
if (!_srows->empty()) {
|
if (!_srows->empty()) {
|
||||||
if (_sel >= 0 && _sel < _srows->size()) {
|
if (_sel >= 0 && _sel < _srows->size()) {
|
||||||
emit stickerChosen((*_srows)[_sel], method);
|
emit stickerChosen((*_srows)[_sel].document, method);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!_mrows->isEmpty()) {
|
} else if (!_mrows->isEmpty()) {
|
||||||
|
@ -872,6 +946,58 @@ void FieldAutocompleteInner::setSel(int sel, bool scroll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FieldAutocompleteInner::rowsUpdated() {
|
||||||
|
if (_srows->empty()) {
|
||||||
|
_stickersLifetime.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FieldAutocompleteInner::getLottieRenderer()
|
||||||
|
-> std::shared_ptr<Lottie::FrameRenderer> {
|
||||||
|
if (auto result = _lottieRenderer.lock()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto result = Lottie::MakeFrameRenderer();
|
||||||
|
_lottieRenderer = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldAutocompleteInner::setupLottie(StickerSuggestion &suggestion) {
|
||||||
|
const auto document = suggestion.document;
|
||||||
|
suggestion.animated = Stickers::LottiePlayerFromDocument(
|
||||||
|
document,
|
||||||
|
Stickers::LottieSize::InlineResults,
|
||||||
|
QSize(
|
||||||
|
st::stickerPanSize.width() - st::buttonRadius * 2,
|
||||||
|
st::stickerPanSize.height() - st::buttonRadius * 2
|
||||||
|
) * cIntRetinaFactor(),
|
||||||
|
getLottieRenderer());
|
||||||
|
|
||||||
|
suggestion.animated->updates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
repaintSticker(document);
|
||||||
|
}, _stickersLifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldAutocompleteInner::repaintSticker(
|
||||||
|
not_null<DocumentData*> document) {
|
||||||
|
const auto i = ranges::find(
|
||||||
|
*_srows,
|
||||||
|
document,
|
||||||
|
&StickerSuggestion::document);
|
||||||
|
if (i == end(*_srows)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto index = (i - begin(*_srows));
|
||||||
|
const auto row = (index / _stickersPerRow);
|
||||||
|
const auto col = (index % _stickersPerRow);
|
||||||
|
update(
|
||||||
|
st::stickerPanPadding + col * st::stickerPanSize.width(),
|
||||||
|
st::stickerPanPadding + row * st::stickerPanSize.height(),
|
||||||
|
st::stickerPanSize.width(),
|
||||||
|
st::stickerPanSize.height());
|
||||||
|
}
|
||||||
|
|
||||||
void FieldAutocompleteInner::selectByMouse(QPoint globalPosition) {
|
void FieldAutocompleteInner::selectByMouse(QPoint globalPosition) {
|
||||||
_mouseSelection = true;
|
_mouseSelection = true;
|
||||||
_lastMousePosition = globalPosition;
|
_lastMousePosition = globalPosition;
|
||||||
|
@ -905,8 +1031,8 @@ void FieldAutocompleteInner::selectByMouse(QPoint globalPosition) {
|
||||||
_down = _sel;
|
_down = _sel;
|
||||||
if (_down >= 0 && _down < _srows->size()) {
|
if (_down >= 0 && _down < _srows->size()) {
|
||||||
Ui::showMediaPreview(
|
Ui::showMediaPreview(
|
||||||
(*_srows)[_down]->stickerSetOrigin(),
|
(*_srows)[_down].document->stickerSetOrigin(),
|
||||||
(*_srows)[_down]);
|
(*_srows)[_down].document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,8 +1051,8 @@ void FieldAutocompleteInner::onParentGeometryChanged() {
|
||||||
void FieldAutocompleteInner::showPreview() {
|
void FieldAutocompleteInner::showPreview() {
|
||||||
if (_down >= 0 && _down < _srows->size()) {
|
if (_down >= 0 && _down < _srows->size()) {
|
||||||
Ui::showMediaPreview(
|
Ui::showMediaPreview(
|
||||||
(*_srows)[_down]->stickerSetOrigin(),
|
(*_srows)[_down].document->stickerSetOrigin(),
|
||||||
(*_srows)[_down]);
|
(*_srows)[_down].document);
|
||||||
_previewShown = true;
|
_previewShown = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "ui/twidget.h"
|
#include "ui/rp_widget.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
#include "chat_helpers/stickers.h"
|
#include "chat_helpers/stickers.h"
|
||||||
|
|
||||||
|
@ -16,22 +16,33 @@ namespace Ui {
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Lottie {
|
||||||
|
class SinglePlayer;
|
||||||
|
class FrameRenderer;
|
||||||
|
} // namespace Lottie;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
struct StickerSuggestion {
|
||||||
|
not_null<DocumentData*> document;
|
||||||
|
std::unique_ptr<Lottie::SinglePlayer> animated;
|
||||||
|
};
|
||||||
|
|
||||||
using MentionRows = QList<UserData*>;
|
using MentionRows = QList<UserData*>;
|
||||||
using HashtagRows = QList<QString>;
|
using HashtagRows = QList<QString>;
|
||||||
using BotCommandRows = QList<QPair<UserData*, const BotCommand*>>;
|
using BotCommandRows = QList<QPair<UserData*, const BotCommand*>>;
|
||||||
using StickerRows = std::vector<not_null<DocumentData*>>;
|
using StickerRows = std::vector<StickerSuggestion>;
|
||||||
|
|
||||||
class FieldAutocompleteInner;
|
class FieldAutocompleteInner;
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
class FieldAutocomplete final : public TWidget {
|
class FieldAutocomplete final : public Ui::RpWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FieldAutocomplete(QWidget *parent);
|
FieldAutocomplete(QWidget *parent);
|
||||||
|
~FieldAutocomplete();
|
||||||
|
|
||||||
bool clearFilteredBotCommands();
|
bool clearFilteredBotCommands();
|
||||||
void showFiltered(
|
void showFiltered(
|
||||||
|
@ -70,8 +81,6 @@ public:
|
||||||
|
|
||||||
void hideFast();
|
void hideFast();
|
||||||
|
|
||||||
~FieldAutocomplete();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const;
|
void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const;
|
||||||
void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const;
|
void hashtagChosen(QString hashtag, FieldAutocomplete::ChooseMethod method) const;
|
||||||
|
@ -93,6 +102,7 @@ private:
|
||||||
|
|
||||||
void updateFiltered(bool resetScroll = false);
|
void updateFiltered(bool resetScroll = false);
|
||||||
void recount(bool resetScroll = false);
|
void recount(bool resetScroll = false);
|
||||||
|
internal::StickerRows getStickerSuggestions();
|
||||||
|
|
||||||
QPixmap _cache;
|
QPixmap _cache;
|
||||||
internal::MentionRows _mrows;
|
internal::MentionRows _mrows;
|
||||||
|
@ -100,7 +110,12 @@ private:
|
||||||
internal::BotCommandRows _brows;
|
internal::BotCommandRows _brows;
|
||||||
internal::StickerRows _srows;
|
internal::StickerRows _srows;
|
||||||
|
|
||||||
void rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const internal::StickerRows &srows, bool resetScroll);
|
void rowsUpdated(
|
||||||
|
internal::MentionRows &&mrows,
|
||||||
|
internal::HashtagRows &&hrows,
|
||||||
|
internal::BotCommandRows &&brows,
|
||||||
|
internal::StickerRows &&srows,
|
||||||
|
bool resetScroll);
|
||||||
|
|
||||||
object_ptr<Ui::ScrollArea> _scroll;
|
object_ptr<Ui::ScrollArea> _scroll;
|
||||||
QPointer<internal::FieldAutocompleteInner> _inner;
|
QPointer<internal::FieldAutocompleteInner> _inner;
|
||||||
|
@ -132,17 +147,25 @@ private:
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
class FieldAutocompleteInner final : public TWidget, private base::Subscriber {
|
class FieldAutocompleteInner final
|
||||||
|
: public Ui::RpWidget
|
||||||
|
, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FieldAutocompleteInner(FieldAutocomplete *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerRows *srows);
|
FieldAutocompleteInner(
|
||||||
|
not_null<FieldAutocomplete*> parent,
|
||||||
|
not_null<MentionRows*> mrows,
|
||||||
|
not_null<HashtagRows*> hrows,
|
||||||
|
not_null<BotCommandRows*> brows,
|
||||||
|
not_null<StickerRows*> srows);
|
||||||
|
|
||||||
void clearSel(bool hidden = false);
|
void clearSel(bool hidden = false);
|
||||||
bool moveSel(int key);
|
bool moveSel(int key);
|
||||||
bool chooseSelected(FieldAutocomplete::ChooseMethod method) const;
|
bool chooseSelected(FieldAutocomplete::ChooseMethod method) const;
|
||||||
|
|
||||||
void setRecentInlineBotsInRows(int32 bots);
|
void setRecentInlineBotsInRows(int32 bots);
|
||||||
|
void rowsUpdated();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const;
|
void mentionChosen(UserData *user, FieldAutocomplete::ChooseMethod method) const;
|
||||||
|
@ -170,11 +193,17 @@ private:
|
||||||
void showPreview();
|
void showPreview();
|
||||||
void selectByMouse(QPoint global);
|
void selectByMouse(QPoint global);
|
||||||
|
|
||||||
FieldAutocomplete *_parent = nullptr;
|
void setupLottie(StickerSuggestion &suggestion);
|
||||||
MentionRows *_mrows = nullptr;
|
void repaintSticker(not_null<DocumentData*> document);
|
||||||
HashtagRows *_hrows = nullptr;
|
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
|
||||||
BotCommandRows *_brows = nullptr;
|
|
||||||
StickerRows *_srows = nullptr;
|
not_null<FieldAutocomplete*> _parent;
|
||||||
|
not_null<MentionRows*> _mrows;
|
||||||
|
not_null<HashtagRows*> _hrows;
|
||||||
|
not_null<BotCommandRows*> _brows;
|
||||||
|
not_null<StickerRows*> _srows;
|
||||||
|
rpl::lifetime _stickersLifetime;
|
||||||
|
std::weak_ptr<Lottie::FrameRenderer> _lottieRenderer;
|
||||||
int _stickersPerRow = 1;
|
int _stickersPerRow = 1;
|
||||||
int _recentInlineBotsInRows = 0;
|
int _recentInlineBotsInRows = 0;
|
||||||
int _sel = -1;
|
int _sel = -1;
|
||||||
|
|
|
@ -1154,10 +1154,11 @@ auto LottieFromDocument(
|
||||||
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
LottieSize sizeTag,
|
LottieSize sizeTag,
|
||||||
QSize box) {
|
QSize box,
|
||||||
const auto method = [](auto &&...args) {
|
std::shared_ptr<Lottie::FrameRenderer> renderer) {
|
||||||
|
const auto method = [&](auto &&...args) {
|
||||||
return std::make_unique<Lottie::SinglePlayer>(
|
return std::make_unique<Lottie::SinglePlayer>(
|
||||||
std::forward<decltype(args)>(args)...);
|
std::forward<decltype(args)>(args)..., std::move(renderer));
|
||||||
};
|
};
|
||||||
return LottieFromDocument(method, document, sizeTag, box);
|
return LottieFromDocument(method, document, sizeTag, box);
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,8 @@ enum class LottieSize : uchar {
|
||||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
LottieSize sizeTag,
|
LottieSize sizeTag,
|
||||||
QSize box);
|
QSize box,
|
||||||
|
std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr);
|
||||||
[[nodiscard]] not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
[[nodiscard]] not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
||||||
not_null<Lottie::MultiPlayer*> player,
|
not_null<Lottie::MultiPlayer*> player,
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
|
|
|
@ -129,6 +129,10 @@ std::unique_ptr<rlottie::Animation> CreateFromContent(
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
|
std::shared_ptr<FrameRenderer> MakeFrameRenderer() {
|
||||||
|
return FrameRenderer::CreateIndependent();
|
||||||
|
}
|
||||||
|
|
||||||
QImage ReadThumbnail(const QByteArray &content) {
|
QImage ReadThumbnail(const QByteArray &content) {
|
||||||
return Init(content, FrameRequest()).match([](
|
return Init(content, FrameRequest()).match([](
|
||||||
const std::unique_ptr<SharedState> &state) {
|
const std::unique_ptr<SharedState> &state) {
|
||||||
|
|
|
@ -22,6 +22,9 @@ namespace Lottie {
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class SharedState;
|
class SharedState;
|
||||||
|
class FrameRenderer;
|
||||||
|
|
||||||
|
std::shared_ptr<FrameRenderer> MakeFrameRenderer();
|
||||||
|
|
||||||
QImage ReadThumbnail(const QByteArray &content);
|
QImage ReadThumbnail(const QByteArray &content);
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
|
|
||||||
std::shared_ptr<FrameRenderer> MakeFrameRenderer() {
|
|
||||||
return FrameRenderer::CreateIndependent();
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiPlayer::MultiPlayer(std::shared_ptr<FrameRenderer> renderer)
|
MultiPlayer::MultiPlayer(std::shared_ptr<FrameRenderer> renderer)
|
||||||
: _timer([=] { checkNextFrameRender(); })
|
: _timer([=] { checkNextFrameRender(); })
|
||||||
, _renderer(renderer ? std::move(renderer) : FrameRenderer::Instance()) {
|
, _renderer(renderer ? std::move(renderer) : FrameRenderer::Instance()) {
|
||||||
|
|
|
@ -27,8 +27,6 @@ struct MultiUpdate {
|
||||||
// std::pair<Animation*, Error>> data;
|
// std::pair<Animation*, Error>> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<FrameRenderer> MakeFrameRenderer();
|
|
||||||
|
|
||||||
class MultiPlayer final : public Player {
|
class MultiPlayer final : public Player {
|
||||||
public:
|
public:
|
||||||
explicit MultiPlayer(std::shared_ptr<FrameRenderer> renderer = nullptr);
|
explicit MultiPlayer(std::shared_ptr<FrameRenderer> renderer = nullptr);
|
||||||
|
|
Loading…
Reference in New Issue