mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/telegramdesktop/tdesktop
synced 2026-09-21 00:23:56 +08:00
show() can hand back an already empty pointer, and subscribing to boxClosing() through it dereferenced null. That event has also already passed by then, so the decline request has to be sent right away instead.
690 lines
21 KiB
C++
690 lines
21 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#include "boxes/url_auth_box.h"
|
|
|
|
#include "apiwrap.h"
|
|
#include "boxes/url_auth_box_content.h"
|
|
#include "chat_helpers/stickers_emoji_pack.h"
|
|
#include "core/application.h"
|
|
#include "core/click_handler_types.h"
|
|
#include "data/data_peer.h"
|
|
#include "data/data_session.h"
|
|
#include "data/stickers/data_custom_emoji.h"
|
|
#include "data/data_user.h"
|
|
#include "history/history_item_components.h"
|
|
#include "history/history_item.h"
|
|
#include "history/history.h"
|
|
#include "info/profile/info_profile_values.h"
|
|
#include "lang/lang_keys.h"
|
|
#include "main/main_account.h"
|
|
#include "main/main_domain.h"
|
|
#include "main/main_session.h"
|
|
#include "ui/boxes/confirm_box.h"
|
|
#include "ui/controls/userpic_button.h"
|
|
#include "ui/dynamic_thumbnails.h"
|
|
#include "ui/emoji_config.h"
|
|
#include "ui/layers/generic_box.h"
|
|
#include "ui/toast/toast.h"
|
|
#include "ui/widgets/menu/menu_action.h"
|
|
#include "ui/widgets/popup_menu.h"
|
|
#include "ui/widgets/shadow.h"
|
|
#include "styles/style_userpic_button.h"
|
|
#include "styles/style_window.h"
|
|
|
|
namespace UrlAuthBox {
|
|
namespace {
|
|
|
|
using AnotherSessionFactory = Fn<not_null<Main::Session*>()>;
|
|
using OnUserChangedCallback = Fn<void(Fn<void()>)>;
|
|
|
|
struct SwitchAccountResult {
|
|
Ui::RpWidget *widget = nullptr;
|
|
AnotherSessionFactory anotherSession;
|
|
OnUserChangedCallback setOnUserChanged;
|
|
Fn<void(UserId)> updateUserIdHint;
|
|
};
|
|
|
|
[[nodiscard]] std::shared_ptr<Ui::DynamicImage> MakeMatchCodeImage(
|
|
not_null<Main::Session*> session,
|
|
const QString &code) {
|
|
auto emojiLength = 0;
|
|
const auto emoji = Ui::Emoji::Find(code, &emojiLength);
|
|
if (!emoji || emojiLength != code.size()) {
|
|
return nullptr;
|
|
}
|
|
const auto makeFor = [&](not_null<Main::Session*> source) {
|
|
if (const auto sticker = source->emojiStickersPack()
|
|
.stickerForEmoji(emoji)) {
|
|
return Ui::MakeEmojiThumbnail(
|
|
&source->data(),
|
|
Data::SerializeCustomEmojiId(sticker.document),
|
|
nullptr,
|
|
nullptr,
|
|
1);
|
|
}
|
|
return std::shared_ptr<Ui::DynamicImage>();
|
|
};
|
|
if (session->isTestMode()) {
|
|
for (const auto &account : Core::App().domain().orderedAccounts()) {
|
|
if (!account->sessionExists()
|
|
|| account->session().isTestMode()) {
|
|
continue;
|
|
}
|
|
if (const auto image = makeFor(&account->session())) {
|
|
return image;
|
|
}
|
|
}
|
|
}
|
|
return makeFor(session);
|
|
}
|
|
|
|
[[nodiscard]] SwitchAccountResult AddAccountsMenu(
|
|
not_null<Ui::RpWidget*> parent,
|
|
UserId userIdHint = UserId()) {
|
|
const auto session = &Core::App().domain().active().session();
|
|
const auto widget = Ui::CreateChild<SwitchableUserpicButton>(parent);
|
|
struct State {
|
|
base::unique_qptr<Ui::PopupMenu> menu;
|
|
UserData *currentUser = nullptr;
|
|
Fn<void()> onUserChanged;
|
|
};
|
|
const auto state = widget->lifetime().make_state<State>();
|
|
|
|
const auto isCurrentTest = session->isTestMode();
|
|
const auto findHintedUser = [&]() -> UserData* {
|
|
if (!userIdHint) {
|
|
return session->user().get();
|
|
}
|
|
for (const auto &account : Core::App().domain().orderedAccounts()) {
|
|
if (!account->sessionExists()
|
|
|| (account->session().isTestMode() != isCurrentTest)) {
|
|
continue;
|
|
}
|
|
if (account->session().userId() == userIdHint) {
|
|
return account->session().user();
|
|
}
|
|
}
|
|
return session->user().get();
|
|
};
|
|
|
|
state->currentUser = findHintedUser();
|
|
const auto userpic = Ui::CreateChild<Ui::UserpicButton>(
|
|
parent,
|
|
state->currentUser,
|
|
st::restoreUserpicIcon);
|
|
widget->setUserpic(userpic);
|
|
const auto filtered = [=] {
|
|
auto result = std::vector<not_null<Main::Session*>>();
|
|
for (const auto &account : Core::App().domain().orderedAccounts()) {
|
|
if (!account->sessionExists()
|
|
|| (account->session().user() == state->currentUser)
|
|
|| (account->session().isTestMode() != isCurrentTest)) {
|
|
continue;
|
|
}
|
|
result.push_back(&account->session());
|
|
}
|
|
return result;
|
|
};
|
|
const auto isSingle = filtered().empty();
|
|
widget->setExpanded(!isSingle);
|
|
widget->setAttribute(Qt::WA_TransparentForMouseEvents, isSingle);
|
|
widget->setClickedCallback([=] {
|
|
const auto &st = st::popupMenuWithIcons;
|
|
state->menu = base::make_unique_q<Ui::PopupMenu>(widget, st);
|
|
for (const auto &anotherSession : filtered()) {
|
|
const auto user = anotherSession->user();
|
|
const auto action = new QAction(user->name(), state->menu);
|
|
QObject::connect(action, &QAction::triggered, [=] {
|
|
state->currentUser = user;
|
|
const auto newUserpic = Ui::CreateChild<Ui::UserpicButton>(
|
|
parent,
|
|
user,
|
|
st::restoreUserpicIcon);
|
|
widget->setUserpic(newUserpic);
|
|
if (state->onUserChanged) {
|
|
state->onUserChanged();
|
|
}
|
|
});
|
|
auto owned = base::make_unique_q<Ui::Menu::Action>(
|
|
state->menu->menu(),
|
|
state->menu->menu()->st(),
|
|
action,
|
|
nullptr,
|
|
nullptr);
|
|
const auto menuUserpic = Ui::CreateChild<Ui::UserpicButton>(
|
|
owned.get(),
|
|
user,
|
|
st::lockSetupEmailUserpicSmall);
|
|
menuUserpic->setAttribute(Qt::WA_TransparentForMouseEvents);
|
|
menuUserpic->move(st.menu.itemIconPosition);
|
|
state->menu->addAction(std::move(owned));
|
|
}
|
|
|
|
state->menu->setForcedOrigin(Ui::PanelAnimation::Origin::TopRight);
|
|
state->menu->popup(
|
|
widget->mapToGlobal(
|
|
QPoint(
|
|
widget->width()
|
|
+ Ui::BoxShadow::ExtendFor(st.shadow).right(),
|
|
widget->height())));
|
|
});
|
|
return {
|
|
widget,
|
|
[=] { return &state->currentUser->session(); },
|
|
[=](Fn<void()> callback) { state->onUserChanged = callback; },
|
|
[=](UserId newUserIdHint) {
|
|
const auto isCurrentTest = session->isTestMode();
|
|
for (const auto &acc : Core::App().domain().orderedAccounts()) {
|
|
if (!acc->sessionExists()
|
|
|| (acc->session().isTestMode() != isCurrentTest)) {
|
|
continue;
|
|
}
|
|
if (acc->session().userId() == newUserIdHint) {
|
|
state->currentUser = acc->session().user();
|
|
const auto next = Ui::CreateChild<Ui::UserpicButton>(
|
|
parent,
|
|
state->currentUser,
|
|
st::restoreUserpicIcon);
|
|
widget->setUserpic(next);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
};
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void RequestButton(
|
|
std::shared_ptr<Ui::Show> show,
|
|
const MTPDurlAuthResultRequest &request,
|
|
not_null<const HistoryItem*> message,
|
|
Api::BotButtonLookup lookup);
|
|
void RequestUrl(
|
|
std::shared_ptr<Ui::Show> show,
|
|
const MTPDurlAuthResultRequest &request,
|
|
not_null<Main::Session*> session,
|
|
const QString &url,
|
|
QVariant context);
|
|
|
|
void ActivateButton(
|
|
std::shared_ptr<Ui::Show> show,
|
|
not_null<const HistoryItem*> message,
|
|
Api::BotButtonLookup lookup) {
|
|
const auto itemId = message->fullId();
|
|
const auto button = lookup();
|
|
if (!button || button->requestId || !message->isRegular()) {
|
|
return;
|
|
}
|
|
const auto session = &message->history()->session();
|
|
const auto inputPeer = message->history()->peer->input();
|
|
const auto buttonId = button->buttonId;
|
|
const auto url = QString::fromUtf8(button->data);
|
|
|
|
using Flag = MTPmessages_RequestUrlAuth::Flag;
|
|
button->requestId = session->api().request(MTPmessages_RequestUrlAuth(
|
|
MTP_flags(Flag::f_peer | Flag::f_msg_id | Flag::f_button_id),
|
|
inputPeer,
|
|
MTP_int(itemId.msg),
|
|
MTP_int(buttonId),
|
|
MTPstring(), // #TODO auth url
|
|
MTPstring() // in_app_origin
|
|
)).done([=](const MTPUrlAuthResult &result) {
|
|
const auto button = lookup();
|
|
if (!button) {
|
|
return;
|
|
}
|
|
|
|
button->requestId = 0;
|
|
result.match([&](const MTPDurlAuthResultAccepted &data) {
|
|
if (const auto url = data.vurl()) {
|
|
UrlClickHandler::Open(qs(url->v));
|
|
}
|
|
}, [&](const MTPDurlAuthResultDefault &data) {
|
|
HiddenUrlClickHandler::Open(url);
|
|
}, [&](const MTPDurlAuthResultRequest &data) {
|
|
if (const auto item = session->data().message(itemId)) {
|
|
RequestButton(show, data, item, lookup);
|
|
}
|
|
});
|
|
}).fail([=] {
|
|
const auto button = lookup();
|
|
if (!button) {
|
|
return;
|
|
}
|
|
|
|
button->requestId = 0;
|
|
HiddenUrlClickHandler::Open(url);
|
|
}).send();
|
|
}
|
|
|
|
void ActivateUrl(
|
|
std::shared_ptr<Ui::Show> show,
|
|
not_null<Main::Session*> session,
|
|
const QString &url,
|
|
QVariant context) {
|
|
context = QVariant::fromValue([&] {
|
|
auto result = context.value<ClickHandlerContext>();
|
|
result.skipBotAutoLogin = true;
|
|
return result;
|
|
}());
|
|
|
|
using Flag = MTPmessages_RequestUrlAuth::Flag;
|
|
session->api().request(MTPmessages_RequestUrlAuth(
|
|
MTP_flags(Flag::f_url),
|
|
MTPInputPeer(),
|
|
MTPint(), // msg_id
|
|
MTPint(), // button_id
|
|
MTP_string(url),
|
|
MTPstring() // in_app_origin
|
|
)).done([=](const MTPUrlAuthResult &result) {
|
|
result.match([&](const MTPDurlAuthResultAccepted &data) {
|
|
UrlClickHandler::Open(qs(data.vurl().value_or_empty()), context);
|
|
}, [&](const MTPDurlAuthResultDefault &data) {
|
|
HiddenUrlClickHandler::Open(url, context);
|
|
}, [&](const MTPDurlAuthResultRequest &data) {
|
|
RequestUrl(show, data, session, url, context);
|
|
});
|
|
}).fail([=](const MTP::Error &error) {
|
|
if (error.type() == u"URL_EXPIRED"_q) {
|
|
show->showToast(
|
|
tr::lng_url_auth_phone_toast_bad_expired(tr::now));
|
|
} else {
|
|
HiddenUrlClickHandler::Open(url, context);
|
|
}
|
|
}).send();
|
|
}
|
|
|
|
void RequestButton(
|
|
std::shared_ptr<Ui::Show> show,
|
|
const MTPDurlAuthResultRequest &request,
|
|
not_null<const HistoryItem*> message,
|
|
Api::BotButtonLookup lookup) {
|
|
const auto itemId = message->fullId();
|
|
const auto button = lookup();
|
|
if (!button || button->requestId || !message->isRegular()) {
|
|
return;
|
|
}
|
|
const auto session = &message->history()->session();
|
|
const auto inputPeer = message->history()->peer->input();
|
|
const auto buttonId = button->buttonId;
|
|
const auto url = QString::fromUtf8(button->data);
|
|
|
|
const auto bot = request.is_request_write_access()
|
|
? session->data().processUser(request.vbot()).get()
|
|
: nullptr;
|
|
const auto box = std::make_shared<base::weak_qptr<Ui::BoxContent>>();
|
|
const auto finishWithUrl = [=](const QString &url, bool accepted) {
|
|
if (*box) {
|
|
(*box)->closeBox();
|
|
}
|
|
if (url.isEmpty() && accepted) {
|
|
show->showToast(tr::lng_passport_success(tr::now));
|
|
} else {
|
|
UrlClickHandler::Open(url);
|
|
}
|
|
};
|
|
const auto callback = [=](Result result) {
|
|
if (!result.auth) {
|
|
session->api().request(MTPmessages_DeclineUrlAuth(
|
|
MTP_string(url)
|
|
)).send();
|
|
finishWithUrl(url, false);
|
|
} else if (session->data().message(itemId)) {
|
|
using Flag = MTPmessages_AcceptUrlAuth::Flag;
|
|
const auto flags = Flag(0)
|
|
| (result.allowWrite ? Flag::f_write_allowed : Flag(0))
|
|
| (result.sharePhone ? Flag::f_share_phone_number : Flag(0))
|
|
| (result.matchCode.isEmpty() ? Flag(0) : Flag::f_match_code)
|
|
| (Flag::f_peer | Flag::f_msg_id | Flag::f_button_id);
|
|
session->api().request(MTPmessages_AcceptUrlAuth(
|
|
MTP_flags(flags),
|
|
inputPeer,
|
|
MTP_int(itemId.msg),
|
|
MTP_int(buttonId),
|
|
MTPstring(),
|
|
result.matchCode.isEmpty()
|
|
? MTPstring()
|
|
: MTP_string(result.matchCode)
|
|
)).done([=](const MTPUrlAuthResult &result) {
|
|
const auto accepted = result.match(
|
|
[](const MTPDurlAuthResultAccepted &data) {
|
|
return true;
|
|
}, [](const auto &) {
|
|
return false;
|
|
});
|
|
const auto to = result.match(
|
|
[&](const MTPDurlAuthResultAccepted &data) {
|
|
return qs(data.vurl().value_or_empty());
|
|
}, [&](const MTPDurlAuthResultDefault &data) {
|
|
return url;
|
|
}, [&](const MTPDurlAuthResultRequest &data) {
|
|
LOG(("API Error: "
|
|
"got urlAuthResultRequest after acceptUrlAuth."));
|
|
return url;
|
|
});
|
|
finishWithUrl(to, accepted);
|
|
}).fail([=] {
|
|
finishWithUrl(url, false);
|
|
}).send();
|
|
}
|
|
};
|
|
const auto displayName = request.is_is_app()
|
|
? (request.vverified_app_name()
|
|
? qs(*request.vverified_app_name())
|
|
: tr::lng_url_auth_unverified_app(tr::now))
|
|
: qs(request.vdomain());
|
|
*box = show->show(
|
|
Box(
|
|
Show,
|
|
url,
|
|
displayName,
|
|
session->user()->name(),
|
|
bot ? bot->firstName : QString(),
|
|
callback),
|
|
Ui::LayerOption::KeepOther);
|
|
}
|
|
|
|
void RequestUrl(
|
|
std::shared_ptr<Ui::Show> show,
|
|
const MTPDurlAuthResultRequest &request,
|
|
not_null<Main::Session*> session,
|
|
const QString &url,
|
|
QVariant context) {
|
|
struct State {
|
|
base::weak_qptr<Ui::BoxContent> box;
|
|
AnotherSessionFactory anotherSession = nullptr;
|
|
QString firstMatchCode;
|
|
rpl::lifetime boxDeclineLifetime;
|
|
rpl::lifetime matchCodesBoxDeclineLifetime;
|
|
};
|
|
const auto bot = request.is_request_write_access()
|
|
? session->data().processUser(request.vbot()).get()
|
|
: nullptr;
|
|
const auto requestPhone = request.is_request_phone_number();
|
|
const auto matchCodesFirst = request.is_match_codes_first();
|
|
const auto isApp = request.is_is_app();
|
|
const auto domain = isApp
|
|
? (request.vverified_app_name()
|
|
? qs(*request.vverified_app_name())
|
|
: tr::lng_url_auth_unverified_app(tr::now))
|
|
: qs(request.vdomain());
|
|
const auto userIdHint = request.vuser_id_hint()
|
|
? peerToUser(peerFromUser(*request.vuser_id_hint()))
|
|
: UserId();
|
|
const auto matchCodes = [&] {
|
|
auto result = QStringList();
|
|
if (const auto codes = request.vmatch_codes()) {
|
|
for (const auto &code : codes->v) {
|
|
result.push_back(qs(code));
|
|
}
|
|
}
|
|
return result;
|
|
}();
|
|
const auto state = std::make_shared<State>();
|
|
const auto finishWithUrl = [=](const QString &to, bool accepted) {
|
|
if (state->box) {
|
|
state->box->closeBox();
|
|
}
|
|
|
|
if ((to.isEmpty() && accepted) || (to == url)) {
|
|
} else {
|
|
UrlClickHandler::Open(to, context);
|
|
}
|
|
};
|
|
const auto resolveSession = [=] {
|
|
return state->anotherSession ? state->anotherSession() : session;
|
|
};
|
|
const auto requestDecline = [=] {
|
|
resolveSession()->api().request(MTPmessages_DeclineUrlAuth(
|
|
MTP_string(url)
|
|
)).send();
|
|
};
|
|
const auto sendRequest = [=](Result result) {
|
|
if (!result.auth) {
|
|
requestDecline();
|
|
finishWithUrl(url, false);
|
|
} else {
|
|
const auto sharePhone = result.sharePhone;
|
|
using Flag = MTPmessages_AcceptUrlAuth::Flag;
|
|
const auto flags = Flag::f_url
|
|
| (result.allowWrite ? Flag::f_write_allowed : Flag(0))
|
|
| (sharePhone ? Flag::f_share_phone_number : Flag(0))
|
|
| (result.matchCode.isEmpty() ? Flag(0) : Flag::f_match_code);
|
|
resolveSession()->api().request(MTPmessages_AcceptUrlAuth(
|
|
MTP_flags(flags),
|
|
MTPInputPeer(),
|
|
MTPint(), // msg_id
|
|
MTPint(), // button_id
|
|
MTP_string(url),
|
|
result.matchCode.isEmpty()
|
|
? MTPstring()
|
|
: MTP_string(result.matchCode)
|
|
)).done([=](const MTPUrlAuthResult &result) {
|
|
const auto accepted = result.match(
|
|
[](const MTPDurlAuthResultAccepted &data) {
|
|
return true;
|
|
}, [](const auto &) {
|
|
return false;
|
|
});
|
|
const auto to = result.match(
|
|
[&](const MTPDurlAuthResultAccepted &data) {
|
|
return qs(data.vurl().value_or_empty());
|
|
}, [&](const MTPDurlAuthResultDefault &data) {
|
|
return url;
|
|
}, [&](const MTPDurlAuthResultRequest &data) {
|
|
LOG(("API Error: "
|
|
"got urlAuthResultRequest after acceptUrlAuth."));
|
|
return url;
|
|
});
|
|
finishWithUrl(to, accepted);
|
|
const auto domainWrapped = isApp
|
|
? tr::bold(domain)
|
|
: tr::link(domain);
|
|
show->showToast(Ui::Toast::Config{
|
|
.title = tr::lng_url_auth_phone_toast_good_title(tr::now),
|
|
.text = ((requestPhone && !sharePhone)
|
|
? tr::lng_url_auth_phone_toast_good_no_phone
|
|
: tr::lng_url_auth_phone_toast_good)(
|
|
tr::now,
|
|
lt_domain,
|
|
domainWrapped,
|
|
tr::marked),
|
|
.duration = crl::time(4000),
|
|
});
|
|
}).fail([=] {
|
|
const auto domainWrapped = isApp
|
|
? tr::bold(domain)
|
|
: tr::link(domain);
|
|
show->showToast(Ui::Toast::Config{
|
|
.title = tr::lng_url_auth_phone_toast_bad_title(tr::now),
|
|
.text = tr::lng_url_auth_phone_toast_bad(
|
|
tr::now,
|
|
lt_domain,
|
|
domainWrapped,
|
|
tr::marked),
|
|
.duration = crl::time(4000),
|
|
});
|
|
finishWithUrl(url, false);
|
|
}).send();
|
|
}
|
|
};
|
|
const auto browser = qs(request.vbrowser().value_or("Unknown browser"));
|
|
const auto device = qs(request.vplatform().value_or("Unknown platform"));
|
|
const auto ip = qs(request.vip().value_or("Unknown IP"));
|
|
const auto region = qs(request.vregion().value_or("Unknown region"));
|
|
const auto showAuthBox = [=] {
|
|
state->box = show->show(Box([=](not_null<Ui::GenericBox*> box) {
|
|
const auto accountResult = box->lifetime().make_state<
|
|
SwitchAccountResult>(nullptr);
|
|
const auto matchCodesShared = box->lifetime().make_state<
|
|
rpl::variable<QStringList>>(matchCodes);
|
|
const auto reloadRequest = [=] {
|
|
using Flag = MTPmessages_RequestUrlAuth::Flag;
|
|
const auto currentSession = resolveSession();
|
|
currentSession->api().request(MTPmessages_RequestUrlAuth(
|
|
MTP_flags(Flag::f_url),
|
|
MTPInputPeer(),
|
|
MTPint(), // msg_id
|
|
MTPint(), // button_id
|
|
MTP_string(url),
|
|
MTPstring() // in_app_origin
|
|
)).done(crl::guard(box, [=](const MTPUrlAuthResult &result) {
|
|
result.match([&](const MTPDurlAuthResultRequest &data) {
|
|
const auto newUserId = data.vuser_id_hint()
|
|
? peerToUser(peerFromUser(*data.vuser_id_hint()))
|
|
: UserId();
|
|
accountResult->updateUserIdHint(newUserId);
|
|
auto newCodes = QStringList();
|
|
if (const auto codes = data.vmatch_codes()) {
|
|
for (const auto &code : codes->v) {
|
|
newCodes.push_back(qs(code));
|
|
}
|
|
}
|
|
*matchCodesShared = newCodes;
|
|
}, [](const auto &) {});
|
|
})).send();
|
|
};
|
|
const auto callback = [=](Result result) {
|
|
state->boxDeclineLifetime.destroy();
|
|
if (result.matchCode.isEmpty()
|
|
&& !state->firstMatchCode.isEmpty()) {
|
|
result.matchCode = state->firstMatchCode;
|
|
}
|
|
if (!requestPhone) {
|
|
return sendRequest(result);
|
|
}
|
|
box->uiShow()->show(Box([=](not_null<Ui::GenericBox*> box) {
|
|
box->setTitle(tr::lng_url_auth_phone_sure_title());
|
|
const auto confirm = [=](bool confirmed) {
|
|
return [=](Fn<void()> close) {
|
|
auto copy = result;
|
|
copy.sharePhone = confirmed;
|
|
sendRequest(copy);
|
|
close();
|
|
};
|
|
};
|
|
const auto currentSession = resolveSession();
|
|
const auto capitalized = [=](const QString &v) {
|
|
return v.left(1).toUpper() + v.mid(1).toLower();
|
|
};
|
|
using namespace Info::Profile;
|
|
Ui::ConfirmBox(
|
|
box,
|
|
Ui::ConfirmBoxArgs{
|
|
.text = tr::lng_url_auth_phone_sure_text(
|
|
lt_domain,
|
|
rpl::single(
|
|
tr::bold(isApp
|
|
? domain
|
|
: capitalized(domain))),
|
|
lt_phone,
|
|
PhoneValue(currentSession->user()),
|
|
tr::rich),
|
|
.confirmed = confirm(true),
|
|
.cancelled = confirm(false),
|
|
.confirmText = tr::lng_allow_bot(),
|
|
.cancelText = tr::lng_url_auth_phone_sure_deny(),
|
|
});
|
|
}));
|
|
};
|
|
ShowDetails(
|
|
box,
|
|
url,
|
|
domain,
|
|
[=](QString code) -> std::shared_ptr<Ui::DynamicImage> {
|
|
return MakeMatchCodeImage(resolveSession(), code);
|
|
},
|
|
callback,
|
|
(bot
|
|
? object_ptr<Ui::UserpicButton>(
|
|
box->verticalLayout(),
|
|
bot,
|
|
st::defaultUserpicButton,
|
|
Ui::PeerUserpicShape::Forum)
|
|
: nullptr),
|
|
bot ? Info::Profile::NameValue(bot) : nullptr,
|
|
browser,
|
|
device,
|
|
ip,
|
|
region,
|
|
(matchCodesFirst
|
|
? (rpl::single(QStringList()) | rpl::type_erased)
|
|
: matchCodesShared->value()),
|
|
isApp);
|
|
|
|
*accountResult = AddAccountsMenu(
|
|
box->verticalLayout(),
|
|
userIdHint);
|
|
box->verticalLayout()->widthValue(
|
|
) | rpl::on_next([=, w = (*accountResult).widget] {
|
|
w->moveToRight(SwitchableUserpicButton::Skip(), 0);
|
|
}, (*accountResult).widget->lifetime());
|
|
state->anotherSession = (*accountResult).anotherSession;
|
|
(*accountResult).setOnUserChanged(reloadRequest);
|
|
}));
|
|
if (const auto strong = state->box.get()) {
|
|
strong->boxClosing() | rpl::on_next([=] {
|
|
requestDecline();
|
|
}, state->boxDeclineLifetime);
|
|
} else {
|
|
// Closed inside show(), so boxClosing() has already passed.
|
|
requestDecline();
|
|
}
|
|
};
|
|
if (!matchCodesFirst || matchCodes.isEmpty()) {
|
|
showAuthBox();
|
|
return;
|
|
}
|
|
auto matchCodesBox = base::weak_qptr<Ui::BoxContent>();
|
|
matchCodesBox = show->show(
|
|
Box([=](not_null<Ui::GenericBox*> matchBox) {
|
|
ShowMatchCodesBox(
|
|
matchBox,
|
|
[=](QString code) -> std::shared_ptr<Ui::DynamicImage> {
|
|
return MakeMatchCodeImage(resolveSession(), code);
|
|
},
|
|
domain,
|
|
matchCodes,
|
|
[=](QString matchCode) {
|
|
state->matchCodesBoxDeclineLifetime.destroy();
|
|
resolveSession()->api().request(
|
|
MTPmessages_CheckUrlAuthMatchCode(
|
|
MTP_string(url),
|
|
MTP_string(matchCode))
|
|
).done([=](const MTPBool &result) {
|
|
if (!mtpIsTrue(result)) {
|
|
show->showToast(
|
|
tr::lng_url_auth_phone_toast_bad_expired(
|
|
tr::now));
|
|
return;
|
|
}
|
|
state->firstMatchCode = std::move(matchCode);
|
|
showAuthBox();
|
|
}).fail([=](const MTP::Error &error) {
|
|
show->showToast((error.type() == u"URL_EXPIRED"_q)
|
|
? tr::lng_url_auth_phone_toast_bad_expired(
|
|
tr::now)
|
|
: error.type());
|
|
}).send();
|
|
},
|
|
isApp);
|
|
}),
|
|
Ui::LayerOption::KeepOther);
|
|
if (const auto strong = matchCodesBox.get()) {
|
|
strong->boxClosing() | rpl::on_next([=] {
|
|
requestDecline();
|
|
}, state->matchCodesBoxDeclineLifetime);
|
|
} else {
|
|
// Closed inside show(), so boxClosing() has already passed.
|
|
requestDecline();
|
|
}
|
|
}
|
|
|
|
} // namespace UrlAuthBox
|