mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Support clipboard reading for attach menu bots.
This commit is contained in:
parent
4c181b6d08
commit
c647afec02
4 changed files with 100 additions and 33 deletions
|
@ -490,7 +490,11 @@ void AttachWebView::request(const WebViewButton &button) {
|
||||||
)).done([=](const MTPWebViewResult &result) {
|
)).done([=](const MTPWebViewResult &result) {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
result.match([&](const MTPDwebViewResultUrl &data) {
|
result.match([&](const MTPDwebViewResultUrl &data) {
|
||||||
show(data.vquery_id().v, qs(data.vurl()), button.text);
|
show(
|
||||||
|
data.vquery_id().v,
|
||||||
|
qs(data.vurl()),
|
||||||
|
button.text,
|
||||||
|
button.fromMenu);
|
||||||
});
|
});
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
_requestId = 0;
|
_requestId = 0;
|
||||||
|
@ -792,7 +796,8 @@ void AttachWebView::ClearAll() {
|
||||||
void AttachWebView::show(
|
void AttachWebView::show(
|
||||||
uint64 queryId,
|
uint64 queryId,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &buttonText) {
|
const QString &buttonText,
|
||||||
|
bool fromMenu) {
|
||||||
Expects(_bot != nullptr && _action.has_value());
|
Expects(_bot != nullptr && _action.has_value());
|
||||||
|
|
||||||
const auto close = crl::guard(this, [=] {
|
const auto close = crl::guard(this, [=] {
|
||||||
|
@ -916,6 +921,7 @@ void AttachWebView::show(
|
||||||
.menuButtons = buttons,
|
.menuButtons = buttons,
|
||||||
.handleMenuButton = handleMenuButton,
|
.handleMenuButton = handleMenuButton,
|
||||||
.themeParams = [] { return Window::Theme::WebViewParams(); },
|
.themeParams = [] { return Window::Theme::WebViewParams(); },
|
||||||
|
.allowClipboardRead = fromMenu,
|
||||||
});
|
});
|
||||||
*panel = _panel.get();
|
*panel = _panel.get();
|
||||||
started(queryId);
|
started(queryId);
|
||||||
|
@ -1023,11 +1029,18 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
|
||||||
if (!PeerMatchesTypes(peer, bot.user, bot.types)) {
|
if (!PeerMatchesTypes(peer, bot.user, bot.types)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const auto callback = [=] {
|
||||||
|
bots->request(
|
||||||
|
nullptr,
|
||||||
|
actionFactory(),
|
||||||
|
bot.user,
|
||||||
|
{ .fromMenu = true });
|
||||||
|
};
|
||||||
auto action = base::make_unique_q<BotAction>(
|
auto action = base::make_unique_q<BotAction>(
|
||||||
raw,
|
raw,
|
||||||
raw->menu()->st(),
|
raw->menu()->st(),
|
||||||
bot,
|
bot,
|
||||||
[=] { bots->request(nullptr, actionFactory(), bot.user, {}); });
|
callback);
|
||||||
action->forceShown(
|
action->forceShown(
|
||||||
) | rpl::start_with_next([=](bool shown) {
|
) | rpl::start_with_next([=](bool shown) {
|
||||||
if (shown) {
|
if (shown) {
|
||||||
|
|
|
@ -69,6 +69,7 @@ public:
|
||||||
QString text;
|
QString text;
|
||||||
QString startCommand;
|
QString startCommand;
|
||||||
QByteArray url;
|
QByteArray url;
|
||||||
|
bool fromMenu = false;
|
||||||
};
|
};
|
||||||
void request(
|
void request(
|
||||||
const Api::SendAction &action,
|
const Api::SendAction &action,
|
||||||
|
@ -127,7 +128,8 @@ private:
|
||||||
void show(
|
void show(
|
||||||
uint64 queryId,
|
uint64 queryId,
|
||||||
const QString &url,
|
const QString &url,
|
||||||
const QString &buttonText = QString());
|
const QString &buttonText = QString(),
|
||||||
|
bool fromMenu = false);
|
||||||
void confirmAddToMenu(
|
void confirmAddToMenu(
|
||||||
AttachWebViewBot bot,
|
AttachWebViewBot bot,
|
||||||
Fn<void()> callback = nullptr);
|
Fn<void()> callback = nullptr);
|
||||||
|
|
|
@ -32,6 +32,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtCore/QJsonDocument>
|
#include <QtCore/QJsonDocument>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QJsonArray>
|
#include <QtCore/QJsonArray>
|
||||||
|
#include <QtGui/QGuiApplication>
|
||||||
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
namespace Ui::BotWebView {
|
namespace Ui::BotWebView {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -344,7 +346,8 @@ Panel::Panel(
|
||||||
QString phone,
|
QString phone,
|
||||||
MenuButtons menuButtons,
|
MenuButtons menuButtons,
|
||||||
Fn<void(MenuButton)> handleMenuButton,
|
Fn<void(MenuButton)> handleMenuButton,
|
||||||
Fn<Webview::ThemeParams()> themeParams)
|
Fn<Webview::ThemeParams()> themeParams,
|
||||||
|
bool allowClipboardRead)
|
||||||
: _userDataPath(userDataPath)
|
: _userDataPath(userDataPath)
|
||||||
, _handleLocalUri(std::move(handleLocalUri))
|
, _handleLocalUri(std::move(handleLocalUri))
|
||||||
, _handleInvoice(std::move(handleInvoice))
|
, _handleInvoice(std::move(handleInvoice))
|
||||||
|
@ -353,7 +356,8 @@ Panel::Panel(
|
||||||
, _phone(phone)
|
, _phone(phone)
|
||||||
, _menuButtons(menuButtons)
|
, _menuButtons(menuButtons)
|
||||||
, _handleMenuButton(std::move(handleMenuButton))
|
, _handleMenuButton(std::move(handleMenuButton))
|
||||||
, _widget(std::make_unique<SeparatePanel>()) {
|
, _widget(std::make_unique<SeparatePanel>())
|
||||||
|
, _allowClipboardRead(allowClipboardRead) {
|
||||||
_widget->setInnerSize(st::paymentsPanelSize);
|
_widget->setInnerSize(st::paymentsPanelSize);
|
||||||
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
|
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
|
||||||
|
|
||||||
|
@ -663,6 +667,8 @@ bool Panel::createWebview() {
|
||||||
requestPhone();
|
requestPhone();
|
||||||
} else if (command == "web_app_setup_closing_behavior") {
|
} else if (command == "web_app_setup_closing_behavior") {
|
||||||
setupClosingBehaviour(arguments);
|
setupClosingBehaviour(arguments);
|
||||||
|
} else if (command == "web_app_read_text_from_clipboard") {
|
||||||
|
requestClipboardText(arguments);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -737,16 +743,10 @@ void Panel::openExternalLink(const QJsonObject &args) {
|
||||||
LOG(("BotWebView Error: Bad 'url' in openExternalLink."));
|
LOG(("BotWebView Error: Bad 'url' in openExternalLink."));
|
||||||
_close();
|
_close();
|
||||||
return;
|
return;
|
||||||
|
} else if (!allowOpenLink()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const auto now = crl::now();
|
File::OpenUrl(url);
|
||||||
if (_mainButtonLastClick
|
|
||||||
&& _mainButtonLastClick + kProcessClickTimeout >= now) {
|
|
||||||
_mainButtonLastClick = 0;
|
|
||||||
File::OpenUrl(url);
|
|
||||||
} else {
|
|
||||||
const auto string = EncodeForJs(url);
|
|
||||||
_webview->window.eval(("window.open(\"" + string + "\");").toUtf8());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::openInvoice(const QJsonObject &args) {
|
void Panel::openInvoice(const QJsonObject &args) {
|
||||||
|
@ -816,9 +816,9 @@ void Panel::openPopup(const QJsonObject &args) {
|
||||||
QJsonArray{ { QJsonValue(*result.id) } }
|
QJsonArray{ { QJsonValue(*result.id) } }
|
||||||
).toJson(QJsonDocument::Compact) + "[0]";
|
).toJson(QJsonDocument::Compact) + "[0]";
|
||||||
};
|
};
|
||||||
postEvent(
|
postEvent("popup_closed", result.id
|
||||||
"popup_closed",
|
? QJsonObject{ { u"button_id"_q, *result.id } }
|
||||||
result.id ? ("\"button_id\": " + safe()) : QString());
|
: EventData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,15 +841,49 @@ void Panel::requestPhone() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (weak) {
|
if (weak) {
|
||||||
postEvent(
|
postEvent("phone_requested", (result.id == "share")
|
||||||
"phone_requested",
|
? QJsonObject{ { u"phone_number"_q, _phone } }
|
||||||
(result.id == "share"
|
: EventData());
|
||||||
? "\"phone_number\": \"" + _phone + "\""
|
|
||||||
: QString()));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Panel::requestClipboardText(const QJsonObject &args) {
|
||||||
|
const auto requestId = args["req_id"];
|
||||||
|
if (requestId.isUndefined()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto result = QJsonObject();
|
||||||
|
result["req_id"] = requestId;
|
||||||
|
if (allowClipboardQuery()) {
|
||||||
|
result["data"] = QGuiApplication::clipboard()->text();
|
||||||
|
}
|
||||||
|
postEvent(u"clipboard_text_received"_q, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Panel::allowOpenLink() const {
|
||||||
|
const auto now = crl::now();
|
||||||
|
if (_mainButtonLastClick
|
||||||
|
&& _mainButtonLastClick + kProcessClickTimeout >= now) {
|
||||||
|
_mainButtonLastClick = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Panel::allowClipboardQuery() const {
|
||||||
|
if (!_allowClipboardRead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto now = crl::now();
|
||||||
|
if (_mainButtonLastClick
|
||||||
|
&& _mainButtonLastClick + kProcessClickTimeout >= now) {
|
||||||
|
_mainButtonLastClick = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Panel::scheduleCloseWithConfirmation() {
|
void Panel::scheduleCloseWithConfirmation() {
|
||||||
if (!_closeWithConfirmationScheduled) {
|
if (!_closeWithConfirmationScheduled) {
|
||||||
_closeWithConfirmationScheduled = true;
|
_closeWithConfirmationScheduled = true;
|
||||||
|
@ -1031,16 +1065,17 @@ void Panel::updateThemeParams(const Webview::ThemeParams ¶ms) {
|
||||||
params.scrollBgOver,
|
params.scrollBgOver,
|
||||||
params.scrollBarBg,
|
params.scrollBarBg,
|
||||||
params.scrollBarBgOver);
|
params.scrollBarBgOver);
|
||||||
postEvent("theme_changed", "\"theme_params\": " + params.json);
|
postEvent("theme_changed", "{\"theme_params\": " + params.json + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::invoiceClosed(const QString &slug, const QString &status) {
|
void Panel::invoiceClosed(const QString &slug, const QString &status) {
|
||||||
if (!_webview || !_webview->window.widget()) {
|
if (!_webview || !_webview->window.widget()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
postEvent(
|
postEvent("invoice_closed", QJsonObject{
|
||||||
"invoice_closed",
|
{ u"slug"_q, slug },
|
||||||
"\"slug\": \"" + slug + "\", \"status\": \"" + status + "\"");
|
{ u"status"_q, status },
|
||||||
|
});
|
||||||
_widget->showAndActivate();
|
_widget->showAndActivate();
|
||||||
_hiddenForPayment = false;
|
_hiddenForPayment = false;
|
||||||
}
|
}
|
||||||
|
@ -1050,13 +1085,21 @@ void Panel::hideForPayment() {
|
||||||
_widget->hideGetDuration();
|
_widget->hideGetDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::postEvent(const QString &event, const QString &data) {
|
void Panel::postEvent(const QString &event) {
|
||||||
|
postEvent(event, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::postEvent(const QString &event, EventData data) {
|
||||||
|
auto written = v::is<QString>(data)
|
||||||
|
? v::get<QString>(data).toUtf8()
|
||||||
|
: QJsonDocument(
|
||||||
|
v::get<QJsonObject>(data)).toJson(QJsonDocument::Compact);
|
||||||
_webview->window.eval(R"(
|
_webview->window.eval(R"(
|
||||||
if (window.TelegramGameProxy) {
|
if (window.TelegramGameProxy) {
|
||||||
window.TelegramGameProxy.receiveEvent(
|
window.TelegramGameProxy.receiveEvent(
|
||||||
")"
|
")"
|
||||||
+ event.toUtf8()
|
+ event.toUtf8()
|
||||||
+ '"' + (data.isEmpty() ? QByteArray() : ", {" + data.toUtf8() + '}')
|
+ '"' + (written.isEmpty() ? QByteArray() : ", " + written)
|
||||||
+ R"();
|
+ R"();
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
@ -1110,7 +1153,8 @@ std::unique_ptr<Panel> Show(Args &&args) {
|
||||||
args.phone,
|
args.phone,
|
||||||
args.menuButtons,
|
args.menuButtons,
|
||||||
std::move(args.handleMenuButton),
|
std::move(args.handleMenuButton),
|
||||||
std::move(args.themeParams));
|
std::move(args.themeParams),
|
||||||
|
args.allowClipboardRead);
|
||||||
if (!result->showWebview(args.url, params, std::move(args.bottom))) {
|
if (!result->showWebview(args.url, params, std::move(args.bottom))) {
|
||||||
const auto available = Webview::Availability();
|
const auto available = Webview::Availability();
|
||||||
if (available.error != Webview::Available::Error::None) {
|
if (available.error != Webview::Available::Error::None) {
|
||||||
|
|
|
@ -52,7 +52,8 @@ public:
|
||||||
QString phone,
|
QString phone,
|
||||||
MenuButtons menuButtons,
|
MenuButtons menuButtons,
|
||||||
Fn<void(MenuButton)> handleMenuButton,
|
Fn<void(MenuButton)> handleMenuButton,
|
||||||
Fn<Webview::ThemeParams()> themeParams);
|
Fn<Webview::ThemeParams()> themeParams,
|
||||||
|
bool allowClipboardRead);
|
||||||
~Panel();
|
~Panel();
|
||||||
|
|
||||||
void requestActivate();
|
void requestActivate();
|
||||||
|
@ -94,13 +95,18 @@ private:
|
||||||
void openInvoice(const QJsonObject &args);
|
void openInvoice(const QJsonObject &args);
|
||||||
void openPopup(const QJsonObject &args);
|
void openPopup(const QJsonObject &args);
|
||||||
void requestPhone();
|
void requestPhone();
|
||||||
|
void requestClipboardText(const QJsonObject &args);
|
||||||
void setupClosingBehaviour(const QJsonObject &args);
|
void setupClosingBehaviour(const QJsonObject &args);
|
||||||
void createMainButton();
|
void createMainButton();
|
||||||
void scheduleCloseWithConfirmation();
|
void scheduleCloseWithConfirmation();
|
||||||
void closeWithConfirmation();
|
void closeWithConfirmation();
|
||||||
|
|
||||||
void postEvent(const QString &event, const QString &data = {});
|
using EventData = std::variant<QString, QJsonObject>;
|
||||||
|
void postEvent(const QString &event);
|
||||||
|
void postEvent(const QString &event, EventData data);
|
||||||
|
|
||||||
|
[[nodiscard]] bool allowOpenLink() const;
|
||||||
|
[[nodiscard]] bool allowClipboardQuery() const;
|
||||||
[[nodiscard]] bool progressWithBackground() const;
|
[[nodiscard]] bool progressWithBackground() const;
|
||||||
[[nodiscard]] QRect progressRect() const;
|
[[nodiscard]] QRect progressRect() const;
|
||||||
void setupProgressGeometry();
|
void setupProgressGeometry();
|
||||||
|
@ -119,7 +125,7 @@ private:
|
||||||
std::unique_ptr<RpWidget> _webviewBottom;
|
std::unique_ptr<RpWidget> _webviewBottom;
|
||||||
QPointer<QWidget> _webviewParent;
|
QPointer<QWidget> _webviewParent;
|
||||||
std::unique_ptr<Button> _mainButton;
|
std::unique_ptr<Button> _mainButton;
|
||||||
crl::time _mainButtonLastClick = 0;
|
mutable crl::time _mainButtonLastClick = 0;
|
||||||
std::unique_ptr<Progress> _progress;
|
std::unique_ptr<Progress> _progress;
|
||||||
rpl::event_stream<> _themeUpdateForced;
|
rpl::event_stream<> _themeUpdateForced;
|
||||||
rpl::lifetime _fgLifetime;
|
rpl::lifetime _fgLifetime;
|
||||||
|
@ -128,6 +134,7 @@ private:
|
||||||
bool _themeUpdateScheduled = false;
|
bool _themeUpdateScheduled = false;
|
||||||
bool _hiddenForPayment = false;
|
bool _hiddenForPayment = false;
|
||||||
bool _closeWithConfirmationScheduled = false;
|
bool _closeWithConfirmationScheduled = false;
|
||||||
|
bool _allowClipboardRead = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,6 +151,7 @@ struct Args {
|
||||||
MenuButtons menuButtons;
|
MenuButtons menuButtons;
|
||||||
Fn<void(MenuButton)> handleMenuButton;
|
Fn<void(MenuButton)> handleMenuButton;
|
||||||
Fn<Webview::ThemeParams()> themeParams;
|
Fn<Webview::ThemeParams()> themeParams;
|
||||||
|
bool allowClipboardRead = false;
|
||||||
};
|
};
|
||||||
[[nodiscard]] std::unique_ptr<Panel> Show(Args &&args);
|
[[nodiscard]] std::unique_ptr<Panel> Show(Args &&args);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue