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(
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)
, _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<PeerListRow*> row) {
auto ChooseRecipientBoxController::createRow(
not_null<History*> history) -> std::unique_ptr<Row> {
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<Row>(history);
}

View File

@ -173,7 +173,8 @@ class ChooseRecipientBoxController
public:
ChooseRecipientBoxController(
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;
void rowClicked(not_null<PeerListRow*> row) override;
@ -189,5 +190,6 @@ protected:
private:
const not_null<Main::Session*> _session;
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 "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<QString>()),
.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)

View File

@ -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<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() {
static auto result = base::flat_set<not_null<AttachWebView*>>();
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<Main::Session*> session)
: _session(session) {
}
@ -465,14 +521,18 @@ void AttachWebView::requestBots() {
void AttachWebView::requestAddToMenu(
PeerData *peer,
not_null<UserData*> 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<PeerData*> 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) },

View File

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

View File

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

View File

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