Use initial bot web app header/body colors.

This commit is contained in:
John Preston 2024-11-11 19:08:06 +04:00
parent 2d1fb0562d
commit 7bf78b3317
8 changed files with 142 additions and 72 deletions

View file

@ -345,6 +345,24 @@ void UserData::setBotInfo(const MTPBotInfo &info) {
const auto privacyChanged = (botInfo->privacyPolicyUrl != privacy);
botInfo->privacyPolicyUrl = privacy;
if (const auto settings = d.vapp_settings()) {
const auto &data = settings->data();
botInfo->botAppColorTitleDay = Ui::MaybeColorFromSerialized(
data.vheader_color()).value_or(QColor(0, 0, 0, 0));
botInfo->botAppColorTitleNight = Ui::MaybeColorFromSerialized(
data.vheader_dark_color()).value_or(QColor(0, 0, 0, 0));
botInfo->botAppColorBodyDay = Ui::MaybeColorFromSerialized(
data.vbackground_color()).value_or(QColor(0, 0, 0, 0));
botInfo->botAppColorBodyNight = Ui::MaybeColorFromSerialized(
data.vbackground_dark_color()).value_or(QColor(0, 0, 0, 0));
} else {
botInfo->botAppColorTitleDay
= botInfo->botAppColorTitleNight
= botInfo->botAppColorBodyDay
= botInfo->botAppColorBodyNight
= QColor(0, 0, 0, 0);
}
if (changedCommands || changedButton || privacyChanged) {
owner().botCommandsChanged(this);
}

View file

@ -33,6 +33,11 @@ struct BotInfo {
QString botMenuButtonUrl;
QString privacyPolicyUrl;
QColor botAppColorTitleDay = QColor(0, 0, 0, 0);
QColor botAppColorTitleNight = QColor(0, 0, 0, 0);
QColor botAppColorBodyDay = QColor(0, 0, 0, 0);
QColor botAppColorBodyNight = QColor(0, 0, 0, 0);
QString startToken;
Dialogs::EntryState inlineReturnTo;

View file

@ -1423,7 +1423,23 @@ void WebViewInstance::started(uint64 queryId) {
}
Webview::ThemeParams WebViewInstance::botThemeParams() {
return Window::Theme::WebViewParams();
auto result = Window::Theme::WebViewParams();
if (const auto info = _bot->botInfo.get()) {
const auto night = Window::Theme::IsNightMode();
const auto &title = night
? info->botAppColorTitleNight
: info->botAppColorTitleDay;
const auto &body = night
? info->botAppColorBodyNight
: info->botAppColorBodyDay;
if (title.alpha() == 255) {
result.titleBg = title;
}
if (body.alpha() == 255) {
result.bodyBg = body;
}
}
return result;
}
bool WebViewInstance::botHandleLocalUri(QString uri, bool keepOpen) {

View file

@ -550,7 +550,7 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
_webview = std::make_unique<WebviewWithLifetime>(
container,
Webview::WindowConfig{
.opaqueBg = params.opaqueBg,
.opaqueBg = params.bodyBg,
.storageId = _delegate->panelWebviewStorageId(),
});
@ -919,7 +919,7 @@ void Panel::updateThemeParams(const Webview::ThemeParams &params) {
return;
}
_webview->window.updateTheme(
params.opaqueBg,
params.bodyBg,
params.scrollBg,
params.scrollBgOver,
params.scrollBarBg,

View file

@ -366,23 +366,19 @@ Panel::Progress::Progress(QWidget *parent, Fn<QRect()> rect)
st::paymentsLoading) {
}
Panel::Panel(
const Webview::StorageId &storageId,
rpl::producer<QString> title,
object_ptr<Ui::RpWidget> titleBadge,
not_null<Delegate*> delegate,
MenuButtons menuButtons,
bool fullscreen,
bool allowClipboardRead)
: _storageId(storageId)
, _delegate(delegate)
, _menuButtons(menuButtons)
Panel::Panel(Args &&args)
: _storageId(args.storageId)
, _delegate(args.delegate)
, _menuButtons(args.menuButtons)
, _widget(std::make_unique<SeparatePanel>())
, _fullscreen(fullscreen)
, _allowClipboardRead(allowClipboardRead) {
, _fullscreen(args.fullscreen)
, _allowClipboardRead(args.allowClipboardRead) {
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
_widget->setInnerSize(st::botWebViewPanelSize, true);
const auto params = _delegate->botThemeParams();
updateColorOverrides(params);
_fullscreen.value(
) | rpl::start_with_next([=](bool fullscreen) {
_widget->toggleFullScreen(fullscreen);
@ -426,8 +422,17 @@ Panel::Panel(
});
}, _widget->lifetime());
setTitle(std::move(title));
_widget->setTitleBadge(std::move(titleBadge));
setTitle(std::move(args.title));
_widget->setTitleBadge(std::move(args.titleBadge));
if (!showWebview(args.url, params, std::move(args.bottom))) {
const auto available = Webview::Availability();
if (available.error != Webview::Available::Error::None) {
showWebviewError(tr::lng_bot_no_webview(tr::now), available);
} else {
showCriticalError({ "Error: Could not initialize WebView." });
}
}
}
Panel::~Panel() {
@ -679,13 +684,17 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
_widget->showInner(std::move(outer));
_webviewParent = container;
_headerColorReceived = false;
_bodyColorReceived = false;
_bottomColorReceived = false;
updateColorOverrides(params);
createWebviewBottom();
container->show();
_webview = std::make_unique<WebviewWithLifetime>(
container,
Webview::WindowConfig{
.opaqueBg = params.opaqueBg,
.opaqueBg = params.bodyBg,
.storageId = _storageId,
});
const auto raw = &_webview->window;
@ -823,6 +832,8 @@ bool Panel::createWebview(const Webview::ThemeParams &params) {
requestClipboardText(arguments);
} else if (command == "web_app_set_header_color") {
processHeaderColor(arguments);
} else if (command == "web_app_set_background_color") {
processBackgroundColor(arguments);
} else if (command == "web_app_set_bottom_bar_color") {
processBottomBarColor(arguments);
} else if (command == "web_app_send_prepared_message") {
@ -1437,6 +1448,7 @@ void Panel::processSettingsButtonMessage(const QJsonObject &args) {
}
void Panel::processHeaderColor(const QJsonObject &args) {
_headerColorReceived = true;
if (const auto color = ParseColor(args["color"].toString())) {
_widget->overrideTitleColor(color);
_headerColorLifetime.destroy();
@ -1453,7 +1465,32 @@ void Panel::processHeaderColor(const QJsonObject &args) {
}
}
void Panel::processBackgroundColor(const QJsonObject &args) {
_bodyColorReceived = true;
if (const auto color = ParseColor(args["color"].toString())) {
_widget->overrideBodyColor(color);
_bodyColorLifetime.destroy();
} else if (const auto color = LookupNamedColor(
args["color_key"].toString())) {
_widget->overrideBodyColor((*color)->c);
_bodyColorLifetime = style::PaletteChanged(
) | rpl::start_with_next([=] {
_widget->overrideBodyColor((*color)->c);
});
} else {
_widget->overrideBodyColor(std::nullopt);
_bodyColorLifetime.destroy();
}
if (const auto raw = _bottomButtonsBg.get()) {
raw->update();
}
if (const auto raw = _webviewBottom.get()) {
raw->update();
}
}
void Panel::processBottomBarColor(const QJsonObject &args) {
_bottomColorReceived = true;
if (const auto color = ParseColor(args["color"].toString())) {
_widget->overrideBottomBarColor(color);
_bottomBarColor = color;
@ -1462,7 +1499,7 @@ void Panel::processBottomBarColor(const QJsonObject &args) {
args["color_key"].toString())) {
_widget->overrideBottomBarColor((*color)->c);
_bottomBarColor = (*color)->c;
_headerColorLifetime = style::PaletteChanged(
_bottomBarColorLifetime = style::PaletteChanged(
) | rpl::start_with_next([=] {
_widget->overrideBottomBarColor((*color)->c);
_bottomBarColor = (*color)->c;
@ -1470,7 +1507,7 @@ void Panel::processBottomBarColor(const QJsonObject &args) {
} else {
_widget->overrideBottomBarColor(std::nullopt);
_bottomBarColor = std::nullopt;
_headerColorLifetime.destroy();
_bottomBarColorLifetime.destroy();
}
if (const auto raw = _bottomButtonsBg.get()) {
raw->update();
@ -1596,13 +1633,15 @@ void Panel::layoutButtons() {
} else if (_bottomButtonsBg) {
_bottomButtonsBg->hide();
}
_footerHeight = _layerShown
const auto footer = _layerShown
? 0
: any
? _bottomButtonsBg->height()
: _fullscreen.current()
? 0
: _webviewBottom->height();
_widget->setBottomBarHeight((!_layerShown && any) ? footer : 0);
_footerHeight = footer;
}
void Panel::showBox(object_ptr<BoxContent> box) {
@ -1707,11 +1746,12 @@ void Panel::showCriticalError(const TextWithEntities &text) {
}
void Panel::updateThemeParams(const Webview::ThemeParams &params) {
updateColorOverrides(params);
if (!_webview || !_webview->window.widget()) {
return;
}
_webview->window.updateTheme(
params.opaqueBg,
params.bodyBg,
params.scrollBg,
params.scrollBgOver,
params.scrollBarBg,
@ -1719,6 +1759,15 @@ void Panel::updateThemeParams(const Webview::ThemeParams &params) {
postEvent("theme_changed", "{\"theme_params\": " + params.json + "}");
}
void Panel::updateColorOverrides(const Webview::ThemeParams &params) {
if (!_headerColorReceived && params.titleBg.alpha() == 255) {
_widget->overrideTitleColor(params.titleBg);
}
if (!_bodyColorReceived && params.bodyBg.alpha() == 255) {
_widget->overrideBodyColor(params.bodyBg);
}
}
void Panel::invoiceClosed(const QString &slug, const QString &status) {
if (!_webview || !_webview->window.widget()) {
return;
@ -1802,27 +1851,7 @@ rpl::lifetime &Panel::lifetime() {
}
std::unique_ptr<Panel> Show(Args &&args) {
auto result = std::make_unique<Panel>(
args.storageId,
std::move(args.title),
std::move(args.titleBadge),
args.delegate,
args.menuButtons,
args.fullscreen,
args.allowClipboardRead);
const auto params = args.delegate->botThemeParams();
if (!result->showWebview(args.url, params, std::move(args.bottom))) {
const auto available = Webview::Availability();
if (available.error != Webview::Available::Error::None) {
result->showWebviewError(
tr::lng_bot_no_webview(tr::now),
available);
} else {
result->showCriticalError({
"Error: Could not initialize WebView." });
}
}
return result;
return std::make_unique<Panel>(std::move(args));
}
} // namespace Ui::BotWebView

View file

@ -87,16 +87,21 @@ public:
virtual void botClose() = 0;
};
struct Args {
QString url;
Webview::StorageId storageId;
rpl::producer<QString> title;
object_ptr<Ui::RpWidget> titleBadge = { nullptr };
rpl::producer<QString> bottom;
not_null<Delegate*> delegate;
MenuButtons menuButtons;
bool fullscreen = false;
bool allowClipboardRead = false;
};
class Panel final : public base::has_weak_ptr {
public:
Panel(
const Webview::StorageId &storageId,
rpl::producer<QString> title,
object_ptr<Ui::RpWidget> titleBadge,
not_null<Delegate*> delegate,
MenuButtons menuButtons,
bool fullscreen,
bool allowClipboardRead);
explicit Panel(Args &&args);
~Panel();
void requestActivate();
@ -148,6 +153,7 @@ private:
void processBackButtonMessage(const QJsonObject &args);
void processSettingsButtonMessage(const QJsonObject &args);
void processHeaderColor(const QJsonObject &args);
void processBackgroundColor(const QJsonObject &args);
void processBottomBarColor(const QJsonObject &args);
void openTgLink(const QJsonObject &args);
void openExternalLink(const QJsonObject &args);
@ -171,6 +177,8 @@ private:
void sendContentSafeArea();
void sendFullScreen();
void updateColorOverrides(const Webview::ThemeParams &params);
using EventData = std::variant<QString, QJsonObject>;
void postEvent(const QString &event);
void postEvent(const QString &event, EventData data);
@ -201,29 +209,22 @@ private:
rpl::event_stream<> _themeUpdateForced;
std::optional<QColor> _bottomBarColor;
rpl::lifetime _headerColorLifetime;
rpl::lifetime _bodyColorLifetime;
rpl::lifetime _bottomBarColorLifetime;
rpl::variable<bool> _fullscreen = false;
bool _layerShown = false;
bool _webviewProgress = false;
bool _themeUpdateScheduled = false;
bool _hiddenForPayment = false;
bool _closeWithConfirmationScheduled = false;
bool _allowClipboardRead = false;
bool _inBlockingRequest = false;
bool _layerShown : 1 = false;
bool _webviewProgress : 1 = false;
bool _themeUpdateScheduled : 1 = false;
bool _hiddenForPayment : 1 = false;
bool _closeWithConfirmationScheduled : 1 = false;
bool _allowClipboardRead : 1 = false;
bool _inBlockingRequest : 1 = false;
bool _headerColorReceived : 1 = false;
bool _bodyColorReceived : 1 = false;
bool _bottomColorReceived : 1 = false;
};
struct Args {
QString url;
Webview::StorageId storageId;
rpl::producer<QString> title;
object_ptr<Ui::RpWidget> titleBadge = { nullptr };
rpl::producer<QString> bottom;
not_null<Delegate*> delegate;
MenuButtons menuButtons;
bool fullscreen = false;
bool allowClipboardRead = false;
};
[[nodiscard]] std::unique_ptr<Panel> Show(Args &&args);
} // namespace Ui::BotWebView

View file

@ -1539,7 +1539,8 @@ bool ReadPaletteValues(const QByteArray &content, Fn<bool(QLatin1String name, QL
mix(bg.blue(), shadow.blue()))));
}
return {
.opaqueBg = st::windowBg->c,
.bodyBg = st::windowBg->c,
.titleBg = QColor(0, 0, 0, 0),
.scrollBg = st::scrollBg->c,
.scrollBgOver = st::scrollBgOver->c,
.scrollBarBg = st::scrollBarBg->c,

@ -1 +1 @@
Subproject commit efc48237bcaf269b57c8a37539e11e1887e1f3cf
Subproject commit 095babf234736e053bdbbc3dc15bc042a40c45b4