mirror of https://github.com/procxx/kepka.git
Confirm 2sv recovery email by code.
This commit is contained in:
parent
93678a07a8
commit
be3e43e6cb
|
@ -342,6 +342,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_settings_sessions_about" = "Control your sessions on other devices.";
|
"lng_settings_sessions_about" = "Control your sessions on other devices.";
|
||||||
"lng_settings_passcode_disable" = "Disable passcode";
|
"lng_settings_passcode_disable" = "Disable passcode";
|
||||||
"lng_settings_password_disable" = "Disable cloud password";
|
"lng_settings_password_disable" = "Disable cloud password";
|
||||||
|
"lng_settings_password_abort" = "Abort two-step verification setup";
|
||||||
|
"lng_settings_password_reenter_email" = "Re-enter recovery email";
|
||||||
"lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco";
|
"lng_settings_about_bio" = "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco";
|
||||||
"lng_settings_name_label" = "Name";
|
"lng_settings_name_label" = "Name";
|
||||||
"lng_settings_username_label" = "Username";
|
"lng_settings_username_label" = "Username";
|
||||||
|
@ -449,7 +451,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passcode_logout" = "Log out";
|
"lng_passcode_logout" = "Log out";
|
||||||
"lng_passcode_need_unblock" = "You need to unlock me first.";
|
"lng_passcode_need_unblock" = "You need to unlock me first.";
|
||||||
|
|
||||||
"lng_cloud_password_waiting" = "Confirmation link sent to {email}...";
|
"lng_cloud_password_waiting_code" = "Confirmation code sent to {email}...";
|
||||||
|
"lng_cloud_password_confirm" = "Confirm recovery email";
|
||||||
"lng_cloud_password_change" = "Change cloud password";
|
"lng_cloud_password_change" = "Change cloud password";
|
||||||
"lng_cloud_password_create" = "Cloud password";
|
"lng_cloud_password_create" = "Cloud password";
|
||||||
"lng_cloud_password_remove" = "Remove cloud password";
|
"lng_cloud_password_remove" = "Remove cloud password";
|
||||||
|
@ -475,6 +478,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_cloud_password_wrong" = "Wrong cloud password";
|
"lng_cloud_password_wrong" = "Wrong cloud password";
|
||||||
"lng_cloud_password_is_same" = "Password was not changed";
|
"lng_cloud_password_is_same" = "Password was not changed";
|
||||||
"lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!";
|
"lng_cloud_password_passport_losing" = "Warning! All data saved in your Telegram Passport will be lost!";
|
||||||
|
"lng_cloud_password_resend" = "Resend code";
|
||||||
|
"lng_cloud_password_resent" = "Code was resent.";
|
||||||
|
|
||||||
"lng_connection_auto_connecting" = "Default (connecting...)";
|
"lng_connection_auto_connecting" = "Default (connecting...)";
|
||||||
"lng_connection_auto" = "Default ({transport} used)";
|
"lng_connection_auto" = "Default ({transport} used)";
|
||||||
|
@ -1602,7 +1607,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passport_create_password" = "Please create a password which will be used\nto encrypt your personal data.";
|
"lng_passport_create_password" = "Please create a password which will be used\nto encrypt your personal data.";
|
||||||
"lng_passport_about_password" = "This password will also be required whenever\nyou log in to a new device.";
|
"lng_passport_about_password" = "This password will also be required whenever\nyou log in to a new device.";
|
||||||
"lng_passport_password_create" = "Create a password";
|
"lng_passport_password_create" = "Create a password";
|
||||||
"lng_passport_link_sent" = "A confirmation link was sent to your email\n{email}";
|
"lng_passport_email_validate" = "Validate";
|
||||||
|
"lng_passport_code_sent" = "A confirmation code was sent to\n{email}";
|
||||||
"lng_passport_stop_password_sure" = "Are you sure you want to cancel setting up your password?";
|
"lng_passport_stop_password_sure" = "Are you sure you want to cancel setting up your password?";
|
||||||
"lng_passport_password_placeholder" = "Your password";
|
"lng_passport_password_placeholder" = "Your password";
|
||||||
"lng_passport_next" = "Next";
|
"lng_passport_next" = "Next";
|
||||||
|
|
|
@ -5038,16 +5038,7 @@ void ApiWrap::reloadPasswordState() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::clearUnconfirmedPassword() {
|
void ApiWrap::clearUnconfirmedPassword() {
|
||||||
_passwordRequestId = request(MTPaccount_UpdatePasswordSettings(
|
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||||
MTP_inputCheckPasswordEmpty(),
|
|
||||||
MTP_account_passwordInputSettings(
|
|
||||||
MTP_flags(
|
|
||||||
MTPDaccount_passwordInputSettings::Flag::f_email),
|
|
||||||
MTP_passwordKdfAlgoUnknown(), // new_algo
|
|
||||||
MTP_bytes(QByteArray()), // new_password_hash
|
|
||||||
MTP_string(QString()), // hint
|
|
||||||
MTP_string(QString()), // email
|
|
||||||
MTPSecureSecretSettings())
|
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
_passwordRequestId = 0;
|
_passwordRequestId = 0;
|
||||||
reloadPasswordState();
|
reloadPasswordState();
|
||||||
|
|
|
@ -118,12 +118,15 @@ public:
|
||||||
_boxClosingStream.fire({});
|
_boxClosingStream.fire({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDelegate(BoxContentDelegate *newDelegate) {
|
void setDelegate(not_null<BoxContentDelegate*> newDelegate) {
|
||||||
_delegate = newDelegate;
|
_delegate = newDelegate;
|
||||||
_preparing = true;
|
_preparing = true;
|
||||||
prepare();
|
prepare();
|
||||||
finishPrepare();
|
finishPrepare();
|
||||||
}
|
}
|
||||||
|
not_null<BoxContentDelegate*> getDelegate() const {
|
||||||
|
return _delegate;
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onScrollToY(int top, int bottom = -1);
|
void onScrollToY(int top, int bottom = -1);
|
||||||
|
@ -187,10 +190,6 @@ protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
|
||||||
not_null<BoxContentDelegate*> getDelegate() const {
|
|
||||||
return _delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onScroll();
|
void onScroll();
|
||||||
void onInnerResize();
|
void onInnerResize();
|
||||||
|
|
|
@ -10,12 +10,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/bytes.h"
|
#include "base/bytes.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
|
#include "boxes/confirm_phone_box.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "auth_session.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
|
#include "ui/widgets/labels.h"
|
||||||
|
#include "ui/wrap/vertical_layout.h"
|
||||||
|
#include "ui/wrap/fade_wrap.h"
|
||||||
#include "passport/passport_encryption.h"
|
#include "passport/passport_encryption.h"
|
||||||
|
#include "passport/passport_panel_edit_contact.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_passport.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
PasscodeBox::PasscodeBox(QWidget*, bool turningOff)
|
PasscodeBox::PasscodeBox(QWidget*, bool turningOff)
|
||||||
: _turningOff(turningOff)
|
: _turningOff(turningOff)
|
||||||
|
@ -64,6 +75,10 @@ rpl::producer<> PasscodeBox::passwordReloadNeeded() const {
|
||||||
return _passwordReloadNeeded.events();
|
return _passwordReloadNeeded.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const {
|
||||||
|
return _clearUnconfirmedPassword.events();
|
||||||
|
}
|
||||||
|
|
||||||
bool PasscodeBox::currentlyHave() const {
|
bool PasscodeBox::currentlyHave() const {
|
||||||
return _cloudPwd ? (!!_curRequest) : Global::LocalPasscode();
|
return _cloudPwd ? (!!_curRequest) : Global::LocalPasscode();
|
||||||
}
|
}
|
||||||
|
@ -266,20 +281,96 @@ void PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||||
|
|
||||||
void PasscodeBox::setPasswordFail(
|
void PasscodeBox::setPasswordFail(
|
||||||
const QByteArray &newPasswordBytes,
|
const QByteArray &newPasswordBytes,
|
||||||
|
const QString &email,
|
||||||
const RPCError &error) {
|
const RPCError &error) {
|
||||||
if (error.type() == qstr("EMAIL_UNCONFIRMED")) {
|
const auto prefix = qstr("EMAIL_UNCONFIRMED_");
|
||||||
|
if (error.type().startsWith(prefix)) {
|
||||||
|
const auto codeLength = error.type().mid(prefix.size()).toInt();
|
||||||
|
|
||||||
closeReplacedBy();
|
closeReplacedBy();
|
||||||
_setRequest = 0;
|
_setRequest = 0;
|
||||||
|
|
||||||
_newPasswordSet.fire_copy(newPasswordBytes);
|
validateEmail(email, codeLength, newPasswordBytes);
|
||||||
getDelegate()->show(
|
|
||||||
Box<InformBox>(lang(lng_cloud_password_almost)),
|
|
||||||
LayerOption::CloseOther);
|
|
||||||
} else {
|
} else {
|
||||||
setPasswordFail(error);
|
setPasswordFail(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PasscodeBox::validateEmail(
|
||||||
|
const QString &email,
|
||||||
|
int codeLength,
|
||||||
|
const QByteArray &newPasswordBytes) {
|
||||||
|
const auto errors = std::make_shared<rpl::event_stream<QString>>();
|
||||||
|
const auto resent = std::make_shared<rpl::event_stream<QString>>();
|
||||||
|
const auto set = std::make_shared<bool>(false);
|
||||||
|
const auto submit = [=](QString code) {
|
||||||
|
if (_setRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_setRequest = request(MTPaccount_ConfirmPasswordEmail(
|
||||||
|
MTP_string(code)
|
||||||
|
)).done([=](const MTPBool &result) {
|
||||||
|
*set = true;
|
||||||
|
setPasswordDone(newPasswordBytes);
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
_setRequest = 0;
|
||||||
|
if (MTP::isFloodError(error)) {
|
||||||
|
errors->fire(lang(lng_flood_error));
|
||||||
|
} else if (error.type() == qstr("CODE_INVALID")) {
|
||||||
|
errors->fire(lang(lng_signin_wrong_code));
|
||||||
|
} else if (error.type() == qstr("EMAIL_HASH_EXPIRED")) {
|
||||||
|
const auto weak = make_weak(this);
|
||||||
|
_clearUnconfirmedPassword.fire({});
|
||||||
|
if (weak) {
|
||||||
|
auto box = Box<InformBox>(
|
||||||
|
Lang::Hard::EmailConfirmationExpired());
|
||||||
|
weak->getDelegate()->show(
|
||||||
|
std::move(box),
|
||||||
|
LayerOption::CloseOther);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errors->fire(Lang::Hard::ServerError());
|
||||||
|
}
|
||||||
|
}).handleFloodErrors().send();
|
||||||
|
};
|
||||||
|
const auto resend = [=] {
|
||||||
|
if (_setRequest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_setRequest = request(MTPaccount_ResendPasswordEmail(
|
||||||
|
)).done([=](const MTPBool &result) {
|
||||||
|
_setRequest = 0;
|
||||||
|
resent->fire(lang(lng_cloud_password_resent));
|
||||||
|
}).fail([=](const RPCError &error) {
|
||||||
|
_setRequest = 0;
|
||||||
|
errors->fire(Lang::Hard::ServerError());
|
||||||
|
}).send();
|
||||||
|
};
|
||||||
|
const auto box = getDelegate()->show(
|
||||||
|
Passport::VerifyEmailBox(
|
||||||
|
email,
|
||||||
|
codeLength,
|
||||||
|
submit,
|
||||||
|
resend,
|
||||||
|
errors->events(),
|
||||||
|
resent->events()),
|
||||||
|
LayerOption::KeepOther);
|
||||||
|
|
||||||
|
box->setCloseByOutsideClick(false);
|
||||||
|
box->setCloseByEscape(false);
|
||||||
|
box->boxClosing(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return !*set;
|
||||||
|
}) | start_with_next([=, weak = make_weak(this)] {
|
||||||
|
if (weak) {
|
||||||
|
weak->_clearUnconfirmedPassword.fire({});
|
||||||
|
}
|
||||||
|
if (weak) {
|
||||||
|
weak->closeBox();
|
||||||
|
}
|
||||||
|
}, box->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
void PasscodeBox::handleSrpIdInvalid() {
|
void PasscodeBox::handleSrpIdInvalid() {
|
||||||
const auto now = getms(true);
|
const auto now = getms(true);
|
||||||
if (_lastSrpIdInvalidTime > 0
|
if (_lastSrpIdInvalidTime > 0
|
||||||
|
@ -474,7 +565,7 @@ void PasscodeBox::sendClearCloudPassword(
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone({});
|
setPasswordDone({});
|
||||||
}).handleFloodErrors().fail([=](const RPCError &error) mutable {
|
}).handleFloodErrors().fail([=](const RPCError &error) mutable {
|
||||||
setPasswordFail({}, error);
|
setPasswordFail({}, QString(), error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +596,7 @@ void PasscodeBox::setNewCloudPassword(const QString &newPassword) {
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone(newPasswordBytes);
|
setPasswordDone(newPasswordBytes);
|
||||||
}).fail([=](const RPCError &error) {
|
}).fail([=](const RPCError &error) {
|
||||||
setPasswordFail(newPasswordBytes, error);
|
setPasswordFail(newPasswordBytes, email, error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,7 +746,7 @@ void PasscodeBox::sendChangeCloudPassword(
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
setPasswordDone(newPasswordBytes);
|
setPasswordDone(newPasswordBytes);
|
||||||
}).handleFloodErrors().fail([=](const RPCError &error) {
|
}).handleFloodErrors().fail([=](const RPCError &error) {
|
||||||
setPasswordFail(newPasswordBytes, error);
|
setPasswordFail(newPasswordBytes, QString(), error);
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,3 +981,81 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||||
_recoverCode->setFocus();
|
_recoverCode->setFocus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecoveryEmailValidation ConfirmRecoveryEmail(const QString &pattern) {
|
||||||
|
const auto errors = std::make_shared<rpl::event_stream<QString>>();
|
||||||
|
const auto resent = std::make_shared<rpl::event_stream<QString>>();
|
||||||
|
const auto requestId = std::make_shared<mtpRequestId>(0);
|
||||||
|
const auto weak = std::make_shared<QPointer<BoxContent>>();
|
||||||
|
const auto reloads = std::make_shared<rpl::event_stream<>>();
|
||||||
|
const auto cancels = std::make_shared<rpl::event_stream<>>();
|
||||||
|
|
||||||
|
const auto submit = [=](QString code) {
|
||||||
|
if (*requestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto done = [=](const MTPBool &result) {
|
||||||
|
*requestId = 0;
|
||||||
|
reloads->fire({});
|
||||||
|
if (*weak) {
|
||||||
|
(*weak)->getDelegate()->show(
|
||||||
|
Box<InformBox>(lang(lng_cloud_password_was_set)),
|
||||||
|
LayerOption::CloseOther);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto fail = [=](const RPCError &error) {
|
||||||
|
const auto skip = MTP::isDefaultHandledError(error)
|
||||||
|
&& !MTP::isFloodError(error);
|
||||||
|
if (skip) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*requestId = 0;
|
||||||
|
if (MTP::isFloodError(error)) {
|
||||||
|
errors->fire(lang(lng_flood_error));
|
||||||
|
} else if (error.type() == qstr("CODE_INVALID")) {
|
||||||
|
errors->fire(lang(lng_signin_wrong_code));
|
||||||
|
} else if (error.type() == qstr("EMAIL_HASH_EXPIRED")) {
|
||||||
|
cancels->fire({});
|
||||||
|
if (*weak) {
|
||||||
|
auto box = Box<InformBox>(
|
||||||
|
Lang::Hard::EmailConfirmationExpired());
|
||||||
|
(*weak)->getDelegate()->show(
|
||||||
|
std::move(box),
|
||||||
|
LayerOption::CloseOther);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errors->fire(Lang::Hard::ServerError());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
*requestId = MTP::send(
|
||||||
|
MTPaccount_ConfirmPasswordEmail(MTP_string(code)),
|
||||||
|
rpcDone(done),
|
||||||
|
rpcFail(fail));
|
||||||
|
};
|
||||||
|
const auto resend = [=] {
|
||||||
|
if (*requestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*requestId = MTP::send(MTPaccount_ResendPasswordEmail(
|
||||||
|
), rpcDone([=](const MTPBool &result) {
|
||||||
|
*requestId = 0;
|
||||||
|
resent->fire(lang(lng_cloud_password_resent));
|
||||||
|
}), rpcFail([=](const RPCError &error) {
|
||||||
|
*requestId = 0;
|
||||||
|
errors->fire(Lang::Hard::ServerError());
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
auto box = Passport::VerifyEmailBox(
|
||||||
|
pattern,
|
||||||
|
0,
|
||||||
|
submit,
|
||||||
|
resend,
|
||||||
|
errors->events(),
|
||||||
|
resent->events());
|
||||||
|
|
||||||
|
*weak = box.data();
|
||||||
|
return { std::move(box), reloads->events(), cancels->events() };
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
|
|
||||||
rpl::producer<QByteArray> newPasswordSet() const;
|
rpl::producer<QByteArray> newPasswordSet() const;
|
||||||
rpl::producer<> passwordReloadNeeded() const;
|
rpl::producer<> passwordReloadNeeded() const;
|
||||||
|
rpl::producer<> clearUnconfirmedPassword() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
@ -59,7 +60,12 @@ private:
|
||||||
void setPasswordFail(const RPCError &error);
|
void setPasswordFail(const RPCError &error);
|
||||||
void setPasswordFail(
|
void setPasswordFail(
|
||||||
const QByteArray &newPasswordBytes,
|
const QByteArray &newPasswordBytes,
|
||||||
|
const QString &email,
|
||||||
const RPCError &error);
|
const RPCError &error);
|
||||||
|
void validateEmail(
|
||||||
|
const QString &email,
|
||||||
|
int codeLength,
|
||||||
|
const QByteArray &newPasswordBytes);
|
||||||
|
|
||||||
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
void recoverStarted(const MTPauth_PasswordRecovery &result);
|
||||||
void recoverStartFail(const RPCError &error);
|
void recoverStartFail(const RPCError &error);
|
||||||
|
@ -90,9 +96,6 @@ private:
|
||||||
const Core::CloudPasswordResult &check,
|
const Core::CloudPasswordResult &check,
|
||||||
const QString &newPassword,
|
const QString &newPassword,
|
||||||
Fn<void()> callback);
|
Fn<void()> callback);
|
||||||
void resetSecretAndChangePassword(
|
|
||||||
const bytes::vector &oldPasswordHash,
|
|
||||||
const QString &newPassword);
|
|
||||||
|
|
||||||
void sendClearCloudPassword(const QString &oldPassword);
|
void sendClearCloudPassword(const QString &oldPassword);
|
||||||
void sendClearCloudPassword(const Core::CloudPasswordResult &check);
|
void sendClearCloudPassword(const Core::CloudPasswordResult &check);
|
||||||
|
@ -134,6 +137,7 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<QByteArray> _newPasswordSet;
|
rpl::event_stream<QByteArray> _newPasswordSet;
|
||||||
rpl::event_stream<> _passwordReloadNeeded;
|
rpl::event_stream<> _passwordReloadNeeded;
|
||||||
|
rpl::event_stream<> _clearUnconfirmedPassword;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,3 +177,10 @@ private:
|
||||||
rpl::event_stream<> _recoveryExpired;
|
rpl::event_stream<> _recoveryExpired;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RecoveryEmailValidation {
|
||||||
|
object_ptr<BoxContent> box;
|
||||||
|
rpl::producer<> reloadRequests;
|
||||||
|
rpl::producer<> cancelRequests;
|
||||||
|
};
|
||||||
|
RecoveryEmailValidation ConfirmRecoveryEmail(const QString &pattern);
|
||||||
|
|
|
@ -62,5 +62,9 @@ inline QString UnknownSecureScanError() {
|
||||||
return qsl("Unknown scan read error.");
|
return qsl("Unknown scan read error.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QString EmailConfirmationExpired() {
|
||||||
|
return qsl("This email confirmation has expired. Please setup two-step verification once again.");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Hard
|
} // namespace Hard
|
||||||
} // namespace Lang
|
} // namespace Lang
|
||||||
|
|
|
@ -1016,15 +1016,7 @@ void FormController::cancelPassword() {
|
||||||
if (_passwordRequestId) {
|
if (_passwordRequestId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_passwordRequestId = request(MTPaccount_UpdatePasswordSettings(
|
_passwordRequestId = request(MTPaccount_CancelPasswordEmail(
|
||||||
MTP_inputCheckPasswordEmpty(),
|
|
||||||
MTP_account_passwordInputSettings(
|
|
||||||
MTP_flags(MTPDaccount_passwordInputSettings::Flag::f_email),
|
|
||||||
MTP_passwordKdfAlgoUnknown(), // new_algo
|
|
||||||
MTP_bytes(QByteArray()), // new_password_hash
|
|
||||||
MTP_string(QString()), // hint
|
|
||||||
MTP_string(QString()), // email
|
|
||||||
MTPSecureSecretSettings())
|
|
||||||
)).done([=](const MTPBool &result) {
|
)).done([=](const MTPBool &result) {
|
||||||
_passwordRequestId = 0;
|
_passwordRequestId = 0;
|
||||||
reloadPassword();
|
reloadPassword();
|
||||||
|
|
|
@ -738,6 +738,11 @@ void PanelController::setupPassword() {
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_form->reloadPassword();
|
_form->reloadPassword();
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
|
|
||||||
|
box->clearUnconfirmedPassword(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_form->cancelPassword();
|
||||||
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelController::cancelPasswordSubmit() {
|
void PanelController::cancelPasswordSubmit() {
|
||||||
|
@ -748,6 +753,24 @@ void PanelController::cancelPasswordSubmit() {
|
||||||
[=] { if (*box) (*box)->closeBox(); _form->cancelPassword(); }));
|
[=] { if (*box) (*box)->closeBox(); _form->cancelPassword(); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PanelController::validateRecoveryEmail() {
|
||||||
|
auto validation = ConfirmRecoveryEmail(unconfirmedEmailPattern());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
validation.reloadRequests
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_form->reloadPassword();
|
||||||
|
}, validation.box->lifetime());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
validation.cancelRequests
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_form->cancelPassword();
|
||||||
|
}, validation.box->lifetime());
|
||||||
|
|
||||||
|
show(std::move(validation.box));
|
||||||
|
}
|
||||||
|
|
||||||
bool PanelController::canAddScan(FileType type) const {
|
bool PanelController::canAddScan(FileType type) const {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocument != nullptr);
|
Expects(_editDocument != nullptr);
|
||||||
|
@ -1335,12 +1358,15 @@ void PanelController::processVerificationNeeded(
|
||||||
text,
|
text,
|
||||||
value->verification.codeLength,
|
value->verification.codeLength,
|
||||||
[=](const QString &code) { _form->verify(value, code); },
|
[=](const QString &code) { _form->verify(value, code); },
|
||||||
|
nullptr, // resend
|
||||||
|
|
||||||
rpl::duplicate(
|
rpl::duplicate(
|
||||||
update
|
update
|
||||||
) | rpl::map([=](not_null<const Value*> field) {
|
) | rpl::map([=](not_null<const Value*> field) {
|
||||||
return field->verification.error;
|
return field->verification.error;
|
||||||
}) | rpl::distinct_until_changed()));
|
}) | rpl::distinct_until_changed(),
|
||||||
|
|
||||||
|
rpl::never<QString>()));
|
||||||
} else {
|
} else {
|
||||||
Unexpected("Type in processVerificationNeeded.");
|
Unexpected("Type in processVerificationNeeded.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,7 @@ public:
|
||||||
|
|
||||||
void setupPassword();
|
void setupPassword();
|
||||||
void cancelPasswordSubmit();
|
void cancelPasswordSubmit();
|
||||||
|
void validateRecoveryEmail();
|
||||||
|
|
||||||
bool canAddScan(FileType type) const;
|
bool canAddScan(FileType type) const;
|
||||||
void uploadScan(FileType type, QByteArray &&content);
|
void uploadScan(FileType type, QByteArray &&content);
|
||||||
|
|
|
@ -35,8 +35,10 @@ public:
|
||||||
const QString &text,
|
const QString &text,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
|
Fn<void()> resend,
|
||||||
rpl::producer<QString> call,
|
rpl::producer<QString> call,
|
||||||
rpl::producer<QString> error);
|
rpl::producer<QString> error,
|
||||||
|
rpl::producer<QString> resent);
|
||||||
|
|
||||||
void setInnerFocus() override;
|
void setInnerFocus() override;
|
||||||
|
|
||||||
|
@ -48,13 +50,15 @@ private:
|
||||||
const QString &text,
|
const QString &text,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
|
Fn<void()> resend,
|
||||||
rpl::producer<QString> call,
|
rpl::producer<QString> call,
|
||||||
rpl::producer<QString> error);
|
rpl::producer<QString> error,
|
||||||
|
rpl::producer<QString> resent);
|
||||||
|
|
||||||
QString _title;
|
QString _title;
|
||||||
Fn<void()> _submit;
|
Fn<void()> _submit;
|
||||||
QPointer<SentCodeField> _code;
|
QPointer<SentCodeField> _code;
|
||||||
int _height = 0;
|
QPointer<Ui::VerticalLayout> _content;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,44 +68,94 @@ VerifyBox::VerifyBox(
|
||||||
const QString &text,
|
const QString &text,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
|
Fn<void()> resend,
|
||||||
rpl::producer<QString> call,
|
rpl::producer<QString> call,
|
||||||
rpl::producer<QString> error)
|
rpl::producer<QString> error,
|
||||||
|
rpl::producer<QString> resent)
|
||||||
: _title(title) {
|
: _title(title) {
|
||||||
setupControls(
|
setupControls(
|
||||||
text,
|
text,
|
||||||
codeLength,
|
codeLength,
|
||||||
submit,
|
submit,
|
||||||
|
resend,
|
||||||
std::move(call),
|
std::move(call),
|
||||||
std::move(error));
|
std::move(error),
|
||||||
|
std::move(resent));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyBox::setupControls(
|
void VerifyBox::setupControls(
|
||||||
const QString &text,
|
const QString &text,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
|
Fn<void()> resend,
|
||||||
rpl::producer<QString> call,
|
rpl::producer<QString> call,
|
||||||
rpl::producer<QString> error) {
|
rpl::producer<QString> error,
|
||||||
const auto description = Ui::CreateChild<Ui::FlatLabel>(
|
rpl::producer<QString> resent) {
|
||||||
this,
|
_content = Ui::CreateChild<Ui::VerticalLayout>(this);
|
||||||
|
|
||||||
|
const auto small = style::margins(
|
||||||
|
st::boxPadding.left(),
|
||||||
|
0,
|
||||||
|
st::boxPadding.right(),
|
||||||
|
st::boxPadding.bottom());
|
||||||
|
const auto description = _content->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
_content,
|
||||||
text,
|
text,
|
||||||
Ui::FlatLabel::InitType::Simple,
|
Ui::FlatLabel::InitType::Simple,
|
||||||
st::boxLabel);
|
st::boxLabel),
|
||||||
_code = Ui::CreateChild<SentCodeField>(
|
small);
|
||||||
this,
|
_code = _content->add(
|
||||||
|
object_ptr<SentCodeField>(
|
||||||
|
_content,
|
||||||
st::defaultInputField,
|
st::defaultInputField,
|
||||||
langFactory(lng_change_phone_code_title));
|
langFactory(lng_change_phone_code_title)),
|
||||||
|
small);
|
||||||
|
|
||||||
const auto problem = Ui::CreateChild<Ui::FadeWrap<Ui::FlatLabel>>(
|
const auto problem = _content->add(
|
||||||
this,
|
object_ptr<Ui::FadeWrap<Ui::FlatLabel>>(
|
||||||
|
_content,
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
this,
|
_content,
|
||||||
QString(),
|
QString(),
|
||||||
Ui::FlatLabel::InitType::Simple,
|
Ui::FlatLabel::InitType::Simple,
|
||||||
st::passportVerifyErrorLabel));
|
st::passportVerifyErrorLabel)),
|
||||||
const auto waiter = Ui::CreateChild<Ui::FlatLabel>(
|
small);
|
||||||
this,
|
const auto waiter = _content->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
_content,
|
||||||
std::move(call),
|
std::move(call),
|
||||||
st::boxDividerLabel);
|
st::boxDividerLabel),
|
||||||
|
small);
|
||||||
|
if (resend) {
|
||||||
|
auto link = TextWithEntities{ lang(lng_cloud_password_resend) };
|
||||||
|
link.entities.push_back(EntityInText(
|
||||||
|
EntityInTextCustomUrl,
|
||||||
|
0,
|
||||||
|
link.text.size(),
|
||||||
|
QString("internal:resend")));
|
||||||
|
const auto label = _content->add(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
_content,
|
||||||
|
rpl::single(
|
||||||
|
link
|
||||||
|
) | rpl::then(rpl::duplicate(
|
||||||
|
resent
|
||||||
|
) | rpl::map([](const QString &value) {
|
||||||
|
return TextWithEntities{ value };
|
||||||
|
})),
|
||||||
|
st::boxDividerLabel),
|
||||||
|
small);
|
||||||
|
std::move(
|
||||||
|
resent
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_content->resizeToWidth(st::boxWidth);
|
||||||
|
}, _content->lifetime());
|
||||||
|
label->setClickHandlerFilter([=](auto&&...) {
|
||||||
|
resend();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
std::move(
|
std::move(
|
||||||
error
|
error
|
||||||
) | rpl::start_with_next([=](const QString &error) {
|
) | rpl::start_with_next([=](const QString &error) {
|
||||||
|
@ -109,29 +163,12 @@ void VerifyBox::setupControls(
|
||||||
problem->hide(anim::type::normal);
|
problem->hide(anim::type::normal);
|
||||||
} else {
|
} else {
|
||||||
problem->entity()->setText(error);
|
problem->entity()->setText(error);
|
||||||
|
_content->resizeToWidth(st::boxWidth);
|
||||||
problem->show(anim::type::normal);
|
problem->show(anim::type::normal);
|
||||||
_code->showError();
|
_code->showError();
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
auto y = 0;
|
|
||||||
const auto innerWidth = st::boxWidth
|
|
||||||
- st::boxPadding.left()
|
|
||||||
- st::boxPadding.right();
|
|
||||||
description->resizeToWidth(innerWidth);
|
|
||||||
description->moveToLeft(st::boxPadding.left(), y);
|
|
||||||
y += description->height() + st::boxPadding.bottom();
|
|
||||||
_code->resizeToWidth(innerWidth);
|
|
||||||
_code->moveToLeft(st::boxPadding.left(), y);
|
|
||||||
y += _code->height() + st::boxPadding.bottom();
|
|
||||||
problem->resizeToWidth(innerWidth);
|
|
||||||
problem->moveToLeft(st::boxPadding.left(), y);
|
|
||||||
y += problem->height() + st::boxPadding.top();
|
|
||||||
waiter->resizeToWidth(innerWidth);
|
|
||||||
waiter->moveToLeft(st::boxPadding.left(), y);
|
|
||||||
y += waiter->height() + st::boxPadding.bottom();
|
|
||||||
_height = y;
|
|
||||||
|
|
||||||
_submit = [=] {
|
_submit = [=] {
|
||||||
submit(_code->getLastText());
|
submit(_code->getLastText());
|
||||||
};
|
};
|
||||||
|
@ -155,7 +192,11 @@ void VerifyBox::prepare() {
|
||||||
addButton(langFactory(lng_change_phone_new_submit), _submit);
|
addButton(langFactory(lng_change_phone_new_submit), _submit);
|
||||||
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
addButton(langFactory(lng_cancel), [=] { closeBox(); });
|
||||||
|
|
||||||
setDimensions(st::boxWidth, _height);
|
_content->resizeToWidth(st::boxWidth);
|
||||||
|
_content->heightValue(
|
||||||
|
) | rpl::start_with_next([=](int height) {
|
||||||
|
setDimensions(st::boxWidth, height);
|
||||||
|
}, _content->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -364,22 +405,28 @@ object_ptr<BoxContent> VerifyPhoneBox(
|
||||||
lng_passport_confirm_phone(lt_phone, App::formatPhone(phone)),
|
lng_passport_confirm_phone(lt_phone, App::formatPhone(phone)),
|
||||||
codeLength,
|
codeLength,
|
||||||
submit,
|
submit,
|
||||||
|
nullptr,
|
||||||
std::move(call),
|
std::move(call),
|
||||||
std::move(error));
|
std::move(error),
|
||||||
|
rpl::never<QString>());
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<BoxContent> VerifyEmailBox(
|
object_ptr<BoxContent> VerifyEmailBox(
|
||||||
const QString &email,
|
const QString &email,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
rpl::producer<QString> error) {
|
Fn<void()> resend,
|
||||||
|
rpl::producer<QString> error,
|
||||||
|
rpl::producer<QString> resent) {
|
||||||
return Box<VerifyBox>(
|
return Box<VerifyBox>(
|
||||||
lang(lng_passport_email_title),
|
lang(lng_passport_email_title),
|
||||||
lng_passport_confirm_email(lt_email, email),
|
lng_passport_confirm_email(lt_email, email),
|
||||||
codeLength,
|
codeLength,
|
||||||
submit,
|
submit,
|
||||||
|
resend,
|
||||||
rpl::single(QString()),
|
rpl::single(QString()),
|
||||||
std::move(error));
|
std::move(error),
|
||||||
|
std::move(resent));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -83,6 +83,8 @@ object_ptr<BoxContent> VerifyEmailBox(
|
||||||
const QString &email,
|
const QString &email,
|
||||||
int codeLength,
|
int codeLength,
|
||||||
Fn<void(QString code)> submit,
|
Fn<void(QString code)> submit,
|
||||||
rpl::producer<QString> error);
|
Fn<void()> resend,
|
||||||
|
rpl::producer<QString> error,
|
||||||
|
rpl::producer<QString> resent);
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/wrap/padding_wrap.h"
|
#include "ui/wrap/padding_wrap.h"
|
||||||
#include "ui/special_buttons.h"
|
#include "ui/special_buttons.h"
|
||||||
|
#include "boxes/passcode_box.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "info/profile/info_profile_icon.h"
|
#include "info/profile/info_profile_icon.h"
|
||||||
#include "styles/style_passport.h"
|
#include "styles/style_passport.h"
|
||||||
|
@ -226,29 +227,49 @@ void PanelNoPassword::refreshBottom() {
|
||||||
_inner,
|
_inner,
|
||||||
(pattern.isEmpty()
|
(pattern.isEmpty()
|
||||||
? lang(lng_passport_about_password)
|
? lang(lng_passport_about_password)
|
||||||
: lng_passport_link_sent(lt_email, pattern)),
|
: lng_passport_code_sent(lt_email, pattern)),
|
||||||
Ui::FlatLabel::InitType::Simple,
|
Ui::FlatLabel::InitType::Simple,
|
||||||
st::passportPasswordSetupLabel)),
|
st::passportPasswordSetupLabel)),
|
||||||
st::passportFormAbout2Padding)->entity());
|
st::passportFormAbout2Padding)->entity());
|
||||||
|
if (pattern.isEmpty()) {
|
||||||
const auto button = _inner->add(
|
const auto button = _inner->add(
|
||||||
object_ptr<Ui::CenterWrap<Ui::RoundButton>>(
|
object_ptr<Ui::CenterWrap<Ui::RoundButton>>(
|
||||||
_inner,
|
_inner,
|
||||||
object_ptr<Ui::RoundButton>(
|
object_ptr<Ui::RoundButton>(
|
||||||
_inner,
|
_inner,
|
||||||
langFactory(pattern.isEmpty()
|
langFactory(lng_passport_password_create),
|
||||||
? lng_passport_password_create
|
|
||||||
: lng_cancel),
|
|
||||||
st::defaultBoxButton)));
|
st::defaultBoxButton)));
|
||||||
if (pattern.isEmpty()) {
|
|
||||||
button->entity()->addClickHandler([=] {
|
button->entity()->addClickHandler([=] {
|
||||||
_controller->setupPassword();
|
_controller->setupPassword();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
button->entity()->addClickHandler([=] {
|
const auto container = _inner->add(
|
||||||
|
object_ptr<Ui::FixedHeightWidget>(
|
||||||
|
_inner,
|
||||||
|
st::defaultBoxButton.height));
|
||||||
|
const auto cancel = Ui::CreateChild<Ui::RoundButton>(
|
||||||
|
container,
|
||||||
|
langFactory(lng_cancel),
|
||||||
|
st::defaultBoxButton);
|
||||||
|
cancel->addClickHandler([=] {
|
||||||
_controller->cancelPasswordSubmit();
|
_controller->cancelPasswordSubmit();
|
||||||
});
|
});
|
||||||
|
const auto validate = Ui::CreateChild<Ui::RoundButton>(
|
||||||
|
container,
|
||||||
|
langFactory(lng_passport_email_validate),
|
||||||
|
st::defaultBoxButton);
|
||||||
|
validate->addClickHandler([=] {
|
||||||
|
_controller->validateRecoveryEmail();
|
||||||
|
});
|
||||||
|
container->widthValue(
|
||||||
|
) | rpl::start_with_next([=](int width) {
|
||||||
|
const auto both = cancel->width()
|
||||||
|
+ validate->width()
|
||||||
|
+ st::boxLittleSkip;
|
||||||
|
cancel->moveToLeft((width - both) / 2, 0, width);
|
||||||
|
validate->moveToRight((width - both) / 2, 0, width);
|
||||||
|
}, container->lifetime());
|
||||||
}
|
}
|
||||||
_button.reset(button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -67,7 +67,6 @@ private:
|
||||||
|
|
||||||
not_null<Ui::VerticalLayout*> _inner;
|
not_null<Ui::VerticalLayout*> _inner;
|
||||||
base::unique_qptr<Ui::RpWidget> _about;
|
base::unique_qptr<Ui::RpWidget> _about;
|
||||||
base::unique_qptr<Ui::RpWidget> _button;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,10 @@ settingsSectionButton: InfoProfileButton(infoProfileButton) {
|
||||||
settingsButton: InfoProfileButton(settingsSectionButton) {
|
settingsButton: InfoProfileButton(settingsSectionButton) {
|
||||||
padding: margins(22px, 10px, 22px, 8px);
|
padding: margins(22px, 10px, 22px, 8px);
|
||||||
}
|
}
|
||||||
|
settingsAttentionButton: InfoProfileButton(settingsButton) {
|
||||||
|
textFg: attentionButtonFg;
|
||||||
|
textFgOver: attentionButtonFgOver;
|
||||||
|
}
|
||||||
settingsSectionSkip: 9px;
|
settingsSectionSkip: 9px;
|
||||||
settingsSectionIconLeft: 22px;
|
settingsSectionIconLeft: 22px;
|
||||||
settingsSeparatorPadding: margins(22px, infoProfileSkip, 0px, infoProfileSkip);
|
settingsSeparatorPadding: margins(22px, infoProfileSkip, 0px, infoProfileSkip);
|
||||||
|
|
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/self_destruction_box.h"
|
#include "boxes/self_destruction_box.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/wrap/fade_wrap.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "calls/calls_instance.h"
|
#include "calls/calls_instance.h"
|
||||||
|
@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_settings.h"
|
#include "styles/style_settings.h"
|
||||||
|
#include "styles/style_boxes.h"
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -242,12 +244,18 @@ void EditCloudPassword() {
|
||||||
current->notEmptyPassport,
|
current->notEmptyPassport,
|
||||||
current->hint,
|
current->hint,
|
||||||
current->newSecureSecret));
|
current->newSecureSecret));
|
||||||
|
|
||||||
rpl::merge(
|
rpl::merge(
|
||||||
box->newPasswordSet() | rpl::map([] { return rpl::empty_value(); }),
|
box->newPasswordSet() | rpl::map([] { return rpl::empty_value(); }),
|
||||||
box->passwordReloadNeeded()
|
box->passwordReloadNeeded()
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
Auth().api().reloadPasswordState();
|
Auth().api().reloadPasswordState();
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
|
|
||||||
|
box->clearUnconfirmedPassword(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Auth().api().clearUnconfirmedPassword();
|
||||||
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveCloudPassword() {
|
void RemoveCloudPassword() {
|
||||||
|
@ -266,6 +274,7 @@ void RemoveCloudPassword() {
|
||||||
current->hint,
|
current->hint,
|
||||||
current->newSecureSecret,
|
current->newSecureSecret,
|
||||||
true));
|
true));
|
||||||
|
|
||||||
rpl::merge(
|
rpl::merge(
|
||||||
box->newPasswordSet(
|
box->newPasswordSet(
|
||||||
) | rpl::map([] { return rpl::empty_value(); }),
|
) | rpl::map([] { return rpl::empty_value(); }),
|
||||||
|
@ -273,15 +282,21 @@ void RemoveCloudPassword() {
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
Auth().api().reloadPasswordState();
|
Auth().api().reloadPasswordState();
|
||||||
}, box->lifetime());
|
}, box->lifetime());
|
||||||
|
|
||||||
|
box->clearUnconfirmedPassword(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Auth().api().clearUnconfirmedPassword();
|
||||||
|
}, box->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
||||||
|
using namespace rpl::mappers;
|
||||||
|
using State = Core::CloudPasswordState;
|
||||||
|
|
||||||
AddDivider(container);
|
AddDivider(container);
|
||||||
AddSkip(container);
|
AddSkip(container);
|
||||||
AddSubsectionTitle(container, lng_settings_password_title);
|
AddSubsectionTitle(container, lng_settings_password_title);
|
||||||
|
|
||||||
using State = Core::CloudPasswordState;
|
|
||||||
|
|
||||||
auto has = rpl::single(
|
auto has = rpl::single(
|
||||||
false
|
false
|
||||||
) | rpl::then(Auth().api().passwordState(
|
) | rpl::then(Auth().api().passwordState(
|
||||||
|
@ -301,7 +316,7 @@ void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
||||||
) | rpl::filter([](const QString &pattern) {
|
) | rpl::filter([](const QString &pattern) {
|
||||||
return !pattern.isEmpty();
|
return !pattern.isEmpty();
|
||||||
}) | rpl::map([](const QString &pattern) {
|
}) | rpl::map([](const QString &pattern) {
|
||||||
return lng_cloud_password_waiting(lt_email, pattern);
|
return lng_cloud_password_waiting_code(lt_email, pattern);
|
||||||
}));
|
}));
|
||||||
auto unconfirmed = rpl::single(
|
auto unconfirmed = rpl::single(
|
||||||
true
|
true
|
||||||
|
@ -346,7 +361,7 @@ void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
||||||
container,
|
container,
|
||||||
std::move(text),
|
std::move(text),
|
||||||
st::settingsButton)));
|
st::settingsButton)));
|
||||||
change->toggleOn(std::move(
|
change->toggleOn(rpl::duplicate(
|
||||||
unconfirmed
|
unconfirmed
|
||||||
) | rpl::map([](bool unconfirmed) {
|
) | rpl::map([](bool unconfirmed) {
|
||||||
return !unconfirmed;
|
return !unconfirmed;
|
||||||
|
@ -357,6 +372,40 @@ void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const auto confirm = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Button>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Button>(
|
||||||
|
container,
|
||||||
|
Lang::Viewer(lng_cloud_password_confirm),
|
||||||
|
st::settingsButton)));
|
||||||
|
confirm->toggleOn(rpl::duplicate(
|
||||||
|
unconfirmed
|
||||||
|
))->setDuration(0);
|
||||||
|
confirm->entity()->addClickHandler([] {
|
||||||
|
const auto state = Auth().api().passwordStateCurrent();
|
||||||
|
auto validation = ConfirmRecoveryEmail(state->unconfirmedPattern);
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
validation.reloadRequests
|
||||||
|
) | rpl::start_with_next([] {
|
||||||
|
Auth().api().reloadPasswordState();
|
||||||
|
}, validation.box->lifetime());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
validation.cancelRequests
|
||||||
|
) | rpl::start_with_next([] {
|
||||||
|
Auth().api().clearUnconfirmedPassword();
|
||||||
|
}, validation.box->lifetime());
|
||||||
|
|
||||||
|
Ui::show(std::move(validation.box));
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto remove = [] {
|
||||||
|
if (CheckEditCloudPassword()) {
|
||||||
|
RemoveCloudPassword();
|
||||||
|
}
|
||||||
|
};
|
||||||
const auto disable = container->add(
|
const auto disable = container->add(
|
||||||
object_ptr<Ui::SlideWrap<Button>>(
|
object_ptr<Ui::SlideWrap<Button>>(
|
||||||
container,
|
container,
|
||||||
|
@ -364,12 +413,24 @@ void SetupCloudPassword(not_null<Ui::VerticalLayout*> container) {
|
||||||
container,
|
container,
|
||||||
Lang::Viewer(lng_settings_password_disable),
|
Lang::Viewer(lng_settings_password_disable),
|
||||||
st::settingsButton)));
|
st::settingsButton)));
|
||||||
disable->toggleOn(base::duplicate(has));
|
disable->toggleOn(rpl::combine(
|
||||||
disable->entity()->addClickHandler([] {
|
rpl::duplicate(has),
|
||||||
if (CheckEditCloudPassword()) {
|
rpl::duplicate(unconfirmed),
|
||||||
RemoveCloudPassword();
|
_1 && !_2));
|
||||||
}
|
disable->entity()->addClickHandler(remove);
|
||||||
});
|
|
||||||
|
const auto abort = container->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Button>>(
|
||||||
|
container,
|
||||||
|
object_ptr<Button>(
|
||||||
|
container,
|
||||||
|
Lang::Viewer(lng_settings_password_abort),
|
||||||
|
st::settingsAttentionButton)));
|
||||||
|
abort->toggleOn(rpl::combine(
|
||||||
|
rpl::duplicate(has),
|
||||||
|
rpl::duplicate(unconfirmed),
|
||||||
|
_1 && _2));
|
||||||
|
abort->entity()->addClickHandler(remove);
|
||||||
|
|
||||||
const auto reloadOnActivation = [=](Qt::ApplicationState state) {
|
const auto reloadOnActivation = [=](Qt::ApplicationState state) {
|
||||||
if (label->toggled() && state == Qt::ApplicationActive) {
|
if (label->toggled() && state == Qt::ApplicationActive) {
|
||||||
|
|
Loading…
Reference in New Issue