mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Improve checkout information / card page design.
This commit is contained in:
parent
fafea73ea7
commit
47fdef1e38
13 changed files with 468 additions and 319 deletions
|
@ -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";
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"));
|
||||
_name = add({
|
||||
.type = FieldType::CardNumber,
|
||||
.placeholder = tr::lng_payments_card_holder(),
|
||||
.required = true,
|
||||
});
|
||||
}
|
||||
auto container = inner->add(
|
||||
object_ptr<FixedHeightWidget>(
|
||||
inner,
|
||||
_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,
|
||||
tr::lng_payments_billing_address(),
|
||||
st::paymentsBillingInformationTitle),
|
||||
st::paymentsBillingInformationTitlePadding);
|
||||
}
|
||||
if (_native.needCountry) {
|
||||
accumulate_max(
|
||||
maxLabelWidth,
|
||||
Row::LabelWidth("Billing Country"));
|
||||
_country = add({
|
||||
.type = FieldType::Country,
|
||||
.placeholder = tr::lng_payments_billing_country(),
|
||||
.required = true,
|
||||
});
|
||||
}
|
||||
if (_native.needZip) {
|
||||
accumulate_max(
|
||||
maxLabelWidth,
|
||||
Row::LabelWidth("Billing Zip"));
|
||||
}
|
||||
_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(
|
||||
inner,
|
||||
showBox,
|
||||
QString(),
|
||||
Type::Text,
|
||||
"MM/YY",
|
||||
maxLabelWidth,
|
||||
QString(),
|
||||
QString(),
|
||||
1024));
|
||||
if (_native.needCardholderName) {
|
||||
_name = inner->add(
|
||||
Row::Create(
|
||||
inner,
|
||||
showBox,
|
||||
QString(),
|
||||
Type::Text,
|
||||
"Cardholder Name",
|
||||
maxLabelWidth,
|
||||
QString(),
|
||||
QString(),
|
||||
1024));
|
||||
}
|
||||
if (_native.needCountry) {
|
||||
_country = inner->add(
|
||||
Row::Create(
|
||||
inner,
|
||||
showBox,
|
||||
QString(),
|
||||
Type::Country,
|
||||
"Billing Country",
|
||||
maxLabelWidth,
|
||||
QString(),
|
||||
QString()));
|
||||
}
|
||||
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(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
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) {
|
||||
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)));
|
||||
}
|
||||
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(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 ¤t,
|
||||
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;
|
||||
|
||||
|
|
140
Telegram/SourceFiles/payments/ui/payments_field.cpp
Normal file
140
Telegram/SourceFiles/payments/ui/payments_field.cpp
Normal file
|
@ -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
|
62
Telegram/SourceFiles/payments/ui/payments_field.h
Normal file
62
Telegram/SourceFiles/payments/ui/payments_field.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/object_ptr.h"
|
||||
#include "base/unique_qptr.h"
|
||||
|
||||
namespace Ui {
|
||||
class RpWidget;
|
||||
class InputField;
|
||||
class MaskedInputField;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Payments::Ui {
|
||||
|
||||
using namespace ::Ui;
|
||||
|
||||
enum class FieldType {
|
||||
Text,
|
||||
CardNumber,
|
||||
CardExpireDate,
|
||||
CardCVC,
|
||||
Country,
|
||||
Phone,
|
||||
Email,
|
||||
};
|
||||
|
||||
struct FieldConfig {
|
||||
FieldType type = FieldType::Text;
|
||||
rpl::producer<QString> placeholder;
|
||||
QString value;
|
||||
int maxLength = 0;
|
||||
bool required = false;
|
||||
};
|
||||
|
||||
class Field final {
|
||||
public:
|
||||
Field(QWidget *parent, FieldConfig &&config);
|
||||
|
||||
[[nodiscard]] RpWidget *widget() const;
|
||||
[[nodiscard]] object_ptr<RpWidget> ownedWidget() const;
|
||||
|
||||
[[nodiscard]] QString value() const;
|
||||
|
||||
void setFocus();
|
||||
void setFocusFast();
|
||||
void showError();
|
||||
|
||||
private:
|
||||
const FieldType _type = FieldType::Text;
|
||||
const base::unique_qptr<RpWidget> _wrap;
|
||||
InputField *_input = nullptr;
|
||||
MaskedInputField *_masked = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Payments::Ui
|
|
@ -58,7 +58,7 @@ QString FormSummary::formatAmount(int64 amount) const {
|
|||
const auto base = FillAmountAndCurrency(
|
||||
std::abs(amount),
|
||||
_invoice.currency);
|
||||
return (amount > 0) ? base : (QString::fromUtf8("\xe2\x88\x92") + base);
|
||||
return (amount < 0) ? (QString::fromUtf8("\xe2\x88\x92") + base) : base;
|
||||
}
|
||||
|
||||
int64 FormSummary::computeTotalAmount() const {
|
||||
|
@ -87,6 +87,9 @@ void FormSummary::setupControls() {
|
|||
_submit->addClickHandler([=] {
|
||||
_delegate->panelSubmit();
|
||||
});
|
||||
if (!_invoice) {
|
||||
_submit->hide();
|
||||
}
|
||||
|
||||
using namespace rpl::mappers;
|
||||
|
||||
|
@ -317,10 +320,12 @@ not_null<RpWidget*> FormSummary::setupContent() {
|
|||
}, inner->lifetime());
|
||||
|
||||
setupCover(inner);
|
||||
Settings::AddDivider(inner);
|
||||
setupPrices(inner);
|
||||
Settings::AddDivider(inner);
|
||||
setupSections(inner);
|
||||
if (_invoice) {
|
||||
Settings::AddDivider(inner);
|
||||
setupPrices(inner);
|
||||
Settings::AddDivider(inner);
|
||||
setupSections(inner);
|
||||
}
|
||||
|
||||
return inner;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace Payments::Ui {
|
|||
Panel::Panel(not_null<PanelDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
, _widget(std::make_unique<SeparatePanel>()) {
|
||||
_widget->setTitle(tr::lng_payments_checkout_title());
|
||||
_widget->setInnerSize(st::passportPanelSize);
|
||||
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
|
||||
|
||||
|
@ -52,6 +51,7 @@ void Panel::showForm(
|
|||
const RequestedInformation ¤t,
|
||||
const PaymentMethodDetails &method,
|
||||
const ShippingOptions &options) {
|
||||
_widget->setTitle(tr::lng_payments_checkout_title());
|
||||
auto form = base::make_unique_q<FormSummary>(
|
||||
_widget.get(),
|
||||
invoice,
|
||||
|
@ -74,6 +74,7 @@ void Panel::showEditInformation(
|
|||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
InformationField field) {
|
||||
_widget->setTitle(tr::lng_payments_shipping_address_title());
|
||||
auto edit = base::make_unique_q<EditInformation>(
|
||||
_widget.get(),
|
||||
invoice,
|
||||
|
@ -83,7 +84,7 @@ void Panel::showEditInformation(
|
|||
_weakEditInformation = edit.get();
|
||||
_widget->showInner(std::move(edit));
|
||||
_widget->setBackAllowed(true);
|
||||
_weakEditInformation->setFocus(field);
|
||||
_weakEditInformation->setFocusFast(field);
|
||||
}
|
||||
|
||||
void Panel::showInformationError(
|
||||
|
@ -125,6 +126,7 @@ void Panel::chooseShippingOption(const ShippingOptions &options) {
|
|||
}
|
||||
|
||||
void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
|
||||
_widget->setTitle(tr::lng_payments_card_title());
|
||||
if (method.native.supported) {
|
||||
showEditCard(method.native, CardField::Number);
|
||||
} else if (!showWebview(method.url, true)) {
|
||||
|
@ -221,7 +223,7 @@ void Panel::showEditCard(
|
|||
_weakEditCard = edit.get();
|
||||
_widget->showInner(std::move(edit));
|
||||
_widget->setBackAllowed(true);
|
||||
_weakEditCard->setFocus(field);
|
||||
_weakEditCard->setFocusFast(field);
|
||||
}
|
||||
|
||||
void Panel::showCardError(
|
||||
|
@ -230,11 +232,12 @@ void Panel::showCardError(
|
|||
if (_weakEditCard) {
|
||||
_weakEditCard->showError(field);
|
||||
} else {
|
||||
showEditCard(native, field);
|
||||
if (_weakEditCard
|
||||
&& field == CardField::AddressCountry) {
|
||||
_weakEditCard->showError(field);
|
||||
}
|
||||
// We cancelled card edit already.
|
||||
//showEditCard(native, field);
|
||||
//if (_weakEditCard
|
||||
// && field == CardField::AddressCountry) {
|
||||
// _weakEditCard->showError(field);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,8 @@ PRIVATE
|
|||
payments/ui/payments_edit_information.h
|
||||
payments/ui/payments_form_summary.cpp
|
||||
payments/ui/payments_form_summary.h
|
||||
payments/ui/payments_field.cpp
|
||||
payments/ui/payments_field.h
|
||||
payments/ui/payments_panel.cpp
|
||||
payments/ui/payments_panel.h
|
||||
payments/ui/payments_panel_data.h
|
||||
|
|
Loading…
Add table
Reference in a new issue