diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 7bfd6ff7a7..475a11ce59 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -208,6 +208,8 @@ nice_target_sources(Telegram ${src_loc} PRIVATE ${style_files} + api/api_bot.cpp + api/api_bot.h api/api_chat_filters.cpp api/api_chat_filters.h api/api_common.h diff --git a/Telegram/SourceFiles/api/api_bot.cpp b/Telegram/SourceFiles/api/api_bot.cpp new file mode 100644 index 0000000000..2b3b5eff60 --- /dev/null +++ b/Telegram/SourceFiles/api/api_bot.cpp @@ -0,0 +1,112 @@ +/* +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 +*/ +#include "api/api_bot.h" + +#include "apiwrap.h" +#include "api/api_send_progress.h" +#include "boxes/confirm_box.h" +#include "boxes/share_box.h" +#include "core/click_handler_types.h" +#include "data/data_changes.h" +#include "data/data_peer.h" +#include "data/data_session.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/history_item_components.h" +#include "main/main_session.h" +#include "ui/toast/toast.h" + +namespace Api { + +void SendBotCallbackData( + not_null item, + int row, + int column) { + if (!IsServerMsgId(item->id)) { + return; + } + const auto history = item->history(); + const auto session = &history->session(); + const auto owner = &history->owner(); + const auto api = &session->api(); + const auto bot = item->getMessageBot(); + const auto getButton = [=] { + return HistoryMessageMarkupButton::Get( + owner, + item->fullId(), + row, + column); + }; + const auto button = getButton(); + if (!button) { + return; + } + + using ButtonType = HistoryMessageMarkupButton::Type; + const auto gameProgressType = Api::SendProgressType::PlayGame; + const auto isGame = (button->type == ButtonType::Game); + + auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0); + QByteArray sendData; + if (isGame) { + flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game; + } else if (button->type == ButtonType::Callback) { + flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data; + sendData = button->data; + } + button->requestId = api->request(MTPmessages_GetBotCallbackAnswer( + MTP_flags(flags), + history->peer->input, + MTP_int(item->id), + MTP_bytes(sendData) + )).done([=](const MTPmessages_BotCallbackAnswer &result, auto id) { + if (const auto button = getButton()) { + button->requestId = 0; + owner->requestItemRepaint(item); + } + result.match([&](const MTPDmessages_botCallbackAnswer &data) { + if (const auto message = data.vmessage()) { + if (data.is_alert()) { + Ui::show(Box(qs(*message))); + } else { + Ui::Toast::Show(qs(*message)); + } + } else if (const auto url = data.vurl()) { + const auto link = qs(*url); + if (!isGame) { + UrlClickHandler::Open(link); + return; + } + const auto scoreLink = AppendShareGameScoreUrl( + session, + link, + item->fullId()); + BotGameUrlClickHandler(bot, scoreLink).onClick({}); + + if (history->mySendActionUpdated(gameProgressType, true)) { + session->sendProgressManager().update( + history, + gameProgressType); + } + } + }); + }).fail([=](const RPCError &error, auto id) { + // Show error? + if (const auto button = getButton()) { + button->requestId = 0; + owner->requestItemRepaint(item); + } + }).send(); + + session->changes().messageUpdated( + item, + Data::MessageUpdate::Flag::BotCallbackSent + ); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_bot.h b/Telegram/SourceFiles/api/api_bot.h new file mode 100644 index 0000000000..9ce54feff7 --- /dev/null +++ b/Telegram/SourceFiles/api/api_bot.h @@ -0,0 +1,19 @@ +/* +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 + +class HistoryItem; + +namespace Api { + +void SendBotCallbackData( + not_null item, + int row, + int column); + +} // namespace Api diff --git a/Telegram/SourceFiles/data/data_changes.h b/Telegram/SourceFiles/data/data_changes.h index 930df35d5a..4e40a7ab94 100644 --- a/Telegram/SourceFiles/data/data_changes.h +++ b/Telegram/SourceFiles/data/data_changes.h @@ -134,8 +134,9 @@ struct MessageUpdate { DialogRowRefresh = (1 << 3), CallAdded = (1 << 4), ReplyMarkup = (1 << 5), + BotCallbackSent = (1 << 6), - LastUsedBit = (1 << 5), + LastUsedBit = (1 << 6), }; using Flags = base::flags; friend inline constexpr auto is_flag_type(Flag) { return true; } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 1ab92b10e8..a2fc7f27b2 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "facades.h" +#include "api/api_bot.h" #include "info/info_memento.h" #include "core/click_handler_types.h" #include "core/application.h" @@ -106,9 +107,10 @@ void activateBotCommand( case ButtonType::Callback: case ButtonType::Game: { - if (const auto m = CheckMainWidget(&msg->history()->session())) { - m->app_sendBotCallback(button, msg, row, column); - } + Api::SendBotCallbackData( + const_cast(msg.get()), + row, + column); } break; case ButtonType::Buy: { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 874d909ac8..3996b48e1c 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/history_widget.h" +#include "api/api_bot.h" #include "api/api_sending.h" #include "api/api_text_entities.h" #include "api/api_send_progress.h" @@ -604,6 +605,33 @@ HistoryWidget::HistoryWidget( } }, lifetime()); + session().changes().messageUpdates( + Data::MessageUpdate::Flag::BotCallbackSent + ) | rpl::start_with_next([=](const Data::MessageUpdate &update) { + const auto item = update.item; + if (item->id < 0 || _peer != item->history()->peer) { + return; + } + + const auto keyId = _keyboard->forMsgId(); + const auto lastKeyboardUsed = (keyId == FullMsgId(_channel, item->id)) + && (keyId == FullMsgId(_channel, _history->lastKeyboardId)); + + session().data().requestItemRepaint(item); + + if (_replyToId == item->id) { + cancelReply(); + } + if (_keyboard->singleUse() + && _keyboard->hasMarkup() + && lastKeyboardUsed) { + if (_kbShown) { + toggleKeyboard(false); + } + _history->lastKeyboardUsed = true; + } + }, lifetime()); + subscribe(Media::Player::instance()->switchToNextNotifier(), [this](const Media::Player::Instance::Switch &pair) { if (pair.from.type() == AudioMsgId::Type::Voice) { scrollToCurrentVoiceMessage(pair.from.contextId(), pair.to); @@ -3596,115 +3624,6 @@ void HistoryWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) { } } -void HistoryWidget::app_sendBotCallback( - not_null button, - not_null msg, - int row, - int column) { - if (msg->id < 0 || _peer != msg->history()->peer) { - return; - } - - bool lastKeyboardUsed = (_keyboard->forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard->forMsgId() == FullMsgId(_channel, msg->id)); - - auto bot = msg->getMessageBot(); - - using ButtonType = HistoryMessageMarkupButton::Type; - BotCallbackInfo info = { - &session(), - bot, - msg->fullId(), - row, - column, - (button->type == ButtonType::Game) - }; - auto flags = MTPmessages_GetBotCallbackAnswer::Flags(0); - QByteArray sendData; - if (info.game) { - flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_game; - } else if (button->type == ButtonType::Callback) { - flags |= MTPmessages_GetBotCallbackAnswer::Flag::f_data; - sendData = button->data; - } - button->requestId = session().api().request(MTPmessages_GetBotCallbackAnswer( - MTP_flags(flags), - _peer->input, - MTP_int(msg->id), - MTP_bytes(sendData) - )).done([info](const MTPmessages_BotCallbackAnswer &result, mtpRequestId requestId) { - BotCallbackDone(info, result, requestId); - }).fail([info](const RPCError &error, mtpRequestId requestId) { - BotCallbackFail(info, error, requestId); - }).send(); - session().data().requestItemRepaint(msg); - - if (_replyToId == msg->id) { - cancelReply(); - } - if (_keyboard->singleUse() && _keyboard->hasMarkup() && lastKeyboardUsed) { - if (_kbShown) toggleKeyboard(false); - _history->lastKeyboardUsed = true; - } -} - -void HistoryWidget::BotCallbackDone( - BotCallbackInfo info, - const MTPmessages_BotCallbackAnswer &answer, - mtpRequestId req) { - const auto session = info.session; - const auto item = session->data().message(info.msgId); - const auto button = HistoryMessageMarkupButton::Get( - &session->data(), - info.msgId, - info.row, - info.col); - if (button && button->requestId == req) { - button->requestId = 0; - session->data().requestItemRepaint(item); - } - answer.match([&](const MTPDmessages_botCallbackAnswer &data) { - if (const auto message = data.vmessage()) { - if (data.is_alert()) { - Ui::show(Box(qs(*message))); - } else { - Ui::Toast::Show(qs(*message)); - } - } else if (const auto url = data.vurl()) { - auto link = qs(*url); - if (info.game) { - link = AppendShareGameScoreUrl(session, link, info.msgId); - BotGameUrlClickHandler(info.bot, link).onClick({}); - } else { - UrlClickHandler::Open(link); - } - } - if (const auto item = info.session->data().message(info.msgId)) { - if (!data.vmessage() && data.vurl() && info.game) { - info.session->sendProgressManager().update( - item->history(), - Api::SendProgressType::PlayGame); - } - } - }); -} - -void HistoryWidget::BotCallbackFail( - BotCallbackInfo info, - const RPCError &error, - mtpRequestId req) { - // show error? - const auto owner = &info.session->data(); - const auto button = HistoryMessageMarkupButton::Get( - owner, - info.msgId, - info.row, - info.col); - if (button && button->requestId == req) { - button->requestId = 0; - owner->requestItemRepaint(owner->message(info.msgId)); - } -} - bool HistoryWidget::insertBotCommand(const QString &cmd) { if (!canWriteMessage()) return false; diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index e75111d007..5f7bd8b6ae 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -268,12 +268,6 @@ public: bool floatPlayerHandleWheelEvent(QEvent *e) override; QRect floatPlayerAvailableRect() override; - void app_sendBotCallback( - not_null button, - not_null msg, - int row, - int column); - PeerData *ui_getPeerForMouseAction(); bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); @@ -335,13 +329,6 @@ private: using TabbedPanel = ChatHelpers::TabbedPanel; using TabbedSelector = ChatHelpers::TabbedSelector; using DragState = Storage::MimeDataState; - struct BotCallbackInfo { - not_null session; - UserData *bot; - FullMsgId msgId; - int row, col; - bool game; - }; struct PinnedBar { PinnedBar(MsgId msgId, HistoryWidget *parent); ~PinnedBar(); @@ -551,9 +538,6 @@ private: static void UnpinMessage(not_null peer); - static void BotCallbackDone(BotCallbackInfo info, const MTPmessages_BotCallbackAnswer &answer, mtpRequestId req); - static void BotCallbackFail(BotCallbackInfo info, const RPCError &error, mtpRequestId req); - void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 }); void updateListSize(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index efe872c44d..fb50ffd1d5 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -833,14 +833,6 @@ void MainWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) { _history->hideSingleUseKeyboard(peer, replyTo); } -void MainWidget::app_sendBotCallback( - not_null button, - not_null msg, - int row, - int column) { - _history->app_sendBotCallback(button, msg, row, column); -} - bool MainWidget::insertBotCommand(const QString &cmd) { return _history->insertBotCommand(cmd); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 97a6116cb9..b4737f49b8 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -219,12 +219,6 @@ public: void searchInChat(Dialogs::Key chat); - void app_sendBotCallback( - not_null button, - not_null msg, - int row, - int column); - void ui_showPeerHistory( PeerId peer, const SectionShow ¶ms,