Refactored sending bot commands.

This commit is contained in:
23rd 2021-07-27 02:18:11 +03:00
parent 34cac3092f
commit a030907598
16 changed files with 149 additions and 52 deletions

View File

@ -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

View File

@ -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<HistoryMessageReplyMarkup>()) {
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<Bot::SendCommandRequest> {
return _sendCommandRequests.events();
}
BotKeyboard::~BotKeyboard() = default;

View File

@ -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<Bot::SendCommandRequest> sendCommandRequests() const;
~BotKeyboard();
protected:
@ -92,6 +95,8 @@ private:
QPoint _lastMousePos;
std::unique_ptr<ReplyKeyboard> _impl;
rpl::event_stream<Bot::SendCommandRequest> _sendCommandRequests;
const style::BotKeyboardButton *_st = nullptr;
};

View File

@ -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<ClickHandlerContext>();
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<ClickHandlerContext>();
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,
});
}
}

View File

@ -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<UserData*> bot) {

View File

@ -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;

View File

@ -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);

View File

@ -66,6 +66,11 @@ public:
const QRect &geometry,
not_null<PinnedMemento*> memento);
Window::SectionActionResult sendBotCommand(
Bot::SendCommandRequest request) override {
return Window::SectionActionResult::Fallback;
}
// Float player interface.
bool floatPlayerHandleWheelEvent(QEvent *e) override;
QRect floatPlayerAvailableRect() override;

View File

@ -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);

View File

@ -93,6 +93,9 @@ public:
const Window::SectionShow &params,
MsgId messageId) override;
Window::SectionActionResult sendBotCommand(
Bot::SendCommandRequest request) override;
void setInternalState(
const QRect &geometry,
not_null<RepliesMemento*> memento);

View File

@ -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) {

View File

@ -74,6 +74,9 @@ public:
const Window::SectionShow &params) override;
std::shared_ptr<Window::SectionMemento> createMemento() override;
Window::SectionActionResult sendBotCommand(
Bot::SendCommandRequest request) override;
void setInternalState(
const QRect &geometry,
not_null<ScheduledMemento*> memento);

View File

@ -572,12 +572,19 @@ void ActionsFiller::addBotCommandActions(not_null<UserData*> 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<QString> text,

View File

@ -828,7 +828,16 @@ crl::time MainWidget::highlightStartTime(not_null<const HistoryItem*> 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) {

View File

@ -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<SectionMemento> createMemento();

View File

@ -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