Show some payment errors, focus fields.

This commit is contained in:
John Preston 2021-03-24 15:30:01 +04:00
parent 0d44736575
commit 212497413c
20 changed files with 244 additions and 130 deletions

View file

@ -101,7 +101,7 @@ void Panel::showBox(
} }
void Panel::showToast(const QString &text) { void Panel::showToast(const QString &text) {
_widget->showToast(text); _widget->showToast({ text });
} }
Panel::~Panel() = default; Panel::~Panel() = default;

View file

@ -12,6 +12,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "payments/ui/payments_webview.h" #include "payments/ui/payments_webview.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "main/main_account.h" #include "main/main_account.h"
#include "main/main_domain.h"
#include "storage/storage_domain.h"
#include "history/history_item.h" #include "history/history_item.h"
#include "history/history.h" #include "history/history.h"
#include "core/local_url_handlers.h" // TryConvertUrlToLocal. #include "core/local_url_handlers.h" // TryConvertUrlToLocal.
@ -19,7 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
// #TODO payments errors // #TODO payments errors
#include "mainwindow.h" #include "mainwindow.h"
#include "ui/toast/toast.h" #include "ui/toasts/common_toasts.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@ -80,6 +82,10 @@ CheckoutProcess::CheckoutProcess(
) | rpl::start_with_next([=](const FormUpdate &update) { ) | rpl::start_with_next([=](const FormUpdate &update) {
handleFormUpdate(update); handleFormUpdate(update);
}, _lifetime); }, _lifetime);
_panel->backRequests(
) | rpl::start_with_next([=] {
showForm();
}, _panel->lifetime());
} }
CheckoutProcess::~CheckoutProcess() { CheckoutProcess::~CheckoutProcess() {
@ -96,12 +102,6 @@ not_null<Ui::PanelDelegate*> CheckoutProcess::panelDelegate() {
void CheckoutProcess::handleFormUpdate(const FormUpdate &update) { void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
v::match(update.data, [&](const FormReady &) { v::match(update.data, [&](const FormReady &) {
showForm(); showForm();
}, [&](const FormError &error) { // #TODO payments refactor errors
handleFormError(error);
}, [&](const ValidateError &error) {
handleValidateError(error);
}, [&](const SendError &error) {
handleSendError(error);
}, [&](const ValidateFinished &) { }, [&](const ValidateFinished &) {
showForm(); showForm();
if (_submitState == SubmitState::Validation) { if (_submitState == SubmitState::Validation) {
@ -113,6 +113,7 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
_webviewWindow->navigate(info.url); _webviewWindow->navigate(info.url);
} else { } else {
_webviewWindow = std::make_unique<Ui::WebviewWindow>( _webviewWindow = std::make_unique<Ui::WebviewWindow>(
webviewDataPath(),
info.url, info.url,
panelDelegate()); panelDelegate());
if (!_webviewWindow->shown()) { if (!_webviewWindow->shown()) {
@ -125,80 +126,78 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
if (weak) { if (weak) {
panelCloseSure(); panelCloseSure();
} }
}, [&](const Error &error) {
handleError(error);
}); });
} }
void CheckoutProcess::handleFormError(const FormError &error) { void CheckoutProcess::handleError(const Error &error) {
// #TODO payments errors const auto showToast = [&](const TextWithEntities &text) {
const auto &type = error.type; if (_panel) {
if (type == u"PROVIDER_ACCOUNT_INVALID"_q) { _panel->requestActivate();
_panel->showToast(text);
} else if (type == u"PROVIDER_ACCOUNT_TIMEOUT"_q) { } else {
App::wnd()->activate();
} else if (type == u"INVOICE_ALREADY_PAID"_q) { Ui::ShowMultilineToast({ .text = text });
}
} };
if (_panel) { const auto &id = error.id;
_panel->showToast("payments.getPaymentForm: " + type); switch (error.type) {
} else { case Error::Type::Form:
App::wnd()->activate(); if (id == u"INVOICE_ALREADY_PAID"_q) {
Ui::Toast::Show("payments.getPaymentForm: " + type); showToast({ "Already Paid!" }); // #TODO payments errors message
} } else if (true
} || id == u"PROVIDER_ACCOUNT_INVALID"_q
|| id == u"PROVIDER_ACCOUNT_TIMEOUT"_q) {
void CheckoutProcess::handleValidateError(const ValidateError &error) { showToast({ "Error: " + id });
// #TODO payments errors }
const auto &type = error.type; break;
if (type == u"REQ_INFO_NAME_INVALID"_q) { case Error::Type::Validate:
if (_submitState == SubmitState::Validation) {
} else if (type == u"REQ_INFO_EMAIL_INVALID"_q) { _submitState = SubmitState::None;
}
} else if (type == u"REQ_INFO_PHONE_INVALID"_q) { if (id == u"REQ_INFO_NAME_INVALID"_q) {
showEditError(Ui::EditField::Name);
} else if (type == u"ADDRESS_STREET_LINE1_INVALID"_q) { } else if (id == u"REQ_INFO_EMAIL_INVALID"_q) {
showEditError(Ui::EditField::Email);
} else if (type == u"ADDRESS_CITY_INVALID"_q) { } else if (id == u"REQ_INFO_PHONE_INVALID"_q) {
showEditError(Ui::EditField::Phone);
} else if (type == u"ADDRESS_STATE_INVALID"_q) { } else if (id == u"ADDRESS_STREET_LINE1_INVALID"_q) {
showEditError(Ui::EditField::ShippingStreet);
} else if (type == u"ADDRESS_COUNTRY_INVALID"_q) { } else if (id == u"ADDRESS_CITY_INVALID"_q) {
showEditError(Ui::EditField::ShippingCity);
} else if (type == u"ADDRESS_POSTCODE_INVALID"_q) { } else if (id == u"ADDRESS_STATE_INVALID"_q) {
showEditError(Ui::EditField::ShippingState);
} else if (type == u"SHIPPING_BOT_TIMEOUT"_q) { } else if (id == u"ADDRESS_COUNTRY_INVALID"_q) {
showEditError(Ui::EditField::ShippingCountry);
} else if (type == u"SHIPPING_NOT_AVAILABLE"_q) { } else if (id == u"ADDRESS_POSTCODE_INVALID"_q) {
showEditError(Ui::EditField::ShippingPostcode);
} } else if (id == u"SHIPPING_BOT_TIMEOUT"_q) {
if (_panel) { showToast({ "Error: Bot Timeout!" }); // #TODO payments errors message
_panel->showToast("payments.validateRequestedInfo: " + type); } else if (id == u"SHIPPING_NOT_AVAILABLE"_q) {
} else { showToast({ "Error: Shipping to the selected country is not available!" }); // #TODO payments errors message
App::wnd()->activate(); } else {
Ui::Toast::Show("payments.validateRequestedInfo: " + type); showToast({ "Error: " + id });
} }
} break;
case Error::Type::Send:
void CheckoutProcess::handleSendError(const SendError &error) { if (_submitState == SubmitState::Finishing) {
// #TODO payments errors _submitState = SubmitState::None;
const auto &type = error.type; }
if (type == u"REQUESTED_INFO_INVALID"_q) { if (id == u"PAYMENT_FAILED"_q) {
showToast({ "Error: Payment Failed. Your card has not been billed." }); // #TODO payments errors message
} else if (type == u"SHIPPING_OPTION_INVALID"_q) { } else if (id == u"BOT_PRECHECKOUT_FAILED"_q) {
showToast({ "Error: PreCheckout Failed. Your card has not been billed." }); // #TODO payments errors message
} else if (type == u"PAYMENT_FAILED"_q) { } else if (id == u"INVOICE_ALREADY_PAID"_q) {
showToast({ "Already Paid!" }); // #TODO payments errors message
} else if (type == u"PAYMENT_CREDENTIALS_INVALID"_q) { } else if (id == u"REQUESTED_INFO_INVALID"_q
|| id == u"SHIPPING_OPTION_INVALID"_q
} else if (type == u"PAYMENT_CREDENTIALS_ID_INVALID"_q) { || id == u"PAYMENT_CREDENTIALS_INVALID"_q
|| id == u"PAYMENT_CREDENTIALS_ID_INVALID"_q) {
} else if (type == u"BOT_PRECHECKOUT_FAILED"_q) { showToast({ "Error: " + id + ". Your card has not been billed." });
}
} break;
if (_panel) { default: Unexpected("Error type in CheckoutProcess::handleError.");
_panel->showToast("payments.sendPaymentForm: " + type);
} else {
App::wnd()->activate();
Ui::Toast::Show("payments.sendPaymentForm: " + type);
} }
} }
@ -245,6 +244,7 @@ void CheckoutProcess::panelSubmit() {
} }
_submitState = SubmitState::Finishing; _submitState = SubmitState::Finishing;
_webviewWindow = std::make_unique<Ui::WebviewWindow>( _webviewWindow = std::make_unique<Ui::WebviewWindow>(
webviewDataPath(),
_form->details().url, _form->details().url,
panelDelegate()); panelDelegate());
if (!_webviewWindow->shown()) { if (!_webviewWindow->shown()) {
@ -306,7 +306,7 @@ bool CheckoutProcess::panelWebviewNavigationAttempt(const QString &uri) {
} }
void CheckoutProcess::panelEditShippingInformation() { void CheckoutProcess::panelEditShippingInformation() {
showEditInformation(Ui::EditField::ShippingInformation); showEditInformation(Ui::EditField::ShippingStreet);
} }
void CheckoutProcess::panelEditName() { void CheckoutProcess::panelEditName() {
@ -338,6 +338,16 @@ void CheckoutProcess::showEditInformation(Ui::EditField field) {
field); field);
} }
void CheckoutProcess::showEditError(Ui::EditField field) {
if (_submitState != SubmitState::None) {
return;
}
_panel->showEditError(
_form->invoice(),
_form->savedInformation(),
field);
}
void CheckoutProcess::chooseShippingOption() { void CheckoutProcess::chooseShippingOption() {
_panel->chooseShippingOption(_form->shippingOptions()); _panel->chooseShippingOption(_form->shippingOptions());
} }
@ -363,4 +373,8 @@ void CheckoutProcess::panelShowBox(object_ptr<Ui::BoxContent> box) {
_panel->showBox(std::move(box)); _panel->showBox(std::move(box));
} }
QString CheckoutProcess::webviewDataPath() const {
return _session->domain().local().webviewDataPath();
}
} // namespace Payments } // namespace Payments

View file

@ -26,9 +26,7 @@ namespace Payments {
class Form; class Form;
struct FormUpdate; struct FormUpdate;
struct FormError; struct Error;
struct SendError;
struct ValidateError;
class CheckoutProcess final class CheckoutProcess final
: public base::has_weak_ptr : public base::has_weak_ptr
@ -56,14 +54,15 @@ private:
[[nodiscard]] not_null<PanelDelegate*> panelDelegate(); [[nodiscard]] not_null<PanelDelegate*> panelDelegate();
void handleFormUpdate(const FormUpdate &update); void handleFormUpdate(const FormUpdate &update);
void handleFormError(const FormError &error); void handleError(const Error &error);
void handleValidateError(const ValidateError &error);
void handleSendError(const SendError &error);
void showForm(); void showForm();
void showEditInformation(Ui::EditField field); void showEditInformation(Ui::EditField field);
void showEditError(Ui::EditField field);
void chooseShippingOption(); void chooseShippingOption();
[[nodiscard]] QString webviewDataPath() const;
void panelRequestClose() override; void panelRequestClose() override;
void panelCloseSure() override; void panelCloseSure() override;
void panelSubmit() override; void panelSubmit() override;

View file

@ -22,7 +22,7 @@ namespace {
.city = qs(data.vcity()), .city = qs(data.vcity()),
.state = qs(data.vstate()), .state = qs(data.vstate()),
.countryIso2 = qs(data.vcountry_iso2()), .countryIso2 = qs(data.vcountry_iso2()),
.postCode = qs(data.vpost_code()), .postcode = qs(data.vpost_code()),
}; };
}); });
} }
@ -60,7 +60,7 @@ namespace {
MTP_string(information.shippingAddress.city), MTP_string(information.shippingAddress.city),
MTP_string(information.shippingAddress.state), MTP_string(information.shippingAddress.state),
MTP_string(information.shippingAddress.countryIso2), MTP_string(information.shippingAddress.countryIso2),
MTP_string(information.shippingAddress.postCode))); MTP_string(information.shippingAddress.postcode)));
} }
} // namespace } // namespace
@ -80,7 +80,7 @@ void Form::requestForm() {
processForm(data); processForm(data);
}); });
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_updates.fire({ FormError{ error.type() } }); _updates.fire({ Error{ Error::Type::Form, error.type() } });
}).send(); }).send();
} }
@ -180,7 +180,7 @@ void Form::send(const QByteArray &serializedCredentials) {
_updates.fire({ VerificationNeeded{ qs(data.vurl()) } }); _updates.fire({ VerificationNeeded{ qs(data.vurl()) } });
}); });
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_updates.fire({ SendError{ error.type() } }); _updates.fire({ Error{ Error::Type::Send, error.type() } });
}).send(); }).send();
} }
@ -217,7 +217,7 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
_updates.fire({ ValidateFinished{} }); _updates.fire({ ValidateFinished{} });
}).fail([=](const MTP::Error &error) { }).fail([=](const MTP::Error &error) {
_validateRequestId = 0; _validateRequestId = 0;
_updates.fire({ ValidateError{ error.type() } }); _updates.fire({ Error{ Error::Type::Validate, error.type() } });
}).send(); }).send();
} }

View file

@ -34,25 +34,19 @@ struct FormDetails {
}; };
struct FormReady {}; struct FormReady {};
struct ValidateFinished {}; struct ValidateFinished {};
struct Error {
struct FormError { enum class Type {
QString type; Form,
Validate,
Send,
};
Type type = Type::Form;
QString id;
}; };
struct ValidateError {
QString type;
};
struct SendError {
QString type;
};
struct VerificationNeeded { struct VerificationNeeded {
QString url; QString url;
}; };
struct PaymentFinished { struct PaymentFinished {
MTPUpdates updates; MTPUpdates updates;
}; };
@ -60,12 +54,10 @@ struct PaymentFinished {
struct FormUpdate { struct FormUpdate {
std::variant< std::variant<
FormReady, FormReady,
FormError,
ValidateError,
SendError,
VerificationNeeded, VerificationNeeded,
ValidateFinished, ValidateFinished,
PaymentFinished> data; PaymentFinished,
Error> data;
}; };
class Form final { class Form final {

View file

@ -10,3 +10,9 @@ using "ui/basic.style";
using "passport/passport.style"; using "passport/passport.style";
paymentsFormPricePadding: margins(22px, 7px, 22px, 6px); paymentsFormPricePadding: margins(22px, 7px, 22px, 6px);
paymentsPanelSubmit: RoundButton(passportPasswordSubmit) {
width: 0px;
height: 49px;
padding: margins(0px, -3px, 0px, 0px);
textTop: 16px;
}

View file

@ -48,6 +48,21 @@ EditInformation::EditInformation(
setupControls(); setupControls();
} }
void EditInformation::setFocus(EditField field) {
_focusField = field;
if (const auto control = controlForField(field)) {
_scroll->ensureWidgetVisible(control);
control->setFocusFast();
}
}
void EditInformation::showError(EditField field) {
if (const auto control = controlForField(field)) {
_scroll->ensureWidgetVisible(control);
control->showError(QString());
}
}
void EditInformation::setupControls() { void EditInformation::setupControls() {
const auto inner = setupContent(); const auto inner = setupContent();
@ -175,7 +190,7 @@ not_null<RpWidget*> EditInformation::setupContent() {
Type::Postcode, Type::Postcode,
tr::lng_passport_postcode(tr::now), tr::lng_passport_postcode(tr::now),
maxLabelWidth, maxLabelWidth,
_information.shippingAddress.postCode, _information.shippingAddress.postcode,
QString(), QString(),
kMaxPostcodeSize)); kMaxPostcodeSize));
//StreetValidate, // #TODO payments //StreetValidate, // #TODO payments
@ -230,6 +245,12 @@ void EditInformation::resizeEvent(QResizeEvent *e) {
updateControlsGeometry(); updateControlsGeometry();
} }
void EditInformation::focusInEvent(QFocusEvent *e) {
if (const auto control = controlForField(_focusField)) {
control->setFocusFast();
}
}
void EditInformation::updateControlsGeometry() { void EditInformation::updateControlsGeometry() {
const auto submitTop = height() - _done->height(); const auto submitTop = height() - _done->height();
_scroll->setGeometry(0, 0, width(), submitTop); _scroll->setGeometry(0, 0, width(), submitTop);
@ -243,6 +264,20 @@ void EditInformation::updateControlsGeometry() {
_scroll->updateBars(); _scroll->updateBars();
} }
auto EditInformation::controlForField(EditField field) const -> Row* {
switch (field) {
case EditField::ShippingStreet: return _street1;
case EditField::ShippingCity: return _city;
case EditField::ShippingState: return _state;
case EditField::ShippingCountry: return _country;
case EditField::ShippingPostcode: return _postcode;
case EditField::Name: return _name;
case EditField::Email: return _email;
case EditField::Phone: return _phone;
}
Unexpected("Unknown field in EditInformation::controlForField.");
}
RequestedInformation EditInformation::collect() const { RequestedInformation EditInformation::collect() const {
return { return {
.name = _name ? _name->valueCurrent() : QString(), .name = _name ? _name->valueCurrent() : QString(),
@ -254,7 +289,7 @@ RequestedInformation EditInformation::collect() const {
.city = _city ? _city->valueCurrent() : QString(), .city = _city ? _city->valueCurrent() : QString(),
.state = _state ? _state->valueCurrent() : QString(), .state = _state ? _state->valueCurrent() : QString(),
.countryIso2 = _country ? _country->valueCurrent() : QString(), .countryIso2 = _country ? _country->valueCurrent() : QString(),
.postCode = _postcode ? _postcode->valueCurrent() : QString(), .postcode = _postcode ? _postcode->valueCurrent() : QString(),
}, },
}; };
} }

View file

@ -36,14 +36,19 @@ public:
EditField field, EditField field,
not_null<PanelDelegate*> delegate); not_null<PanelDelegate*> delegate);
void showError(EditField field);
void setFocus(EditField field);
private: private:
using Row = Passport::Ui::PanelDetailsRow; using Row = Passport::Ui::PanelDetailsRow;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
void focusInEvent(QFocusEvent *e) override;
void setupControls(); void setupControls();
[[nodiscard]] not_null<Ui::RpWidget*> setupContent(); [[nodiscard]] not_null<Ui::RpWidget*> setupContent();
void updateControlsGeometry(); void updateControlsGeometry();
[[nodiscard]] Row *controlForField(EditField field) const;
[[nodiscard]] RequestedInformation collect() const; [[nodiscard]] RequestedInformation collect() const;
@ -66,6 +71,8 @@ private:
Row *_email = nullptr; Row *_email = nullptr;
Row *_phone = nullptr; Row *_phone = nullptr;
EditField _focusField = EditField::ShippingStreet;
}; };
} // namespace Payments::Ui } // namespace Payments::Ui

View file

@ -44,7 +44,7 @@ FormSummary::FormSummary(
tr::lng_payments_pay_amount( tr::lng_payments_pay_amount(
lt_amount, lt_amount,
rpl::single(computeTotalAmount())), rpl::single(computeTotalAmount())),
st::passportPanelAuthorize) { st::paymentsPanelSubmit) {
setupControls(); setupControls();
} }
@ -150,7 +150,7 @@ not_null<Ui::RpWidget*> FormSummary::setupContent() {
push(_information.shippingAddress.city); push(_information.shippingAddress.city);
push(_information.shippingAddress.state); push(_information.shippingAddress.state);
push(_information.shippingAddress.countryIso2); push(_information.shippingAddress.countryIso2);
push(_information.shippingAddress.postCode); push(_information.shippingAddress.postcode);
info->updateContent( info->updateContent(
tr::lng_payments_shipping_address(tr::now), tr::lng_payments_shipping_address(tr::now),
(list.isEmpty() ? "enter pls" : list.join(", ")), (list.isEmpty() ? "enter pls" : list.join(", ")),
@ -200,7 +200,7 @@ not_null<Ui::RpWidget*> FormSummary::setupContent() {
const auto phone = inner->add(object_ptr<FormRow>(inner)); const auto phone = inner->add(object_ptr<FormRow>(inner));
phone->addClickHandler([=] { _delegate->panelEditPhone(); }); phone->addClickHandler([=] { _delegate->panelEditPhone(); });
phone->updateContent( phone->updateContent(
tr::lng_payments_info_email(tr::now), tr::lng_payments_info_phone(tr::now),
(_information.phone.isEmpty() (_information.phone.isEmpty()
? "enter pls" ? "enter pls"
: _information.phone), : _information.phone),

View file

@ -23,6 +23,7 @@ Panel::Panel(not_null<PanelDelegate*> delegate)
, _widget(std::make_unique<SeparatePanel>()) { , _widget(std::make_unique<SeparatePanel>()) {
_widget->setTitle(tr::lng_payments_checkout_title()); _widget->setTitle(tr::lng_payments_checkout_title());
_widget->setInnerSize(st::passportPanelSize); _widget->setInnerSize(st::passportPanelSize);
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
_widget->closeRequests( _widget->closeRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -52,18 +53,37 @@ void Panel::showForm(
current, current,
options, options,
_delegate)); _delegate));
_widget->setBackAllowed(false);
} }
void Panel::showEditInformation( void Panel::showEditInformation(
const Invoice &invoice, const Invoice &invoice,
const RequestedInformation &current, const RequestedInformation &current,
EditField field) { EditField field) {
_widget->showInner(base::make_unique_q<EditInformation>( auto edit = base::make_unique_q<EditInformation>(
_widget.get(), _widget.get(),
invoice, invoice,
current, current,
field, field,
_delegate)); _delegate);
_weakEditWidget = edit.get();
_widget->showInner(std::move(edit));
_widget->setBackAllowed(true);
_weakEditWidget->setFocus(field);
}
void Panel::showEditError(
const Invoice &invoice,
const RequestedInformation &current,
EditField field) {
if (_weakEditWidget) {
_weakEditWidget->showError(field);
} else {
showEditInformation(invoice, current, field);
if (_weakEditWidget && field == EditField::ShippingCountry) {
_weakEditWidget->showError(field);
}
}
} }
void Panel::chooseShippingOption(const ShippingOptions &options) { void Panel::chooseShippingOption(const ShippingOptions &options) {
@ -89,6 +109,10 @@ void Panel::chooseShippingOption(const ShippingOptions &options) {
})); }));
} }
rpl::producer<> Panel::backRequests() const {
return _widget->backRequests();
}
void Panel::showBox(object_ptr<Ui::BoxContent> box) { void Panel::showBox(object_ptr<Ui::BoxContent> box) {
_widget->showBox( _widget->showBox(
std::move(box), std::move(box),
@ -96,8 +120,12 @@ void Panel::showBox(object_ptr<Ui::BoxContent> box) {
anim::type::normal); anim::type::normal);
} }
void Panel::showToast(const QString &text) { void Panel::showToast(const TextWithEntities &text) {
_widget->showToast(text); _widget->showToast(text);
} }
rpl::lifetime &Panel::lifetime() {
return _widget->lifetime();
}
} // namespace Payments::Ui } // namespace Payments::Ui

View file

@ -23,6 +23,7 @@ struct Invoice;
struct RequestedInformation; struct RequestedInformation;
struct ShippingOptions; struct ShippingOptions;
enum class EditField; enum class EditField;
class EditInformation;
class Panel final { class Panel final {
public: public:
@ -39,14 +40,23 @@ public:
const Invoice &invoice, const Invoice &invoice,
const RequestedInformation &current, const RequestedInformation &current,
EditField field); EditField field);
void showEditError(
const Invoice &invoice,
const RequestedInformation &current,
EditField field);
void chooseShippingOption(const ShippingOptions &options); void chooseShippingOption(const ShippingOptions &options);
[[nodiscard]] rpl::producer<> backRequests() const;
void showBox(object_ptr<Ui::BoxContent> box); void showBox(object_ptr<Ui::BoxContent> box);
void showToast(const QString &text); void showToast(const TextWithEntities &text);
[[nodiscard]] rpl::lifetime &lifetime();
private: private:
const not_null<PanelDelegate*> _delegate; const not_null<PanelDelegate*> _delegate;
std::unique_ptr<SeparatePanel> _widget; std::unique_ptr<SeparatePanel> _widget;
QPointer<EditInformation> _weakEditWidget;
}; };

View file

@ -53,7 +53,7 @@ struct Address {
QString city; QString city;
QString state; QString state;
QString countryIso2; QString countryIso2;
QString postCode; QString postcode;
[[nodiscard]] bool valid() const { [[nodiscard]] bool valid() const {
return !address1.isEmpty() return !address1.isEmpty()
@ -70,7 +70,7 @@ struct Address {
&& (city == other.city) && (city == other.city)
&& (state == other.state) && (state == other.state)
&& (countryIso2 == other.countryIso2) && (countryIso2 == other.countryIso2)
&& (postCode == other.postCode); && (postcode == other.postcode);
} }
inline bool operator!=(const Address &other) const { inline bool operator!=(const Address &other) const {
return !(*this == other); return !(*this == other);
@ -117,7 +117,11 @@ struct SavedCredentials {
}; };
enum class EditField { enum class EditField {
ShippingInformation, ShippingStreet,
ShippingCity,
ShippingState,
ShippingCountry,
ShippingPostcode,
Name, Name,
Email, Email,
Phone, Phone,

View file

@ -21,6 +21,7 @@ using namespace ::Ui;
class PanelDelegate; class PanelDelegate;
WebviewWindow::WebviewWindow( WebviewWindow::WebviewWindow(
const QString &userDataPath,
const QString &url, const QString &url,
not_null<PanelDelegate*> delegate) { not_null<PanelDelegate*> delegate) {
if (!url.startsWith("https://", Qt::CaseInsensitive)) { if (!url.startsWith("https://", Qt::CaseInsensitive)) {
@ -49,9 +50,11 @@ WebviewWindow::WebviewWindow(
QPainter(body).fillRect(clip, st::windowBg); QPainter(body).fillRect(clip, st::windowBg);
}, body->lifetime()); }, body->lifetime());
const auto path =
_webview = Ui::CreateChild<Webview::Window>( _webview = Ui::CreateChild<Webview::Window>(
window, window,
window); window,
Webview::WindowConfig{ .userDataPath = userDataPath });
if (!_webview->widget()) { if (!_webview->widget()) {
return; return;
} }

View file

@ -22,6 +22,7 @@ class PanelDelegate;
class WebviewWindow final { class WebviewWindow final {
public: public:
WebviewWindow( WebviewWindow(
const QString &userDataPath,
const QString &url, const QString &url,
not_null<PanelDelegate*> delegate); not_null<PanelDelegate*> delegate);

View file

@ -273,4 +273,8 @@ void Domain::clearOldVersion() {
_oldVersion = 0; _oldVersion = 0;
} }
QString Domain::webviewDataPath() const {
return BaseGlobalPath() + "webview";
}
} // namespace Storage } // namespace Storage

View file

@ -44,6 +44,8 @@ public:
[[nodiscard]] int oldVersion() const; [[nodiscard]] int oldVersion() const;
void clearOldVersion(); void clearOldVersion();
[[nodiscard]] QString webviewDataPath() const;
private: private:
enum class StartModernResult { enum class StartModernResult {
Success, Success,

View file

@ -87,19 +87,24 @@ private:
}; };
CountrySelectBox::CountrySelectBox(QWidget*) CountrySelectBox::CountrySelectBox(QWidget*)
: _select(this, st::defaultMultiSelect, tr::lng_country_ph()) { : CountrySelectBox(nullptr, QString(), Type::Phones) {
} }
CountrySelectBox::CountrySelectBox(QWidget*, const QString &iso, Type type) CountrySelectBox::CountrySelectBox(QWidget*, const QString &iso, Type type)
: _type(type) : _type(type)
, _select(this, st::defaultMultiSelect, tr::lng_country_ph()) { , _select(this, st::defaultMultiSelect, tr::lng_country_ph())
, _ownedInner(this, type) {
if (Data::CountriesByISO2().contains(iso)) { if (Data::CountriesByISO2().contains(iso)) {
LastValidISO = iso; LastValidISO = iso;
} }
} }
rpl::producer<QString> CountrySelectBox::countryChosen() const { rpl::producer<QString> CountrySelectBox::countryChosen() const {
return _inner->countryChosen(); Expects(_ownedInner != nullptr || _inner != nullptr);
return (_ownedInner
? _ownedInner.data()
: _inner.data())->countryChosen();
} }
void CountrySelectBox::prepare() { void CountrySelectBox::prepare() {
@ -114,7 +119,7 @@ void CountrySelectBox::prepare() {
}); });
_inner = setInnerWidget( _inner = setInnerWidget(
object_ptr<Inner>(this, _type), std::move(_ownedInner),
st::countriesScroll, st::countriesScroll,
_select->height()); _select->height());

View file

@ -46,6 +46,7 @@ private:
object_ptr<MultiSelect> _select; object_ptr<MultiSelect> _select;
class Inner; class Inner;
object_ptr<Inner> _ownedInner;
QPointer<Inner> _inner; QPointer<Inner> _inner;
}; };

View file

@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/toast/toast.h" #include "ui/toasts/common_toasts.h"
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
@ -266,8 +266,11 @@ void SeparatePanel::showBox(
_layer->showBox(std::move(box), options, animated); _layer->showBox(std::move(box), options, animated);
} }
void SeparatePanel::showToast(const QString &text) { void SeparatePanel::showToast(const TextWithEntities &text) {
Ui::Toast::Show(this, text); Ui::ShowMultilineToast({
.parentOverride = this,
.text = text,
});
} }
void SeparatePanel::ensureLayerCreated() { void SeparatePanel::ensureLayerCreated() {

View file

@ -38,7 +38,7 @@ public:
object_ptr<Ui::BoxContent> box, object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options, Ui::LayerOptions options,
anim::type animated); anim::type animated);
void showToast(const QString &text); void showToast(const TextWithEntities &text);
void destroyLayer(); void destroyLayer();
rpl::producer<> backRequests() const; rpl::producer<> backRequests() const;