mirror of https://github.com/procxx/kepka.git
Show animated thumbnails in sets box.
This commit is contained in:
parent
3b645422ff
commit
76630528f7
|
@ -559,14 +559,12 @@ void StickerSetBox::Inner::paintSticker(
|
||||||
if (h < 1) h = 1;
|
if (h < 1) h = 1;
|
||||||
QPoint ppos = position + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
|
QPoint ppos = position + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
|
||||||
if (element.animated && element.animated->ready()) {
|
if (element.animated && element.animated->ready()) {
|
||||||
auto request = Lottie::FrameRequest();
|
|
||||||
request.box = boundingBoxSize() * cIntRetinaFactor();
|
|
||||||
const auto paused = _controller->isGifPausedAtLeastFor(
|
const auto paused = _controller->isGifPausedAtLeastFor(
|
||||||
Window::GifPauseReason::Layer);
|
Window::GifPauseReason::Layer);
|
||||||
if (!paused) {
|
if (!paused) {
|
||||||
element.animated->markFrameShown();
|
element.animated->markFrameShown();
|
||||||
}
|
}
|
||||||
const auto frame = element.animated->frame(request);
|
const auto frame = element.animated->frame();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
QRect(ppos, frame.size() / cIntRetinaFactor()),
|
QRect(ppos, frame.size() / cIntRetinaFactor()),
|
||||||
frame);
|
frame);
|
||||||
|
|
|
@ -20,8 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "dialogs/dialogs_layout.h"
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
@ -31,7 +30,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/widgets/discrete_sliders.h"
|
#include "ui/widgets/discrete_sliders.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_chat_helpers.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -655,7 +657,8 @@ StickersBox::Inner::Row::Row(
|
||||||
|
|
||||||
StickersBox::Inner::Row::~Row() = default;
|
StickersBox::Inner::Row::~Row() = default;
|
||||||
|
|
||||||
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent)
|
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section)
|
||||||
|
: RpWidget(parent)
|
||||||
, _section(section)
|
, _section(section)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _shiftingAnimation([=](crl::time now) {
|
, _shiftingAnimation([=](crl::time now) {
|
||||||
|
@ -669,7 +672,8 @@ StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidg
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
StickersBox::Inner::Inner(QWidget *parent, not_null<ChannelData*> megagroup) : TWidget(parent)
|
StickersBox::Inner::Inner(QWidget *parent, not_null<ChannelData*> megagroup)
|
||||||
|
: RpWidget(parent)
|
||||||
, _section(StickersBox::Section::Installed)
|
, _section(StickersBox::Section::Installed)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _shiftingAnimation([=](crl::time now) {
|
, _shiftingAnimation([=](crl::time now) {
|
||||||
|
@ -794,7 +798,7 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
|
||||||
return QRect(buttonx, buttony, buttonw, buttonh);
|
return QRect(buttonx, buttony, buttonw, buttonh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersBox::Inner::paintRow(Painter &p, Row *set, int index) {
|
void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
|
||||||
auto xadd = 0, yadd = qRound(set->yadd.current());
|
auto xadd = 0, yadd = qRound(set->yadd.current());
|
||||||
if (xadd || yadd) p.translate(xadd, yadd);
|
if (xadd || yadd) p.translate(xadd, yadd);
|
||||||
|
|
||||||
|
@ -854,17 +858,7 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set->sticker) {
|
if (set->sticker) {
|
||||||
const auto origin = Data::FileOriginStickerSet(
|
paintRowThumbnail(p, set, stickerx);
|
||||||
set->id,
|
|
||||||
set->accessHash);
|
|
||||||
const auto thumb = set->thumbnail
|
|
||||||
? set->thumbnail.get()
|
|
||||||
: set->sticker->thumbnail();
|
|
||||||
if (thumb) {
|
|
||||||
thumb->load(origin);
|
|
||||||
auto pix = thumb->pix(origin, set->pixw, set->pixh);
|
|
||||||
p.drawPixmapLeft(stickerx + (st::contactsPhotoSize - set->pixw) / 2, st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2, width(), pix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left();
|
int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left();
|
||||||
|
@ -897,7 +891,97 @@ void StickersBox::Inner::paintRow(Painter &p, Row *set, int index) {
|
||||||
if (xadd || yadd) p.translate(-xadd, -yadd);
|
if (xadd || yadd) p.translate(-xadd, -yadd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StickersBox::Inner::paintFakeButton(Painter &p, Row *set, int index) {
|
void StickersBox::Inner::paintRowThumbnail(
|
||||||
|
Painter &p,
|
||||||
|
not_null<Row*> set,
|
||||||
|
int left) {
|
||||||
|
const auto origin = Data::FileOriginStickerSet(
|
||||||
|
set->id,
|
||||||
|
set->accessHash);
|
||||||
|
const auto thumb = set->thumbnail
|
||||||
|
? set->thumbnail.get()
|
||||||
|
: set->sticker->thumbnail();
|
||||||
|
if (!thumb) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thumb->load(origin);
|
||||||
|
validateLottieAnimation(set);
|
||||||
|
if (!set->lottie) {
|
||||||
|
if (!thumb->loaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p.drawPixmapLeft(
|
||||||
|
left + (st::contactsPhotoSize - set->pixw) / 2,
|
||||||
|
st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2,
|
||||||
|
width(),
|
||||||
|
thumb->pix(origin, set->pixw, set->pixh));
|
||||||
|
} else if (set->lottie->ready()) {
|
||||||
|
const auto frame = set->lottie->frame();
|
||||||
|
const auto size = frame.size() / cIntRetinaFactor();
|
||||||
|
p.drawImage(
|
||||||
|
QRect(
|
||||||
|
left + (st::contactsPhotoSize - size.width()) / 2,
|
||||||
|
st::contactsPadding.top() + (st::contactsPhotoSize - size.height()) / 2,
|
||||||
|
size.width(),
|
||||||
|
size.height()),
|
||||||
|
frame);
|
||||||
|
const auto controller = App::wnd()->sessionController();
|
||||||
|
const auto paused = controller->isGifPausedAtLeastFor(
|
||||||
|
Window::GifPauseReason::Layer);
|
||||||
|
if (!paused) {
|
||||||
|
set->lottie->markFrameShown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickersBox::Inner::validateLottieAnimation(not_null<Row*> set) {
|
||||||
|
if (set->lottie
|
||||||
|
|| !Stickers::HasLottieThumbnail(set->thumbnail, set->sticker)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto player = Stickers::LottieThumbnail(
|
||||||
|
set->thumbnail,
|
||||||
|
set->sticker,
|
||||||
|
Stickers::LottieSize::SetsListThumbnail,
|
||||||
|
QSize(
|
||||||
|
st::contactsPhotoSize,
|
||||||
|
st::contactsPhotoSize) * cIntRetinaFactor());
|
||||||
|
if (!player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set->lottie = std::move(player);
|
||||||
|
set->lottie->updates(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateRowThumbnail(set);
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickersBox::Inner::updateRowThumbnail(not_null<Row*> set) {
|
||||||
|
const auto rowTop = [&] {
|
||||||
|
if (set == _megagroupSelectedSet.get()) {
|
||||||
|
return _megagroupDivider->y() - _rowHeight;
|
||||||
|
}
|
||||||
|
auto top = _itemsTop;
|
||||||
|
for (const auto &row : _rows) {
|
||||||
|
if (row.get() == set) {
|
||||||
|
return top + qRound(row->yadd.current());
|
||||||
|
}
|
||||||
|
top += _rowHeight;
|
||||||
|
}
|
||||||
|
Unexpected("StickersBox::Inner::updateRowThumbnail: row not found");
|
||||||
|
}();
|
||||||
|
const auto left = st::contactsPadding.left()
|
||||||
|
+ ((!_megagroupSet && _section == Section::Installed)
|
||||||
|
? st::stickersReorderIcon.width() + st::stickersReorderSkip
|
||||||
|
: 0);
|
||||||
|
update(
|
||||||
|
left,
|
||||||
|
rowTop + st::contactsPadding.top(),
|
||||||
|
st::contactsPhotoSize,
|
||||||
|
st::contactsPhotoSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> set, int index) {
|
||||||
auto removeButton = (_section == Section::Installed && !set->removed);
|
auto removeButton = (_section == Section::Installed && !set->removed);
|
||||||
auto rect = relativeButtonRect(removeButton);
|
auto rect = relativeButtonRect(removeButton);
|
||||||
if (_section != Section::Installed && set->installed && !set->archived && !set->removed) {
|
if (_section != Section::Installed && set->installed && !set->archived && !set->removed) {
|
||||||
|
@ -1535,16 +1619,22 @@ void StickersBox::Inner::updateSize(int newWidth) {
|
||||||
void StickersBox::Inner::updateRows() {
|
void StickersBox::Inner::updateRows() {
|
||||||
int maxNameWidth = countMaxNameWidth();
|
int maxNameWidth = countMaxNameWidth();
|
||||||
auto &sets = Auth().data().stickerSets();
|
auto &sets = Auth().data().stickerSets();
|
||||||
for_const (auto &row, _rows) {
|
for (const auto &row : _rows) {
|
||||||
auto it = sets.constFind(row->id);
|
const auto it = sets.constFind(row->id);
|
||||||
if (it != sets.cend()) {
|
if (it == sets.cend()) {
|
||||||
auto &set = it.value();
|
continue;
|
||||||
|
}
|
||||||
|
const auto &set = it.value();
|
||||||
if (!row->sticker) {
|
if (!row->sticker) {
|
||||||
auto thumbnail = ImagePtr();
|
auto thumbnail = ImagePtr();
|
||||||
auto sticker = (DocumentData*)nullptr;
|
auto sticker = (DocumentData*)nullptr;
|
||||||
auto pixw = 0, pixh = 0;
|
auto pixw = 0, pixh = 0;
|
||||||
fillSetCover(set, &thumbnail, &sticker, &pixw, &pixh);
|
fillSetCover(set, &thumbnail, &sticker, &pixw, &pixh);
|
||||||
if (sticker) {
|
if (sticker) {
|
||||||
|
if ((row->thumbnail.get() != thumbnail.get())
|
||||||
|
|| (!thumbnail && row->sticker != sticker)) {
|
||||||
|
row->lottie = nullptr;
|
||||||
|
}
|
||||||
row->thumbnail = thumbnail;
|
row->thumbnail = thumbnail;
|
||||||
row->sticker = sticker;
|
row->sticker = sticker;
|
||||||
row->pixw = pixw;
|
row->pixw = pixw;
|
||||||
|
@ -1565,7 +1655,6 @@ void StickersBox::Inner::updateRows() {
|
||||||
row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth);
|
row->title = fillSetTitle(set, maxNameWidth, &row->titleWidth);
|
||||||
row->count = fillSetCount(set);
|
row->count = fillSetCount(set);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,10 @@ private:
|
||||||
int stickerPacksCount(bool includeArchivedOfficial = false);
|
int stickerPacksCount(bool includeArchivedOfficial = false);
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class StickersBox::Inner : public TWidget, private base::Subscriber, private MTP::Sender {
|
class StickersBox::Inner
|
||||||
|
: public Ui::RpWidget
|
||||||
|
, private base::Subscriber
|
||||||
|
, private MTP::Sender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -233,6 +236,7 @@ private:
|
||||||
int32 pixh = 0;
|
int32 pixh = 0;
|
||||||
anim::value yadd;
|
anim::value yadd;
|
||||||
std::unique_ptr<Ui::RippleAnimation> ripple;
|
std::unique_ptr<Ui::RippleAnimation> ripple;
|
||||||
|
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||||
};
|
};
|
||||||
struct MegagroupSet {
|
struct MegagroupSet {
|
||||||
inline bool operator==(const MegagroupSet &other) const {
|
inline bool operator==(const MegagroupSet &other) const {
|
||||||
|
@ -272,11 +276,14 @@ private:
|
||||||
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
|
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
|
||||||
|
|
||||||
bool shiftingAnimationCallback(crl::time now);
|
bool shiftingAnimationCallback(crl::time now);
|
||||||
void paintRow(Painter &p, Row *set, int index);
|
void paintRow(Painter &p, not_null<Row*> set, int index);
|
||||||
void paintFakeButton(Painter &p, Row *set, int index);
|
void paintRowThumbnail(Painter &p, not_null<Row*> set, int left);
|
||||||
|
void paintFakeButton(Painter &p, not_null<Row*> set, int index);
|
||||||
void clear();
|
void clear();
|
||||||
void setActionSel(int32 actionSel);
|
void setActionSel(int32 actionSel);
|
||||||
float64 aboveShadowOpacity() const;
|
float64 aboveShadowOpacity() const;
|
||||||
|
void validateLottieAnimation(not_null<Row*> set);
|
||||||
|
void updateRowThumbnail(not_null<Row*> set);
|
||||||
|
|
||||||
void readVisibleSets();
|
void readVisibleSets();
|
||||||
|
|
||||||
|
|
|
@ -710,11 +710,11 @@ QSize StickersListWidget::Footer::iconBox() const {
|
||||||
void StickersListWidget::Footer::validateIconLottieAnimation(
|
void StickersListWidget::Footer::validateIconLottieAnimation(
|
||||||
const StickerIcon &icon) {
|
const StickerIcon &icon) {
|
||||||
if (icon.lottie
|
if (icon.lottie
|
||||||
|| !Stickers::HasLottieThumbnail(ImagePtr(), icon.sticker)) {
|
|| !Stickers::HasLottieThumbnail(icon.thumbnail, icon.sticker)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto player = Stickers::LottieThumbnail(
|
auto player = Stickers::LottieThumbnail(
|
||||||
ImagePtr(),
|
icon.thumbnail,
|
||||||
icon.sticker,
|
icon.sticker,
|
||||||
Stickers::LottieSize::StickersFooter,
|
Stickers::LottieSize::StickersFooter,
|
||||||
iconBox() * cIntRetinaFactor(),
|
iconBox() * cIntRetinaFactor(),
|
||||||
|
@ -757,14 +757,16 @@ void StickersListWidget::Footer::paintSetIcon(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
thumb->load(origin);
|
thumb->load(origin);
|
||||||
|
const_cast<Footer*>(this)->validateIconLottieAnimation(icon);
|
||||||
|
if (!icon.lottie) {
|
||||||
if (!thumb->loaded()) {
|
if (!thumb->loaded()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const_cast<Footer*>(this)->validateIconLottieAnimation(icon);
|
p.drawPixmapLeft(
|
||||||
if (!icon.lottie) {
|
x + (st::stickerIconWidth - icon.pixw) / 2,
|
||||||
auto pix = thumb->pix(origin, icon.pixw, icon.pixh);
|
_iconsTop + (st::emojiFooterHeight - icon.pixh) / 2,
|
||||||
|
width(),
|
||||||
p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix);
|
thumb->pix(origin, icon.pixw, icon.pixh));
|
||||||
} else if (icon.lottie->ready()) {
|
} else if (icon.lottie->ready()) {
|
||||||
auto request = Lottie::FrameRequest();
|
auto request = Lottie::FrameRequest();
|
||||||
request.box = iconBox() * cIntRetinaFactor();
|
request.box = iconBox() * cIntRetinaFactor();
|
||||||
|
|
|
@ -192,6 +192,12 @@ void Animation::parseFailed(Error error) {
|
||||||
_player->failed(this, error);
|
_player->failed(this, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage Animation::frame() const {
|
||||||
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
|
return PrepareFrameByRequest(_state->frameForPaint(), true);
|
||||||
|
}
|
||||||
|
|
||||||
QImage Animation::frame(const FrameRequest &request) const {
|
QImage Animation::frame(const FrameRequest &request) const {
|
||||||
Expects(_state != nullptr);
|
Expects(_state != nullptr);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ public:
|
||||||
const FrameRequest &request);
|
const FrameRequest &request);
|
||||||
|
|
||||||
[[nodiscard]] bool ready() const;
|
[[nodiscard]] bool ready() const;
|
||||||
|
[[nodiscard]] QImage frame() const;
|
||||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -68,6 +68,10 @@ bool SinglePlayer::ready() const {
|
||||||
return _animation.ready();
|
return _animation.ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage SinglePlayer::frame() const {
|
||||||
|
return _animation.frame();
|
||||||
|
}
|
||||||
|
|
||||||
QImage SinglePlayer::frame(const FrameRequest &request) const {
|
QImage SinglePlayer::frame(const FrameRequest &request) const {
|
||||||
return _animation.frame(request);
|
return _animation.frame(request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
rpl::producer<Update, Error> updates() const;
|
rpl::producer<Update, Error> updates() const;
|
||||||
|
|
||||||
[[nodiscard]] bool ready() const;
|
[[nodiscard]] bool ready() const;
|
||||||
|
[[nodiscard]] QImage frame() const;
|
||||||
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
[[nodiscard]] QImage frame(const FrameRequest &request) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue