mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Support webm stickers in field autocomplete.
This commit is contained in:
parent
f45c47f3d5
commit
d96a8d028a
2 changed files with 92 additions and 47 deletions
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "media/clip/media_clip_reader.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/input_fields.h"
|
||||
|
@ -102,8 +103,13 @@ private:
|
|||
|
||||
QSize stickerBoundingBox() const;
|
||||
void setupLottie(StickerSuggestion &suggestion);
|
||||
void setupWebm(StickerSuggestion &suggestion);
|
||||
void repaintSticker(not_null<DocumentData*> document);
|
||||
void repaintStickerAtIndex(int index);
|
||||
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
|
||||
void clipCallback(
|
||||
Media::Clip::Notification notification,
|
||||
not_null<DocumentData*> document);
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<FieldAutocomplete*> _parent;
|
||||
|
@ -141,6 +147,13 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct FieldAutocomplete::StickerSuggestion {
|
||||
not_null<DocumentData*> document;
|
||||
std::shared_ptr<Data::DocumentMedia> documentMedia;
|
||||
std::unique_ptr<Lottie::SinglePlayer> lottie;
|
||||
Media::Clip::ReaderPointer webm;
|
||||
};
|
||||
|
||||
FieldAutocomplete::FieldAutocomplete(
|
||||
QWidget *parent,
|
||||
not_null<Window::SessionController*> controller)
|
||||
|
@ -340,7 +353,7 @@ FieldAutocomplete::StickerRows FieldAutocomplete::getStickerSuggestions() {
|
|||
};
|
||||
}) | ranges::to_vector;
|
||||
for (auto &suggestion : _srows) {
|
||||
if (!suggestion.animated) {
|
||||
if (!suggestion.lottie && !suggestion.webm) {
|
||||
continue;
|
||||
}
|
||||
const auto i = ranges::find(
|
||||
|
@ -348,7 +361,8 @@ FieldAutocomplete::StickerRows FieldAutocomplete::getStickerSuggestions() {
|
|||
suggestion.document,
|
||||
&StickerSuggestion::document);
|
||||
if (i != end(result)) {
|
||||
i->animated = std::move(suggestion.animated);
|
||||
i->lottie = std::move(suggestion.lottie);
|
||||
i->webm = std::move(suggestion.webm);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -812,6 +826,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
|
|||
width(),
|
||||
std::min(st::msgMaxWidth / 2, width() / 2));
|
||||
|
||||
const auto now = crl::now();
|
||||
int32 rows = rowscount(_srows->size(), _stickersPerRow);
|
||||
int32 fromrow = floorclamp(r.y() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
|
||||
int32 torow = ceilclamp(r.y() + r.height() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
|
||||
|
@ -825,12 +840,15 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
|
|||
auto &sticker = (*_srows)[index];
|
||||
const auto document = sticker.document;
|
||||
const auto &media = sticker.documentMedia;
|
||||
if (!document->sticker()) continue;
|
||||
const auto info = document->sticker();
|
||||
if (!info) continue;
|
||||
|
||||
if (document->sticker()->isLottie()
|
||||
&& !sticker.animated
|
||||
&& media->loaded()) {
|
||||
setupLottie(sticker);
|
||||
if (media->loaded()) {
|
||||
if (info->isLottie() && !sticker.lottie) {
|
||||
setupLottie(sticker);
|
||||
} else if (info->isWebm() && !sticker.webm) {
|
||||
setupWebm(sticker);
|
||||
}
|
||||
}
|
||||
|
||||
QPoint pos(st::stickerPanPadding + col * st::stickerPanSize.width(), st::stickerPanPadding + row * st::stickerPanSize.height());
|
||||
|
@ -841,46 +859,34 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
media->checkStickerSmall();
|
||||
auto w = 1;
|
||||
auto h = 1;
|
||||
if (sticker.animated && !document->dimensions.isEmpty()) {
|
||||
const auto request = Lottie::FrameRequest{ stickerBoundingBox() * cIntRetinaFactor() };
|
||||
const auto size = request.size(document->dimensions, true) / cIntRetinaFactor();
|
||||
w = std::max(size.width(), 1);
|
||||
h = std::max(size.height(), 1);
|
||||
} else {
|
||||
const auto coef = std::min(
|
||||
std::min(
|
||||
(st::stickerPanSize.width() - st::roundRadiusSmall * 2) / float64(document->dimensions.width()),
|
||||
(st::stickerPanSize.height() - st::roundRadiusSmall * 2) / float64(document->dimensions.height())),
|
||||
1.);
|
||||
w = std::max(qRound(coef * document->dimensions.width()), 1);
|
||||
h = std::max(qRound(coef * document->dimensions.height()), 1);
|
||||
}
|
||||
|
||||
if (sticker.animated && sticker.animated->ready()) {
|
||||
const auto frame = sticker.animated->frame();
|
||||
const auto size = frame.size() / cIntRetinaFactor();
|
||||
const auto ppos = pos + QPoint(
|
||||
(st::stickerPanSize.width() - size.width()) / 2,
|
||||
(st::stickerPanSize.height() - size.height()) / 2);
|
||||
const auto paused = _controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::SavedGifs);
|
||||
const auto size = ChatHelpers::ComputeStickerSize(
|
||||
document,
|
||||
stickerBoundingBox());
|
||||
const auto ppos = pos + QPoint(
|
||||
(st::stickerPanSize.width() - size.width()) / 2,
|
||||
(st::stickerPanSize.height() - size.height()) / 2);
|
||||
if (sticker.lottie && sticker.lottie->ready()) {
|
||||
const auto frame = sticker.lottie->frame();
|
||||
p.drawImage(
|
||||
QRect(ppos, size),
|
||||
QRect(ppos, frame.size() / cIntRetinaFactor()),
|
||||
frame);
|
||||
const auto paused = _controller->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::SavedGifs);
|
||||
if (!paused) {
|
||||
sticker.animated->markFrameShown();
|
||||
sticker.lottie->markFrameShown();
|
||||
}
|
||||
} else if (sticker.webm && sticker.webm->started()) {
|
||||
p.drawPixmap(ppos, sticker.webm->current({
|
||||
.frame = size,
|
||||
.keepAlpha = true,
|
||||
}, paused ? 0 : now));
|
||||
} else if (const auto image = media->getStickerSmall()) {
|
||||
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||
p.drawPixmapLeft(ppos, width(), image->pix(w, h));
|
||||
p.drawPixmapLeft(ppos, width(), image->pix(size));
|
||||
} else {
|
||||
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
|
||||
ChatHelpers::PaintStickerThumbnailPath(
|
||||
p,
|
||||
media.get(),
|
||||
QRect(ppos, QSize(w, h)),
|
||||
QRect(ppos, size),
|
||||
_pathGradient.get());
|
||||
}
|
||||
}
|
||||
|
@ -1271,19 +1277,30 @@ auto FieldAutocomplete::Inner::getLottieRenderer()
|
|||
|
||||
void FieldAutocomplete::Inner::setupLottie(StickerSuggestion &suggestion) {
|
||||
const auto document = suggestion.document;
|
||||
suggestion.animated = ChatHelpers::LottiePlayerFromDocument(
|
||||
suggestion.lottie = ChatHelpers::LottiePlayerFromDocument(
|
||||
suggestion.documentMedia.get(),
|
||||
ChatHelpers::StickerLottieSize::InlineResults,
|
||||
stickerBoundingBox() * cIntRetinaFactor(),
|
||||
Lottie::Quality::Default,
|
||||
getLottieRenderer());
|
||||
|
||||
suggestion.animated->updates(
|
||||
suggestion.lottie->updates(
|
||||
) | rpl::start_with_next([=] {
|
||||
repaintSticker(document);
|
||||
}, _stickersLifetime);
|
||||
}
|
||||
|
||||
void FieldAutocomplete::Inner::setupWebm(StickerSuggestion &suggestion) {
|
||||
const auto document = suggestion.document;
|
||||
auto callback = [=](Media::Clip::Notification notification) {
|
||||
clipCallback(notification, document);
|
||||
};
|
||||
suggestion.webm = Media::Clip::MakeReader(
|
||||
suggestion.documentMedia->owner()->location(),
|
||||
suggestion.documentMedia->bytes(),
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
QSize FieldAutocomplete::Inner::stickerBoundingBox() const {
|
||||
return QSize(
|
||||
st::stickerPanSize.width() - st::roundRadiusSmall * 2,
|
||||
|
@ -1299,7 +1316,10 @@ void FieldAutocomplete::Inner::repaintSticker(
|
|||
if (i == end(*_srows)) {
|
||||
return;
|
||||
}
|
||||
const auto index = (i - begin(*_srows));
|
||||
repaintStickerAtIndex(i - begin(*_srows));
|
||||
}
|
||||
|
||||
void FieldAutocomplete::Inner::repaintStickerAtIndex(int index) {
|
||||
const auto row = (index / _stickersPerRow);
|
||||
const auto col = (index % _stickersPerRow);
|
||||
update(
|
||||
|
@ -1309,6 +1329,36 @@ void FieldAutocomplete::Inner::repaintSticker(
|
|||
st::stickerPanSize.height());
|
||||
}
|
||||
|
||||
void FieldAutocomplete::Inner::clipCallback(
|
||||
Media::Clip::Notification notification,
|
||||
not_null<DocumentData*> document) {
|
||||
const auto i = ranges::find(
|
||||
*_srows,
|
||||
document,
|
||||
&StickerSuggestion::document);
|
||||
if (i == end(*_srows)) {
|
||||
return;
|
||||
}
|
||||
using namespace Media::Clip;
|
||||
switch (notification) {
|
||||
case Notification::Reinit: {
|
||||
if (!i->webm) {
|
||||
break;
|
||||
} else if (i->webm->state() == State::Error) {
|
||||
i->webm.setBad();
|
||||
} else if (i->webm->ready() && !i->webm->started()) {
|
||||
const auto size = ChatHelpers::ComputeStickerSize(
|
||||
i->document,
|
||||
stickerBoundingBox());
|
||||
i->webm->start({ .frame = size, .keepAlpha = true });
|
||||
}
|
||||
} break;
|
||||
|
||||
case Notification::Repaint: break;
|
||||
}
|
||||
repaintStickerAtIndex(i - begin(*_srows));
|
||||
}
|
||||
|
||||
void FieldAutocomplete::Inner::selectByMouse(QPoint globalPosition) {
|
||||
_mouseSelection = true;
|
||||
_lastMousePosition = globalPosition;
|
||||
|
|
|
@ -129,12 +129,7 @@ protected:
|
|||
private:
|
||||
class Inner;
|
||||
friend class Inner;
|
||||
|
||||
struct StickerSuggestion {
|
||||
not_null<DocumentData*> document;
|
||||
std::shared_ptr<Data::DocumentMedia> documentMedia;
|
||||
std::unique_ptr<Lottie::SinglePlayer> animated;
|
||||
};
|
||||
struct StickerSuggestion;
|
||||
|
||||
struct MentionRow {
|
||||
not_null<UserData*> user;
|
||||
|
|
Loading…
Add table
Reference in a new issue