mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 09:41:41 -05:00
Implement animated stickerset thumbnails.
This commit is contained in:
parent
db2d24ff32
commit
3b645422ff
11 changed files with 381 additions and 63 deletions
|
@ -1093,6 +1093,36 @@ RecentStickerPack &GetRecentPack() {
|
|||
return cRefRecentStickers();
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
auto LottieCachedFromContent(
|
||||
Method &&method,
|
||||
Storage::Cache::Key baseKey,
|
||||
LottieSize sizeTag,
|
||||
not_null<AuthSession*> session,
|
||||
const QByteArray &content,
|
||||
QSize box) {
|
||||
const auto key = Storage::Cache::Key{
|
||||
baseKey.high,
|
||||
baseKey.low + int(sizeTag)
|
||||
};
|
||||
const auto get = [=](FnMut<void(QByteArray &&cached)> handler) {
|
||||
session->data().cacheBigFile().get(
|
||||
key,
|
||||
std::move(handler));
|
||||
};
|
||||
const auto weak = base::make_weak(session.get());
|
||||
const auto put = [=](QByteArray &&cached) {
|
||||
crl::on_main(weak, [=, data = std::move(cached)]() mutable {
|
||||
weak->data().cacheBigFile().put(key, std::move(data));
|
||||
});
|
||||
};
|
||||
return method(
|
||||
get,
|
||||
put,
|
||||
content,
|
||||
Lottie::FrameRequest{ box });
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
auto LottieFromDocument(
|
||||
Method &&method,
|
||||
|
@ -1108,26 +1138,13 @@ auto LottieFromDocument(
|
|||
Lottie::FrameRequest{ box });
|
||||
}
|
||||
if (const auto baseKey = document->bigFileBaseCacheKey()) {
|
||||
const auto key = Storage::Cache::Key{
|
||||
baseKey->high,
|
||||
baseKey->low + int(sizeTag)
|
||||
};
|
||||
const auto get = [=](FnMut<void(QByteArray &&cached)> handler) {
|
||||
document->session().data().cacheBigFile().get(
|
||||
key,
|
||||
std::move(handler));
|
||||
};
|
||||
const auto weak = base::make_weak(&document->session());
|
||||
const auto put = [=](QByteArray &&cached) {
|
||||
crl::on_main(weak, [=, data = std::move(cached)]() mutable {
|
||||
weak->data().cacheBigFile().put(key, std::move(data));
|
||||
});
|
||||
};
|
||||
return method(
|
||||
get,
|
||||
put,
|
||||
return LottieCachedFromContent(
|
||||
std::forward<Method>(method),
|
||||
*baseKey,
|
||||
sizeTag,
|
||||
&document->session(),
|
||||
Lottie::ReadContent(data, filepath),
|
||||
Lottie::FrameRequest{ box });
|
||||
box);
|
||||
}
|
||||
return method(
|
||||
Lottie::ReadContent(data, filepath),
|
||||
|
@ -1156,4 +1173,98 @@ not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
|||
return LottieFromDocument(method, document, sizeTag, box);
|
||||
}
|
||||
|
||||
bool HasLottieThumbnail(
|
||||
ImagePtr thumbnail,
|
||||
not_null<DocumentData*> sticker) {
|
||||
if (thumbnail) {
|
||||
if (!thumbnail->loaded()) {
|
||||
return false;
|
||||
}
|
||||
const auto &location = thumbnail->location();
|
||||
const auto &bytes = thumbnail->bytesForCache();
|
||||
return location.valid()
|
||||
&& location.type() == StorageFileLocation::Type::StickerSetThumb
|
||||
&& !bytes.isEmpty();
|
||||
} else if (const auto info = sticker->sticker()) {
|
||||
if (!info->animated) {
|
||||
return false;
|
||||
}
|
||||
sticker->automaticLoad(sticker->stickerSetOrigin(), nullptr);
|
||||
if (!sticker->loaded()) {
|
||||
return false;
|
||||
}
|
||||
return sticker->bigFileBaseCacheKey().has_value();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
|
||||
ImagePtr thumbnail,
|
||||
not_null<DocumentData*> sticker,
|
||||
LottieSize sizeTag,
|
||||
QSize box,
|
||||
std::shared_ptr<Lottie::FrameRenderer> renderer) {
|
||||
const auto baseKey = thumbnail
|
||||
? thumbnail->location().file().bigFileBaseCacheKey()
|
||||
: sticker->bigFileBaseCacheKey();
|
||||
if (!baseKey) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto content = (thumbnail
|
||||
? thumbnail->bytesForCache()
|
||||
: Lottie::ReadContent(sticker->data(), sticker->filepath()));
|
||||
if (content.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto method = [](auto &&...args) {
|
||||
return std::make_unique<Lottie::SinglePlayer>(
|
||||
std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
return LottieCachedFromContent(
|
||||
method,
|
||||
*baseKey,
|
||||
sizeTag,
|
||||
&sticker->session(),
|
||||
content,
|
||||
box);
|
||||
}
|
||||
|
||||
ThumbnailSource::ThumbnailSource(
|
||||
const StorageImageLocation &location,
|
||||
int size)
|
||||
: StorageSource(location, size) {
|
||||
}
|
||||
|
||||
QImage ThumbnailSource::takeLoaded() {
|
||||
if (_bytesForAnimated.isEmpty()
|
||||
&& _loader
|
||||
&& _loader->finished()
|
||||
&& !_loader->cancelled()) {
|
||||
_bytesForAnimated = _loader->bytes();
|
||||
}
|
||||
auto result = StorageSource::takeLoaded();
|
||||
if (!_bytesForAnimated.isEmpty()
|
||||
&& !result.isNull()
|
||||
&& result.size() != Image::Empty()->original().size()) {
|
||||
_bytesForAnimated = QByteArray();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray ThumbnailSource::bytesForCache() {
|
||||
return _bytesForAnimated;
|
||||
}
|
||||
|
||||
std::unique_ptr<FileLoader> ThumbnailSource::createLoader(
|
||||
Data::FileOrigin origin,
|
||||
LoadFromCloudSetting fromCloud,
|
||||
bool autoLoading) {
|
||||
auto result = StorageSource::createLoader(
|
||||
origin,
|
||||
fromCloud,
|
||||
autoLoading);
|
||||
_loader = result.get();
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Stickers
|
||||
|
|
|
@ -8,12 +8,21 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
#include "ui/image/image_source.h"
|
||||
|
||||
class DocumentData;
|
||||
class AuthSession;
|
||||
|
||||
namespace Storage {
|
||||
namespace Cache {
|
||||
struct Key;
|
||||
} // namespace Cache
|
||||
} // namespace Storage
|
||||
|
||||
namespace Lottie {
|
||||
class SinglePlayer;
|
||||
class MultiPlayer;
|
||||
class FrameRenderer;
|
||||
class Animation;
|
||||
} // namespace Lottie
|
||||
|
||||
|
@ -115,16 +124,50 @@ enum class LottieSize : uchar {
|
|||
MessageHistory,
|
||||
StickerSet,
|
||||
StickersPanel,
|
||||
StickersFooter,
|
||||
SetsListThumbnail,
|
||||
};
|
||||
|
||||
std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottiePlayerFromDocument(
|
||||
not_null<DocumentData*> document,
|
||||
LottieSize sizeTag,
|
||||
QSize box);
|
||||
not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
||||
[[nodiscard]] not_null<Lottie::Animation*> LottieAnimationFromDocument(
|
||||
not_null<Lottie::MultiPlayer*> player,
|
||||
not_null<DocumentData*> document,
|
||||
LottieSize sizeTag,
|
||||
QSize box);
|
||||
|
||||
[[nodiscard]] bool HasLottieThumbnail(
|
||||
ImagePtr thumbnail,
|
||||
not_null<DocumentData*> sticker);
|
||||
[[nodiscard]] std::unique_ptr<Lottie::SinglePlayer> LottieThumbnail(
|
||||
ImagePtr thumbnail,
|
||||
not_null<DocumentData*> sticker,
|
||||
LottieSize sizeTag,
|
||||
QSize box,
|
||||
std::shared_ptr<Lottie::FrameRenderer> renderer = nullptr);
|
||||
|
||||
class ThumbnailSource : public Images::StorageSource {
|
||||
public:
|
||||
ThumbnailSource(
|
||||
const StorageImageLocation &location,
|
||||
int size);
|
||||
|
||||
QImage takeLoaded() override;
|
||||
|
||||
QByteArray bytesForCache() override;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<FileLoader> createLoader(
|
||||
Data::FileOrigin origin,
|
||||
LoadFromCloudSetting fromCloud,
|
||||
bool autoLoading) override;
|
||||
|
||||
private:
|
||||
QPointer<FileLoader> _loader;
|
||||
QByteArray _bytesForAnimated;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Stickers
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/image/image.h"
|
||||
#include "lottie/lottie_multi_player.h"
|
||||
#include "lottie/lottie_single_player.h"
|
||||
#include "lottie/lottie_animation.h"
|
||||
#include "boxes/stickers_box.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
|
@ -64,6 +65,7 @@ struct StickerIcon {
|
|||
}
|
||||
uint64 setId = 0;
|
||||
ImagePtr thumbnail;
|
||||
mutable Lottie::SinglePlayer *lottie = nullptr;
|
||||
DocumentData *sticker = nullptr;
|
||||
ChannelData *megagroup = nullptr;
|
||||
int pixw = 0;
|
||||
|
@ -71,9 +73,11 @@ struct StickerIcon {
|
|||
|
||||
};
|
||||
|
||||
class StickersListWidget::Footer : public TabbedSelector::InnerFooter, private base::Subscriber {
|
||||
class StickersListWidget::Footer
|
||||
: public TabbedSelector::InnerFooter
|
||||
, private base::Subscriber {
|
||||
public:
|
||||
Footer(not_null<StickersListWidget*> parent);
|
||||
explicit Footer(not_null<StickersListWidget*> parent);
|
||||
|
||||
void preloadImages();
|
||||
void validateSelectedIcon(
|
||||
|
@ -88,6 +92,8 @@ public:
|
|||
void returnFocus();
|
||||
void setLoading(bool loading);
|
||||
|
||||
void clearLottieData();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
@ -106,6 +112,12 @@ private:
|
|||
};
|
||||
using OverState = base::variant<SpecialOver, int>;
|
||||
|
||||
struct LottieIcon {
|
||||
std::unique_ptr<Lottie::SinglePlayer> player;
|
||||
bool stale = false;
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
|
||||
template <typename Callback>
|
||||
void enumerateVisibleIcons(Callback callback);
|
||||
|
||||
|
@ -113,9 +125,13 @@ private:
|
|||
void setSelectedIcon(
|
||||
int newSelected,
|
||||
ValidateIconAnimations animations);
|
||||
void validateIconLottieAnimation(const StickerIcon &icon);
|
||||
QSize iconBox() const;
|
||||
|
||||
void refreshIconsGeometry(ValidateIconAnimations animations);
|
||||
void refillLottieData();
|
||||
void updateSelected();
|
||||
void updateSetIcon(uint64 setId);
|
||||
void finishDragging();
|
||||
void paintStickerSettingsIcon(Painter &p) const;
|
||||
void paintSearchIcon(Painter &p) const;
|
||||
|
@ -134,6 +150,7 @@ private:
|
|||
static constexpr auto kVisibleIconsCount = 8;
|
||||
|
||||
QList<StickerIcon> _icons;
|
||||
mutable base::flat_map<uint64, LottieIcon> _lottieData;
|
||||
OverState _iconOver = SpecialOver::None;
|
||||
int _iconSel = 0;
|
||||
OverState _iconDown = SpecialOver::None;
|
||||
|
@ -191,7 +208,8 @@ StickersListWidget::Set &StickersListWidget::Set::operator=(
|
|||
Set &&other) = default;
|
||||
StickersListWidget::Set::~Set() = default;
|
||||
|
||||
StickersListWidget::Footer::Footer(not_null<StickersListWidget*> parent) : InnerFooter(parent)
|
||||
StickersListWidget::Footer::Footer(not_null<StickersListWidget*> parent)
|
||||
: InnerFooter(parent)
|
||||
, _pan(parent)
|
||||
, _iconsAnimation([=](crl::time now) {
|
||||
return iconsAnimationCallback(now);
|
||||
|
@ -205,6 +223,34 @@ StickersListWidget::Footer::Footer(not_null<StickersListWidget*> parent) : Inner
|
|||
});
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::clearLottieData() {
|
||||
for (auto &icon : _icons) {
|
||||
icon.lottie = nullptr;
|
||||
}
|
||||
_lottieData.clear();
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::refillLottieData() {
|
||||
for (auto &item : _lottieData) {
|
||||
item.second.stale = true;
|
||||
}
|
||||
for (auto &icon : _icons) {
|
||||
const auto i = _lottieData.find(icon.setId);
|
||||
if (i == end(_lottieData)) {
|
||||
continue;
|
||||
}
|
||||
icon.lottie = i->second.player.get();
|
||||
i->second.stale = false;
|
||||
}
|
||||
for (auto i = begin(_lottieData); i != end(_lottieData);) {
|
||||
if (i->second.stale) {
|
||||
i = _lottieData.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::initSearch() {
|
||||
_searchField.create(
|
||||
this,
|
||||
|
@ -282,7 +328,7 @@ void StickersListWidget::Footer::enumerateVisibleIcons(Callback callback) {
|
|||
}
|
||||
|
||||
void StickersListWidget::Footer::preloadImages() {
|
||||
enumerateVisibleIcons([](const StickerIcon & icon, int x) {
|
||||
enumerateVisibleIcons([](const StickerIcon &icon, int x) {
|
||||
if (const auto sticker = icon.sticker) {
|
||||
const auto origin = sticker->stickerSetOrigin();
|
||||
if (icon.thumbnail) {
|
||||
|
@ -607,6 +653,7 @@ void StickersListWidget::Footer::updateSelected() {
|
|||
void StickersListWidget::Footer::refreshIcons(
|
||||
ValidateIconAnimations animations) {
|
||||
_pan->fillIcons(_icons);
|
||||
refillLottieData();
|
||||
refreshIconsGeometry(animations);
|
||||
}
|
||||
|
||||
|
@ -654,6 +701,49 @@ void StickersListWidget::Footer::paintFeaturedStickerSetsBadge(Painter &p, int i
|
|||
}
|
||||
}
|
||||
|
||||
QSize StickersListWidget::Footer::iconBox() const {
|
||||
return QSize(
|
||||
st::stickerIconWidth - 2 * st::stickerIconPadding,
|
||||
st::emojiFooterHeight - 2 * st::stickerIconPadding);
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::validateIconLottieAnimation(
|
||||
const StickerIcon &icon) {
|
||||
if (icon.lottie
|
||||
|| !Stickers::HasLottieThumbnail(ImagePtr(), icon.sticker)) {
|
||||
return;
|
||||
}
|
||||
auto player = Stickers::LottieThumbnail(
|
||||
ImagePtr(),
|
||||
icon.sticker,
|
||||
Stickers::LottieSize::StickersFooter,
|
||||
iconBox() * cIntRetinaFactor(),
|
||||
_pan->getLottieRenderer());
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
icon.lottie = player.get();
|
||||
const auto id = icon.setId;
|
||||
const auto [i, ok] = _lottieData.emplace(
|
||||
id,
|
||||
LottieIcon{ std::move(player) });
|
||||
Assert(ok);
|
||||
|
||||
icon.lottie->updates(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateSetIcon(id);
|
||||
}, i->second.lifetime);
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::updateSetIcon(uint64 setId) {
|
||||
enumerateVisibleIcons([&](const StickerIcon &icon, int x) {
|
||||
if (icon.setId != setId) {
|
||||
return;
|
||||
}
|
||||
update(x, _iconsTop, st::stickerIconWidth, st::emojiFooterHeight);
|
||||
});
|
||||
}
|
||||
|
||||
void StickersListWidget::Footer::paintSetIcon(
|
||||
Painter &p,
|
||||
const StickerIcon &icon,
|
||||
|
@ -663,11 +753,35 @@ void StickersListWidget::Footer::paintSetIcon(
|
|||
const auto thumb = icon.thumbnail
|
||||
? icon.thumbnail.get()
|
||||
: icon.sticker->thumbnail();
|
||||
if (thumb) {
|
||||
thumb->load(origin);
|
||||
if (!thumb) {
|
||||
return;
|
||||
}
|
||||
thumb->load(origin);
|
||||
if (!thumb->loaded()) {
|
||||
return;
|
||||
}
|
||||
const_cast<Footer*>(this)->validateIconLottieAnimation(icon);
|
||||
if (!icon.lottie) {
|
||||
auto pix = thumb->pix(origin, icon.pixw, icon.pixh);
|
||||
|
||||
p.drawPixmapLeft(x + (st::stickerIconWidth - icon.pixw) / 2, _iconsTop + (st::emojiFooterHeight - icon.pixh) / 2, width(), pix);
|
||||
} else if (icon.lottie->ready()) {
|
||||
auto request = Lottie::FrameRequest();
|
||||
request.box = iconBox() * cIntRetinaFactor();
|
||||
const auto frame = icon.lottie->frame(request);
|
||||
const auto size = frame.size() / cIntRetinaFactor();
|
||||
p.drawImage(
|
||||
QRect(
|
||||
x + (st::stickerIconWidth - size.width()) / 2,
|
||||
_iconsTop + (st::emojiFooterHeight - size.height()) / 2,
|
||||
size.width(),
|
||||
size.height()),
|
||||
frame);
|
||||
const auto paused = _pan->controller()->isGifPausedAtLeastFor(
|
||||
Window::GifPauseReason::SavedGifs);
|
||||
if (!paused) {
|
||||
icon.lottie->markFrameShown();
|
||||
}
|
||||
}
|
||||
} else if (icon.megagroup) {
|
||||
icon.megagroup->paintUserpicLeft(p, x + (st::stickerIconWidth - st::stickerGroupCategorySize) / 2, _iconsTop + (st::emojiFooterHeight - st::stickerGroupCategorySize) / 2, width(), st::stickerGroupCategorySize);
|
||||
|
@ -1901,11 +2015,17 @@ TabbedSelector::InnerFooter *StickersListWidget::getFooter() const {
|
|||
void StickersListWidget::processHideFinished() {
|
||||
clearSelection();
|
||||
clearLottieData();
|
||||
if (_footer) {
|
||||
_footer->clearLottieData();
|
||||
}
|
||||
}
|
||||
|
||||
void StickersListWidget::processPanelHideFinished() {
|
||||
clearInstalledLocally();
|
||||
clearLottieData();
|
||||
if (_footer) {
|
||||
_footer->clearLottieData();
|
||||
}
|
||||
// Preserve panel state through visibility toggles.
|
||||
//// Reset to the recent stickers section.
|
||||
//if (_section == Section::Featured && (!_footer || !_footer->hasOnlyFeaturedSets())) {
|
||||
|
|
|
@ -69,6 +69,8 @@ public:
|
|||
void sendSearchRequest();
|
||||
void searchForSets(const QString &query);
|
||||
|
||||
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
|
||||
|
||||
~StickersListWidget();
|
||||
|
||||
protected:
|
||||
|
@ -290,8 +292,6 @@ private:
|
|||
|
||||
void showPreview();
|
||||
|
||||
std::shared_ptr<Lottie::FrameRenderer> getLottieRenderer();
|
||||
|
||||
ChannelData *_megagroupSet = nullptr;
|
||||
uint64 _megagroupSetIdRequested = 0;
|
||||
std::vector<Set> _mySets;
|
||||
|
|
|
@ -214,6 +214,10 @@ class TabbedSelector::Inner : public Ui::RpWidget {
|
|||
public:
|
||||
Inner(QWidget *parent, not_null<Window::SessionController*> controller);
|
||||
|
||||
not_null<Window::SessionController*> controller() const {
|
||||
return _controller;
|
||||
}
|
||||
|
||||
int getVisibleTop() const {
|
||||
return _visibleTop;
|
||||
}
|
||||
|
@ -246,10 +250,6 @@ protected:
|
|||
int minimalHeight() const;
|
||||
int resizeGetHeight(int newWidth) override final;
|
||||
|
||||
not_null<Window::SessionController*> controller() const {
|
||||
return _controller;
|
||||
}
|
||||
|
||||
virtual int countDesiredHeight(int newWidth) = 0;
|
||||
virtual InnerFooter *getFooter() const = 0;
|
||||
virtual void processHideFinished() {
|
||||
|
|
|
@ -13,20 +13,22 @@ namespace Lottie {
|
|||
|
||||
SinglePlayer::SinglePlayer(
|
||||
const QByteArray &content,
|
||||
const FrameRequest &request)
|
||||
const FrameRequest &request,
|
||||
std::shared_ptr<FrameRenderer> renderer)
|
||||
: _animation(this, content, request)
|
||||
, _timer([=] { checkNextFrameRender(); })
|
||||
, _renderer(FrameRenderer::Instance()) {
|
||||
, _renderer(renderer ? renderer : FrameRenderer::Instance()) {
|
||||
}
|
||||
|
||||
SinglePlayer::SinglePlayer(
|
||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||
const QByteArray &content,
|
||||
const FrameRequest &request)
|
||||
const FrameRequest &request,
|
||||
std::shared_ptr<FrameRenderer> renderer)
|
||||
: _animation(this, std::move(get), std::move(put), content, request)
|
||||
, _timer([=] { checkNextFrameRender(); })
|
||||
, _renderer(FrameRenderer::Instance()) {
|
||||
, _renderer(renderer ? renderer : FrameRenderer::Instance()) {
|
||||
}
|
||||
|
||||
SinglePlayer::~SinglePlayer() {
|
||||
|
|
|
@ -30,12 +30,14 @@ class SinglePlayer final : public Player {
|
|||
public:
|
||||
SinglePlayer(
|
||||
const QByteArray &content,
|
||||
const FrameRequest &request);
|
||||
const FrameRequest &request,
|
||||
std::shared_ptr<FrameRenderer> renderer = nullptr);
|
||||
SinglePlayer(
|
||||
FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
|
||||
FnMut<void(QByteArray &&cached)> put, // Unknown thread.
|
||||
const QByteArray &content,
|
||||
const FrameRequest &request);
|
||||
const FrameRequest &request,
|
||||
std::shared_ptr<FrameRenderer> renderer = nullptr);
|
||||
~SinglePlayer();
|
||||
|
||||
void start(
|
||||
|
|
|
@ -3516,7 +3516,7 @@ void _readStickerSets(FileKey &stickersKey, Stickers::Order *outOrder = nullptr,
|
|||
setHash,
|
||||
MTPDstickerSet::Flags(setFlags),
|
||||
setInstallDate,
|
||||
Images::Create(setThumbnail)));
|
||||
Images::CreateStickerSetThumbnail(setThumbnail)));
|
||||
}
|
||||
auto &set = it.value();
|
||||
auto inputSet = MTP_inputStickerSetID(MTP_long(set.id), MTP_long(set.access));
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/cache/storage_cache_database.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "chat_helpers/stickers.h"
|
||||
#include "auth_session.h"
|
||||
|
||||
using namespace Images;
|
||||
|
@ -161,7 +162,11 @@ ImagePtr Create(int width, int height) {
|
|||
height)));
|
||||
}
|
||||
|
||||
ImagePtr Create(const StorageImageLocation &location, int size) {
|
||||
template <typename SourceType>
|
||||
ImagePtr Create(
|
||||
const StorageImageLocation &location,
|
||||
int size,
|
||||
const QByteArray &bytes) {
|
||||
if (!location.valid()) {
|
||||
return ImagePtr();
|
||||
}
|
||||
|
@ -173,41 +178,63 @@ ImagePtr Create(const StorageImageLocation &location, int size) {
|
|||
: StorageImages.emplace(
|
||||
key,
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<StorageSource>(location, size))
|
||||
std::make_unique<SourceType>(location, size))
|
||||
).first->second.get();
|
||||
if (found) {
|
||||
image->refreshFileReference(location.fileReference());
|
||||
}
|
||||
if (!bytes.isEmpty()) {
|
||||
image->setImageBytes(bytes);
|
||||
}
|
||||
return ImagePtr(image);
|
||||
|
||||
}
|
||||
|
||||
ImagePtr Create(const StorageImageLocation &location, int size) {
|
||||
return Create<StorageSource>(location, size, QByteArray());
|
||||
}
|
||||
|
||||
ImagePtr Create(
|
||||
const StorageImageLocation &location,
|
||||
const QByteArray &bytes) {
|
||||
const auto key = inMemoryKey(location);
|
||||
const auto i = StorageImages.find(key);
|
||||
const auto found = (i != end(StorageImages));
|
||||
const auto image = found
|
||||
? i->second.get()
|
||||
: StorageImages.emplace(
|
||||
key,
|
||||
std::make_unique<Image>(
|
||||
std::make_unique<StorageSource>(location, bytes.size()))
|
||||
).first->second.get();
|
||||
if (found) {
|
||||
image->refreshFileReference(location.fileReference());
|
||||
}
|
||||
image->setImageBytes(bytes);
|
||||
return ImagePtr(image);
|
||||
return Create<StorageSource>(location, bytes.size(), bytes);
|
||||
}
|
||||
|
||||
template <typename CreateLocation>
|
||||
struct CreateStorageImage {
|
||||
ImagePtr operator()(
|
||||
const StorageImageLocation &location,
|
||||
int size) {
|
||||
return Create(location, size);
|
||||
}
|
||||
ImagePtr operator()(
|
||||
const StorageImageLocation &location,
|
||||
const QByteArray &bytes) {
|
||||
return Create(location, bytes);
|
||||
}
|
||||
};
|
||||
|
||||
struct CreateSetThumbnail {
|
||||
using Source = Stickers::ThumbnailSource;
|
||||
ImagePtr operator()(
|
||||
const StorageImageLocation &location,
|
||||
int size) {
|
||||
return Create<Source>(location, size, QByteArray());
|
||||
}
|
||||
ImagePtr operator()(
|
||||
const StorageImageLocation &location,
|
||||
const QByteArray &bytes) {
|
||||
return Create<Source>(location, bytes.size(), bytes);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CreateLocation, typename Method = CreateStorageImage>
|
||||
ImagePtr CreateFromPhotoSize(
|
||||
CreateLocation &&createLocation,
|
||||
const MTPPhotoSize &size) {
|
||||
const MTPPhotoSize &size,
|
||||
Method method = Method()) {
|
||||
return size.match([&](const MTPDphotoSize &data) {
|
||||
const auto &location = data.vlocation.c_fileLocationToBeDeprecated();
|
||||
return Create(
|
||||
return method(
|
||||
StorageImageLocation(
|
||||
createLocation(data.vtype, location),
|
||||
data.vw.v,
|
||||
|
@ -216,7 +243,7 @@ ImagePtr CreateFromPhotoSize(
|
|||
}, [&](const MTPDphotoCachedSize &data) {
|
||||
const auto bytes = qba(data.vbytes);
|
||||
const auto &location = data.vlocation.c_fileLocationToBeDeprecated();
|
||||
return Create(
|
||||
return method(
|
||||
StorageImageLocation(
|
||||
createLocation(data.vtype, location),
|
||||
data.vw.v,
|
||||
|
@ -291,7 +318,11 @@ ImagePtr Create(const MTPDstickerSet &set, const MTPPhotoSize &size) {
|
|||
location.vvolume_id,
|
||||
location.vlocal_id));
|
||||
};
|
||||
return CreateFromPhotoSize(create, size);
|
||||
return CreateFromPhotoSize(create, size, CreateSetThumbnail());
|
||||
}
|
||||
|
||||
ImagePtr CreateStickerSetThumbnail(const StorageImageLocation &location) {
|
||||
return CreateSetThumbnail()(location, 0);
|
||||
}
|
||||
|
||||
ImagePtr Create(const MTPDphoto &photo, const MTPPhotoSize &size) {
|
||||
|
|
|
@ -27,6 +27,7 @@ ImagePtr Create(
|
|||
QImage &&data);
|
||||
ImagePtr Create(int width, int height);
|
||||
ImagePtr Create(const StorageImageLocation &location, int size = 0);
|
||||
ImagePtr CreateStickerSetThumbnail(const StorageImageLocation &location);
|
||||
ImagePtr Create( // photoCachedSize
|
||||
const StorageImageLocation &location,
|
||||
const QByteArray &bytes);
|
||||
|
|
|
@ -407,9 +407,17 @@ Storage::Cache::Key StorageFileLocation::bigFileBaseCacheKey() const {
|
|||
return Storage::Cache::Key{ high, low };
|
||||
}
|
||||
|
||||
case Type::StickerSetThumb: {
|
||||
const auto high = (uint64(uint32(_localId)) << 24)
|
||||
| ((uint64(_type) + 1) << 16)
|
||||
| ((uint64(_dcId) & 0xFFULL) << 8)
|
||||
| (_volumeId >> 56);
|
||||
const auto low = (_volumeId << 8);
|
||||
return Storage::Cache::Key{ high, low };
|
||||
}
|
||||
|
||||
case Type::Legacy:
|
||||
case Type::PeerPhoto:
|
||||
case Type::StickerSetThumb:
|
||||
case Type::Encrypted:
|
||||
case Type::Secure:
|
||||
case Type::Photo:
|
||||
|
|
Loading…
Add table
Reference in a new issue