diff --git a/Telegram/Resources/animations/passkeys.tgs b/Telegram/Resources/animations/passkeys.tgs
new file mode 100644
index 0000000000..62e11b2540
Binary files /dev/null and b/Telegram/Resources/animations/passkeys.tgs differ
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index 5a52c5f380..34e0b4591e 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -50,6 +50,7 @@
../../animations/rtmp.tgs
../../animations/show_or_premium_lastseen.tgs
../../animations/show_or_premium_readtime.tgs
+ ../../animations/passkeys.tgs
../../animations/profile/profile_muting.tgs
../../animations/profile/profile_unmuting.tgs
diff --git a/Telegram/SourceFiles/settings/settings.style b/Telegram/SourceFiles/settings/settings.style
index 6460e3c3d7..d0a7275782 100644
--- a/Telegram/SourceFiles/settings/settings.style
+++ b/Telegram/SourceFiles/settings/settings.style
@@ -715,6 +715,10 @@ settingsCreditsButton: SettingsButton(settingsButton) {
settingsButtonIconGift: icon {{ "settings/gift", menuIconColor }};
settingsButtonIconEarn: icon {{ "settings/earn", menuIconColor }};
+settingsIconPasskeysAboutIcon1: icon {{ "menu/permissions", boxTextFg }};
+settingsIconPasskeysAboutIcon2: icon {{ "menu/passcode_winhello", boxTextFg }};
+settingsIconPasskeysAboutIcon3: icon {{ "menu/lock", boxTextFg }};
+
settingsAgeVerifyBox: Box(filterInviteBox) {
buttonPadding: margins(24px, 24px, 24px, 24px);
}
diff --git a/Telegram/SourceFiles/settings/settings_passkeys.cpp b/Telegram/SourceFiles/settings/settings_passkeys.cpp
index 3fe0c507e3..b82fd35231 100644
--- a/Telegram/SourceFiles/settings/settings_passkeys.cpp
+++ b/Telegram/SourceFiles/settings/settings_passkeys.cpp
@@ -7,13 +7,157 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "settings/settings_passkeys.h"
+#include "data/components/passkeys.h"
+#include "data/data_session.h"
+#include "window/window_session_controller.h"
+#include "main/main_session.h"
+#include "platform/platform_webauthn.h"
+#include "ui/layers/generic_box.h"
+#include "ui/painter.h"
+#include "ui/rect.h"
+#include "ui/text/text_utilities.h"
#include "ui/vertical_list.h"
+#include "ui/widgets/buttons.h"
#include "ui/wrap/vertical_layout.h"
#include "lang/lang_keys.h"
+#include "lottie/lottie_icon.h"
+#include "styles/style_channel_earn.h"
+#include "styles/style_chat.h"
+#include "styles/style_layers.h"
+#include "styles/style_premium.h"
#include "styles/style_settings.h"
namespace Settings {
+void PasskeysNoneBox(
+ not_null box,
+ not_null session) {
+ box->setWidth(st::boxWideWidth);
+ box->setNoContentMargin(true);
+ box->setCloseByEscape(true);
+ box->addTopButton(st::boxTitleClose, [=] { box->closeBox(); });
+
+ const auto content = box->verticalLayout().get();
+
+ Ui::AddSkip(content);
+ {
+ const auto &size = st::settingsCloudPasswordIconSize;
+ auto icon = CreateLottieIcon(
+ content,
+ { .name = u"passkeys"_q, .sizeOverride = { size, size } },
+ st::settingLocalPasscodeIconPadding);
+ const auto animate = std::move(icon.animate);
+ box->addRow(std::move(icon.widget), style::al_top);
+ box->showFinishes() | rpl::take(1) | rpl::start_with_next([=] {
+ animate(anim::repeat::once);
+ }, content->lifetime());
+ }
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ box->addRow(
+ object_ptr(
+ content,
+ tr::lng_settings_passkeys_none_title(),
+ st::boxTitle),
+ style::al_top);
+ Ui::AddSkip(content);
+ box->addRow(
+ object_ptr(
+ content,
+ tr::lng_settings_passkeys_none_about(),
+ st::channelEarnLearnDescription),
+ style::al_top);
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ {
+ const auto padding = QMargins(
+ st::settingsButton.padding.left(),
+ st::boxRowPadding.top(),
+ st::boxRowPadding.right(),
+ st::boxRowPadding.bottom());
+ const auto addEntry = [&](
+ rpl::producer title,
+ rpl::producer about,
+ const style::icon &icon) {
+ const auto top = content->add(
+ object_ptr(
+ content,
+ std::move(title),
+ st::channelEarnSemiboldLabel),
+ padding);
+ Ui::AddSkip(content, st::channelEarnHistoryThreeSkip);
+ content->add(
+ object_ptr(
+ content,
+ std::move(about),
+ st::channelEarnHistoryRecipientLabel),
+ padding);
+ const auto left = Ui::CreateChild(
+ box->verticalLayout().get());
+ left->paintRequest(
+ ) | rpl::start_with_next([=] {
+ auto p = Painter(left);
+ icon.paint(p, 0, 0, left->width());
+ }, left->lifetime());
+ left->resize(icon.size());
+ top->geometryValue(
+ ) | rpl::start_with_next([=](const QRect &g) {
+ left->moveToLeft(
+ (g.left() - left->width()) / 2,
+ g.top() + st::channelEarnHistoryThreeSkip);
+ }, left->lifetime());
+ };
+ addEntry(
+ tr::lng_settings_passkeys_none_info1_title(),
+ tr::lng_settings_passkeys_none_info1_about(),
+ st::settingsIconPasskeysAboutIcon1);
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ addEntry(
+ tr::lng_settings_passkeys_none_info2_title(),
+ tr::lng_settings_passkeys_none_info2_about(),
+ st::settingsIconPasskeysAboutIcon2);
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ addEntry(
+ tr::lng_settings_passkeys_none_info3_title(),
+ tr::lng_settings_passkeys_none_info3_about(),
+ st::settingsIconPasskeysAboutIcon3);
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ }
+ Ui::AddSkip(content);
+ Ui::AddSkip(content);
+ {
+ const auto &st = st::premiumPreviewDoubledLimitsBox;
+ box->setStyle(st);
+ auto button = object_ptr(
+ box,
+ tr::lng_settings_passkeys_none_button(),
+ st::defaultActiveButton);
+ button->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
+ button->resizeToWidth(box->width()
+ - st.buttonPadding.left()
+ - st.buttonPadding.left());
+ button->setClickedCallback([=] {
+ session->passkeys().initRegistration([=](
+ const Data::Passkey::RegisterData &data) {
+ Platform::WebAuthn::RegisterKey(data, [=](
+ Platform::WebAuthn::RegisterResult result) {
+ if (!result.success) {
+ return;
+ }
+ session->passkeys().registerPasskey(result, [=] {
+ box->closeBox();
+ });
+ });
+ });
+ });
+ box->addButton(std::move(button));
+ }
+}
+
Passkeys::Passkeys(
QWidget *parent,
not_null controller)
diff --git a/Telegram/SourceFiles/settings/settings_passkeys.h b/Telegram/SourceFiles/settings/settings_passkeys.h
index 182e6b713b..999a768030 100644
--- a/Telegram/SourceFiles/settings/settings_passkeys.h
+++ b/Telegram/SourceFiles/settings/settings_passkeys.h
@@ -9,8 +9,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "settings/settings_common_session.h"
+namespace Ui {
+class GenericBox;
+} // namespace Ui
+
namespace Settings {
+void PasskeysNoneBox(
+ not_null box,
+ not_null session);
+
class Passkeys : public Section {
public:
Passkeys(