Add bot menu button with webview open support.

This commit is contained in:
John Preston 2022-04-07 16:16:43 +04:00
parent d35b8f82a3
commit 94c6793e92
9 changed files with 143 additions and 10 deletions

View File

@ -1755,6 +1755,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_add_to_menu_done" = "Bot added to the menu.";
"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";
"lng_typing" = "typing";
"lng_user_typing" = "{user} is typing";

View File

@ -133,10 +133,23 @@ void UserData::setBotInfo(const MTPBotInfo &info) {
const auto changedCommands = Data::UpdateBotCommands(
botInfo->commands,
d.vcommands());
auto text = QString();
auto url = QString();
d.vmenu_button().match([&](const MTPDbotMenuButton &data) {
text = qs(data.vtext());
url = qs(data.vurl());
}, [&](const auto &) {
});
const auto changedButton = (botInfo->botMenuButtonText != text)
|| (botInfo->botMenuButtonUrl != url);
if (changedButton) {
botInfo->botMenuButtonText = text;
botInfo->botMenuButtonUrl = url;
}
botInfo->inited = true;
if (changedCommands) {
if (changedCommands || changedButton) {
owner().botCommandsChanged(this);
}
} break;

View File

@ -612,6 +612,10 @@ HistoryWidget::HistoryWidget(
) | rpl::filter([=](not_null<PeerData*> peer) {
return _peer && (_peer == peer);
}) | rpl::start_with_next([=] {
if (updateCmdStartShown()) {
updateControlsVisibility();
updateControlsGeometry();
}
if (_fieldAutocomplete->clearFilteredBotCommands()) {
checkFieldAutocomplete();
}
@ -2701,6 +2705,9 @@ void HistoryWidget::updateControlsVisibility() {
_botKeyboardShow->hide();
_botKeyboardHide->hide();
_botCommandStart->hide();
if (_botMenuButton) {
_botMenuButton->hide();
}
if (_tabbedPanel) {
_tabbedPanel->hide();
}
@ -2751,6 +2758,9 @@ void HistoryWidget::updateControlsVisibility() {
}
}
_attachToggle->show();
if (_botMenuButton) {
_botMenuButton->show();
}
if (_silent) {
_silent->show();
}
@ -2798,6 +2808,9 @@ void HistoryWidget::updateControlsVisibility() {
if (_sendAs) {
_sendAs->hide();
}
if (_botMenuButton) {
_botMenuButton->hide();
}
_kbScroll->hide();
_fieldBarCancel->hide();
_tabbedSelectorToggle->hide();
@ -4427,19 +4440,66 @@ void HistoryWidget::updateSendButtonType() {
}
bool HistoryWidget::updateCmdStartShown() {
const auto bot = (_peer && _peer->asUser()->isBot())
? _peer->asUser()
: nullptr;
bool cmdStartShown = false;
if (_history && _peer && ((_peer->isChat() && _peer->asChat()->botStatus > 0) || (_peer->isMegagroup() && _peer->asChannel()->mgInfo->botStatus > 0) || (_peer->isUser() && _peer->asUser()->isBot()))) {
if (_history && _peer && ((_peer->isChat() && _peer->asChat()->botStatus > 0) || (_peer->isMegagroup() && _peer->asChannel()->mgInfo->botStatus > 0))) {
if (!isBotStart() && !isBlocked() && !_keyboard->hasMarkup() && !_keyboard->forceReply() && !_editMsgId) {
if (!HasSendText(_field)) {
cmdStartShown = true;
}
}
}
if (_cmdStartShown != cmdStartShown) {
_cmdStartShown = cmdStartShown;
return true;
const auto commandsChanged = (_cmdStartShown != cmdStartShown);
auto buttonChanged = false;
if (!bot
|| (bot->botInfo->botMenuButtonUrl.isEmpty()
&& bot->botInfo->commands.empty())) {
buttonChanged = (_botMenuButton != nullptr);
_botMenuButton.destroy();
} else if (!_botMenuButton) {
buttonChanged = true;
_botMenuButtonText = bot->botInfo->botMenuButtonText;
_botMenuButton.create(
this,
(_botMenuButtonText.isEmpty()
? tr::lng_bot_menu_button()
: rpl::single(_botMenuButtonText)),
st::historyBotMenuButton);
_botMenuButton->setTextTransform(
Ui::RoundButton::TextTransform::NoTransform);
_botMenuButton->setFullRadius(true);
_botMenuButton->setClickedCallback([=] {
const auto user = _peer ? _peer->asUser() : nullptr;
const auto bot = (user && user->isBot()) ? user : nullptr;
if (bot && !bot->botInfo->botMenuButtonUrl.isEmpty()) {
session().attachWebView().requestMenu(controller(), bot);
} else if (!_fieldAutocomplete->isHidden()) {
_fieldAutocomplete->hideAnimated();
} else {
_fieldAutocomplete->showFiltered(_peer, "/", true);
}
});
_botMenuButton->widthValue(
) | rpl::start_with_next([=](int width) {
if (width > st::historyBotMenuMaxWidth) {
_botMenuButton->setFullWidth(st::historyBotMenuMaxWidth);
} else {
updateFieldSize();
}
}, _botMenuButton->lifetime());
}
return false;
const auto textChanged = _botMenuButton
&& (_botMenuButtonText != bot->botInfo->botMenuButtonText);
if (textChanged) {
_botMenuButtonText = bot->botInfo->botMenuButtonText;
_botMenuButton->setText(_botMenuButtonText.isEmpty()
? tr::lng_bot_menu_button()
: rpl::single(_botMenuButtonText));
}
_cmdStartShown = cmdStartShown;
return commandsChanged || buttonChanged || textChanged;
}
void HistoryWidget::searchInChat() {
@ -4697,12 +4757,16 @@ void HistoryWidget::moveFieldControls() {
_kbScroll->setGeometryToLeft(0, bottom, width(), keyboardHeight);
}
// _attachToggle (_sendAs) ------- _inlineResults ---------------------------------- _tabbedPanel -------- _fieldBarCancel
// (_botMenuButton) _attachToggle (_sendAs) ---- _inlineResults ------------------------------ _tabbedPanel ------ _fieldBarCancel
// (_attachDocument|_attachPhoto) _field (_ttlInfo) (_scheduled) (_silent|_cmdStart|_kbShow) (_kbHide|_tabbedSelectorToggle) _send
// (_botStart|_unblock|_joinChannel|_muteUnmute|_reportMessages)
auto buttonsBottom = bottom - _attachToggle->height();
auto left = st::historySendRight;
if (_botMenuButton) {
const auto skip = st::historyBotMenuSkip;
_botMenuButton->moveToLeft(left + skip, buttonsBottom + skip); left += skip + _botMenuButton->width();
}
_attachToggle->moveToLeft(left, buttonsBottom); left += _attachToggle->width();
if (_sendAs) {
_sendAs->moveToLeft(left, buttonsBottom); left += _sendAs->width();
@ -4762,6 +4826,7 @@ void HistoryWidget::updateFieldSize() {
- st::historySendRight
- _send->width()
- _tabbedSelectorToggle->width();
if (_botMenuButton) fieldWidth -= st::historyBotMenuSkip + _botMenuButton->width();
if (_sendAs) fieldWidth -= _sendAs->width();
if (kbShowShown) fieldWidth -= _botKeyboardShow->width();
if (_cmdStartShown) fieldWidth -= _botCommandStart->width();

View File

@ -738,6 +738,8 @@ private:
object_ptr<Ui::FlatButton> _joinChannel;
object_ptr<Ui::FlatButton> _muteUnmute;
object_ptr<Ui::FlatButton> _reportMessages;
object_ptr<Ui::RoundButton> _botMenuButton = { nullptr };
QString _botMenuButtonText;
object_ptr<Ui::IconButton> _attachToggle;
object_ptr<Ui::SendAsButton> _sendAs = { nullptr };
object_ptr<Ui::EmojiButton> _tabbedSelectorToggle;

View File

@ -572,6 +572,40 @@ void AttachWebView::requestSimple(const WebViewButton &button) {
}).send();
}
void AttachWebView::requestMenu(
not_null<Window::SessionController*> controller,
not_null<UserData*> bot) {
cancel();
_bot = bot;
_peer = bot;
const auto url = bot->botInfo->botMenuButtonUrl;
const auto text = bot->botInfo->botMenuButtonText;
confirmOpen(controller, [=] {
using Flag = MTPmessages_RequestWebView::Flag;
_requestId = _session->api().request(MTPmessages_RequestWebView(
MTP_flags(Flag::f_theme_params
| Flag::f_url
| Flag::f_from_bot_menu),
_bot->input,
_bot->inputUser,
MTP_string(url),
MTPstring(),
MTP_dataJSON(MTP_bytes(Window::Theme::WebViewParams())),
MTPint()
)).done([=](const MTPWebViewResult &result) {
_requestId = 0;
result.match([&](const MTPDwebViewResultUrl &data) {
show(data.vquery_id().v, qs(data.vurl()), text);
});
}).fail([=](const MTP::Error &error) {
_requestId = 0;
if (error.type() == u"BOT_INVALID"_q) {
requestBots();
}
}).send();
});
}
void AttachWebView::confirmOpen(
not_null<Window::SessionController*> controller,
Fn<void()> done) {

View File

@ -64,6 +64,9 @@ public:
not_null<Window::SessionController*> controller,
not_null<UserData*> bot,
const WebViewButton &button);
void requestMenu(
not_null<Window::SessionController*> controller,
not_null<UserData*> bot);
void cancel();

View File

@ -167,6 +167,7 @@ void Panel::Button::updateFg(QColor fg) {
void Panel::Button::updateArgs(MainButtonArgs &&args) {
_textFull = std::move(args.text);
setDisabled(!args.isActive);
setVisible(args.isVisible);
toggleProgress(args.isProgressVisible);
update();
@ -251,8 +252,11 @@ void Panel::Button::paintEvent(QPaintEvent *e) {
p,
rect().marginsAdded({ 0, st::callRadius * 2, 0, 0 }),
RectPart::BottomLeft | RectPart::BottomRight);
const auto ripple = ResolveRipple(_bg.color()->c);
paintRipple(p, rect().topLeft(), &ripple);
if (!isDisabled()) {
const auto ripple = ResolveRipple(_bg.color()->c);
paintRipple(p, rect().topLeft(), &ripple);
}
p.setFont(_st.font);
@ -646,6 +650,7 @@ void Panel::processMainButtonMessage(const QJsonValue &value) {
}
_mainButton->updateArgs({
.isActive = args["is_active"].toBool(),
.isVisible = args["is_visible"].toBool(),
.isProgressVisible = args["is_progress_visible"].toBool(),
.text = args["text"].toString(),
@ -659,7 +664,9 @@ void Panel::createMainButton() {
const auto button = _mainButton.get();
button->setClickedCallback([=] {
postEvent("main_button_pressed");
if (!button->isDisabled()) {
postEvent("main_button_pressed");
}
});
button->hide();

View File

@ -22,6 +22,7 @@ struct Available;
namespace Ui::BotWebView {
struct MainButtonArgs {
bool isActive = false;
bool isVisible = false;
bool isProgressVisible = false;
QString text;

View File

@ -239,6 +239,13 @@ historyComposeFieldMaxHeight: 224px;
historySendPadding: 9px;
historySendRight: 2px;
historyBotMenuSkip: 8px;
historyBotMenuMaxWidth: 160px;
historyBotMenuButton: RoundButton(defaultActiveButton) {
width: -24px;
height: 30px;
textTop: 6px;
}
historyComposeButton: FlatButton {
color: windowActiveTextFg;