diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp index d084cc1bd..dbd6e4c2d 100644 --- a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp @@ -276,8 +276,18 @@ not_null EditCard::setupContent() { const auto showBox = [=](object_ptr box) { _delegate->panelShowBox(std::move(box)); }; + auto last = (Field*)nullptr; + const auto make = [&](QWidget *parent, FieldConfig &&config) { + auto result = std::make_unique(parent, std::move(config)); + if (last) { + last->setNextField(result.get()); + result->setPreviousField(last); + } + last = result.get(); + return result; + }; const auto add = [&](FieldConfig &&config) { - auto result = std::make_unique(inner, std::move(config)); + auto result = make(inner, std::move(config)); inner->add(result->ownedWidget(), st::paymentsFieldPadding); return result; }; @@ -291,12 +301,12 @@ not_null EditCard::setupContent() { inner, _number->widget()->height()), st::paymentsFieldPadding); - _expire = std::make_unique(container, FieldConfig{ + _expire = make(container, { .type = FieldType::CardExpireDate, .placeholder = rpl::single(u"MM / YY"_q), .validator = ExpireDateValidator(), }); - _cvc = std::make_unique(container, FieldConfig{ + _cvc = make(container, { .type = FieldType::CardCVC, .placeholder = rpl::single(u"CVC"_q), .validator = CvcValidator([=] { return _number->value(); }), @@ -319,15 +329,6 @@ not_null EditCard::setupContent() { }); } - _number->setNextField(_expire.get()); - _expire->setPreviousField(_number.get()); - _expire->setNextField(_cvc.get()); - _cvc->setPreviousField(_expire.get()); - if (_name) { - _cvc->setNextField(_name.get()); - _name->setPreviousField(_cvc.get()); - } - if (_native.needCountry || _native.needZip) { inner->add( object_ptr( @@ -366,6 +367,12 @@ not_null EditCard::setupContent() { false), st::paymentsSaveCheckboxPadding); } + + last->submitted( + ) | rpl::start_with_next([=] { + _delegate->panelValidateCard(collect(), _save && _save->checked()); + }, lifetime()); + return inner; } diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp index d62abd1ad..ab96a8a9e 100644 --- a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp @@ -113,9 +113,15 @@ not_null EditInformation::setupContent() { const auto showBox = [=](object_ptr box) { _delegate->panelShowBox(std::move(box)); }; + auto last = (Field*)nullptr; const auto add = [&](FieldConfig &&config) { auto result = std::make_unique(inner, std::move(config)); inner->add(result->ownedWidget(), st::paymentsFieldPadding); + if (last) { + last->setNextField(result.get()); + result->setPreviousField(last); + } + last = result.get(); return result; }; if (_invoice.isShippingAddressRequested) { @@ -200,6 +206,14 @@ not_null EditInformation::setupContent() { tr::lng_payments_save_information(tr::now), true), st::paymentsSaveCheckboxPadding); + + if (last) { + last->submitted( + ) | rpl::start_with_next([=] { + _delegate->panelValidateInformation(collect()); + }, lifetime()); + } + return inner; } diff --git a/Telegram/SourceFiles/payments/ui/payments_field.cpp b/Telegram/SourceFiles/payments/ui/payments_field.cpp index 287d6046b..f4d99fccd 100644 --- a/Telegram/SourceFiles/payments/ui/payments_field.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_field.cpp @@ -430,6 +430,7 @@ Field::Field(QWidget *parent, FieldConfig &&config) setupValidator(MoneyValidator(LookupCurrencyRule(config.currency))); } setupFrontBackspace(); + setupSubmit(); } RpWidget *Field::widget() const { @@ -455,6 +456,10 @@ rpl::producer<> Field::finished() const { return _finished.events(); } +rpl::producer<> Field::submitted() const { + return _submitted.events(); +} + void Field::setupMaskedGeometry() { Expects(_masked != nullptr); @@ -492,6 +497,13 @@ void Field::setupCountry() { _masked->setText(Data::CountryNameByISO2(iso2)); _masked->hideError(); raw->closeBox(); + if (!iso2.isEmpty()) { + if (_nextField) { + _nextField->activate(); + } else { + _submitted.fire({}); + } + } }, _masked->lifetime()); raw->boxClosing() | rpl::start_with_next([=] { setFocus(); @@ -563,6 +575,8 @@ void Field::setupValidator(Fn validator) { .nowValue = now.value, .nowPosition = now.position, }); + _valid = result.finished || !result.invalid; + const auto changed = (result.value != now.value); if (changed) { setText(result.value); @@ -609,7 +623,26 @@ void Field::setupFrontBackspace() { } } +void Field::setupSubmit() { + const auto submitted = [=] { + if (!_valid) { + showError(); + } else if (_nextField) { + _nextField->activate(); + } else { + _submitted.fire({}); + } + }; + if (_masked) { + QObject::connect(_masked, &MaskedInputField::submitted, submitted); + } else { + QObject::connect(_input, &InputField::submitted, submitted); + } +} + void Field::setNextField(not_null field) { + _nextField = field; + finished() | rpl::start_with_next([=] { field->setFocus(); }, _masked ? _masked->lifetime() : _input->lifetime()); @@ -622,16 +655,22 @@ void Field::setPreviousField(not_null field) { }, _masked ? _masked->lifetime() : _input->lifetime()); } -void Field::setFocus() { - if (_config.type == FieldType::Country) { - _wrap->setFocus(); - } else if (_input) { +void Field::activate() { + if (_input) { _input->setFocus(); } else { _masked->setFocus(); } } +void Field::setFocus() { + if (_config.type == FieldType::Country) { + _wrap->setFocus(); + } else { + activate(); + } +} + void Field::setFocusFast() { if (_config.type == FieldType::Country) { setFocus(); diff --git a/Telegram/SourceFiles/payments/ui/payments_field.h b/Telegram/SourceFiles/payments/ui/payments_field.h index 5c9c37109..26711ddd9 100644 --- a/Telegram/SourceFiles/payments/ui/payments_field.h +++ b/Telegram/SourceFiles/payments/ui/payments_field.h @@ -98,7 +98,9 @@ public: [[nodiscard]] QString value() const; [[nodiscard]] rpl::producer<> frontBackspace() const; [[nodiscard]] rpl::producer<> finished() const; + [[nodiscard]] rpl::producer<> submitted() const; + void activate(); void setFocus(); void setFocusFast(); void showError(); @@ -120,17 +122,21 @@ private: void setupCountry(); void setupValidator(Fn validator); void setupFrontBackspace(); + void setupSubmit(); const FieldConfig _config; const base::unique_qptr _wrap; rpl::event_stream<> _frontBackspace; rpl::event_stream<> _finished; + rpl::event_stream<> _submitted; rpl::event_stream<> _textPossiblyChanged; // Must be above _masked. InputField *_input = nullptr; MaskedInputField *_masked = nullptr; + Field *_nextField = nullptr; QString _countryIso2; State _was; bool _validating = false; + bool _valid = true; };