summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Preston <johnprestonmail@gmail.com>2021-03-26 19:23:12 +0400
committerJohn Preston <johnprestonmail@gmail.com>2021-03-26 19:23:12 +0400
commit9a722ea8d47e50233d6aababff36853fba1f438a (patch)
treed4479e8b86345e756520771e01058d98821e79f5
parent1aefada45d0db1bef0776f31a7036600e4b77f8f (diff)
Improve checkout information / card page design.
-rw-r--r--Telegram/Resources/langs/lang.strings3
-rw-r--r--Telegram/SourceFiles/payments/payments_checkout_process.cpp26
-rw-r--r--Telegram/SourceFiles/payments/payments_checkout_process.h2
-rw-r--r--Telegram/SourceFiles/payments/ui/payments.style11
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_edit_card.cpp193
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_edit_card.h24
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_edit_information.cpp251
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_edit_information.h33
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_field.cpp140
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_field.h62
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_form_summary.cpp15
-rw-r--r--Telegram/SourceFiles/payments/ui/payments_panel.cpp19
-rw-r--r--Telegram/cmake/td_ui.cmake2
13 files changed, 465 insertions, 316 deletions
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 6be8d6bd0b..3f49c3076d 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1866,7 +1866,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_payments_payment_method" = "Payment Method";
"lng_payments_new_card" = "New Card...";
"lng_payments_shipping_address" = "Shipping Address";
-"lng_payments_receiver_information" = "Receiver";
"lng_payments_address_street1" = "Address 1";
"lng_payments_address_street2" = "Address 2";
"lng_payments_address_city" = "City";
@@ -1878,7 +1877,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_payments_info_name" = "Name";
"lng_payments_info_email" = "Email";
"lng_payments_info_phone" = "Phone";
-"lng_payments_shipping_address_title" = "Shipping Address";
+"lng_payments_shipping_address_title" = "Shipping Information";
"lng_payments_save_shipping_about" = "You can save your shipping information for future use.";
"lng_payments_card_title" = "New Card";
"lng_payments_card_number" = "Card Number";
diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.cpp b/Telegram/SourceFiles/payments/payments_checkout_process.cpp
index 5b7287066f..aba6d5e5a2 100644
--- a/Telegram/SourceFiles/payments/payments_checkout_process.cpp
+++ b/Telegram/SourceFiles/payments/payments_checkout_process.cpp
@@ -87,6 +87,7 @@ CheckoutProcess::CheckoutProcess(
) | rpl::start_with_next([=] {
showForm();
}, _panel->lifetime());
+ showForm();
}
CheckoutProcess::~CheckoutProcess() {
@@ -156,7 +157,7 @@ void CheckoutProcess::handleError(const Error &error) {
showToast({ "Error: " + id });
}
break;
- case Error::Type::Validate:
+ case Error::Type::Validate: {
if (_submitState == SubmitState::Validation) {
_submitState = SubmitState::None;
}
@@ -189,7 +190,21 @@ void CheckoutProcess::handleError(const Error &error) {
} else {
showToast({ "Error: " + id });
}
- break;
+ } break;
+ case Error::Type::Stripe: {
+ using Field = Ui::CardField;
+ if (id == u"InvalidNumber"_q || id == u"IncorrectNumber"_q) {
+ showCardError(Field::Number);
+ } else if (id == u"InvalidCVC"_q || id == u"IncorrectCVC"_q) {
+ showCardError(Field::CVC);
+ } else if (id == u"InvalidExpiryMonth"_q
+ || id == u"InvalidExpiryYear"_q
+ || id == u"ExpiredCard"_q) {
+ showCardError(Field::ExpireDate);
+ } else {
+ showToast({ "Error: " + id });
+ }
+ } break;
case Error::Type::Send:
if (_submitState == SubmitState::Finishing) {
_submitState = SubmitState::None;
@@ -375,6 +390,13 @@ void CheckoutProcess::showInformationError(Ui::InformationField field) {
field);
}
+void CheckoutProcess::showCardError(Ui::CardField field) {
+ if (_submitState != SubmitState::None) {
+ return;
+ }
+ _panel->showCardError(_form->paymentMethod().ui.native, field);
+}
+
void CheckoutProcess::chooseShippingOption() {
_panel->chooseShippingOption(_form->shippingOptions());
}
diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.h b/Telegram/SourceFiles/payments/payments_checkout_process.h
index 636915071e..de9d37724b 100644
--- a/Telegram/SourceFiles/payments/payments_checkout_process.h
+++ b/Telegram/SourceFiles/payments/payments_checkout_process.h
@@ -19,6 +19,7 @@ class Session;
namespace Payments::Ui {
class Panel;
enum class InformationField;
+enum class CardField;
} // namespace Payments::Ui
namespace Payments {
@@ -58,6 +59,7 @@ private:
void showForm();
void showEditInformation(Ui::InformationField field);
void showInformationError(Ui::InformationField field);
+ void showCardError(Ui::CardField field);
void chooseShippingOption();
void editPaymentMethod();
diff --git a/Telegram/SourceFiles/payments/ui/payments.style b/Telegram/SourceFiles/payments/ui/payments.style
index 811f70160b..20e44354a4 100644
--- a/Telegram/SourceFiles/payments/ui/payments.style
+++ b/Telegram/SourceFiles/payments/ui/payments.style
@@ -56,3 +56,14 @@ paymentsIconName: icon {{ "payments/payment_name", menuIconFg }};
paymentsIconEmail: icon {{ "payments/payment_email", menuIconFg }};
paymentsIconPhone: icon {{ "payments/payment_phone", menuIconFg }};
paymentsIconShippingMethod: icon {{ "payments/payment_shipping", menuIconFg }};
+
+paymentsField: defaultInputField;
+paymentsFieldPadding: margins(28px, 0px, 28px, 2px);
+paymentsExpireCvcSkip: 34px;
+
+paymentsBillingInformationTitle: FlatLabel(defaultFlatLabel) {
+ style: semiboldTextStyle;
+ textFg: windowActiveTextFg;
+ minWidth: 240px;
+}
+paymentsBillingInformationTitlePadding: margins(28px, 26px, 28px, 1px);
diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp
index 7d5918e9f1..8d647a174f 100644
--- a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp
+++ b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/ui/payments_edit_card.h"
#include "payments/ui/payments_panel_delegate.h"
-#include "passport/ui/passport_details_row.h"
+#include "payments/ui/payments_field.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
@@ -52,16 +52,24 @@ EditCard::EditCard(
void EditCard::setFocus(CardField field) {
_focusField = field;
- if (const auto control = controlForField(field)) {
- _scroll->ensureWidgetVisible(control);
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
+ control->setFocus();
+ }
+}
+
+void EditCard::setFocusFast(CardField field) {
+ _focusField = field;
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
control->setFocusFast();
}
}
void EditCard::showError(CardField field) {
- if (const auto control = controlForField(field)) {
- _scroll->ensureWidgetVisible(control);
- control->showError(QString());
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
+ control->showError();
}
}
@@ -95,102 +103,69 @@ not_null<RpWidget*> EditCard::setupContent() {
const auto showBox = [=](object_ptr<BoxContent> box) {
_delegate->panelShowBox(std::move(box));
};
- using Type = Passport::Ui::PanelDetailsType;
- auto maxLabelWidth = 0;
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("Card Number"));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("CVC"));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("MM/YY"));
+ const auto add = [&](FieldConfig &&config) {
+ auto result = std::make_unique<Field>(inner, std::move(config));
+ inner->add(result->ownedWidget(), st::paymentsFieldPadding);
+ return result;
+ };
+ _number = add({
+ .type = FieldType::CardNumber,
+ .placeholder = tr::lng_payments_card_number(),
+ .required = true,
+ });
if (_native.needCardholderName) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("Cardholder Name"));
- }
- if (_native.needCountry) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("Billing Country"));
- }
- if (_native.needZip) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth("Billing Zip"));
+ _name = add({
+ .type = FieldType::CardNumber,
+ .placeholder = tr::lng_payments_card_holder(),
+ .required = true,
+ });
}
- _number = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- "Card Number",
- maxLabelWidth,
- QString(),
- QString(),
- 1024));
- _cvc = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- "CVC",
- maxLabelWidth,
- QString(),
- QString(),
- 1024));
- _expire = inner->add(
- Row::Create(
+ auto container = inner->add(
+ object_ptr<FixedHeightWidget>(
inner,
- showBox,
- QString(),
- Type::Text,
- "MM/YY",
- maxLabelWidth,
- QString(),
- QString(),
- 1024));
- if (_native.needCardholderName) {
- _name = inner->add(
- Row::Create(
+ _number->widget()->height()),
+ st::paymentsFieldPadding);
+ _expire = std::make_unique<Field>(container, FieldConfig{
+ .type = FieldType::CardExpireDate,
+ .placeholder = rpl::single(u"MM / YY"_q),
+ .required = true,
+ });
+ _cvc = std::make_unique<Field>(container, FieldConfig{
+ .type = FieldType::CardCVC,
+ .placeholder = rpl::single(u"CVC"_q),
+ .required = true,
+ });
+ container->widthValue(
+ ) | rpl::start_with_next([=](int width) {
+ const auto left = (width - st::paymentsExpireCvcSkip) / 2;
+ const auto right = width - st::paymentsExpireCvcSkip - left;
+ _expire->widget()->resizeToWidth(left);
+ _cvc->widget()->resizeToWidth(right);
+ _expire->widget()->moveToLeft(0, 0, width);
+ _cvc->widget()->moveToRight(0, 0, width);
+ }, container->lifetime());
+ if (_native.needCountry || _native.needZip) {
+ inner->add(
+ object_ptr<Ui::FlatLabel>(
inner,
- showBox,
- QString(),
- Type::Text,
- "Cardholder Name",
- maxLabelWidth,
- QString(),
- QString(),
- 1024));
+ tr::lng_payments_billing_address(),
+ st::paymentsBillingInformationTitle),
+ st::paymentsBillingInformationTitlePadding);
}
if (_native.needCountry) {
- _country = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Country,
- "Billing Country",
- maxLabelWidth,
- QString(),
- QString()));
+ _country = add({
+ .type = FieldType::Country,
+ .placeholder = tr::lng_payments_billing_country(),
+ .required = true,
+ });
}
if (_native.needZip) {
- _zip = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Postcode,
- "Billing Zip Code",
- maxLabelWidth,
- QString(),
- QString(),
- kMaxPostcodeSize));
+ _zip = add({
+ .type = FieldType::Text,
+ .placeholder = tr::lng_payments_billing_zip_code(),
+ .maxLength = kMaxPostcodeSize,
+ .required = true,
+ });
}
return inner;
}
@@ -200,7 +175,7 @@ void EditCard::resizeEvent(QResizeEvent *e) {
}
void EditCard::focusInEvent(QFocusEvent *e) {
- if (const auto control = controlForField(_focusField)) {
+ if (const auto control = lookupField(_focusField)) {
control->setFocusFast();
}
}
@@ -218,27 +193,27 @@ void EditCard::updateControlsGeometry() {
_scroll->updateBars();
}
-auto EditCard::controlForField(CardField field) const -> Row* {
+auto EditCard::lookupField(CardField field) const -> Field* {
switch (field) {
- case CardField::Number: return _number;
- case CardField::CVC: return _cvc;
- case CardField::ExpireDate: return _expire;
- case CardField::Name: return _name;
- case CardField::AddressCountry: return _country;
- case CardField::AddressZip: return _zip;
+ case CardField::Number: return _number.get();
+ case CardField::CVC: return _cvc.get();
+ case CardField::ExpireDate: return _expire.get();
+ case CardField::Name: return _name.get();
+ case CardField::AddressCountry: return _country.get();
+ case CardField::AddressZip: return _zip.get();
}
Unexpected("Unknown field in EditCard::controlForField.");
}
UncheckedCardDetails EditCard::collect() const {
return {
- .number = _number ? _number->valueCurrent() : QString(),
- .cvc = _cvc ? _cvc->valueCurrent() : QString(),
- .expireYear = _expire ? ExtractYear(_expire->valueCurrent()) : 0,
- .expireMonth = _expire ? ExtractMonth(_expire->valueCurrent()) : 0,
- .cardholderName = _name ? _name->valueCurrent() : QString(),
- .addressCountry = _country ? _country->valueCurrent() : QString(),
- .addressZip = _zip ? _zip->valueCurrent() : QString(),
+ .number = _number ? _number->value() : QString(),
+ .cvc = _cvc ? _cvc->value() : QString(),
+ .expireYear = _expire ? ExtractYear(_expire->value()) : 0,
+ .expireMonth = _expire ? ExtractMonth(_expire->value()) : 0,
+ .cardholderName = _name ? _name->value() : QString(),
+ .addressCountry = _country ? _country->value() : QString(),
+ .addressZip = _zip ? _zip->value() : QString(),
};
}
diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_card.h b/Telegram/SourceFiles/payments/ui/payments_edit_card.h
index 157e13edc9..742bdbf341 100644
--- a/Telegram/SourceFiles/payments/ui/payments_edit_card.h
+++ b/Telegram/SourceFiles/payments/ui/payments_edit_card.h
@@ -17,15 +17,12 @@ class FadeShadow;
class RoundButton;
} // namespace Ui
-namespace Passport::Ui {
-class PanelDetailsRow;
-} // namespace Passport::Ui
-
namespace Payments::Ui {
using namespace ::Ui;
class PanelDelegate;
+class Field;
class EditCard final : public RpWidget {
public:
@@ -35,19 +32,18 @@ public:
CardField field,
not_null<PanelDelegate*> delegate);
- void showError(CardField field);
void setFocus(CardField field);
+ void setFocusFast(CardField field);
+ void showError(CardField field);
private:
- using Row = Passport::Ui::PanelDetailsRow;
-
void resizeEvent(QResizeEvent *e) override;
void focusInEvent(QFocusEvent *e) override;
void setupControls();
[[nodiscard]] not_null<Ui::RpWidget*> setupContent();
void updateControlsGeometry();
- [[nodiscard]] Row *controlForField(CardField field) const;
+ [[nodiscard]] Field *lookupField(CardField field) const;
[[nodiscard]] UncheckedCardDetails collect() const;
@@ -59,12 +55,12 @@ private:
object_ptr<FadeShadow> _bottomShadow;
object_ptr<RoundButton> _done;
- Row *_number = nullptr;
- Row *_cvc = nullptr;
- Row *_expire = nullptr;
- Row *_name = nullptr;
- Row *_country = nullptr;
- Row *_zip = nullptr;
+ std::unique_ptr<Field> _number;
+ std::unique_ptr<Field> _cvc;
+ std::unique_ptr<Field> _expire;
+ std::unique_ptr<Field> _name;
+ std::unique_ptr<Field> _country;
+ std::unique_ptr<Field> _zip;
CardField _focusField = CardField::Number;
diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp
index eff78b29ba..8445c38156 100644
--- a/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp
+++ b/Telegram/SourceFiles/payments/ui/payments_edit_information.cpp
@@ -8,7 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/ui/payments_edit_information.h"
#include "payments/ui/payments_panel_delegate.h"
-#include "passport/ui/passport_details_row.h"
+#include "payments/ui/payments_field.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
@@ -48,18 +48,28 @@ EditInformation::EditInformation(
setupControls();
}
+EditInformation::~EditInformation() = default;
+
void EditInformation::setFocus(InformationField field) {
_focusField = field;
- if (const auto control = controlForField(field)) {
- _scroll->ensureWidgetVisible(control);
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
+ control->setFocus();
+ }
+}
+
+void EditInformation::setFocusFast(InformationField field) {
+ _focusField = field;
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
control->setFocusFast();
}
}
void EditInformation::showError(InformationField field) {
- if (const auto control = controlForField(field)) {
- _scroll->ensureWidgetVisible(control);
- control->showError(QString());
+ if (const auto control = lookupField(field)) {
+ _scroll->ensureWidgetVisible(control->widget());
+ control->showError();
}
}
@@ -93,106 +103,44 @@ not_null<RpWidget*> EditInformation::setupContent() {
const auto showBox = [=](object_ptr<BoxContent> box) {
_delegate->panelShowBox(std::move(box));
};
- using Type = Passport::Ui::PanelDetailsType;
- auto maxLabelWidth = 0;
- if (_invoice.isShippingAddressRequested) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_passport_street(tr::now)));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_passport_city(tr::now)));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_passport_state(tr::now)));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_passport_country(tr::now)));
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_passport_postcode(tr::now)));
- }
- if (_invoice.isNameRequested) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_payments_info_name(tr::now)));
- }
- if (_invoice.isEmailRequested) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_payments_info_email(tr::now)));
- }
- if (_invoice.isPhoneRequested) {
- accumulate_max(
- maxLabelWidth,
- Row::LabelWidth(tr::lng_payments_info_phone(tr::now)));
- }
+ const auto add = [&](FieldConfig &&config) {
+ auto result = std::make_unique<Field>(inner, std::move(config));
+ inner->add(result->ownedWidget(), st::paymentsFieldPadding);
+ return result;
+ };
if (_invoice.isShippingAddressRequested) {
- _street1 = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_passport_street(tr::now),
- maxLabelWidth,
- _information.shippingAddress.address1,
- QString(),
- kMaxStreetSize));
- _street2 = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_passport_street(tr::now),
- maxLabelWidth,
- _information.shippingAddress.address2,
- QString(),
- kMaxStreetSize));
- _city = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_passport_city(tr::now),
- maxLabelWidth,
- _information.shippingAddress.city,
- QString(),
- kMaxStreetSize));
- _state = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_passport_state(tr::now),
- maxLabelWidth,
- _information.shippingAddress.state,
- QString(),
- kMaxStreetSize));
- _country = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Country,
- tr::lng_passport_country(tr::now),
- maxLabelWidth,
- _information.shippingAddress.countryIso2,
- QString()));
- _postcode = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Postcode,
- tr::lng_passport_postcode(tr::now),
- maxLabelWidth,
- _information.shippingAddress.postcode,
- QString(),
- kMaxPostcodeSize));
+ _street1 = add({
+ .placeholder = tr::lng_payments_address_street1(),
+ .value = _information.shippingAddress.address1,
+ .maxLength = kMaxStreetSize,
+ .required = true,
+ });
+ _street2 = add({
+ .placeholder = tr::lng_payments_address_street2(),
+ .value = _information.shippingAddress.address2,
+ .maxLength = kMaxStreetSize,
+ });
+ _city = add({
+ .placeholder = tr::lng_payments_address_city(),
+ .value = _information.shippingAddress.city,
+ .required = true,
+ });
+ _state = add({
+ .placeholder = tr::lng_payments_address_state(),
+ .value = _information.shippingAddress.state,
+ });
+ _country = add({
+ .type = FieldType::Country,
+ .placeholder = tr::lng_payments_address_country(),
+ .value = _information.shippingAddress.countryIso2,
+ .required = true,
+ });
+ _postcode = add({
+ .placeholder = tr::lng_payments_address_postcode(),
+ .value = _information.shippingAddress.postcode,
+ .maxLength = kMaxPostcodeSize,
+ .required = true,
+ });
//StreetValidate, // #TODO payments
//CityValidate,
//CountryValidate,
@@ -200,43 +148,28 @@ not_null<RpWidget*> EditInformation::setupContent() {
//PostcodeValidate,
}
if (_invoice.isNameRequested) {
- _name = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_payments_info_name(tr::now),
- maxLabelWidth,
- _information.name,
- QString(),
- kMaxNameSize));
+ _name = add({
+ .placeholder = tr::lng_payments_info_name(),
+ .value = _information.name,
+ .maxLength = kMaxNameSize,
+ .required = true,
+ });
}
if (_invoice.isEmailRequested) {
- _email = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_payments_info_email(tr::now),
- maxLabelWidth,
- _information.email,
- QString(),
- kMaxEmailSize));
+ _email = add({
+ .placeholder = tr::lng_payments_info_email(),
+ .value = _information.email,
+ .maxLength = kMaxEmailSize,
+ .required = true,
+ });
}
if (_invoice.isPhoneRequested) {
- _phone = inner->add(
- Row::Create(
- inner,
- showBox,
- QString(),
- Type::Text,
- tr::lng_payments_info_phone(tr::now),
- maxLabelWidth,
- _information.phone,
- QString(),
- kMaxPhoneSize));
+ _phone = add({
+ .placeholder = tr::lng_payments_info_phone(),
+ .value = _information.phone,
+ .maxLength = kMaxPhoneSize,
+ .required = true,
+ });
}
return inner;
}
@@ -246,8 +179,8 @@ void EditInformation::resizeEvent(QResizeEvent *e) {
}
void EditInformation::focusInEvent(QFocusEvent *e) {
- if (const auto control = controlForField(_focusField)) {
- control->setFocusFast();
+ if (const auto control = lookupField(_focusField)) {
+ control->setFocus();
}
}
@@ -264,32 +197,32 @@ void EditInformation::updateControlsGeometry() {
_scroll->updateBars();
}
-auto EditInformation::controlForField(InformationField field) const -> Row* {
+auto EditInformation::lookupField(InformationField field) const -> Field* {
switch (field) {
- case InformationField::ShippingStreet: return _street1;
- case InformationField::ShippingCity: return _city;
- case InformationField::ShippingState: return _state;
- case InformationField::ShippingCountry: return _country;
- case InformationField::ShippingPostcode: return _postcode;
- case InformationField::Name: return _name;
- case InformationField::Email: return _email;
- case InformationField::Phone: return _phone;
+ case InformationField::ShippingStreet: return _street1.get();
+ case InformationField::ShippingCity: return _city.get();
+ case InformationField::ShippingState: return _state.get();
+ case InformationField::ShippingCountry: return _country.get();
+ case InformationField::ShippingPostcode: return _postcode.get();
+ case InformationField::Name: return _name.get();
+ case InformationField::Email: return _email.get();
+ case InformationField::Phone: return _phone.get();
}
- Unexpected("Unknown field in EditInformation::controlForField.");
+ Unexpected("Unknown field in EditInformation::lookupField.");
}
RequestedInformation EditInformation::collect() const {
return {
- .name = _name ? _name->valueCurrent() : QString(),
- .phone = _phone ? _phone->valueCurrent() : QString(),
- .email = _email ? _email->valueCurrent() : QString(),
+ .name = _name ? _name->value() : QString(),
+ .phone = _phone ? _phone->value() : QString(),
+ .email = _email ? _email->value() : QString(),
.shippingAddress = {
- .address1 = _street1 ? _street1->valueCurrent() : QString(),
- .address2 = _street2 ? _street2->valueCurrent() : QString(),
- .city = _city ? _city->valueCurrent() : QString(),
- .state = _state ? _state->valueCurrent() : QString(),
- .countryIso2 = _country ? _country->valueCurrent() : QString(),
- .postcode = _postcode ? _postcode->valueCurrent() : QString(),
+ .address1 = _street1 ? _street1->value() : QString(),
+ .address2 = _street2 ? _street2->value() : QString(),
+ .city = _city ? _city->value() : QString(),
+ .state = _state ? _state->value() : QString(),
+ .countryIso2 = _country ? _country->value() : QString(),
+ .postcode = _postcode ? _postcode->value() : QString(),
},
};
}
diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_information.h b/Telegram/SourceFiles/payments/ui/payments_edit_information.h
index d4f8ee78e8..978b72b433 100644
--- a/Telegram/SourceFiles/payments/ui/payments_edit_information.h
+++ b/Telegram/SourceFiles/payments/ui/payments_edit_information.h
@@ -15,17 +15,16 @@ namespace Ui {
class ScrollArea;
class FadeShadow;
class RoundButton;
+class InputField;
+class MaskedInputField;
} // namespace Ui
-namespace Passport::Ui {
-class PanelDetailsRow;
-} // namespace Passport::Ui
-
namespace Payments::Ui {
using namespace ::Ui;
class PanelDelegate;
+class Field;
class EditInformation final : public RpWidget {
public:
@@ -35,20 +34,20 @@ public:
const RequestedInformation &current,
InformationField field,
not_null<PanelDelegate*> delegate);
+ ~EditInformation();
- void showError(InformationField field);
void setFocus(InformationField field);
+ void setFocusFast(InformationField field);
+ void showError(InformationField field);
private:
- using Row = Passport::Ui::PanelDetailsRow;
-
void resizeEvent(QResizeEvent *e) override;
void focusInEvent(QFocusEvent *e) override;
void setupControls();
[[nodiscard]] not_null<Ui::RpWidget*> setupContent();
void updateControlsGeometry();
- [[nodiscard]] Row *controlForField(InformationField field) const;
+ [[nodiscard]] Field *lookupField(InformationField field) const;
[[nodiscard]] RequestedInformation collect() const;
@@ -61,15 +60,15 @@ private:
object_ptr<FadeShadow> _bottomShadow;
object_ptr<RoundButton> _done;
- Row *_street1 = nullptr;
- Row *_street2 = nullptr;
- Row *_city = nullptr;
- Row *_state = nullptr;
- Row *_country = nullptr;
- Row *_postcode = nullptr;
- Row *_name = nullptr;
- Row *_email = nullptr;
- Row *_phone = nullptr;
+ std::unique_ptr<Field> _street1;
+ std::unique_ptr<Field> _street2;
+ std::unique_ptr<Field> _city;
+ std::unique_ptr<Field> _state;
+ std::unique_ptr<Field> _country;
+ std::unique_ptr<Field> _postcode;
+ std::unique_ptr<Field> _name;
+ std::unique_ptr<Field> _email;
+ std::unique_ptr<Field> _phone;
InformationField _focusField = InformationField::ShippingStreet;
diff --git a/Telegram/SourceFiles/payments/ui/payments_field.cpp b/Telegram/SourceFiles/payments/ui/payments_field.cpp
new file mode 100644
index 0000000000..2161772f91
--- /dev/null
+++ b/Telegram/SourceFiles/payments/ui/payments_field.cpp
@@ -0,0 +1,140 @@
+/*
+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 "payments/ui/payments_field.h"
+
+#include "ui/widgets/input_fields.h"
+#include "styles/style_payments.h"
+
+namespace Payments::Ui {
+namespace {
+
+[[nodiscard]] bool UseMaskedField(FieldType type) {
+ switch (type) {
+ case FieldType::Text:
+ case FieldType::Email:
+ return false;
+ case FieldType::CardNumber:
+ case FieldType::CardExpireDate:
+ case FieldType::CardCVC:
+ case FieldType::Country:
+ case FieldType::Phone:
+ return true;
+ }
+ Unexpected("FieldType in Payments::Ui::UseMaskedField.");
+}
+
+[[nodiscard]] base::unique_qptr<RpWidget> CreateWrap(
+ QWidget *parent,
+ FieldConfig &config) {
+ switch (config.type) {
+ case FieldType::Text:
+ case FieldType::Email:
+ return base::make_unique_q<InputField>(
+ parent,
+ st::paymentsField,
+ std::move(config.placeholder),
+ config.value);
+ case FieldType::CardNumber:
+ case FieldType::CardExpireDate:
+ case FieldType::CardCVC:
+ case FieldType::Country:
+ case FieldType::Phone:
+ return base::make_unique_q<RpWidget>(parent);
+ }
+ Unexpected("FieldType in Payments::Ui::CreateWrap.");
+}
+
+[[nodiscard]] InputField *LookupInputField(
+ not_null<RpWidget*> wrap,
+ FieldConfig &config) {
+ return UseMaskedField(config.type)
+ ? nullptr
+ : static_cast<InputField*>(wrap.get());
+}
+
+[[nodiscard]] MaskedInputField *LookupMaskedField(
+ not_null<RpWidget*> wrap,
+ FieldConfig &config) {
+ if (!UseMaskedField(config.type)) {
+ return nullptr;
+ }
+ switch (config.type) {
+ case FieldType::Text:
+ case FieldType::Email:
+ return nullptr;
+ case FieldType::CardNumber:
+ case FieldType::CardExpireDate:
+ case FieldType::CardCVC:
+ case FieldType::Country:
+ case FieldType::Phone:
+ return CreateChild<MaskedInputField>(
+ wrap.get(),
+ st::paymentsField,
+ std::move(config.placeholder),
+ config.value);
+ }
+ Unexpected("FieldType in Payments::Ui::LookupMaskedField.");
+}
+
+} // namespace
+
+Field::Field(QWidget *parent, FieldConfig &&config)
+: _type(config.type)
+, _wrap(CreateWrap(parent, config))
+, _input(LookupInputField(_wrap.get(), config))
+, _masked(LookupMaskedField(_wrap.get(), config)) {
+ if (_masked) {
+ _wrap->resize(_masked->size());
+ _wrap->widthValue(
+ ) | rpl::start_with_next([=](int width) {
+ _masked->resize(width, _masked->height());
+ }, _masked->lifetime());
+ _masked->heightValue(
+ ) | rpl::start_with_next([=](int height) {
+ _wrap->resize(_wrap->width(), height);
+ }, _masked->lifetime());
+ }
+}
+
+RpWidget *Field::widget() const {
+ return _wrap.get();
+}
+
+object_ptr<RpWidget> Field::ownedWidget() const {
+ return object_ptr<RpWidget>::fromRaw(_wrap.get());
+}
+
+[[nodiscard]] QString Field::value() const {
+ return _input ? _input->getLastText() : _masked->getLastText();
+}
+
+void Field::setFocus() {
+ if (_input) {
+ _input->setFocus();
+ } else {
+ _masked->setFocus();
+ }
+}
+
+void Field::setFocusFast() {
+ if (_input) {
+ _input->setFocusFast();
+ } else {
+ _masked->setFocusFast();
+ }
+}
+
+void Field::showError() {
+ if (_input) {
+ _input->showError();
+ } else {
+ _masked->showError();
+ }
+}
+
+} // namespace Payments::Ui
diff --git a/Telegram/SourceFiles/payments/ui/payments_field.h b/Telegram/SourceFiles/payments/ui/payments_field.h
new file mode 100644
index 0000000000..92277ac360
--- /dev/null
+++ b/Telegram/SourceFiles/payments/ui/payments_field.h
@@ -0,0 +1,62 @@
+/