mirror of https://github.com/procxx/kepka.git
Move inline thumbnail image to DocumentMedia.
This commit is contained in:
parent
6ca43153bb
commit
bdd3c51ab8
|
@ -396,6 +396,8 @@ PRIVATE
|
||||||
data/data_poll.h
|
data/data_poll.h
|
||||||
data/data_pts_waiter.cpp
|
data/data_pts_waiter.cpp
|
||||||
data/data_pts_waiter.h
|
data/data_pts_waiter.h
|
||||||
|
data/data_reply_preview.cpp
|
||||||
|
data/data_reply_preview.h
|
||||||
data/data_search_controller.cpp
|
data/data_search_controller.cpp
|
||||||
data/data_search_controller.h
|
data/data_search_controller.h
|
||||||
data/data_session.cpp
|
data/data_session.cpp
|
||||||
|
|
|
@ -442,7 +442,7 @@ void GifsListWidget::processPanelHideFinished() {
|
||||||
if (const auto result = item->getResult()) {
|
if (const auto result = item->getResult()) {
|
||||||
result->unload();
|
result->unload();
|
||||||
}
|
}
|
||||||
item->unloadAnimation();
|
item->unloadHeavyPart();
|
||||||
};
|
};
|
||||||
// Preserve panel state through visibility toggles.
|
// Preserve panel state through visibility toggles.
|
||||||
//clearInlineRows(false);
|
//clearInlineRows(false);
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_streaming.h"
|
#include "data/data_streaming.h"
|
||||||
#include "data/data_document_good_thumbnail.h"
|
#include "data/data_document_good_thumbnail.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
|
#include "data/data_reply_preview.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -470,6 +471,12 @@ DocumentData::DocumentData(not_null<Data::Session*> owner, DocumentId id)
|
||||||
, _owner(owner) {
|
, _owner(owner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DocumentData::~DocumentData() {
|
||||||
|
destroyLoader();
|
||||||
|
unload();
|
||||||
|
ActiveCache().remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
Data::Session &DocumentData::owner() const {
|
Data::Session &DocumentData::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
}
|
}
|
||||||
|
@ -616,10 +623,11 @@ bool DocumentData::checkWallPaperProperties() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::updateThumbnails(
|
void DocumentData::updateThumbnails(
|
||||||
ImagePtr thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
ImagePtr thumbnail) {
|
ImagePtr thumbnail) {
|
||||||
if (thumbnailInline && !_thumbnailInline) {
|
if (!inlineThumbnailBytes.isEmpty()
|
||||||
_thumbnailInline = thumbnailInline;
|
&& _inlineThumbnailBytes.isEmpty()) {
|
||||||
|
_inlineThumbnailBytes = inlineThumbnailBytes;
|
||||||
}
|
}
|
||||||
if (thumbnail
|
if (thumbnail
|
||||||
&& (!_thumbnail
|
&& (!_thumbnail
|
||||||
|
@ -642,10 +650,6 @@ bool DocumentData::hasThumbnail() const {
|
||||||
return !_thumbnail->isNull();
|
return !_thumbnail->isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *DocumentData::thumbnailInline() const {
|
|
||||||
return _thumbnailInline ? _thumbnailInline.get() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Image *DocumentData::thumbnail() const {
|
Image *DocumentData::thumbnail() const {
|
||||||
return _thumbnail ? _thumbnail.get() : nullptr;
|
return _thumbnail ? _thumbnail.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -750,7 +754,6 @@ void DocumentData::unload() {
|
||||||
// Also, you can't unload() images that you don't own
|
// Also, you can't unload() images that you don't own
|
||||||
// from the destructor, because they're already destroyed.
|
// from the destructor, because they're already destroyed.
|
||||||
//
|
//
|
||||||
//_thumbnailInline->unload();
|
|
||||||
//_thumbnail->unload();
|
//_thumbnail->unload();
|
||||||
if (sticker()) {
|
if (sticker()) {
|
||||||
if (sticker()->image) {
|
if (sticker()->image) {
|
||||||
|
@ -758,7 +761,7 @@ void DocumentData::unload() {
|
||||||
sticker()->image = nullptr;
|
sticker()->image = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_replyPreview.clear();
|
_replyPreview = nullptr;
|
||||||
if (!_data.isEmpty()) {
|
if (!_data.isEmpty()) {
|
||||||
ActiveCache().decrement(_data.size());
|
ActiveCache().decrement(_data.size());
|
||||||
_data.clear();
|
_data.clear();
|
||||||
|
@ -1192,28 +1195,10 @@ bool DocumentData::isStickerSetInstalled() const {
|
||||||
Image *DocumentData::getReplyPreview(Data::FileOrigin origin) {
|
Image *DocumentData::getReplyPreview(Data::FileOrigin origin) {
|
||||||
if (!_thumbnail) {
|
if (!_thumbnail) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (_replyPreview
|
} else if (!_replyPreview) {
|
||||||
&& (_replyPreview.good() || !_thumbnail->loaded())) {
|
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||||
return _replyPreview.image();
|
|
||||||
}
|
}
|
||||||
const auto option = isVideoMessage()
|
return _replyPreview->image(origin);
|
||||||
? Images::Option::Circled
|
|
||||||
: Images::Option::None;
|
|
||||||
if (_thumbnail->loaded()) {
|
|
||||||
_replyPreview.prepare(
|
|
||||||
_thumbnail.get(),
|
|
||||||
origin,
|
|
||||||
option);
|
|
||||||
} else {
|
|
||||||
_thumbnail->load(origin);
|
|
||||||
if (_thumbnailInline) {
|
|
||||||
_replyPreview.prepare(
|
|
||||||
_thumbnailInline.get(),
|
|
||||||
origin,
|
|
||||||
option | Images::Option::Blurred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _replyPreview.image();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StickerData *DocumentData::sticker() const {
|
StickerData *DocumentData::sticker() const {
|
||||||
|
@ -1653,12 +1638,6 @@ void DocumentData::collectLocalData(not_null<DocumentData*> local) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentData::~DocumentData() {
|
|
||||||
destroyLoader();
|
|
||||||
unload();
|
|
||||||
ActiveCache().remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DocumentData::ComposeNameString(
|
QString DocumentData::ComposeNameString(
|
||||||
const QString &filename,
|
const QString &filename,
|
||||||
const QString &songTitle,
|
const QString &songTitle,
|
||||||
|
|
|
@ -33,6 +33,7 @@ class Loader;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Session;
|
class Session;
|
||||||
class DocumentMedia;
|
class DocumentMedia;
|
||||||
|
class ReplyPreview;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
|
@ -84,9 +85,10 @@ namespace Serialize {
|
||||||
class Document;
|
class Document;
|
||||||
} // namespace Serialize;
|
} // namespace Serialize;
|
||||||
|
|
||||||
class DocumentData {
|
class DocumentData final {
|
||||||
public:
|
public:
|
||||||
DocumentData(not_null<Data::Session*> owner, DocumentId id);
|
DocumentData(not_null<Data::Session*> owner, DocumentId id);
|
||||||
|
~DocumentData();
|
||||||
|
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
@ -175,12 +177,15 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] bool hasThumbnail() const;
|
[[nodiscard]] bool hasThumbnail() const;
|
||||||
void loadThumbnail(Data::FileOrigin origin);
|
void loadThumbnail(Data::FileOrigin origin);
|
||||||
[[nodiscard]] Image *thumbnailInline() const;
|
|
||||||
[[nodiscard]] Image *thumbnail() const;
|
[[nodiscard]] Image *thumbnail() const;
|
||||||
void updateThumbnails(
|
void updateThumbnails(
|
||||||
ImagePtr thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
ImagePtr thumbnail);
|
ImagePtr thumbnail);
|
||||||
|
|
||||||
|
[[nodiscard]] QByteArray inlineThumbnailBytes() const {
|
||||||
|
return _inlineThumbnailBytes;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
|
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
|
||||||
[[nodiscard]] bool goodThumbnailChecked() const;
|
[[nodiscard]] bool goodThumbnailChecked() const;
|
||||||
[[nodiscard]] bool goodThumbnailGenerating() const;
|
[[nodiscard]] bool goodThumbnailGenerating() const;
|
||||||
|
@ -242,8 +247,6 @@ public:
|
||||||
void setInappPlaybackFailed();
|
void setInappPlaybackFailed();
|
||||||
[[nodiscard]] bool inappPlaybackFailed() const;
|
[[nodiscard]] bool inappPlaybackFailed() const;
|
||||||
|
|
||||||
~DocumentData();
|
|
||||||
|
|
||||||
DocumentId id = 0;
|
DocumentId id = 0;
|
||||||
DocumentType type = FileDocument;
|
DocumentType type = FileDocument;
|
||||||
QSize dimensions;
|
QSize dimensions;
|
||||||
|
@ -310,9 +313,9 @@ private:
|
||||||
QString _mimeString;
|
QString _mimeString;
|
||||||
WebFileLocation _urlLocation;
|
WebFileLocation _urlLocation;
|
||||||
|
|
||||||
ImagePtr _thumbnailInline;
|
QByteArray _inlineThumbnailBytes;
|
||||||
ImagePtr _thumbnail;
|
ImagePtr _thumbnail;
|
||||||
Data::ReplyPreview _replyPreview;
|
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||||
std::weak_ptr<Data::DocumentMedia> _media;
|
std::weak_ptr<Data::DocumentMedia> _media;
|
||||||
PhotoData *_goodThumbnailPhoto = nullptr;
|
PhotoData *_goodThumbnailPhoto = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,19 @@ void DocumentMedia::setGoodThumbnail(QImage thumbnail) {
|
||||||
_owner->session().downloaderTaskFinished().notify();
|
_owner->session().downloaderTaskFinished().notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image *DocumentMedia::thumbnailInline() const {
|
||||||
|
if (!_inlineThumbnail) {
|
||||||
|
auto image = Images::FromInlineBytes(_owner->inlineThumbnailBytes());
|
||||||
|
if (!image.isNull()) {
|
||||||
|
_inlineThumbnail = std::make_unique<Image>(
|
||||||
|
std::make_unique<Images::ImageSource>(
|
||||||
|
std::move(image),
|
||||||
|
"PNG"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _inlineThumbnail.get();
|
||||||
|
}
|
||||||
|
|
||||||
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
|
void DocumentMedia::GenerateGoodThumbnail(not_null<DocumentData*> document) {
|
||||||
const auto data = document->data();
|
const auto data = document->data();
|
||||||
const auto type = document->isWallPaper()
|
const auto type = document->isWallPaper()
|
||||||
|
|
|
@ -20,8 +20,9 @@ public:
|
||||||
[[nodiscard]] Image *goodThumbnail() const;
|
[[nodiscard]] Image *goodThumbnail() const;
|
||||||
void setGoodThumbnail(QImage thumbnail);
|
void setGoodThumbnail(QImage thumbnail);
|
||||||
|
|
||||||
|
[[nodiscard]] Image *thumbnailInline() const;
|
||||||
|
|
||||||
// For DocumentData.
|
// For DocumentData.
|
||||||
void validateGoodThumbnail();
|
|
||||||
static void CheckGoodThumbnail(not_null<DocumentData*> document);
|
static void CheckGoodThumbnail(not_null<DocumentData*> document);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -36,6 +37,7 @@ private:
|
||||||
|
|
||||||
const not_null<DocumentData*> _owner;
|
const not_null<DocumentData*> _owner;
|
||||||
std::unique_ptr<Image> _goodThumbnail;
|
std::unique_ptr<Image> _goodThumbnail;
|
||||||
|
mutable std::unique_ptr<Image> _inlineThumbnail;
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_reply_preview.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/image/image_source.h"
|
#include "ui/image/image_source.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -22,6 +23,8 @@ PhotoData::PhotoData(not_null<Data::Session*> owner, PhotoId id)
|
||||||
, _owner(owner) {
|
, _owner(owner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhotoData::~PhotoData() = default;
|
||||||
|
|
||||||
Data::Session &PhotoData::owner() const {
|
Data::Session &PhotoData::owner() const {
|
||||||
return *_owner;
|
return *_owner;
|
||||||
}
|
}
|
||||||
|
@ -105,37 +108,14 @@ void PhotoData::unload() {
|
||||||
_thumbnailSmall->unload();
|
_thumbnailSmall->unload();
|
||||||
_thumbnail->unload();
|
_thumbnail->unload();
|
||||||
_large->unload();
|
_large->unload();
|
||||||
_replyPreview.clear();
|
_replyPreview = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
|
Image *PhotoData::getReplyPreview(Data::FileOrigin origin) {
|
||||||
if (_replyPreview
|
if (!_replyPreview) {
|
||||||
&& (_replyPreview.good() || !_thumbnailSmall->loaded())) {
|
_replyPreview = std::make_unique<Data::ReplyPreview>(this);
|
||||||
return _replyPreview.image();
|
|
||||||
}
|
}
|
||||||
if (_thumbnailSmall->isDelayedStorageImage()
|
return _replyPreview->image(origin);
|
||||||
&& !_large->isNull()
|
|
||||||
&& !_large->isDelayedStorageImage()
|
|
||||||
&& _large->loaded()) {
|
|
||||||
_replyPreview.prepare(
|
|
||||||
_large.get(),
|
|
||||||
origin,
|
|
||||||
Images::Option(0));
|
|
||||||
} else if (_thumbnailSmall->loaded()) {
|
|
||||||
_replyPreview.prepare(
|
|
||||||
_thumbnailSmall.get(),
|
|
||||||
origin,
|
|
||||||
Images::Option(0));
|
|
||||||
} else {
|
|
||||||
_thumbnailSmall->load(origin);
|
|
||||||
if (_thumbnailInline) {
|
|
||||||
_replyPreview.prepare(
|
|
||||||
_thumbnailInline.get(),
|
|
||||||
origin,
|
|
||||||
Images::Option::Blurred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _replyPreview.image();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::setRemoteLocation(
|
void PhotoData::setRemoteLocation(
|
||||||
|
|
|
@ -15,11 +15,13 @@ class Session;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Session;
|
class Session;
|
||||||
|
class ReplyPreview;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
class PhotoData {
|
class PhotoData final {
|
||||||
public:
|
public:
|
||||||
PhotoData(not_null<Data::Session*> owner, PhotoId id);
|
PhotoData(not_null<Data::Session*> owner, PhotoId id);
|
||||||
|
~PhotoData();
|
||||||
|
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
@ -97,7 +99,7 @@ private:
|
||||||
int32 _dc = 0;
|
int32 _dc = 0;
|
||||||
uint64 _access = 0;
|
uint64 _access = 0;
|
||||||
QByteArray _fileReference;
|
QByteArray _fileReference;
|
||||||
Data::ReplyPreview _replyPreview;
|
std::unique_ptr<Data::ReplyPreview> _replyPreview;
|
||||||
|
|
||||||
not_null<Data::Session*> _owner;
|
not_null<Data::Session*> _owner;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "data/data_reply_preview.h"
|
||||||
|
|
||||||
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
|
#include "data/data_photo.h"
|
||||||
|
#include "ui/image/image.h"
|
||||||
|
#include "ui/image/image_source.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
ReplyPreview::ReplyPreview(not_null<DocumentData*> document)
|
||||||
|
: _document(document)
|
||||||
|
, _documentMedia(_document->createMediaView()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ReplyPreview::ReplyPreview(not_null<PhotoData*> photo)
|
||||||
|
: _photo(photo) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
|
||||||
|
if (image->isNull() || !image->loaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int w = image->width(), h = image->height();
|
||||||
|
if (w <= 0) w = 1;
|
||||||
|
if (h <= 0) h = 1;
|
||||||
|
auto thumbSize = (w > h)
|
||||||
|
? QSize(
|
||||||
|
w * st::msgReplyBarSize.height() / h,
|
||||||
|
st::msgReplyBarSize.height())
|
||||||
|
: QSize(
|
||||||
|
st::msgReplyBarSize.height(),
|
||||||
|
h * st::msgReplyBarSize.height() / w);
|
||||||
|
thumbSize *= cIntRetinaFactor();
|
||||||
|
const auto prepareOptions = Images::Option::Smooth
|
||||||
|
| Images::Option::TransparentBackground
|
||||||
|
| options;
|
||||||
|
auto outerSize = st::msgReplyBarSize.height();
|
||||||
|
auto bitmap = image->pixNoCache(
|
||||||
|
FileOrigin(),
|
||||||
|
thumbSize.width(),
|
||||||
|
thumbSize.height(),
|
||||||
|
prepareOptions,
|
||||||
|
outerSize,
|
||||||
|
outerSize);
|
||||||
|
_image = std::make_unique<Image>(
|
||||||
|
std::make_unique<Images::ImageSource>(
|
||||||
|
bitmap.toImage(),
|
||||||
|
"PNG"));
|
||||||
|
_good = ((options & Images::Option::Blurred) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image *ReplyPreview::image(Data::FileOrigin origin) {
|
||||||
|
if (_document) {
|
||||||
|
const auto thumbnail = _document->thumbnail();
|
||||||
|
Assert(thumbnail != nullptr);
|
||||||
|
if (!_image || (!_good && thumbnail->loaded())) {
|
||||||
|
const auto option = _document->isVideoMessage()
|
||||||
|
? Images::Option::Circled
|
||||||
|
: Images::Option::None;
|
||||||
|
if (thumbnail->loaded()) {
|
||||||
|
prepare(thumbnail, option);
|
||||||
|
} else {
|
||||||
|
thumbnail->load(origin);
|
||||||
|
if (const auto image = _documentMedia->thumbnailInline()) {
|
||||||
|
prepare(image, option | Images::Option::Blurred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assert(_photo != nullptr);
|
||||||
|
const auto small = _photo->thumbnailSmall();
|
||||||
|
const auto large = _photo->large();
|
||||||
|
if (!_image || (!_good && (small->loaded() || large->loaded()))) {
|
||||||
|
if (small->isDelayedStorageImage()
|
||||||
|
&& !large->isNull()
|
||||||
|
&& !large->isDelayedStorageImage()
|
||||||
|
&& large->loaded()) {
|
||||||
|
prepare(large, Images::Option(0));
|
||||||
|
} else if (small->loaded()) {
|
||||||
|
prepare(small, Images::Option(0));
|
||||||
|
} else {
|
||||||
|
small->load(origin);
|
||||||
|
if (const auto blurred = _photo->thumbnailInline()) {
|
||||||
|
prepare(blurred, Images::Option::Blurred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _image.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Data
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class DocumentData;
|
||||||
|
class PhotoData;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
class DocumentMedia;
|
||||||
|
struct FileOrigin;
|
||||||
|
|
||||||
|
class ReplyPreview {
|
||||||
|
public:
|
||||||
|
explicit ReplyPreview(not_null<DocumentData*> document);
|
||||||
|
explicit ReplyPreview(not_null<PhotoData*> photo);
|
||||||
|
|
||||||
|
[[nodiscard]] Image *image(Data::FileOrigin origin);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void prepare(not_null<Image*> image, Images::Options options);
|
||||||
|
|
||||||
|
std::unique_ptr<Image> _image;
|
||||||
|
bool _good = false;
|
||||||
|
DocumentData *_document = nullptr;
|
||||||
|
PhotoData *_photo = nullptr;
|
||||||
|
std::shared_ptr<DocumentMedia> _documentMedia;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Data
|
|
@ -126,19 +126,20 @@ std::vector<UnavailableReason> ExtractUnavailableReasons(
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPPhotoSize FindDocumentInlineThumbnail(const MTPDdocument &data) {
|
QByteArray FindDocumentInlineThumbnail(const MTPDdocument &data) {
|
||||||
const auto thumbs = data.vthumbs();
|
const auto thumbs = data.vthumbs();
|
||||||
if (!thumbs) {
|
if (!thumbs) {
|
||||||
return MTP_photoSizeEmpty(MTP_string());
|
return QByteArray();
|
||||||
}
|
}
|
||||||
const auto &list = thumbs->v;
|
const auto &list = thumbs->v;
|
||||||
const auto i = ranges::find(
|
const auto i = ranges::find(
|
||||||
list,
|
list,
|
||||||
mtpc_photoStrippedSize,
|
mtpc_photoStrippedSize,
|
||||||
&MTPPhotoSize::type);
|
&MTPPhotoSize::type);
|
||||||
return (i != list.end())
|
if (i == list.end()) {
|
||||||
? (*i)
|
return QByteArray();
|
||||||
: MTPPhotoSize(MTP_photoSizeEmpty(MTP_string()));
|
}
|
||||||
|
return i->c_photoStrippedSize().vbytes().v;
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
|
MTPPhotoSize FindDocumentThumbnail(const MTPDdocument &data) {
|
||||||
|
@ -2371,7 +2372,7 @@ not_null<DocumentData*> Session::processDocument(
|
||||||
fields.vdate().v,
|
fields.vdate().v,
|
||||||
fields.vattributes().v,
|
fields.vattributes().v,
|
||||||
mime,
|
mime,
|
||||||
ImagePtr(),
|
QByteArray(),
|
||||||
Images::Create(std::move(thumb), format),
|
Images::Create(std::move(thumb), format),
|
||||||
fields.vdc_id().v,
|
fields.vdc_id().v,
|
||||||
fields.vsize().v,
|
fields.vsize().v,
|
||||||
|
@ -2388,7 +2389,7 @@ not_null<DocumentData*> Session::document(
|
||||||
TimeId date,
|
TimeId date,
|
||||||
const QVector<MTPDocumentAttribute> &attributes,
|
const QVector<MTPDocumentAttribute> &attributes,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnail,
|
const ImagePtr &thumbnail,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
int32 size,
|
int32 size,
|
||||||
|
@ -2401,7 +2402,7 @@ not_null<DocumentData*> Session::document(
|
||||||
date,
|
date,
|
||||||
attributes,
|
attributes,
|
||||||
mime,
|
mime,
|
||||||
thumbnailInline,
|
inlineThumbnailBytes,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
dc,
|
dc,
|
||||||
size,
|
size,
|
||||||
|
@ -2476,7 +2477,7 @@ DocumentData *Session::documentFromWeb(
|
||||||
base::unixtime::now(),
|
base::unixtime::now(),
|
||||||
data.vattributes().v,
|
data.vattributes().v,
|
||||||
data.vmime_type().v,
|
data.vmime_type().v,
|
||||||
ImagePtr(),
|
QByteArray(),
|
||||||
thumb,
|
thumb,
|
||||||
MTP::maindc(),
|
MTP::maindc(),
|
||||||
int32(0), // data.vsize().v
|
int32(0), // data.vsize().v
|
||||||
|
@ -2497,7 +2498,7 @@ DocumentData *Session::documentFromWeb(
|
||||||
base::unixtime::now(),
|
base::unixtime::now(),
|
||||||
data.vattributes().v,
|
data.vattributes().v,
|
||||||
data.vmime_type().v,
|
data.vmime_type().v,
|
||||||
ImagePtr(),
|
QByteArray(),
|
||||||
thumb,
|
thumb,
|
||||||
MTP::maindc(),
|
MTP::maindc(),
|
||||||
int32(0), // data.vsize().v
|
int32(0), // data.vsize().v
|
||||||
|
@ -2517,7 +2518,7 @@ void Session::documentApplyFields(
|
||||||
void Session::documentApplyFields(
|
void Session::documentApplyFields(
|
||||||
not_null<DocumentData*> document,
|
not_null<DocumentData*> document,
|
||||||
const MTPDdocument &data) {
|
const MTPDdocument &data) {
|
||||||
const auto thumbnailInline = FindDocumentInlineThumbnail(data);
|
const auto inlineThumbnailBytes = FindDocumentInlineThumbnail(data);
|
||||||
const auto thumbnailSize = FindDocumentThumbnail(data);
|
const auto thumbnailSize = FindDocumentThumbnail(data);
|
||||||
const auto thumbnail = Images::Create(data, thumbnailSize);
|
const auto thumbnail = Images::Create(data, thumbnailSize);
|
||||||
documentApplyFields(
|
documentApplyFields(
|
||||||
|
@ -2527,7 +2528,7 @@ void Session::documentApplyFields(
|
||||||
data.vdate().v,
|
data.vdate().v,
|
||||||
data.vattributes().v,
|
data.vattributes().v,
|
||||||
qs(data.vmime_type()),
|
qs(data.vmime_type()),
|
||||||
Images::Create(data, thumbnailInline),
|
inlineThumbnailBytes,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
data.vdc_id().v,
|
data.vdc_id().v,
|
||||||
data.vsize().v,
|
data.vsize().v,
|
||||||
|
@ -2541,7 +2542,7 @@ void Session::documentApplyFields(
|
||||||
TimeId date,
|
TimeId date,
|
||||||
const QVector<MTPDocumentAttribute> &attributes,
|
const QVector<MTPDocumentAttribute> &attributes,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnail,
|
const ImagePtr &thumbnail,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
int32 size,
|
int32 size,
|
||||||
|
@ -2551,7 +2552,7 @@ void Session::documentApplyFields(
|
||||||
}
|
}
|
||||||
document->date = date;
|
document->date = date;
|
||||||
document->setMimeString(mime);
|
document->setMimeString(mime);
|
||||||
document->updateThumbnails(thumbnailInline, thumbnail);
|
document->updateThumbnails(inlineThumbnailBytes, thumbnail);
|
||||||
document->size = size;
|
document->size = size;
|
||||||
document->setattributes(attributes);
|
document->setattributes(attributes);
|
||||||
|
|
||||||
|
|
|
@ -494,7 +494,7 @@ public:
|
||||||
TimeId date,
|
TimeId date,
|
||||||
const QVector<MTPDocumentAttribute> &attributes,
|
const QVector<MTPDocumentAttribute> &attributes,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnail,
|
const ImagePtr &thumbnail,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
int32 size,
|
int32 size,
|
||||||
|
@ -749,7 +749,7 @@ private:
|
||||||
TimeId date,
|
TimeId date,
|
||||||
const QVector<MTPDocumentAttribute> &attributes,
|
const QVector<MTPDocumentAttribute> &attributes,
|
||||||
const QString &mime,
|
const QString &mime,
|
||||||
const ImagePtr &thumbnailInline,
|
const QByteArray &inlineThumbnailBytes,
|
||||||
const ImagePtr &thumbnail,
|
const ImagePtr &thumbnail,
|
||||||
int32 dc,
|
int32 dc,
|
||||||
int32 size,
|
int32 size,
|
||||||
|
|
|
@ -8,9 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_types.h"
|
#include "data/data_types.h"
|
||||||
|
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_file_origin.h"
|
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "ui/image/image_source.h"
|
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "storage/cache/storage_cache_types.h"
|
#include "storage/cache/storage_cache_types.h"
|
||||||
#include "base/openssl_help.h"
|
#include "base/openssl_help.h"
|
||||||
|
@ -34,20 +32,6 @@ constexpr auto kGeoPointCacheMask = 0x000000FFFFFFFFFFULL;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct ReplyPreview::Data {
|
|
||||||
Data(std::unique_ptr<Images::Source> &&source, bool good);
|
|
||||||
|
|
||||||
Image image;
|
|
||||||
bool good = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
ReplyPreview::Data::Data(
|
|
||||||
std::unique_ptr<Images::Source> &&source,
|
|
||||||
bool good)
|
|
||||||
: image(std::move(source))
|
|
||||||
, good(good) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) {
|
Storage::Cache::Key DocumentCacheKey(int32 dcId, uint64 id) {
|
||||||
return Storage::Cache::Key{
|
return Storage::Cache::Key{
|
||||||
Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask),
|
Data::kDocumentCacheTag | (uint64(dcId) & Data::kDocumentCacheMask),
|
||||||
|
@ -109,63 +93,6 @@ Storage::Cache::Key GeoPointCacheKey(const GeoPointLocation &location) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplyPreview::ReplyPreview() = default;
|
|
||||||
|
|
||||||
ReplyPreview::ReplyPreview(ReplyPreview &&other) = default;
|
|
||||||
|
|
||||||
ReplyPreview &ReplyPreview::operator=(ReplyPreview &&other) = default;
|
|
||||||
|
|
||||||
ReplyPreview::~ReplyPreview() = default;
|
|
||||||
|
|
||||||
void ReplyPreview::prepare(
|
|
||||||
not_null<Image*> image,
|
|
||||||
FileOrigin origin,
|
|
||||||
Images::Options options) {
|
|
||||||
int w = image->width(), h = image->height();
|
|
||||||
if (w <= 0) w = 1;
|
|
||||||
if (h <= 0) h = 1;
|
|
||||||
auto thumbSize = (w > h)
|
|
||||||
? QSize(
|
|
||||||
w * st::msgReplyBarSize.height() / h,
|
|
||||||
st::msgReplyBarSize.height())
|
|
||||||
: QSize(
|
|
||||||
st::msgReplyBarSize.height(),
|
|
||||||
h * st::msgReplyBarSize.height() / w);
|
|
||||||
thumbSize *= cIntRetinaFactor();
|
|
||||||
const auto prepareOptions = Images::Option::Smooth
|
|
||||||
| Images::Option::TransparentBackground
|
|
||||||
| options;
|
|
||||||
auto outerSize = st::msgReplyBarSize.height();
|
|
||||||
auto bitmap = image->pixNoCache(
|
|
||||||
origin,
|
|
||||||
thumbSize.width(),
|
|
||||||
thumbSize.height(),
|
|
||||||
prepareOptions,
|
|
||||||
outerSize,
|
|
||||||
outerSize);
|
|
||||||
_data = std::make_unique<ReplyPreview::Data>(
|
|
||||||
std::make_unique<Images::ImageSource>(
|
|
||||||
bitmap.toImage(),
|
|
||||||
"PNG"),
|
|
||||||
((options & Images::Option::Blurred) == 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReplyPreview::clear() {
|
|
||||||
_data = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Image *ReplyPreview::image() const {
|
|
||||||
return _data ? &_data->image : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReplyPreview::good() const {
|
|
||||||
return !empty() && _data->good;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReplyPreview::empty() const {
|
|
||||||
return !_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
uint32 AudioMsgId::CreateExternalPlayId() {
|
uint32 AudioMsgId::CreateExternalPlayId() {
|
||||||
|
|
|
@ -56,33 +56,6 @@ constexpr auto kAnimationCacheTag = uint8(0x05);
|
||||||
|
|
||||||
struct FileOrigin;
|
struct FileOrigin;
|
||||||
|
|
||||||
class ReplyPreview {
|
|
||||||
public:
|
|
||||||
ReplyPreview();
|
|
||||||
ReplyPreview(ReplyPreview &&other);
|
|
||||||
ReplyPreview &operator=(ReplyPreview &&other);
|
|
||||||
~ReplyPreview();
|
|
||||||
|
|
||||||
void prepare(
|
|
||||||
not_null<Image*> image,
|
|
||||||
FileOrigin origin,
|
|
||||||
Images::Options options);
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
[[nodiscard]] Image *image() const;
|
|
||||||
[[nodiscard]] bool good() const;
|
|
||||||
[[nodiscard]] bool empty() const;
|
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const {
|
|
||||||
return !empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Data;
|
|
||||||
std::unique_ptr<Data> _data;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
struct MessageGroupId {
|
struct MessageGroupId {
|
||||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
@ -262,6 +263,8 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
|
||||||
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
|
auto topMinus = isBubbleTop() ? 0 : st::msgFileTopMinus;
|
||||||
int nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0;
|
int nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0, bottom = 0;
|
||||||
if (auto thumbed = Get<HistoryDocumentThumbed>()) {
|
if (auto thumbed = Get<HistoryDocumentThumbed>()) {
|
||||||
|
ensureDataMediaCreated();
|
||||||
|
|
||||||
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
||||||
nametop = st::msgFileThumbNameTop - topMinus;
|
nametop = st::msgFileThumbNameTop - topMinus;
|
||||||
nameright = st::msgFileThumbPadding.left();
|
nameright = st::msgFileThumbPadding.left();
|
||||||
|
@ -278,7 +281,7 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
|
||||||
thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
thumb = normal->pixSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||||
} else {
|
} else {
|
||||||
_data->loadThumbnail(_realParent->fullId());
|
_data->loadThumbnail(_realParent->fullId());
|
||||||
if (const auto blurred = _data->thumbnailInline()) {
|
if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
thumb = blurred->pixBlurredSingle(_realParent->fullId(), thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,6 +494,24 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::checkHeavyPart() {
|
||||||
|
if (!_dataMedia) {
|
||||||
|
history()->owner().unregisterHeavyViewPart(_parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::unloadHeavyPart() {
|
||||||
|
_dataMedia = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Document::ensureDataMediaCreated() const {
|
||||||
|
if (_dataMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataMedia = _data->createMediaView();
|
||||||
|
history()->owner().registerHeavyViewPart(_parent);
|
||||||
|
}
|
||||||
|
|
||||||
bool Document::downloadInCorner() const {
|
bool Document::downloadInCorner() const {
|
||||||
return _data->isAudioFile()
|
return _data->isAudioFile()
|
||||||
&& _data->canBeStreamed()
|
&& _data->canBeStreamed()
|
||||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
struct HistoryDocumentNamed;
|
struct HistoryDocumentNamed;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class DocumentMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace Text {
|
namespace Text {
|
||||||
class String;
|
class String;
|
||||||
|
@ -63,6 +67,9 @@ public:
|
||||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||||
void parentTextUpdated() override;
|
void parentTextUpdated() override;
|
||||||
|
|
||||||
|
void checkHeavyPart() override;
|
||||||
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float64 dataProgress() const override;
|
float64 dataProgress() const override;
|
||||||
bool dataFinished() const override;
|
bool dataFinished() const override;
|
||||||
|
@ -75,6 +82,8 @@ private:
|
||||||
int realDuration = 0;
|
int realDuration = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ensureDataMediaCreated() const;
|
||||||
|
|
||||||
[[nodiscard]] Ui::Text::String createCaption();
|
[[nodiscard]] Ui::Text::String createCaption();
|
||||||
|
|
||||||
QSize countOptimalSize() override;
|
QSize countOptimalSize() override;
|
||||||
|
@ -93,6 +102,7 @@ private:
|
||||||
StateRequest request) const;
|
StateRequest request) const;
|
||||||
|
|
||||||
not_null<DocumentData*> _data;
|
not_null<DocumentData*> _data;
|
||||||
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -425,7 +425,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_data->loadThumbnail(_realParent->fullId());
|
_data->loadThumbnail(_realParent->fullId());
|
||||||
if (const auto blurred = _data->thumbnailInline()) {
|
if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
|
||||||
} else if (!isRound) {
|
} else if (!isRound) {
|
||||||
const auto roundTop = (roundCorners & RectPart::TopLeft);
|
const auto roundTop = (roundCorners & RectPart::TopLeft);
|
||||||
|
@ -1140,7 +1140,7 @@ void Gif::validateGroupedCache(
|
||||||
? good
|
? good
|
||||||
: useThumb
|
: useThumb
|
||||||
? thumb
|
? thumb
|
||||||
: _data->thumbnailInline();
|
: _dataMedia->thumbnailInline();
|
||||||
const auto blur = !useGood
|
const auto blur = !useGood
|
||||||
&& (!useThumb
|
&& (!useThumb
|
||||||
|| (thumb->width() < kUseNonBlurredThreshold
|
|| (thumb->width() < kUseNonBlurredThreshold
|
||||||
|
|
|
@ -207,8 +207,8 @@ void ThemeDocument::validateThumbnail() const {
|
||||||
}
|
}
|
||||||
if (_data->thumbnail()->loaded()) {
|
if (_data->thumbnail()->loaded()) {
|
||||||
prepareThumbnailFrom(_data->thumbnail(), 0);
|
prepareThumbnailFrom(_data->thumbnail(), 0);
|
||||||
} else if (const auto blurred = _data->thumbnailInline()) {
|
} else if (_thumbnail.isNull()) {
|
||||||
if (_thumbnail.isNull()) {
|
if (const auto blurred = _dataMedia->thumbnailInline()) {
|
||||||
prepareThumbnailFrom(blurred, -1);
|
prepareThumbnailFrom(blurred, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
#include "styles/style_chat_helpers.h"
|
#include "styles/style_chat_helpers.h"
|
||||||
|
@ -325,13 +326,21 @@ void Gif::validateThumbnail(
|
||||||
|
|
||||||
void Gif::prepareThumbnail(QSize size, QSize frame) const {
|
void Gif::prepareThumbnail(QSize size, QSize frame) const {
|
||||||
if (const auto document = getShownDocument()) {
|
if (const auto document = getShownDocument()) {
|
||||||
|
ensureDataMediaCreated(document);
|
||||||
validateThumbnail(document->thumbnail(), size, frame, true);
|
validateThumbnail(document->thumbnail(), size, frame, true);
|
||||||
validateThumbnail(document->thumbnailInline(), size, frame, false);
|
validateThumbnail(_dataMedia->thumbnailInline(), size, frame, false);
|
||||||
} else {
|
} else {
|
||||||
validateThumbnail(getResultThumb(), size, frame, true);
|
validateThumbnail(getResultThumb(), size, frame, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Gif::ensureDataMediaCreated(not_null<DocumentData*> document) const {
|
||||||
|
if (_dataMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataMedia = document->createMediaView();
|
||||||
|
}
|
||||||
|
|
||||||
void Gif::ensureAnimation() const {
|
void Gif::ensureAnimation() const {
|
||||||
if (!_animation) {
|
if (!_animation) {
|
||||||
_animation = std::make_unique<AnimationData>([=](crl::time now) {
|
_animation = std::make_unique<AnimationData>([=](crl::time now) {
|
||||||
|
@ -367,9 +376,14 @@ void Gif::radialAnimationCallback(crl::time now) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Gif::unloadHeavyPart() {
|
||||||
|
unloadAnimation();
|
||||||
|
getShownDocument()->unload();
|
||||||
|
_dataMedia = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Gif::unloadAnimation() {
|
void Gif::unloadAnimation() {
|
||||||
_gif.reset();
|
_gif.reset();
|
||||||
getShownDocument()->unload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gif::clipCallback(Media::Clip::Notification notification) {
|
void Gif::clipCallback(Media::Clip::Notification notification) {
|
||||||
|
@ -1380,11 +1394,19 @@ void Game::prepareThumbnail(QSize size) const {
|
||||||
validateThumbnail(photo->thumbnail(), size, true);
|
validateThumbnail(photo->thumbnail(), size, true);
|
||||||
validateThumbnail(photo->thumbnailInline(), size, false);
|
validateThumbnail(photo->thumbnailInline(), size, false);
|
||||||
} else if (const auto document = getResultDocument()) {
|
} else if (const auto document = getResultDocument()) {
|
||||||
|
ensureDataMediaCreated(document);
|
||||||
validateThumbnail(document->thumbnail(), size, true);
|
validateThumbnail(document->thumbnail(), size, true);
|
||||||
validateThumbnail(document->thumbnailInline(), size, false);
|
validateThumbnail(_dataMedia->thumbnailInline(), size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::ensureDataMediaCreated(not_null<DocumentData*> document) const {
|
||||||
|
if (_dataMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataMedia = document->createMediaView();
|
||||||
|
}
|
||||||
|
|
||||||
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
|
void Game::validateThumbnail(Image *image, QSize size, bool good) const {
|
||||||
if (!image || (_thumbGood && !good)) {
|
if (!image || (_thumbGood && !good)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1450,9 +1472,14 @@ void Game::radialAnimationCallback(crl::time now) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::unloadHeavyPart() {
|
||||||
|
unloadAnimation();
|
||||||
|
getResultDocument()->unload();
|
||||||
|
_dataMedia = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Game::unloadAnimation() {
|
void Game::unloadAnimation() {
|
||||||
_gif.reset();
|
_gif.reset();
|
||||||
getResultDocument()->unload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::clipCallback(Media::Clip::Notification notification) {
|
void Game::clipCallback(Media::Clip::Notification notification) {
|
||||||
|
@ -1464,7 +1491,20 @@ void Game::clipCallback(Media::Clip::Notification notification) {
|
||||||
_gif.setBad();
|
_gif.setBad();
|
||||||
getResultDocument()->unload();
|
getResultDocument()->unload();
|
||||||
} else if (_gif->ready() && !_gif->started()) {
|
} else if (_gif->ready() && !_gif->started()) {
|
||||||
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, RectPart::None);
|
if (_gif->width() * _gif->height() > kMaxInlineArea) {
|
||||||
|
getResultDocument()->dimensions = QSize(
|
||||||
|
_gif->width(),
|
||||||
|
_gif->height());
|
||||||
|
unloadAnimation();
|
||||||
|
} else {
|
||||||
|
_gif->start(
|
||||||
|
_frameSize.width(),
|
||||||
|
_frameSize.height(),
|
||||||
|
st::inlineThumbSize,
|
||||||
|
st::inlineThumbSize,
|
||||||
|
ImageRoundRadius::None,
|
||||||
|
RectPart::None);
|
||||||
|
}
|
||||||
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
||||||
unloadAnimation();
|
unloadAnimation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ namespace Lottie {
|
||||||
class SinglePlayer;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class DocumentMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace InlineBots {
|
namespace InlineBots {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -75,23 +79,30 @@ public:
|
||||||
|
|
||||||
int resizeGetHeight(int width) override;
|
int resizeGetHeight(int width) override;
|
||||||
|
|
||||||
void unloadAnimation() override;
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSize countFrameSize() const;
|
|
||||||
|
|
||||||
enum class StateFlag {
|
enum class StateFlag {
|
||||||
Over = (1 << 0),
|
Over = (1 << 0),
|
||||||
DeleteOver = (1 << 1),
|
DeleteOver = (1 << 1),
|
||||||
};
|
};
|
||||||
using StateFlags = base::flags<StateFlag>;
|
using StateFlags = base::flags<StateFlag>;
|
||||||
friend inline constexpr auto is_flag_type(StateFlag) { return true; };
|
friend inline constexpr auto is_flag_type(StateFlag) { return true; };
|
||||||
StateFlags _state;
|
|
||||||
|
|
||||||
Media::Clip::ReaderPointer _gif;
|
struct AnimationData {
|
||||||
ClickHandlerPtr _delete;
|
template <typename Callback>
|
||||||
mutable QPixmap _thumb;
|
AnimationData(Callback &&callback)
|
||||||
mutable bool _thumbGood = false;
|
: radial(std::forward<Callback>(callback)) {
|
||||||
|
}
|
||||||
|
bool over = false;
|
||||||
|
Ui::Animations::Simple _a_over;
|
||||||
|
Ui::RadialAnimation radial;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
||||||
|
void unloadAnimation();
|
||||||
|
QSize countFrameSize() const;
|
||||||
|
|
||||||
void validateThumbnail(
|
void validateThumbnail(
|
||||||
Image *image,
|
Image *image,
|
||||||
QSize size,
|
QSize size,
|
||||||
|
@ -105,15 +116,15 @@ private:
|
||||||
|
|
||||||
void clipCallback(Media::Clip::Notification notification);
|
void clipCallback(Media::Clip::Notification notification);
|
||||||
|
|
||||||
struct AnimationData {
|
StateFlags _state;
|
||||||
template <typename Callback>
|
|
||||||
AnimationData(Callback &&callback)
|
Media::Clip::ReaderPointer _gif;
|
||||||
: radial(std::forward<Callback>(callback)) {
|
ClickHandlerPtr _delete;
|
||||||
}
|
mutable QPixmap _thumb;
|
||||||
bool over = false;
|
mutable bool _thumbGood = false;
|
||||||
Ui::Animations::Simple _a_over;
|
|
||||||
Ui::RadialAnimation radial;
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
};
|
|
||||||
mutable std::unique_ptr<AnimationData> _animation;
|
mutable std::unique_ptr<AnimationData> _animation;
|
||||||
mutable Ui::Animations::Simple _a_deleteOver;
|
mutable Ui::Animations::Simple _a_deleteOver;
|
||||||
|
|
||||||
|
@ -372,9 +383,11 @@ public:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const override;
|
StateRequest request) const override;
|
||||||
|
|
||||||
void unloadAnimation() override;
|
void unloadHeavyPart() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensureDataMediaCreated(not_null<DocumentData*> document) const;
|
||||||
|
void unloadAnimation();
|
||||||
void countFrameSize();
|
void countFrameSize();
|
||||||
|
|
||||||
void prepareThumbnail(QSize size) const;
|
void prepareThumbnail(QSize size) const;
|
||||||
|
@ -386,6 +399,7 @@ private:
|
||||||
void clipCallback(Media::Clip::Notification notification);
|
void clipCallback(Media::Clip::Notification notification);
|
||||||
|
|
||||||
Media::Clip::ReaderPointer _gif;
|
Media::Clip::ReaderPointer _gif;
|
||||||
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
mutable QPixmap _thumb;
|
mutable QPixmap _thumb;
|
||||||
mutable bool _thumbGood = false;
|
mutable bool _thumbGood = false;
|
||||||
mutable std::unique_ptr<Ui::RadialAnimation> _radial;
|
mutable std::unique_ptr<Ui::RadialAnimation> _radial;
|
||||||
|
|
|
@ -80,7 +80,7 @@ public:
|
||||||
PhotoData *getPreviewPhoto() const;
|
PhotoData *getPreviewPhoto() const;
|
||||||
|
|
||||||
virtual void preload() const;
|
virtual void preload() const;
|
||||||
virtual void unloadAnimation() {
|
virtual void unloadHeavyPart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void update() const;
|
void update() const;
|
||||||
|
|
|
@ -304,7 +304,7 @@ void Inner::hideFinish(bool completely) {
|
||||||
if (const auto result = item->getResult()) {
|
if (const auto result = item->getResult()) {
|
||||||
result->unload();
|
result->unload();
|
||||||
}
|
}
|
||||||
item->unloadAnimation();
|
item->unloadHeavyPart();
|
||||||
};
|
};
|
||||||
clearInlineRows(false);
|
clearInlineRows(false);
|
||||||
for (const auto &[result, layout] : _inlineLayouts) {
|
for (const auto &[result, layout] : _inlineLayouts) {
|
||||||
|
|
|
@ -2183,7 +2183,10 @@ void OverlayWidget::initStreamingThumbnail() {
|
||||||
const auto useGood = (good && good->loaded());
|
const auto useGood = (good && good->loaded());
|
||||||
const auto thumb = _doc->thumbnail();
|
const auto thumb = _doc->thumbnail();
|
||||||
const auto useThumb = (thumb && thumb->loaded());
|
const auto useThumb = (thumb && thumb->loaded());
|
||||||
const auto blurred = _doc->thumbnailInline();
|
|
||||||
|
// #TODO optimize
|
||||||
|
const auto blurred = media ? media->thumbnailInline() : nullptr;
|
||||||
|
|
||||||
if (good && !useGood) {
|
if (good && !useGood) {
|
||||||
good->load({});
|
good->load({});
|
||||||
} else if (thumb && !useThumb) {
|
} else if (thumb && !useThumb) {
|
||||||
|
|
|
@ -1376,7 +1376,10 @@ QImage Pip::videoFrame(const FrameRequest &request) const {
|
||||||
const auto useGood = (good && good->loaded());
|
const auto useGood = (good && good->loaded());
|
||||||
const auto thumb = _data->thumbnail();
|
const auto thumb = _data->thumbnail();
|
||||||
const auto useThumb = (thumb && thumb->loaded());
|
const auto useThumb = (thumb && thumb->loaded());
|
||||||
const auto blurred = _data->thumbnailInline();
|
|
||||||
|
// #TODO optimize always use when available
|
||||||
|
const auto blurred = media ? media->thumbnailInline() : nullptr;
|
||||||
|
|
||||||
const auto state = !cover.isNull()
|
const auto state = !cover.isNull()
|
||||||
? ThumbState::Cover
|
? ThumbState::Cover
|
||||||
: useGood
|
: useGood
|
||||||
|
|
|
@ -437,7 +437,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
ensureDataMediaCreated();
|
ensureDataMediaCreated();
|
||||||
|
|
||||||
const auto selected = (selection == FullSelection);
|
const auto selected = (selection == FullSelection);
|
||||||
const auto blurred = _data->thumbnailInline();
|
const auto blurred = _dataMedia->thumbnailInline();
|
||||||
const auto thumbLoaded = _data->hasThumbnail()
|
const auto thumbLoaded = _data->hasThumbnail()
|
||||||
&& _data->thumbnail()->loaded();
|
&& _data->thumbnail()->loaded();
|
||||||
const auto goodLoaded = _dataMedia->goodThumbnail()
|
const auto goodLoaded = _dataMedia->goodThumbnail()
|
||||||
|
@ -672,10 +672,15 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
_st.songThumbSize,
|
_st.songThumbSize,
|
||||||
_width);
|
_width);
|
||||||
if (clip.intersects(inner)) {
|
if (clip.intersects(inner)) {
|
||||||
|
if (_data->hasThumbnail()) {
|
||||||
|
ensureDataMediaCreated();
|
||||||
|
}
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
const auto thumbLoaded = _data->hasThumbnail()
|
const auto thumbLoaded = _data->hasThumbnail()
|
||||||
&& _data->thumbnail()->loaded();
|
&& _data->thumbnail()->loaded();
|
||||||
const auto blurred = _data->thumbnailInline();
|
const auto blurred = _dataMedia
|
||||||
|
? _dataMedia->thumbnailInline()
|
||||||
|
: nullptr;
|
||||||
if (thumbLoaded || blurred) {
|
if (thumbLoaded || blurred) {
|
||||||
const auto thumb = thumbLoaded
|
const auto thumb = thumbLoaded
|
||||||
? _data->thumbnail()->pixCircled(
|
? _data->thumbnail()->pixCircled(
|
||||||
|
@ -826,6 +831,13 @@ TextState Voice::getState(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Voice::ensureDataMediaCreated() const {
|
||||||
|
if (_dataMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataMedia = _data->createMediaView();
|
||||||
|
}
|
||||||
|
|
||||||
float64 Voice::dataProgress() const {
|
float64 Voice::dataProgress() const {
|
||||||
return _data->progress();
|
return _data->progress();
|
||||||
}
|
}
|
||||||
|
@ -1023,8 +1035,9 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
|
||||||
QRect rthumb(style::rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width));
|
QRect rthumb(style::rtlrect(0, st::linksBorder + _st.filePadding.top(), _st.fileThumbSize, _st.fileThumbSize, _width));
|
||||||
if (clip.intersects(rthumb)) {
|
if (clip.intersects(rthumb)) {
|
||||||
if (wthumb) {
|
if (wthumb) {
|
||||||
|
ensureDataMediaCreated();
|
||||||
const auto thumbLoaded = _data->thumbnail()->loaded();
|
const auto thumbLoaded = _data->thumbnail()->loaded();
|
||||||
const auto blurred = _data->thumbnailInline();
|
const auto blurred = _dataMedia->thumbnailInline();
|
||||||
if (thumbLoaded || blurred) {
|
if (thumbLoaded || blurred) {
|
||||||
if (_thumb.isNull() || (thumbLoaded && !_thumbLoaded)) {
|
if (_thumb.isNull() || (thumbLoaded && !_thumbLoaded)) {
|
||||||
_thumbLoaded = thumbLoaded;
|
_thumbLoaded = thumbLoaded;
|
||||||
|
@ -1279,6 +1292,13 @@ const style::RoundCheckbox &Document::checkboxStyle() const {
|
||||||
return st::overviewSmallCheck;
|
return st::overviewSmallCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Document::ensureDataMediaCreated() const {
|
||||||
|
if (_dataMedia) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_dataMedia = _data->createMediaView();
|
||||||
|
}
|
||||||
|
|
||||||
float64 Document::dataProgress() const {
|
float64 Document::dataProgress() const {
|
||||||
return _data->progress();
|
return _data->progress();
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,7 +255,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Voice : public RadialProgressItem {
|
class Voice final : public RadialProgressItem {
|
||||||
public:
|
public:
|
||||||
Voice(
|
Voice(
|
||||||
not_null<HistoryItem*> parent,
|
not_null<HistoryItem*> parent,
|
||||||
|
@ -276,9 +276,11 @@ protected:
|
||||||
const style::RoundCheckbox &checkboxStyle() const override;
|
const style::RoundCheckbox &checkboxStyle() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensureDataMediaCreated() const;
|
||||||
int duration() const;
|
int duration() const;
|
||||||
|
|
||||||
not_null<DocumentData*> _data;
|
not_null<DocumentData*> _data;
|
||||||
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
StatusText _status;
|
StatusText _status;
|
||||||
ClickHandlerPtr _namel;
|
ClickHandlerPtr _namel;
|
||||||
|
|
||||||
|
@ -292,7 +294,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Document : public RadialProgressItem {
|
class Document final : public RadialProgressItem {
|
||||||
public:
|
public:
|
||||||
Document(
|
Document(
|
||||||
not_null<HistoryItem*> parent,
|
not_null<HistoryItem*> parent,
|
||||||
|
@ -305,7 +307,7 @@ public:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const override;
|
StateRequest request) const override;
|
||||||
|
|
||||||
virtual DocumentData *getDocument() const override {
|
DocumentData *getDocument() const override {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +325,10 @@ private:
|
||||||
QPoint point,
|
QPoint point,
|
||||||
StateRequest request) const;
|
StateRequest request) const;
|
||||||
|
|
||||||
|
void ensureDataMediaCreated() const;
|
||||||
|
|
||||||
not_null<DocumentData*> _data;
|
not_null<DocumentData*> _data;
|
||||||
|
mutable std::shared_ptr<Data::DocumentMedia> _dataMedia;
|
||||||
StatusText _status;
|
StatusText _status;
|
||||||
ClickHandlerPtr _msgl, _namel;
|
ClickHandlerPtr _msgl, _namel;
|
||||||
|
|
||||||
|
@ -342,7 +347,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Link : public ItemBase {
|
class Link final : public ItemBase {
|
||||||
public:
|
public:
|
||||||
Link(
|
Link(
|
||||||
not_null<HistoryItem*> parent,
|
not_null<HistoryItem*> parent,
|
||||||
|
|
|
@ -3942,7 +3942,7 @@ void importOldRecentStickers() {
|
||||||
date,
|
date,
|
||||||
attributes,
|
attributes,
|
||||||
mime,
|
mime,
|
||||||
ImagePtr(),
|
QByteArray(),
|
||||||
ImagePtr(),
|
ImagePtr(),
|
||||||
dc,
|
dc,
|
||||||
size,
|
size,
|
||||||
|
|
|
@ -146,7 +146,7 @@ DocumentData *Document::readFromStreamHelper(int streamAppVersion, QDataStream &
|
||||||
date,
|
date,
|
||||||
attributes,
|
attributes,
|
||||||
mime,
|
mime,
|
||||||
ImagePtr(),
|
QByteArray(),
|
||||||
Images::Create(*thumb),
|
Images::Create(*thumb),
|
||||||
dc,
|
dc,
|
||||||
size,
|
size,
|
||||||
|
|
|
@ -61,6 +61,56 @@ uint64 SinglePixKey(Options options) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
QImage FromInlineBytes(const QByteArray &bytes) {
|
||||||
|
if (bytes.size() < 3 || bytes[0] != '\x01') {
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49"
|
||||||
|
"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c"
|
||||||
|
"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37"
|
||||||
|
"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3"
|
||||||
|
"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff"
|
||||||
|
"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35"
|
||||||
|
"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
||||||
|
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
||||||
|
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
||||||
|
"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00"
|
||||||
|
"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01"
|
||||||
|
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
|
||||||
|
"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05"
|
||||||
|
"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06"
|
||||||
|
"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52"
|
||||||
|
"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28"
|
||||||
|
"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53"
|
||||||
|
"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75"
|
||||||
|
"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96"
|
||||||
|
"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6"
|
||||||
|
"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6"
|
||||||
|
"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4"
|
||||||
|
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01"
|
||||||
|
"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
|
||||||
|
"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05"
|
||||||
|
"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41"
|
||||||
|
"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33"
|
||||||
|
"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26"
|
||||||
|
"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a"
|
||||||
|
"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74"
|
||||||
|
"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94"
|
||||||
|
"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4"
|
||||||
|
"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4"
|
||||||
|
"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4"
|
||||||
|
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00"
|
||||||
|
"\x3f\x00";
|
||||||
|
const char footer[] = "\xff\xd9";
|
||||||
|
auto real = QByteArray(header, sizeof(header) - 1);
|
||||||
|
real[164] = bytes[1];
|
||||||
|
real[166] = bytes[2];
|
||||||
|
const auto ready = real
|
||||||
|
+ bytes.mid(3)
|
||||||
|
+ QByteArray::fromRawData(footer, sizeof(footer) - 1);
|
||||||
|
return App::readImage(ready);
|
||||||
|
}
|
||||||
|
|
||||||
void ClearRemote() {
|
void ClearRemote() {
|
||||||
base::take(StorageImages);
|
base::take(StorageImages);
|
||||||
base::take(WebUrlImages);
|
base::take(WebUrlImages);
|
||||||
|
@ -251,54 +301,7 @@ ImagePtr CreateFromPhotoSize(
|
||||||
data.vh().v),
|
data.vh().v),
|
||||||
bytes);
|
bytes);
|
||||||
}, [&](const MTPDphotoStrippedSize &data) {
|
}, [&](const MTPDphotoStrippedSize &data) {
|
||||||
const auto bytes = qba(data.vbytes());
|
auto image = FromInlineBytes(qba(data.vbytes()));
|
||||||
if (bytes.size() < 3 || bytes[0] != '\x01') {
|
|
||||||
return ImagePtr();
|
|
||||||
}
|
|
||||||
const char header[] = "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49"
|
|
||||||
"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c"
|
|
||||||
"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37"
|
|
||||||
"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3"
|
|
||||||
"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff"
|
|
||||||
"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35"
|
|
||||||
"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
|
||||||
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
|
||||||
"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8"
|
|
||||||
"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00"
|
|
||||||
"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01"
|
|
||||||
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
|
|
||||||
"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05"
|
|
||||||
"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06"
|
|
||||||
"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52"
|
|
||||||
"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28"
|
|
||||||
"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53"
|
|
||||||
"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75"
|
|
||||||
"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96"
|
|
||||||
"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6"
|
|
||||||
"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6"
|
|
||||||
"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4"
|
|
||||||
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01"
|
|
||||||
"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08"
|
|
||||||
"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05"
|
|
||||||
"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41"
|
|
||||||
"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33"
|
|
||||||
"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26"
|
|
||||||
"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a"
|
|
||||||
"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74"
|
|
||||||
"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94"
|
|
||||||
"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4"
|
|
||||||
"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4"
|
|
||||||
"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4"
|
|
||||||
"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00"
|
|
||||||
"\x3f\x00";
|
|
||||||
const char footer[] = "\xff\xd9";
|
|
||||||
auto real = QByteArray(header, sizeof(header) - 1);
|
|
||||||
real[164] = bytes[1];
|
|
||||||
real[166] = bytes[2];
|
|
||||||
const auto ready = real
|
|
||||||
+ bytes.mid(3)
|
|
||||||
+ QByteArray::fromRawData(footer, sizeof(footer) - 1);
|
|
||||||
auto image = App::readImage(ready);
|
|
||||||
return !image.isNull()
|
return !image.isNull()
|
||||||
? Images::Create(std::move(image), "JPG")
|
? Images::Create(std::move(image), "JPG")
|
||||||
: ImagePtr();
|
: ImagePtr();
|
||||||
|
|
|
@ -13,6 +13,8 @@ class HistoryItem;
|
||||||
|
|
||||||
namespace Images {
|
namespace Images {
|
||||||
|
|
||||||
|
[[nodiscard]] QImage FromInlineBytes(const QByteArray &bytes);
|
||||||
|
|
||||||
void ClearRemote();
|
void ClearRemote();
|
||||||
void ClearAll();
|
void ClearAll();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
|
#include "data/data_document_media.h"
|
||||||
#include "ui/image/image.h"
|
#include "ui/image/image.h"
|
||||||
#include "ui/emoji_config.h"
|
#include "ui/emoji_config.h"
|
||||||
#include "lottie/lottie_single_player.h"
|
#include "lottie/lottie_single_player.h"
|
||||||
|
@ -114,6 +115,7 @@ void MediaPreviewWidget::showPreview(
|
||||||
_origin = origin;
|
_origin = origin;
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
_document = document;
|
_document = document;
|
||||||
|
_documentMedia = _document->createMediaView();
|
||||||
fillEmojiString();
|
fillEmojiString();
|
||||||
resetGifAndCache();
|
resetGifAndCache();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +127,7 @@ void MediaPreviewWidget::showPreview(
|
||||||
_origin = origin;
|
_origin = origin;
|
||||||
_photo = photo;
|
_photo = photo;
|
||||||
_document = nullptr;
|
_document = nullptr;
|
||||||
|
_documentMedia = nullptr;
|
||||||
fillEmojiString();
|
fillEmojiString();
|
||||||
resetGifAndCache();
|
resetGifAndCache();
|
||||||
}
|
}
|
||||||
|
@ -137,7 +140,7 @@ void MediaPreviewWidget::startShow() {
|
||||||
_controller->enableGifPauseReason(Window::GifPauseReason::MediaPreview);
|
_controller->enableGifPauseReason(Window::GifPauseReason::MediaPreview);
|
||||||
}
|
}
|
||||||
_hiding = false;
|
_hiding = false;
|
||||||
_a_shown.start([this] { update(); }, 0., 1., st::stickerPreviewDuration);
|
_a_shown.start([=] { update(); }, 0., 1., st::stickerPreviewDuration);
|
||||||
} else {
|
} else {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
@ -149,9 +152,10 @@ void MediaPreviewWidget::hidePreview() {
|
||||||
}
|
}
|
||||||
if (_gif) _cache = currentImage();
|
if (_gif) _cache = currentImage();
|
||||||
_hiding = true;
|
_hiding = true;
|
||||||
_a_shown.start([this] { update(); }, 1., 0., st::stickerPreviewDuration);
|
_a_shown.start([=] { update(); }, 1., 0., st::stickerPreviewDuration);
|
||||||
_photo = nullptr;
|
_photo = nullptr;
|
||||||
_document = nullptr;
|
_document = nullptr;
|
||||||
|
_documentMedia = nullptr;
|
||||||
resetGifAndCache();
|
resetGifAndCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +283,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
|
||||||
if (_document->thumbnail()->loaded()) {
|
if (_document->thumbnail()->loaded()) {
|
||||||
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||||
_cacheStatus = CacheThumbLoaded;
|
_cacheStatus = CacheThumbLoaded;
|
||||||
} else if (const auto blurred = _document->thumbnailInline()) {
|
} else if (const auto blurred = _documentMedia->thumbnailInline()) {
|
||||||
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
_cache = _document->thumbnail()->pixBlurred(_origin, s.width(), s.height());
|
||||||
_cacheStatus = CacheThumbLoaded;
|
_cacheStatus = CacheThumbLoaded;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class DocumentMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Lottie {
|
namespace Lottie {
|
||||||
class SinglePlayer;
|
class SinglePlayer;
|
||||||
} // namespace Lottie
|
} // namespace Lottie
|
||||||
|
@ -55,6 +59,7 @@ private:
|
||||||
bool _hiding = false;
|
bool _hiding = false;
|
||||||
Data::FileOrigin _origin;
|
Data::FileOrigin _origin;
|
||||||
DocumentData *_document = nullptr;
|
DocumentData *_document = nullptr;
|
||||||
|
std::shared_ptr<Data::DocumentMedia> _documentMedia;
|
||||||
PhotoData *_photo = nullptr;
|
PhotoData *_photo = nullptr;
|
||||||
Media::Clip::ReaderPointer _gif;
|
Media::Clip::ReaderPointer _gif;
|
||||||
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
std::unique_ptr<Lottie::SinglePlayer> _lottie;
|
||||||
|
|
Loading…
Reference in New Issue