From 9f6130cd20118f571adf360239382ba8fc107814 Mon Sep 17 00:00:00 2001 From: John Preston <johnprestonmail@gmail.com> Date: Mon, 16 Apr 2018 21:02:40 +0400 Subject: [PATCH] Allow 2sv password setup in passport. --- .../icons/passport_password_setup.png | Bin 0 -> 6041 bytes .../icons/passport_password_setup@2x.png | Bin 0 -> 11801 bytes Telegram/Resources/langs/lang.strings | 5 + Telegram/SourceFiles/boxes/abstract_box.cpp | 12 ++- Telegram/SourceFiles/boxes/abstract_box.h | 33 +++++- Telegram/SourceFiles/boxes/passcode_box.cpp | 22 ++-- Telegram/SourceFiles/passport/passport.style | 8 ++ .../passport/passport_form_controller.cpp | 39 ++++++- .../passport/passport_form_controller.h | 4 +- .../passport/passport_form_view_controller.h | 15 ++- .../SourceFiles/passport/passport_panel.cpp | 16 +-- .../SourceFiles/passport/passport_panel.h | 6 +- .../passport/passport_panel_controller.cpp | 54 ++++++++-- .../passport/passport_panel_controller.h | 10 +- .../passport/passport_panel_form.cpp | 36 +++---- .../passport/passport_panel_password.cpp | 97 ++++++++++++++++-- .../passport/passport_panel_password.h | 17 ++- Telegram/SourceFiles/ui/wrap/padding_wrap.cpp | 31 ++++++ Telegram/SourceFiles/ui/wrap/padding_wrap.h | 36 +++++++ Telegram/SourceFiles/ui/wrap/wrap.h | 20 ---- Telegram/SourceFiles/window/layer_widget.cpp | 2 +- 21 files changed, 359 insertions(+), 104 deletions(-) create mode 100644 Telegram/Resources/icons/passport_password_setup.png create mode 100644 Telegram/Resources/icons/passport_password_setup@2x.png diff --git a/Telegram/Resources/icons/passport_password_setup.png b/Telegram/Resources/icons/passport_password_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..fa56c75125fb5718ec00a0f12ad0be20c5329a7a GIT binary patch literal 6041 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 Oh_Zq@wBm_n`2PXD^19^! literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/passport_password_setup@2x.png b/Telegram/Resources/icons/passport_password_setup@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..77fa1391d347c20220eca69987a02b00cc33f36e GIT binary patch literal 11801 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 literal 0 HcmV?d00001 diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 90be90624..fe64ace2e 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1516,6 +1516,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_passport_title" = "Telegram passport"; "lng_passport_request1" = "{bot} requests access to your personal data"; "lng_passport_request2" = "to sign you up for their services"; +"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_password_create" = "Create a password"; +"lng_passport_link_sent" = "Confirmation link was sent to your email\n{email}"; +"lng_passport_stop_password_sure" = "Are you sure you want to stop your password setup?"; "lng_passport_password_placeholder" = "Your password"; "lng_passport_next" = "Next"; "lng_passport_password_wrong" = "The password you entered is not valid."; diff --git a/Telegram/SourceFiles/boxes/abstract_box.cpp b/Telegram/SourceFiles/boxes/abstract_box.cpp index a475ffeae..9b1687580 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.cpp +++ b/Telegram/SourceFiles/boxes/abstract_box.cpp @@ -227,8 +227,9 @@ void BoxContent::paintEvent(QPaintEvent *e) { } } -AbstractBox::AbstractBox(QWidget *parent, object_ptr<BoxContent> content) -: LayerWidget(parent) +AbstractBox::AbstractBox(not_null<Window::LayerStackWidget*> layer, object_ptr<BoxContent> content) +: LayerWidget(layer) +, _layer(layer) , _content(std::move(content)) { subscribe(Lang::Current().updated(), [this] { refreshLang(); }); _content->setParent(this); @@ -330,6 +331,13 @@ bool AbstractBox::hasTitle() const { return (_title != nullptr) || !_additionalTitle.isEmpty(); } +void AbstractBox::showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) { + _layer->showBox(std::move(box), options, animated); +} + void AbstractBox::updateSize() { setDimensions(width(), _maxContentHeight); } diff --git a/Telegram/SourceFiles/boxes/abstract_box.h b/Telegram/SourceFiles/boxes/abstract_box.h index 8983812f1..84f4f6ea2 100644 --- a/Telegram/SourceFiles/boxes/abstract_box.h +++ b/Telegram/SourceFiles/boxes/abstract_box.h @@ -23,6 +23,8 @@ class FlatLabel; class FadeShadow; } // namespace Ui +class BoxContent; + class BoxContentDelegate { public: virtual void setLayerType(bool layerType) = 0; @@ -34,11 +36,25 @@ public: virtual QPointer<Ui::RoundButton> addLeftButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback, const style::RoundButton &st) = 0; virtual void updateButtonsPositions() = 0; + virtual void showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) = 0; virtual void setDimensions(int newWidth, int maxHeight) = 0; virtual void setNoContentMargin(bool noContentMargin) = 0; virtual bool isBoxShown() const = 0; virtual void closeBox() = 0; + template <typename BoxType> + QPointer<BoxType> show( + object_ptr<BoxType> content, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type::normal) { + auto result = QPointer<BoxType>(content.data()); + showBox(std::move(content), options, animated); + return result; + } + }; class BoxContent : public Ui::RpWidget, protected base::Subscriber { @@ -163,6 +179,10 @@ protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; + not_null<BoxContentDelegate*> getDelegate() const { + return _delegate; + } + private slots: void onScroll(); void onInnerResize(); @@ -179,10 +199,6 @@ private: void updateShadowsVisibility(); object_ptr<TWidget> doTakeInnerWidget(); - BoxContentDelegate *getDelegate() const { - Expects(_delegate != nullptr); - return _delegate; - } BoxContentDelegate *_delegate = nullptr; bool _preparing = false; @@ -205,13 +221,19 @@ class AbstractBox , public BoxContentDelegate , protected base::Subscriber { public: - AbstractBox(QWidget *parent, object_ptr<BoxContent> content); + AbstractBox( + not_null<Window::LayerStackWidget*> layer, + object_ptr<BoxContent> content); void parentResized() override; void setLayerType(bool layerType) override; void setTitle(base::lambda<TextWithEntities()> titleFactory) override; void setAdditionalTitle(base::lambda<QString()> additionalFactory) override; + void showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) override; void clearButtons() override; QPointer<Ui::RoundButton> addButton(base::lambda<QString()> textFactory, base::lambda<void()> clickCallback, const style::RoundButton &st) override; @@ -262,6 +284,7 @@ private: int countRealHeight() const; void updateSize(); + not_null<Window::LayerStackWidget*> _layer; int _fullHeight = 0; bool _noContentMargin = false; diff --git a/Telegram/SourceFiles/boxes/passcode_box.cpp b/Telegram/SourceFiles/boxes/passcode_box.cpp index 2926864a3..6eb117381 100644 --- a/Telegram/SourceFiles/boxes/passcode_box.cpp +++ b/Telegram/SourceFiles/boxes/passcode_box.cpp @@ -190,7 +190,7 @@ void PasscodeBox::setPasswordDone(const MTPBool &result) { _setRequest = 0; emit reloadPassword(); auto text = lang(_reenterPasscode->isHidden() ? lng_cloud_password_removed : (_oldPasscode->isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)); - Ui::show(Box<InformBox>(text)); + getDelegate()->show(Box<InformBox>(text), LayerOption::CloseOther); } void PasscodeBox::closeReplacedBy() { @@ -244,7 +244,9 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) { _recoverEmail->showError(); update(); } else if (err == qstr("EMAIL_UNCONFIRMED")) { - Ui::show(Box<InformBox>(lang(lng_cloud_password_almost))); + getDelegate()->show( + Box<InformBox>(lang(lng_cloud_password_almost)), + LayerOption::CloseOther); emit reloadPassword(); } return true; @@ -307,9 +309,9 @@ void PasscodeBox::save(bool force) { } if (!_recoverEmail->isHidden() && email.isEmpty() && !force) { _skipEmailWarning = true; - _replacedBy = Ui::show(Box<ConfirmBox>(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, base::lambda_guarded(this, [this] { + _replacedBy = getDelegate()->show(Box<ConfirmBox>(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton, base::lambda_guarded(this, [this] { save(true); - })), LayerOption::KeepOther); + }))); } else { QByteArray newPasswordData = pwd.isEmpty() ? QByteArray() : (_newSalt + pwd.toUtf8() + _newSalt); QByteArray newPasswordHash = pwd.isEmpty() ? QByteArray() : QByteArray(32, Qt::Uninitialized); @@ -407,9 +409,7 @@ void PasscodeBox::recoverExpired() { void PasscodeBox::recover() { if (_pattern == "-") return; - const auto box = Ui::show( - Box<RecoverBox>(_pattern), - LayerOption::KeepOther); + const auto box = getDelegate()->show(Box<RecoverBox>(_pattern)); connect(box, &RecoverBox::reloadPassword, this, &PasscodeBox::reloadPassword); connect(box, &RecoverBox::recoveryExpired, this, &PasscodeBox::recoverExpired); _replacedBy = box; @@ -494,7 +494,9 @@ void RecoverBox::codeSubmitDone(bool recover, const MTPauth_Authorization &resul _submitRequest = 0; emit reloadPassword(); - Ui::show(Box<InformBox>(lang(lng_cloud_password_removed))); + getDelegate()->show( + Box<InformBox>(lang(lng_cloud_password_removed)), + LayerOption::CloseOther); } bool RecoverBox::codeSubmitFail(const RPCError &error) { @@ -512,7 +514,9 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) { const QString &err = error.type(); if (err == qstr("PASSWORD_EMPTY")) { emit reloadPassword(); - Ui::show(Box<InformBox>(lang(lng_cloud_password_removed))); + getDelegate()->show( + Box<InformBox>(lang(lng_cloud_password_removed)), + LayerOption::CloseOther); return true; } else if (err == qstr("PASSWORD_RECOVERY_NA")) { closeBox(); diff --git a/Telegram/SourceFiles/passport/passport.style b/Telegram/SourceFiles/passport/passport.style index 627c0b1d4..9fa1d40ce 100644 --- a/Telegram/SourceFiles/passport/passport.style +++ b/Telegram/SourceFiles/passport/passport.style @@ -26,6 +26,9 @@ passportPasswordLabelBold: FlatLabel(passportPasswordLabel) { linkFontOver: font(boxFontSize semibold underline); } } +passportPasswordSetupLabel: FlatLabel(passportPasswordLabel) { + minWidth: 0px; +} passportPasswordHintLabel: passportPasswordLabel; passportErrorLabel: FlatLabel(passportPasswordLabel) { textFg: boxTextFgError; @@ -223,3 +226,8 @@ passportDetailsSkip: 30px; passportDetailsGenderSkip: 30px; passportRequestTypeSkip: 16px; + +passportPasswordAbout1Padding: margins(10px, 28px, 10px, 0px); +passportPasswordAbout2Padding: margins(10px, 0px, 10px, 28px); +passportPasswordIconHeight: 224px; +passportPasswordIcon: icon {{ "passport_password_setup", windowSubTextFg }}; diff --git a/Telegram/SourceFiles/passport/passport_form_controller.cpp b/Telegram/SourceFiles/passport/passport_form_controller.cpp index 3fb2e78c4..b5f8c7df5 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_form_controller.cpp @@ -388,6 +388,34 @@ void FormController::submitPassword(const QString &password) { }).send(); } +void FormController::reloadPassword() { + requestPassword(); +} + +void FormController::cancelPassword() { + if (_passwordRequestId) { + return; + } + _passwordRequestId = request(MTPaccount_UpdatePasswordSettings( + MTP_bytes(QByteArray()), + MTP_account_passwordInputSettings( + MTP_flags(MTPDaccount_passwordInputSettings::Flag::f_email), + MTP_bytes(QByteArray()), // new_salt + MTP_bytes(QByteArray()), // new_password_hash + MTP_string(QString()), // hint + MTP_string(QString()), // email + MTP_bytes(QByteArray()), // new_secure_salt + MTP_bytes(QByteArray()), // new_secure_secret + MTP_long(0)) // new_secure_secret_hash + )).done([=](const MTPBool &result) { + _passwordRequestId = 0; + reloadPassword(); + }).fail([=](const RPCError &error) { + _passwordRequestId = 0; + reloadPassword(); + }).send(); +} + void FormController::validateSecureSecret( bytes::const_span salt, bytes::const_span encryptedSecret, @@ -525,8 +553,8 @@ rpl::producer<QString> FormController::passwordError() const { return _passwordError.events(); } -QString FormController::passwordHint() const { - return _password.hint; +const PasswordSettings &FormController::passwordSettings() const { + return _password; } void FormController::uploadScan( @@ -1702,6 +1730,9 @@ void FormController::formFail(const QString &error) { } void FormController::requestPassword() { + if (_passwordRequestId) { + return; + } _passwordRequestId = request(MTPaccount_GetPassword( )).done([=](const MTPaccount_Password &result) { _passwordRequestId = 0; @@ -1733,14 +1764,13 @@ void FormController::showForm() { } if (!_password.salt.empty()) { _view->showAskPassword(); - } else if (!_password.unconfirmedPattern.isEmpty()) { - _view->showPasswordUnconfirmed(); } else { _view->showNoPassword(); } } void FormController::parsePassword(const MTPDaccount_noPassword &result) { + _password = PasswordSettings(); _password.unconfirmedPattern = qs(result.vemail_unconfirmed_pattern); _password.newSalt = bytes::make_vector(result.vnew_salt.v); _password.newSecureSalt = bytes::make_vector(result.vnew_secure_salt.v); @@ -1748,6 +1778,7 @@ void FormController::parsePassword(const MTPDaccount_noPassword &result) { } void FormController::parsePassword(const MTPDaccount_password &result) { + _password = PasswordSettings(); _password.hint = qs(result.vhint); _password.hasRecovery = mtpIsTrue(result.vhas_recovery); _password.salt = bytes::make_vector(result.vcurrent_salt.v); diff --git a/Telegram/SourceFiles/passport/passport_form_controller.h b/Telegram/SourceFiles/passport/passport_form_controller.h index 45f9d6e81..215d7e503 100644 --- a/Telegram/SourceFiles/passport/passport_form_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_controller.h @@ -217,7 +217,9 @@ public: std::vector<not_null<const Value*>> submitGetErrors(); void submitPassword(const QString &password); rpl::producer<QString> passwordError() const; - QString passwordHint() const; + const PasswordSettings &passwordSettings() const; + void reloadPassword(); + void cancelPassword(); bool canAddScan(not_null<const Value*> value) const; void uploadScan(not_null<const Value*> value, QByteArray &&content); diff --git a/Telegram/SourceFiles/passport/passport_form_view_controller.h b/Telegram/SourceFiles/passport/passport_form_view_controller.h index 6ef43feab..4a46b4e19 100644 --- a/Telegram/SourceFiles/passport/passport_form_view_controller.h +++ b/Telegram/SourceFiles/passport/passport_form_view_controller.h @@ -42,11 +42,13 @@ class ViewController { public: virtual void showAskPassword() = 0; virtual void showNoPassword() = 0; - virtual void showPasswordUnconfirmed() = 0; virtual void showCriticalError(const QString &error) = 0; virtual void editScope(int index) = 0; - virtual void showBox(object_ptr<BoxContent> box) = 0; + virtual void showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) = 0; virtual void showToast(const QString &text) = 0; virtual void suggestReset(base::lambda<void()> callback) = 0; @@ -56,9 +58,12 @@ public: } template <typename BoxType> - QPointer<BoxType> show(object_ptr<BoxType> content) { - auto result = QPointer<BoxType>(content.data()); - showBox(std::move(content)); + QPointer<BoxType> show( + object_ptr<BoxType> box, + LayerOptions options = LayerOption::KeepOther, + anim::type animated = anim::type::normal) { + auto result = QPointer<BoxType>(box.data()); + showBox(std::move(box), options, animated); return result; } diff --git a/Telegram/SourceFiles/passport/passport_panel.cpp b/Telegram/SourceFiles/passport/passport_panel.cpp index 7a47f254b..f7d464b00 100644 --- a/Telegram/SourceFiles/passport/passport_panel.cpp +++ b/Telegram/SourceFiles/passport/passport_panel.cpp @@ -226,12 +226,6 @@ void Panel::showNoPassword() { setBackAllowed(false); } -void Panel::showPasswordUnconfirmed() { - showInner( - base::make_unique_q<PanelPasswordUnconfirmed>(_body, _controller)); - setBackAllowed(false); -} - void Panel::showCriticalError(const QString &error) { auto container = base::make_unique_q<Ui::PaddingWrap<Ui::FlatLabel>>( _body, @@ -258,12 +252,12 @@ void Panel::showEditValue(object_ptr<Ui::RpWidget> from) { showInner(base::unique_qptr<Ui::RpWidget>(from.data())); } -void Panel::showBox(object_ptr<BoxContent> box) { +void Panel::showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) { ensureLayerCreated(); - _layer->showBox( - std::move(box), - LayerOption::KeepOther, - anim::type::normal); + _layer->showBox(std::move(box), options, animated); } void Panel::ensureLayerCreated() { diff --git a/Telegram/SourceFiles/passport/passport_panel.h b/Telegram/SourceFiles/passport/passport_panel.h index abb705f82..73ce87413 100644 --- a/Telegram/SourceFiles/passport/passport_panel.h +++ b/Telegram/SourceFiles/passport/passport_panel.h @@ -37,11 +37,13 @@ public: void showAskPassword(); void showNoPassword(); - void showPasswordUnconfirmed(); void showForm(); void showCriticalError(const QString &error); void showEditValue(object_ptr<Ui::RpWidget> form); - void showBox(object_ptr<BoxContent> box); + void showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated); rpl::producer<> backRequests() const; void setBackAllowed(bool allowed); diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.cpp b/Telegram/SourceFiles/passport/passport_panel_controller.cpp index 38ebb4e52..f9b036e0a 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_controller.cpp @@ -13,6 +13,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "passport/passport_panel_edit_contact.h" #include "passport/passport_panel_edit_scans.h" #include "passport/passport_panel.h" +#include "base/openssl_help.h" +#include "boxes/passcode_box.h" #include "boxes/confirm_box.h" #include "ui/toast/toast.h" #include "ui/countryinput.h" @@ -403,7 +405,11 @@ rpl::producer<QString> PanelController::passwordError() const { } QString PanelController::passwordHint() const { - return _form->passwordHint(); + return _form->passwordSettings().hint; +} + +QString PanelController::unconfirmedEmailPattern() const { + return _form->passwordSettings().unconfirmedPattern; } QString PanelController::defaultEmail() const { @@ -414,6 +420,40 @@ QString PanelController::defaultPhoneNumber() const { return _form->defaultPhoneNumber(); } +void PanelController::setupPassword() { + Expects(_panel != nullptr); + + const auto &settings = _form->passwordSettings(); + Assert(settings.salt.empty()); + + constexpr auto kRandomPart = 8; + auto newSalt = QByteArray( + reinterpret_cast<const char*>(settings.newSalt.data()), + settings.newSalt.size()); + newSalt.resize(newSalt.size() + kRandomPart); + bytes::set_random( + bytes::make_span(newSalt).subspan(settings.newSalt.size())); + const auto currentSalt = QByteArray(); + const auto hasRecovery = false; + const auto hint = QString(); + auto box = show(Box<PasscodeBox>( + newSalt, + currentSalt, + hasRecovery, + hint)); + box->connect(box, &PasscodeBox::reloadPassword, _panel.get(), [=] { + _form->reloadPassword(); + }); +} + +void PanelController::cancelPasswordSubmit() { + const auto box = std::make_shared<QPointer<BoxContent>>(); + *box = show(Box<ConfirmBox>( + lang(lng_passport_stop_password_sure), + lang(lng_passport_stop), + [=] { if (*box) (*box)->closeBox(); _form->cancelPassword(); })); +} + bool PanelController::canAddScan() const { Expects(_editScope != nullptr); Expects(_editDocument != nullptr); @@ -683,11 +723,6 @@ void PanelController::showNoPassword() { _panel->showNoPassword(); } -void PanelController::showPasswordUnconfirmed() { - ensurePanelCreated(); - _panel->showPasswordUnconfirmed(); -} - void PanelController::showCriticalError(const QString &error) { ensurePanelCreated(); _panel->showCriticalError(error); @@ -1060,8 +1095,11 @@ void PanelController::cancelAuth() { _form->cancel(); } -void PanelController::showBox(object_ptr<BoxContent> box) { - _panel->showBox(std::move(box)); +void PanelController::showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) { + _panel->showBox(std::move(box), options, animated); } void PanelController::showToast(const QString &text) { diff --git a/Telegram/SourceFiles/passport/passport_panel_controller.h b/Telegram/SourceFiles/passport/passport_panel_controller.h index 1adb33197..f2bf6fa19 100644 --- a/Telegram/SourceFiles/passport/passport_panel_controller.h +++ b/Telegram/SourceFiles/passport/passport_panel_controller.h @@ -69,6 +69,10 @@ public: void submitPassword(const QString &password); rpl::producer<QString> passwordError() const; QString passwordHint() const; + QString unconfirmedEmailPattern() const; + + void setupPassword(); + void cancelPasswordSubmit(); bool canAddScan() const; void uploadScan(QByteArray &&content); @@ -88,7 +92,6 @@ public: void showAskPassword() override; void showNoPassword() override; - void showPasswordUnconfirmed() override; void showCriticalError(const QString &error) override; void fillRows( @@ -106,7 +109,10 @@ public: const ValueMap &filesData) const; void cancelEditScope(); - void showBox(object_ptr<BoxContent> box) override; + void showBox( + object_ptr<BoxContent> box, + LayerOptions options, + anim::type animated) override; void showToast(const QString &text) override; void suggestReset(base::lambda<void()> callback) override; diff --git a/Telegram/SourceFiles/passport/passport_panel_form.cpp b/Telegram/SourceFiles/passport/passport_panel_form.cpp index af3258b03..f52dbad9a 100644 --- a/Telegram/SourceFiles/passport/passport_panel_form.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_form.cpp @@ -220,25 +220,25 @@ not_null<Ui::RpWidget*> PanelForm::setupContent() { _userpic->move((width - _userpic->width()) / 2, _userpic->y()); }, _userpic->lifetime()); - auto about1 = object_ptr<Ui::FlatLabel>( - inner, - lng_passport_request1(lt_bot, App::peerName(bot)), - Ui::FlatLabel::InitType::Simple, - st::passportPasswordLabelBold); - _about1 = about1.data(); - inner->add( - object_ptr<Ui::IgnoreNaturalWidth>(inner, std::move(about1)), - st::passportFormAbout1Padding); + _about1 = inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + inner, + object_ptr<Ui::FlatLabel>( + inner, + lng_passport_request1(lt_bot, App::peerName(bot)), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordLabelBold)), + st::passportFormAbout1Padding)->entity(); - auto about2 = object_ptr<Ui::FlatLabel>( - inner, - lang(lng_passport_request2), - Ui::FlatLabel::InitType::Simple, - st::passportPasswordLabel); - _about2 = about2.data(); - inner->add( - object_ptr<Ui::IgnoreNaturalWidth>(inner, std::move(about2)), - st::passportFormAbout2Padding); + _about2 = inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + inner, + object_ptr<Ui::FlatLabel>( + inner, + lang(lng_passport_request2), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordLabel)), + st::passportFormAbout2Padding)->entity(); inner->add(object_ptr<BoxContentDivider>( inner, diff --git a/Telegram/SourceFiles/passport/passport_panel_password.cpp b/Telegram/SourceFiles/passport/passport_panel_password.cpp index b5b8684a1..5596c01ae 100644 --- a/Telegram/SourceFiles/passport/passport_panel_password.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_password.cpp @@ -11,8 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/widgets/input_fields.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/wrap/padding_wrap.h" #include "ui/special_buttons.h" #include "lang/lang_keys.h" +#include "info/profile/info_profile_icon.h" #include "styles/style_passport.h" #include "styles/style_boxes.h" @@ -148,14 +151,96 @@ PanelNoPassword::PanelNoPassword( QWidget *parent, not_null<PanelController*> controller) : RpWidget(parent) -, _controller(controller) { +, _controller(controller) +, _inner(Ui::CreateChild<Ui::VerticalLayout>(this)) { + setupContent(); } -PanelPasswordUnconfirmed::PanelPasswordUnconfirmed( - QWidget *parent, - not_null<PanelController*> controller) -: RpWidget(parent) -, _controller(controller) { +void PanelNoPassword::setupContent() { + widthValue( + ) | rpl::start_with_next([=](int newWidth) { + _inner->resizeToWidth(newWidth); + }, _inner->lifetime()); + + const auto about1 = _inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + _inner, + object_ptr<Ui::FlatLabel>( + _inner, + lng_passport_request1( + lt_bot, + App::peerName(_controller->bot())), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordLabelBold)), + st::passportPasswordAbout1Padding)->entity(); + + const auto about2 = _inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + _inner, + object_ptr<Ui::FlatLabel>( + _inner, + lang(lng_passport_request2), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordLabel)), + st::passportPasswordAbout2Padding)->entity(); + + const auto iconWrap = _inner->add( + object_ptr<Ui::CenterWrap<Ui::FixedHeightWidget>>( + _inner, + object_ptr<Ui::FixedHeightWidget>( + _inner, + st::passportPasswordIconHeight))); + iconWrap->entity()->resizeToWidth(st::passportPasswordIcon.width()); + Ui::CreateChild<Info::Profile::FloatingIcon>( + iconWrap->entity(), + st::passportPasswordIcon, + QPoint(0, 0)); + + const auto about3 = _inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + _inner, + object_ptr<Ui::FlatLabel>( + _inner, + lang(lng_passport_create_password), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordSetupLabel)), + st::passportFormAbout2Padding)->entity(); + + refreshBottom(); +} + +void PanelNoPassword::refreshBottom() { + const auto pattern = _controller->unconfirmedEmailPattern(); + _about.reset(_inner->add( + object_ptr<Ui::CenterWrap<Ui::FlatLabel>>( + _inner, + object_ptr<Ui::FlatLabel>( + _inner, + (pattern.isEmpty() + ? lang(lng_passport_about_password) + : lng_passport_link_sent(lt_email, pattern)), + Ui::FlatLabel::InitType::Simple, + st::passportPasswordSetupLabel)), + st::passportFormAbout2Padding)->entity()); + const auto button = _inner->add( + object_ptr<Ui::CenterWrap<Ui::RoundButton>>( + _inner, + object_ptr<Ui::RoundButton>( + _inner, + langFactory(pattern.isEmpty() + ? lng_passport_password_create + : lng_cancel), + st::defaultBoxButton))); + if (pattern.isEmpty()) { + button->entity()->addClickHandler([=] { + _controller->setupPassword(); + }); + } else { + button->entity()->addClickHandler([=] { + _controller->cancelPasswordSubmit(); + }); + } + _button.reset(button); } } // namespace Passport diff --git a/Telegram/SourceFiles/passport/passport_panel_password.h b/Telegram/SourceFiles/passport/passport_panel_password.h index 2a6233d52..14de59bfd 100644 --- a/Telegram/SourceFiles/passport/passport_panel_password.h +++ b/Telegram/SourceFiles/passport/passport_panel_password.h @@ -15,6 +15,7 @@ class FlatLabel; class LinkButton; class RoundButton; class UserpicButton; +class VerticalLayout; } // namespace Ui namespace Passport { @@ -58,18 +59,14 @@ public: not_null<PanelController*> controller); private: + void setupContent(); + void refreshBottom(); + not_null<PanelController*> _controller; -}; - -class PanelPasswordUnconfirmed : public Ui::RpWidget { -public: - PanelPasswordUnconfirmed( - QWidget *parent, - not_null<PanelController*> controller); - -private: - not_null<PanelController*> _controller; + not_null<Ui::VerticalLayout*> _inner; + base::unique_qptr<Ui::RpWidget> _about; + base::unique_qptr<Ui::RpWidget> _button; }; diff --git a/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp index 100a986e1..33ec9ba23 100644 --- a/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp +++ b/Telegram/SourceFiles/ui/wrap/padding_wrap.cpp @@ -67,4 +67,35 @@ int PaddingWrap<RpWidget>::resizeGetHeight(int newWidth) { return heightNoMargins(); } +CenterWrap<RpWidget>::CenterWrap( + QWidget *parent, + object_ptr<RpWidget> &&child) +: Parent(parent, std::move(child)) { + if (const auto weak = wrapped()) { + wrappedSizeUpdated(weak->size()); + } +} + +int CenterWrap<RpWidget>::naturalWidth() const { + return -1; +} + +int CenterWrap<RpWidget>::resizeGetHeight(int newWidth) { + updateWrappedPosition(newWidth); + return heightNoMargins(); +} + +void CenterWrap<RpWidget>::wrappedSizeUpdated(QSize size) { + updateWrappedPosition(width()); +} + +void CenterWrap<RpWidget>::updateWrappedPosition(int forWidth) { + if (const auto weak = wrapped()) { + const auto margins = weak->getMargins(); + weak->moveToLeft( + (forWidth - weak->width()) / 2 + margins.left(), + margins.top()); + } +} + } // namespace Ui diff --git a/Telegram/SourceFiles/ui/wrap/padding_wrap.h b/Telegram/SourceFiles/ui/wrap/padding_wrap.h index 4f529a505..24bf1a888 100644 --- a/Telegram/SourceFiles/ui/wrap/padding_wrap.h +++ b/Telegram/SourceFiles/ui/wrap/padding_wrap.h @@ -54,6 +54,42 @@ public: }; +template <typename Widget = RpWidget> +class CenterWrap; + +template <> +class CenterWrap<RpWidget> : public Wrap<RpWidget> { + using Parent = Wrap<RpWidget>; + +public: + CenterWrap( + QWidget *parent, + object_ptr<RpWidget> &&child); + + int naturalWidth() const override; + +protected: + int resizeGetHeight(int newWidth) override; + void wrappedSizeUpdated(QSize size) override; + +private: + void updateWrappedPosition(int forWidth); + +}; + +template <typename Widget> +class CenterWrap : public Wrap<Widget, CenterWrap<RpWidget>> { + using Parent = Wrap<Widget, CenterWrap<RpWidget>>; + +public: + CenterWrap( + QWidget *parent, + object_ptr<Widget> &&child) + : Parent(parent, std::move(child)) { + } + +}; + class FixedHeightWidget : public RpWidget { public: FixedHeightWidget(QWidget *parent, int height) diff --git a/Telegram/SourceFiles/ui/wrap/wrap.h b/Telegram/SourceFiles/ui/wrap/wrap.h index be855168f..221dae1a3 100644 --- a/Telegram/SourceFiles/ui/wrap/wrap.h +++ b/Telegram/SourceFiles/ui/wrap/wrap.h @@ -183,24 +183,4 @@ private: }; -class IgnoreNaturalWidth : public Wrap<RpWidget> { - using Parent = Wrap<RpWidget>; - -public: - IgnoreNaturalWidth(QWidget *parent, object_ptr<RpWidget> &&child) - : Parent(parent, std::move(child)) { - if (auto weak = wrapped()) { - auto margins = weak->getMargins(); - resizeToWidth(weak->width() - - margins.left() - - margins.right()); - } - } - - int naturalWidth() const override { - return -1; - } - -}; - } // namespace Ui diff --git a/Telegram/SourceFiles/window/layer_widget.cpp b/Telegram/SourceFiles/window/layer_widget.cpp index 3a8ce5008..f5ef4d5d9 100644 --- a/Telegram/SourceFiles/window/layer_widget.cpp +++ b/Telegram/SourceFiles/window/layer_widget.cpp @@ -686,7 +686,7 @@ LayerWidget *LayerStackWidget::pushBox( if (_layers.size() > 1) { if (!_background->animating()) { - layer->show(); + layer->setVisible(true); showFinished(); } } else {