mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-29 06:42:42 +00:00
Improve main menu bots disclaimer acceptance.
This commit is contained in:
parent
229f7a2c15
commit
ef969df86e
@ -2268,6 +2268,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_bot_reload_page" = "Reload Page";
|
||||
"lng_bot_add_to_menu" = "{bot} asks your permission to be added as an option to your attachments menu so you can access it from any chat.";
|
||||
"lng_bot_add_to_menu_done" = "Bot added to the menu.";
|
||||
"lng_bot_will_be_added" = "{bot} shortcuts will be added to the attachment options and the main menu.";
|
||||
"lng_bot_side_menu_new" = "NEW";
|
||||
"lng_bot_menu_not_supported" = "This bot isn't supported in the attach menu.";
|
||||
"lng_bot_menu_already_added" = "This bot is already added in your attach menu.";
|
||||
"lng_bot_menu_button" = "Menu";
|
||||
|
@ -24,4 +24,5 @@ struct BotAppData {
|
||||
|
||||
uint64 accessHash = 0;
|
||||
uint64 hash = 0;
|
||||
bool hasSettings = false;
|
||||
};
|
||||
|
@ -124,6 +124,10 @@ constexpr auto kRefreshBotsTimeout = 60 * 60 * crl::time(1000);
|
||||
if (result && result->icon) {
|
||||
result->icon->forceToCache(true);
|
||||
}
|
||||
if (const auto icon = result->icon) {
|
||||
result->media = icon->createMediaView();
|
||||
icon->save(Data::FileOrigin(), {});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -194,6 +198,78 @@ void ShowChooseBox(
|
||||
return result;
|
||||
}
|
||||
|
||||
void FillDisclaimerBox(not_null<Ui::GenericBox*> box, Fn<void()> done) {
|
||||
const auto updateCheck = std::make_shared<Fn<void()>>();
|
||||
const auto validateCheck = std::make_shared<Fn<bool()>>();
|
||||
|
||||
const auto callback = [=](Fn<void()> close) {
|
||||
if (validateCheck && (*validateCheck)()) {
|
||||
done();
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
const auto padding = st::boxRowPadding;
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = tr::lng_mini_apps_disclaimer_text(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue),
|
||||
.confirmed = callback,
|
||||
.confirmText = tr::lng_box_ok(),
|
||||
.labelPadding = QMargins(padding.left(), 0, padding.right(), 0),
|
||||
.title = tr::lng_mini_apps_disclaimer_title(),
|
||||
});
|
||||
|
||||
auto checkView = std::make_unique<Ui::CheckView>(
|
||||
st::defaultCheck,
|
||||
false,
|
||||
[=] { if (*updateCheck) { (*updateCheck)(); } });
|
||||
const auto check = checkView.get();
|
||||
const auto row = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
tr::lng_mini_apps_disclaimer_button(
|
||||
lt_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
tr::lng_mini_apps_disclaimer_link(tr::now),
|
||||
tr::lng_mini_apps_tos_url(tr::now))),
|
||||
Ui::Text::WithEntities),
|
||||
st::defaultBoxCheckbox,
|
||||
std::move(checkView)),
|
||||
{
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.right(),
|
||||
0,
|
||||
});
|
||||
row->setAllowTextLines(5);
|
||||
row->setClickHandlerFilter([=](
|
||||
const ClickHandlerPtr &link,
|
||||
Qt::MouseButton button) {
|
||||
ActivateClickHandler(row, link, ClickContext{
|
||||
.button = button,
|
||||
.other = QVariant::fromValue(ClickHandlerContext{
|
||||
.show = box->uiShow(),
|
||||
})
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
(*updateCheck) = [=] { row->update(); };
|
||||
|
||||
const auto showError = Ui::CheckView::PrepareNonToggledError(
|
||||
check,
|
||||
box->lifetime());
|
||||
|
||||
(*validateCheck) = [=] {
|
||||
if (check->checked()) {
|
||||
return true;
|
||||
}
|
||||
showError();
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
class BotAction final : public Ui::Menu::ItemBase {
|
||||
public:
|
||||
BotAction(
|
||||
@ -818,10 +894,6 @@ void AttachWebView::requestBots() {
|
||||
_attachBots.reserve(data.vbots().v.size());
|
||||
for (const auto &bot : data.vbots().v) {
|
||||
if (auto parsed = ParseAttachBot(_session, bot)) {
|
||||
if (const auto icon = parsed->icon) {
|
||||
parsed->media = icon->createMediaView();
|
||||
icon->save(Data::FileOrigin(), {});
|
||||
}
|
||||
_attachBots.push_back(std::move(*parsed));
|
||||
}
|
||||
}
|
||||
@ -832,6 +904,11 @@ void AttachWebView::requestBots() {
|
||||
}).send();
|
||||
}
|
||||
|
||||
bool AttachWebView::showingDisclaimer(const AttachWebViewBot &bot) const {
|
||||
return bot.disclaimerRequired
|
||||
&& !_disclaimerAccepted.contains(bot.user);
|
||||
}
|
||||
|
||||
void AttachWebView::requestAddToMenu(
|
||||
not_null<UserData*> bot,
|
||||
std::optional<QString> startCommand) {
|
||||
@ -885,9 +962,7 @@ void AttachWebView::requestAddToMenu(
|
||||
}
|
||||
} else if (!startCommand) {
|
||||
_bot = bot;
|
||||
acceptDisclaimer(strong, [=] {
|
||||
requestSimple(strong, bot, { .fromMainMenu = true });
|
||||
});
|
||||
return true;
|
||||
} else if (const auto useTypes = chooseTypes & types) {
|
||||
const auto done = [=](not_null<Data::Thread*> thread) {
|
||||
@ -1128,6 +1203,7 @@ void AttachWebView::requestApp(
|
||||
_bot->id,
|
||||
data.vapp());
|
||||
_app = received ? received : already;
|
||||
_app->hasSettings = data.is_has_settings();
|
||||
if (!_app) {
|
||||
cancel();
|
||||
showToast(tr::lng_username_app_not_found(tr::now));
|
||||
@ -1140,8 +1216,8 @@ void AttachWebView::requestApp(
|
||||
requestAppView(false);
|
||||
}
|
||||
}).fail([=] {
|
||||
cancel();
|
||||
showToast(tr::lng_username_app_not_found(tr::now));
|
||||
cancel();
|
||||
}).send();
|
||||
}
|
||||
|
||||
@ -1190,13 +1266,14 @@ void AttachWebView::requestAppView(bool allowWrite) {
|
||||
return;
|
||||
}
|
||||
using Flag = MTPmessages_RequestAppWebView::Flag;
|
||||
const auto app = _app;
|
||||
const auto flags = Flag::f_theme_params
|
||||
| (_startCommand.isEmpty() ? Flag(0) : Flag::f_start_param)
|
||||
| (allowWrite ? Flag::f_write_allowed : Flag(0));
|
||||
_requestId = _session->api().request(MTPmessages_RequestAppWebView(
|
||||
MTP_flags(flags),
|
||||
_context->action.history->peer->input,
|
||||
MTP_inputBotAppID(MTP_long(_app->id), MTP_long(_app->accessHash)),
|
||||
MTP_inputBotAppID(MTP_long(app->id), MTP_long(app->accessHash)),
|
||||
MTP_string(_startCommand),
|
||||
MTP_dataJSON(MTP_bytes(Window::Theme::WebViewParams().json)),
|
||||
MTP_string("tdesktop")
|
||||
@ -1204,7 +1281,7 @@ void AttachWebView::requestAppView(bool allowWrite) {
|
||||
_requestId = 0;
|
||||
const auto &data = result.data();
|
||||
const auto queryId = uint64();
|
||||
show(queryId, qs(data.vurl()));
|
||||
show(queryId, qs(data.vurl()), QString(), false, app);
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_requestId = 0;
|
||||
if (error.type() == u"BOT_INVALID"_q) {
|
||||
@ -1256,93 +1333,17 @@ void AttachWebView::acceptDisclaimer(
|
||||
} else if (i->inactive) {
|
||||
requestAddToMenu(_bot, {}, controller, {}, {});
|
||||
return;
|
||||
} else if (!i->disclaimerRequired) {
|
||||
} else if (!showingDisclaimer(*i)) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto weak = base::make_weak(this);
|
||||
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto updateCheck = std::make_shared<Fn<void()>>();
|
||||
const auto validateCheck = std::make_shared<Fn<bool()>>();
|
||||
|
||||
const auto callback = [=](Fn<void()> close) {
|
||||
if (validateCheck && (*validateCheck)() && weak) {
|
||||
const auto i = ranges::find(
|
||||
_attachBots,
|
||||
not_null(_bot),
|
||||
&AttachWebViewBot::user);
|
||||
if (i == end(_attachBots)) {
|
||||
controller->show(Box(FillDisclaimerBox, crl::guard(this, [=] {
|
||||
_disclaimerAccepted.emplace(_bot);
|
||||
_attachBotsUpdates.fire({});
|
||||
} else if (i->inactive) {
|
||||
requestAddToMenu(_bot, std::nullopt);
|
||||
} else {
|
||||
i->disclaimerRequired = false;
|
||||
requestBots();
|
||||
done();
|
||||
}
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = tr::lng_mini_apps_disclaimer_text(
|
||||
tr::now,
|
||||
Ui::Text::RichLangValue),
|
||||
.confirmed = callback,
|
||||
.confirmText = tr::lng_box_ok(),
|
||||
.title = tr::lng_mini_apps_disclaimer_title(),
|
||||
});
|
||||
|
||||
auto checkView = std::make_unique<Ui::CheckView>(
|
||||
st::defaultCheck,
|
||||
false,
|
||||
[=] { if (*updateCheck) { (*updateCheck)(); } });
|
||||
const auto check = checkView.get();
|
||||
const auto row = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box.get(),
|
||||
tr::lng_mini_apps_disclaimer_button(
|
||||
lt_link,
|
||||
rpl::single(Ui::Text::Link(
|
||||
tr::lng_mini_apps_disclaimer_link(tr::now),
|
||||
tr::lng_mini_apps_tos_url(tr::now))),
|
||||
Ui::Text::WithEntities),
|
||||
st::defaultBoxCheckbox,
|
||||
std::move(checkView)),
|
||||
{
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.left(),
|
||||
st::boxRowPadding.right(),
|
||||
st::defaultBoxCheckbox.margin.bottom(),
|
||||
});
|
||||
row->setAllowTextLines(5);
|
||||
row->setClickHandlerFilter([=](
|
||||
const ClickHandlerPtr &link,
|
||||
Qt::MouseButton button) {
|
||||
ActivateClickHandler(row, link, ClickContext{
|
||||
.button = button,
|
||||
.other = QVariant::fromValue(ClickHandlerContext{
|
||||
.show = box->uiShow(),
|
||||
})
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
(*updateCheck) = [=] { row->update(); };
|
||||
|
||||
const auto showError = Ui::CheckView::PrepareNonToggledError(
|
||||
check,
|
||||
box->lifetime());
|
||||
|
||||
(*validateCheck) = [=] {
|
||||
if (check->checked()) {
|
||||
return true;
|
||||
}
|
||||
showError();
|
||||
return false;
|
||||
};
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
void AttachWebView::ClearAll() {
|
||||
@ -1355,7 +1356,8 @@ void AttachWebView::show(
|
||||
uint64 queryId,
|
||||
const QString &url,
|
||||
const QString &buttonText,
|
||||
bool allowClipboardRead) {
|
||||
bool allowClipboardRead,
|
||||
const BotAppData *app) {
|
||||
Expects(_bot != nullptr && _context != nullptr);
|
||||
|
||||
auto title = Info::Profile::NameValue(_bot);
|
||||
@ -1366,12 +1368,15 @@ void AttachWebView::show(
|
||||
_attachBots,
|
||||
not_null{ _bot },
|
||||
&AttachWebViewBot::user);
|
||||
const auto hasSettings = (attached != end(_attachBots))
|
||||
const auto hasSettings = app
|
||||
? app->hasSettings
|
||||
: ((attached != end(_attachBots))
|
||||
&& !attached->inactive
|
||||
&& attached->hasSettings;
|
||||
&& attached->hasSettings);
|
||||
const auto hasOpenBot = !_context
|
||||
|| (_bot != _context->action.history->peer);
|
||||
const auto hasRemoveFromMenu = (attached != end(_attachBots))
|
||||
const auto hasRemoveFromMenu = !app
|
||||
&& (attached != end(_attachBots))
|
||||
&& (!attached->inactive || attached->inMainMenu);
|
||||
const auto buttons = (hasSettings ? Button::Settings : Button::None)
|
||||
| (hasOpenBot ? Button::OpenBot : Button::None)
|
||||
@ -1473,6 +1478,14 @@ void AttachWebView::confirmAddToMenu(
|
||||
});
|
||||
close();
|
||||
};
|
||||
const auto disclaimer = showingDisclaimer(bot);
|
||||
if (disclaimer) {
|
||||
FillDisclaimerBox(box, [=] {
|
||||
_disclaimerAccepted.emplace(bot.user);
|
||||
_attachBotsUpdates.fire({});
|
||||
done([] {});
|
||||
});
|
||||
} else {
|
||||
Ui::ConfirmBox(box, {
|
||||
(bot.inMainMenu
|
||||
? tr::lng_bot_add_to_side_menu
|
||||
@ -1483,6 +1496,7 @@ void AttachWebView::confirmAddToMenu(
|
||||
Ui::Text::WithEntities),
|
||||
done,
|
||||
});
|
||||
}
|
||||
if (bot.requestWriteAccess) {
|
||||
(*allowed) = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
@ -1496,11 +1510,27 @@ void AttachWebView::confirmAddToMenu(
|
||||
st::urlAuthCheckbox),
|
||||
style::margins(
|
||||
st::boxRowPadding.left(),
|
||||
st::boxPhotoCaptionSkip,
|
||||
(disclaimer
|
||||
? st::boxPhotoCaptionSkip
|
||||
: st::boxRowPadding.left()),
|
||||
st::boxRowPadding.right(),
|
||||
st::boxPhotoCaptionSkip));
|
||||
st::boxRowPadding.left()));
|
||||
(*allowed)->setAllowTextLines();
|
||||
}
|
||||
if (disclaimer) {
|
||||
if (!bot.requestWriteAccess) {
|
||||
box->addRow(object_ptr<Ui::FixedHeightWidget>(
|
||||
box,
|
||||
st::boxRowPadding.left()));
|
||||
}
|
||||
box->addRow(object_ptr<Ui::FlatLabel>(
|
||||
box,
|
||||
tr::lng_bot_will_be_added(
|
||||
lt_bot,
|
||||
rpl::single(Ui::Text::Bold(bot.name)),
|
||||
Ui::Text::WithEntities),
|
||||
st::boxLabel));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -119,6 +119,7 @@ public:
|
||||
[[nodiscard]] rpl::producer<> attachBotsUpdates() const {
|
||||
return _attachBotsUpdates.events();
|
||||
}
|
||||
[[nodiscard]] bool showingDisclaimer(const AttachWebViewBot &bot) const;
|
||||
|
||||
void requestAddToMenu(
|
||||
not_null<UserData*> bot,
|
||||
@ -195,7 +196,8 @@ private:
|
||||
uint64 queryId,
|
||||
const QString &url,
|
||||
const QString &buttonText = QString(),
|
||||
bool allowClipboardRead = false);
|
||||
bool allowClipboardRead = false,
|
||||
const BotAppData *app = nullptr);
|
||||
void confirmAddToMenu(
|
||||
AttachWebViewBot bot,
|
||||
Fn<void()> callback = nullptr);
|
||||
@ -238,6 +240,7 @@ private:
|
||||
|
||||
std::vector<AttachWebViewBot> _attachBots;
|
||||
rpl::event_stream<> _attachBotsUpdates;
|
||||
base::flat_set<not_null<UserData*>> _disclaimerAccepted;
|
||||
|
||||
std::unique_ptr<Ui::BotWebView::Panel> _panel;
|
||||
|
||||
|
@ -24,7 +24,9 @@ void ConfirmBox(not_null<Ui::GenericBox*> box, ConfirmBoxArgs &&args) {
|
||||
|
||||
if (!v::is_null(args.text)) {
|
||||
const auto padding = st::boxPadding;
|
||||
const auto use = withTitle
|
||||
const auto use = args.labelPadding
|
||||
? *args.labelPadding
|
||||
: withTitle
|
||||
? QMargins(padding.left(), 0, padding.right(), padding.bottom())
|
||||
: padding;
|
||||
const auto label = box->addRow(
|
||||
|
@ -30,6 +30,7 @@ struct ConfirmBoxArgs {
|
||||
|
||||
const style::FlatLabel *labelStyle = nullptr;
|
||||
Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)> labelFilter;
|
||||
std::optional<QMargins> labelPadding;
|
||||
|
||||
v::text::data title = v::null;
|
||||
|
||||
|
@ -561,10 +561,6 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
|
||||
_widget->showInner(std::move(outer));
|
||||
_webviewParent = container;
|
||||
|
||||
container->paintRequest() | rpl::start_with_next([=] {
|
||||
QPainter(container).fillRect(container->rect(), QColor(0, 128, 0, 255));
|
||||
}, container->lifetime());
|
||||
|
||||
_webviewBottom = std::make_unique<RpWidget>(_widget.get());
|
||||
const auto bottom = _webviewBottom.get();
|
||||
bottom->show();
|
||||
|
@ -211,15 +211,19 @@ void SetupMenuBots(
|
||||
) | rpl::then(
|
||||
bots->attachBotsUpdates()
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto width = wrap->widthNoMargins();
|
||||
wrap->clear();
|
||||
for (const auto &bot : bots->attachBots()) {
|
||||
if (!bot.inMainMenu) {
|
||||
continue;
|
||||
}
|
||||
const auto button = Settings::AddButton(
|
||||
container,
|
||||
wrap,
|
||||
rpl::single(bot.name),
|
||||
st::mainMenuButton);
|
||||
const auto menu = button->lifetime().make_state<
|
||||
base::unique_qptr<Ui::PopupMenu>
|
||||
>();
|
||||
const auto icon = Ui::CreateChild<InlineBots::MenuBotIcon>(
|
||||
button.get(),
|
||||
bot.media);
|
||||
@ -229,12 +233,57 @@ void SetupMenuBots(
|
||||
st::mainMenuButton.iconLeft,
|
||||
(height - icon->height()) / 2);
|
||||
}, button->lifetime());
|
||||
button->setClickedCallback([=] {
|
||||
bots->requestSimple(controller, bot.user, {
|
||||
const auto user = bot.user;
|
||||
button->setAcceptBoth(true);
|
||||
button->clicks(
|
||||
) | rpl::start_with_next([=](Qt::MouseButton which) {
|
||||
if (which == Qt::LeftButton) {
|
||||
bots->requestSimple(controller, user, {
|
||||
.fromMainMenu = true,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
(*menu) = nullptr;
|
||||
(*menu) = base::make_unique_q<Ui::PopupMenu>(
|
||||
button,
|
||||
st::popupMenuWithIcons);
|
||||
(*menu)->addAction(
|
||||
tr::lng_bot_remove_from_menu(tr::now),
|
||||
[=] { bots->removeFromMenu(user); },
|
||||
&st::menuIconDelete);
|
||||
(*menu)->popup(QCursor::pos());
|
||||
}
|
||||
}, button->lifetime());
|
||||
|
||||
const auto badge = bots->showingDisclaimer(bot)
|
||||
? Ui::CreateChild<Ui::PaddingWrap<Ui::FlatLabel>>(
|
||||
button.get(),
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
button,
|
||||
tr::lng_bot_side_menu_new(),
|
||||
st::settingsPremiumNewBadge),
|
||||
st::settingsPremiumNewBadgePadding)
|
||||
: nullptr;
|
||||
if (badge) {
|
||||
badge->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
badge->paintRequest() | rpl::start_with_next([=] {
|
||||
auto p = QPainter(badge);
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::windowBgActive);
|
||||
const auto r = st::settingsPremiumNewBadgePadding.left();
|
||||
p.drawRoundedRect(badge->rect(), r, r);
|
||||
}, badge->lifetime());
|
||||
|
||||
button->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize size) {
|
||||
badge->moveToRight(
|
||||
st::mainMenuButton.padding.right(),
|
||||
(size.height() - badge->height()) / 2,
|
||||
size.width());
|
||||
}, badge->lifetime());
|
||||
}
|
||||
}
|
||||
wrap->resizeToWidth(width);
|
||||
}, wrap->lifetime());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user