diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a034160700..18a2c486a8 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -1094,6 +1094,7 @@ PRIVATE window/window_outdated_bar.h window/window_peer_menu.cpp window/window_peer_menu.h + window/window_section_common.h window/window_session_controller.cpp window/window_session_controller.h window/window_slide_animation.cpp diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp index ece1c61f0c..7f43c43cc6 100644 --- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp +++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp @@ -161,6 +161,30 @@ void BotKeyboard::leaveEventHook(QEvent *e) { bool BotKeyboard::moderateKeyActivate(int key) { const auto &data = _controller->session().data(); + + const auto botCommand = [](int key) { + if (key == Qt::Key_Q || key == Qt::Key_6) { + return u"/translate"_q; + } else if (key == Qt::Key_W || key == Qt::Key_5) { + return u"/eng"_q; + } else if (key == Qt::Key_3) { + return u"/pattern"_q; + } else if (key == Qt::Key_4) { + return u"/abuse"_q; + } else if (key == Qt::Key_0 || key == Qt::Key_E || key == Qt::Key_9) { + return u"/undo"_q; + } else if (key == Qt::Key_Plus + || key == Qt::Key_QuoteLeft + || key == Qt::Key_7) { + return u"/next"_q; + } else if (key == Qt::Key_Period + || key == Qt::Key_S + || key == Qt::Key_8) { + return u"/stats"_q; + } + return QString(); + }; + if (const auto item = data.message(_wasForMsgId)) { if (const auto markup = item->Get()) { if (key >= Qt::Key_1 && key <= Qt::Key_2) { @@ -173,20 +197,13 @@ bool BotKeyboard::moderateKeyActivate(int key) { } } else if (const auto user = item->history()->peer->asUser()) { if (user->isBot() && item->from() == user) { - if (key == Qt::Key_Q || key == Qt::Key_6) { - App::sendBotCommand(user, user, qsl("/translate")); - } else if (key == Qt::Key_W || key == Qt::Key_5) { - App::sendBotCommand(user, user, qsl("/eng")); - } else if (key == Qt::Key_3) { - App::sendBotCommand(user, user, qsl("/pattern")); - } else if (key == Qt::Key_4) { - App::sendBotCommand(user, user, qsl("/abuse")); - } else if (key == Qt::Key_0 || key == Qt::Key_E || key == Qt::Key_9) { - App::sendBotCommand(user, user, qsl("/undo")); - } else if (key == Qt::Key_Plus || key == Qt::Key_QuoteLeft || key == Qt::Key_7) { - App::sendBotCommand(user, user, qsl("/next")); - } else if (key == Qt::Key_Period || key == Qt::Key_S || key == Qt::Key_8) { - App::sendBotCommand(user, user, qsl("/stats")); + const auto command = botCommand(key); + if (!command.isEmpty()) { + _sendCommandRequests.fire({ + .peer = user, + .command = command, + .context = item->fullId(), + }); } return true; } @@ -327,4 +344,9 @@ void BotKeyboard::updateSelected() { } } +auto BotKeyboard::sendCommandRequests() const +-> rpl::producer { + return _sendCommandRequests.events(); +} + BotKeyboard::~BotKeyboard() = default; diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.h b/Telegram/SourceFiles/chat_helpers/bot_keyboard.h index 2afa020d76..2096234613 100644 --- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.h +++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/widgets/tooltip.h" +#include "chat_helpers/bot_command.h" class ReplyKeyboard; @@ -62,6 +63,8 @@ public: void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; + rpl::producer sendCommandRequests() const; + ~BotKeyboard(); protected: @@ -92,6 +95,8 @@ private: QPoint _lastMousePos; std::unique_ptr _impl; + rpl::event_stream _sendCommandRequests; + const style::BotKeyboardButton *_st = nullptr; }; diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp index 2314e3c42b..d7caa8b3be 100644 --- a/Telegram/SourceFiles/core/click_handler_types.cpp +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -216,24 +216,30 @@ auto CashtagClickHandler::getTextEntity() const -> TextEntity { void BotCommandClickHandler::onClick(ClickContext context) const { const auto button = context.button; - if (button == Qt::LeftButton || button == Qt::MiddleButton) { - const auto my = context.other.value(); - if (const auto delegate = my.elementDelegate ? my.elementDelegate() : nullptr) { - delegate->elementSendBotCommand(_cmd, my.itemId); + if (button != Qt::LeftButton && button != Qt::MiddleButton) { + return; + } + const auto my = context.other.value(); + if (const auto delegate = my.elementDelegate ? my.elementDelegate() : nullptr) { + delegate->elementSendBotCommand(_cmd, my.itemId); + } else if (const auto controller = my.sessionWindow.get()) { + const auto peer = my.peer + ? my.peer + : my.itemId + ? controller->session().data().message(my.itemId)->history()->peer + : nullptr; + // Can't find context. + if (!peer) { return; - } else if (auto peer = Ui::getPeerForMouseAction()) { // old way - auto bot = peer->isUser() ? peer->asUser() : nullptr; - if (!bot) { - if (const auto view = App::hoveredLinkItem()) { - // may return nullptr - bot = view->data()->fromOriginal()->asUser(); - } - } - Ui::showPeerHistory(peer, ShowAtTheEndMsgId); - App::sendBotCommand(peer, bot, _cmd); - } else { - App::insertBotCommand(_cmd); } + controller->widget()->ui_hideSettingsAndLayer(anim::type::normal); + Core::App().hideMediaView(); + controller->content()->sendBotCommand({ + .peer = peer, + .command = _cmd, + .context = my.itemId, + .replyTo = 0, + }); } } diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index b60d123e86..a88062abcb 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -2620,19 +2620,7 @@ bool HistoryInner::elementIsGifPaused() { void HistoryInner::elementSendBotCommand( const QString &command, const FullMsgId &context) { - if (auto peer = Ui::getPeerForMouseAction()) { // old way - auto bot = peer->isUser() ? peer->asUser() : nullptr; - if (!bot) { - if (const auto view = App::hoveredLinkItem()) { - // may return nullptr - bot = view->data()->fromOriginal()->asUser(); - } - } - Ui::showPeerHistory(peer, ShowAtTheEndMsgId); - App::sendBotCommand(peer, bot, command); - } else { - App::insertBotCommand(command); - } + _widget->sendBotCommand({ _history->peer, command, context }); } void HistoryInner::elementHandleViaClick(not_null bot) { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index be88ff850b..3b3e3fed8d 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -313,6 +313,11 @@ HistoryWidget::HistoryWidget( InitMessageField(controller, _field); + _keyboard->sendCommandRequests( + ) | rpl::start_with_next([=](Bot::SendCommandRequest r) { + sendBotCommand(r); + }, lifetime()); + _fieldAutocomplete->mentionChosen( ) | rpl::start_with_next([=](FieldAutocomplete::MentionChosen data) { insertMention(data.user); @@ -1189,7 +1194,7 @@ void HistoryWidget::insertHashtagOrBotCommand( // Send bot command at once, if it was not inserted by pressing Tab. if (str.at(0) == '/' && method != FieldAutocomplete::ChooseMethod::ByTab) { - App::sendBotCommand(_peer, nullptr, str, replyToId()); + sendBotCommand({ _peer, str, FullMsgId(), replyToId() }); session().api().finishForwarding(Api::SendAction(_history)); setFieldText(_field->getTextWithTagsPart(_field->textCursor().position())); } else { @@ -3601,7 +3606,7 @@ void HistoryWidget::mouseReleaseEvent(QMouseEvent *e) { } } -void HistoryWidget::sendBotCommand(Bot::SendCommandRequest request) { +void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) { // replyTo != 0 from ReplyKeyboardMarkup, == 0 from command links if (_peer != request.peer.get()) { return; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 2d8b0c3c47..36098584af 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -213,7 +213,7 @@ public: void escape(); - void sendBotCommand(Bot::SendCommandRequest request); + void sendBotCommand(const Bot::SendCommandRequest &request); void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo); bool insertBotCommand(const QString &cmd); diff --git a/Telegram/SourceFiles/history/view/history_view_pinned_section.h b/Telegram/SourceFiles/history/view/history_view_pinned_section.h index 0420b4d704..9757935d1e 100644 --- a/Telegram/SourceFiles/history/view/history_view_pinned_section.h +++ b/Telegram/SourceFiles/history/view/history_view_pinned_section.h @@ -66,6 +66,11 @@ public: const QRect &geometry, not_null memento); + Window::SectionActionResult sendBotCommand( + Bot::SendCommandRequest request) override { + return Window::SectionActionResult::Fallback; + } + // Float player interface. bool floatPlayerHandleWheelEvent(QEvent *e) override; QRect floatPlayerAvailableRect() override; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index 2d29151e0e..e40e1629c9 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -1394,6 +1394,15 @@ bool RepliesWidget::showMessage( return true; } +Window::SectionActionResult RepliesWidget::sendBotCommand( + Bot::SendCommandRequest request) { + if (request.peer != _history->peer) { + return Window::SectionActionResult::Ignore; + } + listSendBotCommand(request.command, request.context); + return Window::SectionActionResult::Handle; +} + void RepliesWidget::replyToMessage(FullMsgId itemId) { // if (item->history() != _history || item->replyToTop() != _rootId) { _composeControls->replyToMessage(itemId); diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index 566422c296..f56a511f4d 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -93,6 +93,9 @@ public: const Window::SectionShow ¶ms, MsgId messageId) override; + Window::SectionActionResult sendBotCommand( + Bot::SendCommandRequest request) override; + void setInternalState( const QRect &geometry, not_null memento); diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp index cc3b7d4645..d7ffa049e8 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.cpp @@ -1177,6 +1177,15 @@ bool ScheduledWidget::listIsGoodForAroundPosition( return true; } +Window::SectionActionResult ScheduledWidget::sendBotCommand( + Bot::SendCommandRequest request) { + if (request.peer != _history->peer) { + return Window::SectionActionResult::Ignore; + } + listSendBotCommand(request.command, request.context); + return Window::SectionActionResult::Handle; +} + void ScheduledWidget::listSendBotCommand( const QString &command, const FullMsgId &context) { diff --git a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h index 28f2c3fea7..ea3f92b5b7 100644 --- a/Telegram/SourceFiles/history/view/history_view_scheduled_section.h +++ b/Telegram/SourceFiles/history/view/history_view_scheduled_section.h @@ -74,6 +74,9 @@ public: const Window::SectionShow ¶ms) override; std::shared_ptr createMemento() override; + Window::SectionActionResult sendBotCommand( + Bot::SendCommandRequest request) override; + void setInternalState( const QRect &geometry, not_null memento); diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 07f1c5a759..d454ba05c0 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -572,12 +572,19 @@ void ActionsFiller::addBotCommandActions(not_null user) { return !findBotCommand(command).isEmpty(); }); }; - auto sendBotCommand = [=](const QString &command) { - auto original = findBotCommand(command); - if (!original.isEmpty()) { - Ui::showPeerHistory(user, ShowAtTheEndMsgId); - App::sendBotCommand(user, user, '/' + original); + auto sendBotCommand = [=, window = _controller->parentController()]( + const QString &command) { + const auto original = findBotCommand(command); + if (original.isEmpty()) { + return; } + BotCommandClickHandler('/' + original).onClick(ClickContext{ + Qt::LeftButton, + QVariant::fromValue(ClickHandlerContext{ + .sessionWindow = base::make_weak(window.get()), + .peer = user, + }) + }); }; auto addBotCommand = [=]( rpl::producer text, diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index acc296483a..8e3856a3ca 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -828,7 +828,16 @@ crl::time MainWidget::highlightStartTime(not_null item) cons } void MainWidget::sendBotCommand(Bot::SendCommandRequest request) { - _history->sendBotCommand(request); + const auto type = _mainSection + ? _mainSection->sendBotCommand(request) + : Window::SectionActionResult::Fallback; + if (type == Window::SectionActionResult::Fallback) { + ui_showPeerHistory( + request.peer->id, + SectionShow::Way::ClearStack, + ShowAtTheEndMsgId); + _history->sendBotCommand(request); + } } void MainWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) { diff --git a/Telegram/SourceFiles/window/section_widget.h b/Telegram/SourceFiles/window/section_widget.h index ef7c7720b3..cb9ea5abea 100644 --- a/Telegram/SourceFiles/window/section_widget.h +++ b/Telegram/SourceFiles/window/section_widget.h @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "dialogs/dialogs_key.h" #include "media/player/media_player_float.h" // FloatSectionDelegate #include "base/object_ptr.h" +#include "window/window_section_common.h" namespace Main { class Session; @@ -130,6 +131,12 @@ public: return false; } + // Send bot command from peer info or media viewer. + virtual SectionActionResult sendBotCommand( + Bot::SendCommandRequest request) { + return SectionActionResult::Ignore; + } + // Create a memento of that section to store it in the history stack. // This method may modify the section ("take" heavy items). virtual std::shared_ptr createMemento(); diff --git a/Telegram/SourceFiles/window/window_section_common.h b/Telegram/SourceFiles/window/window_section_common.h new file mode 100644 index 0000000000..4dffe113f9 --- /dev/null +++ b/Telegram/SourceFiles/window/window_section_common.h @@ -0,0 +1,18 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Window { + +enum class SectionActionResult { + Handle, // Handle an action and stay in the current section. + Fallback, // Ignore an action and fallback to the HistoryWidget. + Ignore, // Ignore an action and stay in the current section. +}; + +} // namespace Window