| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /*
- 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 "passport/passport_panel_edit_contact.h"
- #include "core/file_utilities.h"
- #include "passport/passport_panel_controller.h"
- #include "passport/ui/passport_details_row.h"
- #include "ui/widgets/fields/input_field.h"
- #include "ui/widgets/labels.h"
- #include "ui/widgets/buttons.h"
- #include "ui/widgets/shadow.h"
- #include "ui/widgets/box_content_divider.h"
- #include "ui/widgets/sent_code_field.h"
- #include "ui/wrap/vertical_layout.h"
- #include "ui/wrap/slide_wrap.h"
- #include "ui/wrap/fade_wrap.h"
- #include "ui/text/format_values.h" // Ui::FormatPhone
- #include "ui/text/text_utilities.h" // Ui::Text::ToUpper
- #include "ui/widgets/fields/special_fields.h"
- #include "boxes/abstract_box.h"
- #include "data/data_user.h"
- #include "countries/countries_instance.h" // Countries::ExtractPhoneCode.
- #include "main/main_session.h"
- #include "lang/lang_keys.h"
- #include "styles/style_boxes.h"
- #include "styles/style_passport.h"
- #include "styles/style_layers.h"
- namespace Passport {
- namespace {
- class VerifyBox : public Ui::BoxContent {
- public:
- VerifyBox(
- QWidget*,
- rpl::producer<QString> title,
- const QString &text,
- int codeLength,
- const QString &openUrl,
- Fn<void(QString code)> submit,
- Fn<void()> resend,
- rpl::producer<QString> call,
- rpl::producer<QString> error,
- rpl::producer<QString> resent);
- void setInnerFocus() override;
- protected:
- void prepare() override;
- private:
- void setupControls(
- const QString &text,
- int codeLength,
- const QString &openUrl,
- Fn<void(QString code)> submit,
- Fn<void()> resend,
- rpl::producer<QString> call,
- rpl::producer<QString> error,
- rpl::producer<QString> resent);
- rpl::producer<QString> _title;
- Fn<void()> _submit;
- QPointer<Ui::SentCodeField> _code;
- QPointer<Ui::VerticalLayout> _content;
- };
- VerifyBox::VerifyBox(
- QWidget*,
- rpl::producer<QString> title,
- const QString &text,
- int codeLength,
- const QString &openUrl,
- Fn<void(QString code)> submit,
- Fn<void()> resend,
- rpl::producer<QString> call,
- rpl::producer<QString> error,
- rpl::producer<QString> resent)
- : _title(std::move(title)) {
- setupControls(
- text,
- codeLength,
- openUrl,
- submit,
- resend,
- std::move(call),
- std::move(error),
- std::move(resent));
- }
- void VerifyBox::setupControls(
- const QString &text,
- int codeLength,
- const QString &openUrl,
- Fn<void(QString code)> submit,
- Fn<void()> resend,
- rpl::producer<QString> call,
- rpl::producer<QString> error,
- rpl::producer<QString> resent) {
- _content = Ui::CreateChild<Ui::VerticalLayout>(this);
- const auto small = style::margins(
- st::boxPadding.left(),
- 0,
- st::boxPadding.right(),
- st::boxPadding.bottom());
- _content->add(
- object_ptr<Ui::FlatLabel>(
- _content,
- text,
- st::boxLabel),
- small);
- _code = _content->add(
- object_ptr<Ui::SentCodeField>(
- _content,
- st::defaultInputField,
- tr::lng_change_phone_code_title()),
- small);
- const auto problem = _content->add(
- object_ptr<Ui::FadeWrap<Ui::FlatLabel>>(
- _content,
- object_ptr<Ui::FlatLabel>(
- _content,
- QString(),
- st::passportVerifyErrorLabel)),
- small);
- _content->add(
- object_ptr<Ui::FlatLabel>(
- _content,
- std::move(call),
- st::boxDividerLabel),
- small);
- if (!openUrl.isEmpty()) {
- const auto button = _content->add(
- object_ptr<Ui::RoundButton>(
- _content,
- tr::lng_intro_fragment_button(),
- st::fragmentBoxButton),
- small);
- _content->widthValue(
- ) | rpl::start_with_next([=](int w) {
- button->setFullWidth(w - small.left() - small.right());
- }, button->lifetime());
- button->setClickedCallback([=] { ::File::OpenUrl(openUrl); });
- button->setTextTransform(
- Ui::RoundButton::TextTransform::NoTransform);
- }
- if (resend) {
- auto link = TextWithEntities{ tr::lng_cloud_password_resend(tr::now) };
- link.entities.push_back({
- EntityType::CustomUrl,
- 0,
- int(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(TextWithEntities::Simple)),
- st::boxDividerLabel),
- small);
- std::move(
- resent
- ) | rpl::start_with_next([=] {
- _content->resizeToWidth(st::boxWidth);
- }, _content->lifetime());
- label->overrideLinkClickHandler(resend);
- }
- std::move(
- error
- ) | rpl::start_with_next([=](const QString &error) {
- if (error.isEmpty()) {
- problem->hide(anim::type::normal);
- } else {
- problem->entity()->setText(error);
- _content->resizeToWidth(st::boxWidth);
- problem->show(anim::type::normal);
- _code->showError();
- }
- }, lifetime());
- _submit = [=] {
- submit(_code->getDigitsOnly());
- };
- if (codeLength > 0) {
- _code->setAutoSubmit(codeLength, _submit);
- } else {
- _code->submits() | rpl::start_with_next(_submit, _code->lifetime());
- }
- _code->changes(
- ) | rpl::start_with_next([=] {
- problem->hide(anim::type::normal);
- }, _code->lifetime());
- }
- void VerifyBox::setInnerFocus() {
- _code->setFocusFast();
- }
- void VerifyBox::prepare() {
- setTitle(std::move(_title));
- addButton(tr::lng_change_phone_new_submit(), _submit);
- addButton(tr::lng_cancel(), [=] { closeBox(); });
- _content->resizeToWidth(st::boxWidth);
- _content->heightValue(
- ) | rpl::start_with_next([=](int height) {
- setDimensions(st::boxWidth, height);
- }, _content->lifetime());
- }
- } // namespace
- EditContactScheme::EditContactScheme(ValueType type) : type(type) {
- }
- PanelEditContact::PanelEditContact(
- QWidget*,
- not_null<PanelController*> controller,
- Scheme scheme,
- const QString &data,
- const QString &existing)
- : _controller(controller)
- , _scheme(std::move(scheme))
- , _content(this)
- , _bottomShadow(this)
- , _done(
- this,
- tr::lng_passport_save_value(),
- st::passportPanelSaveValue) {
- setupControls(data, existing);
- }
- void PanelEditContact::setupControls(
- const QString &data,
- const QString &existing) {
- widthValue(
- ) | rpl::start_with_next([=](int width) {
- _content->resizeToWidth(width);
- }, _content->lifetime());
- _content->add(object_ptr<Ui::BoxContentDivider>(
- _content,
- st::passportFormDividerHeight));
- if (!existing.isEmpty()) {
- _content->add(
- object_ptr<Ui::SettingsButton>(
- _content,
- tr::lng_passport_use_existing(
- lt_existing,
- rpl::single(_scheme.format
- ? _scheme.format(existing)
- : existing)),
- st::passportUploadButton),
- st::passportUploadButtonPadding
- )->addClickHandler([=] {
- save(existing);
- });
- _content->add(
- object_ptr<Ui::DividerLabel>(
- _content,
- object_ptr<Ui::FlatLabel>(
- _content,
- _scheme.aboutExisting,
- st::boxDividerLabel),
- st::passportFormLabelPadding));
- _content->add(
- object_ptr<Ui::FlatLabel>(
- _content,
- _scheme.newHeader,
- st::passportFormHeader),
- st::passportDetailsHeaderPadding);
- }
- const auto &fieldStyle = existing.isEmpty()
- ? st::passportContactField
- : st::passportDetailsField;
- const auto fieldPadding = existing.isEmpty()
- ? st::passportContactFieldPadding
- : st::passportContactNewFieldPadding;
- auto fieldPlaceholder = existing.isEmpty()
- ? rpl::duplicate(_scheme.newPlaceholder)
- : nullptr;
- auto wrap = object_ptr<Ui::RpWidget>(_content);
- if (_scheme.type == Scheme::ValueType::Phone) {
- _field = Ui::CreateChild<Ui::PhoneInput>(
- wrap.data(),
- fieldStyle,
- std::move(fieldPlaceholder),
- Countries::ExtractPhoneCode(
- _controller->bot()->session().user()->phone()),
- data,
- [](const QString &s) { return Countries::Groups(s); });
- } else {
- _field = Ui::CreateChild<Ui::MaskedInputField>(
- wrap.data(),
- fieldStyle,
- std::move(fieldPlaceholder),
- data);
- }
- _field->move(0, 0);
- _field->heightValue(
- ) | rpl::start_with_next([=, pointer = wrap.data()](int height) {
- pointer->resize(pointer->width(), height);
- }, _field->lifetime());
- wrap->widthValue(
- ) | rpl::start_with_next([=](int width) {
- _field->resize(width, _field->height());
- }, _field->lifetime());
- _content->add(std::move(wrap), fieldPadding);
- const auto errorWrap = _content->add(
- object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
- _content,
- object_ptr<Ui::FlatLabel>(
- _content,
- QString(),
- st::passportVerifyErrorLabel),
- st::passportContactErrorPadding),
- st::passportContactErrorMargin);
- errorWrap->hide(anim::type::instant);
- _content->add(
- object_ptr<Ui::DividerLabel>(
- _content,
- object_ptr<Ui::FlatLabel>(
- _content,
- _scheme.aboutNew,
- st::boxDividerLabel),
- st::passportFormLabelPadding));
- if (auto text = _controller->deleteValueLabel()) {
- _content->add(
- object_ptr<Ui::SettingsButton>(
- _content,
- std::move(*text) | Ui::Text::ToUpper(),
- st::passportDeleteButton),
- st::passportUploadButtonPadding
- )->addClickHandler([=] {
- _controller->deleteValue();
- });
- }
- _controller->saveErrors(
- ) | rpl::start_with_next([=](const ScopeError &error) {
- if (error.key == QString("value")) {
- _field->showError();
- errorWrap->entity()->setText(error.text);
- _content->resizeToWidth(width());
- errorWrap->show(anim::type::normal);
- }
- }, lifetime());
- const auto submit = [=] {
- crl::on_main(this, [=] {
- save();
- });
- };
- connect(_field, &Ui::MaskedInputField::submitted, submit);
- connect(_field, &Ui::MaskedInputField::changed, [=] {
- errorWrap->hide(anim::type::normal);
- });
- _done->addClickHandler(submit);
- }
- void PanelEditContact::focusInEvent(QFocusEvent *e) {
- crl::on_main(this, [=] {
- _field->setFocusFast();
- });
- }
- void PanelEditContact::resizeEvent(QResizeEvent *e) {
- updateControlsGeometry();
- }
- void PanelEditContact::updateControlsGeometry() {
- const auto submitTop = height() - _done->height();
- _bottomShadow->resizeToWidth(width());
- _bottomShadow->moveToLeft(0, submitTop - st::lineWidth);
- _done->resizeToWidth(width());
- _done->moveToLeft(0, submitTop);
- }
- void PanelEditContact::save() {
- const auto result = _field->getLastText();
- const auto processed = _scheme.postprocess
- ? _scheme.postprocess(result)
- : result;
- if (_scheme.validate && !_scheme.validate(processed)) {
- _field->showError();
- return;
- }
- save(processed);
- }
- void PanelEditContact::save(const QString &value) {
- auto data = ValueMap();
- data.fields["value"].text = value;
- _controller->saveScope(std::move(data), {});
- }
- object_ptr<Ui::BoxContent> VerifyPhoneBox(
- const QString &phone,
- int codeLength,
- const QString &openUrl,
- Fn<void(QString code)> submit,
- rpl::producer<QString> call,
- rpl::producer<QString> error) {
- return Box<VerifyBox>(
- tr::lng_passport_phone_title(),
- tr::lng_passport_confirm_phone(
- tr::now,
- lt_phone,
- Ui::FormatPhone(phone)),
- codeLength,
- openUrl,
- submit,
- nullptr,
- std::move(call),
- std::move(error),
- nullptr);
- }
- object_ptr<Ui::BoxContent> VerifyEmailBox(
- const QString &email,
- int codeLength,
- Fn<void(QString code)> submit,
- Fn<void()> resend,
- rpl::producer<QString> error,
- rpl::producer<QString> resent) {
- return Box<VerifyBox>(
- tr::lng_passport_email_title(),
- tr::lng_passport_confirm_email(tr::now, lt_email, email),
- codeLength,
- QString(),
- submit,
- resend,
- rpl::single(QString()),
- std::move(error),
- std::move(resent));
- }
- } // namespace Passport
|