diff --git a/Telegram/SourceFiles/core/click_handler_types.h b/Telegram/SourceFiles/core/click_handler_types.h index 15a7dc1f95..e064d1e2d4 100644 --- a/Telegram/SourceFiles/core/click_handler_types.h +++ b/Telegram/SourceFiles/core/click_handler_types.h @@ -46,6 +46,7 @@ struct ClickHandlerContext { bool mayShowConfirmation = false; bool skipBotAutoLogin = false; bool botStartAutoSubmit = false; + bool ignoreIv = false; // Is filled from peer info. PeerData *peer = nullptr; }; diff --git a/Telegram/SourceFiles/core/ui_integration.cpp b/Telegram/SourceFiles/core/ui_integration.cpp index e6b62203dc..6de0c7570a 100644 --- a/Telegram/SourceFiles/core/ui_integration.cpp +++ b/Telegram/SourceFiles/core/ui_integration.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/stickers/data_custom_emoji.h" #include "data/data_session.h" #include "data/data_sponsored_messages.h" +#include "iv/iv_instance.h" #include "ui/text/text_custom_emoji.h" #include "ui/basic_click_handlers.h" #include "ui/emoji_config.h" @@ -237,6 +238,13 @@ bool UiIntegration::handleUrlClick( } else if (local.startsWith(u"internal:"_q, Qt::CaseInsensitive)) { Core::App().openInternalUrl(local, context); return true; + } else if (Iv::PreferForUri(url) + && !context.value().ignoreIv) { + const auto my = context.value(); + if (const auto controller = my.sessionWindow.get()) { + Core::App().iv().openWithIvPreferred(controller, url, context); + return true; + } } auto parsed = UrlForAutoLogin(url); diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index c3f78b2d05..682afe3ded 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -656,50 +656,12 @@ void AttachWebView::botHandleMenuButton(Ui::BotWebView::MenuButton button) { } void AttachWebView::botOpenIvLink(QString uri) { - const auto parts = uri.split('#'); - if (parts.isEmpty()) { - return; + const auto window = _context ? _context->controller.get() : nullptr; + if (window) { + Core::App().iv().openWithIvPreferred(window, uri); + } else { + Core::App().iv().openWithIvPreferred(_session, uri); } - const auto hash = (parts.size() > 1) ? parts[1] : u""_q; - const auto url = parts[0]; - if (const auto i = _ivCache.find(url); i != end(_ivCache)) { - const auto page = i->second; - if (page && page->iv) { - const auto window = _context - ? _context->controller.get() - : nullptr; - if (window) { - Core::App().iv().show(window, page->iv.get(), hash); - } else { - Core::App().iv().show(_session, page->iv.get(), hash); - } - } else { - UrlClickHandler::Open(uri); - } - return; - } else if (_ivRequestUri == uri) { - return; - } else if (_ivRequestId) { - _session->api().request(_ivRequestId).cancel(); - } - const auto finish = [=](WebPageData *page) { - _ivRequestId = 0; - _ivRequestUri = QString(); - _ivCache[url] = page; - botOpenIvLink(uri); - }; - _ivRequestUri = uri; - _ivRequestId = _session->api().request(MTPmessages_GetWebPage( - MTP_string(url), - MTP_int(0) - )).done([=](const MTPmessages_WebPage &result) { - const auto &data = result.data(); - _session->data().processUsers(data.vusers()); - _session->data().processChats(data.vchats()); - finish(_session->data().processWebpage(data.vwebpage())); - }).fail([=] { - finish(nullptr); - }).send(); } void AttachWebView::botSendData(QByteArray data) { diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h index c172cd5c37..aebf993325 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h @@ -267,10 +267,6 @@ private: rpl::event_stream<> _attachBotsUpdates; base::flat_set> _disclaimerAccepted; - base::flat_map _ivCache; - QString _ivRequestUri; - mtpRequestId _ivRequestId = 0; - std::unique_ptr _panel; bool _catchingCancelInShowCall = false; diff --git a/Telegram/SourceFiles/iv/iv_instance.cpp b/Telegram/SourceFiles/iv/iv_instance.cpp index f84d55223a..62527e35fc 100644 --- a/Telegram/SourceFiles/iv/iv_instance.cpp +++ b/Telegram/SourceFiles/iv/iv_instance.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/application.h" #include "core/file_utilities.h" #include "core/shortcuts.h" +#include "core/click_handler_types.h" #include "data/data_changes.h" #include "data/data_channel.h" #include "data/data_cloud_file.h" @@ -926,20 +927,104 @@ void Instance::show( } }, _shown->lifetime()); - if (!_tracking.contains(session)) { - _tracking.emplace(session); - session->lifetime().add([=] { - _tracking.remove(session); - _joining.remove(session); - _fullRequested.remove(session); - if (_shownSession == session) { - _shownSession = nullptr; - } - if (_shown && _shown->showingFrom(session)) { - _shown = nullptr; - } - }); + trackSession(session); +} + +void Instance::trackSession(not_null session) { + if (!_tracking.emplace(session).second) { + return; } + session->lifetime().add([=] { + _tracking.remove(session); + _joining.remove(session); + _fullRequested.remove(session); + _ivCache.remove(session); + if (_ivRequestSession == session) { + session->api().request(_ivRequestId).cancel(); + _ivRequestSession = nullptr; + _ivRequestUri = QString(); + _ivRequestId = 0; + } + if (_shownSession == session) { + _shownSession = nullptr; + } + if (_shown && _shown->showingFrom(session)) { + _shown = nullptr; + } + }); +} + +void Instance::openWithIvPreferred( + not_null controller, + QString uri, + QVariant context) { + auto my = context.value(); + my.sessionWindow = controller; + openWithIvPreferred( + &controller->session(), + uri, + QVariant::fromValue(my)); +} + +void Instance::openWithIvPreferred( + not_null session, + QString uri, + QVariant context) { + const auto openExternal = [=] { + auto my = context.value(); + my.ignoreIv = true; + UrlClickHandler::Open(uri, QVariant::fromValue(my)); + }; + const auto parts = uri.split('#'); + if (parts.isEmpty() || parts[0].isEmpty()) { + return; + } else if (!ShowButton()) { + return openExternal(); + } + trackSession(session); + const auto hash = (parts.size() > 1) ? parts[1] : u""_q; + const auto url = parts[0]; + auto &cache = _ivCache[session]; + if (const auto i = cache.find(url); i != end(cache)) { + const auto page = i->second; + if (page && page->iv) { + auto my = context.value(); + if (const auto window = my.sessionWindow.get()) { + show(window, page->iv.get(), hash); + } else { + show(session, page->iv.get(), hash); + } + } else { + openExternal(); + } + return; + } else if (_ivRequestSession == session.get() && _ivRequestUri == uri) { + return; + } else if (_ivRequestId) { + _ivRequestSession->api().request(_ivRequestId).cancel(); + } + const auto finish = [=](WebPageData *page) { + Expects(_ivRequestSession == session); + + _ivRequestId = 0; + _ivRequestUri = QString(); + _ivRequestSession = nullptr; + _ivCache[session][url] = page; + openWithIvPreferred(session, uri, context); + }; + _ivRequestSession = session; + _ivRequestUri = uri; + _ivRequestId = session->api().request(MTPmessages_GetWebPage( + MTP_string(url), + MTP_int(0) + )).done([=](const MTPmessages_WebPage &result) { + const auto &data = result.data(); + session->data().processUsers(data.vusers()); + session->data().processChats(data.vchats()); + finish(session->data().processWebpage(data.vwebpage())); + }).fail([=] { + finish(nullptr); + }).send(); } void Instance::requestFull( @@ -1033,4 +1118,17 @@ void Instance::closeAll() { _shown = nullptr; } +bool PreferForUri(const QString &uri) { + const auto url = QUrl(uri); + const auto host = url.host().toLower(); + const auto path = url.path().toLower(); + return (host == u"telegra.ph"_q) + || (host == u"te.legra.ph"_q) + || (host == u"graph.org"_q) + || (host == u"telegram.org"_q + && (path.startsWith(u"/faq"_q) + || path.startsWith(u"/privacy"_q) + || path.startsWith(u"/blog"_q))); +} + } // namespace Iv diff --git a/Telegram/SourceFiles/iv/iv_instance.h b/Telegram/SourceFiles/iv/iv_instance.h index 608c9c2835..1299bbdddb 100644 --- a/Telegram/SourceFiles/iv/iv_instance.h +++ b/Telegram/SourceFiles/iv/iv_instance.h @@ -41,6 +41,15 @@ public: not_null data, QString hash); + void openWithIvPreferred( + not_null controller, + QString uri, + QVariant context = {}); + void openWithIvPreferred( + not_null session, + QString uri, + QVariant context = {}); + [[nodiscard]] bool hasActiveWindow( not_null session) const; @@ -56,6 +65,8 @@ private: void processJoinChannel(const QString &context); void requestFull(not_null session, const QString &id); + void trackSession(not_null session); + const not_null _delegate; std::unique_ptr _shown; @@ -68,8 +79,18 @@ private: not_null, base::flat_set> _fullRequested; + base::flat_map< + not_null, + base::flat_map> _ivCache; + Main::Session *_ivRequestSession = nullptr; + QString _ivRequestUri; + mtpRequestId _ivRequestId = 0; + + rpl::lifetime _lifetime; }; +[[nodiscard]] bool PreferForUri(const QString &uri); + } // namespace Iv