diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index a0bf8bbdec..1f4d720c3e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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"; diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp index 56696c471d..43e3d63abe 100644 --- a/Telegram/SourceFiles/data/data_user.cpp +++ b/Telegram/SourceFiles/data/data_user.cpp @@ -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; diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 64251a8c37..50b4faafc3 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -612,6 +612,10 @@ HistoryWidget::HistoryWidget( ) | rpl::filter([=](not_null 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(); diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index e077e12270..5a0bf8fe16 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -738,6 +738,8 @@ private: object_ptr _joinChannel; object_ptr _muteUnmute; object_ptr _reportMessages; + object_ptr _botMenuButton = { nullptr }; + QString _botMenuButtonText; object_ptr _attachToggle; object_ptr _sendAs = { nullptr }; object_ptr _tabbedSelectorToggle; diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 944b9440f7..e09b167c93 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -572,6 +572,40 @@ void AttachWebView::requestSimple(const WebViewButton &button) { }).send(); } +void AttachWebView::requestMenu( + not_null controller, + not_null 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 controller, Fn done) { diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h index 564ae6698b..425d88505a 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h @@ -64,6 +64,9 @@ public: not_null controller, not_null bot, const WebViewButton &button); + void requestMenu( + not_null controller, + not_null bot); void cancel(); diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp index 99a51cea56..e47cb07efa 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp @@ -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(); diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h index c8feb45d43..acd436e858 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h +++ b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h @@ -22,6 +22,7 @@ struct Available; namespace Ui::BotWebView { struct MainButtonArgs { + bool isActive = false; bool isVisible = false; bool isProgressVisible = false; QString text; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 406081be29..fa71b6c6b0 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -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;