Use CloudImageView in the inline bot thumbnails.

This commit is contained in:
John Preston 2020-05-27 18:31:39 +04:00
parent 50e0c3ee4d
commit 897e432f40
9 changed files with 257 additions and 119 deletions

View File

@ -66,56 +66,6 @@ inline const char *cGUIDStr() {
return gGuidStr;
}
struct BuiltInDc {
int id;
const char *ip;
int port;
};
static const BuiltInDc _builtInDcs[] = {
{ 1, "149.154.175.50", 443 },
{ 2, "149.154.167.51", 443 },
{ 3, "149.154.175.100", 443 },
{ 4, "149.154.167.91", 443 },
{ 5, "149.154.171.5", 443 }
};
static const BuiltInDc _builtInDcsIPv6[] = {
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000a", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000a", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000a", 443 },
{ 4, "2001:067c:04e8:f004:0000:0000:0000:000a", 443 },
{ 5, "2001:0b28:f23f:f005:0000:0000:0000:000a", 443 }
};
static const BuiltInDc _builtInTestDcs[] = {
{ 1, "149.154.175.10", 443 },
{ 2, "149.154.167.40", 443 },
{ 3, "149.154.175.117", 443 }
};
static const BuiltInDc _builtInTestDcsIPv6[] = {
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000e", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000e", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000e", 443 }
};
inline const BuiltInDc *builtInDcs() {
return cTestMode() ? _builtInTestDcs : _builtInDcs;
}
inline int builtInDcsCount() {
return (cTestMode() ? sizeof(_builtInTestDcs) : sizeof(_builtInDcs)) / sizeof(BuiltInDc);
}
inline const BuiltInDc *builtInDcsIPv6() {
return cTestMode() ? _builtInTestDcsIPv6 : _builtInDcsIPv6;
}
inline int builtInDcsCountIPv6() {
return (cTestMode() ? sizeof(_builtInTestDcsIPv6) : sizeof(_builtInDcsIPv6)) / sizeof(BuiltInDc);
}
static const char *UpdatesPublicKey = "\
-----BEGIN RSA PUBLIC KEY-----\n\
MIGJAoGBAMA4ViQrjkPZ9xj0lrer3r23JvxOnrtE8nI69XLGSr+sRERz9YnUptnU\n\

View File

@ -8,11 +8,96 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_cloud_file.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "storage/cache/storage_cache_database.h"
#include "storage/file_download.h"
#include "ui/image/image.h"
#include "main/main_session.h"
#include <compare>
namespace Data {
void CloudImageView::set(
not_null<Main::Session*> session,
QImage image) {
_image = std::make_unique<Image>(
std::make_unique<Images::ImageSource>(std::move(image), "PNG"));
session->downloaderTaskFinished().notify();
}
CloudImage::CloudImage(not_null<Main::Session*> session)
: _session(session) {
}
Image *CloudImageView::image() const {
return _image.get();
}
void CloudImage::set(const ImageWithLocation &data) {
UpdateCloudFile(
_file,
data,
_session->data().cache(),
kImageCacheTag,
[=](FileOrigin origin) { load(origin); },
[=](QImage preloaded) {
if (const auto view = activeView()) {
view->set(_session, data.preloaded);
}
});
}
bool CloudImage::empty() const {
return !_file.location.valid();
}
bool CloudImage::loading() const {
return (_file.loader != nullptr);
}
bool CloudImage::failed() const {
return (_file.flags & CloudFile::Flag::Failed);
}
void CloudImage::load(FileOrigin origin) {
const auto fromCloud = LoadFromCloudOrLocal;
const auto cacheTag = kImageCacheTag;
const auto autoLoading = false;
LoadCloudFile(_file, origin, fromCloud, autoLoading, cacheTag, [=] {
if (const auto active = activeView()) {
return !active->image();
}
return true;
}, [=](QImage result) {
if (const auto active = activeView()) {
active->set(_session, std::move(result));
}
});
}
const ImageLocation &CloudImage::location() const {
return _file.location;
}
int CloudImage::byteSize() const {
return _file.byteSize;
}
std::shared_ptr<CloudImageView> CloudImage::createView() {
if (auto active = activeView()) {
return active;
}
auto view = std::make_shared<CloudImageView>();
_view = view;
return view;
}
std::shared_ptr<CloudImageView> CloudImage::activeView() {
return _view.lock();
}
void UpdateCloudFile(
CloudFile &file,
const ImageWithLocation &data,
@ -167,7 +252,7 @@ void LoadCloudFile(
Fn<void()> progress) {
const auto callback = [=](CloudFile &file) {
if (auto bytes = file.loader->bytes(); bytes.isEmpty()) {
file.flags |= Data::CloudFile::Flag::Failed;
file.flags |= CloudFile::Flag::Failed;
if (const auto onstack = fail) {
onstack(true);
}

View File

@ -18,6 +18,10 @@ class Database;
} // namespace Cache
} // namespace Storage
namespace Main {
class Session;
} // namespace Main
namespace Data {
struct FileOrigin;
@ -35,6 +39,40 @@ struct CloudFile final {
base::flags<Flag> flags;
};
class CloudImageView final {
public:
void set(not_null<Main::Session*> session, QImage image);
[[nodiscard]] Image *image() const;
private:
std::unique_ptr<Image> _image;
};
class CloudImage final {
public:
explicit CloudImage(not_null<Main::Session*> session);
void set(const ImageWithLocation &data);
[[nodiscard]] bool empty() const;
[[nodiscard]] bool loading() const;
[[nodiscard]] bool failed() const;
void load(FileOrigin origin);
[[nodiscard]] const ImageLocation &location() const;
[[nodiscard]] int byteSize() const;
[[nodiscard]] std::shared_ptr<CloudImageView> createView();
[[nodiscard]] std::shared_ptr<CloudImageView> activeView();
private:
const not_null<Main::Session*> _session;
CloudFile _file;
std::weak_ptr<CloudImageView> _view;
};
void UpdateCloudFile(
CloudFile &file,
const ImageWithLocation &data,

View File

@ -1125,8 +1125,7 @@ TextState Contact::getState(
}
void Contact::prepareThumbnail(int width, int height) const {
const auto thumb = getResultThumb();
if (!thumb) {
if (!hasResultThumb()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = getResultContactAvatar(width, height);
}
@ -1134,26 +1133,26 @@ void Contact::prepareThumbnail(int width, int height) const {
}
const auto origin = fileOrigin();
if (thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
auto w = qMax(style::ConvertScale(thumb->width()), 1);
auto h = qMax(style::ConvertScale(thumb->height()), 1);
if (w * height > h * width) {
if (height < h) {
w = w * height / h;
h = height;
}
} else {
if (width < w) {
h = h * width / w;
w = width;
}
}
_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
const auto thumb = getResultThumb(origin);
if (!thumb
|| ((_thumb.width() == width * cIntRetinaFactor())
&& (_thumb.height() == height * cIntRetinaFactor()))) {
return;
}
auto w = qMax(style::ConvertScale(thumb->width()), 1);
auto h = qMax(style::ConvertScale(thumb->height()), 1);
if (w * height > h * width) {
if (height < h) {
w = w * height / h;
h = height;
}
} else {
thumb->load(origin);
if (width < w) {
h = h * width / w;
w = width;
}
}
_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
}
Article::Article(
@ -1214,8 +1213,7 @@ void Article::paint(Painter &p, const QRect &clip, const PaintContext *context)
prepareThumbnail(st::inlineThumbSize, st::inlineThumbSize);
QRect rthumb(style::rtlrect(0, st::inlineRowMargin, st::inlineThumbSize, st::inlineThumbSize, _width));
if (_thumb.isNull()) {
const auto thumb = getResultThumb();
if (!thumb && !_thumbLetter.isEmpty()) {
if (!hasResultThumb() && !_thumbLetter.isEmpty()) {
int32 index = (_thumbLetter.at(0).unicode() % 4);
style::color colors[] = {
st::msgFile3Bg,
@ -1279,8 +1277,7 @@ TextState Article::getState(
}
void Article::prepareThumbnail(int width, int height) const {
const auto thumb = getResultThumb();
if (!thumb) {
if (!hasResultThumb()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = getResultContactAvatar(width, height);
}
@ -1288,26 +1285,26 @@ void Article::prepareThumbnail(int width, int height) const {
}
const auto origin = fileOrigin();
if (thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
auto w = qMax(style::ConvertScale(thumb->width()), 1);
auto h = qMax(style::ConvertScale(thumb->height()), 1);
if (w * height > h * width) {
if (height < h) {
w = w * height / h;
h = height;
}
} else {
if (width < w) {
h = h * width / w;
w = width;
}
}
_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
const auto thumb = getResultThumb(origin);
if (!thumb
|| ((_thumb.width() == width * cIntRetinaFactor())
&& (_thumb.height() == height * cIntRetinaFactor()))) {
return;
}
auto w = qMax(style::ConvertScale(thumb->width()), 1);
auto h = qMax(style::ConvertScale(thumb->height()), 1);
if (w * height > h * width) {
if (height < h) {
w = w * height / h;
h = height;
}
} else {
thumb->load(origin);
if (width < w) {
h = h * width / w;
w = width;
}
}
_thumb = thumb->pixNoCache(origin, w * cIntRetinaFactor(), h * cIntRetinaFactor(), Images::Option::Smooth, width, height);
}
Game::Game(not_null<Context*> context, not_null<Result*> result)

View File

@ -75,8 +75,8 @@ void ItemBase::preload() const {
}
} else if (const auto document = _result->_document) {
document->loadThumbnail(origin);
} else if (const auto thumb = _result->_thumb; !thumb->isNull()) {
thumb->load(origin);
} else if (auto &thumb = _result->_thumbnail; !thumb.empty()) {
thumb.load(origin);
}
} else if (_document) {
_document->loadThumbnail(origin);
@ -144,15 +144,23 @@ PhotoData *ItemBase::getResultPhoto() const {
return _result ? _result->_photo : nullptr;
}
Image *ItemBase::getResultThumb() const {
if (_result) {
if (!_result->_thumb->isNull()) {
return _result->_thumb.get();
} else if (!_result->_locationThumb->isNull()) {
return _result->_locationThumb.get();
bool ItemBase::hasResultThumb() const {
return _result
&& (!_result->_thumbnail.empty()
|| !_result->_locationThumbnail.empty());
}
Image *ItemBase::getResultThumb(Data::FileOrigin origin) const {
if (_result && !_thumbnail) {
if (!_result->_thumbnail.empty()) {
_thumbnail = _result->_thumbnail.createView();
_result->_thumbnail.load(origin);
} else if (!_result->_locationThumbnail.empty()) {
_thumbnail = _result->_locationThumbnail.createView();
_result->_locationThumbnail.load(origin);
}
}
return nullptr;
return _thumbnail->image();
}
QPixmap ItemBase::getResultContactAvatar(int width, int height) const {

View File

@ -10,6 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "layout.h"
#include "ui/text/text.h"
namespace Data {
class CloudImageView;
} // namespace Data
namespace InlineBots {
class Result;
@ -81,6 +85,7 @@ public:
virtual void preload() const;
virtual void unloadHeavyPart() {
_thumbnail = nullptr;
}
void update() const;
@ -105,7 +110,8 @@ public:
protected:
DocumentData *getResultDocument() const;
PhotoData *getResultPhoto() const;
Image *getResultThumb() const;
bool hasResultThumb() const;
Image *getResultThumb(Data::FileOrigin origin) const;
QPixmap getResultContactAvatar(int width, int height) const;
int getResultDuration() const;
QString getResultUrl() const;
@ -128,6 +134,7 @@ protected:
private:
not_null<Context*> _context;
mutable std::shared_ptr<Data::CloudImageView> _thumbnail;
};

View File

@ -41,7 +41,11 @@ QString GetContentUrl(const MTPWebDocument &document) {
} // namespace
Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creator.type) {
Result::Result(const Creator &creator)
: _queryId(creator.queryId)
, _type(creator.type)
, _thumbnail(&Auth())
, _locationThumbnail(&Auth()) {
}
std::unique_ptr<Result> Result::create(
@ -122,7 +126,9 @@ std::unique_ptr<Result> Result::create(
}
}
if (!result->_photo && !result->_document && imageThumb) {
result->_thumb = Images::Create(*r.vthumb(), result->thumbBox());
result->_thumbnail.set(ImageWithLocation{
.location = Images::FromWebDocument(*r.vthumb())
});
}
message = &r.vsend_message();
} break;
@ -274,7 +280,9 @@ std::unique_ptr<Result> Result::create(
location.height = h;
location.zoom = zoom;
location.scale = scale;
result->_locationThumb = Images::Create(location);
result->_locationThumbnail.set(ImageWithLocation{
.location = ImageLocation({ location }, w, h)
});
}
return result;
@ -345,7 +353,7 @@ void Result::cancelFile() {
}
bool Result::hasThumbDisplay() const {
if (!_thumb->isNull()
if (!_thumbnail.empty()
|| _photo
|| (_document && _document->hasThumbnail())) {
return true;

View File

@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "data/data_cloud_file.h"
class FileLoader;
class History;
@ -115,7 +117,8 @@ private:
std::unique_ptr<MTPReplyMarkup> _mtpKeyboard;
ImagePtr _thumb, _locationThumb;
Data::CloudImage _thumbnail;
Data::CloudImage _locationThumbnail;
std::unique_ptr<internal::SendData> sendData;

View File

@ -17,7 +17,42 @@ namespace {
using namespace details;
const char *(PublicRSAKeys[]) = { "\
struct BuiltInDc {
int id;
const char *ip;
int port;
};
const BuiltInDc kBuiltInDcs[] = {
{ 1, "149.154.175.50" , 443 },
{ 2, "149.154.167.51" , 443 },
{ 2, "95.161.76.100" , 443 },
{ 3, "149.154.175.100", 443 },
{ 4, "149.154.167.91" , 443 },
{ 5, "149.154.171.5" , 443 },
};
const BuiltInDc kBuiltInDcsIPv6[] = {
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000a", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000a", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000a", 443 },
{ 4, "2001:067c:04e8:f004:0000:0000:0000:000a", 443 },
{ 5, "2001:0b28:f23f:f005:0000:0000:0000:000a", 443 },
};
const BuiltInDc kBuiltInDcsTest[] = {
{ 1, "149.154.175.10" , 443 },
{ 2, "149.154.167.40" , 443 },
{ 3, "149.154.175.117", 443 }
};
const BuiltInDc kBuiltInDcsIPv6Test[] = {
{ 1, "2001:0b28:f23d:f001:0000:0000:0000:000e", 443 },
{ 2, "2001:067c:04e8:f002:0000:0000:0000:000e", 443 },
{ 3, "2001:0b28:f23d:f003:0000:0000:0000:000e", 443 }
};
const char *(kPublicRSAKeys[]) = { "\
-----BEGIN RSA PUBLIC KEY-----\n\
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n\
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\n\
@ -116,7 +151,7 @@ bool DcOptions::ValidateSecret(bytes::const_span secret) {
}
void DcOptions::readBuiltInPublicKeys() {
for (const auto key : PublicRSAKeys) {
for (const auto key : kPublicRSAKeys) {
const auto keyBytes = bytes::make_span(key, strlen(key));
auto parsed = RSAPublicKey(keyBytes);
if (parsed.valid()) {
@ -134,22 +169,29 @@ void DcOptions::constructFromBuiltIn() {
readBuiltInPublicKeys();
auto bdcs = builtInDcs();
for (auto i = 0, l = builtInDcsCount(); i != l; ++i) {
const auto list = cTestMode()
? gsl::make_span(kBuiltInDcsTest)
: gsl::make_span(kBuiltInDcs).subspan(0);
for (const auto &entry : list) {
const auto flags = Flag::f_static | 0;
const auto bdc = bdcs[i];
applyOneGuarded(bdc.id, flags, bdc.ip, bdc.port, {});
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: "
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3"
).arg(entry.id
).arg(entry.ip
).arg(entry.port));
}
auto bdcsipv6 = builtInDcsIPv6();
for (auto i = 0, l = builtInDcsCountIPv6(); i != l; ++i) {
const auto listv6 = cTestMode()
? gsl::make_span(kBuiltInDcsIPv6Test)
: gsl::make_span(kBuiltInDcsIPv6).subspan(0);
for (const auto &entry : listv6) {
const auto flags = Flag::f_static | Flag::f_ipv6;
const auto bdc = bdcsipv6[i];
applyOneGuarded(bdc.id, flags, bdc.ip, bdc.port, {});
applyOneGuarded(entry.id, flags, entry.ip, entry.port, {});
DEBUG_LOG(("MTP Info: adding built in DC %1 IPv6 connect option: "
"%2:%3").arg(bdc.id).arg(bdc.ip).arg(bdc.port));
"%2:%3"
).arg(entry.id
).arg(entry.ip
).arg(entry.port));
}
}