Support new attach bot deeplinks.

This commit is contained in:
John Preston 2022-06-03 00:26:41 +04:00
parent 092474fdb9
commit 6454f67e74
7 changed files with 109 additions and 12 deletions

View file

@ -480,10 +480,12 @@ std::unique_ptr<PeerListRow> ContactsBoxController::createRow(
ChooseRecipientBoxController::ChooseRecipientBoxController( ChooseRecipientBoxController::ChooseRecipientBoxController(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FnMut<void(not_null<PeerData*>)> callback) FnMut<void(not_null<PeerData*>)> callback,
Fn<bool(not_null<PeerData*>)> filter)
: ChatsListBoxController(session) : ChatsListBoxController(session)
, _session(session) , _session(session)
, _callback(std::move(callback)) { , _callback(std::move(callback))
, _filter(std::move(filter)) {
} }
Main::Session &ChooseRecipientBoxController::session() const { Main::Session &ChooseRecipientBoxController::session() const {
@ -506,7 +508,9 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
auto ChooseRecipientBoxController::createRow( auto ChooseRecipientBoxController::createRow(
not_null<History*> history) -> std::unique_ptr<Row> { not_null<History*> history) -> std::unique_ptr<Row> {
const auto peer = history->peer; const auto peer = history->peer;
const auto skip = (peer->isBroadcast() && !peer->canWrite()) const auto skip = _filter
|| peer->isRepliesChat(); ? !_filter(peer)
: ((peer->isBroadcast() && !peer->canWrite())
|| peer->isRepliesChat());
return skip ? nullptr : std::make_unique<Row>(history); return skip ? nullptr : std::make_unique<Row>(history);
} }

View file

@ -173,7 +173,8 @@ class ChooseRecipientBoxController
public: public:
ChooseRecipientBoxController( ChooseRecipientBoxController(
not_null<Main::Session*> session, not_null<Main::Session*> session,
FnMut<void(not_null<PeerData*>)> callback); FnMut<void(not_null<PeerData*>)> callback,
Fn<bool(not_null<PeerData*>)> filter = nullptr);
Main::Session &session() const override; Main::Session &session() const override;
void rowClicked(not_null<PeerListRow*> row) override; void rowClicked(not_null<PeerListRow*> row) override;
@ -189,5 +190,6 @@ protected:
private: private:
const not_null<Main::Session*> _session; const not_null<Main::Session*> _session;
FnMut<void(not_null<PeerData*>)> _callback; FnMut<void(not_null<PeerData*>)> _callback;
Fn<bool(not_null<PeerData*>)> _filter;
}; };

View file

@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mainwidget.h" #include "mainwidget.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_session_settings.h" #include "main/main_session_settings.h"
#include "inline_bots/bot_attach_web_view.h"
#include "history/history.h" #include "history/history.h"
#include "base/qt/qt_common_adapters.h" #include "base/qt/qt_common_adapters.h"
#include "apiwrap.h" #include "apiwrap.h"
@ -387,6 +388,8 @@ bool ResolveUsernameOrPhone(
.attachBotToggleCommand = (params.contains(u"startattach"_q) .attachBotToggleCommand = (params.contains(u"startattach"_q)
? params.value(u"startattach"_q) ? params.value(u"startattach"_q)
: std::optional<QString>()), : std::optional<QString>()),
.attachBotChooseTypes = InlineBots::ParseChooseTypes(
params.value(u"choose"_q)),
.voicechatHash = (params.contains(u"livestream"_q) .voicechatHash = (params.contains(u"livestream"_q)
? std::make_optional(params.value(u"livestream"_q)) ? std::make_optional(params.value(u"livestream"_q))
: params.contains(u"videochat"_q) : params.contains(u"videochat"_q)

View file

@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_item.h" #include "history/history_item.h"
#include "payments/payments_checkout_process.h" #include "payments/payments_checkout_process.h"
#include "storage/storage_account.h" #include "storage/storage_account.h"
#include "boxes/peer_list_controllers.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "base/random.h" #include "base/random.h"
#include "base/timer_rpl.h" #include "base/timer_rpl.h"
@ -114,6 +115,45 @@ struct ParsedBot {
return result; return result;
} }
void ShowChooseBox(
not_null<Window::SessionController*> controller,
PeerTypes types,
Fn<void(not_null<PeerData*>)> callback) {
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
auto done = [=](not_null<PeerData*> peer) mutable {
if (const auto strong = *weak) {
strong->closeBox();
}
callback(peer);
};
auto filter = [=](not_null<PeerData*> 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<PeerListBox*> box) {
box->addButton(tr::lng_cancel(), [box] {
box->closeBox();
});
};
*weak = controller->show(Box<PeerListBox>(
std::make_unique<ChooseRecipientBoxController>(
&controller->session(),
std::move(done),
std::move(filter)),
std::move(initBox)), Ui::LayerOption::KeepOther);
}
[[nodiscard]] base::flat_set<not_null<AttachWebView*>> &ActiveWebViews() { [[nodiscard]] base::flat_set<not_null<AttachWebView*>> &ActiveWebViews() {
static auto result = base::flat_set<not_null<AttachWebView*>>(); static auto result = base::flat_set<not_null<AttachWebView*>>();
return result; return result;
@ -332,6 +372,22 @@ bool PeerMatchesTypes(
return (types & PeerType::Group); 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<Main::Session*> session) AttachWebView::AttachWebView(not_null<Main::Session*> session)
: _session(session) { : _session(session) {
} }
@ -465,14 +521,18 @@ void AttachWebView::requestBots() {
void AttachWebView::requestAddToMenu( void AttachWebView::requestAddToMenu(
PeerData *peer, PeerData *peer,
not_null<UserData*> bot, not_null<UserData*> bot,
const QString &startCommand) { const QString &startCommand,
Window::SessionController *controller,
PeerTypes chooseTypes) {
if (!bot->isBot() || !bot->botInfo->supportsAttachMenu) { if (!bot->isBot() || !bot->botInfo->supportsAttachMenu) {
Ui::ShowMultilineToast({ Ui::ShowMultilineToast({
.text = { tr::lng_bot_menu_not_supported(tr::now) }, .text = { tr::lng_bot_menu_not_supported(tr::now) },
}); });
return; return;
} }
_addToMenuChooseController = base::make_weak(controller);
_addToMenuStartCommand = startCommand; _addToMenuStartCommand = startCommand;
_addToMenuChooseTypes = chooseTypes;
_addToMenuPeer = peer; _addToMenuPeer = peer;
if (_addToMenuId) { if (_addToMenuId) {
if (_addToMenuBot == bot) { if (_addToMenuBot == bot) {
@ -487,9 +547,24 @@ void AttachWebView::requestAddToMenu(
_addToMenuId = 0; _addToMenuId = 0;
const auto bot = base::take(_addToMenuBot); const auto bot = base::take(_addToMenuBot);
const auto contextPeer = base::take(_addToMenuPeer); const auto contextPeer = base::take(_addToMenuPeer);
const auto chooseTypes = base::take(_addToMenuChooseTypes);
const auto startCommand = base::take(_addToMenuStartCommand); const auto startCommand = base::take(_addToMenuStartCommand);
const auto open = [=] { const auto chooseController = base::take(_addToMenuChooseController);
if (!contextPeer) { const auto open = [=](PeerTypes types) {
if (const auto useTypes = chooseTypes & types) {
if (const auto strong = chooseController.get()) {
const auto callback = [=](not_null<PeerData*> peer) {
strong->showPeerHistory(peer);
request(
nullptr,
peer,
bot,
{ .startCommand = startCommand });
};
ShowChooseBox(strong, useTypes, callback);
}
return true;
} else if (!contextPeer) {
return false; return false;
} }
request( request(
@ -503,11 +578,14 @@ void AttachWebView::requestAddToMenu(
_session->data().processUsers(data.vusers()); _session->data().processUsers(data.vusers());
if (const auto parsed = ParseAttachBot(_session, data.vbot())) { if (const auto parsed = ParseAttachBot(_session, data.vbot())) {
if (bot == parsed->user) { if (bot == parsed->user) {
const auto types = parsed->types;
if (parsed->inactive) { if (parsed->inactive) {
confirmAddToMenu(*parsed, open); confirmAddToMenu(*parsed, [=] {
open(types);
});
} else { } else {
requestBots(); requestBots();
if (!open()) { if (!open(types)) {
Ui::ShowMultilineToast({ Ui::ShowMultilineToast({
.text = { .text = {
tr::lng_bot_menu_already_added(tr::now) }, tr::lng_bot_menu_already_added(tr::now) },

View file

@ -47,6 +47,7 @@ using PeerTypes = base::flags<PeerType>;
not_null<PeerData*> peer, not_null<PeerData*> peer,
not_null<UserData*> bot, not_null<UserData*> bot,
PeerTypes types); PeerTypes types);
[[nodiscard]] PeerTypes ParseChooseTypes(const QString &choose);
struct AttachWebViewBot { struct AttachWebViewBot {
not_null<UserData*> user; not_null<UserData*> user;
@ -97,7 +98,9 @@ public:
void requestAddToMenu( void requestAddToMenu(
PeerData *peer, PeerData *peer,
not_null<UserData*> bot, not_null<UserData*> bot,
const QString &startCommand); const QString &startCommand,
Window::SessionController *controller = nullptr,
PeerTypes chooseTypes = {});
void removeFromMenu(not_null<UserData*> bot); void removeFromMenu(not_null<UserData*> bot);
static void ClearAll(); static void ClearAll();
@ -147,6 +150,8 @@ private:
UserData *_addToMenuBot = nullptr; UserData *_addToMenuBot = nullptr;
mtpRequestId _addToMenuId = 0; mtpRequestId _addToMenuId = 0;
QString _addToMenuStartCommand; QString _addToMenuStartCommand;
base::weak_ptr<Window::SessionController> _addToMenuChooseController;
PeerTypes _addToMenuChooseTypes;
std::vector<AttachWebViewBot> _attachBots; std::vector<AttachWebViewBot> _attachBots;
rpl::event_stream<> _attachBotsUpdates; rpl::event_stream<> _attachBotsUpdates;

View file

@ -376,7 +376,9 @@ void SessionNavigation::showPeerByLinkResolved(
bot->session().attachWebView().requestAddToMenu( bot->session().attachWebView().requestAddToMenu(
contextUser, contextUser,
bot, bot,
*info.attachBotToggleCommand); *info.attachBotToggleCommand,
parentController(),
info.attachBotChooseTypes);
} else { } else {
crl::on_main(this, [=] { crl::on_main(this, [=] {
showPeerHistory(peer->id, params, msgId); showPeerHistory(peer->id, params, msgId);

View file

@ -39,6 +39,8 @@ class Session;
namespace InlineBots { namespace InlineBots {
class AttachWebView; class AttachWebView;
enum class PeerType : uint8;
using PeerTypes = base::flags<PeerType>;
} // namespace InlineBots } // namespace InlineBots
namespace Calls { namespace Calls {
@ -196,6 +198,7 @@ public:
bool startAutoSubmit = false; bool startAutoSubmit = false;
QString attachBotUsername; QString attachBotUsername;
std::optional<QString> attachBotToggleCommand; std::optional<QString> attachBotToggleCommand;
InlineBots::PeerTypes attachBotChooseTypes;
std::optional<QString> voicechatHash; std::optional<QString> voicechatHash;
FullMsgId clickFromMessageId; FullMsgId clickFromMessageId;
}; };