Update API scheme on layer 140.

This commit is contained in:
John Preston 2022-03-31 13:24:13 +04:00
parent 2aa293f1a5
commit b1e66279d5
7 changed files with 207 additions and 127 deletions

View file

@ -1336,7 +1336,11 @@ phone.groupCallStreamChannels#d0e482b2 channels:Vector<GroupCallStreamChannel> =
phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl;
attachMenuBot#4fdf05a8 flags:# inactive:flags.0?true bot_id:long attach_menu_name:string attach_menu_icon:Document = AttachMenuBot;
attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;
attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;
attachMenuBot#e93cb772 flags:# inactive:flags.0?true bot_id:long short_name:string icons:Vector<AttachMenuBotIcon> = AttachMenuBot;
attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;
@ -1344,7 +1348,6 @@ attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User>
attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot;
webViewResultUrl#c14557c query_id:long url:string = WebViewResult;
webViewResultConfirmationRequired#b1cad385 bot:AttachMenuBot users:Vector<User> = WebViewResult;
simpleWebViewResultUrl#882f76bb url:string = SimpleWebViewResult;
@ -1653,7 +1656,7 @@ messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = mes
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
messages.toggleBotInAttachMenu#1aee33af bot:InputUser enabled:Bool = Bool;
messages.requestWebView#2221fe98 flags:# silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string theme_params:flags.2?DataJSON reply_to_msg_id:flags.0?int = WebViewResult;
messages.requestWebView#fa04dff flags:# silent:flags.5?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON reply_to_msg_id:flags.0?int = WebViewResult;
messages.prolongWebView#d22ad148 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to_msg_id:flags.0?int = Bool;
messages.requestSimpleWebView#6abb2f73 flags:# bot:InputUser url:string theme_params:flags.0?DataJSON = SimpleWebViewResult;
messages.sendWebViewResultMessage#ddcf50eb query_id:long result:InputBotInlineResult = WebViewMessageSent;

View file

@ -362,7 +362,9 @@ bool ResolveUsernameOrPhone(
.startToken = startToken,
.startAdminRights = adminRights,
.attachBotUsername = params.value(u"attach"_q),
.attachBotToggle = params.contains(u"setattach"_q),
.attachBotToggleCommand = (params.contains(u"startattach"_q)
? params.value(u"startattach"_q)
: std::optional<QString>()),
.voicechatHash = (params.contains(u"livestream"_q)
? std::make_optional(params.value(u"livestream"_q))
: params.contains(u"videochat"_q)
@ -782,7 +784,8 @@ QString TryConvertUrlToLocal(QString url) {
if (telegramMeMatch) {
auto query = telegramMeMatch->capturedView(5);
if (auto phoneMatch = regex_match(qsl("^\\+([0-9]+)(\\?|$)"), query, matchOptions)) {
return qsl("tg://resolve?phone=") + phoneMatch->captured(1);
auto params = query.mid(phoneMatch->captured(0).size()).toString();
return qsl("tg://resolve?phone=") + phoneMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params);
} else if (auto joinChatMatch = regex_match(qsl("^(joinchat/|\\+|\\%20)([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) {
return qsl("tg://join?invite=") + url_encode(joinChatMatch->captured(2));
} else if (auto stickerSetMatch = regex_match(qsl("^addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) {

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "core/application.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "base/random.h"
#include "base/timer_rpl.h"
@ -46,6 +47,25 @@ struct ParsedBot {
bool inactive = false;
};
[[nodiscard]] DocumentData *ResolveIcon(
not_null<Main::Session*> session,
const MTPDattachMenuBot &data) {
for (const auto &icon : data.vicons().v) {
const auto document = icon.match([&](
const MTPDattachMenuBotIcon &data
) -> DocumentData* {
if (data.vname().v == "default_static") {
return session->data().processDocument(data.vicon()).get();
}
return nullptr;
});
if (document) {
return document;
}
}
return nullptr;
}
[[nodiscard]] std::optional<AttachWebViewBot> ParseAttachBot(
not_null<Main::Session*> session,
const MTPAttachMenuBot &bot) {
@ -57,13 +77,12 @@ struct ParsedBot {
return good
? AttachWebViewBot{
.user = user,
.icon = session->data().processDocument(
data.vattach_menu_icon()),
.name = qs(data.vattach_menu_name()),
.icon = ResolveIcon(session, data),
.name = qs(data.vshort_name()),
.inactive = data.is_inactive(),
} : std::optional<AttachWebViewBot>();
});
if (result) {
if (result && result->icon) {
result->icon->forceToCache(true);
}
return result;
@ -150,7 +169,7 @@ BotAction::BotAction(
void BotAction::validateIcon() {
if (_mask.isNull()) {
if (!_bot.media->loaded()) {
if (!_bot.media || !_bot.media->loaded()) {
return;
}
auto icon = QSvgRenderer(_bot.media->bytes());
@ -281,12 +300,15 @@ AttachWebView::~AttachWebView() {
void AttachWebView::request(
not_null<PeerData*> peer,
const QString &botUsername) {
const QString &botUsername,
const QString &startCommand) {
if (botUsername.isEmpty()) {
return;
}
const auto username = _bot ? _bot->username : _botUsername;
if (_peer == peer && username.toLower() == botUsername.toLower()) {
if (_peer == peer
&& username.toLower() == botUsername.toLower()
&& _startCommand == startCommand) {
if (_panel) {
_panel->requestActivate();
}
@ -296,6 +318,7 @@ void AttachWebView::request(
_peer = peer;
_botUsername = botUsername;
_startCommand = startCommand;
resolve();
}
@ -320,38 +343,30 @@ void AttachWebView::request(
void AttachWebView::request(const WebViewButton &button) {
Expects(_peer != nullptr && _bot != nullptr);
_startCommand = button.startCommand;
using Flag = MTPmessages_RequestWebView::Flag;
const auto flags = Flag::f_theme_params
| (button.url.isEmpty() ? Flag(0) : Flag::f_url);
| (button.url.isEmpty() ? Flag(0) : Flag::f_url)
| (_startCommand.isEmpty() ? Flag(0) : Flag::f_start_param);
_requestId = _session->api().request(MTPmessages_RequestWebView(
MTP_flags(flags),
_peer->input,
_bot->inputUser,
MTP_bytes(button.url),
MTP_string(_startCommand),
MTP_dataJSON(MTP_bytes(Window::Theme::WebViewParams())),
MTPint() // reply_to_msg_id
)).done([=](const MTPWebViewResult &result) {
_requestId = 0;
result.match([&](const MTPDwebViewResultUrl &data) {
show(data.vquery_id().v, qs(data.vurl()), button.text);
}, [&](const MTPDwebViewResultConfirmationRequired &data) {
_session->data().processUsers(data.vusers());
const auto &received = data.vbot();
if (const auto bot = ParseAttachBot(_session, received)) {
if (_bot != bot->user) {
cancel();
return;
}
confirmAddToMenu(*bot, [=] {
request(button);
});
} else {
cancel();
}
});
}).fail([=](const MTP::Error &error) {
_requestId = 0;
int a = error.code();
if (error.type() == u"BOT_INVALID"_q) {
requestBots();
}
}).send();
}
@ -362,6 +377,7 @@ void AttachWebView::cancel() {
_panel = nullptr;
_peer = _bot = nullptr;
_botUsername = QString();
_startCommand = QString();
}
void AttachWebView::requestBots() {
@ -381,8 +397,10 @@ void AttachWebView::requestBots() {
for (const auto &bot : data.vbots().v) {
if (auto parsed = ParseAttachBot(_session, bot)) {
if (!parsed->inactive) {
parsed->media = parsed->icon->createMediaView();
parsed->icon->save(Data::FileOrigin(), {});
if (const auto icon = parsed->icon) {
parsed->media = icon->createMediaView();
icon->save(Data::FileOrigin(), {});
}
_attachBots.push_back(std::move(*parsed));
}
}
@ -394,10 +412,19 @@ void AttachWebView::requestBots() {
}).send();
}
void AttachWebView::requestAddToMenu(not_null<UserData*> bot) {
void AttachWebView::requestAddToMenu(
PeerData *peer,
not_null<UserData*> bot,
const QString &startCommand) {
if (!bot->isBot() || !bot->botInfo->supportsAttachMenu) {
Ui::ShowMultilineToast({
.text = { tr::lng_bot_menu_not_supported(tr::now) },
});
return;
} else if (_addToMenuId) {
}
_addToMenuStartCommand = startCommand;
_addToMenuPeer = peer;
if (_addToMenuId) {
if (_addToMenuBot == bot) {
return;
}
@ -408,19 +435,30 @@ void AttachWebView::requestAddToMenu(not_null<UserData*> bot) {
bot->inputUser
)).done([=](const MTPAttachMenuBotsBot &result) {
_addToMenuId = 0;
const auto requested = base::take(_addToMenuBot);
const auto bot = base::take(_addToMenuBot);
const auto contextPeer = base::take(_addToMenuPeer);
const auto startCommand = base::take(_addToMenuStartCommand);
const auto open = [=] {
if (!contextPeer) {
return false;
}
request(contextPeer, bot, { .startCommand = startCommand });
return true;
};
result.match([&](const MTPDattachMenuBotsBot &data) {
_session->data().processUsers(data.vusers());
if (const auto bot = ParseAttachBot(_session, data.vbot())) {
if (requested == bot->user) {
if (bot->inactive) {
confirmAddToMenu(*bot);
if (const auto parsed = ParseAttachBot(_session, data.vbot())) {
if (bot == parsed->user) {
if (parsed->inactive) {
confirmAddToMenu(*parsed, open);
} else {
requestBots();
Ui::ShowMultilineToast({
.text = {
tr::lng_bot_menu_already_added(tr::now) },
});
if (!open()) {
Ui::ShowMultilineToast({
.text = {
tr::lng_bot_menu_already_added(tr::now) },
});
}
}
}
}
@ -428,6 +466,8 @@ void AttachWebView::requestAddToMenu(not_null<UserData*> bot) {
}).fail([=] {
_addToMenuId = 0;
_addToMenuBot = nullptr;
_addToMenuPeer = nullptr;
_addToMenuStartCommand = QString();
Ui::ShowMultilineToast({
.text = { tr::lng_bot_menu_not_supported(tr::now) },
});
@ -443,21 +483,15 @@ void AttachWebView::removeFromMenu(not_null<UserData*> bot) {
}
void AttachWebView::resolve() {
if (!_bot) {
requestByUsername();
}
}
void AttachWebView::requestByUsername() {
resolveUsername(_botUsername, [=](not_null<PeerData*> bot) {
_bot = bot->asUser();
if (!_bot || !_bot->isBot() || !_bot->botInfo->supportsAttachMenu) {
if (!_bot) {
Ui::ShowMultilineToast({
.text = { tr::lng_bot_menu_not_supported(tr::now) }
});
return;
}
request();
requestAddToMenu(_peer, _bot, _startCommand);
});
}
@ -652,7 +686,7 @@ std::unique_ptr<Ui::DropdownMenu> MakeAttachBotsMenu(
const auto callback = [=] {
const auto active = controller->activeChatCurrent();
if (const auto history = active.history()) {
bots->request(history->peer, bot.user);
bots->request(history->peer, bot.user, {});
}
};
auto action = base::make_unique_q<BotAction>(

View file

@ -35,7 +35,7 @@ namespace InlineBots {
struct AttachWebViewBot {
not_null<UserData*> user;
not_null<DocumentData*> icon;
DocumentData *icon = nullptr;
std::shared_ptr<Data::DocumentMedia> media;
QString name;
bool inactive = false;
@ -48,13 +48,17 @@ public:
struct WebViewButton {
QString text;
QString startCommand;
QByteArray url;
};
void request(not_null<PeerData*> peer, const QString &botUsername);
void request(
not_null<PeerData*> peer,
const QString &botUsername,
const QString &startCommand);
void request(
not_null<PeerData*> peer,
not_null<UserData*> bot,
const WebViewButton &button = WebViewButton());
const WebViewButton &button);
void requestSimple(
not_null<UserData*> bot,
const WebViewButton &button);
@ -69,15 +73,17 @@ public:
return _attachBotsUpdates.events();
}
void requestAddToMenu(not_null<UserData*> bot);
void requestAddToMenu(
PeerData *peer,
not_null<UserData*> bot,
const QString &startCommand);
void removeFromMenu(not_null<UserData*> bot);
static void ClearAll();
private:
void resolve();
void request(const WebViewButton &button = WebViewButton());
void requestByUsername();
void request(const WebViewButton &button);
void resolveUsername(
const QString &username,
Fn<void(not_null<PeerData*>)> done);
@ -101,6 +107,7 @@ private:
PeerData *_peer = nullptr;
UserData *_bot = nullptr;
QString _botUsername;
QString _startCommand;
QPointer<Ui::GenericBox> _confirmAddBox;
MsgId _replyToMsgId;
@ -110,8 +117,10 @@ private:
uint64 _botsHash = 0;
mtpRequestId _botsRequestId = 0;
PeerData *_addToMenuPeer = nullptr;
UserData *_addToMenuBot = nullptr;
mtpRequestId _addToMenuId = 0;
QString _addToMenuStartCommand;
std::vector<AttachWebViewBot> _attachBots;
rpl::event_stream<> _attachBotsUpdates;

View file

@ -311,9 +311,9 @@ bool Panel::createWebview() {
}
const auto list = message.array();
const auto command = list.at(0).toString();
if (command == "webview_close") {
if (command == "web_app_close") {
_close();
} else if (command == "webview_data_send") {
} else if (command == "web_app_data_send") {
auto error = QJsonParseError();
auto json = list.at(1).toString();
const auto dictionary = QJsonDocument::fromJson(

View file

@ -295,50 +295,12 @@ void SessionNavigation::showPeerByLinkResolved(
});
// Then try to join the voice chat.
const auto bad = [=] {
Ui::ShowMultilineToast({
.text = { tr::lng_group_invite_bad_link(tr::now) }
});
};
const auto hash = *info.voicechatHash;
_api.request(base::take(_resolveRequestId)).cancel();
_resolveRequestId = _api.request(
MTPchannels_GetFullChannel(peer->asChannel()->inputChannel)
).done([=](const MTPmessages_ChatFull &result) {
_session->api().processFullPeer(peer, result);
const auto call = peer->groupCall();
if (!call) {
bad();
return;
}
const auto join = [=] {
parentController()->startOrJoinGroupCall(
peer,
{ hash, Calls::StartGroupCallArgs::JoinConfirm::Always });
};
if (call->loaded()) {
join();
return;
}
const auto id = call->id();
const auto limit = 5;
_resolveRequestId = _api.request(
MTPphone_GetGroupCall(call->input(), MTP_int(limit))
).done([=](const MTPphone_GroupCall &result) {
if (const auto now = peer->groupCall()
; now && now->id() == id) {
if (!now->loaded()) {
now->processFullCall(result);
}
join();
} else {
bad();
}
}).fail(bad).send();
}).send();
joinVoiceChatFromLink(peer, info);
return;
}
using Scope = AddBotToGroupBoxController::Scope;
const auto user = peer->asUser();
const auto bot = (user && user->isBot()) ? user : nullptr;
const auto &replies = info.repliesInfo;
if (const auto threadId = std::get_if<ThreadId>(&replies)) {
showRepliesForMessage(
@ -352,8 +314,10 @@ void SessionNavigation::showPeerByLinkResolved(
info.messageId,
commentId->id,
params);
} else if (info.messageId == ShowAtProfileMsgId && !peer->isChannel()) {
const auto user = peer->asUser();
} else if (bot
&& (info.startType == BotStartType::Group
|| info.startType == BotStartType::Channel
|| info.startType == BotStartType::ShareGame)) {
const auto scope = (info.startType == BotStartType::ShareGame)
? Scope::ShareGame
: (info.startType == BotStartType::Group)
@ -361,47 +325,111 @@ void SessionNavigation::showPeerByLinkResolved(
: (info.startType == BotStartType::Channel)
? Scope::ChannelAdmin
: Scope::None;
if (!user || !user->isBot()) {
showPeerInfo(peer, params);
} else if (scope != Scope::None) {
AddBotToGroupBoxController::Start(
user,
scope,
info.startToken,
info.startAdminRights);
} else {
Assert(scope != Scope::None);
AddBotToGroupBoxController::Start(
bot,
scope,
info.startToken,
info.startAdminRights);
} else if (info.messageId == ShowAtProfileMsgId) {
if (bot) {
// Always open bot chats, even from mention links.
crl::on_main(this, [=] {
showPeerHistory(peer->id, params);
showPeerHistory(bot->id, params);
});
} else {
showPeerInfo(peer, params);
}
} else {
const auto user = peer->asUser();
auto msgId = info.messageId;
if (msgId == ShowAtProfileMsgId || !peer->isChannel()) {
// Show specific posts only in channels / supergroups.
msgId = ShowAtUnreadMsgId;
}
// Show specific posts only in channels / supergroups.
const auto msgId = peer->isChannel()
? info.messageId
: ShowAtUnreadMsgId;
const auto attachBotUsername = info.attachBotUsername;
if (user
&& user->isBot()
&& user->botInfo->startToken != info.startToken) {
user->botInfo->startToken = info.startToken;
user->session().changes().peerUpdated(
user,
if (bot && bot->botInfo->startToken != info.startToken) {
bot->botInfo->startToken = info.startToken;
bot->session().changes().peerUpdated(
bot,
Data::PeerUpdate::Flag::BotStartToken);
}
if (user && info.attachBotToggle) {
user->session().attachWebView().requestAddToMenu(user);
if (!attachBotUsername.isEmpty()) {
crl::on_main(this, [=] {
showPeerHistory(peer->id, params, msgId);
peer->session().attachWebView().request(
peer,
attachBotUsername,
info.attachBotToggleCommand.value_or(QString()));
});
} else if (bot && info.attachBotToggleCommand) {
const auto itemId = info.clickFromMessageId;
const auto item = _session->data().message(itemId);
const auto contextPeer = item
? item->history()->peer.get()
: nullptr;
const auto contextUser = contextPeer
? contextPeer->asUser()
: nullptr;
bot->session().attachWebView().requestAddToMenu(
contextUser,
bot,
*info.attachBotToggleCommand);
} else {
crl::on_main(this, [=] {
showPeerHistory(peer->id, params, msgId);
peer->session().attachWebView().request(peer, attachBotUsername);
});
}
}
}
void SessionNavigation::joinVoiceChatFromLink(
not_null<PeerData*> peer,
const PeerByLinkInfo &info) {
Expects(info.voicechatHash.has_value());
const auto bad = [=] {
Ui::ShowMultilineToast({
.text = { tr::lng_group_invite_bad_link(tr::now) }
});
};
const auto hash = *info.voicechatHash;
_api.request(base::take(_resolveRequestId)).cancel();
_resolveRequestId = _api.request(
MTPchannels_GetFullChannel(peer->asChannel()->inputChannel)
).done([=](const MTPmessages_ChatFull &result) {
_session->api().processFullPeer(peer, result);
const auto call = peer->groupCall();
if (!call) {
bad();
return;
}
const auto join = [=] {
parentController()->startOrJoinGroupCall(
peer,
{ hash, Calls::StartGroupCallArgs::JoinConfirm::Always });
};
if (call->loaded()) {
join();
return;
}
const auto id = call->id();
const auto limit = 5;
_resolveRequestId = _api.request(
MTPphone_GetGroupCall(call->input(), MTP_int(limit))
).done([=](const MTPphone_GroupCall &result) {
if (const auto now = peer->groupCall()
; now && now->id() == id) {
if (!now->loaded()) {
now->processFullCall(result);
}
join();
} else {
bad();
}
}).fail(bad).send();
}).send();
}
void SessionNavigation::showRepliesForMessage(
not_null<History*> history,
MsgId rootId,

View file

@ -196,7 +196,7 @@ public:
QString startToken;
ChatAdminRights startAdminRights;
QString attachBotUsername;
bool attachBotToggle = false;
std::optional<QString> attachBotToggleCommand;
std::optional<QString> voicechatHash;
FullMsgId clickFromMessageId;
};
@ -267,6 +267,9 @@ private:
void showPeerByLinkResolved(
not_null<PeerData*> peer,
const PeerByLinkInfo &info);
void joinVoiceChatFromLink(
not_null<PeerData*> peer,
const PeerByLinkInfo &info);
const not_null<Main::Session*> _session;