Support theming for webview-s (payments, attach).

This commit is contained in:
John Preston 2022-03-29 00:14:10 +04:00
parent df15ff9f8e
commit aed1904b4c
14 changed files with 147 additions and 31 deletions

View file

@ -1997,6 +1997,19 @@ void Updates::feedUpdate(const MTPUpdate &update) {
}
} break;
case mtpc_updateAttachMenuBots: {
} break;
case mtpc_updateWebViewResultSent: {
const auto &d = update.c_updateWebViewResultSent();
session().data().webViewResultSent({
.peerId = peerFromMTP(d.vpeer()),
.botId = UserId(d.vbot_id()),
.queryId = d.vquery_id().v,
});
} break;
case mtpc_updatePendingJoinRequests: {
const auto &d = update.c_updatePendingJoinRequests();
if (const auto peer = session().data().peerLoaded(peerFromMTP(d.vpeer()))) {

View file

@ -4225,6 +4225,14 @@ uint64 Session::wallpapersHash() const {
return _wallpapersHash;
}
void Session::webViewResultSent(WebViewResultSent &&sent) {
return _webViewResultSent.fire(std::move(sent));
}
auto Session::webViewResultSent() const -> rpl::producer<WebViewResultSent> {
return _webViewResultSent.events();
}
void Session::clearLocalStorage() {
_cache->close();
_cache->clear();

View file

@ -698,6 +698,14 @@ public:
const std::vector<WallPaper> &wallpapers() const;
uint64 wallpapersHash() const;
struct WebViewResultSent {
PeerId peerId = 0;
UserId botId = 0;
uint64 queryId = 0;
};
void webViewResultSent(WebViewResultSent &&sent);
[[nodiscard]] rpl::producer<WebViewResultSent> webViewResultSent() const;
void clearLocalStorage();
private:
@ -984,6 +992,8 @@ private:
std::vector<WallPaper> _wallpapers;
uint64 _wallpapersHash = 0;
rpl::event_stream<WebViewResultSent> _webViewResultSent;
Groups _groups;
const std::unique_ptr<ChatFilters> _chatsFilters;
std::unique_ptr<ScheduledMessages> _scheduledMessages;

View file

@ -54,11 +54,17 @@ void HistoryMessageVia::create(
tr::lng_inline_bot_via(tr::now, lt_inline_bot, '@' + bot->username));
link = std::make_shared<LambdaClickHandler>([bot = this->bot](
ClickContext context) {
if (base::IsCtrlPressed()) {
if (const auto window = App::wnd()) {
if (const auto controller = window->sessionController()) {
if (const auto window = App::wnd()) {
if (const auto controller = window->sessionController()) {
if (base::IsCtrlPressed()) {
controller->showPeerInfo(bot);
return;
} else if (!bot->isBot()
|| bot->botInfo->inlinePlaceholder.isEmpty()) {
controller->showPeerHistory(
bot->id,
Window::SectionShow::Way::Forward);
return;
}
}
}

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "apiwrap.h"
#include "api/api_cloud_password.h"
#include "window/themes/window_theme.h"
#include <QJsonDocument>
#include <QJsonObject>
@ -161,6 +162,17 @@ CheckoutProcess::CheckoutProcess(
showForm();
_panel->toggleProgress(true);
style::PaletteChanged(
) | rpl::filter([=] {
return !_themeUpdateScheduled;
}) | rpl::start_with_next([=] {
_themeUpdateScheduled = true;
crl::on_main(this, [=] {
_themeUpdateScheduled = false;
_panel->updateThemeParams(Window::Theme::WebViewParams());
});
}, _panel->lifetime());
if (mode == Mode::Payment) {
_session->api().cloudPassword().state(
) | rpl::start_with_next([=](const Core::CloudPasswordState &state) {

View file

@ -137,6 +137,7 @@ private:
SubmitState _submitState = SubmitState::None;
bool _initialSilentValidation = false;
bool _themeUpdateScheduled = false;
rpl::lifetime _gettingPasswordState;
rpl::lifetime _lifetime;

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "apiwrap.h"
#include "core/core_cloud_password.h"
#include "window/themes/window_theme.h"
#include "styles/style_payments.h" // paymentsThumbnailSize.
#include <QtCore/QJsonDocument>
@ -106,27 +107,6 @@ constexpr auto kPasswordPeriod = 15 * TimeId(60);
+ SmartGlocal::Last4(card);
}
[[nodiscard]] QByteArray ThemeParams() {
const auto colors = std::vector<std::pair<QString, const style::color&>>{
{ "bg_color", st::windowBg },
{ "text_color", st::windowFg },
{ "hint_color", st::windowSubTextFg },
{ "link_color", st::windowActiveTextFg },
{ "button_color", st::windowBgActive },
{ "button_text_color", st::windowFgActive },
};
auto object = QJsonObject();
for (const auto &[name, color] : colors) {
const auto value = uint32(0xFF000000U)
| (uint32(color->c.red()) << 16)
| (uint32(color->c.green()) << 8)
| (uint32(color->c.blue()));
const auto int32value = *reinterpret_cast<const int32*>(&value);
object.insert(name, int32value);
}
return QJsonDocument(object).toJson(QJsonDocument::Compact);
}
} // namespace
Form::Form(not_null<PeerData*> peer, MsgId itemId, bool receipt)
@ -262,7 +242,7 @@ void Form::requestForm() {
MTP_flags(MTPpayments_GetPaymentForm::Flag::f_theme_params),
_peer->input,
MTP_int(_msgId),
MTP_dataJSON(MTP_bytes(ThemeParams()))
MTP_dataJSON(MTP_bytes(Window::Theme::WebViewParams()))
)).done([=](const MTPpayments_PaymentForm &result) {
hideProgress();
result.match([&](const auto &data) {

View file

@ -781,6 +781,19 @@ void Panel::showWebviewError(
showCriticalError(rich);
}
void Panel::updateThemeParams(const QByteArray &json) {
if (!_webview || !_webview->window.widget()) {
return;
}
_webview->window.eval(R"(
if (window.TelegramGameProxy) {
window.TelegramGameProxy.receiveEvent(
"theme_changed",
{ "theme_params": )" + json + R"( });
}
)");
}
rpl::lifetime &Panel::lifetime() {
return _widget->lifetime();
}

View file

@ -76,6 +76,7 @@ public:
const QString &url,
bool allowBack,
rpl::producer<QString> bottomText);
void updateThemeParams(const QByteArray &json);
[[nodiscard]] rpl::producer<> backRequests() const;

View file

@ -69,7 +69,8 @@ Panel::Progress::Progress(QWidget *parent, Fn<QRect()> rect)
Panel::Panel(
const QString &userDataPath,
Fn<void(QByteArray)> sendData,
Fn<void()> close)
Fn<void()> close,
Fn<QByteArray()> themeParams)
: _userDataPath(userDataPath)
, _sendData(std::move(sendData))
, _close(std::move(close))
@ -83,6 +84,17 @@ Panel::Panel(
_widget->closeEvents(
) | rpl::start_with_next(_close, _widget->lifetime());
style::PaletteChanged(
) | rpl::filter([=] {
return !_themeUpdateScheduled;
}) | rpl::start_with_next([=] {
_themeUpdateScheduled = true;
crl::on_main(_widget.get(), [=] {
_themeUpdateScheduled = false;
updateThemeParams(themeParams());
});
}, _widget->lifetime());
setTitle(rpl::single(u"Title"_q));
}
@ -392,6 +404,19 @@ void Panel::showCriticalError(const TextWithEntities &text) {
_widget->showInner(std::move(error));
}
void Panel::updateThemeParams(const QByteArray &json) {
if (!_webview || !_webview->window.widget()) {
return;
}
_webview->window.eval(R"(
if (window.TelegramGameProxy) {
window.TelegramGameProxy.receiveEvent(
"theme_changed",
{ "theme_params": )" + json + R"( });
}
)");
}
void Panel::showWebviewError(
const QString &text,
const Webview::Available &information) {
@ -438,7 +463,8 @@ std::unique_ptr<Panel> Show(Args &&args) {
auto result = std::make_unique<Panel>(
args.userDataPath,
std::move(args.sendData),
std::move(args.close));
std::move(args.close),
std::move(args.themeParams));
result->showWebview(args.url, rpl::single(u"smth"_q));
return result;
}

View file

@ -26,7 +26,8 @@ public:
Panel(
const QString &userDataPath,
Fn<void(QByteArray)> sendData,
Fn<void()> close);
Fn<void()> close,
Fn<QByteArray()> themeParams);
~Panel();
void requestActivate();
@ -40,6 +41,8 @@ public:
void showToast(const TextWithEntities &text);
void showCriticalError(const TextWithEntities &text);
void updateThemeParams(const QByteArray &json);
[[nodiscard]] rpl::lifetime &lifetime();
private:
@ -66,6 +69,7 @@ private:
std::unique_ptr<RpWidget> _webviewBottom;
std::unique_ptr<Progress> _progress;
bool _webviewProgress = false;
bool _themeUpdateScheduled = false;
};
@ -74,7 +78,7 @@ struct Args {
QString userDataPath;
Fn<void(QByteArray)> sendData;
Fn<void()> close;
bool simple = false;
Fn<QByteArray()> themeParams;
};
[[nodiscard]] std::unique_ptr<Panel> Show(Args &&args);

View file

@ -38,6 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat.h"
#include <QtCore/QBuffer>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
namespace Window {
namespace Theme {
@ -1489,5 +1491,31 @@ bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QL
return true;
}
[[nodiscard]] QByteArray WebViewParams() {
const auto colors = std::vector<std::pair<QString, const style::color&>>{
{ "bg_color", st::windowBg },
{ "text_color", st::windowFg },
{ "hint_color", st::windowSubTextFg },
{ "link_color", st::windowActiveTextFg },
{ "button_color", st::windowBgActive },
{ "button_text_color", st::windowFgActive },
};
auto object = QJsonObject();
for (const auto &[name, color] : colors) {
auto r = 0;
auto g = 0;
auto b = 0;
color->c.getRgb(&r, &g, &b);
const auto hex = [](int component) {
const auto digit = [](int c) {
return QChar((c < 10) ? ('0' + c) : ('a' + c - 10));
};
return QString() + digit(component / 16) + digit(component % 16);
};
object.insert(name, '#' + hex(r) + hex(g) + hex(b));
}
return QJsonDocument(object).toJson(QJsonDocument::Compact);
}
} // namespace Theme
} // namespace Window

View file

@ -293,5 +293,7 @@ bool ReadPaletteValues(
const QByteArray &content,
Fn<bool(QLatin1String name, QLatin1String value)> callback);
[[nodiscard]] QByteArray WebViewParams();
} // namespace Theme
} // namespace Window

View file

@ -432,12 +432,14 @@ void SessionNavigation::requestAttachWebview(
not_null<UserData*> bot,
const WebViewButton &button) {
using Flag = MTPmessages_RequestWebView::Flag;
const auto flags = Flag::f_theme_params
| (button.url.isEmpty() ? Flag(0) : Flag::f_url);
_api.request(MTPmessages_RequestWebView(
MTP_flags(button.url.isEmpty() ? Flag(0) : Flag::f_url),
MTP_flags(flags),
peer->input,
bot->inputUser,
MTP_bytes(button.url),
MTPDataJSON(), // theme_params
MTP_dataJSON(MTP_bytes(Theme::WebViewParams())),
MTPint() // reply_to_msg_id
)).done([=](const MTPWebViewResult &result) {
result.match([&](const MTPDwebViewResultUrl &data) {
@ -509,7 +511,17 @@ void SessionNavigation::showAttachWebview(
.userDataPath = session().domain().local().webviewDataPath(),
.sendData = sendData,
.close = close,
.themeParams = [] { return Window::Theme::WebViewParams(); },
});
session().data().webViewResultSent(
) | rpl::filter([=](const Data::Session::WebViewResultSent &sent) {
return (sent.peerId == peer->id)
&& (sent.botId == bot->id)
&& (sent.queryId == queryId);
}) | rpl::start_with_next([=] {
_botWebView = nullptr;
}, _botWebView->lifetime());
}
void SessionNavigation::requestAddToMenu(