Always jump to next field in payments.

This commit is contained in:
John Preston 2021-04-01 19:06:48 +04:00
parent 491ec2db7f
commit bdffdea358
4 changed files with 82 additions and 16 deletions

View file

@ -276,8 +276,18 @@ not_null<RpWidget*> EditCard::setupContent() {
const auto showBox = [=](object_ptr<BoxContent> box) { const auto showBox = [=](object_ptr<BoxContent> box) {
_delegate->panelShowBox(std::move(box)); _delegate->panelShowBox(std::move(box));
}; };
auto last = (Field*)nullptr;
const auto make = [&](QWidget *parent, FieldConfig &&config) {
auto result = std::make_unique<Field>(parent, std::move(config));
if (last) {
last->setNextField(result.get());
result->setPreviousField(last);
}
last = result.get();
return result;
};
const auto add = [&](FieldConfig &&config) { const auto add = [&](FieldConfig &&config) {
auto result = std::make_unique<Field>(inner, std::move(config)); auto result = make(inner, std::move(config));
inner->add(result->ownedWidget(), st::paymentsFieldPadding); inner->add(result->ownedWidget(), st::paymentsFieldPadding);
return result; return result;
}; };
@ -291,12 +301,12 @@ not_null<RpWidget*> EditCard::setupContent() {
inner, inner,
_number->widget()->height()), _number->widget()->height()),
st::paymentsFieldPadding); st::paymentsFieldPadding);
_expire = std::make_unique<Field>(container, FieldConfig{ _expire = make(container, {
.type = FieldType::CardExpireDate, .type = FieldType::CardExpireDate,
.placeholder = rpl::single(u"MM / YY"_q), .placeholder = rpl::single(u"MM / YY"_q),
.validator = ExpireDateValidator(), .validator = ExpireDateValidator(),
}); });
_cvc = std::make_unique<Field>(container, FieldConfig{ _cvc = make(container, {
.type = FieldType::CardCVC, .type = FieldType::CardCVC,
.placeholder = rpl::single(u"CVC"_q), .placeholder = rpl::single(u"CVC"_q),
.validator = CvcValidator([=] { return _number->value(); }), .validator = CvcValidator([=] { return _number->value(); }),
@ -319,15 +329,6 @@ not_null<RpWidget*> 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) { if (_native.needCountry || _native.needZip) {
inner->add( inner->add(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
@ -366,6 +367,12 @@ not_null<RpWidget*> EditCard::setupContent() {
false), false),
st::paymentsSaveCheckboxPadding); st::paymentsSaveCheckboxPadding);
} }
last->submitted(
) | rpl::start_with_next([=] {
_delegate->panelValidateCard(collect(), _save && _save->checked());
}, lifetime());
return inner; return inner;
} }

View file

@ -113,9 +113,15 @@ not_null<RpWidget*> EditInformation::setupContent() {
const auto showBox = [=](object_ptr<BoxContent> box) { const auto showBox = [=](object_ptr<BoxContent> box) {
_delegate->panelShowBox(std::move(box)); _delegate->panelShowBox(std::move(box));
}; };
auto last = (Field*)nullptr;
const auto add = [&](FieldConfig &&config) { const auto add = [&](FieldConfig &&config) {
auto result = std::make_unique<Field>(inner, std::move(config)); auto result = std::make_unique<Field>(inner, std::move(config));
inner->add(result->ownedWidget(), st::paymentsFieldPadding); inner->add(result->ownedWidget(), st::paymentsFieldPadding);
if (last) {
last->setNextField(result.get());
result->setPreviousField(last);
}
last = result.get();
return result; return result;
}; };
if (_invoice.isShippingAddressRequested) { if (_invoice.isShippingAddressRequested) {
@ -200,6 +206,14 @@ not_null<RpWidget*> EditInformation::setupContent() {
tr::lng_payments_save_information(tr::now), tr::lng_payments_save_information(tr::now),
true), true),
st::paymentsSaveCheckboxPadding); st::paymentsSaveCheckboxPadding);
if (last) {
last->submitted(
) | rpl::start_with_next([=] {
_delegate->panelValidateInformation(collect());
}, lifetime());
}
return inner; return inner;
} }

View file

@ -430,6 +430,7 @@ Field::Field(QWidget *parent, FieldConfig &&config)
setupValidator(MoneyValidator(LookupCurrencyRule(config.currency))); setupValidator(MoneyValidator(LookupCurrencyRule(config.currency)));
} }
setupFrontBackspace(); setupFrontBackspace();
setupSubmit();
} }
RpWidget *Field::widget() const { RpWidget *Field::widget() const {
@ -455,6 +456,10 @@ rpl::producer<> Field::finished() const {
return _finished.events(); return _finished.events();
} }
rpl::producer<> Field::submitted() const {
return _submitted.events();
}
void Field::setupMaskedGeometry() { void Field::setupMaskedGeometry() {
Expects(_masked != nullptr); Expects(_masked != nullptr);
@ -492,6 +497,13 @@ void Field::setupCountry() {
_masked->setText(Data::CountryNameByISO2(iso2)); _masked->setText(Data::CountryNameByISO2(iso2));
_masked->hideError(); _masked->hideError();
raw->closeBox(); raw->closeBox();
if (!iso2.isEmpty()) {
if (_nextField) {
_nextField->activate();
} else {
_submitted.fire({});
}
}
}, _masked->lifetime()); }, _masked->lifetime());
raw->boxClosing() | rpl::start_with_next([=] { raw->boxClosing() | rpl::start_with_next([=] {
setFocus(); setFocus();
@ -563,6 +575,8 @@ void Field::setupValidator(Fn<ValidateResult(ValidateRequest)> validator) {
.nowValue = now.value, .nowValue = now.value,
.nowPosition = now.position, .nowPosition = now.position,
}); });
_valid = result.finished || !result.invalid;
const auto changed = (result.value != now.value); const auto changed = (result.value != now.value);
if (changed) { if (changed) {
setText(result.value); 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*> field) { void Field::setNextField(not_null<Field*> field) {
_nextField = field;
finished() | rpl::start_with_next([=] { finished() | rpl::start_with_next([=] {
field->setFocus(); field->setFocus();
}, _masked ? _masked->lifetime() : _input->lifetime()); }, _masked ? _masked->lifetime() : _input->lifetime());
@ -622,16 +655,22 @@ void Field::setPreviousField(not_null<Field*> field) {
}, _masked ? _masked->lifetime() : _input->lifetime()); }, _masked ? _masked->lifetime() : _input->lifetime());
} }
void Field::setFocus() { void Field::activate() {
if (_config.type == FieldType::Country) { if (_input) {
_wrap->setFocus();
} else if (_input) {
_input->setFocus(); _input->setFocus();
} else { } else {
_masked->setFocus(); _masked->setFocus();
} }
} }
void Field::setFocus() {
if (_config.type == FieldType::Country) {
_wrap->setFocus();
} else {
activate();
}
}
void Field::setFocusFast() { void Field::setFocusFast() {
if (_config.type == FieldType::Country) { if (_config.type == FieldType::Country) {
setFocus(); setFocus();

View file

@ -98,7 +98,9 @@ public:
[[nodiscard]] QString value() const; [[nodiscard]] QString value() const;
[[nodiscard]] rpl::producer<> frontBackspace() const; [[nodiscard]] rpl::producer<> frontBackspace() const;
[[nodiscard]] rpl::producer<> finished() const; [[nodiscard]] rpl::producer<> finished() const;
[[nodiscard]] rpl::producer<> submitted() const;
void activate();
void setFocus(); void setFocus();
void setFocusFast(); void setFocusFast();
void showError(); void showError();
@ -120,17 +122,21 @@ private:
void setupCountry(); void setupCountry();
void setupValidator(Fn<ValidateResult(ValidateRequest)> validator); void setupValidator(Fn<ValidateResult(ValidateRequest)> validator);
void setupFrontBackspace(); void setupFrontBackspace();
void setupSubmit();
const FieldConfig _config; const FieldConfig _config;
const base::unique_qptr<RpWidget> _wrap; const base::unique_qptr<RpWidget> _wrap;
rpl::event_stream<> _frontBackspace; rpl::event_stream<> _frontBackspace;
rpl::event_stream<> _finished; rpl::event_stream<> _finished;
rpl::event_stream<> _submitted;
rpl::event_stream<> _textPossiblyChanged; // Must be above _masked. rpl::event_stream<> _textPossiblyChanged; // Must be above _masked.
InputField *_input = nullptr; InputField *_input = nullptr;
MaskedInputField *_masked = nullptr; MaskedInputField *_masked = nullptr;
Field *_nextField = nullptr;
QString _countryIso2; QString _countryIso2;
State _was; State _was;
bool _validating = false; bool _validating = false;
bool _valid = true;
}; };