Support additional saved payment methods.

This commit is contained in:
John Preston 2022-07-26 17:01:08 +03:00
parent e492a18194
commit f7885da7dd
9 changed files with 155 additions and 77 deletions

View file

@ -2397,7 +2397,6 @@ 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_no_use" = "Unfortunately, you can't use payments with current system configuration.";
"lng_payments_webview_install_edge" = "Please install {link}."; "lng_payments_webview_install_edge" = "Please install {link}.";
"lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkit2gtk-5.0/webkit2gtk-4.1/webkit2gtk-4.0) using your package manager."; "lng_payments_webview_install_webkit" = "Please install WebKitGTK (webkit2gtk-5.0/webkit2gtk-4.1/webkit2gtk-4.0) using your package manager.";

View file

@ -853,7 +853,7 @@ inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w
upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
payments.paymentForm#4cc5563f flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector<PaymentFormMethod> saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = payments.PaymentForm; payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector<PaymentFormMethod> saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector<PaymentSavedCredentials> users:Vector<User> = payments.PaymentForm;
payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo; payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo;

View file

@ -234,6 +234,11 @@ CheckoutProcess::CheckoutProcess(
handleFormUpdate(update); handleFormUpdate(update);
}, _lifetime); }, _lifetime);
_panel->savedMethodChosen(
) | rpl::start_with_next([=](QString id) {
_form->chooseSavedMethod(id);
}, _panel->lifetime());
_panel->backRequests( _panel->backRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
panelCancelEdit(); panelCancelEdit();
@ -284,7 +289,7 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
if (!_initialSilentValidation) { if (!_initialSilentValidation) {
showForm(); showForm();
} }
if (_form->paymentMethod().savedCredentials) { if (!_form->paymentMethod().savedCredentials.empty()) {
_session->api().cloudPassword().reload(); _session->api().cloudPassword().reload();
} }
}, [&](const ThumbnailUpdated &data) { }, [&](const ThumbnailUpdated &data) {
@ -532,7 +537,8 @@ void CheckoutProcess::panelSubmit() {
|| invoice.isPhoneRequested)) { || invoice.isPhoneRequested)) {
_submitState = SubmitState::Validating; _submitState = SubmitState::Validating;
_form->validateInformation(_form->information()); _form->validateInformation(_form->information());
} else if (!method.newCredentials && !method.savedCredentials) { } else if (!method.newCredentials
&& method.savedCredentialsIndex >= method.savedCredentials.size()) {
editPaymentMethod(); editPaymentMethod();
} else if (invoice.isRecurring && !_form->details().termsAccepted) { } else if (invoice.isRecurring && !_form->details().termsAccepted) {
_panel->requestTermsAcceptance( _panel->requestTermsAcceptance(
@ -712,10 +718,13 @@ void CheckoutProcess::requestPassword() {
getPasswordState([=](const Core::CloudPasswordState &state) { getPasswordState([=](const Core::CloudPasswordState &state) {
auto fields = PasscodeBox::CloudFields::From(state); auto fields = PasscodeBox::CloudFields::From(state);
fields.customTitle = tr::lng_payments_password_title(); fields.customTitle = tr::lng_payments_password_title();
const auto &method = _form->paymentMethod();
const auto &list = method.savedCredentials;
const auto index = method.savedCredentialsIndex;
fields.customDescription = tr::lng_payments_password_description( fields.customDescription = tr::lng_payments_password_description(
tr::now, tr::now,
lt_card, lt_card,
_form->paymentMethod().savedCredentials.title); (index < list.size()) ? list[index].title : QString());
fields.customSubmitButton = tr::lng_payments_password_submit(); fields.customSubmitButton = tr::lng_payments_password_submit();
fields.customCheckCallback = [=]( fields.customCheckCallback = [=](
const Core::CloudPasswordResult &result) { const Core::CloudPasswordResult &result) {

View file

@ -314,10 +314,15 @@ void Form::processForm(const MTPDpayments_paymentForm &data) {
processSavedInformation(data); processSavedInformation(data);
}); });
} }
_paymentMethod.savedCredentials.clear();
_paymentMethod.savedCredentialsIndex = 0;
if (const auto credentials = data.vsaved_credentials()) { if (const auto credentials = data.vsaved_credentials()) {
credentials->match([&](const auto &data) { _paymentMethod.savedCredentials.reserve(credentials->v.size());
processSavedCredentials(data); for (const auto &saved : credentials->v) {
}); saved.match([&](const auto &data) {
addSavedCredentials(data);
});
}
} }
if (const auto additional = data.vadditional_methods()) { if (const auto additional = data.vadditional_methods()) {
processAdditionalPaymentMethods(additional->v); processAdditionalPaymentMethods(additional->v);
@ -344,10 +349,11 @@ void Form::processReceipt(const MTPDpayments_paymentReceipt &data) {
_shippingOptions.selectedId = _shippingOptions.list.front().id; _shippingOptions.selectedId = _shippingOptions.list.front().id;
} }
} }
_paymentMethod.savedCredentials = SavedCredentials{ _paymentMethod.savedCredentials = { {
.id = "(used)", .id = "(used)",
.title = qs(data.vcredentials_title()), .title = qs(data.vcredentials_title()),
}; } };
_paymentMethod.savedCredentialsIndex = 0;
fillPaymentMethodInformation(); fillPaymentMethodInformation();
_updates.fire(FormReady{}); _updates.fire(FormReady{});
} }
@ -467,12 +473,12 @@ void Form::processSavedInformation(const MTPDpaymentRequestedInfo &data) {
}; };
} }
void Form::processSavedCredentials( void Form::addSavedCredentials(
const MTPDpaymentSavedCredentialsCard &data) { const MTPDpaymentSavedCredentialsCard &data) {
_paymentMethod.savedCredentials = SavedCredentials{ _paymentMethod.savedCredentials.push_back({
.id = qs(data.vid()), .id = qs(data.vid()),
.title = qs(data.vtitle()), .title = qs(data.vtitle()),
}; });
refreshPaymentMethodDetails(); refreshPaymentMethodDetails();
} }
@ -489,17 +495,33 @@ void Form::processAdditionalPaymentMethods(
} }
void Form::refreshPaymentMethodDetails() { void Form::refreshPaymentMethodDetails() {
const auto &saved = _paymentMethod.savedCredentials; refreshSavedPaymentMethodDetails();
const auto &entered = _paymentMethod.newCredentials;
_paymentMethod.ui.title = entered ? entered.title : saved.title;
_paymentMethod.ui.provider = _invoice.provider; _paymentMethod.ui.provider = _invoice.provider;
_paymentMethod.ui.ready = entered || saved;
_paymentMethod.ui.native.defaultCountry = defaultCountry(); _paymentMethod.ui.native.defaultCountry = defaultCountry();
_paymentMethod.ui.canSaveInformation _paymentMethod.ui.canSaveInformation
= _paymentMethod.ui.native.canSaveInformation = _paymentMethod.ui.native.canSaveInformation
= _details.canSaveCredentials || _details.passwordMissing; = _details.canSaveCredentials || _details.passwordMissing;
} }
void Form::refreshSavedPaymentMethodDetails() {
const auto &list = _paymentMethod.savedCredentials;
const auto index = _paymentMethod.savedCredentialsIndex;
const auto &entered = _paymentMethod.newCredentials;
_paymentMethod.ui.savedMethods.clear();
if (entered) {
_paymentMethod.ui.savedMethods.push_back({ .title = entered.title });
}
for (const auto &item : list) {
_paymentMethod.ui.savedMethods.push_back({
.id = item.id,
.title = item.title,
});
}
_paymentMethod.ui.savedMethodIndex = (index < list.size())
? (index + (entered ? 1 : 0))
: 0;
}
QString Form::defaultPhone() const { QString Form::defaultPhone() const {
return _session->user()->phone(); return _session->user()->phone();
} }
@ -588,12 +610,16 @@ void Form::fillSmartGlocalNativeMethod(QJsonObject object) {
void Form::submit() { void Form::submit() {
Expects(_paymentMethod.newCredentials Expects(_paymentMethod.newCredentials
|| _paymentMethod.savedCredentials); || (_paymentMethod.savedCredentialsIndex
< _paymentMethod.savedCredentials.size()));
const auto password = _paymentMethod.newCredentials const auto index = _paymentMethod.savedCredentialsIndex;
? QByteArray() const auto &list = _paymentMethod.savedCredentials;
: _session->validTmpPassword();
if (!_paymentMethod.newCredentials && password.isEmpty()) { const auto password = (index < list.size())
? _session->validTmpPassword()
: QByteArray();
if (index < list.size() && password.isEmpty()) {
_updates.fire(TmpPasswordRequired{}); _updates.fire(TmpPasswordRequired{});
return; return;
} else if (!_session->local().isBotTrustedPayment(_details.botId)) { } else if (!_session->local().isBotTrustedPayment(_details.botId)) {
@ -618,16 +644,16 @@ void Form::submit() {
inputInvoice(), inputInvoice(),
MTP_string(_requestedInformationId), MTP_string(_requestedInformationId),
MTP_string(_shippingOptions.selectedId), MTP_string(_shippingOptions.selectedId),
(_paymentMethod.newCredentials (index < list.size()
? MTP_inputPaymentCredentials( ? MTP_inputPaymentCredentialsSaved(
MTP_string(list[index].id),
MTP_bytes(password))
: MTP_inputPaymentCredentials(
MTP_flags((_paymentMethod.newCredentials.saveOnServer MTP_flags((_paymentMethod.newCredentials.saveOnServer
&& _details.canSaveCredentials) && _details.canSaveCredentials)
? MTPDinputPaymentCredentials::Flag::f_save ? MTPDinputPaymentCredentials::Flag::f_save
: MTPDinputPaymentCredentials::Flag(0)), : MTPDinputPaymentCredentials::Flag(0)),
MTP_dataJSON(MTP_bytes(_paymentMethod.newCredentials.data))) MTP_dataJSON(MTP_bytes(_paymentMethod.newCredentials.data)))),
: MTP_inputPaymentCredentialsSaved(
MTP_string(_paymentMethod.savedCredentials.id),
MTP_bytes(password))),
MTP_long(_invoice.tipsSelected) MTP_long(_invoice.tipsSelected)
)).done([=](const MTPpayments_PaymentResult &result) { )).done([=](const MTPpayments_PaymentResult &result) {
hideProgress(); hideProgress();
@ -725,7 +751,9 @@ bool Form::hasChanges() const {
return (information != _savedInformation) return (information != _savedInformation)
|| (_stripe != nullptr) || (_stripe != nullptr)
|| (_smartglocal != nullptr) || (_smartglocal != nullptr)
|| !_paymentMethod.newCredentials.empty(); || (!_paymentMethod.newCredentials.empty()
&& (_paymentMethod.savedCredentialsIndex
>= _paymentMethod.savedCredentials.size()));
} }
bool Form::validateInformationLocal( bool Form::validateInformationLocal(
@ -940,10 +968,30 @@ void Form::setPaymentCredentials(const NewCredentials &credentials) {
Expects(!credentials.empty()); Expects(!credentials.empty());
_paymentMethod.newCredentials = credentials; _paymentMethod.newCredentials = credentials;
_paymentMethod.savedCredentialsIndex
= _paymentMethod.savedCredentials.size();
refreshSavedPaymentMethodDetails();
const auto requestNewPassword = credentials.saveOnServer const auto requestNewPassword = credentials.saveOnServer
&& !_details.canSaveCredentials && !_details.canSaveCredentials
&& _details.passwordMissing; && _details.passwordMissing;
refreshPaymentMethodDetails(); _updates.fire(PaymentMethodUpdate{ requestNewPassword });
}
void Form::chooseSavedMethod(const QString &id) {
auto &index = _paymentMethod.savedCredentialsIndex;
const auto &list = _paymentMethod.savedCredentials;
if (id.isEmpty() && _paymentMethod.newCredentials) {
index = list.size();
} else {
const auto i = ranges::find(list, id, &SavedCredentials::id);
index = (i != end(list)) ? (i - begin(list)) : 0;
}
refreshSavedPaymentMethodDetails();
const auto requestNewPassword = (index == list.size())
&& _paymentMethod.newCredentials
&& _paymentMethod.newCredentials.saveOnServer
&& !_details.canSaveCredentials
&& _details.passwordMissing;
_updates.fire(PaymentMethodUpdate{ requestNewPassword }); _updates.fire(PaymentMethodUpdate{ requestNewPassword });
} }

View file

@ -113,7 +113,8 @@ struct NativePaymentMethod {
struct PaymentMethod { struct PaymentMethod {
NativePaymentMethod native; NativePaymentMethod native;
SavedCredentials savedCredentials; std::vector<SavedCredentials> savedCredentials;
int savedCredentialsIndex = 0;
NewCredentials newCredentials; NewCredentials newCredentials;
Ui::PaymentMethodDetails ui; Ui::PaymentMethodDetails ui;
}; };
@ -222,6 +223,7 @@ public:
const Ui::UncheckedCardDetails &details, const Ui::UncheckedCardDetails &details,
bool saveInformation); bool saveInformation);
void setPaymentCredentials(const NewCredentials &credentials); void setPaymentCredentials(const NewCredentials &credentials);
void chooseSavedMethod(const QString &id);
void setHasPassword(bool has); void setHasPassword(bool has);
void setShippingOption(const QString &id); void setShippingOption(const QString &id);
void setTips(int64 value); void setTips(int64 value);
@ -254,7 +256,7 @@ private:
void processDetails(const MTPDpayments_paymentForm &data); void processDetails(const MTPDpayments_paymentForm &data);
void processDetails(const MTPDpayments_paymentReceipt &data); void processDetails(const MTPDpayments_paymentReceipt &data);
void processSavedInformation(const MTPDpaymentRequestedInfo &data); void processSavedInformation(const MTPDpaymentRequestedInfo &data);
void processSavedCredentials( void addSavedCredentials(
const MTPDpaymentSavedCredentialsCard &data); const MTPDpaymentSavedCredentialsCard &data);
void processAdditionalPaymentMethods( void processAdditionalPaymentMethods(
const QVector<MTPPaymentFormMethod> &list); const QVector<MTPPaymentFormMethod> &list);
@ -263,6 +265,7 @@ private:
void fillStripeNativeMethod(QJsonObject object); void fillStripeNativeMethod(QJsonObject object);
void fillSmartGlocalNativeMethod(QJsonObject object); void fillSmartGlocalNativeMethod(QJsonObject object);
void refreshPaymentMethodDetails(); void refreshPaymentMethodDetails();
void refreshSavedPaymentMethodDetails();
[[nodiscard]] QString defaultPhone() const; [[nodiscard]] QString defaultPhone() const;
[[nodiscard]] QString defaultCountry() const; [[nodiscard]] QString defaultCountry() const;

View file

@ -500,7 +500,9 @@ void FormSummary::setupSections(not_null<VerticalLayout*> layout) {
}; };
add( add(
tr::lng_payments_payment_method(), tr::lng_payments_payment_method(),
_method.title, (_method.savedMethods.empty()
? QString()
: _method.savedMethods[_method.savedMethodIndex].title),
&st::paymentsIconPaymentMethod, &st::paymentsIconPaymentMethod,
[=] { _delegate->panelEditPaymentMethod(); }); [=] { _delegate->panelEditPaymentMethod(); });
if (_invoice.isShippingAddressRequested) { if (_invoice.isShippingAddressRequested) {

View file

@ -227,7 +227,9 @@ void Panel::showForm(
const RequestedInformation &current, const RequestedInformation &current,
const PaymentMethodDetails &method, const PaymentMethodDetails &method,
const ShippingOptions &options) { const ShippingOptions &options) {
if (invoice && !method.ready && !method.native.supported) { if (invoice
&& method.savedMethods.empty()
&& !method.native.supported) {
const auto available = Webview::Availability(); const auto available = Webview::Availability();
if (available.error != Webview::Available::Error::None) { if (available.error != Webview::Available::Error::None) {
showWebviewError( showWebviewError(
@ -410,25 +412,35 @@ void Panel::chooseTips(const Invoice &invoice) {
} }
void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) { void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
auto bottomText = method.canSaveInformation
? rpl::producer<QString>()
: tr::lng_payments_processed_by(
lt_provider,
rpl::single(method.provider));
setTitle(tr::lng_payments_card_title()); setTitle(tr::lng_payments_card_title());
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 {
showEditCardByUrl(
method.url,
method.provider,
method.canSaveInformation);
}
}
void Panel::showEditCardByUrl(
const QString &url,
const QString &provider,
bool canSaveInformation) {
auto bottomText = canSaveInformation
? rpl::producer<QString>()
: tr::lng_payments_processed_by(lt_provider, rpl::single(provider));
if (!showWebview(url, true, std::move(bottomText))) {
const auto available = Webview::Availability(); const auto available = Webview::Availability();
if (available.error != Webview::Available::Error::None) { if (available.error != Webview::Available::Error::None) {
showWebviewError( showWebviewError(
tr::lng_payments_webview_no_card(tr::now), tr::lng_payments_webview_no_use(tr::now),
available); available);
} else { } else {
showCriticalError({ "Error: Could not initialize WebView." }); showCriticalError({ "Error: Could not initialize WebView." });
} }
_widget->setBackAllowed(true); _widget->setBackAllowed(true);
} else if (method.canSaveInformation) { } else if (canSaveInformation) {
const auto &padding = st::paymentsPanelPadding; const auto &padding = st::paymentsPanelPadding;
_saveWebviewInformation = CreateChild<Checkbox>( _saveWebviewInformation = CreateChild<Checkbox>(
_webviewBottom.get(), _webviewBottom.get(),
@ -444,23 +456,11 @@ void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
} }
void Panel::showAdditionalMethod( void Panel::showAdditionalMethod(
const PaymentMethodAdditional &method,
const QString &provider, const QString &provider,
const PaymentMethodAdditional &method) { bool canSaveInformation) {
auto bottomText = tr::lng_payments_processed_by(
lt_provider,
rpl::single(provider));
setTitle(rpl::single(method.title)); setTitle(rpl::single(method.title));
if (!showWebview(method.url, true, std::move(bottomText))) { showEditCardByUrl(method.url, provider, canSaveInformation);
const auto available = Webview::Availability();
if (available.error != Webview::Available::Error::None) {
showWebviewError(
tr::lng_payments_webview_no_use(tr::now),
available);
} else {
showCriticalError({ "Error: Could not initialize WebView." });
}
_widget->setBackAllowed(true);
}
} }
void Panel::showWebviewProgress() { void Panel::showWebviewProgress() {
@ -592,29 +592,32 @@ postEvent: function(eventType, eventData) {
} }
void Panel::choosePaymentMethod(const PaymentMethodDetails &method) { void Panel::choosePaymentMethod(const PaymentMethodDetails &method) {
const auto hasSaved = method.ready; if (method.savedMethods.empty() && method.additionalMethods.empty()) {
if (!hasSaved && method.additionalMethods.empty()) {
showEditPaymentMethod(method); showEditPaymentMethod(method);
return; return;
} }
showBox(Box([=](not_null<GenericBox*> box) { showBox(Box([=](not_null<GenericBox*> box) {
const auto save = [=](int option) { const auto save = [=](int option) {
const auto basic = hasSaved ? 1 : 0; const auto saved = int(method.savedMethods.size());
if (option > basic) { if (!option) {
const auto index = option - basic - 1; showEditPaymentMethod(method);
} else if (option > saved) {
const auto index = option - saved - 1;
Assert(index < method.additionalMethods.size()); Assert(index < method.additionalMethods.size());
showAdditionalMethod( showAdditionalMethod(
method.additionalMethods[index],
method.provider, method.provider,
method.additionalMethods[index]); method.canSaveInformation);
} else if (!option) { } else {
showEditPaymentMethod(method); const auto index = option - 1;
_savedMethodChosen.fire_copy(method.savedMethods[index].id);
} }
}; };
auto options = std::vector{ auto options = std::vector{
tr::lng_payments_new_card(tr::now), tr::lng_payments_new_card(tr::now),
}; };
if (hasSaved) { for (const auto &saved : method.savedMethods) {
options.push_back(method.title); options.push_back(saved.title);
} }
for (const auto &additional : method.additionalMethods) { for (const auto &additional : method.additionalMethods) {
options.push_back(additional.title); options.push_back(additional.title);
@ -622,7 +625,9 @@ void Panel::choosePaymentMethod(const PaymentMethodDetails &method) {
SingleChoiceBox(box, { SingleChoiceBox(box, {
.title = tr::lng_payments_payment_method(), .title = tr::lng_payments_payment_method(),
.options = std::move(options), .options = std::move(options),
.initialSelection = hasSaved ? 1 : -1, .initialSelection = (method.savedMethods.empty()
? -1
: (method.savedMethodIndex + 1)),
.callback = save, .callback = save,
}); });
})); }));
@ -823,6 +828,10 @@ rpl::producer<> Panel::backRequests() const {
return _widget->backRequests(); return _widget->backRequests();
} }
rpl::producer<QString> Panel::savedMethodChosen() const {
return _savedMethodChosen.events();
}
void Panel::showBox(object_ptr<BoxContent> box) { void Panel::showBox(object_ptr<BoxContent> box) {
if (const auto widget = _webview ? _webview->window.widget() : nullptr) { if (const auto widget = _webview ? _webview->window.widget() : nullptr) {
const auto hideNow = !widget->isHidden(); const auto hideNow = !widget->isHidden();

View file

@ -63,14 +63,15 @@ public:
InformationField field); InformationField field);
void showEditPaymentMethod(const PaymentMethodDetails &method); void showEditPaymentMethod(const PaymentMethodDetails &method);
void showAdditionalMethod( void showAdditionalMethod(
const PaymentMethodAdditional &method,
const QString &provider, const QString &provider,
const PaymentMethodAdditional &method); bool canSaveInformation);
void showEditCard( void showEditCard(const NativeMethodDetails &native, CardField field);
const NativeMethodDetails &native, void showEditCardByUrl(
CardField field); const QString &url,
void showCardError( const QString &provider,
const NativeMethodDetails &native, bool canSaveInformation);
CardField field); void showCardError(const NativeMethodDetails &native, CardField field);
void chooseShippingOption(const ShippingOptions &options); void chooseShippingOption(const ShippingOptions &options);
void chooseTips(const Invoice &invoice); void chooseTips(const Invoice &invoice);
void choosePaymentMethod(const PaymentMethodDetails &method); void choosePaymentMethod(const PaymentMethodDetails &method);
@ -86,6 +87,7 @@ public:
void updateThemeParams(const Webview::ThemeParams &params); void updateThemeParams(const Webview::ThemeParams &params);
[[nodiscard]] rpl::producer<> backRequests() const; [[nodiscard]] rpl::producer<> backRequests() const;
[[nodiscard]] rpl::producer<QString> savedMethodChosen() const;
void showBox(object_ptr<Ui::BoxContent> box); void showBox(object_ptr<Ui::BoxContent> box);
void showToast(const TextWithEntities &text); void showToast(const TextWithEntities &text);
@ -120,6 +122,7 @@ private:
rpl::variable<int> _formScrollTop; rpl::variable<int> _formScrollTop;
QPointer<EditInformation> _weakEditInformation; QPointer<EditInformation> _weakEditInformation;
QPointer<EditCard> _weakEditCard; QPointer<EditCard> _weakEditCard;
rpl::event_stream<QString> _savedMethodChosen;
bool _webviewProgress = false; bool _webviewProgress = false;
bool _testMode = false; bool _testMode = false;

View file

@ -167,13 +167,18 @@ struct PaymentMethodAdditional {
QString url; QString url;
}; };
struct PaymentMethodDetails { struct PaymentMethodSaved {
QString id;
QString title; QString title;
};
struct PaymentMethodDetails {
NativeMethodDetails native; NativeMethodDetails native;
std::vector<PaymentMethodSaved> savedMethods;
std::vector<PaymentMethodAdditional> additionalMethods; std::vector<PaymentMethodAdditional> additionalMethods;
QString url; QString url;
QString provider; QString provider;
bool ready = false; int savedMethodIndex = 0;
bool canSaveInformation = false; bool canSaveInformation = false;
}; };