From 6454f67e74b9cdb6a1157a452b45460a42fcea48 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 3 Jun 2022 00:26:41 +0400 Subject: [PATCH] Support new attach bot deeplinks. --- .../boxes/peer_list_controllers.cpp | 12 ++- .../SourceFiles/boxes/peer_list_controllers.h | 4 +- .../SourceFiles/core/local_url_handlers.cpp | 3 + .../inline_bots/bot_attach_web_view.cpp | 88 +++++++++++++++++-- .../inline_bots/bot_attach_web_view.h | 7 +- .../window/window_session_controller.cpp | 4 +- .../window/window_session_controller.h | 3 + 7 files changed, 109 insertions(+), 12 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp index 4edf1738f..d17c6bac1 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.cpp @@ -480,10 +480,12 @@ std::unique_ptr ContactsBoxController::createRow( ChooseRecipientBoxController::ChooseRecipientBoxController( not_null session, - FnMut)> callback) + FnMut)> callback, + Fn)> filter) : ChatsListBoxController(session) , _session(session) -, _callback(std::move(callback)) { +, _callback(std::move(callback)) +, _filter(std::move(filter)) { } Main::Session &ChooseRecipientBoxController::session() const { @@ -506,7 +508,9 @@ void ChooseRecipientBoxController::rowClicked(not_null row) { auto ChooseRecipientBoxController::createRow( not_null history) -> std::unique_ptr { const auto peer = history->peer; - const auto skip = (peer->isBroadcast() && !peer->canWrite()) - || peer->isRepliesChat(); + const auto skip = _filter + ? !_filter(peer) + : ((peer->isBroadcast() && !peer->canWrite()) + || peer->isRepliesChat()); return skip ? nullptr : std::make_unique(history); } diff --git a/Telegram/SourceFiles/boxes/peer_list_controllers.h b/Telegram/SourceFiles/boxes/peer_list_controllers.h index 3422c5ad6..f8d580902 100644 --- a/Telegram/SourceFiles/boxes/peer_list_controllers.h +++ b/Telegram/SourceFiles/boxes/peer_list_controllers.h @@ -173,7 +173,8 @@ class ChooseRecipientBoxController public: ChooseRecipientBoxController( not_null session, - FnMut)> callback); + FnMut)> callback, + Fn)> filter = nullptr); Main::Session &session() const override; void rowClicked(not_null row) override; @@ -189,5 +190,6 @@ protected: private: const not_null _session; FnMut)> _callback; + Fn)> _filter; }; diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index c7a2dafcb..3e0a40f2b 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "mainwidget.h" #include "main/main_session.h" #include "main/main_session_settings.h" +#include "inline_bots/bot_attach_web_view.h" #include "history/history.h" #include "base/qt/qt_common_adapters.h" #include "apiwrap.h" @@ -387,6 +388,8 @@ bool ResolveUsernameOrPhone( .attachBotToggleCommand = (params.contains(u"startattach"_q) ? params.value(u"startattach"_q) : std::optional()), + .attachBotChooseTypes = InlineBots::ParseChooseTypes( + params.value(u"choose"_q)), .voicechatHash = (params.contains(u"livestream"_q) ? std::make_optional(params.value(u"livestream"_q)) : params.contains(u"videochat"_q) diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp index 1db3f2b0e..8409f72db 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp @@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "payments/payments_checkout_process.h" #include "storage/storage_account.h" +#include "boxes/peer_list_controllers.h" #include "lang/lang_keys.h" #include "base/random.h" #include "base/timer_rpl.h" @@ -114,6 +115,45 @@ struct ParsedBot { return result; } +void ShowChooseBox( + not_null controller, + PeerTypes types, + Fn)> callback) { + const auto weak = std::make_shared>(); + auto done = [=](not_null peer) mutable { + if (const auto strong = *weak) { + strong->closeBox(); + } + callback(peer); + }; + auto filter = [=](not_null peer) -> bool { + if (!peer->canWrite()) { + return false; + } else if (const auto user = peer->asUser()) { + if (user->isBot()) { + return (types & PeerType::Bot); + } else { + return (types & PeerType::User); + } + } else if (peer->isBroadcast()) { + return (types & PeerType::Broadcast); + } else { + return (types & PeerType::Group); + } + }; + auto initBox = [](not_null box) { + box->addButton(tr::lng_cancel(), [box] { + box->closeBox(); + }); + }; + *weak = controller->show(Box( + std::make_unique( + &controller->session(), + std::move(done), + std::move(filter)), + std::move(initBox)), Ui::LayerOption::KeepOther); +} + [[nodiscard]] base::flat_set> &ActiveWebViews() { static auto result = base::flat_set>(); return result; @@ -332,6 +372,22 @@ bool PeerMatchesTypes( return (types & PeerType::Group); } +PeerTypes ParseChooseTypes(const QString &choose) { + auto result = PeerTypes(); + for (const auto entry : choose.split(QChar(' '))) { + if (entry == "users") { + result |= PeerType::User; + } else if (entry == "bots") { + result |= PeerType::Bot; + } else if (entry == "groups") { + result |= PeerType::Group; + } else if (entry == "channels") { + result |= PeerType::Broadcast; + } + } + return result; +} + AttachWebView::AttachWebView(not_null session) : _session(session) { } @@ -465,14 +521,18 @@ void AttachWebView::requestBots() { void AttachWebView::requestAddToMenu( PeerData *peer, not_null bot, - const QString &startCommand) { + const QString &startCommand, + Window::SessionController *controller, + PeerTypes chooseTypes) { if (!bot->isBot() || !bot->botInfo->supportsAttachMenu) { Ui::ShowMultilineToast({ .text = { tr::lng_bot_menu_not_supported(tr::now) }, }); return; } + _addToMenuChooseController = base::make_weak(controller); _addToMenuStartCommand = startCommand; + _addToMenuChooseTypes = chooseTypes; _addToMenuPeer = peer; if (_addToMenuId) { if (_addToMenuBot == bot) { @@ -487,9 +547,24 @@ void AttachWebView::requestAddToMenu( _addToMenuId = 0; const auto bot = base::take(_addToMenuBot); const auto contextPeer = base::take(_addToMenuPeer); + const auto chooseTypes = base::take(_addToMenuChooseTypes); const auto startCommand = base::take(_addToMenuStartCommand); - const auto open = [=] { - if (!contextPeer) { + const auto chooseController = base::take(_addToMenuChooseController); + const auto open = [=](PeerTypes types) { + if (const auto useTypes = chooseTypes & types) { + if (const auto strong = chooseController.get()) { + const auto callback = [=](not_null peer) { + strong->showPeerHistory(peer); + request( + nullptr, + peer, + bot, + { .startCommand = startCommand }); + }; + ShowChooseBox(strong, useTypes, callback); + } + return true; + } else if (!contextPeer) { return false; } request( @@ -503,11 +578,14 @@ void AttachWebView::requestAddToMenu( _session->data().processUsers(data.vusers()); if (const auto parsed = ParseAttachBot(_session, data.vbot())) { if (bot == parsed->user) { + const auto types = parsed->types; if (parsed->inactive) { - confirmAddToMenu(*parsed, open); + confirmAddToMenu(*parsed, [=] { + open(types); + }); } else { requestBots(); - if (!open()) { + if (!open(types)) { Ui::ShowMultilineToast({ .text = { tr::lng_bot_menu_already_added(tr::now) }, diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h index 7a2094aac..90fd9beb8 100644 --- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h +++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h @@ -47,6 +47,7 @@ using PeerTypes = base::flags; not_null peer, not_null bot, PeerTypes types); +[[nodiscard]] PeerTypes ParseChooseTypes(const QString &choose); struct AttachWebViewBot { not_null user; @@ -97,7 +98,9 @@ public: void requestAddToMenu( PeerData *peer, not_null bot, - const QString &startCommand); + const QString &startCommand, + Window::SessionController *controller = nullptr, + PeerTypes chooseTypes = {}); void removeFromMenu(not_null bot); static void ClearAll(); @@ -147,6 +150,8 @@ private: UserData *_addToMenuBot = nullptr; mtpRequestId _addToMenuId = 0; QString _addToMenuStartCommand; + base::weak_ptr _addToMenuChooseController; + PeerTypes _addToMenuChooseTypes; std::vector _attachBots; rpl::event_stream<> _attachBotsUpdates; diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index f948a2554..39cddeba1 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -376,7 +376,9 @@ void SessionNavigation::showPeerByLinkResolved( bot->session().attachWebView().requestAddToMenu( contextUser, bot, - *info.attachBotToggleCommand); + *info.attachBotToggleCommand, + parentController(), + info.attachBotChooseTypes); } else { crl::on_main(this, [=] { showPeerHistory(peer->id, params, msgId); diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 8623ec7c9..812ba2898 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -39,6 +39,8 @@ class Session; namespace InlineBots { class AttachWebView; +enum class PeerType : uint8; +using PeerTypes = base::flags; } // namespace InlineBots namespace Calls { @@ -196,6 +198,7 @@ public: bool startAutoSubmit = false; QString attachBotUsername; std::optional attachBotToggleCommand; + InlineBots::PeerTypes attachBotChooseTypes; std::optional voicechatHash; FullMsgId clickFromMessageId; };