mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-11 09:19:35 +00:00
Show toast on successfull payment.
This commit is contained in:
parent
a2d2c8a208
commit
35ff621b5b
@ -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";
|
||||
|
@ -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<HistoryItem*> 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<UserData*> 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<HistoryServicePayment>()) {
|
||||
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(
|
||||
|
@ -33,6 +33,7 @@ namespace {
|
||||
|
||||
struct SessionProcesses {
|
||||
base::flat_map<FullMsgId, std::unique_ptr<CheckoutProcess>> map;
|
||||
base::flat_set<FullMsgId> paymentStarted;
|
||||
rpl::lifetime lifetime;
|
||||
};
|
||||
|
||||
@ -93,6 +94,47 @@ void CheckoutProcess::Start(
|
||||
j->second->requestActivate();
|
||||
}
|
||||
|
||||
bool CheckoutProcess::TakePaymentStarted(
|
||||
not_null<const HistoryItem*> 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<CheckoutProcess*> 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<CheckoutProcess*> 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<PeerData*> 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();
|
||||
}
|
||||
|
@ -52,6 +52,8 @@ public:
|
||||
not_null<const HistoryItem*> item,
|
||||
Mode mode,
|
||||
Fn<void()> reactivate);
|
||||
[[nodiscard]] static bool TakePaymentStarted(
|
||||
not_null<const HistoryItem*> item);
|
||||
|
||||
CheckoutProcess(
|
||||
not_null<PeerData*> peer,
|
||||
@ -70,6 +72,9 @@ private:
|
||||
};
|
||||
[[nodiscard]] not_null<PanelDelegate*> panelDelegate();
|
||||
|
||||
static void RegisterPaymentStart(not_null<CheckoutProcess*> process);
|
||||
static void UnregisterPaymentStart(not_null<CheckoutProcess*> process);
|
||||
|
||||
void setReactivateCallback(Fn<void()> reactivate);
|
||||
void requestActivate();
|
||||
void closeAndReactivate();
|
||||
|
@ -323,7 +323,7 @@ not_null<RpWidget*> EditCard::setupContent() {
|
||||
|
||||
if (_native.needCardholderName) {
|
||||
_name = add({
|
||||
.type = FieldType::CardNumber,
|
||||
.type = FieldType::Text,
|
||||
.placeholder = tr::lng_payments_card_holder(),
|
||||
.validator = CardHolderNameValidator(),
|
||||
});
|
||||
|
@ -278,6 +278,7 @@ bool Panel::showWebview(
|
||||
if (!_webview && !createWebview()) {
|
||||
return false;
|
||||
}
|
||||
_widget->destroyLayer();
|
||||
_webview->navigate(url);
|
||||
_widget->setBackAllowed(allowBack);
|
||||
if (bottomText) {
|
||||
|
Loading…
Reference in New Issue
Block a user