From b7259615a71b3209a9748aa0636a31bf42be1a9a Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 30 May 2022 17:08:26 +0400 Subject: [PATCH] Request terms acceptance for recurring payments. --- Telegram/Resources/langs/lang.strings | 6 ++ Telegram/Resources/tl/api.tl | 12 ++- .../payments/payments_checkout_process.cpp | 9 ++ .../payments/payments_checkout_process.h | 1 + .../SourceFiles/payments/payments_form.cpp | 9 ++ Telegram/SourceFiles/payments/payments_form.h | 3 + .../payments/ui/payments_panel.cpp | 85 +++++++++++++++++++ .../SourceFiles/payments/ui/payments_panel.h | 1 + .../payments/ui/payments_panel_data.h | 2 + .../payments/ui/payments_panel_delegate.h | 1 + Telegram/lib_ui | 2 +- 11 files changed, 126 insertions(+), 5 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index a53f8e2c1..973ffb539 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -2353,6 +2353,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "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_payments_terms_title" = "Terms of Service"; +"lng_payments_terms_text" = "Subscribe and accept terms of service of {bot}?"; +"lng_payments_terms_agree" = "I agree to {link}"; +"lng_payments_terms_link" = "Terms of Service"; +"lng_payments_terms_accept" = "Accept"; + "lng_call_status_incoming" = "is calling you..."; "lng_call_status_connecting" = "connecting..."; "lng_call_status_exchanging" = "exchanging encryption keys..."; diff --git a/Telegram/Resources/tl/api.tl b/Telegram/Resources/tl/api.tl index a8c92abae..46a7c0086 100644 --- a/Telegram/Resources/tl/api.tl +++ b/Telegram/Resources/tl/api.tl @@ -173,8 +173,8 @@ messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageActi messageActionPinMessage#94bd38ed = MessageAction; messageActionHistoryClear#9fbab604 = MessageAction; messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; -messageActionPaymentSent#96163f56 flags:# currency:string total_amount:long invoice_slug:flags.0?string = MessageAction; +messageActionPaymentSentMe#8f31b327 flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction; +messageActionPaymentSent#96163f56 flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string = MessageAction; messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; messageActionScreenshotTaken#4792929b = MessageAction; messageActionCustomAction#fae69f56 message:string = MessageAction; @@ -826,7 +826,7 @@ dataJSON#7d748d04 data:string = DataJSON; labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; -invoice#cd886e0 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector = Invoice; +invoice#3e85a91b flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector recurring_terms_url:flags.9?string = Invoice; paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; @@ -1345,7 +1345,7 @@ attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; -attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true bot_id:long short_name:string peer_types:Vector icons:Vector = AttachMenuBot; +attachMenuBot#c8aa2cd2 flags:# inactive:flags.0?true has_settings:flags.1?true bot_id:long short_name:string peer_types:Vector icons:Vector = AttachMenuBot; attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; @@ -1386,6 +1386,8 @@ payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; messages.transcribedAudio#93752c52 flags:# pending:flags.0?true transcription_id:long text:string = messages.TranscribedAudio; +help.premiumPromo#3f7ae6ee status_text:string status_entities:Vector video_sections:Vector videos:Vector = help.PremiumPromo; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1729,6 +1731,7 @@ help.getPromoData#c0977421 = help.PromoData; help.hidePromoData#1e251c95 peer:InputPeer = Bool; help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; +help.getPremiumPromo#b81b93d4 = help.PremiumPromo; channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; @@ -1792,6 +1795,7 @@ payments.getBankCardData#2e79d779 number:string = payments.BankCardData; payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; payments.assignAppStoreTransaction#6299a12f transaction_id:string = Updates; payments.assignPlayMarketTransaction#4faa4aed purchase_token:string = Updates; +payments.requestRecurringPayment#146e958d user_id:InputUser recurring_init_charge:string invoice_media:InputMedia = Updates; stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true animated:flags.1?true videos:flags.4?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.cpp b/Telegram/SourceFiles/payments/payments_checkout_process.cpp index 307e96465..8f3bf7fbd 100644 --- a/Telegram/SourceFiles/payments/payments_checkout_process.cpp +++ b/Telegram/SourceFiles/payments/payments_checkout_process.cpp @@ -533,6 +533,10 @@ void CheckoutProcess::panelSubmit() { _form->validateInformation(_form->information()); } else if (!method.newCredentials && !method.savedCredentials) { editPaymentMethod(); + } else if (invoice.isRecurring && !_form->details().termsAccepted) { + _panel->requestTermsAcceptance( + _form->details().termsBotUsername, + invoice.recurringTermsUrl); } else { RegisterPaymentStart(this, { _form->invoice().cover.title }); _submitState = SubmitState::Finishing; @@ -545,6 +549,11 @@ void CheckoutProcess::panelTrustAndSubmit() { panelSubmit(); } +void CheckoutProcess::panelAcceptTermsAndSubmit() { + _form->acceptTerms(); + panelSubmit(); +} + void CheckoutProcess::panelWebviewMessage( const QJsonDocument &message, bool saveInformation) { diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.h b/Telegram/SourceFiles/payments/payments_checkout_process.h index 74fdc667c..121d15a03 100644 --- a/Telegram/SourceFiles/payments/payments_checkout_process.h +++ b/Telegram/SourceFiles/payments/payments_checkout_process.h @@ -123,6 +123,7 @@ private: void panelCloseSure() override; void panelSubmit() override; void panelTrustAndSubmit() override; + void panelAcceptTermsAndSubmit() override; void panelWebviewMessage( const QJsonDocument &message, bool saveInformation) override; diff --git a/Telegram/SourceFiles/payments/payments_form.cpp b/Telegram/SourceFiles/payments/payments_form.cpp index aa032df6e..3b2411fdd 100644 --- a/Telegram/SourceFiles/payments/payments_form.cpp +++ b/Telegram/SourceFiles/payments/payments_form.cpp @@ -368,9 +368,13 @@ void Form::processInvoice(const MTPDinvoice &data) { .isPhoneRequested = data.is_phone_requested(), .isEmailRequested = data.is_email_requested(), .isShippingAddressRequested = data.is_shipping_address_requested(), + .isRecurring = data.is_recurring(), .isFlexible = data.is_flexible(), .isTest = data.is_test(), + .recurringTermsUrl = qs( + data.vrecurring_terms_url().value_or_empty()), + .phoneSentToProvider = data.is_phone_to_provider(), .emailSentToProvider = data.is_email_to_provider(), }; @@ -403,6 +407,7 @@ void Form::processDetails(const MTPDpayments_paymentForm &data) { if (const auto botId = _details.botId) { if (const auto bot = _session->data().userLoaded(botId)) { _invoice.cover.seller = bot->name; + _details.termsBotUsername = bot->username; } } if (const auto providerId = _details.providerId) { @@ -938,6 +943,10 @@ void Form::setTips(int64 value) { _invoice.tipsSelected = std::min(value, _invoice.tipsMax); } +void Form::acceptTerms() { + _details.termsAccepted = true; +} + void Form::trustBot() { _session->local().markBotTrustedPayment(_details.botId); } diff --git a/Telegram/SourceFiles/payments/payments_form.h b/Telegram/SourceFiles/payments/payments_form.h index dcfd5c3af..c1de78030 100644 --- a/Telegram/SourceFiles/payments/payments_form.h +++ b/Telegram/SourceFiles/payments/payments_form.h @@ -42,11 +42,13 @@ struct FormDetails { uint64 formId = 0; QString url; QString nativeProvider; + QString termsBotUsername; QByteArray nativeParamsJson; UserId botId = 0; UserId providerId = 0; bool canSaveCredentials = false; bool passwordMissing = false; + bool termsAccepted = false; [[nodiscard]] bool valid() const { return !url.isEmpty(); @@ -223,6 +225,7 @@ public: void setHasPassword(bool has); void setShippingOption(const QString &id); void setTips(int64 value); + void acceptTerms(); void trustBot(); void submit(); void submit(const Core::CloudPasswordResult &result); diff --git a/Telegram/SourceFiles/payments/ui/payments_panel.cpp b/Telegram/SourceFiles/payments/ui/payments_panel.cpp index a09f8e37b..ba36f22c3 100644 --- a/Telegram/SourceFiles/payments/ui/payments_panel.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_panel.cpp @@ -644,6 +644,91 @@ void Panel::showWarning(const QString &bot, const QString &provider) { })); } +void Panel::requestTermsAcceptance( + const QString &username, + const QString &url) { + showBox(Box([=](not_null box) { + box->setTitle(tr::lng_payments_terms_title()); + box->addRow(object_ptr( + box.get(), + tr::lng_payments_terms_text( + lt_bot, + rpl::single(Ui::Text::Bold('@' + username)), + Ui::Text::WithEntities), + st::boxLabel)); + const auto update = std::make_shared>(); + auto checkView = std::make_unique( + st::defaultCheck, + false, + [=] { if (*update) { (*update)(); } }); + const auto check = checkView.get(); + const auto row = box->addRow( + object_ptr( + box.get(), + tr::lng_payments_terms_agree( + lt_link, + rpl::single(Ui::Text::Link( + tr::lng_payments_terms_link(tr::now), + url)), + Ui::Text::WithEntities), + st::defaultBoxCheckbox, + std::move(checkView)), + { + st::boxRowPadding.left(), + st::boxRowPadding.left(), + st::boxRowPadding.right(), + st::defaultBoxCheckbox.margin.bottom(), + }); + (*update) = [=] { row->update(); }; + + struct State { + bool error = false; + Ui::Animations::Simple errorAnimation; + }; + const auto state = box->lifetime().make_state(); + const auto showError = [=] { + const auto callback = [=] { + const auto error = state->errorAnimation.value( + state->error ? 1. : 0.); + if (error == 0.) { + check->setUntoggledOverride(std::nullopt); + } else { + const auto color = anim::color( + st::defaultCheck.untoggledFg, + st::boxTextFgError, + error); + check->setUntoggledOverride(color); + } + }; + state->error = true; + state->errorAnimation.stop(); + state->errorAnimation.start( + callback, + 0., + 1., + st::defaultCheck.duration); + }; + + row->checkedChanges( + ) | rpl::filter([=](bool checked) { + return checked; + }) | rpl::start_with_next([=] { + state->error = false; + check->setUntoggledOverride(std::nullopt); + }, row->lifetime()); + + box->addButton(tr::lng_payments_terms_accept(), [=] { + if (check->checked()) { + _delegate->panelAcceptTermsAndSubmit(); + box->closeBox(); + } else { + showError(); + } + }); + box->addButton(tr::lng_cancel(), [=] { box->closeBox(); }); + })); +} + void Panel::showEditCard( const NativeMethodDetails &native, CardField field) { diff --git a/Telegram/SourceFiles/payments/ui/payments_panel.h b/Telegram/SourceFiles/payments/ui/payments_panel.h index 10ba33b88..d484592ec 100644 --- a/Telegram/SourceFiles/payments/ui/payments_panel.h +++ b/Telegram/SourceFiles/payments/ui/payments_panel.h @@ -72,6 +72,7 @@ public: void askSetPassword(); void showCloseConfirm(); void showWarning(const QString &bot, const QString &provider); + void requestTermsAcceptance(const QString &username, const QString &url); bool showWebview( const QString &url, diff --git a/Telegram/SourceFiles/payments/ui/payments_panel_data.h b/Telegram/SourceFiles/payments/ui/payments_panel_data.h index 77ae15bc1..4fc37321b 100644 --- a/Telegram/SourceFiles/payments/ui/payments_panel_data.h +++ b/Telegram/SourceFiles/payments/ui/payments_panel_data.h @@ -49,10 +49,12 @@ struct Invoice { bool isPhoneRequested = false; bool isEmailRequested = false; bool isShippingAddressRequested = false; + bool isRecurring = false; bool isFlexible = false; bool isTest = false; QString provider; + QString recurringTermsUrl; bool phoneSentToProvider = false; bool emailSentToProvider = false; diff --git a/Telegram/SourceFiles/payments/ui/payments_panel_delegate.h b/Telegram/SourceFiles/payments/ui/payments_panel_delegate.h index 77d417e30..e147c67f2 100644 --- a/Telegram/SourceFiles/payments/ui/payments_panel_delegate.h +++ b/Telegram/SourceFiles/payments/ui/payments_panel_delegate.h @@ -29,6 +29,7 @@ public: virtual void panelCloseSure() = 0; virtual void panelSubmit() = 0; virtual void panelTrustAndSubmit() = 0; + virtual void panelAcceptTermsAndSubmit() = 0; virtual void panelWebviewMessage( const QJsonDocument &message, bool saveInformation) = 0; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 676d8697c..e1ec6a38b 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 676d8697c6c704c6c5494f03f0bc78d006052768 +Subproject commit e1ec6a38beae8f90202b8bfa5a247e8f286b810f