diff --git a/Telegram/SourceFiles/api/api_bot.cpp b/Telegram/SourceFiles/api/api_bot.cpp index 072758298..10725c8e6 100644 --- a/Telegram/SourceFiles/api/api_bot.cpp +++ b/Telegram/SourceFiles/api/api_bot.cpp @@ -9,21 +9,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" #include "api/api_cloud_password.h" -#include "core/core_cloud_password.h" #include "api/api_send_progress.h" -#include "ui/boxes/confirm_box.h" #include "boxes/share_box.h" #include "boxes/passcode_box.h" +#include "boxes/url_auth_box.h" #include "lang/lang_keys.h" +#include "core/core_cloud_password.h" #include "core/click_handler_types.h" #include "data/data_changes.h" #include "data/data_peer.h" +#include "data/data_poll.h" +#include "data/data_user.h" #include "data/data_session.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_item_components.h" +#include "inline_bots/bot_attach_web_view.h" +#include "payments/payments_checkout_process.h" #include "main/main_session.h" +#include "mainwidget.h" +#include "mainwindow.h" #include "window/window_session_controller.h" +#include "window/window_peer_menu.h" +#include "ui/boxes/confirm_box.h" #include "ui/toast/toast.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" @@ -36,7 +44,7 @@ void SendBotCallbackData( not_null item, int row, int column, - std::optional password = std::nullopt, + std::optional password, Fn handleError = nullptr) { if (!item->isRegular()) { return; @@ -154,6 +162,14 @@ void SendBotCallbackData( ); } +void HideSingleUseKeyboard( + not_null controller, + not_null item) { + controller->content()->hideSingleUseKeyboard( + item->history()->peer, + item->id); +} + } // namespace void SendBotCallbackData( @@ -252,4 +268,192 @@ void SendBotCallbackDataWithPassword( }); } +bool SwitchInlineBotButtonReceived( + not_null controller, + const QString &query, + UserData *samePeerBot, + MsgId samePeerReplyTo) { + return controller->content()->notify_switchInlineBotButtonReceived( + query, + samePeerBot, + samePeerReplyTo); +} + +void ActivateBotCommand( + not_null controller, + not_null item, + int row, + int column) { + const auto button = HistoryMessageMarkupButton::Get( + &item->history()->owner(), + item->fullId(), + row, + column); + if (!button) { + return; + } + + using ButtonType = HistoryMessageMarkupButton::Type; + switch (button->type) { + case ButtonType::Default: { + // Copy string before passing it to the sending method + // because the original button can be destroyed inside. + const auto replyTo = item->isRegular() ? item->id : 0; + controller->content()->sendBotCommand({ + .peer = item->history()->peer, + .command = QString(button->text), + .context = item->fullId(), + .replyTo = replyTo, + }); + } break; + + case ButtonType::Callback: + case ButtonType::Game: { + SendBotCallbackData(controller, item, row, column); + } break; + + case ButtonType::CallbackWithPassword: { + SendBotCallbackDataWithPassword(controller, item, row, column); + } break; + + case ButtonType::Buy: { + Payments::CheckoutProcess::Start( + item, + Payments::Mode::Payment, + crl::guard(controller, [=](auto) { + controller->widget()->activate(); + })); + } break; + + case ButtonType::Url: { + auto url = QString::fromUtf8(button->data); + auto skipConfirmation = false; + if (const auto bot = item->getMessageBot()) { + if (bot->isVerified()) { + skipConfirmation = true; + } + } + const auto context = QVariant::fromValue(ClickHandlerContext{ + .sessionWindow = controller.get(), + }); + if (skipConfirmation) { + UrlClickHandler::Open(url, context); + } else { + HiddenUrlClickHandler::Open(url, context); + } + } break; + + case ButtonType::RequestLocation: { + HideSingleUseKeyboard(controller, item); + controller->show( + Ui::MakeInformBox(tr::lng_bot_share_location_unavailable())); + } break; + + case ButtonType::RequestPhone: { + HideSingleUseKeyboard(controller, item); + const auto itemId = item->id; + const auto history = item->history(); + controller->show(Ui::MakeConfirmBox({ + .text = tr::lng_bot_share_phone(), + .confirmed = [=] { + controller->showPeerHistory( + history, + Window::SectionShow::Way::Forward, + ShowAtTheEndMsgId); + auto action = Api::SendAction(history); + action.clearDraft = false; + action.replyTo = itemId; + history->session().api().shareContact( + history->session().user(), + action); + }, + .confirmText = tr::lng_bot_share_phone_confirm(), + })); + } break; + + case ButtonType::RequestPoll: { + HideSingleUseKeyboard(controller, item); + auto chosen = PollData::Flags(); + auto disabled = PollData::Flags(); + if (!button->data.isEmpty()) { + disabled |= PollData::Flag::Quiz; + if (button->data[0]) { + chosen |= PollData::Flag::Quiz; + } + } + const auto replyToId = MsgId(0); + Window::PeerMenuCreatePoll( + controller, + item->history()->peer, + replyToId, + chosen, + disabled); + } break; + + case ButtonType::SwitchInlineSame: + case ButtonType::SwitchInline: { + const auto session = &item->history()->session(); + if (const auto bot = item->getMessageBot()) { + const auto fastSwitchDone = [&] { + const auto samePeer = (button->type + == ButtonType::SwitchInlineSame); + if (samePeer) { + SwitchInlineBotButtonReceived( + controller, + QString::fromUtf8(button->data), + bot, + item->id); + return true; + } else if (bot->isBot() && bot->botInfo->inlineReturnTo.key) { + const auto switched = SwitchInlineBotButtonReceived( + controller, + QString::fromUtf8(button->data)); + if (switched) { + return true; + } + } + return false; + }(); + if (!fastSwitchDone) { + controller->content()->inlineSwitchLayer('@' + + bot->username + + ' ' + + QString::fromUtf8(button->data)); + } + } + } break; + + case ButtonType::Auth: + UrlAuthBox::Activate(item, row, column); + break; + + case ButtonType::UserProfile: { + const auto session = &item->history()->session(); + const auto userId = UserId(button->data.toULongLong()); + if (const auto user = session->data().userLoaded(userId)) { + controller->showPeerInfo(user); + } + } break; + + case ButtonType::WebView: { + if (const auto bot = item->getMessageBot()) { + bot->session().attachWebView().request( + controller, + bot, + bot, + { .text = button->text, .url = button->data }); + } + } break; + + case ButtonType::SimpleWebView: { + if (const auto bot = item->getMessageBot()) { + bot->session().attachWebView().requestSimple( + controller, + bot, + { .text = button->text, .url = button->data }); + } + } break; + } +} + } // namespace Api diff --git a/Telegram/SourceFiles/api/api_bot.h b/Telegram/SourceFiles/api/api_bot.h index 45a40ca08..0c8ecbacd 100644 --- a/Telegram/SourceFiles/api/api_bot.h +++ b/Telegram/SourceFiles/api/api_bot.h @@ -27,4 +27,16 @@ void SendBotCallbackDataWithPassword( int row, int column); +bool SwitchInlineBotButtonReceived( + not_null controller, + const QString &query, + UserData *samePeerBot = nullptr, + MsgId samePeerReplyTo = 0); + +void ActivateBotCommand( + not_null controller, + not_null item, + int row, + int column); + } // namespace Api diff --git a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp index 13e1e571d..9d14fa556 100644 --- a/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp +++ b/Telegram/SourceFiles/chat_helpers/bot_keyboard.cpp @@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "window/window_session_controller.h" #include "ui/cached_round_corners.h" -#include "facades.h" +#include "api/api_bot.h" #include "styles/style_widgets.h" #include "styles/style_chat.h" @@ -202,7 +202,7 @@ bool BotKeyboard::moderateKeyActivate(int key) { if (!markup->data.rows.empty() && index >= 0 && index < int(markup->data.rows.front().size())) { - App::activateBotCommand(_controller, item, 0, index); + Api::ActivateBotCommand(_controller, item, 0, index); return true; } } else if (const auto user = item->history()->peer->asUser()) { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index ba9242c07..e74136f0b 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_app_config.h" #include "apiwrap.h" #include "mainwidget.h" +#include "api/api_bot.h" #include "api/api_text_entities.h" #include "core/application.h" #include "core/core_settings.h" @@ -105,9 +106,13 @@ void CheckForSwitchInlineButton(not_null item) { for (const auto &button : row) { using ButtonType = HistoryMessageMarkupButton::Type; if (button.type == ButtonType::SwitchInline) { - Notify::switchInlineBotButtonReceived( - &item->history()->session(), - QString::fromUtf8(button.data)); + const auto session = &item->history()->session(); + const auto &windows = session->windows(); + if (!windows.empty()) { + Api::SwitchInlineBotButtonReceived( + windows.front(), + QString::fromUtf8(button.data)); + } return; } } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index dd33432c0..21b7c13c4 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -56,201 +56,6 @@ namespace { } // namespace -namespace App { - -void hideSingleUseKeyboard(not_null message) { - if (const auto m = CheckMainWidget(&message->history()->session())) { - m->hideSingleUseKeyboard(message->history()->peer, message->id); - } -} - -bool insertBotCommand(const QString &cmd) { - if (const auto m = App::main()) { // multi good - return m->insertBotCommand(cmd); - } - return false; -} - -void activateBotCommand( - not_null sessionController, - not_null msg, - int row, - int column) { - const auto button = HistoryMessageMarkupButton::Get( - &msg->history()->owner(), - msg->fullId(), - row, - column); - if (!button) { - return; - } - - using ButtonType = HistoryMessageMarkupButton::Type; - switch (button->type) { - case ButtonType::Default: { - // Copy string before passing it to the sending method - // because the original button can be destroyed inside. - const auto replyTo = msg->isRegular() ? msg->id : 0; - sessionController->content()->sendBotCommand({ - .peer = msg->history()->peer, - .command = QString(button->text), - .context = msg->fullId(), - .replyTo = replyTo, - }); - } break; - - case ButtonType::Callback: - case ButtonType::Game: { - Api::SendBotCallbackData( - sessionController, - const_cast(msg.get()), - row, - column); - } break; - - case ButtonType::CallbackWithPassword: { - Api::SendBotCallbackDataWithPassword( - sessionController, - const_cast(msg.get()), - row, - column); - } break; - - case ButtonType::Buy: { - Payments::CheckoutProcess::Start( - msg, - Payments::Mode::Payment, - crl::guard(sessionController, [=](auto) { - sessionController->widget()->activate(); - })); - } break; - - case ButtonType::Url: { - auto url = QString::fromUtf8(button->data); - auto skipConfirmation = false; - if (const auto bot = msg->getMessageBot()) { - if (bot->isVerified()) { - skipConfirmation = true; - } - } - const auto context = QVariant::fromValue(ClickHandlerContext{ - .sessionWindow = sessionController.get(), - }); - if (skipConfirmation) { - UrlClickHandler::Open(url, context); - } else { - HiddenUrlClickHandler::Open(url, context); - } - } break; - - case ButtonType::RequestLocation: { - hideSingleUseKeyboard(msg); - sessionController->show( - Ui::MakeInformBox(tr::lng_bot_share_location_unavailable())); - } break; - - case ButtonType::RequestPhone: { - hideSingleUseKeyboard(msg); - const auto msgId = msg->id; - const auto history = msg->history(); - sessionController->show(Ui::MakeConfirmBox({ - .text = tr::lng_bot_share_phone(), - .confirmed = [=] { - Ui::showPeerHistory(history, ShowAtTheEndMsgId); - auto action = Api::SendAction(history); - action.clearDraft = false; - action.replyTo = msgId; - history->session().api().shareContact( - history->session().user(), - action); - }, - .confirmText = tr::lng_bot_share_phone_confirm(), - })); - } break; - - case ButtonType::RequestPoll: { - hideSingleUseKeyboard(msg); - auto chosen = PollData::Flags(); - auto disabled = PollData::Flags(); - if (!button->data.isEmpty()) { - disabled |= PollData::Flag::Quiz; - if (button->data[0]) { - chosen |= PollData::Flag::Quiz; - } - } - if (const auto m = CheckMainWidget(&msg->history()->session())) { - const auto replyToId = MsgId(0); - Window::PeerMenuCreatePoll( - m->controller(), - msg->history()->peer, - replyToId, - chosen, - disabled); - } - } break; - - case ButtonType::SwitchInlineSame: - case ButtonType::SwitchInline: { - const auto session = &msg->history()->session(); - if (const auto m = CheckMainWidget(session)) { - if (const auto bot = msg->getMessageBot()) { - const auto fastSwitchDone = [&] { - auto samePeer = (button->type == ButtonType::SwitchInlineSame); - if (samePeer) { - Notify::switchInlineBotButtonReceived(session, QString::fromUtf8(button->data), bot, msg->id); - return true; - } else if (bot->isBot() && bot->botInfo->inlineReturnTo.key) { - if (Notify::switchInlineBotButtonReceived(session, QString::fromUtf8(button->data))) { - return true; - } - } - return false; - }(); - if (!fastSwitchDone) { - m->inlineSwitchLayer('@' + bot->username + ' ' + QString::fromUtf8(button->data)); - } - } - } - } break; - - case ButtonType::Auth: - UrlAuthBox::Activate(msg, row, column); - break; - - case ButtonType::UserProfile: { - const auto session = &msg->history()->session(); - const auto userId = UserId(button->data.toULongLong()); - if (const auto user = session->data().userLoaded(userId)) { - const auto &windows = session->windows(); - if (!windows.empty()) { - windows.front()->showPeerInfo(user); - } - } - } break; - - case ButtonType::WebView: { - if (const auto bot = msg->getMessageBot()) { - bot->session().attachWebView().request( - sessionController, - bot, - bot, - { .text = button->text, .url = button->data }); - } - } break; - - case ButtonType::SimpleWebView: { - if (const auto bot = msg->getMessageBot()) { - bot->session().attachWebView().requestSimple( - sessionController, - bot, - { .text = button->text, .url = button->data }); - } - } break; - } -} - -} // namespace App - namespace Ui { void showChatsList(not_null session) { @@ -285,21 +90,3 @@ bool skipPaintEvent(QWidget *widget, QPaintEvent *event) { } } // namespace Ui - -namespace Notify { - -bool switchInlineBotButtonReceived( - not_null session, - const QString &query, - UserData *samePeerBot, - MsgId samePeerReplyTo) { - if (const auto m = CheckMainWidget(session)) { - return m->notify_switchInlineBotButtonReceived( - query, - samePeerBot, - samePeerReplyTo); - } - return false; -} - -} // namespace Notify diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 5edcc152c..10c0e7fb4 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -34,13 +34,6 @@ template }; } -bool insertBotCommand(const QString &cmd); -void activateBotCommand( - not_null sessionController, - not_null msg, - int row, - int column); - } // namespace App namespace Ui { @@ -50,23 +43,7 @@ namespace Ui { void showPeerHistory(not_null peer, MsgId msgId); void showPeerHistory(not_null history, MsgId msgId); void showChatsList(not_null session); -PeerData *getPeerForMouseAction(); bool skipPaintEvent(QWidget *widget, QPaintEvent *event); } // namespace Ui - -enum ClipStopperType { - ClipStopperMediaview, - ClipStopperSavedGifsPanel, -}; - -namespace Notify { - -bool switchInlineBotButtonReceived( - not_null session, - const QString &query, - UserData *samePeerBot = nullptr, - MsgId samePeerReplyTo = 0); - -} // namespace Notify diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 0cc6185dd..005768aa4 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -3212,7 +3212,7 @@ void HistoryInner::elementSendBotCommand( } void HistoryInner::elementHandleViaClick(not_null bot) { - App::insertBotCommand('@' + bot->username); + _widget->insertBotCommand('@' + bot->username); } bool HistoryInner::elementIsChatWide() { diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 8379c4878..b5b99fd26 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -35,7 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_file_click_handler.h" #include "main/main_session.h" #include "window/window_session_controller.h" -#include "facades.h" +#include "api/api_bot.h" #include "styles/style_widgets.h" #include "styles/style_chat.h" @@ -54,26 +54,25 @@ void HistoryMessageVia::create( maxWidth = st::msgServiceNameFont->width( tr::lng_inline_bot_via(tr::now, lt_inline_bot, '@' + bot->username)); link = std::make_shared([bot = this->bot]( - ClickContext context) { - if (const auto window = App::wnd()) { - if (const auto controller = window->sessionController()) { - if (base::IsCtrlPressed()) { - controller->showPeerInfo(bot); - return; - } else if (!bot->isBot() - || bot->botInfo->inlinePlaceholder.isEmpty()) { - controller->showPeerHistory( - bot->id, - Window::SectionShow::Way::Forward); - return; - } + ClickContext context) { + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + if (base::IsCtrlPressed()) { + controller->showPeerInfo(bot); + return; + } else if (!bot->isBot() + || bot->botInfo->inlinePlaceholder.isEmpty()) { + controller->showPeerHistory( + bot->id, + Window::SectionShow::Way::Forward); + return; } } - const auto my = context.other.value(); - if (const auto delegate = my.elementDelegate ? my.elementDelegate() : nullptr) { + const auto delegate = my.elementDelegate + ? my.elementDelegate() + : nullptr; + if (delegate) { delegate->elementHandleViaClick(bot); - } else { - App::insertBotCommand('@' + bot->username); } }); } @@ -524,9 +523,11 @@ void ReplyMarkupClickHandler::onClick(ClickContext context) const { if (context.button != Qt::LeftButton) { return; } - if (const auto item = _owner->message(_itemId)) { - const auto my = context.other.value(); - App::activateBotCommand(my.sessionWindow.get(), item, _row, _column); + const auto my = context.other.value(); + if (const auto controller = my.sessionWindow.get()) { + if (const auto item = _owner->message(_itemId)) { + Api::ActivateBotCommand(controller, item, _row, _column); + } } } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 58d1f911b..d4eb57ae8 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -155,7 +155,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "support/support_preload.h" #include "dialogs/dialogs_key.h" #include "calls/calls_instance.h" -#include "facades.h" +#include "api/api_bot.h" #include "styles/style_chat.h" #include "styles/style_dialogs.h" #include "styles/style_window.h" @@ -359,10 +359,11 @@ HistoryWidget::HistoryWidget( initTabbedSelector(); - _attachToggle->addClickHandler(App::LambdaDelayed( - st::historyAttach.ripple.hideDuration, - this, - [=] { chooseAttach(); })); + _attachToggle->setClickedCallback([=] { + base::call_delayed(st::historyAttach.ripple.hideDuration, this, [=] { + chooseAttach(); + }); + }); const auto rawTextEdit = _field->rawTextEdit().get(); rpl::merge( @@ -1792,7 +1793,7 @@ bool HistoryWidget::notify_switchInlineBotButtonReceived(const QString &query, U if (history == _history) { applyDraft(); } else { - Ui::showPeerHistory(history->peer, ShowAtUnreadMsgId); + controller()->showPeerHistory(history->peer); } } return true; @@ -4207,7 +4208,9 @@ void HistoryWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) { } bool HistoryWidget::insertBotCommand(const QString &cmd) { - if (!canWriteMessage()) return false; + if (!canWriteMessage()) { + return false; + } auto insertingInlineBot = !cmd.isEmpty() && (cmd.at(0) == '@'); auto toInsert = cmd; @@ -6056,7 +6059,10 @@ void HistoryWidget::mousePressEvent(QMouseEvent *e) { optionsChanged, changeRecipient)); } else { - Ui::showPeerHistory(_peer, _editMsgId ? _editMsgId : replyToId()); + controller()->showPeerHistory( + _peer, + Window::SectionShow::Way::Forward, + _editMsgId ? _editMsgId : replyToId()); } } } @@ -6410,7 +6416,10 @@ void HistoryWidget::checkPinnedBarState() { ) | rpl::start_with_next([=] { const auto id = _pinnedTracker->currentMessageId(); if (const auto item = session().data().message(id.message)) { - Ui::showPeerHistory(item->history()->peer, item->id); + controller()->showPeerHistory( + item->history()->peer, + Window::SectionShow::Way::Forward, + item->id); if (const auto group = session().data().groups().find(item)) { // Hack for the case when a non-first item of an album // is pinned and we still want the 'show last after first'. @@ -6495,7 +6504,7 @@ void HistoryWidget::refreshPinnedBarButton(bool many, HistoryItem *item) { Ui::RoundButton::TextTransform::NoTransform); button->setFullRadius(true); button->setClickedCallback([=] { - App::activateBotCommand(controller(), item, 0, 0); + Api::ActivateBotCommand(controller(), item, 0, 0); }); if (button->width() > st::historyPinnedBotButtonMaxWidth) { button->setFullWidth(st::historyPinnedBotButtonMaxWidth); @@ -7806,10 +7815,8 @@ bool HistoryWidget::paintShowAnimationFrame() { } void HistoryWidget::paintEvent(QPaintEvent *e) { - if (paintShowAnimationFrame()) { - return; - } - if (Ui::skipPaintEvent(this, e)) { + if (paintShowAnimationFrame() + || controller()->window().widget()->contentOverlapped(this, e)) { return; } if (hasPendingResizedItems()) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index b66e8a70f..ff142da80 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -785,10 +785,6 @@ void MainWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) { _history->hideSingleUseKeyboard(peer, replyTo); } -bool MainWidget::insertBotCommand(const QString &cmd) { - return _history->insertBotCommand(cmd); -} - void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) { // #TODO windows if (!_dialogs) { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index df1315aa0..88a24119d 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -183,7 +183,6 @@ public: void sendBotCommand(Bot::SendCommandRequest request); void hideSingleUseKeyboard(PeerData *peer, MsgId replyTo); - bool insertBotCommand(const QString &cmd); void searchMessages(const QString &query, Dialogs::Key inChat);