Open some telegram.org and Telegram links in IV.

This commit is contained in:
John Preston 2024-04-04 20:41:13 +04:00
parent 09f07a7a9d
commit ea178862d8
6 changed files with 146 additions and 60 deletions

View File

@ -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;
};

View File

@ -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<ClickHandlerContext>().ignoreIv) {
const auto my = context.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
Core::App().iv().openWithIvPreferred(controller, url, context);
return true;
}
}
auto parsed = UrlForAutoLogin(url);

View File

@ -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) {

View File

@ -267,10 +267,6 @@ private:
rpl::event_stream<> _attachBotsUpdates;
base::flat_set<not_null<UserData*>> _disclaimerAccepted;
base::flat_map<QString, WebPageData*> _ivCache;
QString _ivRequestUri;
mtpRequestId _ivRequestId = 0;
std::unique_ptr<Ui::BotWebView::Panel> _panel;
bool _catchingCancelInShowCall = false;

View File

@ -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<Main::Session*> 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<Window::SessionController*> controller,
QString uri,
QVariant context) {
auto my = context.value<ClickHandlerContext>();
my.sessionWindow = controller;
openWithIvPreferred(
&controller->session(),
uri,
QVariant::fromValue(my));
}
void Instance::openWithIvPreferred(
not_null<Main::Session*> session,
QString uri,
QVariant context) {
const auto openExternal = [=] {
auto my = context.value<ClickHandlerContext>();
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<ClickHandlerContext>();
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

View File

@ -41,6 +41,15 @@ public:
not_null<Data*> data,
QString hash);
void openWithIvPreferred(
not_null<Window::SessionController*> controller,
QString uri,
QVariant context = {});
void openWithIvPreferred(
not_null<Main::Session*> session,
QString uri,
QVariant context = {});
[[nodiscard]] bool hasActiveWindow(
not_null<Main::Session*> session) const;
@ -56,6 +65,8 @@ private:
void processJoinChannel(const QString &context);
void requestFull(not_null<Main::Session*> session, const QString &id);
void trackSession(not_null<Main::Session*> session);
const not_null<Delegate*> _delegate;
std::unique_ptr<Shown> _shown;
@ -68,8 +79,18 @@ private:
not_null<Main::Session*>,
base::flat_set<QString>> _fullRequested;
base::flat_map<
not_null<Main::Session*>,
base::flat_map<QString, WebPageData*>> _ivCache;
Main::Session *_ivRequestSession = nullptr;
QString _ivRequestUri;
mtpRequestId _ivRequestId = 0;
rpl::lifetime _lifetime;
};
[[nodiscard]] bool PreferForUri(const QString &uri);
} // namespace Iv