Support paid files-with-comment and polls.

This commit is contained in:
John Preston 2025-02-20 14:55:34 +04:00
parent 3633c19208
commit 101d626d4f
5 changed files with 136 additions and 27 deletions

View file

@ -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);

View file

@ -258,7 +258,7 @@ void ShowSendPaidConfirm(
}
void ShowSendPaidConfirm(
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Main::SessionShow> show,
not_null<PeerData*> peer,
SendPaymentDetails details,
Fn<void()> confirmed) {
@ -330,6 +330,61 @@ void ShowSendPaidConfirm(
}));
}
bool SendPaymentHelper::check(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer,
int messagesCount,
int starsApproved,
Fn<void(int)> resend) {
return check(
navigation->uiShow(),
peer,
messagesCount,
starsApproved,
std::move(resend));
}
bool SendPaymentHelper::check(
std::shared_ptr<Main::SessionShow> show,
not_null<PeerData*> peer,
int messagesCount,
int starsApproved,
Fn<void(int)> 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<HistoryItem*> item,
PeerId peerId,

View file

@ -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<void()> confirmed);
void ShowSendPaidConfirm(
std::shared_ptr<ChatHelpers::Show> show,
std::shared_ptr<Main::SessionShow> show,
not_null<PeerData*> peer,
SendPaymentDetails details,
Fn<void()> confirmed);
class SendPaymentHelper final {
public:
[[nodiscard]] bool check(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer,
int messagesCount,
int starsApproved,
Fn<void(int)> resend);
[[nodiscard]] bool check(
std::shared_ptr<Main::SessionShow> show,
not_null<PeerData*> peer,
int messagesCount,
int starsApproved,
Fn<void(int)> resend);
private:
Fn<void()> _resend;
rpl::lifetime _lifetime;
};
[[nodiscard]] Data::SendErrorWithThread GetErrorForSending(
const std::vector<not_null<Data::Thread*>> &threads,
SendingErrorRequest request);

View file

@ -226,10 +226,12 @@ const auto kPsaAboutPrefix = "cloud_lng_about_psa_";
} // namespace
struct HistoryWidget::SendingFiles {
Ui::PreparedList list;
std::vector<Ui::PreparedGroup> 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>(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<SendingAlbum>()
: nullptr;

View file

@ -1737,11 +1737,27 @@ void PeerMenuCreatePoll(
disabled,
sendType,
sendMenuDetails);
const auto weak = Ui::MakeWeak(box.data());
const auto lock = box->lifetime().make_state<bool>(false);
box->submitRequests(
) | rpl::start_with_next([=](const CreatePollBox::Result &result) {
if (std::exchange(*lock, true)) {
struct State {
QPointer<CreatePollBox> weak;
Fn<void(const CreatePollBox::Result &)> create;
SendPaymentHelper sendPayment;
bool lock = false;
};
const auto state = std::make_shared<State>();
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);
}