mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add better error reporting to payments.
This commit is contained in:
parent
e106bd143e
commit
ee098d00ad
12 changed files with 161 additions and 52 deletions
|
@ -1855,6 +1855,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_theme_editor_menu_show" = "Show palette file";
|
"lng_theme_editor_menu_show" = "Show palette file";
|
||||||
|
|
||||||
"lng_payments_not_supported" = "Sorry, Telegram Desktop doesn't support payments yet. Please use one of our mobile apps to do this.";
|
"lng_payments_not_supported" = "Sorry, Telegram Desktop doesn't support payments yet. Please use one of our mobile apps to do this.";
|
||||||
|
"lng_payments_webview_no_card" = "Unfortunately, you can't add a new card with current system configuration.";
|
||||||
|
"lng_payments_webview_no_use" = "Unfortunately, you can't use payments with current system configuration.";
|
||||||
|
"lng_payments_webview_install_edge" = "Please install {link}.";
|
||||||
|
"lng_payments_webview_install_webkit" = "Please install WebKitGTK 4 (webkit2gtk-4.0) using your package manager.";
|
||||||
|
"lng_payments_webview_switch_mutter" = "Qt's window embedding doesn't work well with Mutter window manager. Please switch to another window manager or desktop environment.";
|
||||||
|
"lng_payments_webview_switch_wayland" = "There is no way to embed WebView window on Wayland. Please switch to X11.";
|
||||||
"lng_payments_sure_close" = "Are you sure you want to close this payment form? The changes you made will be lost.";
|
"lng_payments_sure_close" = "Are you sure you want to close this payment form? The changes you made will be lost.";
|
||||||
"lng_payments_receipt_label" = "Receipt";
|
"lng_payments_receipt_label" = "Receipt";
|
||||||
"lng_payments_receipt_label_test" = "Test receipt";
|
"lng_payments_receipt_label_test" = "Test receipt";
|
||||||
|
@ -1903,6 +1909,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_payments_tips_box_title" = "Add Tip";
|
"lng_payments_tips_box_title" = "Add Tip";
|
||||||
"lng_payments_tips_max" = "Max possible tip amount: {amount}";
|
"lng_payments_tips_max" = "Max possible tip amount: {amount}";
|
||||||
|
|
||||||
|
"lng_payments_shipping_not_available" = "Shipping to the selected country is not available.";
|
||||||
|
"lng_payments_card_declined" = "Your card was declined.";
|
||||||
|
"lng_payments_payment_failed" = "Payment failed. Your card has not been billed.";
|
||||||
|
"lng_payments_precheckout_failed" = "The bot couldn't process your payment. Your card has not been billed.";
|
||||||
|
"lng_payments_already_paid" = "You have already paid for this item.";
|
||||||
|
|
||||||
"lng_call_status_incoming" = "is calling you...";
|
"lng_call_status_incoming" = "is calling you...";
|
||||||
"lng_call_status_connecting" = "connecting...";
|
"lng_call_status_connecting" = "connecting...";
|
||||||
"lng_call_status_exchanging" = "exchanging encryption keys...";
|
"lng_call_status_exchanging" = "exchanging encryption keys...";
|
||||||
|
|
|
@ -91,7 +91,6 @@ constexpr auto kFastRevokeRestriction = 24 * 60 * TimeId(60);
|
||||||
*data.vphoto(),
|
*data.vphoto(),
|
||||||
ImageLocation())
|
ImageLocation())
|
||||||
: nullptr),
|
: nullptr),
|
||||||
.isMultipleAllowed = item->history()->isChannel(), // #TODO payments
|
|
||||||
.isTest = data.is_test(),
|
.isTest = data.is_test(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -189,10 +188,6 @@ PollData *Media::poll() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Media::setInvoiceReceiptId(MsgId id) {
|
|
||||||
Unexpected("Media::setInvoiceReceiptId.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Media::uploading() const {
|
bool Media::uploading() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1195,11 +1190,6 @@ const Invoice *MediaInvoice::invoice() const {
|
||||||
return &_invoice;
|
return &_invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaInvoice::setInvoiceReceiptId(MsgId id) {
|
|
||||||
_invoice.receiptMsgId = id;
|
|
||||||
parent()->checkBuyButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MediaInvoice::hasReplyPreview() const {
|
bool MediaInvoice::hasReplyPreview() const {
|
||||||
if (const auto photo = _invoice.photo) {
|
if (const auto photo = _invoice.photo) {
|
||||||
return !photo->isNull();
|
return !photo->isNull();
|
||||||
|
|
|
@ -62,7 +62,6 @@ struct Invoice {
|
||||||
QString title;
|
QString title;
|
||||||
QString description;
|
QString description;
|
||||||
PhotoData *photo = nullptr;
|
PhotoData *photo = nullptr;
|
||||||
bool isMultipleAllowed = false;
|
|
||||||
bool isTest = false;
|
bool isTest = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,8 +84,6 @@ public:
|
||||||
virtual Data::CloudImage *location() const;
|
virtual Data::CloudImage *location() const;
|
||||||
virtual PollData *poll() const;
|
virtual PollData *poll() const;
|
||||||
|
|
||||||
virtual void setInvoiceReceiptId(MsgId id);
|
|
||||||
|
|
||||||
virtual bool uploading() const;
|
virtual bool uploading() const;
|
||||||
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
|
virtual Storage::SharedMediaTypesMask sharedMediaTypes() const;
|
||||||
virtual bool canBeGrouped() const;
|
virtual bool canBeGrouped() const;
|
||||||
|
@ -384,7 +381,6 @@ public:
|
||||||
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
||||||
|
|
||||||
const Invoice *invoice() const override;
|
const Invoice *invoice() const override;
|
||||||
void setInvoiceReceiptId(MsgId id) override;
|
|
||||||
|
|
||||||
bool hasReplyPreview() const override;
|
bool hasReplyPreview() const override;
|
||||||
Image *replyPreview() const override;
|
Image *replyPreview() const override;
|
||||||
|
|
|
@ -776,16 +776,9 @@ HistoryService::PreparedText HistoryService::preparePaymentSentText() {
|
||||||
if (payment->msg) {
|
if (payment->msg) {
|
||||||
if (const auto media = payment->msg->media()) {
|
if (const auto media = payment->msg->media()) {
|
||||||
if (const auto invoice = media->invoice()) {
|
if (const auto invoice = media->invoice()) {
|
||||||
if (!invoice->isMultipleAllowed
|
|
||||||
&& !invoice->receiptMsgId) {
|
|
||||||
media->setInvoiceReceiptId(id);
|
|
||||||
}
|
|
||||||
return textcmdLink(1, invoice->title);
|
return textcmdLink(1, invoice->title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QString();// tr::lng_deleted_message(tr::now);
|
|
||||||
} else if (payment->msgId) {
|
|
||||||
return QString();// tr::lng_contacts_loading(tr::now);
|
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}();
|
}();
|
||||||
|
|
|
@ -199,10 +199,14 @@ void CheckoutProcess::handleError(const Error &error) {
|
||||||
const auto &id = error.id;
|
const auto &id = error.id;
|
||||||
switch (error.type) {
|
switch (error.type) {
|
||||||
case Error::Type::Form:
|
case Error::Type::Form:
|
||||||
if (true
|
if (id == u"INVOICE_ALREADY_PAID"_q) {
|
||||||
|
_panel->showCriticalError({
|
||||||
|
tr::lng_payments_already_paid(tr::now)
|
||||||
|
});
|
||||||
|
} else if (true
|
||||||
|| id == u"PROVIDER_ACCOUNT_INVALID"_q
|
|| id == u"PROVIDER_ACCOUNT_INVALID"_q
|
||||||
|| id == u"PROVIDER_ACCOUNT_TIMEOUT"_q) {
|
|| id == u"PROVIDER_ACCOUNT_TIMEOUT"_q) {
|
||||||
showToast({ "Error: " + id });
|
_panel->showCriticalError({ "Error: " + id });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Error::Type::Validate: {
|
case Error::Type::Validate: {
|
||||||
|
@ -246,9 +250,9 @@ void CheckoutProcess::handleError(const Error &error) {
|
||||||
} else if (id == u"LOCAL_CARD_BILLING_ZIP_INVALID"_q) {
|
} else if (id == u"LOCAL_CARD_BILLING_ZIP_INVALID"_q) {
|
||||||
showCardError(CardField::AddressZip);
|
showCardError(CardField::AddressZip);
|
||||||
} else if (id == u"SHIPPING_BOT_TIMEOUT"_q) {
|
} else if (id == u"SHIPPING_BOT_TIMEOUT"_q) {
|
||||||
showToast({ "Error: Bot Timeout!" }); // #TODO payments errors message
|
showToast({ "Error: Bot Timeout!" });
|
||||||
} else if (id == u"SHIPPING_NOT_AVAILABLE"_q) {
|
} else if (id == u"SHIPPING_NOT_AVAILABLE"_q) {
|
||||||
showToast({ "Error: Shipping to the selected country is not available!" }); // #TODO payments errors message
|
showToast({ tr::lng_payments_shipping_not_available(tr::now) });
|
||||||
} else {
|
} else {
|
||||||
showToast({ "Error: " + id });
|
showToast({ "Error: " + id });
|
||||||
}
|
}
|
||||||
|
@ -264,11 +268,9 @@ void CheckoutProcess::handleError(const Error &error) {
|
||||||
|| id == u"ExpiredCard"_q) {
|
|| id == u"ExpiredCard"_q) {
|
||||||
showCardError(Field::ExpireDate);
|
showCardError(Field::ExpireDate);
|
||||||
} else if (id == u"CardDeclined"_q) {
|
} else if (id == u"CardDeclined"_q) {
|
||||||
// #TODO payments errors message
|
showToast({ tr::lng_payments_card_declined(tr::now) });
|
||||||
showToast({ "Error: " + id });
|
|
||||||
} else if (id == u"ProcessingError"_q) {
|
} else if (id == u"ProcessingError"_q) {
|
||||||
// #TODO payments errors message
|
showToast({ "Sorry, a processing error occurred." });
|
||||||
showToast({ "Error: " + id });
|
|
||||||
} else {
|
} else {
|
||||||
showToast({ "Error: " + id });
|
showToast({ "Error: " + id });
|
||||||
}
|
}
|
||||||
|
@ -287,17 +289,20 @@ void CheckoutProcess::handleError(const Error &error) {
|
||||||
if (_submitState == SubmitState::Finishing) {
|
if (_submitState == SubmitState::Finishing) {
|
||||||
_submitState = SubmitState::Validated;
|
_submitState = SubmitState::Validated;
|
||||||
}
|
}
|
||||||
if (id == u"PAYMENT_FAILED"_q) {
|
if (id == u"INVOICE_ALREADY_PAID"_q) {
|
||||||
showToast({ "Error: Payment Failed. Your card has not been billed." }); // #TODO payments errors message
|
showToast({ tr::lng_payments_already_paid(tr::now) });
|
||||||
|
} else if (id == u"PAYMENT_FAILED"_q) {
|
||||||
|
showToast({ tr::lng_payments_payment_failed(tr::now) });
|
||||||
} else if (id == u"BOT_PRECHECKOUT_FAILED"_q) {
|
} else if (id == u"BOT_PRECHECKOUT_FAILED"_q) {
|
||||||
showToast({ "Error: PreCheckout Failed. Your card has not been billed." }); // #TODO payments errors message
|
showToast({ tr::lng_payments_precheckout_failed(tr::now) });
|
||||||
} else if (id == u"REQUESTED_INFO_INVALID"_q
|
} else if (id == u"REQUESTED_INFO_INVALID"_q
|
||||||
|| id == u"SHIPPING_OPTION_INVALID"_q
|
|| id == u"SHIPPING_OPTION_INVALID"_q
|
||||||
|| id == u"PAYMENT_CREDENTIALS_INVALID"_q
|
|| id == u"PAYMENT_CREDENTIALS_INVALID"_q
|
||||||
|| id == u"PAYMENT_CREDENTIALS_ID_INVALID"_q) {
|
|| id == u"PAYMENT_CREDENTIALS_ID_INVALID"_q) {
|
||||||
|
showToast({ tr::lng_payments_payment_failed(tr::now) });
|
||||||
showToast({ "Error: " + id + ". Your card has not been billed." });
|
showToast({ "Error: " + id + ". Your card has not been billed." });
|
||||||
} else if (id == u"TMP_PASSWORD_INVALID"_q) {
|
} else if (id == u"TMP_PASSWORD_INVALID"_q) {
|
||||||
// #TODO payments save
|
requestPassword();
|
||||||
} else {
|
} else {
|
||||||
showToast({ "Error: " + id });
|
showToast({ "Error: " + id });
|
||||||
}
|
}
|
||||||
|
@ -574,6 +579,10 @@ void CheckoutProcess::panelSetPassword() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckoutProcess::panelOpenUrl(const QString &url) {
|
||||||
|
File::OpenUrl(url);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckoutProcess::getPasswordState(
|
void CheckoutProcess::getPasswordState(
|
||||||
Fn<void(const Core::CloudPasswordState&)> callback) {
|
Fn<void(const Core::CloudPasswordState&)> callback) {
|
||||||
Expects(callback != nullptr);
|
Expects(callback != nullptr);
|
||||||
|
|
|
@ -102,6 +102,7 @@ private:
|
||||||
bool saveInformation) override;
|
bool saveInformation) override;
|
||||||
bool panelWebviewNavigationAttempt(const QString &uri) override;
|
bool panelWebviewNavigationAttempt(const QString &uri) override;
|
||||||
void panelSetPassword() override;
|
void panelSetPassword() override;
|
||||||
|
void panelOpenUrl(const QString &url) override;
|
||||||
|
|
||||||
void panelCancelEdit() override;
|
void panelCancelEdit() override;
|
||||||
void panelEditPaymentMethod() override;
|
void panelEditPaymentMethod() override;
|
||||||
|
|
|
@ -9,6 +9,8 @@ using "ui/basic.style";
|
||||||
|
|
||||||
using "info/info.style";
|
using "info/info.style";
|
||||||
|
|
||||||
|
paymentsPanelSize: size(392px, 600px);
|
||||||
|
|
||||||
paymentsPanelButton: defaultBoxButton;
|
paymentsPanelButton: defaultBoxButton;
|
||||||
paymentsPanelSubmit: RoundButton(defaultActiveButton) {
|
paymentsPanelSubmit: RoundButton(defaultActiveButton) {
|
||||||
width: -36px;
|
width: -36px;
|
||||||
|
@ -116,3 +118,10 @@ paymentTipsErrorPadding: margins(22px, 6px, 22px, 0px);
|
||||||
|
|
||||||
paymentsToProviderLabel: paymentsShippingPrice;
|
paymentsToProviderLabel: paymentsShippingPrice;
|
||||||
paymentsToProviderPadding: margins(28px, 6px, 28px, 6px);
|
paymentsToProviderPadding: margins(28px, 6px, 28px, 6px);
|
||||||
|
|
||||||
|
paymentsCriticalError: FlatLabel(boxLabel) {
|
||||||
|
minWidth: 370px;
|
||||||
|
align: align(top);
|
||||||
|
textFg: windowSubTextFg;
|
||||||
|
}
|
||||||
|
paymentsCriticalErrorPadding: margins(10px, 40px, 10px, 0px);
|
||||||
|
|
|
@ -76,6 +76,7 @@ FormSummary::FormSummary(
|
||||||
, _options(options)
|
, _options(options)
|
||||||
, _information(current)
|
, _information(current)
|
||||||
, _scroll(this, st::passportPanelScroll)
|
, _scroll(this, st::passportPanelScroll)
|
||||||
|
, _layout(_scroll->setOwnedWidget(object_ptr<VerticalLayout>(this)))
|
||||||
, _topShadow(this)
|
, _topShadow(this)
|
||||||
, _bottomShadow(this)
|
, _bottomShadow(this)
|
||||||
, _submit(_invoice.receipt.paid
|
, _submit(_invoice.receipt.paid
|
||||||
|
@ -114,6 +115,20 @@ rpl::producer<int> FormSummary::scrollTopValue() const {
|
||||||
return _scroll->scrollTopValue();
|
return _scroll->scrollTopValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FormSummary::showCriticalError(const TextWithEntities &text) {
|
||||||
|
if (_invoice
|
||||||
|
|| (_scroll->height() - _layout->height()
|
||||||
|
< st::paymentsPanelSize.height() / 2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Settings::AddSkip(_layout.get(), st::paymentsPricesTopSkip);
|
||||||
|
_layout->add(object_ptr<FlatLabel>(
|
||||||
|
_layout.get(),
|
||||||
|
rpl::single(text),
|
||||||
|
st::paymentsCriticalError));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void FormSummary::updateThumbnail(const QImage &thumbnail) {
|
void FormSummary::updateThumbnail(const QImage &thumbnail) {
|
||||||
_invoice.cover.thumbnail = thumbnail;
|
_invoice.cover.thumbnail = thumbnail;
|
||||||
_thumbnails.fire_copy(thumbnail);
|
_thumbnails.fire_copy(thumbnail);
|
||||||
|
@ -149,7 +164,7 @@ int64 FormSummary::computeTotalAmount() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormSummary::setupControls() {
|
void FormSummary::setupControls() {
|
||||||
const auto inner = setupContent();
|
setupContent(_layout.get());
|
||||||
|
|
||||||
if (_submit) {
|
if (_submit) {
|
||||||
_submit->addClickHandler([=] {
|
_submit->addClickHandler([=] {
|
||||||
|
@ -173,7 +188,7 @@ void FormSummary::setupControls() {
|
||||||
_bottomShadow->toggleOn(rpl::combine(
|
_bottomShadow->toggleOn(rpl::combine(
|
||||||
_scroll->scrollTopValue(),
|
_scroll->scrollTopValue(),
|
||||||
_scroll->heightValue(),
|
_scroll->heightValue(),
|
||||||
inner->heightValue(),
|
_layout->heightValue(),
|
||||||
_1 + _2 < _3));
|
_1 + _2 < _3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,24 +548,19 @@ void FormSummary::setupSections(not_null<VerticalLayout*> layout) {
|
||||||
Settings::AddSkip(layout, st::paymentsSectionsTopSkip);
|
Settings::AddSkip(layout, st::paymentsSectionsTopSkip);
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<RpWidget*> FormSummary::setupContent() {
|
void FormSummary::setupContent(not_null<VerticalLayout*> layout) {
|
||||||
const auto inner = _scroll->setOwnedWidget(
|
|
||||||
object_ptr<VerticalLayout>(this));
|
|
||||||
|
|
||||||
_scroll->widthValue(
|
_scroll->widthValue(
|
||||||
) | rpl::start_with_next([=](int width) {
|
) | rpl::start_with_next([=](int width) {
|
||||||
inner->resizeToWidth(width);
|
layout->resizeToWidth(width);
|
||||||
}, inner->lifetime());
|
}, layout->lifetime());
|
||||||
|
|
||||||
setupCover(inner);
|
setupCover(layout);
|
||||||
if (_invoice) {
|
if (_invoice) {
|
||||||
Settings::AddDivider(inner);
|
Settings::AddDivider(layout);
|
||||||
setupPrices(inner);
|
setupPrices(layout);
|
||||||
Settings::AddDivider(inner);
|
Settings::AddDivider(layout);
|
||||||
setupSections(inner);
|
setupSections(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormSummary::resizeEvent(QResizeEvent *e) {
|
void FormSummary::resizeEvent(QResizeEvent *e) {
|
||||||
|
|
|
@ -39,11 +39,13 @@ public:
|
||||||
void updateThumbnail(const QImage &thumbnail);
|
void updateThumbnail(const QImage &thumbnail);
|
||||||
[[nodiscard]] rpl::producer<int> scrollTopValue() const;
|
[[nodiscard]] rpl::producer<int> scrollTopValue() const;
|
||||||
|
|
||||||
|
bool showCriticalError(const TextWithEntities &text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
void setupControls();
|
void setupControls();
|
||||||
[[nodiscard]] not_null<Ui::RpWidget*> setupContent();
|
void setupContent(not_null<VerticalLayout*> layout);
|
||||||
void setupCover(not_null<VerticalLayout*> layout);
|
void setupCover(not_null<VerticalLayout*> layout);
|
||||||
void setupPrices(not_null<VerticalLayout*> layout);
|
void setupPrices(not_null<VerticalLayout*> layout);
|
||||||
void setupSuggestedTips(not_null<VerticalLayout*> layout);
|
void setupSuggestedTips(not_null<VerticalLayout*> layout);
|
||||||
|
@ -61,6 +63,7 @@ private:
|
||||||
ShippingOptions _options;
|
ShippingOptions _options;
|
||||||
RequestedInformation _information;
|
RequestedInformation _information;
|
||||||
object_ptr<ScrollArea> _scroll;
|
object_ptr<ScrollArea> _scroll;
|
||||||
|
not_null<VerticalLayout*> _layout;
|
||||||
object_ptr<FadeShadow> _topShadow;
|
object_ptr<FadeShadow> _topShadow;
|
||||||
object_ptr<FadeShadow> _bottomShadow;
|
object_ptr<FadeShadow> _bottomShadow;
|
||||||
object_ptr<RoundButton> _submit;
|
object_ptr<RoundButton> _submit;
|
||||||
|
|
|
@ -17,10 +17,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/fade_wrap.h"
|
#include "ui/wrap/fade_wrap.h"
|
||||||
#include "ui/boxes/single_choice_box.h"
|
#include "ui/boxes/single_choice_box.h"
|
||||||
#include "ui/text/format_values.h"
|
#include "ui/text/format_values.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "webview/webview_embed.h"
|
#include "webview/webview_embed.h"
|
||||||
|
#include "webview/webview_interface.h"
|
||||||
#include "styles/style_payments.h"
|
#include "styles/style_payments.h"
|
||||||
#include "styles/style_passport.h"
|
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
|
||||||
namespace Payments::Ui {
|
namespace Payments::Ui {
|
||||||
|
@ -28,7 +29,7 @@ namespace Payments::Ui {
|
||||||
Panel::Panel(not_null<PanelDelegate*> delegate)
|
Panel::Panel(not_null<PanelDelegate*> delegate)
|
||||||
: _delegate(delegate)
|
: _delegate(delegate)
|
||||||
, _widget(std::make_unique<SeparatePanel>()) {
|
, _widget(std::make_unique<SeparatePanel>()) {
|
||||||
_widget->setInnerSize(st::passportPanelSize);
|
_widget->setInnerSize(st::paymentsPanelSize);
|
||||||
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
|
_widget->setWindowFlag(Qt::WindowStaysOnTopHint, false);
|
||||||
|
|
||||||
_widget->closeRequests(
|
_widget->closeRequests(
|
||||||
|
@ -56,6 +57,16 @@ void Panel::showForm(
|
||||||
const RequestedInformation ¤t,
|
const RequestedInformation ¤t,
|
||||||
const PaymentMethodDetails &method,
|
const PaymentMethodDetails &method,
|
||||||
const ShippingOptions &options) {
|
const ShippingOptions &options) {
|
||||||
|
if (invoice && !method.ready && !method.native.supported) {
|
||||||
|
const auto available = Webview::Availability();
|
||||||
|
if (available.error != Webview::Available::Error::None) {
|
||||||
|
showWebviewError(
|
||||||
|
tr::lng_payments_webview_no_use(tr::now),
|
||||||
|
available);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_testMode = invoice.isTest;
|
_testMode = invoice.isTest;
|
||||||
setTitle(invoice.receipt
|
setTitle(invoice.receipt
|
||||||
? tr::lng_payments_receipt_title()
|
? tr::lng_payments_receipt_title()
|
||||||
|
@ -250,7 +261,15 @@ void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
|
||||||
if (method.native.supported) {
|
if (method.native.supported) {
|
||||||
showEditCard(method.native, CardField::Number);
|
showEditCard(method.native, CardField::Number);
|
||||||
} else if (!showWebview(method.url, true, std::move(bottomText))) {
|
} else if (!showWebview(method.url, true, std::move(bottomText))) {
|
||||||
// #TODO payments errors not supported
|
const auto available = Webview::Availability();
|
||||||
|
if (available.error != Webview::Available::Error::None) {
|
||||||
|
showWebviewError(
|
||||||
|
tr::lng_payments_webview_no_card(tr::now),
|
||||||
|
available);
|
||||||
|
} else {
|
||||||
|
showCriticalError({ "Error: Could not initialize WebView." });
|
||||||
|
}
|
||||||
|
_widget->setBackAllowed(true);
|
||||||
} else if (method.canSaveInformation) {
|
} else if (method.canSaveInformation) {
|
||||||
const auto &padding = st::paymentsPanelPadding;
|
const auto &padding = st::paymentsPanelPadding;
|
||||||
_saveWebviewInformation = CreateChild<Checkbox>(
|
_saveWebviewInformation = CreateChild<Checkbox>(
|
||||||
|
@ -487,6 +506,67 @@ void Panel::showToast(const TextWithEntities &text) {
|
||||||
_widget->showToast(text);
|
_widget->showToast(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Panel::showCriticalError(const TextWithEntities &text) {
|
||||||
|
if (!_weakFormSummary || !_weakFormSummary->showCriticalError(text)) {
|
||||||
|
auto error = base::make_unique_q<PaddingWrap<FlatLabel>>(
|
||||||
|
_widget.get(),
|
||||||
|
object_ptr<FlatLabel>(
|
||||||
|
_widget.get(),
|
||||||
|
rpl::single(text),
|
||||||
|
st::paymentsCriticalError),
|
||||||
|
st::paymentsCriticalErrorPadding);
|
||||||
|
error->entity()->setClickHandlerFilter([=](
|
||||||
|
const ClickHandlerPtr &handler,
|
||||||
|
Qt::MouseButton) {
|
||||||
|
const auto entity = handler->getTextEntity();
|
||||||
|
if (entity.type != EntityType::CustomUrl) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_delegate->panelOpenUrl(entity.data);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
_widget->showInner(std::move(error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::showWebviewError(
|
||||||
|
const QString &text,
|
||||||
|
const Webview::Available &information) {
|
||||||
|
using Error = Webview::Available::Error;
|
||||||
|
Expects(information.error != Error::None);
|
||||||
|
|
||||||
|
auto rich = TextWithEntities{ text };
|
||||||
|
rich.append("\n\n");
|
||||||
|
switch (information.error) {
|
||||||
|
case Error::NoWebview2: {
|
||||||
|
const auto command = QString(QChar(TextCommand));
|
||||||
|
const auto text = tr::lng_payments_webview_install_edge(
|
||||||
|
tr::now,
|
||||||
|
lt_link,
|
||||||
|
command);
|
||||||
|
const auto parts = text.split(command);
|
||||||
|
rich.append(parts.value(0))
|
||||||
|
.append(Text::Link(
|
||||||
|
"Microsoft Edge WebView2 Runtime",
|
||||||
|
"https://go.microsoft.com/fwlink/p/?LinkId=2124703"))
|
||||||
|
.append(parts.value(1));
|
||||||
|
} break;
|
||||||
|
case Error::NoGtkOrWebkit2Gtk:
|
||||||
|
rich.append(tr::lng_payments_webview_install_webkit(tr::now));
|
||||||
|
break;
|
||||||
|
case Error::MutterWM:
|
||||||
|
rich.append(tr::lng_payments_webview_switch_mutter(tr::now));
|
||||||
|
break;
|
||||||
|
case Error::Wayland:
|
||||||
|
rich.append(tr::lng_payments_webview_switch_wayland(tr::now));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rich.append(QString::fromStdString(information.details));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
showCriticalError(rich);
|
||||||
|
}
|
||||||
|
|
||||||
rpl::lifetime &Panel::lifetime() {
|
rpl::lifetime &Panel::lifetime() {
|
||||||
return _widget->lifetime();
|
return _widget->lifetime();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ class Checkbox;
|
||||||
|
|
||||||
namespace Webview {
|
namespace Webview {
|
||||||
class Window;
|
class Window;
|
||||||
|
struct Available;
|
||||||
} // namespace Webview
|
} // namespace Webview
|
||||||
|
|
||||||
namespace Payments::Ui {
|
namespace Payments::Ui {
|
||||||
|
@ -80,11 +81,15 @@ public:
|
||||||
|
|
||||||
void showBox(object_ptr<Ui::BoxContent> box);
|
void showBox(object_ptr<Ui::BoxContent> box);
|
||||||
void showToast(const TextWithEntities &text);
|
void showToast(const TextWithEntities &text);
|
||||||
|
void showCriticalError(const TextWithEntities &text);
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime();
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool createWebview();
|
bool createWebview();
|
||||||
|
void showWebviewError(
|
||||||
|
const QString &text,
|
||||||
|
const Webview::Available &information);
|
||||||
void setTitle(rpl::producer<QString> title);
|
void setTitle(rpl::producer<QString> title);
|
||||||
|
|
||||||
const not_null<PanelDelegate*> _delegate;
|
const not_null<PanelDelegate*> _delegate;
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
bool saveInformation) = 0;
|
bool saveInformation) = 0;
|
||||||
virtual bool panelWebviewNavigationAttempt(const QString &uri) = 0;
|
virtual bool panelWebviewNavigationAttempt(const QString &uri) = 0;
|
||||||
virtual void panelSetPassword() = 0;
|
virtual void panelSetPassword() = 0;
|
||||||
|
virtual void panelOpenUrl(const QString &url) = 0;
|
||||||
|
|
||||||
virtual void panelCancelEdit() = 0;
|
virtual void panelCancelEdit() = 0;
|
||||||
virtual void panelEditPaymentMethod() = 0;
|
virtual void panelEditPaymentMethod() = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue