From 101d626d4f2cd651170cbd95269662d5107e29d9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 20 Feb 2025 14:55:34 +0400 Subject: [PATCH] Support paid files-with-comment and polls. --- Telegram/SourceFiles/apiwrap.cpp | 5 ++ .../history/history_item_helpers.cpp | 57 ++++++++++++++++++- .../history/history_item_helpers.h | 24 +++++++- .../SourceFiles/history/history_widget.cpp | 44 ++++++++------ .../SourceFiles/window/window_peer_menu.cpp | 33 ++++++++--- 5 files changed, 136 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index dad5a8730..1d6cb2ede 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -577,6 +577,11 @@ void ApiWrap::sendMessageFail( if (show) { show->showToast(tr::lng_error_schedule_limit(tr::now)); } + } else if (error.startsWith(u"ALLOW_PAYMENT_REQUIRED_"_q)) { + if (show) { + show->showToast( + u"Payment requirements changed. Please, try again."_q); + } } if (const auto item = _session->data().message(itemId)) { Assert(randomId != 0); diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 2420807c0..5fb0d9f76 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -258,7 +258,7 @@ void ShowSendPaidConfirm( } void ShowSendPaidConfirm( - std::shared_ptr show, + std::shared_ptr show, not_null peer, SendPaymentDetails details, Fn confirmed) { @@ -330,6 +330,61 @@ void ShowSendPaidConfirm( })); } +bool SendPaymentHelper::check( + not_null navigation, + not_null peer, + int messagesCount, + int starsApproved, + Fn resend) { + return check( + navigation->uiShow(), + peer, + messagesCount, + starsApproved, + std::move(resend)); +} + +bool SendPaymentHelper::check( + std::shared_ptr show, + not_null peer, + int messagesCount, + int starsApproved, + Fn resend) { + _lifetime.destroy(); + const auto details = ComputePaymentDetails(peer, messagesCount); + if (!details) { + _resend = [=] { resend(starsApproved); }; + + if (!peer->session().credits().loaded()) { + peer->session().credits().loadedValue( + ) | rpl::filter( + rpl::mappers::_1 + ) | rpl::take(1) | rpl::start_with_next([=] { + if (const auto callback = base::take(_resend)) { + callback(); + } + }, _lifetime); + } + + peer->session().changes().peerUpdates( + peer, + Data::PeerUpdate::Flag::FullInfo + ) | rpl::start_with_next([=] { + if (const auto callback = base::take(_resend)) { + callback(); + } + }, _lifetime); + + return false; + } else if (const auto stars = details->stars; stars > starsApproved) { + ShowSendPaidConfirm(show, peer, *details, [=] { + resend(stars); + }); + return false; + } + return true; +} + void RequestDependentMessageItem( not_null item, PeerId peerId, diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index 8265c21b9..34d8f5d18 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -29,6 +29,7 @@ struct SendErrorWithThread; namespace Main { class Session; +class SessionShow; } // namespace Main namespace Ui { @@ -149,11 +150,32 @@ void ShowSendPaidConfirm( SendPaymentDetails details, Fn confirmed); void ShowSendPaidConfirm( - std::shared_ptr show, + std::shared_ptr show, not_null peer, SendPaymentDetails details, Fn confirmed); +class SendPaymentHelper final { +public: + [[nodiscard]] bool check( + not_null navigation, + not_null peer, + int messagesCount, + int starsApproved, + Fn resend); + [[nodiscard]] bool check( + std::shared_ptr show, + not_null peer, + int messagesCount, + int starsApproved, + Fn resend); + +private: + Fn _resend; + rpl::lifetime _lifetime; + +}; + [[nodiscard]] Data::SendErrorWithThread GetErrorForSending( const std::vector> &threads, SendingErrorRequest request); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index bf6c33cc5..5e9aa5ca2 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -226,10 +226,12 @@ const auto kPsaAboutPrefix = "cloud_lng_about_psa_"; } // namespace struct HistoryWidget::SendingFiles { - Ui::PreparedList list; + std::vector groups; Ui::SendFilesWay way; TextWithTags caption; Api::SendOptions options; + int totalCount = 0; + bool sendComment = false; bool ctrlShiftEnter = false; }; @@ -895,14 +897,16 @@ HistoryWidget::HistoryWidget( } }, lifetime()); - session().credits().loadedValue( - ) | rpl::filter( - rpl::mappers::_1 - ) | rpl::take(1) | rpl::start_with_next([=] { - if (const auto callback = base::take(_resendOnFullUpdated)) { - callback(); - } - }, lifetime()); + if (!session().credits().loaded()) { + session().credits().loadedValue( + ) | rpl::filter( + rpl::mappers::_1 + ) | rpl::take(1) | rpl::start_with_next([=] { + if (const auto callback = base::take(_resendOnFullUpdated)) { + callback(); + } + }, lifetime()); + } using Type = Data::DefaultNotify; rpl::merge( @@ -6037,11 +6041,20 @@ void HistoryWidget::sendingFilesConfirmed( return; } + const auto filesCount = int(list.files.size()); + auto groups = DivideByGroups( + std::move(list), + way, + _peer->slowmodeApplied()); + const auto sendComment = !caption.text.isEmpty() + && (groups.size() != 1 || !groups.front().sentWithCaption()); sendingFilesConfirmed(std::make_shared(SendingFiles{ - .list = std::move(list), + .groups = std::move(groups), .way = way, .caption = std::move(caption), .options = options, + .totalCount = filesCount + (sendComment ? 1 : 0), + .sendComment = sendComment, .ctrlShiftEnter = ctrlShiftEnter, })); } @@ -6053,28 +6066,23 @@ void HistoryWidget::sendingFilesConfirmed( sendingFilesConfirmed(args); }; const auto checked = checkSendPayment( - args->list.files.size(), + args->totalCount, args->options.starsApproved, withPaymentApproved); if (!checked) { return; } - auto groups = DivideByGroups( - std::move(args->list), - args->way, - _peer->slowmodeApplied()); const auto compress = args->way.sendImagesAsPhotos(); const auto type = compress ? SendMediaType::Photo : SendMediaType::File; auto action = prepareSendAction(args->options); action.clearDraft = false; - if ((groups.size() != 1 || !groups.front().sentWithCaption()) - && !args->caption.text.isEmpty()) { + if (args->sendComment) { auto message = Api::MessageToSend(action); message.textWithTags = base::take(args->caption); session().api().sendMessage(std::move(message)); } - for (auto &group : groups) { + for (auto &group : args->groups) { const auto album = (group.type != Ui::AlbumType::None) ? std::make_shared() : nullptr; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 655ddc6dd..01f48bfc4 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -1737,11 +1737,27 @@ void PeerMenuCreatePoll( disabled, sendType, sendMenuDetails); - const auto weak = Ui::MakeWeak(box.data()); - const auto lock = box->lifetime().make_state(false); - box->submitRequests( - ) | rpl::start_with_next([=](const CreatePollBox::Result &result) { - if (std::exchange(*lock, true)) { + struct State { + QPointer weak; + Fn create; + SendPaymentHelper sendPayment; + bool lock = false; + }; + const auto state = std::make_shared(); + state->weak = box; + state->create = [=](const CreatePollBox::Result &result) { + const auto withPaymentApproved = [=](int stars) { + auto copy = result; + copy.options.starsApproved = stars; + state->create(copy); + }; + const auto checked = state->sendPayment.check( + controller, + peer, + 1, + result.options.starsApproved, + withPaymentApproved); + if (!checked || std::exchange(state->lock, true)) { return; } auto action = Api::SendAction( @@ -1755,13 +1771,16 @@ void PeerMenuCreatePoll( action.clearDraft = false; } const auto api = &peer->session().api(); + const auto weak = state->weak; api->polls().create(result.poll, action, crl::guard(weak, [=] { weak->closeBox(); }), crl::guard(weak, [=] { - *lock = false; + state->lock = false; weak->submitFailed(tr::lng_attach_failed(tr::now)); })); - }, box->lifetime()); + }; + box->submitRequests( + ) | rpl::start_with_next(state->create, box->lifetime()); controller->show(std::move(box), Ui::LayerOption::CloseOther); }