From 35ff621b5b52f7e3553fb0f990ea13ade7101b8e Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 12 Apr 2021 12:50:31 +0400 Subject: [PATCH] Show toast on successfull payment. --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/history/history.cpp | 137 +++++++++--------- .../payments/payments_checkout_process.cpp | 63 ++++++-- .../payments/payments_checkout_process.h | 5 + .../payments/ui/payments_edit_card.cpp | 2 +- .../payments/ui/payments_panel.cpp | 1 + 6 files changed, 127 insertions(+), 82 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 6dd0b6790..21b66bbe7 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1878,6 +1878,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_payments_invoice_label" = "Invoice"; "lng_payments_invoice_label_test" = "Test invoice"; "lng_payments_receipt_button" = "Receipt"; +"lng_payments_success" = "You paid {amount} for {title}."; "lng_payments_checkout_title" = "Checkout"; "lng_payments_receipt_title" = "Receipt"; diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index a168e37c4..fe4a62a98 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -42,6 +42,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "support/support_helper.h" #include "ui/image/image.h" #include "ui/text/text_options.h" +#include "ui/toasts/common_toasts.h" +#include "ui/text/text_utilities.h" +#include "payments/payments_checkout_process.h" #include "core/crash_reports.h" #include "core/application.h" #include "base/unixtime.h" @@ -852,14 +855,19 @@ void History::applyMessageChanges( void History::applyServiceChanges( not_null item, const MTPDmessageService &data) { - auto &action = data.vaction(); - switch (action.type()) { - case mtpc_messageActionChatAddUser: { - auto &d = action.c_messageActionChatAddUser(); + const auto replyTo = data.vreply_to(); + const auto setGroupCallFrom = [&](const auto &data) { + if (const auto channel = peer->asChannel()) { + channel->setGroupCall(data.vcall()); + } else if (const auto chat = peer->asChat()) { + chat->setGroupCall(data.vcall()); + } + }; + data.vaction().match([&](const MTPDmessageActionChatAddUser &data) { if (const auto megagroup = peer->asMegagroup()) { const auto mgInfo = megagroup->mgInfo.get(); Assert(mgInfo != nullptr); - for (const auto &userId : d.vusers().v) { + for (const auto &userId : data.vusers().v) { if (const auto user = owner().userLoaded(userId.v)) { if (!base::contains(mgInfo->lastParticipants, user)) { mgInfo->lastParticipants.push_front(user); @@ -870,21 +878,19 @@ void History::applyServiceChanges( } if (user->isBot()) { peer->asChannel()->mgInfo->bots.insert(user); - if (peer->asChannel()->mgInfo->botStatus != 0 && peer->asChannel()->mgInfo->botStatus < 2) { + if (peer->asChannel()->mgInfo->botStatus != 0 + && peer->asChannel()->mgInfo->botStatus < 2) { peer->asChannel()->mgInfo->botStatus = 2; } } } } } - } break; - - case mtpc_messageActionChatJoinedByLink: { - auto &d = action.c_messageActionChatJoinedByLink(); - if (auto megagroup = peer->asMegagroup()) { - auto mgInfo = megagroup->mgInfo.get(); + }, [&](const MTPDmessageActionChatJoinedByLink &data) { + if (const auto megagroup = peer->asMegagroup()) { + const auto mgInfo = megagroup->mgInfo.get(); Assert(mgInfo != nullptr); - if (auto user = item->from()->asUser()) { + if (const auto user = item->from()->asUser()) { if (!base::contains(mgInfo->lastParticipants, user)) { mgInfo->lastParticipants.push_front(user); session().changes().peerUpdated( @@ -900,25 +906,20 @@ void History::applyServiceChanges( } } } - } break; - - case mtpc_messageActionChatDeletePhoto: { + }, [&](const MTPDmessageActionChatDeletePhoto &data) { if (const auto chat = peer->asChat()) { chat->setPhoto(MTP_chatPhotoEmpty()); } - } break; - - case mtpc_messageActionChatDeleteUser: { - auto &d = action.c_messageActionChatDeleteUser(); - auto uid = d.vuser_id().v; + }, [&](const MTPDmessageActionChatDeleteUser &data) { + const auto uid = data.vuser_id().v; if (lastKeyboardFrom == peerFromUser(uid)) { clearLastKeyboard(); } - if (auto megagroup = peer->asMegagroup()) { - if (auto user = owner().userLoaded(uid)) { - auto mgInfo = megagroup->mgInfo.get(); + if (const auto megagroup = peer->asMegagroup()) { + if (const auto user = owner().userLoaded(uid)) { + const auto mgInfo = megagroup->mgInfo.get(); Assert(mgInfo != nullptr); - auto i = ranges::find( + const auto i = ranges::find( mgInfo->lastParticipants, user, [](not_null user) { return user.get(); }); @@ -930,15 +931,18 @@ void History::applyServiceChanges( } owner().removeMegagroupParticipant(megagroup, user); if (megagroup->membersCount() > 1) { - megagroup->setMembersCount(megagroup->membersCount() - 1); + megagroup->setMembersCount( + megagroup->membersCount() - 1); } else { - mgInfo->lastParticipantsStatus |= MegagroupInfo::LastParticipantsCountOutdated; + mgInfo->lastParticipantsStatus + |= MegagroupInfo::LastParticipantsCountOutdated; mgInfo->lastParticipantsCount = 0; } if (mgInfo->lastAdmins.contains(user)) { mgInfo->lastAdmins.remove(user); if (megagroup->adminsCount() > 1) { - megagroup->setAdminsCount(megagroup->adminsCount() - 1); + megagroup->setAdminsCount( + megagroup->adminsCount() - 1); } session().changes().peerUpdated( peer, @@ -951,11 +955,8 @@ void History::applyServiceChanges( } Data::ChannelAdminChanges(megagroup).remove(uid); } - } break; - - case mtpc_messageActionChatEditPhoto: { - const auto &d = action.c_messageActionChatEditPhoto(); - d.vphoto().match([&](const MTPDphoto &data) { + }, [&](const MTPDmessageActionChatEditPhoto &data) { + data.vphoto().match([&](const MTPDphoto &data) { using Flag = MTPDchatPhoto::Flag; const auto photo = owner().processPhoto(data); photo->peer = peer; @@ -980,37 +981,27 @@ void History::applyServiceChanges( channel->setPhoto(MTP_chatPhotoEmpty()); } }); - } break; - - case mtpc_messageActionChatEditTitle: { - auto &d = action.c_messageActionChatEditTitle(); - if (auto chat = peer->asChat()) { - chat->setName(qs(d.vtitle())); + }, [&](const MTPDmessageActionChatEditTitle &data) { + if (const auto chat = peer->asChat()) { + chat->setName(qs(data.vtitle())); } - } break; - - case mtpc_messageActionChatMigrateTo: { + }, [&](const MTPDmessageActionChatMigrateTo &data) { if (const auto chat = peer->asChat()) { chat->addFlags(MTPDchat::Flag::f_deactivated); - const auto &d = action.c_messageActionChatMigrateTo(); - if (const auto channel = owner().channelLoaded(d.vchannel_id().v)) { + if (const auto channel = owner().channelLoaded( + data.vchannel_id().v)) { Data::ApplyMigration(chat, channel); } } - } break; - - case mtpc_messageActionChannelMigrateFrom: { + }, [&](const MTPDmessageActionChannelMigrateFrom &data) { if (const auto channel = peer->asChannel()) { channel->addFlags(MTPDchannel::Flag::f_megagroup); - const auto &d = action.c_messageActionChannelMigrateFrom(); - if (const auto chat = owner().chatLoaded(d.vchat_id().v)) { + if (const auto chat = owner().chatLoaded(data.vchat_id().v)) { Data::ApplyMigration(chat, channel); } } - } break; - - case mtpc_messageActionPinMessage: { - if (const auto replyTo = data.vreply_to()) { + }, [&](const MTPDmessageActionPinMessage &data) { + if (replyTo) { replyTo->match([&](const MTPDmessageReplyHeader &data) { const auto id = data.vreply_to_msg_id().v; if (item) { @@ -1023,20 +1014,34 @@ void History::applyServiceChanges( } }); } - } break; - - case mtpc_messageActionGroupCall: - case mtpc_messageActionGroupCallScheduled: { - const auto &call = (action.type() == mtpc_messageActionGroupCall) - ? action.c_messageActionGroupCall().vcall() - : action.c_messageActionGroupCallScheduled().vcall(); - if (const auto channel = peer->asChannel()) { - channel->setGroupCall(call); - } else if (const auto chat = peer->asChat()) { - chat->setGroupCall(call); + }, [&](const MTPDmessageActionGroupCall &data) { + setGroupCallFrom(data); + }, [&](const MTPDmessageActionGroupCallScheduled &data) { + setGroupCallFrom(data); + }, [&](const MTPDmessageActionPaymentSent &data) { + if (const auto payment = item->Get()) { + if (const auto message = payment->msg) { + if (const auto media = message->media()) { + if (const auto invoice = media->invoice()) { + using Payments::CheckoutProcess; + if (CheckoutProcess::TakePaymentStarted(message)) { + // Toast on a current active window. + Ui::ShowMultilineToast({ + .text = tr::lng_payments_success( + tr::now, + lt_amount, + Ui::Text::Bold(payment->amount), + lt_title, + Ui::Text::Bold(invoice->title), + Ui::Text::WithEntities), + }); + } + } + } + } } - } break; - } + }, [](const auto &) { + }); } void History::mainViewRemoved( diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.cpp b/Telegram/SourceFiles/payments/payments_checkout_process.cpp index 0c6690cee..bb98de17a 100644 --- a/Telegram/SourceFiles/payments/payments_checkout_process.cpp +++ b/Telegram/SourceFiles/payments/payments_checkout_process.cpp @@ -33,6 +33,7 @@ namespace { struct SessionProcesses { base::flat_map> map; + base::flat_set paymentStarted; rpl::lifetime lifetime; }; @@ -93,6 +94,47 @@ void CheckoutProcess::Start( j->second->requestActivate(); } +bool CheckoutProcess::TakePaymentStarted( + not_null item) { + const auto session = &item->history()->session(); + const auto itemId = item->fullId(); + const auto i = Processes.find(session); + if (i == end(Processes) || !i->second.paymentStarted.contains(itemId)) { + return false; + } + i->second.paymentStarted.erase(itemId); + const auto j = i->second.map.find(itemId); + if (j != end(i->second.map)) { + j->second->closeAndReactivate(); + } else if (i->second.paymentStarted.empty() && i->second.map.empty()) { + Processes.erase(i); + } + return true; +} + +void CheckoutProcess::RegisterPaymentStart( + not_null process) { + const auto i = Processes.find(process->_session); + Assert(i != end(Processes)); + for (const auto &[itemId, itemProcess] : i->second.map) { + if (itemProcess.get() == process) { + i->second.paymentStarted.emplace(itemId); + } + } +} + +void CheckoutProcess::UnregisterPaymentStart( + not_null process) { + const auto i = Processes.find(process->_session); + if (i != end(Processes)) { + for (const auto &[itemId, itemProcess] : i->second.map) { + if (itemProcess.get() == process) { + i->second.paymentStarted.emplace(itemId); + } + } + } +} + CheckoutProcess::CheckoutProcess( not_null peer, MsgId itemId, @@ -164,9 +206,11 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) { requestSetPassword(); } }, [&](const TmpPasswordRequired &) { + UnregisterPaymentStart(this); _submitState = SubmitState::Validated; requestPassword(); }, [&](const BotTrustRequired &data) { + UnregisterPaymentStart(this); _submitState = SubmitState::Validated; _panel->showWarning(data.bot->name, data.provider->name); if (const auto box = _enterPasswordBox.data()) { @@ -276,20 +320,7 @@ void CheckoutProcess::handleError(const Error &error) { } } break; case Error::Type::SmartGlocal: { - //using Field = Ui::CardField; - //if (id == u"InvalidNumber"_q || id == u"IncorrectNumber"_q) { - // showCardError(Field::Number); - //} else if (id == u"InvalidCVC"_q || id == u"IncorrectCVC"_q) { - // showCardError(Field::Cvc); - //} else if (id == u"InvalidExpiryMonth"_q - // || id == u"InvalidExpiryYear"_q - // || id == u"ExpiredCard"_q) { - // showCardError(Field::ExpireDate); - //} else if (id == u"CardDeclined"_q) { - // showToast({ tr::lng_payments_card_declined(tr::now) }); - //} else { - showToast({ "SmartGlocal Error: " + id }); - //} + showToast({ "SmartGlocal Error: " + id }); } break; case Error::Type::TmpPassword: if (const auto box = _enterPasswordBox.data()) { @@ -303,6 +334,7 @@ void CheckoutProcess::handleError(const Error &error) { box->closeBox(); } if (_submitState == SubmitState::Finishing) { + UnregisterPaymentStart(this); _submitState = SubmitState::Validated; } if (id == u"INVOICE_ALREADY_PAID"_q) { @@ -359,7 +391,7 @@ void CheckoutProcess::close() { return; } i->second.map.erase(j); - if (i->second.map.empty()) { + if (i->second.map.empty() && i->second.paymentStarted.empty()) { Processes.erase(i); } } @@ -388,6 +420,7 @@ void CheckoutProcess::panelSubmit() { } else if (!method.newCredentials && !method.savedCredentials) { editPaymentMethod(); } else { + RegisterPaymentStart(this); _submitState = SubmitState::Finishing; _form->submit(); } diff --git a/Telegram/SourceFiles/payments/payments_checkout_process.h b/Telegram/SourceFiles/payments/payments_checkout_process.h index 46ec38d8f..498e1385f 100644 --- a/Telegram/SourceFiles/payments/payments_checkout_process.h +++ b/Telegram/SourceFiles/payments/payments_checkout_process.h @@ -52,6 +52,8 @@ public: not_null item, Mode mode, Fn reactivate); + [[nodiscard]] static bool TakePaymentStarted( + not_null item); CheckoutProcess( not_null peer, @@ -70,6 +72,9 @@ private: }; [[nodiscard]] not_null panelDelegate(); + static void RegisterPaymentStart(not_null process); + static void UnregisterPaymentStart(not_null process); + void setReactivateCallback(Fn reactivate); void requestActivate(); void closeAndReactivate(); diff --git a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp index dbd6e4c2d..95200b504 100644 --- a/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_edit_card.cpp @@ -323,7 +323,7 @@ not_null EditCard::setupContent() { if (_native.needCardholderName) { _name = add({ - .type = FieldType::CardNumber, + .type = FieldType::Text, .placeholder = tr::lng_payments_card_holder(), .validator = CardHolderNameValidator(), }); diff --git a/Telegram/SourceFiles/payments/ui/payments_panel.cpp b/Telegram/SourceFiles/payments/ui/payments_panel.cpp index d3b05b042..49d8e586a 100644 --- a/Telegram/SourceFiles/payments/ui/payments_panel.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_panel.cpp @@ -278,6 +278,7 @@ bool Panel::showWebview( if (!_webview && !createWebview()) { return false; } + _widget->destroyLayer(); _webview->navigate(url); _widget->setBackAllowed(allowBack); if (bottomText) {