mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Handle native / non-native payment methods (same way).
This commit is contained in:
parent
5e4bc200c2
commit
56031a6402
20 changed files with 360 additions and 355 deletions
Telegram
Resources/langs
SourceFiles
payments
ui/widgets
cmake
|
@ -1864,6 +1864,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_payments_total_label" = "Total";
|
||||
"lng_payments_pay_amount" = "Pay {amount}";
|
||||
"lng_payments_payment_method" = "Payment Method";
|
||||
"lng_payments_new_card" = "New Card...";
|
||||
"lng_payments_payment_method_ph" = "Enter your card details";
|
||||
"lng_payments_shipping_address" = "Shipping Information";
|
||||
"lng_payments_shipping_address_ph" = "Enter your shipping information";
|
||||
|
|
|
@ -9,7 +9,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "payments/payments_form.h"
|
||||
#include "payments/ui/payments_panel.h"
|
||||
#include "payments/ui/payments_webview.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_account.h"
|
||||
#include "main/main_domain.h"
|
||||
|
@ -17,10 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "core/local_url_handlers.h" // TryConvertUrlToLocal.
|
||||
#include "core/file_utilities.h" // File::OpenUrl.
|
||||
#include "apiwrap.h"
|
||||
#include "stripe/stripe_api_client.h"
|
||||
#include "stripe/stripe_error.h"
|
||||
#include "stripe/stripe_token.h"
|
||||
|
||||
// #TODO payments errors
|
||||
#include "mainwindow.h"
|
||||
|
@ -57,13 +54,6 @@ base::flat_map<not_null<Main::Session*>, SessionProcesses> Processes;
|
|||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] QString CardTitle(const Stripe::Card &card) {
|
||||
// Like server stores saved_credentials title.
|
||||
return Stripe::CardBrandToString(card.brand()).toLower()
|
||||
+ " *"
|
||||
+ card.last4();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CheckoutProcess::Start(not_null<const HistoryItem*> item) {
|
||||
|
@ -110,7 +100,7 @@ not_null<Ui::PanelDelegate*> CheckoutProcess::panelDelegate() {
|
|||
}
|
||||
|
||||
void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
|
||||
v::match(update.data, [&](const FormReady &) {
|
||||
v::match(update, [&](const FormReady &) {
|
||||
performInitialSilentValidation();
|
||||
if (!_initialSilentValidation) {
|
||||
showForm();
|
||||
|
@ -124,17 +114,12 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
|
|||
_submitState = SubmitState::Validated;
|
||||
panelSubmit();
|
||||
}
|
||||
}, [&](const PaymentMethodUpdate&) {
|
||||
showForm();
|
||||
}, [&](const VerificationNeeded &info) {
|
||||
if (_webviewWindow) {
|
||||
_webviewWindow->navigate(info.url);
|
||||
} else {
|
||||
_webviewWindow = std::make_unique<Ui::WebviewWindow>(
|
||||
webviewDataPath(),
|
||||
info.url,
|
||||
panelDelegate());
|
||||
if (!_webviewWindow->shown()) {
|
||||
// #TODO payments errors
|
||||
}
|
||||
if (!_panel->showWebview(info.url, false)) {
|
||||
File::OpenUrl(info.url);
|
||||
panelCloseSure();
|
||||
}
|
||||
}, [&](const PaymentFinished &result) {
|
||||
const auto weak = base::make_weak(this);
|
||||
|
@ -249,7 +234,7 @@ void CheckoutProcess::panelSubmit() {
|
|||
|| _submitState == SubmitState::Finishing) {
|
||||
return;
|
||||
}
|
||||
const auto &native = _form->nativePayment();
|
||||
const auto &method = _form->paymentMethod();
|
||||
const auto &invoice = _form->invoice();
|
||||
const auto &options = _form->shippingOptions();
|
||||
if (!options.list.empty() && options.selectedId.isEmpty()) {
|
||||
|
@ -264,24 +249,12 @@ void CheckoutProcess::panelSubmit() {
|
|||
_submitState = SubmitState::Validation;
|
||||
_form->validateInformation(_form->savedInformation());
|
||||
return;
|
||||
} else if (native
|
||||
&& !native.newCredentials
|
||||
&& !native.savedCredentials) {
|
||||
} else if (!method.newCredentials && !method.savedCredentials) {
|
||||
editPaymentMethod();
|
||||
return;
|
||||
}
|
||||
_submitState = SubmitState::Finishing;
|
||||
if (!native) {
|
||||
_webviewWindow = std::make_unique<Ui::WebviewWindow>(
|
||||
webviewDataPath(),
|
||||
_form->details().url,
|
||||
panelDelegate());
|
||||
if (!_webviewWindow->shown()) {
|
||||
// #TODO payments errors
|
||||
}
|
||||
} else if (native.newCredentials) {
|
||||
_form->send(native.newCredentials.data);
|
||||
}
|
||||
_form->submit();
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelWebviewMessage(const QJsonDocument &message) {
|
||||
|
@ -321,19 +294,25 @@ void CheckoutProcess::panelWebviewMessage(const QJsonDocument &message) {
|
|||
"Not an object received in payment credentials."));
|
||||
return;
|
||||
}
|
||||
const auto serializedCredentials = QJsonDocument(
|
||||
credentials.toObject()
|
||||
).toJson(QJsonDocument::Compact);
|
||||
|
||||
_form->send(serializedCredentials);
|
||||
crl::on_main(this, [=] {
|
||||
_form->setPaymentCredentials(NewCredentials{
|
||||
.title = title,
|
||||
.data = QJsonDocument(
|
||||
credentials.toObject()
|
||||
).toJson(QJsonDocument::Compact),
|
||||
.saveOnServer = false, // #TODO payments save
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool CheckoutProcess::panelWebviewNavigationAttempt(const QString &uri) {
|
||||
if (Core::TryConvertUrlToLocal(uri) == uri) {
|
||||
return true;
|
||||
}
|
||||
panelCloseSure();
|
||||
App::wnd()->activate();
|
||||
crl::on_main(this, [=] {
|
||||
panelCloseSure();
|
||||
App::wnd()->activate();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -346,46 +325,7 @@ void CheckoutProcess::panelEditPaymentMethod() {
|
|||
}
|
||||
|
||||
void CheckoutProcess::panelValidateCard(Ui::UncheckedCardDetails data) {
|
||||
Expects(_form->nativePayment().type == NativePayment::Type::Stripe);
|
||||
Expects(!_form->nativePayment().stripePublishableKey.isEmpty());
|
||||
|
||||
if (_stripe) {
|
||||
return;
|
||||
}
|
||||
auto configuration = Stripe::PaymentConfiguration{
|
||||
.publishableKey = _form->nativePayment().stripePublishableKey,
|
||||
.companyName = "Telegram",
|
||||
};
|
||||
_stripe = std::make_unique<Stripe::APIClient>(std::move(configuration));
|
||||
auto card = Stripe::CardParams{
|
||||
.number = data.number,
|
||||
.expMonth = data.expireMonth,
|
||||
.expYear = data.expireYear,
|
||||
.cvc = data.cvc,
|
||||
.name = data.cardholderName,
|
||||
.addressZip = data.addressZip,
|
||||
.addressCountry = data.addressCountry,
|
||||
};
|
||||
_stripe->createTokenWithCard(std::move(card), crl::guard(this, [=](
|
||||
Stripe::Token token,
|
||||
Stripe::Error error) {
|
||||
_stripe = nullptr;
|
||||
|
||||
if (error) {
|
||||
int a = 0;
|
||||
// #TODO payment errors
|
||||
} else {
|
||||
_form->setPaymentCredentials({
|
||||
.title = CardTitle(token.card()),
|
||||
.data = QJsonDocument(QJsonObject{
|
||||
{ "type", "card" },
|
||||
{ "id", token.tokenId() },
|
||||
}).toJson(QJsonDocument::Compact),
|
||||
.saveOnServer = false,
|
||||
});
|
||||
showForm();
|
||||
}
|
||||
}));
|
||||
_form->validateCard(data);
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelEditShippingInformation() {
|
||||
|
@ -408,7 +348,7 @@ void CheckoutProcess::showForm() {
|
|||
_panel->showForm(
|
||||
_form->invoice(),
|
||||
_form->savedInformation(),
|
||||
_form->nativePayment().details,
|
||||
_form->paymentMethod().ui,
|
||||
_form->shippingOptions());
|
||||
}
|
||||
|
||||
|
@ -437,7 +377,7 @@ void CheckoutProcess::chooseShippingOption() {
|
|||
}
|
||||
|
||||
void CheckoutProcess::editPaymentMethod() {
|
||||
_panel->choosePaymentMethod(_form->nativePayment().details);
|
||||
_panel->choosePaymentMethod(_form->paymentMethod().ui);
|
||||
}
|
||||
|
||||
void CheckoutProcess::panelChooseShippingOption() {
|
||||
|
@ -474,7 +414,7 @@ void CheckoutProcess::performInitialSilentValidation() {
|
|||
_form->validateInformation(saved);
|
||||
}
|
||||
|
||||
QString CheckoutProcess::webviewDataPath() const {
|
||||
QString CheckoutProcess::panelWebviewDataPath() {
|
||||
return _session->domain().local().webviewDataPath();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,17 +12,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
class HistoryItem;
|
||||
|
||||
namespace Stripe {
|
||||
class APIClient;
|
||||
} // namespace Stripe
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Payments::Ui {
|
||||
class Panel;
|
||||
class WebviewWindow;
|
||||
enum class InformationField;
|
||||
} // namespace Payments::Ui
|
||||
|
||||
|
@ -67,7 +62,6 @@ private:
|
|||
void editPaymentMethod();
|
||||
|
||||
void performInitialSilentValidation();
|
||||
[[nodiscard]] QString webviewDataPath() const;
|
||||
|
||||
void panelRequestClose() override;
|
||||
void panelCloseSure() override;
|
||||
|
@ -87,11 +81,11 @@ private:
|
|||
void panelValidateCard(Ui::UncheckedCardDetails data) override;
|
||||
void panelShowBox(object_ptr<Ui::BoxContent> box) override;
|
||||
|
||||
QString panelWebviewDataPath() override;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
const std::unique_ptr<Form> _form;
|
||||
const std::unique_ptr<Ui::Panel> _panel;
|
||||
std::unique_ptr<Ui::WebviewWindow> _webviewWindow;
|
||||
std::unique_ptr<Stripe::APIClient> _stripe;
|
||||
SubmitState _submitState = SubmitState::None;
|
||||
bool _initialSilentValidation = false;
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "main/main_session.h"
|
||||
#include "data/data_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "stripe/stripe_api_client.h"
|
||||
#include "stripe/stripe_error.h"
|
||||
#include "stripe/stripe_token.h"
|
||||
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
@ -67,6 +70,13 @@ namespace {
|
|||
MTP_string(information.shippingAddress.postcode)));
|
||||
}
|
||||
|
||||
[[nodiscard]] QString CardTitle(const Stripe::Card &card) {
|
||||
// Like server stores saved_credentials title.
|
||||
return Stripe::CardBrandToString(card.brand()).toLower()
|
||||
+ " *"
|
||||
+ card.last4();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Form::Form(not_null<Main::Session*> session, FullMsgId itemId)
|
||||
|
@ -76,6 +86,8 @@ Form::Form(not_null<Main::Session*> session, FullMsgId itemId)
|
|||
requestForm();
|
||||
}
|
||||
|
||||
Form::~Form() = default;
|
||||
|
||||
void Form::requestForm() {
|
||||
_api.request(MTPpayments_GetPaymentForm(
|
||||
MTP_int(_msgId)
|
||||
|
@ -84,7 +96,7 @@ void Form::requestForm() {
|
|||
processForm(data);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_updates.fire({ Error{ Error::Type::Form, error.type() } });
|
||||
_updates.fire(Error{ Error::Type::Form, error.type() });
|
||||
}).send();
|
||||
}
|
||||
|
||||
|
@ -105,8 +117,8 @@ void Form::processForm(const MTPDpayments_paymentForm &data) {
|
|||
processSavedCredentials(data);
|
||||
});
|
||||
}
|
||||
fillNativePaymentInformation();
|
||||
_updates.fire({ FormReady{} });
|
||||
fillPaymentMethodInformation();
|
||||
_updates.fire(FormReady{});
|
||||
}
|
||||
|
||||
void Form::processInvoice(const MTPDinvoice &data) {
|
||||
|
@ -156,30 +168,32 @@ void Form::processSavedInformation(const MTPDpaymentRequestedInfo &data) {
|
|||
|
||||
void Form::processSavedCredentials(
|
||||
const MTPDpaymentSavedCredentialsCard &data) {
|
||||
// #TODO payments not yet supported
|
||||
// #TODO payments save
|
||||
//_nativePayment.savedCredentials = SavedCredentials{
|
||||
// .id = qs(data.vid()),
|
||||
// .title = qs(data.vtitle()),
|
||||
//};
|
||||
refreshNativePaymentDetails();
|
||||
refreshPaymentMethodDetails();
|
||||
}
|
||||
|
||||
void Form::refreshNativePaymentDetails() {
|
||||
const auto &saved = _nativePayment.savedCredentials;
|
||||
const auto &entered = _nativePayment.newCredentials;
|
||||
_nativePayment.details.credentialsTitle = entered
|
||||
? entered.title
|
||||
: saved.title;
|
||||
_nativePayment.details.ready = entered || saved;
|
||||
void Form::refreshPaymentMethodDetails() {
|
||||
const auto &saved = _paymentMethod.savedCredentials;
|
||||
const auto &entered = _paymentMethod.newCredentials;
|
||||
_paymentMethod.ui.title = entered ? entered.title : saved.title;
|
||||
_paymentMethod.ui.ready = entered || saved;
|
||||
}
|
||||
|
||||
void Form::fillNativePaymentInformation() {
|
||||
auto saved = std::move(_nativePayment.savedCredentials);
|
||||
auto entered = std::move(_nativePayment.newCredentials);
|
||||
_nativePayment = NativePayment();
|
||||
if (_details.nativeProvider != "stripe") {
|
||||
return;
|
||||
void Form::fillPaymentMethodInformation() {
|
||||
_paymentMethod.native = NativePaymentMethod();
|
||||
_paymentMethod.ui.native = Ui::NativeMethodDetails();
|
||||
_paymentMethod.ui.url = _details.url;
|
||||
if (_details.nativeProvider == "stripe") {
|
||||
fillStripeNativeMethod();
|
||||
}
|
||||
refreshPaymentMethodDetails();
|
||||
}
|
||||
|
||||
void Form::fillStripeNativeMethod() {
|
||||
auto error = QJsonParseError();
|
||||
auto document = QJsonDocument::fromJson(
|
||||
_details.nativeParamsJson,
|
||||
|
@ -202,22 +216,22 @@ void Form::fillNativePaymentInformation() {
|
|||
LOG(("Payment Error: No publishable_key in native_params."));
|
||||
return;
|
||||
}
|
||||
_nativePayment = NativePayment{
|
||||
.type = NativePayment::Type::Stripe,
|
||||
.stripePublishableKey = key,
|
||||
.savedCredentials = std::move(saved),
|
||||
.newCredentials = std::move(entered),
|
||||
.details = Ui::NativePaymentDetails{
|
||||
.supported = true,
|
||||
.needCountry = value(u"need_country").toBool(),
|
||||
.needZip = value(u"need_zip").toBool(),
|
||||
.needCardholderName = value(u"need_cardholder_name").toBool(),
|
||||
_paymentMethod.native = NativePaymentMethod{
|
||||
.data = StripePaymentMethod{
|
||||
.publishableKey = key,
|
||||
},
|
||||
};
|
||||
refreshNativePaymentDetails();
|
||||
_paymentMethod.ui.native = Ui::NativeMethodDetails{
|
||||
.supported = true,
|
||||
.needCountry = value(u"need_country").toBool(),
|
||||
.needZip = value(u"need_zip").toBool(),
|
||||
.needCardholderName = value(u"need_cardholder_name").toBool(),
|
||||
};
|
||||
}
|
||||
|
||||
void Form::send(const QByteArray &serializedCredentials) {
|
||||
void Form::submit() {
|
||||
Expects(!_paymentMethod.newCredentials.data.isEmpty()); // #TODO payments save
|
||||
|
||||
using Flag = MTPpayments_SendPaymentForm::Flag;
|
||||
_api.request(MTPpayments_SendPaymentForm(
|
||||
MTP_flags((_requestedInformationId.isEmpty()
|
||||
|
@ -231,15 +245,15 @@ void Form::send(const QByteArray &serializedCredentials) {
|
|||
MTP_string(_shippingOptions.selectedId),
|
||||
MTP_inputPaymentCredentials(
|
||||
MTP_flags(0),
|
||||
MTP_dataJSON(MTP_bytes(serializedCredentials)))
|
||||
MTP_dataJSON(MTP_bytes(_paymentMethod.newCredentials.data)))
|
||||
)).done([=](const MTPpayments_PaymentResult &result) {
|
||||
result.match([&](const MTPDpayments_paymentResult &data) {
|
||||
_updates.fire({ PaymentFinished{ data.vupdates() } });
|
||||
_updates.fire(PaymentFinished{ data.vupdates() });
|
||||
}, [&](const MTPDpayments_paymentVerificationNeeded &data) {
|
||||
_updates.fire({ VerificationNeeded{ qs(data.vurl()) } });
|
||||
_updates.fire(VerificationNeeded{ qs(data.vurl()) });
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_updates.fire({ Error{ Error::Type::Send, error.type() } });
|
||||
_updates.fire(Error{ Error::Type::Send, error.type() });
|
||||
}).send();
|
||||
}
|
||||
|
||||
|
@ -273,18 +287,76 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
|
|||
_shippingOptions.selectedId = _shippingOptions.list.front().id;
|
||||
}
|
||||
_savedInformation = _validatedInformation;
|
||||
_updates.fire({ ValidateFinished{} });
|
||||
_updates.fire(ValidateFinished{});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_validateRequestId = 0;
|
||||
_updates.fire({ Error{ Error::Type::Validate, error.type() } });
|
||||
_updates.fire(Error{ Error::Type::Validate, error.type() });
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Form::validateCard(const Ui::UncheckedCardDetails &details) {
|
||||
Expects(!v::is_null(_paymentMethod.native.data));
|
||||
|
||||
const auto &native = _paymentMethod.native.data;
|
||||
if (const auto stripe = std::get_if<StripePaymentMethod>(&native)) {
|
||||
validateCard(*stripe, details);
|
||||
} else {
|
||||
Unexpected("Native payment provider in Form::validateCard.");
|
||||
}
|
||||
}
|
||||
|
||||
void Form::validateCard(
|
||||
const StripePaymentMethod &method,
|
||||
const Ui::UncheckedCardDetails &details) {
|
||||
Expects(!method.publishableKey.isEmpty());
|
||||
|
||||
if (_stripe) {
|
||||
return;
|
||||
}
|
||||
auto configuration = Stripe::PaymentConfiguration{
|
||||
.publishableKey = method.publishableKey,
|
||||
.companyName = "Telegram",
|
||||
};
|
||||
_stripe = std::make_unique<Stripe::APIClient>(std::move(configuration));
|
||||
auto card = Stripe::CardParams{
|
||||
.number = details.number,
|
||||
.expMonth = details.expireMonth,
|
||||
.expYear = details.expireYear,
|
||||
.cvc = details.cvc,
|
||||
.name = details.cardholderName,
|
||||
.addressZip = details.addressZip,
|
||||
.addressCountry = details.addressCountry,
|
||||
};
|
||||
_stripe->createTokenWithCard(std::move(card), crl::guard(this, [=](
|
||||
Stripe::Token token,
|
||||
Stripe::Error error) {
|
||||
_stripe = nullptr;
|
||||
|
||||
if (error) {
|
||||
LOG(("Stripe Error %1: %2 (%3)"
|
||||
).arg(int(error.code())
|
||||
).arg(error.description()
|
||||
).arg(error.message()));
|
||||
_updates.fire(Error{ Error::Type::Stripe, error.description() });
|
||||
} else {
|
||||
setPaymentCredentials({
|
||||
.title = CardTitle(token.card()),
|
||||
.data = QJsonDocument(QJsonObject{
|
||||
{ "type", "card" },
|
||||
{ "id", token.tokenId() },
|
||||
}).toJson(QJsonDocument::Compact),
|
||||
.saveOnServer = false, // #TODO payments save
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void Form::setPaymentCredentials(const NewCredentials &credentials) {
|
||||
Expects(!credentials.empty());
|
||||
|
||||
_nativePayment.newCredentials = credentials;
|
||||
refreshNativePaymentDetails();
|
||||
_paymentMethod.newCredentials = credentials;
|
||||
refreshPaymentMethodDetails();
|
||||
_updates.fire(PaymentMethodUpdate{});
|
||||
}
|
||||
|
||||
void Form::setShippingOption(const QString &id) {
|
||||
|
|
|
@ -8,8 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
#include "payments/ui/payments_panel_data.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
namespace Stripe {
|
||||
class APIClient;
|
||||
} // namespace Stripe
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -58,55 +63,64 @@ struct NewCredentials {
|
|||
}
|
||||
};
|
||||
|
||||
struct NativePayment {
|
||||
enum class Type {
|
||||
None,
|
||||
Stripe,
|
||||
};
|
||||
Type type = Type::None;
|
||||
QString stripePublishableKey;
|
||||
SavedCredentials savedCredentials;
|
||||
NewCredentials newCredentials;
|
||||
Ui::NativePaymentDetails details;
|
||||
struct StripePaymentMethod {
|
||||
QString publishableKey;
|
||||
};
|
||||
|
||||
struct NativePaymentMethod {
|
||||
std::variant<
|
||||
v::null_t,
|
||||
StripePaymentMethod> data;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return (type != Type::None);
|
||||
return !v::is_null(data);
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
};
|
||||
|
||||
struct PaymentMethod {
|
||||
NativePaymentMethod native;
|
||||
SavedCredentials savedCredentials;
|
||||
NewCredentials newCredentials;
|
||||
Ui::PaymentMethodDetails ui;
|
||||
};
|
||||
|
||||
struct FormReady {};
|
||||
struct ValidateFinished {};
|
||||
struct Error {
|
||||
enum class Type {
|
||||
Form,
|
||||
Validate,
|
||||
Send,
|
||||
};
|
||||
Type type = Type::Form;
|
||||
QString id;
|
||||
};
|
||||
struct PaymentMethodUpdate {};
|
||||
struct VerificationNeeded {
|
||||
QString url;
|
||||
};
|
||||
struct PaymentFinished {
|
||||
MTPUpdates updates;
|
||||
};
|
||||
|
||||
struct FormUpdate {
|
||||
std::variant<
|
||||
FormReady,
|
||||
VerificationNeeded,
|
||||
ValidateFinished,
|
||||
PaymentFinished,
|
||||
Error> data;
|
||||
struct Error {
|
||||
enum class Type {
|
||||
Form,
|
||||
Validate,
|
||||
Stripe,
|
||||
Send,
|
||||
};
|
||||
Type type = Type::Form;
|
||||
QString id;
|
||||
};
|
||||
|
||||
class Form final {
|
||||
struct FormUpdate : std::variant<
|
||||
FormReady,
|
||||
ValidateFinished,
|
||||
PaymentMethodUpdate,
|
||||
VerificationNeeded,
|
||||
PaymentFinished,
|
||||
Error> {
|
||||
using variant::variant;
|
||||
};
|
||||
|
||||
class Form final : public base::has_weak_ptr {
|
||||
public:
|
||||
Form(not_null<Main::Session*> session, FullMsgId itemId);
|
||||
~Form();
|
||||
|
||||
[[nodiscard]] const Ui::Invoice &invoice() const {
|
||||
return _invoice;
|
||||
|
@ -117,8 +131,8 @@ public:
|
|||
[[nodiscard]] const Ui::RequestedInformation &savedInformation() const {
|
||||
return _savedInformation;
|
||||
}
|
||||
[[nodiscard]] const NativePayment &nativePayment() const {
|
||||
return _nativePayment;
|
||||
[[nodiscard]] const PaymentMethod &paymentMethod() const {
|
||||
return _paymentMethod;
|
||||
}
|
||||
[[nodiscard]] const Ui::ShippingOptions &shippingOptions() const {
|
||||
return _shippingOptions;
|
||||
|
@ -129,9 +143,10 @@ public:
|
|||
}
|
||||
|
||||
void validateInformation(const Ui::RequestedInformation &information);
|
||||
void validateCard(const Ui::UncheckedCardDetails &details);
|
||||
void setPaymentCredentials(const NewCredentials &credentials);
|
||||
void setShippingOption(const QString &id);
|
||||
void send(const QByteArray &serializedCredentials);
|
||||
void submit();
|
||||
|
||||
private:
|
||||
void requestForm();
|
||||
|
@ -142,8 +157,13 @@ private:
|
|||
void processSavedCredentials(
|
||||
const MTPDpaymentSavedCredentialsCard &data);
|
||||
void processShippingOptions(const QVector<MTPShippingOption> &data);
|
||||
void fillNativePaymentInformation();
|
||||
void refreshNativePaymentDetails();
|
||||
void fillPaymentMethodInformation();
|
||||
void fillStripeNativeMethod();
|
||||
void refreshPaymentMethodDetails();
|
||||
|
||||
void validateCard(
|
||||
const StripePaymentMethod &method,
|
||||
const Ui::UncheckedCardDetails &details);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
@ -152,11 +172,13 @@ private:
|
|||
Ui::Invoice _invoice;
|
||||
FormDetails _details;
|
||||
Ui::RequestedInformation _savedInformation;
|
||||
NativePayment _nativePayment;
|
||||
PaymentMethod _paymentMethod;
|
||||
|
||||
Ui::RequestedInformation _validatedInformation;
|
||||
mtpRequestId _validateRequestId = 0;
|
||||
|
||||
std::unique_ptr<Stripe::APIClient> _stripe;
|
||||
|
||||
Ui::ShippingOptions _shippingOptions;
|
||||
QString _requestedInformationId;
|
||||
|
||||
|
|
|
@ -11,6 +11,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace Stripe {
|
||||
|
||||
Error::Code Error::code() const {
|
||||
return _code;
|
||||
}
|
||||
|
||||
QString Error::description() const {
|
||||
return _description;
|
||||
}
|
||||
|
||||
QString Error::message() const {
|
||||
return _message;
|
||||
}
|
||||
|
||||
QString Error::parameter() const {
|
||||
return _parameter;
|
||||
}
|
||||
|
||||
Error Error::None() {
|
||||
return Error(Code::None, {}, {}, {});
|
||||
}
|
||||
|
||||
Error Error::DecodedObjectFromResponse(QJsonObject object) {
|
||||
const auto entry = object.value("error");
|
||||
if (!entry.isObject()) {
|
||||
|
@ -80,4 +100,8 @@ Error Error::DecodedObjectFromResponse(QJsonObject object) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Error::empty() const {
|
||||
return (_code == Code::None);
|
||||
}
|
||||
|
||||
} // namespace Stripe
|
||||
|
|
|
@ -42,14 +42,15 @@ public:
|
|||
, _parameter(parameter) {
|
||||
}
|
||||
|
||||
[[nodiscard]] static Error None() {
|
||||
return Error(Code::None, QString(), QString());
|
||||
}
|
||||
[[nodiscard]] Code code() const;
|
||||
[[nodiscard]] QString description() const;
|
||||
[[nodiscard]] QString message() const;
|
||||
[[nodiscard]] QString parameter() const;
|
||||
|
||||
[[nodiscard]] static Error None();
|
||||
[[nodiscard]] static Error DecodedObjectFromResponse(QJsonObject object);
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return (_code == Code::None);
|
||||
}
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return !empty();
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ constexpr auto kMaxPostcodeSize = 10;
|
|||
|
||||
EditCard::EditCard(
|
||||
QWidget *parent,
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field,
|
||||
not_null<PanelDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
|
|
|
@ -31,7 +31,7 @@ class EditCard final : public RpWidget {
|
|||
public:
|
||||
EditCard(
|
||||
QWidget *parent,
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field,
|
||||
not_null<PanelDelegate*> delegate);
|
||||
|
||||
|
@ -52,7 +52,7 @@ private:
|
|||
[[nodiscard]] UncheckedCardDetails collect() const;
|
||||
|
||||
const not_null<PanelDelegate*> _delegate;
|
||||
NativePaymentDetails _native;
|
||||
NativeMethodDetails _native;
|
||||
|
||||
object_ptr<ScrollArea> _scroll;
|
||||
object_ptr<FadeShadow> _topShadow;
|
||||
|
|
|
@ -30,12 +30,12 @@ FormSummary::FormSummary(
|
|||
QWidget *parent,
|
||||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
const NativePaymentDetails &native,
|
||||
const PaymentMethodDetails &method,
|
||||
const ShippingOptions &options,
|
||||
not_null<PanelDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
, _invoice(invoice)
|
||||
, _native(native)
|
||||
, _method(method)
|
||||
, _options(options)
|
||||
, _information(current)
|
||||
, _scroll(this, st::passportPanelScroll)
|
||||
|
@ -136,20 +136,18 @@ not_null<Ui::RpWidget*> FormSummary::setupContent() {
|
|||
st::passportFormDividerHeight),
|
||||
{ 0, 0, 0, st::passportFormHeaderPadding.top() });
|
||||
|
||||
if (_native.supported) {
|
||||
const auto method = inner->add(object_ptr<FormRow>(inner));
|
||||
method->addClickHandler([=] {
|
||||
_delegate->panelEditPaymentMethod();
|
||||
});
|
||||
method->updateContent(
|
||||
tr::lng_payments_payment_method(tr::now),
|
||||
(_native.ready
|
||||
? _native.credentialsTitle
|
||||
: tr::lng_payments_payment_method_ph(tr::now)),
|
||||
_native.ready,
|
||||
false,
|
||||
anim::type::instant);
|
||||
}
|
||||
const auto method = inner->add(object_ptr<FormRow>(inner));
|
||||
method->addClickHandler([=] {
|
||||
_delegate->panelEditPaymentMethod();
|
||||
});
|
||||
method->updateContent(
|
||||
tr::lng_payments_payment_method(tr::now),
|
||||
(_method.ready
|
||||
? _method.title
|
||||
: tr::lng_payments_payment_method_ph(tr::now)),
|
||||
_method.ready,
|
||||
false,
|
||||
anim::type::instant);
|
||||
if (_invoice.isShippingAddressRequested) {
|
||||
const auto info = inner->add(object_ptr<FormRow>(inner));
|
||||
info->addClickHandler([=] {
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
QWidget *parent,
|
||||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
const NativePaymentDetails &native,
|
||||
const PaymentMethodDetails &method,
|
||||
const ShippingOptions &options,
|
||||
not_null<PanelDelegate*> delegate);
|
||||
|
||||
|
@ -45,7 +45,7 @@ private:
|
|||
|
||||
const not_null<PanelDelegate*> _delegate;
|
||||
Invoice _invoice;
|
||||
NativePaymentDetails _native;
|
||||
PaymentMethodDetails _method;
|
||||
ShippingOptions _options;
|
||||
RequestedInformation _information;
|
||||
object_ptr<ScrollArea> _scroll;
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/separate_panel.h"
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "webview/webview_embed.h"
|
||||
#include "styles/style_payments.h"
|
||||
#include "styles/style_passport.h"
|
||||
|
||||
|
@ -37,7 +38,10 @@ Panel::Panel(not_null<PanelDelegate*> delegate)
|
|||
}, _widget->lifetime());
|
||||
}
|
||||
|
||||
Panel::~Panel() = default;
|
||||
Panel::~Panel() {
|
||||
// Destroy _widget before _webview.
|
||||
_widget = nullptr;
|
||||
}
|
||||
|
||||
void Panel::requestActivate() {
|
||||
_widget->showAndActivate();
|
||||
|
@ -46,14 +50,14 @@ void Panel::requestActivate() {
|
|||
void Panel::showForm(
|
||||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
const NativePaymentDetails &native,
|
||||
const PaymentMethodDetails &method,
|
||||
const ShippingOptions &options) {
|
||||
_widget->showInner(
|
||||
base::make_unique_q<FormSummary>(
|
||||
_widget.get(),
|
||||
invoice,
|
||||
current,
|
||||
native,
|
||||
method,
|
||||
options,
|
||||
_delegate));
|
||||
_widget->setBackAllowed(false);
|
||||
|
@ -113,23 +117,84 @@ void Panel::chooseShippingOption(const ShippingOptions &options) {
|
|||
}));
|
||||
}
|
||||
|
||||
void Panel::choosePaymentMethod(const NativePaymentDetails &native) {
|
||||
Expects(native.supported);
|
||||
void Panel::showEditPaymentMethod(const PaymentMethodDetails &method) {
|
||||
if (method.native.supported) {
|
||||
showEditCard(method.native, CardField::Number);
|
||||
} else if (!showWebview(method.url, true)) {
|
||||
// #TODO payments errors not supported
|
||||
}
|
||||
}
|
||||
|
||||
if (!native.ready) {
|
||||
showEditCard(native, CardField::Number);
|
||||
bool Panel::showWebview(const QString &url, bool allowBack) {
|
||||
if (!_webview && !createWebview()) {
|
||||
return false;
|
||||
}
|
||||
_webview->navigate(url);
|
||||
_widget->setBackAllowed(allowBack);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Panel::createWebview() {
|
||||
auto container = base::make_unique_q<RpWidget>(_widget.get());
|
||||
|
||||
container->setGeometry(_widget->innerGeometry());
|
||||
container->show();
|
||||
|
||||
_webview = std::make_unique<Webview::Window>(
|
||||
container.get(),
|
||||
Webview::WindowConfig{
|
||||
.userDataPath = _delegate->panelWebviewDataPath(),
|
||||
});
|
||||
const auto raw = _webview.get();
|
||||
QObject::connect(container.get(), &QObject::destroyed, [=] {
|
||||
if (_webview.get() == raw) {
|
||||
_webview = nullptr;
|
||||
}
|
||||
});
|
||||
if (!raw->widget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
container->geometryValue(
|
||||
) | rpl::start_with_next([=](QRect geometry) {
|
||||
raw->widget()->setGeometry(geometry);
|
||||
}, container->lifetime());
|
||||
|
||||
raw->setMessageHandler([=](const QJsonDocument &message) {
|
||||
_delegate->panelWebviewMessage(message);
|
||||
});
|
||||
|
||||
raw->setNavigationHandler([=](const QString &uri) {
|
||||
return _delegate->panelWebviewNavigationAttempt(uri);
|
||||
});
|
||||
|
||||
raw->init(R"(
|
||||
window.TelegramWebviewProxy = {
|
||||
postEvent: function(eventType, eventData) {
|
||||
if (window.external && window.external.invoke) {
|
||||
window.external.invoke(JSON.stringify([eventType, eventData]));
|
||||
}
|
||||
}
|
||||
};)");
|
||||
|
||||
_widget->showInner(std::move(container));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Panel::choosePaymentMethod(const PaymentMethodDetails &method) {
|
||||
if (!method.ready) {
|
||||
showEditPaymentMethod(method);
|
||||
return;
|
||||
}
|
||||
const auto title = native.credentialsTitle;
|
||||
showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto save = [=](int option) {
|
||||
if (option) {
|
||||
showEditCard(native, CardField::Number);
|
||||
showEditPaymentMethod(method);
|
||||
}
|
||||
};
|
||||
SingleChoiceBox(box, {
|
||||
.title = tr::lng_payments_payment_method(),
|
||||
.options = { native.credentialsTitle, "New Card..." }, // #TODO payments lang
|
||||
.options = { method.title, tr::lng_payments_new_card(tr::now) },
|
||||
.initialSelection = 0,
|
||||
.callback = save,
|
||||
});
|
||||
|
@ -137,8 +202,10 @@ void Panel::choosePaymentMethod(const NativePaymentDetails &native) {
|
|||
}
|
||||
|
||||
void Panel::showEditCard(
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field) {
|
||||
Expects(native.supported);
|
||||
|
||||
auto edit = base::make_unique_q<EditCard>(
|
||||
_widget.get(),
|
||||
native,
|
||||
|
@ -151,7 +218,7 @@ void Panel::showEditCard(
|
|||
}
|
||||
|
||||
void Panel::showCardError(
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field) {
|
||||
if (_weakEditCard) {
|
||||
_weakEditCard->showError(field);
|
||||
|
|
|
@ -14,6 +14,10 @@ class SeparatePanel;
|
|||
class BoxContent;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Webview {
|
||||
class Window;
|
||||
} // namespace Webview
|
||||
|
||||
namespace Payments::Ui {
|
||||
|
||||
using namespace ::Ui;
|
||||
|
@ -26,7 +30,8 @@ enum class InformationField;
|
|||
enum class CardField;
|
||||
class EditInformation;
|
||||
class EditCard;
|
||||
struct NativePaymentDetails;
|
||||
struct PaymentMethodDetails;
|
||||
struct NativeMethodDetails;
|
||||
|
||||
class Panel final {
|
||||
public:
|
||||
|
@ -38,7 +43,7 @@ public:
|
|||
void showForm(
|
||||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
const NativePaymentDetails &native,
|
||||
const PaymentMethodDetails &method,
|
||||
const ShippingOptions &options);
|
||||
void showEditInformation(
|
||||
const Invoice &invoice,
|
||||
|
@ -48,14 +53,17 @@ public:
|
|||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
InformationField field);
|
||||
void showEditPaymentMethod(const PaymentMethodDetails &method);
|
||||
void showEditCard(
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field);
|
||||
void showCardError(
|
||||
const NativePaymentDetails &native,
|
||||
const NativeMethodDetails &native,
|
||||
CardField field);
|
||||
void chooseShippingOption(const ShippingOptions &options);
|
||||
void choosePaymentMethod(const NativePaymentDetails &native);
|
||||
void choosePaymentMethod(const PaymentMethodDetails &method);
|
||||
|
||||
bool showWebview(const QString &url, bool allowBack);
|
||||
|
||||
[[nodiscard]] rpl::producer<> backRequests() const;
|
||||
|
||||
|
@ -65,8 +73,11 @@ public:
|
|||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
bool createWebview();
|
||||
|
||||
const not_null<PanelDelegate*> _delegate;
|
||||
std::unique_ptr<SeparatePanel> _widget;
|
||||
std::unique_ptr<Webview::Window> _webview;
|
||||
QPointer<EditInformation> _weakEditInformation;
|
||||
QPointer<EditCard> _weakEditCard;
|
||||
|
||||
|
|
|
@ -115,15 +115,20 @@ enum class InformationField {
|
|||
Phone,
|
||||
};
|
||||
|
||||
struct NativePaymentDetails {
|
||||
QString credentialsTitle;
|
||||
bool ready = false;
|
||||
struct NativeMethodDetails {
|
||||
bool supported = false;
|
||||
bool needCountry = false;
|
||||
bool needZip = false;
|
||||
bool needCardholderName = false;
|
||||
};
|
||||
|
||||
struct PaymentMethodDetails {
|
||||
QString title;
|
||||
NativeMethodDetails native;
|
||||
QString url;
|
||||
bool ready = false;
|
||||
};
|
||||
|
||||
enum class CardField {
|
||||
Number,
|
||||
CVC,
|
||||
|
|
|
@ -42,6 +42,8 @@ public:
|
|||
virtual void panelValidateInformation(RequestedInformation data) = 0;
|
||||
virtual void panelValidateCard(Ui::UncheckedCardDetails data) = 0;
|
||||
virtual void panelShowBox(object_ptr<BoxContent> box) = 0;
|
||||
|
||||
virtual QString panelWebviewDataPath() = 0;
|
||||
};
|
||||
|
||||
} // namespace Payments::Ui
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
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_webview.h"
|
||||
|
||||
#include "payments/ui/payments_panel_delegate.h"
|
||||
#include "webview/webview_embed.h"
|
||||
#include "webview/webview_interface.h"
|
||||
#include "ui/widgets/window.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
||||
namespace Payments::Ui {
|
||||
|
||||
using namespace ::Ui;
|
||||
|
||||
class PanelDelegate;
|
||||
|
||||
WebviewWindow::WebviewWindow(
|
||||
const QString &userDataPath,
|
||||
const QString &url,
|
||||
not_null<PanelDelegate*> delegate) {
|
||||
if (!url.startsWith("https://", Qt::CaseInsensitive)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto window = &_window;
|
||||
|
||||
window->setGeometry({
|
||||
style::ConvertScale(100),
|
||||
style::ConvertScale(100),
|
||||
style::ConvertScale(640),
|
||||
style::ConvertScale(480)
|
||||
});
|
||||
window->show();
|
||||
|
||||
window->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
|
||||
if (e->type() == QEvent::Close) {
|
||||
delegate->panelCloseSure();
|
||||
}
|
||||
}, window->lifetime());
|
||||
|
||||
const auto body = window->body();
|
||||
body->paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
QPainter(body).fillRect(clip, st::windowBg);
|
||||
}, body->lifetime());
|
||||
|
||||
const auto path =
|
||||
_webview = Ui::CreateChild<Webview::Window>(
|
||||
window,
|
||||
window,
|
||||
Webview::WindowConfig{ .userDataPath = userDataPath });
|
||||
if (!_webview->widget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
body->geometryValue(
|
||||
) | rpl::start_with_next([=](QRect geometry) {
|
||||
_webview->widget()->setGeometry(geometry);
|
||||
}, body->lifetime());
|
||||
|
||||
_webview->setMessageHandler([=](const QJsonDocument &message) {
|
||||
delegate->panelWebviewMessage(message);
|
||||
});
|
||||
|
||||
_webview->setNavigationHandler([=](const QString &uri) {
|
||||
return delegate->panelWebviewNavigationAttempt(uri);
|
||||
});
|
||||
|
||||
_webview->init(R"(
|
||||
window.TelegramWebviewProxy = {
|
||||
postEvent: function(eventType, eventData) {
|
||||
if (window.external && window.external.invoke) {
|
||||
window.external.invoke(JSON.stringify([eventType, eventData]));
|
||||
}
|
||||
}
|
||||
};)");
|
||||
|
||||
navigate(url);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool WebviewWindow::shown() const {
|
||||
return _webview && _webview->widget();
|
||||
}
|
||||
|
||||
void WebviewWindow::navigate(const QString &url) {
|
||||
if (shown()) {
|
||||
_webview->navigate(url);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Payments::Ui
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
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 "ui/widgets/window.h"
|
||||
|
||||
namespace Webview {
|
||||
class Window;
|
||||
} // namespace Webview
|
||||
|
||||
namespace Payments::Ui {
|
||||
|
||||
using namespace ::Ui;
|
||||
|
||||
class PanelDelegate;
|
||||
|
||||
class WebviewWindow final {
|
||||
public:
|
||||
WebviewWindow(
|
||||
const QString &userDataPath,
|
||||
const QString &url,
|
||||
not_null<PanelDelegate*> delegate);
|
||||
|
||||
[[nodiscard]] bool shown() const;
|
||||
void navigate(const QString &url);
|
||||
|
||||
private:
|
||||
Ui::Window _window;
|
||||
Webview::Window *_webview = nullptr;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Payments::Ui
|
|
@ -344,6 +344,10 @@ void SeparatePanel::setInnerSize(QSize size) {
|
|||
}
|
||||
}
|
||||
|
||||
QRect SeparatePanel::innerGeometry() const {
|
||||
return _body->geometry();
|
||||
}
|
||||
|
||||
void SeparatePanel::initGeometry(QSize size) {
|
||||
const auto active = QApplication::activeWindow();
|
||||
const auto center = !active
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
|
||||
void setTitle(rpl::producer<QString> title);
|
||||
void setInnerSize(QSize size);
|
||||
[[nodiscard]] QRect innerGeometry() const;
|
||||
|
||||
void setHideOnDeactivate(bool hideOnDeactivate);
|
||||
void showAndActivate();
|
||||
|
@ -41,9 +42,9 @@ public:
|
|||
void showToast(const TextWithEntities &text);
|
||||
void destroyLayer();
|
||||
|
||||
rpl::producer<> backRequests() const;
|
||||
rpl::producer<> closeRequests() const;
|
||||
rpl::producer<> closeEvents() const;
|
||||
[[nodiscard]] rpl::producer<> backRequests() const;
|
||||
[[nodiscard]] rpl::producer<> closeRequests() const;
|
||||
[[nodiscard]] rpl::producer<> closeEvents() const;
|
||||
void setBackAllowed(bool allowed);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -79,8 +79,6 @@ PRIVATE
|
|||
payments/ui/payments_panel.h
|
||||
payments/ui/payments_panel_data.h
|
||||
payments/ui/payments_panel_delegate.h
|
||||
payments/ui/payments_webview.cpp
|
||||
payments/ui/payments_webview.h
|
||||
|
||||
platform/mac/file_bookmark_mac.h
|
||||
platform/mac/file_bookmark_mac.mm
|
||||
|
|
Loading…
Add table
Reference in a new issue