From 0f901b3728d604ccc55b0d30d3386fcc447151af Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 4 Mar 2018 23:04:13 +0300 Subject: [PATCH] Update API and use WebDocument for inline bots. --- Telegram/Resources/scheme.tl | 23 +- Telegram/SourceFiles/data/data_document.cpp | 15 +- Telegram/SourceFiles/data/data_document.h | 3 + .../SourceFiles/data/data_media_types.cpp | 40 +-- Telegram/SourceFiles/data/data_session.cpp | 79 ++++++ Telegram/SourceFiles/data/data_session.h | 10 + Telegram/SourceFiles/facades.cpp | 2 - Telegram/SourceFiles/facades.h | 1 - .../inline_bots/inline_bot_layout_item.cpp | 2 +- .../inline_bots/inline_bot_result.cpp | 243 +++++++++++------- .../inline_bots/inline_bot_result.h | 15 +- .../inline_bots/inline_results_widget.cpp | 6 +- Telegram/SourceFiles/mtproto/connection.cpp | 11 +- Telegram/SourceFiles/mtproto/mtp_instance.cpp | 1 - .../SourceFiles/storage/file_download.cpp | 47 ++-- Telegram/SourceFiles/storage/file_download.h | 15 +- Telegram/SourceFiles/ui/images.cpp | 160 +++++++++++- Telegram/SourceFiles/ui/images.h | 101 +++++--- 18 files changed, 536 insertions(+), 238 deletions(-) diff --git a/Telegram/Resources/scheme.tl b/Telegram/Resources/scheme.tl index f9785bb7dd..87d1f80b3a 100644 --- a/Telegram/Resources/scheme.tl +++ b/Telegram/Resources/scheme.tl @@ -460,11 +460,11 @@ photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#ea52fe5a dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes cdn_file_hashes:Vector = upload.File; +upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true id:int ip_address:string port:int = DcOption; -config#e644ec1f flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; +config#86b5778e flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int = Config; nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; @@ -569,8 +569,6 @@ stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; messages.allStickersNotModified#e86602c3 = messages.AllStickers; messages.allStickers#edfd405f hash:int sets:Vector = messages.AllStickers; -disabledFeature#ae636f24 feature:string description:string = DisabledFeature; - messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; contactLinkUnknown#5f4f9247 = ContactLink; @@ -697,7 +695,7 @@ inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:s inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult; +inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; @@ -708,7 +706,7 @@ botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period:int reply_markup:f botInlineMessageMediaVenue#4366232e flags:# geo:GeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; botInlineMessageMediaContact#35edb4d4 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineResult#9bebaeb9 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:BotInlineMessage = BotInlineResult; +botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector cache_time:int users:Vector = messages.BotResults; @@ -839,6 +837,7 @@ paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string e paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; webDocument#c61acbd8 url:string access_hash:long size:int mime_type:string attributes:Vector dc_id:int = WebDocument; +webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; @@ -927,8 +926,6 @@ channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?tru popularContact#5ce14175 client_id:long importers:int = PopularContact; -cdnFileHash#77eec38f offset:int limit:int hash:bytes = CdnFileHash; - messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; messages.favedStickers#f37f2f16 hash:int packs:Vector stickers:Vector = messages.FavedStickers; @@ -959,6 +956,8 @@ dialogPeerFeed#da429411 feed_id:int = DialogPeer; messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; messages.foundStickerSets#5108d648 hash:int sets:Vector = messages.FoundStickerSets; +fileHash#6242c773 offset:int limit:int hash:bytes = FileHash; + feedPosition#5059dc73 date:int peer:Peer id:int = FeedPosition; messages.feedMessagesNotModified#4678d0cf = messages.FeedMessages; @@ -996,7 +995,7 @@ auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentC auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -account.registerDevice#1389cc token_type:int token:string app_sandbox:Bool other_uids:Vector = Bool; +account.registerDevice#5cbea590 token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector = Bool; account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; @@ -1061,6 +1060,7 @@ messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6 messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.hideReportSpam#a8f1709b peer:InputPeer = Bool; messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings; +messages.report#bd82b658 peer:InputPeer id:Vector reason:ReportReason = Bool; messages.getChats#3c6aa187 id:Vector = messages.Chats; messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull; messages.editChatTitle#dc452855 chat_id:int title:string = Updates; @@ -1156,8 +1156,9 @@ upload.getFile#e3a6cfb5 location:InputFileLocation offset:int limit:int = upload upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; upload.getCdnFile#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile; -upload.reuploadCdnFile#1af91c09 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#f715c87b file_token:bytes offset:int = Vector; +upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; +upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector; +upload.getFileHashes#c7025931 location:InputFileLocation offset:int = Vector; help.getConfig#c4f9186b = Config; help.getNearestDc#1fb33026 = NearestDc; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index ee2c251fda..de8b611c92 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -717,11 +717,14 @@ void DocumentData::save( if (fromCloud == LoadFromCloudOrLocal) _loader->permitLoadFromCloud(); } else { status = FileReady; - if (!_access && !_url.isEmpty()) { + if (hasWebLocation()) { + _loader = new mtpFileLoader(&_urlLocation, size, fromCloud, autoLoading); + } else if (!_access && !_url.isEmpty()) { _loader = new webFileLoader(_url, toFile, fromCloud, autoLoading); } else { _loader = new mtpFileLoader(_dc, id, _access, _version, locationType(), toFile, size, (saveToCache() ? LoadToCacheAsWell : LoadToFileOnly), fromCloud, autoLoading); } + _loader->connect(_loader, SIGNAL(progress(FileLoader*)), App::main(), SLOT(documentLoadProgress(FileLoader*))); _loader->connect(_loader, SIGNAL(failed(FileLoader*,bool)), App::main(), SLOT(documentLoadFailed(FileLoader*,bool))); _loader->start(); @@ -935,8 +938,12 @@ bool DocumentData::hasRemoteLocation() const { return (_dc != 0 && _access != 0); } +bool DocumentData::hasWebLocation() const { + return _urlLocation.dc() != 0 && _urlLocation.accessHash() != 0; +} + bool DocumentData::isValid() const { - return hasRemoteLocation() || !_url.isEmpty(); + return hasRemoteLocation() || hasWebLocation() || !_url.isEmpty(); } MTPInputDocument DocumentData::mtpInput() const { @@ -1086,6 +1093,10 @@ void DocumentData::setContentUrl(const QString &url) { _url = url; } +void DocumentData::setWebLocation(const WebFileLocation &location) { + _urlLocation = location; +} + void DocumentData::collectLocalData(DocumentData *local) { if (local == this) return; diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 37f9cff2b1..f49806414b 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -148,7 +148,9 @@ public: bool setRemoteVersion(int32 version); // Returns true if version has changed. void setRemoteLocation(int32 dc, uint64 access); void setContentUrl(const QString &url); + void setWebLocation(const WebFileLocation &location); bool hasRemoteLocation() const; + bool hasWebLocation() const; bool isValid() const; MTPInputDocument mtpInput() const; @@ -198,6 +200,7 @@ private: QString _url; QString _filename; QString _mimeString; + WebFileLocation _urlLocation; not_null _session; diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index cd297ae9f1..c96f960fab 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -54,43 +54,9 @@ Invoice ComputeInvoiceData(const MTPDmessageMediaInvoice &data) { if (data.has_receipt_msg_id()) { result.receiptMsgId = data.vreceipt_msg_id.v; } - if (data.has_photo() && data.vphoto.type() == mtpc_webDocument) { - auto &doc = data.vphoto.c_webDocument(); - auto imageSize = QSize(); - for (auto &attribute : doc.vattributes.v) { - if (attribute.type() == mtpc_documentAttributeImageSize) { - auto &size = attribute.c_documentAttributeImageSize(); - imageSize = QSize(size.vw.v, size.vh.v); - break; - } - } - if (!imageSize.isEmpty()) { - auto thumbsize = shrinkToKeepAspect(imageSize.width(), imageSize.height(), 100, 100); - auto thumb = ImagePtr(thumbsize.width(), thumbsize.height()); - - auto mediumsize = shrinkToKeepAspect(imageSize.width(), imageSize.height(), 320, 320); - auto medium = ImagePtr(mediumsize.width(), mediumsize.height()); - - // We don't use size from WebDocument, because it is not reliable. - // It can be > 0 and different from the real size that we get in upload.WebFile result. - auto filesize = 0; // doc.vsize.v; - auto full = ImagePtr( - WebFileImageLocation( - imageSize.width(), - imageSize.height(), - doc.vdc_id.v, - doc.vurl.v, - doc.vaccess_hash.v), - filesize); - auto photoId = rand_value(); - result.photo = Auth().data().photo( - photoId, - uint64(0), - unixtime(), - thumb, - medium, - full); - } + if (data.has_photo()) { + const auto thumb = ImagePtr(); + result.photo = Auth().data().photoFromWeb(data.vphoto, thumb); } return result; } diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 14c17cc8cf..c3d2f8b7d1 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -644,6 +644,32 @@ void Session::photoConvert( photoApplyFields(original, data); } +PhotoData *Session::photoFromWeb( + const MTPWebDocument &data, + ImagePtr thumb) { + const auto full = ImagePtr(data); + if (full->isNull()) { + return nullptr; + } + const auto width = full->width(); + const auto height = full->height(); + if (thumb->isNull()) { + auto thumbsize = shrinkToKeepAspect(width, height, 100, 100); + thumb = ImagePtr(thumbsize.width(), thumbsize.height()); + } + + auto mediumsize = shrinkToKeepAspect(width, height, 320, 320); + auto medium = ImagePtr(mediumsize.width(), mediumsize.height()); + + return photo( + rand_value(), + uint64(0), + unixtime(), + thumb, + medium, + full); +} + void Session::photoApplyFields( not_null photo, const MTPPhoto &data) { @@ -850,6 +876,59 @@ void Session::documentConvert( } } +DocumentData *Session::documentFromWeb( + const MTPWebDocument &data, + ImagePtr thumb) { + switch (data.type()) { + case mtpc_webDocument: + return documentFromWeb(data.c_webDocument(), thumb); + + case mtpc_webDocumentNoProxy: + return documentFromWeb(data.c_webDocumentNoProxy(), thumb); + + } + Unexpected("Type in Session::documentFromWeb."); +} + +DocumentData *Session::documentFromWeb( + const MTPDwebDocument &data, + ImagePtr thumb) { + const auto result = document( + rand_value(), + uint64(0), + int32(0), + unixtime(), + data.vattributes.v, + data.vmime_type.v, + thumb, + MTP::maindc(), + int32(0), // data.vsize.v + StorageImageLocation()); + result->setWebLocation(WebFileLocation( + data.vdc_id.v, + data.vurl.v, + data.vaccess_hash.v)); + return result; +} + +DocumentData *Session::documentFromWeb( + const MTPDwebDocumentNoProxy &data, + ImagePtr thumb) { + const auto result = document( + rand_value(), + uint64(0), + int32(0), + unixtime(), + data.vattributes.v, + data.vmime_type.v, + thumb, + MTP::maindc(), + int32(0), // data.vsize.v + StorageImageLocation()); + result->setContentUrl(qs(data.vurl)); + return result; +} + void Session::documentApplyFields( not_null document, const MTPDocument &data) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 2f1e871d6d..a5ffcd032e 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -226,6 +226,7 @@ public: void photoConvert( not_null original, const MTPPhoto &data); + PhotoData *photoFromWeb(const MTPWebDocument &data, ImagePtr thumb); not_null document(DocumentId id); not_null document(const MTPDocument &data); @@ -247,6 +248,9 @@ public: void documentConvert( not_null original, const MTPDocument &data); + DocumentData *documentFromWeb( + const MTPWebDocument &data, + ImagePtr thumb); not_null webpage(WebPageId id); not_null webpage(const MTPWebPage &data); @@ -397,6 +401,12 @@ private: int32 dc, int32 size, const StorageImageLocation &thumbLocation); + DocumentData *documentFromWeb( + const MTPDwebDocument &data, + ImagePtr thumb); + DocumentData *documentFromWeb( + const MTPDwebDocumentNoProxy &data, + ImagePtr thumb); void webpageApplyFields( not_null page, diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 9e88bcd32e..3913429ee5 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -511,7 +511,6 @@ struct Data { int32 OnlineCloudTimeout = 300000; int32 NotifyCloudDelay = 30000; int32 NotifyDefaultDelay = 1500; - int32 ChatBigSize = 10; int32 PushChatPeriod = 60000; int32 PushChatLimit = 2; int32 SavedGifsLimit = 200; @@ -631,7 +630,6 @@ DefineVar(Global, int32, OnlineFocusTimeout); DefineVar(Global, int32, OnlineCloudTimeout); DefineVar(Global, int32, NotifyCloudDelay); DefineVar(Global, int32, NotifyDefaultDelay); -DefineVar(Global, int32, ChatBigSize); DefineVar(Global, int32, PushChatPeriod); DefineVar(Global, int32, PushChatLimit); DefineVar(Global, int32, SavedGifsLimit); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 8c2ad614b3..3028dcb789 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -328,7 +328,6 @@ DeclareVar(int32, OnlineFocusTimeout); // not from config DeclareVar(int32, OnlineCloudTimeout); DeclareVar(int32, NotifyCloudDelay); DeclareVar(int32, NotifyDefaultDelay); -DeclareVar(int32, ChatBigSize); DeclareVar(int32, PushChatPeriod); DeclareVar(int32, PushChatLimit); DeclareVar(int32, SavedGifsLimit); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index cfc37d613d..97b4ae674c 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -154,7 +154,7 @@ QPixmap ItemBase::getResultContactAvatar(int width, int height) const { } int ItemBase::getResultDuration() const { - return _result->_duration; + return 0; } QString ItemBase::getResultUrl() const { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index aec1921ad2..da1b8fbd3e 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -18,6 +18,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "auth_session.h" namespace InlineBots { +namespace { + +QString GetContentUrl(const MTPWebDocument &document) { + switch (document.type()) { + case mtpc_webDocument: + return qs(document.c_webDocument().vurl); + case mtpc_webDocumentNoProxy: + return qs(document.c_webDocumentNoProxy().vurl); + } + Unexpected("Type in GetContentUrl."); +} + +} // namespace Result::Result(const Creator &creator) : _queryId(creator.queryId), _type(creator.type) { } @@ -58,24 +71,30 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult const MTPBotInlineMessage *message = nullptr; switch (mtpData.type()) { case mtpc_botInlineResult: { - const auto &r(mtpData.c_botInlineResult()); + const auto &r = mtpData.c_botInlineResult(); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); if (r.has_url()) result->_url = qs(r.vurl); - if (r.has_thumb_url()) result->_thumb_url = qs(r.vthumb_url); - if (r.has_content_type()) result->_content_type = qs(r.vcontent_type); - if (r.has_content_url()) result->_content_url = qs(r.vcontent_url); - if (r.has_w()) result->_width = r.vw.v; - if (r.has_h()) result->_height = r.vh.v; - if (r.has_duration()) result->_duration = r.vduration.v; - if (!result->_thumb_url.startsWith(qstr("http://"), Qt::CaseInsensitive) && !result->_thumb_url.startsWith(qstr("https://"), Qt::CaseInsensitive)) { - result->_thumb_url = QString(); + if (r.has_thumb()) { + result->_thumb = ImagePtr(r.vthumb, result->thumbBox()); + } + if (r.has_content()) { + result->_content_url = GetContentUrl(r.vcontent); + if (result->_type == Type::Photo) { + result->_photo = Auth().data().photoFromWeb( + r.vcontent, + result->_thumb); + } else { + result->_document = Auth().data().documentFromWeb( + result->adjustAttributes(r.vcontent), + result->_thumb); + } } message = &r.vsend_message; } break; case mtpc_botInlineMediaResult: { - const auto &r(mtpData.c_botInlineMediaResult()); + const auto &r = mtpData.c_botInlineMediaResult(); result->_id = qs(r.vid); if (r.has_title()) result->_title = qs(r.vtitle); if (r.has_description()) result->_description = qs(r.vdescription); @@ -96,15 +115,17 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult // Ensure required media fields for layouts. if (result->_type == Type::Photo) { - if (!result->_photo && result->_content_url.isEmpty()) { + if (!result->_photo) { return nullptr; } - result->createPhoto(); - } else if (result->_type == Type::File || result->_type == Type::Gif || result->_type == Type::Sticker) { - if (!result->_document && result->_content_url.isEmpty()) { + } else if (result->_type == Type::Audio + || result->_type == Type::File + || result->_type == Type::Video + || result->_type == Type::Sticker + || result->_type == Type::Gif) { + if (!result->_document) { return nullptr; } - result->createDocument(); } switch (message->type()) { @@ -114,13 +135,17 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult ? TextUtilities::EntitiesFromMTP(r.ventities.v) : EntitiesInText(); if (result->_type == Type::Photo) { - result->createPhoto(); + if (!result->_photo) { + return nullptr; + } result->sendData = std::make_unique(result->_photo, qs(r.vmessage), entities); } else if (result->_type == Type::Game) { result->createGame(); result->sendData = std::make_unique(result->_game); } else { - result->createDocument(); + if (!result->_document) { + return nullptr; + } result->sendData = std::make_unique(result->_document, qs(r.vmessage), entities); } if (r.has_reply_markup()) { @@ -135,9 +160,17 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult : EntitiesInText(); result->sendData = std::make_unique(qs(r.vmessage), entities, r.is_no_webpage()); if (result->_type == Type::Photo) { - result->createPhoto(); - } else if (result->_type == Type::Audio || result->_type == Type::File || result->_type == Type::Video || result->_type == Type::Sticker || result->_type == Type::Gif) { - result->createDocument(); + if (!result->_photo) { + return nullptr; + } + } else if (result->_type == Type::Audio + || result->_type == Type::File + || result->_type == Type::Video + || result->_type == Type::Sticker + || result->_type == Type::Gif) { + if (!result->_document) { + return nullptr; + } } if (r.has_reply_markup()) { result->_mtpKeyboard = std::make_unique(r.vreply_markup); @@ -186,9 +219,6 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult return nullptr; } - if (result->_thumb->isNull() && !result->_thumb_url.isEmpty()) { - result->_thumb = ImagePtr(result->_thumb_url); - } LocationCoords location; if (result->getLocationCoords(&location)) { int32 w = st::inlineThumbSize, h = st::inlineThumbSize; @@ -307,80 +337,6 @@ QString Result::getLayoutDescription() const { Result::~Result() { } -void Result::createPhoto() { - if (_photo) return; - - if (_thumb_url.isEmpty()) { - QSize thumbsize = shrinkToKeepAspect(_width, _height, 100, 100); - _thumb = ImagePtr(thumbsize.width(), thumbsize.height()); - } else { - _thumb = ImagePtr(_thumb_url, QSize(320, 320)); - } -// ImagePtr medium = ImagePtr(_content_url, QSize(320, 320)); - QSize mediumsize = shrinkToKeepAspect(_width, _height, 320, 320); - ImagePtr medium = ImagePtr(mediumsize.width(), mediumsize.height()); - - ImagePtr full = ImagePtr(_content_url, _width, _height); - auto photoId = rand_value(); - _photo = Auth().data().photo( - photoId, - uint64(0), - unixtime(), - _thumb, - medium, - full); - _photo->thumb = _thumb; -} - -void Result::createDocument() { - if (_document) return; - - if (!_thumb_url.isEmpty()) { - _thumb = ImagePtr(_thumb_url, QSize(90, 90)); - } - - QString mime = _content_type; - - QVector attributes; - auto dimensions = QSize(_width, _height); - if (_type == Type::Gif) { - auto filename = (mime == qstr("video/mp4") ? "animation.gif.mp4" : "animation.gif"); - attributes.push_back(MTP_documentAttributeFilename(MTP_string(filename))); - attributes.push_back(MTP_documentAttributeAnimated()); - auto flags = MTPDdocumentAttributeVideo::Flags(0); - attributes.push_back(MTP_documentAttributeVideo(MTP_flags(flags), MTP_int(_duration), MTP_int(_width), MTP_int(_height))); - } else if (_type == Type::Video) { - auto flags = MTPDdocumentAttributeVideo::Flags(0); - attributes.push_back(MTP_documentAttributeVideo(MTP_flags(flags), MTP_int(_duration), MTP_int(_width), MTP_int(_height))); - } else if (_type == Type::Audio) { - auto flags = MTPDdocumentAttributeAudio::Flags(0); - if (mime == qstr("audio/ogg")) { - flags |= MTPDdocumentAttributeAudio::Flag::f_voice; - } else { - QStringList p = mimeTypeForName(mime).globPatterns(); - QString pattern = p.isEmpty() ? QString() : p.front(); - QString extension = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString()); - QString filename = filedialogDefaultName(qsl("inline"), extension, QString(), true); - attributes.push_back(MTP_documentAttributeFilename(MTP_string(filename))); - } - attributes.push_back(MTP_documentAttributeAudio(MTP_flags(flags), MTP_int(_duration), MTPstring(), MTPstring(), MTPbytes())); - } - - auto documentId = rand_value(); - _document = Auth().data().document( - documentId, - uint64(0), - int32(0), - unixtime(), - attributes, - mime, - _thumb, - MTP::maindc(), - int32(0), - StorageImageLocation()); - _document->setContentUrl(_content_url); -} - void Result::createGame() { if (_game) return; @@ -395,4 +351,97 @@ void Result::createGame() { _document); } +QSize Result::thumbBox() const { + return (_type == Type::Photo) ? QSize(100, 100) : QSize(90, 90); +} + +MTPWebDocument Result::adjustAttributes(const MTPWebDocument &document) { + switch (document.type()) { + case mtpc_webDocument: { + const auto &data = document.c_webDocument(); + return MTP_webDocument( + data.vurl, + data.vaccess_hash, + data.vsize, + data.vmime_type, + adjustAttributes(data.vattributes, data.vmime_type), + data.vdc_id); + } break; + + case mtpc_webDocumentNoProxy: { + const auto &data = document.c_webDocumentNoProxy(); + return MTP_webDocumentNoProxy( + data.vurl, + data.vsize, + data.vmime_type, + adjustAttributes(data.vattributes, data.vmime_type)); + } break; + } + Unexpected("Type in InlineBots::Result::adjustAttributes."); +} + +MTPVector Result::adjustAttributes( + const MTPVector &existing, + const MTPstring &mimeType) { + auto result = existing.v; + const auto find = [&](mtpTypeId attributeType) { + return ranges::find( + result, + attributeType, + [](const MTPDocumentAttribute &value) { return value.type(); }); + }; + const auto exists = [&](mtpTypeId attributeType) { + return find(attributeType) != result.cend(); + }; + const auto mime = qs(mimeType); + if (_type == Type::Gif) { + if (!exists(mtpc_documentAttributeFilename)) { + auto filename = (mime == qstr("video/mp4") + ? "animation.gif.mp4" + : "animation.gif"); + result.push_back(MTP_documentAttributeFilename( + MTP_string(filename))); + } + if (!exists(mtpc_documentAttributeAnimated)) { + result.push_back(MTP_documentAttributeAnimated()); + } + } else if (_type == Type::Audio) { + const auto audio = find(mtpc_documentAttributeAudio); + if (audio != result.cend()) { + using Flag = MTPDdocumentAttributeAudio::Flag; + if (mime == qstr("audio/ogg")) { + // We always treat audio/ogg as a voice message. + // It was that way before we started to get attributes here. + const auto &fields = audio->c_documentAttributeAudio(); + if (!(fields.vflags.v & Flag::f_voice)) { + *audio = MTP_documentAttributeAudio( + MTP_flags(fields.vflags.v | Flag::f_voice), + fields.vduration, + fields.vtitle, + fields.vperformer, + fields.vwaveform); + } + } + + const auto &fields = audio->c_documentAttributeAudio(); + if (!exists(mtpc_documentAttributeFilename) + && !(fields.vflags.v & Flag::f_voice)) { + const auto p = mimeTypeForName(mime).globPatterns(); + auto pattern = p.isEmpty() ? QString() : p.front(); + const auto extension = pattern.isEmpty() + ? qsl(".unknown") + : pattern.replace('*', QString()); + const auto filename = filedialogDefaultName( + qsl("inline"), + extension, + QString(), + true); + result.push_back( + MTP_documentAttributeFilename(MTP_string(filename))); + } + } + } + return MTP_vector(std::move(result)); +} + } // namespace InlineBots diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.h b/Telegram/SourceFiles/inline_bots/inline_bot_result.h index b54b6cb16c..c6478ade00 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.h @@ -63,9 +63,12 @@ public: ~Result(); private: - void createPhoto(); - void createDocument(); void createGame(); + QSize thumbBox() const; + MTPWebDocument adjustAttributes(const MTPWebDocument &document); + MTPVector adjustAttributes( + const MTPVector &document, + const MTPstring &mimeType); enum class Type { Unknown, @@ -92,12 +95,8 @@ private: uint64 _queryId = 0; QString _id; Type _type = Type::Unknown; - QString _title, _description, _url, _thumb_url; - QString _content_type, _content_url; - int _width = 0; - int _height = 0; - int _duration = 0; - + QString _title, _description, _url; + QString _content_url; DocumentData *_document = nullptr; PhotoData *_photo = nullptr; GameData *_game = nullptr; diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp index ebe4ed9ddd..e2b7ddea60 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp @@ -112,6 +112,8 @@ bool Inner::isRestrictedView() { int Inner::countHeight() { if (isRestrictedView()) { return st::stickerPanPadding + _restrictedLabel->height() + st::stickerPanPadding; + } else if (_rows.isEmpty() && !_switchPmButton) { + return st::stickerPanPadding + st::normalFont->height + st::stickerPanPadding; } auto result = st::stickerPanPadding; if (_switchPmButton) { @@ -1087,7 +1089,9 @@ void Widget::onInlineRequest() { auto it = _inlineCache.find(_inlineQuery); if (it != _inlineCache.cend()) { nextOffset = it->second->nextOffset; - if (nextOffset.isEmpty()) return; + if (nextOffset.isEmpty()) { + return; + } } Notify::inlineBotRequesting(true); _inlineRequestId = request(MTPmessages_GetInlineBotResults(MTP_flags(0), _inlineBot->inputUser, _inlineQueryPeer->input, MTPInputGeoPoint(), MTP_string(_inlineQuery), MTP_string(nextOffset))).done([this](const MTPmessages_BotResults &result, mtpRequestId requestId) { diff --git a/Telegram/SourceFiles/mtproto/connection.cpp b/Telegram/SourceFiles/mtproto/connection.cpp index 999f043df5..767b6f07c5 100644 --- a/Telegram/SourceFiles/mtproto/connection.cpp +++ b/Telegram/SourceFiles/mtproto/connection.cpp @@ -2030,8 +2030,15 @@ ConnectionPrivate::HandleResult ConnectionPrivate::handleOneReceived(const mtpPr QWriteLocker locker(sessionData->haveReceivedMutex()); sessionData->haveReceivedUpdates().push_back(SerializedMessage(update)); - if (cons != mtpc_updatesTooLong && cons != mtpc_updateShortMessage && cons != mtpc_updateShortChatMessage && cons != mtpc_updateShortSentMessage && cons != mtpc_updateShort && cons != mtpc_updatesCombined && cons != mtpc_updates) { - LOG(("Message Error: unknown constructor %1").arg(cons)); // maybe new api?.. + if (cons != mtpc_updatesTooLong + && cons != mtpc_updateShortMessage + && cons != mtpc_updateShortChatMessage + && cons != mtpc_updateShortSentMessage + && cons != mtpc_updateShort + && cons != mtpc_updatesCombined + && cons != mtpc_updates) { + // Maybe some new unknown update? + LOG(("Message Error: unknown constructor %1").arg(cons)); } } else { LOG(("Message Error: unexpected updates in dcType: %1").arg(static_cast(_dcType))); diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 7812962461..de208b1ad0 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -598,7 +598,6 @@ void Instance::Private::configLoadDone(const MTPConfig &result) { Global::SetOnlineCloudTimeout(data.vonline_cloud_timeout_ms.v); Global::SetNotifyCloudDelay(data.vnotify_cloud_delay_ms.v); Global::SetNotifyDefaultDelay(data.vnotify_default_delay_ms.v); - Global::SetChatBigSize(data.vchat_big_size.v); Global::SetPushChatPeriod(data.vpush_chat_period_ms.v); Global::SetPushChatLimit(data.vpush_chat_limit.v); Global::SetSavedGifsLimit(data.vsaved_gifs_limit.v); diff --git a/Telegram/SourceFiles/storage/file_download.cpp b/Telegram/SourceFiles/storage/file_download.cpp index 26167f62d5..a02689e610 100644 --- a/Telegram/SourceFiles/storage/file_download.cpp +++ b/Telegram/SourceFiles/storage/file_download.cpp @@ -416,7 +416,7 @@ mtpFileLoader::mtpFileLoader(int32 dc, uint64 id, uint64 accessHash, int32 versi _queue = &i.value(); } -mtpFileLoader::mtpFileLoader(const WebFileImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading) +mtpFileLoader::mtpFileLoader(const WebFileLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading) : FileLoader(QString(), size, UnknownFileLocation, LoadToCacheAsWell, fromCloud, autoLoading) , _dcId(location->dc()) , _urlLocation(location) { @@ -484,18 +484,19 @@ void mtpFileLoader::makeRequest(int offset) { return MTP::send(MTPupload_GetWebFile(MTP_inputWebFileLocation(MTP_bytes(_urlLocation->url()), MTP_long(_urlLocation->accessHash())), MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::webPartLoaded), rpcFail(&mtpFileLoader::partFailed), shiftedDcId, 50); } else { Assert(requestData.dcId == _dcId); - auto location = [this] { - if (_location) { - return MTP_inputFileLocation(MTP_long(_location->volume()), MTP_int(_location->local()), MTP_long(_location->secret())); - } - return MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_accessHash), MTP_int(_version)); - }; - return MTP::send(MTPupload_GetFile(location(), MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::normalPartLoaded), rpcFail(&mtpFileLoader::partFailed), shiftedDcId, 50); + return MTP::send(MTPupload_GetFile(computeLocation(), MTP_int(offset), MTP_int(limit)), rpcDone(&mtpFileLoader::normalPartLoaded), rpcFail(&mtpFileLoader::partFailed), shiftedDcId, 50); } }; placeSentRequest(send(), requestData); } +MTPInputFileLocation mtpFileLoader::computeLocation() const { + if (_location) { + return MTP_inputFileLocation(MTP_long(_location->volume()), MTP_int(_location->local()), MTP_long(_location->secret())); + } + return MTP_inputDocumentFileLocation(MTP_long(_id), MTP_long(_accessHash), MTP_int(_version)); +} + void mtpFileLoader::requestMoreCdnFileHashes() { Expects(!_finished); @@ -609,13 +610,13 @@ mtpFileLoader::CheckCdnHashResult mtpFileLoader::checkCdnFileHash(int offset, ba return CheckCdnHashResult::Good; } -void mtpFileLoader::reuploadDone(const MTPVector &result, mtpRequestId requestId) { +void mtpFileLoader::reuploadDone(const MTPVector &result, mtpRequestId requestId) { auto offset = finishSentRequestGetOffset(requestId); addCdnHashes(result.v); makeRequest(offset); } -void mtpFileLoader::getCdnFileHashesDone(const MTPVector &result, mtpRequestId requestId) { +void mtpFileLoader::getCdnFileHashesDone(const MTPVector &result, mtpRequestId requestId) { Expects(!_finished); Expects(_cdnHashesRequestId == requestId); @@ -805,7 +806,7 @@ bool mtpFileLoader::cdnPartFailed(const RPCError &error, mtpRequestId requestId) } if (error.type() == qstr("FILE_TOKEN_INVALID") || error.type() == qstr("REQUEST_TOKEN_INVALID")) { auto offset = finishSentRequestGetOffset(requestId); - changeCDNParams(offset, 0, QByteArray(), QByteArray(), QByteArray(), QVector()); + changeCDNParams(offset, 0, QByteArray(), QByteArray(), QByteArray(), QVector()); return true; } return partFailed(error); @@ -819,19 +820,29 @@ void mtpFileLoader::cancelRequests() { } } -void mtpFileLoader::switchToCDN(int offset, const MTPDupload_fileCdnRedirect &redirect) { - changeCDNParams(offset, redirect.vdc_id.v, redirect.vfile_token.v, redirect.vencryption_key.v, redirect.vencryption_iv.v, redirect.vcdn_file_hashes.v); +void mtpFileLoader::switchToCDN( + int offset, + const MTPDupload_fileCdnRedirect &redirect) { + changeCDNParams( + offset, + redirect.vdc_id.v, + redirect.vfile_token.v, + redirect.vencryption_key.v, + redirect.vencryption_iv.v, + redirect.vfile_hashes.v); } -void mtpFileLoader::addCdnHashes(const QVector &hashes) { +void mtpFileLoader::addCdnHashes(const QVector &hashes) { for_const (auto &hash, hashes) { - Assert(hash.type() == mtpc_cdnFileHash); - auto &data = hash.c_cdnFileHash(); - _cdnFileHashes.emplace(data.voffset.v, CdnFileHash { data.vlimit.v, data.vhash.v }); + Assert(hash.type() == mtpc_fileHash); + auto &data = hash.c_fileHash(); + _cdnFileHashes.emplace( + data.voffset.v, + CdnFileHash { data.vlimit.v, data.vhash.v }); } } -void mtpFileLoader::changeCDNParams(int offset, MTP::DcId dcId, const QByteArray &token, const QByteArray &encryptionKey, const QByteArray &encryptionIV, const QVector &hashes) { +void mtpFileLoader::changeCDNParams(int offset, MTP::DcId dcId, const QByteArray &token, const QByteArray &encryptionKey, const QByteArray &encryptionIV, const QVector &hashes) { if (dcId != 0 && (encryptionKey.size() != MTP::CTRState::KeySize || encryptionIV.size() != MTP::CTRState::IvecSize)) { LOG(("Message Error: Wrong key (%1) / iv (%2) size in CDN params").arg(encryptionKey.size()).arg(encryptionIV.size())); cancel(true); diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index 2533cf7bc9..59e88c1bae 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -176,14 +176,14 @@ protected: }; class StorageImageLocation; -class WebFileImageLocation; +class WebFileLocation; class mtpFileLoader : public FileLoader, public RPCSender { Q_OBJECT public: mtpFileLoader(const StorageImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading); mtpFileLoader(int32 dc, uint64 id, uint64 accessHash, int32 version, LocationType type, const QString &toFile, int32 size, LoadToCacheSetting toCache, LoadFromCloudSetting fromCloud, bool autoLoading); - mtpFileLoader(const WebFileImageLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading); + mtpFileLoader(const WebFileLocation *location, int32 size, LoadFromCloudSetting fromCloud, bool autoLoading); int32 currentOffset(bool includeSkipped = false) const override; @@ -217,13 +217,14 @@ private: RequestData prepareRequest(int offset) const; void makeRequest(int offset); + MTPInputFileLocation computeLocation() const; bool loadPart() override; void normalPartLoaded(const MTPupload_File &result, mtpRequestId requestId); void webPartLoaded(const MTPupload_WebFile &result, mtpRequestId requestId); void cdnPartLoaded(const MTPupload_CdnFile &result, mtpRequestId requestId); - void reuploadDone(const MTPVector &result, mtpRequestId requestId); + void reuploadDone(const MTPVector &result, mtpRequestId requestId); void requestMoreCdnFileHashes(); - void getCdnFileHashesDone(const MTPVector &result, mtpRequestId requestId); + void getCdnFileHashesDone(const MTPVector &result, mtpRequestId requestId); bool feedPart(int offset, base::const_byte_span bytes); void partLoaded(int offset, base::const_byte_span bytes); @@ -234,8 +235,8 @@ private: void placeSentRequest(mtpRequestId requestId, const RequestData &requestData); int finishSentRequestGetOffset(mtpRequestId requestId); void switchToCDN(int offset, const MTPDupload_fileCdnRedirect &redirect); - void addCdnHashes(const QVector &hashes); - void changeCDNParams(int offset, MTP::DcId dcId, const QByteArray &token, const QByteArray &encryptionKey, const QByteArray &encryptionIV, const QVector &hashes); + void addCdnHashes(const QVector &hashes); + void changeCDNParams(int offset, MTP::DcId dcId, const QByteArray &token, const QByteArray &encryptionKey, const QByteArray &encryptionIV, const QVector &hashes); enum class CheckCdnHashResult { NoHash, @@ -257,7 +258,7 @@ private: uint64 _accessHash = 0; int32 _version = 0; - const WebFileImageLocation *_urlLocation = nullptr; // for webdocument locations + const WebFileLocation *_urlLocation = nullptr; // for webdocument locations MTP::DcId _cdnDcId = 0; QByteArray _cdnToken; diff --git a/Telegram/SourceFiles/ui/images.cpp b/Telegram/SourceFiles/ui/images.cpp index b29f6eeb80..f0e65bd3b8 100644 --- a/Telegram/SourceFiles/ui/images.cpp +++ b/Telegram/SourceFiles/ui/images.cpp @@ -403,7 +403,7 @@ uint64 SinglePixKey(Images::Options options) { } // namespace StorageImageLocation StorageImageLocation::Null; -WebFileImageLocation WebFileImageLocation::Null; +WebFileLocation WebFileLocation::Null; bool Image::isNull() const { return (this == blank()); @@ -1040,25 +1040,45 @@ FileLoader *StorageImage::createLoader(LoadFromCloudSetting fromCloud, bool auto return new mtpFileLoader(&_location, _size, fromCloud, autoLoading); } -WebFileImage::WebFileImage(const WebFileImageLocation &location, int32 size) +WebFileImage::WebFileImage( + const WebFileLocation &location, + QSize box, + int size) : _location(location) +, _box(box) +, _width(0) +, _height(0) , _size(size) { } -int32 WebFileImage::countWidth() const { - return _location.width(); +WebFileImage::WebFileImage( + const WebFileLocation &location, + int width, + int height, + int size) +: _location(location) +, _width(width) +, _height(height) +, _size(size) { } -int32 WebFileImage::countHeight() const { - return _location.height(); +int WebFileImage::countWidth() const { + return _width; } -void WebFileImage::setInformation(int32 size, int32 width, int32 height) { +int WebFileImage::countHeight() const { + return _height; +} + +void WebFileImage::setInformation(int size, int width, int height) { _size = size; - _location.setSize(width, height); + _width = width; + _height = height; } -FileLoader *WebFileImage::createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) { +FileLoader *WebFileImage::createLoader( + LoadFromCloudSetting fromCloud, + bool autoLoading) { if (_location.isNull()) return 0; return new mtpFileLoader(&_location, _size, fromCloud, autoLoading); } @@ -1146,10 +1166,19 @@ void DelayedStorageImage::cancel() { StorageImage::cancel(); } -WebImage::WebImage(const QString &url, QSize box) : _url(url), _box(box), _size(0), _width(0), _height(0) { +WebImage::WebImage(const QString &url, QSize box) +: _url(url) +, _box(box) +, _size(0) +, _width(0) +, _height(0) { } -WebImage::WebImage(const QString &url, int width, int height) : _url(url), _size(0), _width(width), _height(height) { +WebImage::WebImage(const QString &url, int width, int height) +: _url(url) +, _size(0) +, _width(width) +, _height(height) { } void WebImage::setSize(int width, int height) { @@ -1256,11 +1285,116 @@ StorageImage *getImage(const StorageImageLocation &location, const QByteArray &b return i.value(); } -WebFileImage *getImage(const WebFileImageLocation &location, int32 size) { +QSize getImageSize(const QVector &attributes) { + for (const auto &attribute : attributes) { + if (attribute.type() == mtpc_documentAttributeImageSize) { + auto &size = attribute.c_documentAttributeImageSize(); + return QSize(size.vw.v, size.vh.v); + } + } + return QSize(); +} + +Image *getImage(const MTPDwebDocument &document) { + const auto size = getImageSize(document.vattributes.v); + if (size.isEmpty()) { + return blank(); + } + + // We don't use size from WebDocument, because it is not reliable. + // It can be > 0 and different from the real size that we get in upload.WebFile result. + auto filesize = 0; // document.vsize.v; + return getImage( + WebFileLocation( + document.vdc_id.v, + document.vurl.v, + document.vaccess_hash.v), + size.width(), + size.height(), + filesize); +} + +Image *getImage(const MTPDwebDocumentNoProxy &document) { + const auto size = getImageSize(document.vattributes.v); + if (size.isEmpty()) { + return blank(); + } + + return getImage(qs(document.vurl), size.width(), size.height()); +} + +Image *getImage(const MTPDwebDocument &document, QSize box) { + const auto size = getImageSize(document.vattributes.v); + if (size.isEmpty()) { + return blank(); + } + + // We don't use size from WebDocument, because it is not reliable. + // It can be > 0 and different from the real size that we get in upload.WebFile result. + auto filesize = 0; // document.vsize.v; + return getImage( + WebFileLocation( + document.vdc_id.v, + document.vurl.v, + document.vaccess_hash.v), + box, + filesize); +} + +Image *getImage(const MTPDwebDocumentNoProxy &document, QSize box) { + const auto size = getImageSize(document.vattributes.v); + if (size.isEmpty()) { + return blank(); + } + + return getImage(qs(document.vurl), box); +} + +Image *getImage(const MTPWebDocument &document) { + switch (document.type()) { + case mtpc_webDocument: + return getImage(document.c_webDocument()); + case mtpc_webDocumentNoProxy: + return getImage(document.c_webDocumentNoProxy()); + } + Unexpected("Type in getImage(MTPWebDocument)."); +} + +Image *getImage(const MTPWebDocument &document, QSize box) { + switch (document.type()) { + case mtpc_webDocument: + return getImage(document.c_webDocument(), box); + case mtpc_webDocumentNoProxy: + return getImage(document.c_webDocumentNoProxy(), box); + } + Unexpected("Type in getImage(MTPWebDocument)."); +} + +WebFileImage *getImage( + const WebFileLocation &location, + QSize box, + int size) { auto key = storageKey(location); auto i = webFileImages.constFind(key); if (i == webFileImages.cend()) { - i = webFileImages.insert(key, new WebFileImage(location, size)); + i = webFileImages.insert( + key, + new WebFileImage(location, box, size)); + } + return i.value(); +} + +WebFileImage *getImage( + const WebFileLocation &location, + int width, + int height, + int size) { + auto key = storageKey(location); + auto i = webFileImages.constFind(key); + if (i == webFileImages.cend()) { + i = webFileImages.insert( + key, + new WebFileImage(location, width, height, size)); } return i.value(); } diff --git a/Telegram/SourceFiles/ui/images.h b/Telegram/SourceFiles/ui/images.h index 7a7dfeb1ca..0a83ce8742 100644 --- a/Telegram/SourceFiles/ui/images.h +++ b/Telegram/SourceFiles/ui/images.h @@ -183,23 +183,17 @@ inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation return !(a == b); } -class WebFileImageLocation { +class WebFileLocation { public: - WebFileImageLocation() = default; - WebFileImageLocation(int32 width, int32 height, int32 dc, const QByteArray &url, uint64 accessHash) : _widthheight(packIntInt(width, height)), _accessHash(accessHash), _url(url), _dc(dc) { + WebFileLocation() = default; + WebFileLocation(int32 dc, const QByteArray &url, uint64 accessHash) + : _accessHash(accessHash) + , _url(url) + , _dc(dc) { } bool isNull() const { return !_dc; } - int32 width() const { - return unpackIntFirst(_widthheight); - } - int32 height() const { - return unpackIntSecond(_widthheight); - } - void setSize(int32 width, int32 height) { - _widthheight = packIntInt(width, height); - } int32 dc() const { return _dc; } @@ -210,21 +204,20 @@ public: return _url; } - static WebFileImageLocation Null; + static WebFileLocation Null; private: - uint64 _widthheight = 0; uint64 _accessHash = 0; QByteArray _url; int32 _dc = 0; - friend inline bool operator==(const WebFileImageLocation &a, const WebFileImageLocation &b) { + friend inline bool operator==(const WebFileLocation &a, const WebFileLocation &b) { return (a._dc == b._dc) && (a._accessHash == b._accessHash) && (a._url == b._url); } }; -inline bool operator!=(const WebFileImageLocation &a, const WebFileImageLocation &b) { +inline bool operator!=(const WebFileLocation &a, const WebFileLocation &b) { return !(a == b); } @@ -354,10 +347,13 @@ inline StorageKey storageKey(const MTPDfileLocation &location) { inline StorageKey storageKey(const StorageImageLocation &location) { return storageKey(location.dc(), location.volume(), location.local()); } -inline StorageKey storageKey(const WebFileImageLocation &location) { +inline StorageKey storageKey(const WebFileLocation &location) { auto url = location.url(); auto sha = hashSha1(url.data(), url.size()); - return storageKey(location.dc(), *reinterpret_cast(sha.data()), *reinterpret_cast(sha.data() + sizeof(uint64))); + return storageKey( + location.dc(), + *reinterpret_cast(sha.data()), + *reinterpret_cast(sha.data() + sizeof(uint64))); } class RemoteImage : public Image { @@ -427,17 +423,25 @@ protected: class WebFileImage : public RemoteImage { public: - WebFileImage(const WebFileImageLocation &location, int32 size = 0); + WebFileImage(const WebFileLocation &location, QSize box, int size = 0); + WebFileImage(const WebFileLocation &location, int width, int height, int size = 0); protected: - void setInformation(int32 size, int32 width, int32 height) override; + void setInformation(int size, int width, int height) override; FileLoader *createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) override; - WebFileImageLocation _location; - int32 _size; + QSize shrinkBox() const override { + return _box; + } - int32 countWidth() const override; - int32 countHeight() const override; + WebFileLocation _location; + QSize _box; + int _width = 0; + int _height = 0; + int _size = 0; + + int countWidth() const override; + int countHeight() const override; }; @@ -476,7 +480,6 @@ private: class WebImage : public RemoteImage { public: - // If !box.isEmpty() then resize the image to fit in this box. WebImage(const QString &url, QSize box = QSize()); WebImage(const QString &url, int width, int height); @@ -484,7 +487,6 @@ public: void setSize(int width, int height); protected: - QSize shrinkBox() const override { return _box; } @@ -502,16 +504,33 @@ private: }; namespace internal { - Image *getImage(const QString &file, QByteArray format); - Image *getImage(const QString &url, QSize box); - Image *getImage(const QString &url, int width, int height); - Image *getImage(const QByteArray &filecontent, QByteArray format); - Image *getImage(const QPixmap &pixmap, QByteArray format); - Image *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap); - Image *getImage(int32 width, int32 height); - StorageImage *getImage(const StorageImageLocation &location, int32 size = 0); - StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes); - WebFileImage *getImage(const WebFileImageLocation &location, int32 size = 0); + +Image *getImage(const QString &file, QByteArray format); +Image *getImage(const QString &url, QSize box); +Image *getImage(const QString &url, int width, int height); +Image *getImage(const QByteArray &filecontent, QByteArray format); +Image *getImage(const QPixmap &pixmap, QByteArray format); +Image *getImage( + const QByteArray &filecontent, + QByteArray format, + const QPixmap &pixmap); +Image *getImage(int32 width, int32 height); +StorageImage *getImage(const StorageImageLocation &location, int size = 0); +StorageImage *getImage( + const StorageImageLocation &location, + const QByteArray &bytes); +Image *getImage(const MTPWebDocument &location); +Image *getImage(const MTPWebDocument &location, QSize box); +WebFileImage *getImage( + const WebFileLocation &location, + int width, + int height, + int size = 0); +WebFileImage *getImage( + const WebFileLocation &location, + QSize box, + int size = 0); + } // namespace internal class ImagePtr : public ManagedPtr { @@ -533,7 +552,15 @@ public: } ImagePtr(const StorageImageLocation &location, const QByteArray &bytes) : Parent(internal::getImage(location, bytes)) { } - ImagePtr(const WebFileImageLocation &location, int32 size = 0) : Parent(internal::getImage(location, size)) { + ImagePtr(const MTPWebDocument &location) : Parent(internal::getImage(location)) { + } + ImagePtr(const MTPWebDocument &location, QSize box) : Parent(internal::getImage(location, box)) { + } + ImagePtr(const WebFileLocation &location, int width, int height, int size = 0) + : Parent(internal::getImage(location, width, height, size)) { + } + ImagePtr(const WebFileLocation &location, QSize box, int size = 0) + : Parent(internal::getImage(location, box, size)) { } ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def = ImagePtr()); ImagePtr(int32 width, int32 height) : Parent(internal::getImage(width, height)) {